
  :root { --bg:#0E0E0E; --card:#181818; --card2:#202020; --border:#333333; --text:#8AB4D4; --muted:#507090; --accent:#777777; --accent2:#999999; --green:#10b981; --red:#ef4444; --red-rgb:239,68,68; --hover:#14b8a6; --hover-rgb:20,184,166; }
  body.light-mode { --bg:#F2F2F2; --card:#FFFFFF; --card2:#EBEBEB; --border:#CCCCCC; --text:#1A1A1A; --muted:#666666; }
  * { box-sizing:border-box; }
  body { margin:0; font-family:'Segoe UI',system-ui,sans-serif; background:var(--bg); color:var(--text); min-height:100vh; transition:background-color .15s, color .15s; }
  .center { display:flex; align-items:center; justify-content:center; min-height:100vh; padding:20px; }
  .card { background:var(--card); border:1px solid var(--border); border-radius:16px; padding:40px; width:100%; max-width:400px; }
  .logo { font-size:2rem; font-weight:800; text-align:center; background:linear-gradient(135deg,var(--accent),var(--accent2)); -webkit-background-clip:text; -webkit-text-fill-color:transparent; margin-bottom:6px; }
  .sub { text-align:center; color:var(--muted); font-size:.85rem; margin-bottom:28px; }
  label { display:block; font-size:.78rem; color:var(--muted); font-weight:600; text-transform:uppercase; margin-bottom:6px; }
  input, select { width:100%; padding:11px 14px; background:var(--bg); border:1px solid var(--border); border-radius:9px; color:var(--text); font-size:.9rem; margin-bottom:14px; }
  button { cursor:pointer; border:none; border-radius:9px; font-weight:700; font-size:.9rem; }
  .btn-primary { width:100%; padding:13px; background:linear-gradient(135deg,var(--accent),var(--accent2)); color:#fff; }
  .err { color:var(--red); font-size:.85rem; margin-top:10px; text-align:center; }
  .pw-wrap { position:relative; }
  .pw-wrap input { padding-right:90px; }
  .pw-toggle { position:absolute; right:8px; top:50%; transform:translateY(calc(-50% - 7px)); padding:6px 12px; font-size:.72rem; font-weight:600; background:var(--card2); color:var(--text); border:1px solid var(--border); border-radius:6px; cursor:pointer; }
  .forgot { display:inline-block; margin-top:14px; font-size:.85rem; color:var(--muted); text-decoration:none; border-bottom:1px dotted var(--muted); }
  .forgot:hover { color:var(--text); }

  /* На всю высоту окна и колонкой: шапка остаётся сверху, а плитки ниже
     центрируются в оставшемся месте. box-sizing уже border-box, поэтому
     100vh считается вместе с отступами и полосы прокрутки не появляется. */
  .launcher { width:100%; padding:40px 40px; box-sizing:border-box;
              min-height:100vh; display:flex; flex-direction:column; }
  /* «Правила» — документ с жёсткими переносами строк (он же скачивается
     как .txt), поэтому на широком мониторе строка занимала лишь левую
     треть экрана. Раскладываем его в колонки: чем шире окно, тем больше
     колонок — страница используется целиком и меньше приходится
     прокручивать. На узких экранах колонка остаётся одна. */
  /* Колонка должна вмещать самую длинную строку документа целиком
     (строки прав ролей — около 106 знаков ≈ 900px), иначе описание после
     тире переносится в начало следующей строки и таблица «разъезжается».
     Поэтому вторая колонка появляется только на действительно широких
     экранах, где каждая колонка всё ещё шире этой длины. */
  .rules-cols { column-gap: 26px; }
  .rules-pre {
    background:var(--card); border:1px solid var(--border); border-radius:14px;
    padding:20px 24px; margin:0 0 18px;
    font-family:'Consolas','Courier New',monospace; font-size:.84rem; line-height:1.55;
    color:var(--text); white-space:pre-wrap; overflow-wrap:break-word;
    break-inside: avoid;            /* раздел не разрывается между колонками */
    -webkit-column-break-inside: avoid;
  }
  /* Разделы 1–3 — таблицы ролей и программ, они короткие по строке и хорошо
     ложатся в две колонки. Разделы с 4-го — сплошной текст и команды, в узкой
     колонке они рвутся и читаются плохо, поэтому растягиваем на всю ширину. */
  .rules-pre.rules-wide { column-span: all; -webkit-column-span: all; }
  /* Каждая строка документа — отдельный блок со своим левым отступом. Так
     перенос длинной строки продолжается под её же началом, а не уезжает
     к левому краю: у пункта списка виден его отступ, у команды — её. */
  .rules-pre .rl { display:block; }
  /* Ключевые слова в «Правилах»: названия программ — вишнёвым, заголовки
     разделов — акцентным. Пояснения остаются обычным текстом, чтобы
     подсветка помогала читать, а не пестрила. */
  /* ── Палитра «Правил»: один смысл — один цвет ────────────────────────
     Структура документа (заголовок, подзаголовок, имя пункта) — оттенки
     светлого: их роль передаёт насыщенность, а не цвет. Цветом помечены
     только сущности: программы, люди, техника, уровни доступа.
     Раньше заголовки и технические термины делили один серый, поэтому
     подсветка выглядела случайной. */
  .rk-head  { color:#e6edf3; font-weight:800; letter-spacing:.03em; }   /* 4. БЕЗОПАСНОСТЬ ВХОДА */
  .rk-sub   { color:#b8c6d4; font-weight:700; }                        /* ── Как часто менять ── */
  .rk-item  { color:#dce6f0; font-weight:700; }                        /* 1. AUTH_SSO_SECRET     */
  .rk-rule  { color:#2b3540; }                                         /* рамки ═══ и ─── */
  .rk-app   { color:#b07cc7; font-weight:700; }                        /* названия программ по тексту */
  .rk-apps  { color:#b07cc7; font-weight:600; }                        /* перечень программ в шапке */
  .rk-pos   { color:#d9a441; font-weight:600; }                        /* должности и роли */
  .rk-tech  { color:#5ec9c0; }                                         /* переменные, файлы, пути */
  .rk-label { color:#7f9bb5; font-weight:600; }                        /* Где: Зачем: Важно: */
  .rk-ok    { color:#10b981; }                                         /* полный доступ */
  .rk-warn  { color:#d9a441; }                                         /* только просмотр */
  /* Красный на странице один — тот же, что у секундной стрелки часов.
     Отдельного оттенка для светлой темы нет: у стрелки его тоже нет. */
  .rk-no    { color:var(--red); }                                      /* нет доступа */
  /* На светлом фоне те же роли, но с достаточным контрастом к белому */
  body.light-mode .rk-head  { color:#0f172a; }
  body.light-mode .rk-sub   { color:#334155; }
  body.light-mode .rk-item  { color:#1e293b; }
  body.light-mode .rk-rule  { color:#cbd5e1; }
  body.light-mode .rk-app   { color:#5b2c6f; }
  body.light-mode .rk-apps  { color:#5b2c6f; }
  body.light-mode .rk-pos   { color:#a16207; }
  body.light-mode .rk-tech  { color:#0f766e; }
  body.light-mode .rk-label { color:#475569; }
  body.light-mode .rk-ok    { color:#047857; }
  body.light-mode .rk-warn  { color:#a16207; }
  .header { display:flex; justify-content:space-between; align-items:center; margin-bottom:30px; gap:14px; }
  /* Названию раздела и кнопкам рвать себя по словам нечего: «Роли и
     доступ» разъезжалось на две строки со сдвигом влево, а у кнопки
     значок отрывался от подписи. Переносим ряд целиком, а не слова. */
  .header > div:first-child { white-space:nowrap; }
  .header .btn-secondary, .header a.btn-secondary { white-space:nowrap; }
  .header > div:last-child { flex-wrap:wrap; justify-content:flex-end; row-gap:8px; }
  /* Шапка раздела «Роли»: название — кнопкой слева, действия по центру,
     «Назад» справа. Выравнивание по верхнему краю: когда ряд действий
     переносится на вторую строку, название и «Назад» остаются на одной
     линии с первой, а не сползают к середине блока. */
  .roles-header { align-items:flex-start; }
  .roles-header .roles-actions { flex:1 1 auto; display:flex; flex-wrap:wrap;
    gap:14px; align-items:center; justify-content:center; row-gap:8px; }
  .roles-header .roles-home { flex:none; font-weight:700; }
  /* Одна высота на все кнопки шапки: разнобой полей ломал ряд, а тумблер
     темы в 26 точек не помещался вровень и уезжал на вторую строку. */
  .roles-header .btn-secondary { height:38px; padding:0 16px; display:inline-flex;
    align-items:center; justify-content:center; line-height:1; }
  /* Переключатели вида — те же 38 в высоту, но уже: в них по два знака. */
  .roles-header .roles-view-toggles .btn-secondary { padding:0 12px; }
  /* Тумблер темы: внешняя высота как у кнопок, сам тумблер прежний и
     стоит по центру своей области. */
  .roles-header .theme-switch { height:38px; width:56px; border-radius:10px; }
  .roles-header .theme-switch .ts-knob { top:8px; }
  /* Единая подсветка при наведении — как у плиток программ. Прозрачная
     рамка задана заранее, чтобы при наведении ничего не «прыгало». */
  .hoverable {
    border:1px solid transparent; border-radius:10px; padding:6px 10px;
    transition:background-color .15s, border-color .15s;
  }
  .hoverable:hover { background:var(--card2); border-color:var(--hover); }
  /* Кнопки в шапке уже имеют свою рамку — подсвечиваем только её цвет */
  .btn-secondary, .btn-link, .theme-switch { transition:background-color .15s, border-color .15s, color .15s; }
  .btn-secondary:hover, .theme-switch:hover { background:var(--card2); border-color:var(--hover); color:var(--hover); }
  /* Кнопки строки резервной копии. Идут после общего правила выше, чтобы
     перебить его серый ховер: вес селекторов одинаковый, решает порядок.
     Цвет задан здесь, а не в атрибуте style, — иначе inline-стиль победил бы ховер. */
  .bk-delete { color:var(--red); }
  .bk-download:hover { color:var(--green); border-color:var(--green); background:rgba(16,185,129,.12); }
  .bk-delete:hover   { color:#fff;         border-color:var(--red);   background:var(--red); }
  .btn-link:hover { color:var(--text); background:var(--card2); border-color:var(--hover); }
  /* Гибкая раскладка вместо сетки: в сетке одинокая плитка неполного ряда
     встаёт в первую колонку и прижимается влево. Здесь неполный ряд
     центрируется сам. */
  /* Полоса плиток ограничена по ширине и центрирована: без ограничения на
     широком мониторе три плитки растянулись бы в длинные полосы. */
  /* Сколько колонок по 284 точки поместится в отведённую ширину — столько
     сетка и создаст: девять плиток лягут по три в ряд, одна займёт одну
     колонку и не растянется. Ширину задаёт колонка, поэтому внутренние
     отступы и рамка плитки на раскладку больше не влияют — на них и
     спотыкался прежний расчёт долей. */
  .apps-grid { display:grid; grid-template-columns:repeat(auto-fit, 284px);
               justify-content:center; gap:14px; max-width:880px; margin:auto; }
  .app-tile { min-width:0; }
  /* Часы стоят слева от сетки. Их место вычисляется в коде по фактическому
     положению плиток, поэтому здесь только размеры и внутренний строй. */
  .launcher { position:relative; }
  /* Три столбца в одном ряду: часы, плитки, календари. Выравнивание по
     верхнему краю и одинаковые зазоры получаются сами — раньше положение
     считалось в коде по замерам сетки, и любая смена вида его ломала. */
  .main-row { display:flex; align-items:flex-start; justify-content:space-between; gap:14px; }
  .main-row .apps-grid { margin:0 auto; min-width:0; }
  /* Столбец тянется на всю высоту ряда и делит её поровну — иначе при показе
     плиток списком нижние часы заканчивались выше плиток и будильника. */
  .world-clocks { width:240px; flex:none; display:flex; flex-direction:column;
                  gap:14px; align-self:stretch; justify-content:space-between; }
  /* Столбец повторяет высоту блока плиток и делится поровну между городами.
     Циферблат ужимается под свою долю, поэтому четыре города умещаются
     так же ровно, как умещались три. */
  .world-clocks > div { display:flex; align-items:stretch; }
  .world-clocks .wc-pill { display:flex; align-items:center; gap:12px; width:100%;
                           padding:6px 16px 6px 8px; border-radius:999px;
                           background:var(--card); border:1px solid var(--border); }
  .world-clocks svg { flex:none; width:96px; height:96px;
  }
  .world-clocks .wc-text { display:flex; flex-direction:column; gap:1px; min-width:0; }
  /* Часы — такой же элемент страницы, как плитка, и отклик на курсор должен
     быть тот же: без него они кажутся картинкой, а не частью интерфейса. */
  .world-clocks .wc-pill { transition:background-color .15s, border-color .15s; }
  .world-clocks .wc-pill:hover { background:var(--card2); border-color:var(--hover); }
  /* Календари справа от плиток — зеркально часам слева. Положение так же
     считается из кода по фактическому расположению сетки. */
  /* Столбец во всю высоту блока плиток: месяц прижат к верху, неделя к низу,
     между ними воздух — так правая сторона уравновешивает часы слева. */
  /* Столбец тянется на всю высоту ряда, а нижний блок забирает остаток —
     так будильник заканчивается вровень с последним рядом плиток. */
  .side-cals { width:240px; flex:none; align-self:stretch;
               display:flex; flex-direction:column; gap:14px; }
  .side-cals .cal-box:last-child { flex:1; }
  .side-cals .cal-box { background:var(--card); border:1px solid var(--border);
                        border-radius:14px; padding:10px 12px; }
  .side-cals .cal-head { display:flex; align-items:center; justify-content:space-between;
                         font-weight:700; font-size:.85rem; margin-bottom:8px; }
  .side-cals .cal-nav { cursor:pointer; padding:0 7px; color:var(--muted); user-select:none; }
  .side-cals .cal-nav { transition:color .15s; }
  /* Будильник — последний блок в столбце. «Плюс» зелёный, как отработавшие
     напоминания: добавление здесь — единственное созидательное действие. */
  .side-cals .cal-box:last-child .cal-head .cal-nav { color:var(--green); }
  /* Удаление краснеет, пауза синеет: три действия в строке стоят вплотную,
     и различать их только по значку тесно. */
  .side-cals .cal-row .cal-nav[title="Удалить"]:hover { color:var(--red); }
  .side-cals .cal-row .cal-nav:not([title="Удалить"]):hover { color:#3b82f6; }
  .side-cals .cal-nav:hover { color:var(--text); }
  .side-cals .cal-grid { display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
  .side-cals .cal-dow { text-align:center; font-size:.62rem; color:var(--muted); font-weight:600; }
  .side-cals .cal-day { text-align:center; font-size:.72rem; padding:3px 0; border-radius:6px;
                        font-variant-numeric:tabular-nums; }
  /* Дни соседних месяцев показываем бледными: без них сетка рвётся, но и
     спутать их с текущим месяцем нельзя. */
  .side-cals .cal-day.out { color:var(--border); }
  .side-cals .cal-day.off { background:rgba(127,127,127,.13); }
  .side-cals .cal-day.today { outline:2px solid var(--hover); }
  .side-cals .cal-day.hol-ru { background:rgba(var(--red-rgb),.20); color:var(--red); font-weight:700; }
  .side-cals .cal-day.hol-other { background:rgba(245,158,11,.22); color:#f59e0b; font-weight:700; }
  /* Подсветка при наведении: в узком столбце легко потерять, на каком именно
     дне или напоминании стоит курсор. Обводкой, а не рамкой — рамка сдвигает
     соседние клетки. */
  .side-cals .cal-day:hover { outline:2px solid var(--hover); outline-offset:-1px; }
  .side-cals .cal-row:hover { background:rgba(var(--hover-rgb),.12); border-radius:6px; }
  .side-cals .cal-row { display:flex; gap:8px; align-items:baseline; padding:4px 0;
                        border-bottom:1px solid var(--border); font-size:.74rem; }
  .side-cals .cal-row:last-child { border-bottom:none; }
  /* Список созвонов не должен растягивать столбец: прокрутка внутри
     коробки, а весь список — по двойному щелчку в отдельном окне. */
  .side-cals .cal-scroll { max-height:190px; overflow-y:auto; overscroll-behavior:contain; }
  .side-cals .cal-scroll::-webkit-scrollbar { width:6px; }
  .side-cals .cal-scroll::-webkit-scrollbar-thumb { background:var(--border); border-radius:3px; }
  /* Заголовок коробки, который разворачивается: курсор подсказывает,
     что по нему можно щёлкнуть дважды. */
  .side-cals .cal-head.expandable { cursor:zoom-in; }

  /* ── Окно «во весь экран» ── */
  /* Палитра окна противоположна странице: по умолчанию тема тёмная, значит
     окно светлое; при `body.light-mode` — наоборот. Переопределяем те же
     имена переменных, что и в теме, поэтому карточки, рамки и текст внутри
     перекрашиваются сами. */
  /* Тему не инвертируем: окно живёт в той же теме, что и вся программа.
     Переменные берутся у страницы — карточки, рамки и текст красятся сами.
     Имена и подписи не выделяются мышью: случайное выделение вызывало
     всплывающее меню браузера («Поиск», «Копировать», «Снимок») поверх
     строки. Телефоны, почта и Telegram выделяются — их копируют. */
  .calls-full { position:fixed; inset:0; z-index:1000;
                background:var(--bg); color:var(--text);
                display:flex; flex-direction:column; user-select:none; }
  .calls-full .cf-contacts, .calls-full a { user-select:text; }
  .calls-full-head { display:flex; align-items:center; gap:14px; padding:16px 24px;
                     border-bottom:1px solid var(--border); flex:none; }
  /* Заголовок окна — кнопка перехода в AI-Auth (22.09.2026): выглядит
     как кнопка, иначе никто не догадается, что на него можно нажать. */
  .calls-full-title { font-size:1.15rem; font-weight:800; cursor:pointer;
    background:transparent; color:var(--text); border:1px solid var(--border);
    border-radius:10px; padding:4px 12px; transition:.15s; font-family:inherit; }
  .calls-full-title:hover { color:#fff; background:var(--hover, #14b8a6); border-color:var(--hover, #14b8a6); }
  /* Все кнопки шапки — одной высоты и с одинаковыми полями: заголовок
     крупнее по шрифту, но коробка у него та же (22.09.2026). */
  .calls-full-head .calls-full-title,
  .calls-full-head .btn-secondary {
    display:inline-flex; align-items:center; justify-content:center;
    height:34px; padding:0 12px; box-sizing:border-box; line-height:1; }
  .calls-full-body { flex:1; overflow-y:auto; padding:18px 24px 30px; }
  .calls-full-day { font-size:.78rem; font-weight:700; text-transform:uppercase;
                    letter-spacing:.05em; color:var(--muted); margin:18px 0 8px; }
  .calls-full-day:first-child { margin-top:0; }
  /* Актуальный день — светлым, прошедший — серым; заголовок дня можно
     щёлкнуть и получить дату в буфер. */
  .calls-full-day { cursor:copy; border-radius:6px; padding:2px 6px; margin-left:-6px;
                    transition:background-color .15s, color .15s; }
  .calls-full-day:hover { background:var(--hover-bg); color:var(--hover); }
  .calls-full-day.actual-day { color:var(--text); }
  .calls-full-day.past-day { color:var(--muted); }
  .calls-full-row { display:flex; gap:16px; align-items:flex-start; padding:12px 14px;
                    border:1px solid var(--border); border-radius:12px; margin-bottom:8px;
                    background:var(--card); }
  .calls-full-row.past { opacity:.55; }
  /* Отметка «есть запись»: кнопкой, потому что по ней открывают записи. */
  .cf-rec { display:inline-block; padding:1px 9px; border-radius:99px; font-size:.72rem;
    font-weight:700; cursor:pointer; border:1px solid #3b82f6; color:#3b82f6;
    background:rgba(59,130,246,.12); }
  .cf-rec:hover { background:#3b82f6; color:#fff; }
  .cf-rec-item { border:1px solid var(--border); border-radius:12px; padding:12px; margin-bottom:12px; }
  .cf-rec-head { display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;
    align-items:baseline; margin-bottom:8px; }
  .cf-rec-head span { font-size:.76rem; color:var(--muted); }
  .calls-full-time { font-weight:800; font-size:1rem; width:64px; flex:none;
                     font-variant-numeric:tabular-nums; }
  .calls-full-main { flex:1; min-width:0; }
  .calls-full-name { font-weight:700; font-size:.95rem; }
  /* Тема созвона — утверждённым красным (решение владельца, 27.08.2026).
     Цвет задан и для посещённых ссылок: иначе браузер перекрашивал уже
     открытые темы в сиреневый, и список выглядел разноцветным. */
  .calls-full-name a,
  .calls-full-name a:visited { color:var(--red); text-decoration:none;
    border-bottom:1px solid rgba(var(--red-rgb),.45); }
  .calls-full-name a:hover { border-bottom-color:var(--red); filter:brightness(1.1); }
  .calls-full-people { font-size:.78rem; color:var(--muted); margin-top:4px; }
  /* Контакты занимают свободное место строки — между названием и
     кнопками. Своя колонка, а не приписка к участникам: так они не
     сливаются с именами и не растягивают левый блок. */
  .cf-contacts { flex:0 1 340px; min-width:0; display:flex; flex-direction:column; gap:6px;
                 font-size:.76rem; padding-left:12px; }
  /* Контакты каждого сотрудника — в своей рамке (22.09.2026): без неё
     телефоны, ники и почты трёх человек сливаются в одну кашу, и
     непонятно, где чьи. */
  .cf-contact-row { display:flex; flex-wrap:wrap; align-items:center; gap:5px 8px;
    border:1px solid var(--cf-frame, rgba(255,255,255,.38)); border-radius:10px;
    padding:7px 9px; }
  body.light-mode .cf-contact-row { --cf-frame: rgba(0,0,0,.55); }
  .cf-contact-row + .cf-contact-row { margin-top:2px; }
  /* «Написать в чат» — рядом с почтой. Залитая бирюзовая плашка: это
     действие, а не сведения, поэтому выглядит иначе, чем контакты. */
  .cf-contact-chat { display:inline-flex; align-items:center; gap:.3em;
    padding:.05em .55em; border-radius:7px; cursor:pointer; white-space:nowrap;
    font: inherit; font-size:.92em; color:#fff; background:var(--hover, #14b8a6);
    border:1px solid var(--hover, #14b8a6); transition:.15s; }
  .cf-contact-chat:hover { filter:brightness(1.12); }
  .cf-contact-row .cf-contact-who { flex:1 0 100%; margin-bottom:1px; }
  .cf-contact-who { color:var(--muted); }
  .cf-contact-who b { color:var(--text); font-weight:600; }
  .cf-contacts a { color:var(--text); text-decoration:none; white-space:nowrap; }
  .cf-contacts a:hover { color:var(--hover); text-decoration:underline; }
  .cf-none { color:var(--muted); font-style:italic; }
  /* Карточки контактов свёрнуты по умолчанию (23.09.2026): кнопка
     «👥 Контакты (N)» под участниками на любой ширине; раскрытые — колонкой
     справа на компьютере, во всю ширину строки на телефоне. */
  .cf-contacts { display:none; }
  .calls-full-row.cf-open .cf-contacts { display:flex; }
  .cf-mobile-btns { display:flex; gap:6px; flex-wrap:wrap; }
  .cf-toggle { display:inline-flex; align-items:center; gap:.35em; margin-top:8px; padding:4px 9px;
    border:1px solid var(--border); border-radius:9px; background:transparent; color:var(--text);
    font:inherit; font-size:.78rem; cursor:pointer; }
  .cf-toggle:hover { border-color:var(--hover,#14b8a6); color:var(--hover,#14b8a6); }
  .calls-full-row.cf-open .cf-toggle:not(.cf-chat-toggle), .calls-full-row.cf-chat-open .cf-chat-toggle { border-color:var(--hover,#14b8a6); }
  /* «Чат с: …» свёрнут за кнопкой «💬 Чат (N)» на любой ширине (решение владельца 23.09.2026). */
  .cf-chatwith { display:none; }
  .calls-full-row.cf-chat-open .cf-chatwith { display:block; }
  @media (max-width:900px) {
    .calls-full-row { flex-wrap:wrap; gap:6px 10px; }
    /* Время — своей строкой сверху: название, участники и кнопки получают всю ширину. */
    .calls-full-time { flex:0 0 100%; width:auto; min-width:0; margin-bottom:-4px; }
    .calls-full-row.cf-open .cf-contacts { flex:1 0 100%; order:9; padding-left:0; font-size:.84rem; }
    .calls-full-row.cf-open .cf-contact-row { padding:9px 11px; }
    .calls-full-row.cf-open .cf-contact-row a, .calls-full-row.cf-open .cf-contact-chat { font-size:1em; }
  }

  /* Правка и отмена стоят рядом, и промахнуться легко: разводим их
     просветом и даём каждой заметный отклик под курсором. */
  .calls-full-acts { display:flex; gap:14px; align-items:center; flex:none; padding-left:8px; }
  .calls-full-acts .cal-nav {
    width:30px; height:30px; display:inline-flex; align-items:center; justify-content:center;
    border-radius:8px; padding:0; transition:background-color .15s, color .15s, transform .1s;
  }
  .calls-full-acts .cal-nav:hover { background:var(--card2); transform:translateY(-1px); }
  /* Принять / Отказаться — выделенные кнопки: зелёная и красная рамка с подложкой (23.09.2026). */
  .calls-full-acts .cal-nav[title="Принять"] { width:34px; height:34px; border:1px solid rgba(16,185,129,.5); background:rgba(16,185,129,.12); color:var(--green,#10b981) !important; font-size:1.05rem; }
  .calls-full-acts .cal-nav[title="Принять"]:hover { background:rgba(16,185,129,.24); border-color:var(--green,#10b981); }
  .calls-full-acts .cal-nav[title="Отказаться"], .calls-full-acts .cal-nav[title="Отменить"] { width:34px; height:34px; border:1px solid rgba(239,68,68,.5); background:rgba(239,68,68,.12); color:#ef4444 !important; font-size:1.05rem; }
  .calls-full-acts .cal-nav[title="Отказаться"]:hover, .calls-full-acts .cal-nav[title="Отменить"]:hover { background:rgba(239,68,68,.24); border-color:#ef4444; }
  .calls-full-acts .cal-nav[title="Изменить"] { width:34px; height:34px; border:1px solid var(--border); }
  /* Виджет на главной: те же цвета у галки и креста. */
  .side-cals .cal-nav[title="Принять"] { color:var(--green,#10b981); }
  .side-cals .cal-nav[title="Отказаться"], .side-cals .cal-nav[title="Отменить"] { color:#ef4444; }
  /* Отмена краснеет, правка синеет — по цвету видно, что произойдёт,
     ещё до нажатия. */
  .calls-full-acts .cal-nav[title="Отменить"]:hover { background:rgba(var(--red-rgb),.16); color:var(--red); }
  .calls-full-acts .cal-nav[title="Изменить"]:hover { background:rgba(var(--hover-rgb),.16); color:var(--hover); }
  /* Участник, которому можно написать: подчёркиванием даём понять, что
     по имени можно щёлкнуть. Отключённый сотрудник остаётся текстом. */
  /* Участник — плашка как контакты в карточке справа (23.09.2026): рамка и
     подложка берут цвет статуса (currentColor), поэтому «принял» зелёный,
     «ждём» серый, «отказался» красный без отдельных правил. */
  .cf-person { cursor:pointer; display:inline-flex; align-items:center; gap:.3em; padding:.05em .5em;
    border-radius:7px; border:1px solid color-mix(in srgb, currentColor 35%, transparent);
    background:color-mix(in srgb, currentColor 10%, transparent); transition:.15s; white-space:nowrap; }
  .cf-person:hover { border-color:currentColor; filter:brightness(1.08); }
  .cf-chatwith .cf-person { margin:2px 0; }
  .cf-person-off { opacity:.6; text-decoration:line-through; }

  /* Переписка — панелью справа, а не поверх списка: видно, о каком
     созвоне речь, пока пишешь. */
  .cf-chat { position:fixed; top:0; right:0; bottom:0; width:380px; max-width:100%;
             z-index:1010; background:var(--card); border-left:1px solid var(--border);
             display:flex; flex-direction:column; box-shadow:-6px 0 22px rgba(0,0,0,.25); }
  /* Имя и должность в шапке — заметные: панель открывают из списка, и
     нужно сразу понимать, с кем говоришь и из какой он фирмы. */
  .cf-who-name { font-weight:800; font-size:1rem; color:var(--text); }
  .cf-who-post { display:block; font-size:.76rem; color:var(--hover); font-weight:600; margin-top:2px; }
  /* Цитата: полоска слева, как в основном чате. */
  .cf-quote { border-left:3px solid var(--hover); padding:2px 0 2px 8px; margin-bottom:4px;
              font-size:.76rem; color:var(--muted); overflow:hidden; text-overflow:ellipsis;
              white-space:nowrap; }
  .cf-quote b { display:block; color:var(--hover); font-weight:700; }
  .cf-reply { display:flex; align-items:center; gap:8px; padding:6px 10px;
              background:var(--card2); border-radius:8px; margin-bottom:6px; }
  .cf-emoji { display:flex; flex-wrap:wrap; gap:4px; padding:6px; background:var(--card2);
              border-radius:8px; margin-bottom:6px; max-height:120px; overflow-y:auto; }
  .cf-emoji button, .cf-emoji-btn { background:none; border:1px solid transparent; cursor:pointer;
              font-size:1.05rem; line-height:1; padding:4px 6px; border-radius:6px; }
  .cf-emoji button:hover, .cf-emoji-btn:hover { background:var(--hover-bg); border-color:var(--hover); }
  .cf-msg { cursor:pointer; }
  .cf-chat-head { padding:12px 14px; border-bottom:1px solid var(--border);
                  display:flex; align-items:flex-start; gap:10px; flex:none; }
  .cf-chat-about { font-size:.74rem; color:var(--muted); margin-top:3px; line-height:1.35; }
  /* Крестик закрытия — такая же кнопка, как правка и отмена в строке
     списка: квадрат со скруглением, подложка и краснота под курсором. */
  .cf-chat-head .cal-nav {
    width:30px; height:30px; flex:none; display:inline-flex;
    align-items:center; justify-content:center; border-radius:8px;
    padding:0; cursor:pointer; color:var(--muted); user-select:none;
    transition:background-color .15s, color .15s, transform .1s;
  }
  .cf-chat-head .cal-nav:hover {
    background:rgba(var(--red-rgb),.16); color:var(--red); transform:translateY(-1px);
  }
  .cf-chat-head .cal-nav:active { transform:translateY(0); }
  .cf-chat-body { flex:1; overflow-y:auto; padding:12px 14px;
                  display:flex; flex-direction:column; gap:8px; }
  .cf-msg { max-width:82%; padding:7px 11px; border-radius:12px; font-size:.82rem;
            line-height:1.4; word-break:break-word; }
  .cf-msg.them { align-self:flex-start; background:var(--card2); }
  .cf-msg.me { align-self:flex-end; background:var(--hover); color:#fff; }
  .cf-msg-when { font-size:.66rem; opacity:.65; margin-top:3px; }
  .cf-chat-foot { padding:10px 14px; border-top:1px solid var(--border); flex:none; }
  /* В этой программе у input прописан нижний отступ, а у .btn-primary —
     ширина во всю форму. Внутри панели и то и другое мешает: поле должно
     тянуться, кнопка — оставаться кнопкой. */
  .cf-send { display:flex; gap:8px; align-items:stretch; }
  .cf-send input { flex:1 1 auto; width:auto; margin-bottom:0; }
  .cf-send button { flex:0 0 auto; width:auto; padding:0 18px; margin:0; font-size:1rem; }
  /* Разделитель дня: без него длинная переписка сливается в одну ленту. */
  .cf-day { align-self:center; font-size:.7rem; color:var(--muted); padding:2px 10px;
            background:var(--card2); border-radius:99px; margin:4px 0; }
  /* Отметки доставки: одна галка — ушло, две — прочитано. Пишем их
     помельче времени, чтобы не спорили с текстом сообщения. */
  .cf-ticks { margin-left:6px; font-weight:700; letter-spacing:-2px; }
  .cf-ticks.read { color:#7fe3d4; }
  .cf-chat-seen { font-size:.72rem; color:var(--muted); margin-top:2px; }
  /* Строка «Чат с:» — под создателем, отдельной строкой. */
  .cf-chatwith { margin-top:3px; }
  .cf-chatwith-label { color:var(--muted); }
  /* Маленькая кнопка коробки созвонов: у значков-глифов не было ни рамки,
     ни подписи — теперь видно, что это кнопки и что они делают. */
  .cal-btn { font-size:.68rem; font-weight:700; padding:2px 8px; border-radius:8px;
             border:1px solid var(--border); background:var(--card2); color:var(--text);
             cursor:pointer; white-space:nowrap; flex:none;
             transition:background-color .15s, border-color .15s, color .15s; }
  .cal-btn:hover { border-color:var(--hover); color:var(--hover); background:var(--hover-bg); }
  .cal-btn.danger { color:var(--red); border-color:rgba(var(--red-rgb),.4); }
  .cal-btn.danger:hover { background:rgba(var(--red-rgb),.12); border-color:var(--red); color:var(--red); }
  /* Плюс заметнее: крупный знак, а line-height:1 не даёт ему растянуть
     шапку. Отклик — как у кнопок, а не голый курсор. */
  .cal-plus { font-size:1.25rem; font-weight:700; line-height:1; padding:2px 8px;
              border-radius:8px; border:1px solid transparent;
              transition:background-color .15s, border-color .15s, color .15s; }
  .cal-plus:hover { background:var(--hover-bg); border-color:var(--hover); color:var(--hover) !important; }
  .cf-all { font-weight:800; color:var(--hover); }
  /* Автор над чужим сообщением — только в групповом чате созвона. */
  .cf-msg-author { font-size:.7rem; font-weight:700; color:var(--hover); margin-bottom:2px; }
  .cf-empty { margin:auto; text-align:center; color:var(--muted); font-size:.82rem;
              line-height:1.5; padding:0 20px; }
  .cf-quick { display:flex; flex-wrap:wrap; gap:6px; margin-bottom:8px; }
  .cf-quick button { font-size:.72rem; padding:4px 9px; border-radius:99px;
                     border:1px solid var(--border); background:var(--card2);
                     color:var(--text); cursor:pointer; }
  .cf-quick button:hover { border-color:var(--hover); }
  .side-cals .cal-row .d { width:52px; color:var(--muted); flex:none;
                           font-variant-numeric:tabular-nums; }
  .side-cals .cal-row .n { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .side-cals .cal-row .cal-nav { flex:none; font-size:.8rem; padding:0 4px; }
  .side-cals .cal-note { font-size:.62rem; color:var(--muted); margin-top:7px; line-height:1.3; }


  /* Компактный вид: плитка превращается в строку — значок и название слева,
     уровень доступа справа. Все программы видны без прокрутки. */
  /* В списке ширина та же, что у трёх плиток: иначе ряд сжимался по
     содержимому и всё смещалось при каждом переключении вида. */
  .apps-grid.list { grid-template-columns:1fr; gap:8px; width:880px; max-width:100%; }
  .apps-grid.list .app-tile { display:flex; align-items:center; gap:14px;
                              text-align:left; padding:10px 16px; grid-column:auto; }
  .apps-grid.list .app-tile .icon { font-size:1.7rem; margin:0; }
  .apps-grid.list .app-tile .name { font-size:1.3rem; flex:1; }
  .apps-grid.list .app-tile .access,
  .apps-grid.list .app-tile .soon-badge { margin:0; white-space:nowrap; }
  /* Подпрыгивание при наведении уместно у крупной плитки, у строки — рябит. */
  .apps-grid.list .app-tile:hover { transform:none; }

  .app-tile.wide { grid-column:span 2; }
  /* На узком экране — одна плитка во всю ширину. */
  @media (max-width:620px) {
    .apps-grid { grid-template-columns:1fr; }
    .app-tile.wide { grid-column:auto; }
  }
  .app-tile { background:var(--card); border:1px solid var(--border); border-radius:16px; padding:24px 18px; text-align:center; cursor:pointer; transition:.15s; }
  .app-tile:hover { background:rgba(var(--hover-rgb),.12); border-color:var(--hover); transform:translateY(-3px); }
  .app-tile.disabled { cursor:not-allowed; opacity:.55; }
  /* Программа есть, но роли в неё нельзя: плитку видно, наведение — красное. */
  .app-tile.denied { cursor:not-allowed; }
  .app-tile.denied:hover { background:rgba(var(--red-rgb),.12); border-color:var(--red);
    transform:none; box-shadow:none; }
  .app-tile.denied .name { color:var(--muted); }
  .access.denied-text { color:var(--red); }
  .app-tile.disabled:hover { background:var(--card); border-color:var(--border); transform:none; box-shadow:none; }
  .app-tile .icon { font-size:2.4rem; margin-bottom:10px; line-height:1; display:inline-block; }
  /* Значок плитки приветственно покачивается под курсором. Анимация висит
     на :hover и доигрывает один раз; людям с отключённой анимацией в
     системе не показывается. */
  .app-tile:hover .icon { animation: tileWiggle .55s ease-in-out; }
  @keyframes tileWiggle {
    0%   { transform: rotate(0)      scale(1); }
    25%  { transform: rotate(-9deg)  scale(1.12); }
    50%  { transform: rotate(8deg)   scale(1.12); }
    75%  { transform: rotate(-4deg)  scale(1.06); }
    100% { transform: rotate(0)      scale(1); }
  }
  @media (prefers-reduced-motion: reduce) {
    .app-tile:hover .icon { animation: none; }
  }
  /* Внимание: ниже по файлу, в блоке «12 плиток», эти же размеры
     задаются заново — действует именно тот, поздний блок. */
  .app-tile .name { font-weight:700; font-size:1.3rem; letter-spacing:.2px; }
  .app-tile .access { font-size:.85rem; color:var(--muted); margin-top:8px; }
  /* Уровень доступа на плитке — теми же цветами, что в разделе «Роли»:
     зелёный и жёлтый; красный взят от секундной стрелки часов, чтобы
     один и тот же цвет на странице не был двух оттенков. Раньше подпись
     всегда была серой, и
     «Полный доступ» на глаз не отличался от «Только просмотр». */
  .app-tile .access.acc-full { color:var(--green); font-weight:600; }
  .app-tile .access.acc-read { color:#f59e0b; font-weight:600; }
  .app-tile .access.denied-text { color:var(--red); font-weight:600; }
  .app-tile .soon-badge { display:inline-block; margin-top:6px; padding:3px 10px; border-radius:99px; font-size:.72rem; font-weight:700; background:rgba(127,127,127,.2); color:var(--muted); }
  /* Янтарный читается и на светлой, и на тёмной теме — тем же цветом
     показано вечернее время на часах. */
  .badge.role-owner { background:rgba(245,158,11,.18); border-color:#f59e0b;
                      color:#f59e0b; font-weight:700; }
  .role-card-title.role-owner-title { color:#f59e0b; }
  .badge.role-admin { background:rgba(16,185,129,.18); border-color:#10b981;
                      color:#10b981; font-weight:700; }
  .role-card-title.role-admin-title { color:#10b981; }
  /* Директор — третья роль с полными правами. Сиреневый: янтарный и
     зелёный заняты владельцем и администратором. */
  .badge.role-director { background:rgba(176,124,199,.18); border-color:#b07cc7;
                         color:#b07cc7; font-weight:700; }
  .role-card-title.role-director-title { color:#b07cc7; }
  #r_key[readonly] { background:var(--card2); color:var(--muted); cursor:default; }
  /* Свёрнутый вид: карточек два десятка, и когда нужен только перечень
     ролей, права и списки людей мешают смотреть. */
  #app.roles-hide-pills .access-pills  { display:none; }
  #app.roles-hide-emps  .role-emp-list { display:none; }
  #app.roles-hide-pos   .positions-box  { display:none; }
  /* Отделы сворачиваются отдельно от должностей. Свой класс обязателен:
     общий с должностями прятал справочник заодно с ними. */
  #app.roles-hide-dept  .departments-box { display:none; }
  #app.roles-hide-t1    .roles-grid-t1  { display:none; }
  #app.roles-hide-t2    .roles-grid-t2  { display:none; }
  /* Должности живут в такой же карточке, что и роли: два перечня на
     одной странице должны выглядеть одинаково. */
  .positions-box, .departments-box { background:var(--card); border:1px solid var(--border);
                   border-radius:14px; padding:8px 14px 4px; }
  /* Поиск по ролям отдела: узкая строка над сеткой карточек. */
  /* Закреплённая шапка раздела: фон обязателен — без него сквозь неё
     просвечивает уезжающий список. Ниже окон (z-index 1100), чтобы
     карточки открывались поверх. */
  .header-sticky { position:sticky; top:0; z-index:30; background:var(--bg);
                   padding:10px 0 12px; margin-bottom:18px;
                   border-bottom:1px solid var(--border); }
  .t2-search-row { display:flex; align-items:center; gap:10px; margin:0 0 12px; }
  .t2-search-row input { max-width:420px; }
  .t2-count { font-size:.82rem; color:var(--muted); white-space:nowrap; }
  #app.roles-hide-t2 .t2-search-row { display:none; }
  .positions-box table { margin:0; }
  .pos-filter-row th { padding:5px 6px !important; font-weight:400;
                       border-top:1px solid var(--border); }
  .pos-filter-row input, .pos-filter-row select { margin:0; width:100%;
                       font-size:.8rem; padding:3px 5px; }
  /* Заголовок раздела сворачивается двойным щелчком — курсор об этом
     говорит, подсказка тоже. */
  .tier-label { cursor:pointer; user-select:none;
                display:flex; align-items:center; gap:8px; min-height:30px;
                /* Заголовок сворачивает раздел двойным щелчком — значит,
                   он кнопка, и при наведении должен выглядеть кнопкой.
                   Рамка и поля заданы заранее прозрачными, чтобы соседние
                   строки не прыгали в момент наведения. */
                width:fit-content; max-width:100%; padding:4px 12px;
                border:1px solid transparent; border-radius:10px;
                transition:background-color .15s, border-color .15s, color .15s; }
  .tier-label:hover { background:var(--card2); border-color:var(--hover);
                      color:var(--hover); }
  /* Кнопка внутри заголовка не должна задавать его высоту. */
  .tier-label button { padding:4px 12px; font-size:.75rem; }
  /* Глиф стрелки приходит из запасного шрифта с большими метриками —
     без этого он один растягивал строку с 14 до 46 пикселей. */
  .tier-caret { display:inline-block; font-size:.8rem; line-height:1;
                width:12px; flex:none; }
  /* Переключатели вида стоят своей группой: между ними просвет меньше,
     чем до кнопок-действий слева, — так видно, что это одно целое. */
  .roles-view-toggles { display:flex; gap:6px; margin-left:6px; }
  /* Свёрнутый вид должен быть заметно плотнее, иначе он не экономит место:
     карточки уже, отступы меньше, а когда скрыто и то и другое — шапка
     остаётся единственным содержимым, и нижний отступ ей не нужен. */
  #app.roles-hide-pills .roles-grid { grid-template-columns:repeat(auto-fit,minmax(230px,1fr)); gap:12px; }
  #app.roles-hide-pills .role-card { padding:12px 14px; }
  #app.roles-hide-pills.roles-hide-emps .role-card-head { margin-bottom:0; }
  /* Свёрнутая карточка узкая, и счётчик отъедал у названия половину строки.
     Ставим его под названием — длинные роли умещаются в одну строку. */
  #app.roles-hide-pills .role-card-head { flex-direction:column; align-items:flex-start; gap:4px; }
  #app.roles-hide-pills .role-card-head button { padding:2px 7px; font-size:.72rem; }
  .badge { display:inline-block; padding:3px 10px; border-radius:99px; font-size:.72rem; font-weight:700; background:rgba(59,130,246,.15); color:var(--accent); }
  /* Цветные варианты таблеток — те же значения, что в Учебном центре
     (Edu/style.css), чтобы один и тот же статус выглядел одинаково в
     обеих программах. Свои цвета здесь заводить нельзя. */
  .badge-blue   { background:rgba(138,180,212,.20); color:#8AB4D4; border:1px solid rgba(138,180,212,.35); }
  .badge-green  { background:rgba(16,185,129,.20);  color:#34d399; border:1px solid rgba(16,185,129,.35); }
  .badge-red    { background:rgba(239,68,68,.20);   color:#f87171; border:1px solid rgba(239,68,68,.35); }
  .badge-yellow { background:rgba(245,158,11,.20);  color:#fbbf24; border:1px solid rgba(245,158,11,.35); }
  .badge-gray   { background:rgba(138,180,212,.12); color:#8AB4D4; border:1px solid rgba(138,180,212,.25); }
  .badge-orange { background:rgba(249,115,22,.20);  color:#fb923c; border:1px solid rgba(249,115,22,.35); }
  .badge-purple { background:rgba(168,85,247,.22);  color:#c084fc; border:1px solid rgba(168,85,247,.35); }
  /* Колонка статуса не должна рябить: таблетки одной ширины и по центру,
     как «Тип обучения» в списке курсов. */
  .hr-status { min-width:132px; justify-content:center; text-align:center; display:inline-block; }
  .btn-secondary { padding:8px 16px; background:var(--card2); border:1px solid var(--border); color:var(--text); }
  /* «Выйти» и «← Назад»: прозрачная рамка задана заранее, чтобы при
     наведении подсветка появлялась без сдвига соседних элементов */
  /* Выход — единственное действие в шапке, которое стоит заметить не сразу,
     а когда ищешь его глазами. Отсюда бордовый вместо приглушённого серого. */
  .btn-logout { color:var(--red) !important; }
  .btn-logout:hover { color:var(--red) !important; filter:brightness(1.2); }
  /* «Выйти» стоит особняком, и общая рамка фокуса с полями кнопки-ссылки
     обводила его кольцом заметно крупнее самой надписи. Поджимаем поля
     и отступ обводки, чтобы она шла по тексту. */
  .btn-logout { padding:3px 8px; border-radius:8px; }
  .btn-logout:focus-visible { outline-width:1.5px; outline-offset:1px; }
  /* «Назад» — кнопка общего формата, но утверждённым красным:
     выход со страницы должен читаться сразу. */
  .btn-secondary.btn-back { color:#ef4444; }
  /* «Копии» и «Выйти» в правой колонке шапки: один класс задаёт размер
     обеим, чтобы им было не с чего разъехаться. !important — общий слой
     ui.css грузится последним и уже перебивал точечные подгонки. */
  .hdr-col-btn {
    width: 128px !important; box-sizing: border-box !important;
    padding: 8px 6px !important; font-size: .8rem !important;
    white-space: nowrap; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .btn-secondary.btn-back:hover { color:#ef4444; border-color:#ef4444; }
  .btn-link { background:none; color:var(--muted); text-decoration:underline;
              padding:6px 10px; border:1px solid transparent; border-radius:10px; font-size:.82rem; }

  table { width:100%; border-collapse:collapse; font-size:.85rem; margin-top:20px; }
  th, td { padding:10px 12px; text-align:left; border-bottom:1px solid var(--border); }
  th { color:rgba(59,130,246,.85); font-size:.72rem; text-transform:uppercase; }
  .modal-overlay { position:fixed; inset:0; background:rgba(0,0,0,.6); display:flex; align-items:center; justify-content:center; z-index:1100; padding:20px; }
  .modal { background:var(--card); border:1px solid var(--border); border-radius:14px; padding:26px; width:100%; max-width:460px;
           max-height:calc(100vh - 40px); overflow-y:auto; }
  /* Широкое окно для форм с большим числом полей */
  .modal-wide { max-width:920px; }
  /* Поля в две колонки. Строке можно вернуть всю ширину классом full —
     это нужно длинным подписям и блокам вроде списка исключений. */
  .form-2col { display:grid; grid-template-columns:1fr 1fr; gap:0 22px; align-items:start; }
  .form-2col .full { grid-column:1 / -1; }
  /* На узком экране две колонки не помещаются — возвращаем один столбец */
  @media (max-width:760px){ .form-2col { grid-template-columns:1fr; } }
  /* Окно роли: полей много (девять программ + чат), и в двух столбцах оно
     не помещалось на экран — появлялась боковая прокрутка, а «Удалить роль»
     пряталась под липкой полосой кнопок. Сетка из шести долей: название и
     ключ занимают по три (те же полширины), доступы — по две, то есть по
     три в ряд. Высота падает почти вдвое. */
  .role-modal { max-width:1080px; padding:18px 22px; }
  /* Уплотнение подобрано в браузере на экране 1366×768: с ним окно
     занимает 682 точки при доступных 728 — запас есть даже с панелью
     закладок. Без него оставался один пиксель, и прокрутка возвращалась. */
  .role-modal h3 { margin-bottom:10px; font-size:1.1rem; }
  /* Колонок столько, сколько поместится, но ни одна не уже самой длинной
     надписи («🟡 Только просмотр») вместе со значком, стрелкой списка и
     отступами. Прежняя жёсткая сетка «ровно три в ряд» обрезала текст:
     значки на разных системах рисуются разными шрифтами и занимают
     разную ширину. */
  .role-modal .form-2col { grid-template-columns:repeat(auto-fit, minmax(268px, 1fr)); gap:0 18px; }
  .role-modal .form-2col > .rm-name { grid-column:1 / -1; }
  /* Списку — вся ширина ячейки и место справа под стрелку, чтобы текст в
     неё не упирался. */
  .role-modal .form-2col select { width:100%; padding-right:30px; text-overflow:ellipsis; }
  .role-modal .form-2col label { margin-bottom:2px; }
  .role-modal .form-2col input,
  .role-modal .form-2col select { margin-bottom:7px; }
  /* Между «Удалить роль» и полосой кнопок — воздух: липкая полоса
     наезжает на содержимое, и без отступа кнопка обрезалась. */
  .role-modal .form-2col .full { margin-top:4px; }
  .role-modal .modal-actions { margin-top:8px; padding-top:10px; }
  /* На узком экране три столбца не читаются — обратно в один */
  @media (max-width:900px){
    .role-modal .form-2col { grid-template-columns:1fr; }
    .role-modal .form-2col > div { grid-column:1 / -1; }
  }
  /* Свои окна вместо браузерных (confirm/alert/prompt). Выше окон-форм
     (1100), потому что спрашивают как раз о том, что в них происходит. */
  .ui-dlg-overlay { position:fixed; inset:0; background:rgba(0,0,0,.55); display:flex;
    align-items:center; justify-content:center; z-index:1200; padding:20px; }
  .ui-dlg { background:var(--card); border:1px solid var(--border); border-radius:14px;
    padding:22px 24px; width:100%; max-width:460px; box-shadow:0 18px 50px rgba(0,0,0,.45); }
  /* pre-line сохраняет пустые строки из текстов: в них поясняется
     последствие, и слипшимся абзацем это не читается. */
  .ui-dlg-text { white-space:pre-line; font-size:.94rem; line-height:1.5; color:var(--text); }
  .ui-dlg input { width:100%; margin:14px 0 0; }
  .ui-dlg-acts { display:flex; gap:10px; margin-top:18px; }
  /* width:auto перебивает общее правило кнопок на всю ширину */
  .ui-dlg-acts button { flex:1 1 0; width:auto; margin:0; padding:11px 12px; font-weight:600; }
  .ui-dlg-yes { background:var(--green); border-color:var(--green); color:#fff; }
  .ui-dlg-yes.danger { background:var(--red); border-color:var(--red); color:#fff; }
  .ui-dlg-acts button:hover { filter:brightness(1.12); }
  /* Вопрос вместо кнопки: тот же красный, что у самого действия, чтобы
     было видно — спрашивают именно про удаление. */
  .ask-inplace { margin-top:6px; padding:10px 12px; border-radius:10px;
    background:rgba(var(--red-rgb),.10); border:1px solid var(--red); }
  .ask-inplace .ask-text { font-size:.84rem; color:var(--red); font-weight:600; margin-bottom:8px; }
  .ask-inplace .ask-btns { display:flex; gap:8px; }
  /* width:auto перебивает общее правило кнопок на всю ширину — иначе
     «Да» и «Отмена» встали бы друг под другом. */
  .ask-inplace .ask-btns button { flex:1 1 0; width:auto; margin:0; padding:8px 10px; font-size:.84rem; }
  .ask-inplace .ask-yes { background:var(--red); border-color:var(--red); color:#fff; font-weight:700; }
  .ask-inplace .ask-yes:hover { filter:brightness(1.12); }
  /* Ответ сервера — там же, где спрашивали, а не отдельным окном сверху. */
  .modal-err { margin-top:8px; padding:10px 12px; border-radius:10px; font-size:.84rem;
    background:rgba(var(--red-rgb),.10); border:1px solid var(--red); color:var(--red); }
  /* Кнопки формы всегда видны: прижаты к низу окна и не уезжают за край */
  .modal-actions { position:sticky; bottom:-26px; background:var(--card);
                   padding:14px 0 0; margin-top:16px; display:flex; gap:10px; }
  /* Цвет по смыслу действия: сохранение — зелёным, отмена — красным.
     Селектор из двух классов перебивает общий ховер кнопок: вес выше,
     и порядок в файле уже не важен. */
  .modal-actions .btn-primary, .modal-actions .btn-secondary { transition:background-color .15s, border-color .15s, color .15s; }
  .modal-actions .btn-primary   { background:var(--green); border-color:var(--green); color:#fff; }
  .modal-actions .btn-secondary { background:var(--red);   border-color:var(--red);   color:#fff; }
  /* Третий свет: действие нужное, но с последствием за пределами окна —
     карточка с паролем ложится файлом на диск. Янтарный тот же, что у
     владельца в ролях и у вечернего времени на часах. */
  .modal-actions .btn-warn      { background:#f59e0b;      border-color:#f59e0b;      color:#fff; }
  /* Наведение теперь заметно только подсветкой: цвет уже занят смыслом. */
  .modal-actions .btn-primary:hover,
  .modal-actions .btn-warn:hover,
  .modal-actions .btn-secondary:hover { filter:brightness(1.12); }
  .row { display:flex; gap:10px; }

  .theme-switch { position:relative; width:52px; height:26px; background:var(--card2); border:1px solid var(--border); border-radius:99px; cursor:pointer; display:flex; align-items:center; justify-content:space-between; padding:0 6px; flex-shrink:0; }
  .theme-switch .ts-icon { font-size:.7rem; line-height:1; z-index:1; user-select:none; }
  .theme-switch .ts-knob { position:absolute; top:2px; left:2px; width:20px; height:20px; border-radius:50%; background:linear-gradient(135deg,var(--accent),var(--accent2)); transition:left .2s ease; box-shadow:0 2px 6px rgba(0,0,0,.3); }
  body.light-mode .theme-switch .ts-knob { left:28px; }

  .roles-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:16px; }
  /* Должность, у которой роль удалили. Красный — единый цвет ошибки во
     всех программах (#ef4444). Фиолетовый занят ролью «Директор», и
     плашка-сирота рядом с директорской читалась бы как ещё одна роль. */
  .badge.role-gone { background:rgba(var(--red-rgb),.14); border-color:var(--red); color:var(--red); font-weight:700; }
  .role-card { background:var(--card); border:1px solid var(--border); border-radius:14px; padding:20px; }
  /* «Вот куда сохранилось»: после записи роли её карточка подсвечивается
     и получает плашку. Убирается само через несколько секунд. */
  .role-card.just-saved { border-color:#14b8a6; box-shadow:0 0 0 3px rgba(20,184,166,.25);
    position:relative; transition:border-color .4s, box-shadow .4s; }
  .role-card.just-saved::before { content:'✓ Сохранено здесь'; position:absolute; top:-11px; left:14px;
    background:#14b8a6; color:#fff; font-size:.72rem; font-weight:700;
    padding:2px 10px; border-radius:99px; }
  .role-card.tier1 { border-color:rgba(16,185,129,.35); }
  /* Зазор и запрет переноса у счётчика: без них «0 пользователей» вплотную
     прилипало к длинному названию и читалось как одно слово. */
  .role-card-head { display:flex; justify-content:space-between; align-items:flex-start;
                    gap:10px; margin-bottom:10px; }
  /* Длинные слова вроде «Операционный» не переносятся сами и наезжали на
     счётчик. Разрешаем перенос внутри слова, а счётчику запрещаем сжиматься:
     иначе текст вылезал за свою рамку и рисовался поверх названия. */
  /* anywhere рвал слова где придётся: «Делопроиз-водитель», «Регистрато-р».
     break-word переносит по пробелам и лезет внутрь слова только когда оно
     не помещается целиком, а hyphens:auto делит его по слогам — для этого
     у страницы должен быть указан русский язык. */
  .role-card-title { font-weight:700; font-size:1rem; flex:1 1 auto; min-width:0;
                     overflow-wrap:break-word; hyphens:auto; }
  /* Роль — синим, люди — бирюзовым: в карточке они стоят вплотную, и
     одинаковый приглушённый цвет читался как продолжение названия. */
  .role-card-count { font-size:.78rem; color:var(--hover); white-space:nowrap; flex:0 0 auto; }
  .access-pills { display:flex; gap:6px; margin-bottom:14px; }
  .access-pill { font-size:.7rem; font-weight:700; padding:3px 9px; border-radius:99px; }
  .access-full { background:rgba(16,185,129,.18); color:var(--green); }
  .access-read { background:rgba(245,158,11,.18); color:#f59e0b; }
  .access-none { background:rgba(var(--red-rgb),.20); color:var(--red); }
  body.light-mode .access-none { background:rgba(var(--red-rgb),.12); }
  .role-emp-list { display:flex; flex-direction:column; gap:6px; max-height:180px; overflow-y:auto; }
  .role-emp-item { font-size:.85rem; padding:6px 10px; background:var(--card2); border-radius:8px; display:flex; justify-content:space-between; align-items:center; }
  .role-emp-item > span:first-child { color:var(--hover); }
  /* Подписи занимают одинаковую ширину, поэтому «Полный доступ», «Только
     просмотр» и «Нет доступа» начинаются с одной вертикали. Раньше плашки
     плясали вслед за длиной слова, и колонку было тяжело читать сверху вниз. */
  .access-pills > span:first-child { flex:0 0 92px; }
  .role-emp-empty { font-size:.82rem; color:var(--muted); font-style:italic; }

  .ab-toggle { position:relative; width:48px; height:26px; background:var(--card2); border:1px solid var(--border); border-radius:99px; cursor:pointer; flex-shrink:0; transition:.2s; }
  .ab-toggle .ab-knob { position:absolute; top:2px; left:2px; width:20px; height:20px; border-radius:50%; background:var(--muted); transition:.2s; }
  .ab-toggle.on { background:rgba(16,185,129,.2); border-color:var(--green); }
  .ab-toggle.on .ab-knob { left:24px; background:var(--green); }
  .settings-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr)); gap:14px; margin-bottom:16px; }
  .backup-table { width:100%; border-collapse:collapse; font-size:.85rem; margin-top:16px; }
  .backup-table th, .backup-table td { padding:10px 12px; text-align:left; border-bottom:1px solid var(--border); }
  .backup-table th { color:rgba(59,130,246,.85); font-size:.72rem; text-transform:uppercase; }
  /* Подсветка строки резервной копии. Рамку рисуем внутренними тенями, а не
     border: тень не занимает места, поэтому строка не дёргается на 1px при
     наведении. Боковые грани — только у крайних ячеек, чтобы вышел один
     прямоугольник на всю строку, а не рамка вокруг каждой ячейки. */
  table tbody tr td { transition:background-color .15s, box-shadow .15s; }
  table tbody tr:hover td { background:var(--card2); box-shadow:inset 0 1px 0 var(--accent2), inset 0 -1px 0 var(--accent2); }
  table tbody tr:hover td:first-child { box-shadow:inset 0 1px 0 var(--accent2), inset 0 -1px 0 var(--accent2), inset 1px 0 0 var(--accent2); }
  table tbody tr:hover td:last-child  { box-shadow:inset 0 1px 0 var(--accent2), inset 0 -1px 0 var(--accent2), inset -1px 0 0 var(--accent2); }
  .tier-label { font-size:.72rem; font-weight:700; text-transform:uppercase; letter-spacing:.05em; color:var(--muted); margin:22px 0 12px; }
  .tier-label:first-child { margin-top:0; }
/* Подсветка только что сохранённой строки таблицы */
tr.row-flash td { animation: rowFlash 4s ease-out; }
@keyframes rowFlash {
  0%   { background: rgba(99, 140, 255, .28); }
  60%  { background: rgba(99, 140, 255, .18); }
  100% { background: transparent; }
}

/* ── Единая палитра наведения для кнопок (вся программа) ──
   Правило: обычные кнопки — бирюза (морская волна), подтверждение —
   зелёный, опасные (удаление) — красный. Блок в конце — перекрывает
   разрозненные старые ховеры. */
.btn-primary, .btn-secondary, .btn-link, .theme-switch, .bk-download, .bk-delete {
  transition: background-color .15s, border-color .15s, color .15s;
}
.btn-secondary:hover, .btn-link:hover, .theme-switch:hover, .hoverable:hover {
  background: rgba(var(--hover-rgb),.12);
  border-color: var(--hover);
  color: var(--text);
}
.btn-primary:hover, .modal-actions .btn-primary:hover {
  background: var(--green); border-color: var(--green); color: #fff;
}
/* Цвет кнопок окна задан выше: сохранение зелёное, отмена красная.
   Прежнее бирюзовое правило стояло ниже по файлу и перебивало их. */
/* Опасные действия: кнопка опасна и в покое, а не только под курсором.
   В покое — красная плашка с ярким красным текстом (видно, что действие
   особое), при наведении — сплошной красный с белыми буквами: текст не
   сливается с фоном ни в одном состоянии. */
.btn-secondary[onclick^="deletePosition"],
.btn-secondary[onclick^="deleteRole"],
.btn-secondary[onclick^="deleteCounterparty"],
.btn-secondary[onclick^="deleteCustomer"],
.btn-secondary[onclick^="deleteOrg"],
.btn-secondary[onclick^="deleteEmployee"] {
  background: rgba(239,68,68,.12); border-color: rgba(239,68,68,.4);
  color: #ef4444 !important; font-weight: 700;
}
.bk-delete:hover,
.btn-secondary[onclick^="deletePosition"]:hover,
.btn-secondary[onclick^="deleteRole"]:hover,
.btn-secondary[onclick^="deleteCounterparty"]:hover,
.btn-secondary[onclick^="deleteCustomer"]:hover,
.btn-secondary[onclick^="deleteOrg"]:hover,
.btn-secondary[onclick^="deleteEmployee"]:hover {
  background: var(--red); border-color: var(--red); color: #fff !important;
}
/* ── Полоса компаний группы внизу главной ── */
/* ── Правила: строка вкладок ── */
/* Строка вкладок остаётся на виду при прокрутке длинного раздела:
   без этого, уехав вниз по тексту, переключиться было невозможно.
   Фон обязателен — иначе текст просвечивает сквозь закреплённую панель. */
.rules-tabs {
  display:flex; gap:8px; flex-wrap:wrap; overflow-x:visible;   /* площадки переносятся на новую строку, без прокрутки вбок (20.09.2026) */
  padding:10px 0 12px; margin-bottom:8px;
  border-bottom:1px solid var(--border);
  position:sticky; top:0; z-index:20; background:var(--bg);
}
.rules-tab {
  /* Кнопки одной ширины растягиваются на всю строку, подпись по центру —
     поле занято целиком, промежутки одинаковые (решение владельца 20.09.2026). */
  flex:1 1 calc((100% - (var(--rt-cols, 6) - 1) * 8px) / var(--rt-cols, 6)); min-width:0;
  text-align:center; padding:8px 10px; overflow:hidden; text-overflow:ellipsis; border:1px solid var(--border); border-radius:9px;
  background:var(--card2); color:var(--muted); font:inherit; font-size:.9rem; cursor:pointer;
  white-space:nowrap; transition:background-color .15s, border-color .15s, color .15s;
}
.rules-tab:hover { background:rgba(var(--hover-rgb),.12); border-color:var(--hover); color:var(--text); }
.rules-tab.active { background:rgba(var(--hover-rgb),.18); border-color:var(--hover); color:var(--text); font-weight:600; }
/* Свёрнутый раздел: видна только шапка с заголовком и знаком «+».
   Развёрнутый показывает «−» — знак и есть переключатель, отдельная
   кнопка рядом с заголовком была бы лишней мишенью. */
.rules-sec { border:1px solid var(--border); border-radius:12px;
             background:var(--card); margin-bottom:10px; }
.rules-sum { cursor:pointer; list-style:none; padding:12px 16px;
             font-weight:800; font-size:.86rem; letter-spacing:.03em; color:var(--text);
             display:flex; align-items:center; gap:10px;
             transition:background-color .15s; border-radius:12px; }
.rules-sum::-webkit-details-marker { display:none; }
.rules-sum::before { content:'+'; width:18px; text-align:center;
                     color:var(--hover); font-weight:800; }
.rules-sec[open] > .rules-sum::before { content:'\2212'; }
.rules-sum:hover { background:rgba(var(--hover-rgb),.10); }
.rules-sec > .rules-pre { margin:0; padding:0 16px 14px; }
/* Шапка правил закреплена целиком: уехав вниз по длинному разделу, надо
   мочь и переключить вкладку, и скачать файл, и вернуться назад. */
.rules-sticky { position:sticky; top:0; z-index:22; background:var(--bg); padding-top:6px; }
.rules-sticky .header { margin-bottom:6px; }
.rules-sticky .rules-tabs { position:static; }
.rules-dl { margin-left:auto; padding:0 8px; color:var(--muted); font-weight:400;
            border-radius:6px; transition:color .15s, background-color .15s; }
.rules-dl:hover { color:var(--hover); background:rgba(var(--hover-rgb),.12); }
.rk-step { color:#e6edf3; font-weight:800; }
body.light-mode .rk-step { color:#0f172a; }
.demo-badge {
  display:inline-flex; align-items:center; gap:6px; white-space:nowrap;
  padding:4px 10px; border-radius:999px; font-size:.82rem; font-weight:600;
  background:rgba(245,158,11,.14); border:1px solid rgba(245,158,11,.45); color:#f59e0b;
}
/* За неделю до конца срока цвет меняется на тревожный: чтобы о продлении
   вспомнили заранее, а не в день отключения. */
.demo-badge.expiring { background:rgba(var(--red-rgb),.14); border-color:rgba(var(--red-rgb),.5); color:var(--red); }
.companies-bar {
  display:flex; align-items:center; justify-content:center; flex-wrap:wrap;
  gap:6px 10px; margin-top:48px; padding:16px 0 6px; border-top:1px solid var(--border);
}
.companies-bar a {
  color:var(--muted); text-decoration:none; font-size:1.02rem; white-space:nowrap;
  padding:4px 8px; border-radius:6px; border:1px solid transparent;
  transition:color .15s, background-color .15s, border-color .15s;
}
.companies-bar a:hover { color:var(--text); background:rgba(var(--hover-rgb),.12); border-color:var(--hover); }
.companies-sep { color:var(--border); }
.companies-plain { color:var(--muted); font-size:1.02rem; padding:4px 8px; white-space:nowrap; }
/* ── Навигация главной: по центру, кнопки одной ширины ── */
.header-nav { display:flex; gap:10px; align-items:center; justify-content:center; flex:0 1 880px; flex-wrap:wrap;
  /* Та же ширина, что у трёх плиток, — полоса кнопок и сетка идут по одной линии. */
  max-width:880px; margin:0 auto; }
  /* Переходы между разделами — ссылки, а не кнопки: пункт «Открыть в новой
     вкладке» браузер предлагает только для ссылок, у кнопки его нет. Вид
     остаётся кнопочным, поэтому здесь повторено то, что <a> не наследует
     от <button>: указатель, скругление, начертание, отсутствие подчёркивания. */
  a.btn-secondary { display:inline-flex; align-items:center; justify-content:center;
    gap:6px; cursor:pointer; border-radius:9px; font-weight:700; font-size:.9rem;
    text-decoration:none; }
  /* Вес селектора выше, чем у .nav-btn, поэтому размер шрифта возвращаем явно */
  a.nav-btn { font-size:.8rem; }
/* Кнопки делят полосу поровну и заполняют её целиком: тогда их края
   совпадают с краями блока плиток, а второй ряд не появляется. */
.nav-btn { flex:1 1 0; min-width:0; text-align:center; white-space:nowrap;
           overflow:hidden; text-overflow:ellipsis; font-size:.8rem;
           padding-left:6px; padding-right:6px; }

    /* Строка фильтров под заголовками таблицы пользователей */
    .emp-filter-row th { background:var(--card2,#f1f3f7); padding:5px 6px !important;
      font-weight:400; border-top:1px solid var(--border,#e3e6ec); }
    .emp-filter-row select, .emp-filter-row input { margin:0; }

/* ── Отклик на наведение и фокус ──────────────────────────
   Поля ввода и списки раньше никак не отзывались: у них не было ни ховера,
   ни рамки фокуса, и понять, куда именно ты попал, можно было только по
   курсору. Цвет — та же бирюза, что у кнопок, чтобы отклик читался одинаково
   во всей программе. */
input:not(:disabled):not([readonly]):hover,
select:not(:disabled):hover,
textarea:not(:disabled):not([readonly]):hover {
  border-color: var(--hover);
}
input:not(:disabled):not([readonly]):focus,
select:not(:disabled):focus,
textarea:not(:disabled):not([readonly]):focus {
  outline: none;
  border-color: var(--hover);
  box-shadow: 0 0 0 3px rgba(var(--hover-rgb),.18);
}
input, select, textarea { transition: border-color .15s, box-shadow .15s; }
/* Заблокированные поля честно показывают, что их не тронуть. */
input:disabled, select:disabled, textarea:disabled { cursor: not-allowed; opacity: .8; }

/* Кнопкам добавляем отклик формой, а не только цветом: подъём с тенью при
   наведении и нажатие при щелчке. Цвета остаются прежними — бирюза для
   обычных, зелёный для подтверждения, красный для опасных. */
.btn-primary, .btn-secondary, .btn-link, .bk-download, .bk-delete {
  transition: background-color .15s, border-color .15s, color .15s,
              box-shadow .15s, transform .1s;
}
.btn-primary:hover, .btn-secondary:hover, .btn-link:hover,
.bk-download:hover, .bk-delete:hover {
  box-shadow: 0 3px 10px rgba(0,0,0,.18);
}
.btn-primary:active, .btn-secondary:active, .btn-link:active,
.bk-download:active, .bk-delete:active {
  transform: translateY(1px);
  box-shadow: none;
}
/* Обводка для тех, кто ходит с клавиатуры: :focus-visible не появляется от
   щелчка мышью, поэтому обычную работу она не загромождает. */
.btn-primary:focus-visible, .btn-secondary:focus-visible, .btn-link:focus-visible,
.theme-switch:focus-visible, .app-tile:focus-visible {
  outline: 2px solid var(--hover);
  outline-offset: 2px;
}
/* Плитка программы и переключатель темы — тоже элементы управления. */
.theme-switch { transition: background-color .15s, border-color .15s, box-shadow .15s; }
.theme-switch:hover { box-shadow: 0 3px 10px rgba(0,0,0,.18); }


/* ── 12 плиток (28.08.2026): компактнее, по четыре в ряд ──
   Плиток стало двенадцать: прежний размер 284px давал три ряда по три и
   хвост. Уменьшаем плитку, чтобы сетка собиралась в три ряда по четыре. */
.apps-grid { grid-template-columns:repeat(auto-fit, 205px); max-width:900px; gap:12px; }
.app-tile { padding:14px 10px; }
.app-tile .icon { font-size:1.55rem; margin-bottom:4px; }
/* Крупнее на два шага (04.09.2026, решение владельца). Это действующие
   размеры подписей на плитках — правило выше по файлу они перекрывают. */
.app-tile .name { font-size:1.15rem; }
.app-tile .access, .app-tile .soon-badge { font-size:.9rem; }


/* ── симметрия главной 29.08.2026 ──
   1) Ряд «часы + плитки + календарь» центрируется по вертикали: авто-отступы
      делят свободную высоту поровну сверху и снизу, полоса фирм остаётся
      прижатой к низу. Раньше контент лип к шапке, а весь запас высоты
      скапливался снизу.
   2) Сетка плиток растягивается на высоту ряда, а ряды расходятся
      равномерно — нижний ряд плиток встаёт на одну линию с нижними часами
      и низом блока «Созвоны» (те и так тянутся на всю высоту ряда).
      Вид «списком» не трогаем: там растяжка рвала бы строки. */
.main-row { margin-top:auto; margin-bottom:auto; }
.companies-bar { margin-top:0; }
.main-row .apps-grid:not(.list) { align-self:stretch; align-content:space-between; }


/* ── компактная главная 29.08.2026 (следом за симметрией) ──
   Шапка стала двухэтажной (имя над кнопками), и страница перестала
   влезать в высоту окна — появилась прокрутка. Ужимаем вертикальные поля
   только на главной (класс launcher-home), остальные разделы не трогаем. */
.launcher-home { padding-top:18px; padding-bottom:10px; }
.launcher-home .header { margin-bottom:0; }
.launcher-home .companies-bar { padding:10px 0 2px; margin-top:0; }
/* Часы — самый высокий столбец и главный виновник высоты ряда: позволяем
   циферблатам ужиматься, ряд перестаёт распирать страницу. */
.launcher-home .world-clocks > div { min-height:0; }


/* ── Часы в строке с именем ─────────────────────────────────
   Раскладка (ряд, размер циферблата) задана прямо в разметке в app.js —
   она не должна зависеть от того, свежий ли у браузера этот файл.
   Здесь остаётся только косметика: отклик на курсор. */
.hdr-clocks .wc-pill { transition:background-color .15s, border-color .15s; }
.hdr-clocks .wc-pill:hover { background:var(--card2); border-color:var(--hover); }

/* Строка кнопок и всё, что под ней, опускается ниже: часы поднялись
   в шапку, и между ними и кнопками нужен воздух. */
.launcher-home .header-toolbar { margin-top:26px; }
.launcher-home .main-row { margin-top:18px; }

/* Шесть циферблатов с подписями и имя занимают около 1600 пикселей.
   Ниже этого часы переносим под имя, иначе ряд не помещается. */
@media (max-width: 1650px) {
  .header-clocks { flex-wrap:wrap; justify-content:center; gap:12px; }
  .header-clocks > #userNameRow { order:-1; flex:1 0 100% !important; }
}


/* ── Плитки забирают всю свободную ширину ───────────────────
   Раньше слева от них стоял столбец часов; часы ушли в шапку, и место
   осталось пустым. Сетка тянется до календаря, столбцов по-прежнему
   четыре — привычный строй 4×4 сохраняется, шире становится плитка.
   Вес из трёх селекторов нужен, чтобы перебить .apps-grid ниже по файлу
   с её max-width:900px. */
.launcher-home .main-row .apps-grid {
  flex:1; max-width:none; margin:0;
  grid-template-columns:repeat(4, minmax(0, 1fr));
}
/* Список — единая колонка во всю ширину, как и был, но без прежнего
   ограничения в 880px: иначе он оставил бы ту же пустоту. */
.launcher-home .main-row .apps-grid.list {
  grid-template-columns:1fr; width:auto;
}
/* На узком экране столбцов меньше — иначе плитка станет уже значка. */
@media (max-width: 1250px) {
  .launcher-home .main-row .apps-grid { grid-template-columns:repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .launcher-home .main-row .apps-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); }
}

/* Объём плиток убран 04.09.2026 по решению владельца: многослойные тени,
   перспектива, translateZ и наклон за курсором читались как «3D» и давали
   ту самую серость под плитками. Подъём при наведении остался в правиле
   .app-tile:hover выше — он показывает, что плитка живая, без тени. */

/* Плитка-ссылка ведёт себя как прежний div: без подчёркивания и синевы */
a.app-tile { color:inherit; text-decoration:none; }


/* ── Бегущая строка проблем сети ──────────────────────────
   Идёт справа налево, чтобы текст читался в привычную сторону.
   При наведении останавливается: длинное сообщение иначе не дочитать. */
.alert-ticker { display:flex; align-items:stretch; margin-top:26px;
  border:1px solid var(--red); border-radius:10px; overflow:hidden;
  background:rgba(var(--red-rgb),.10); }
/* Обязательно: display:flex выше перебивает встроенное правило браузера
   для [hidden], и полоса оставалась бы на экране пустой после того, как
   проблема ушла. Селектор с атрибутом весомее — !important не нужен. */
.alert-ticker[hidden] { display:none; }
.alert-ticker-label { flex:0 0 auto; display:flex; align-items:center;
  padding:9px 15px; background:var(--red); color:#fff;
  font-weight:700; font-size:.82rem; white-space:nowrap; letter-spacing:.02em; }
.alert-ticker-view { flex:1 1 auto; overflow:hidden; position:relative; }
.alert-ticker-track { display:inline-flex; white-space:nowrap; padding:9px 0;
  will-change:transform; animation:alertScroll linear infinite; }
.alert-ticker-view:hover .alert-ticker-track { animation-play-state:paused; }
.alert-ticker-item { padding:0 30px; color:var(--red); font-weight:600; font-size:.86rem; }
.alert-ticker-item .since { color:var(--muted); font-weight:400; }
/* Сообщение — ссылка в Инфраструктуру. Цвет и начертание те же: это всё
   ещё сообщение о беде, а не элемент управления. Подчёркивание только
   под курсором — постоянное рябило бы в бегущей строке. */
a.alert-ticker-link { color:var(--red); text-decoration:none; cursor:pointer; }
a.alert-ticker-link:hover { text-decoration:underline; }
/* Сдвиг ровно на половину дорожки: вторая копия встаёт на место первой. */
@keyframes alertScroll { from { transform:translateX(0); } to { transform:translateX(-50%); } }
/* Человеку, которому анимация мешает, показываем список без движения. */
@media (prefers-reduced-motion: reduce) {
  .alert-ticker-track { animation:none; }
  .alert-ticker-view { overflow-x:auto; }
}

/* emp-compact: таблица пользователей плотнее, чтобы влезала без прокрутки */
#empTable { font-size:.8rem; }
#empTable td, #empTable th { padding:6px 8px; }
/* перенос посреди слова — только у почты (см. emp-cols3 ниже) */
#empTable .role-badge, #empTable [class*="badge"] { font-size:.7rem; padding:2px 8px; white-space:nowrap; }

/* emp-cols3: «Дата создания» скрыта ради места (данные целы; чтобы
   вернуть — удалите две строки про nth-child(2)). Почта шире и только
   она может рваться внутри слова; логин — одной строкой. */
#empTable th:nth-child(2), #empTable td:nth-child(2) { display:none; }
#empTable td:nth-child(3) { white-space:nowrap; }
#empTable th:nth-child(8), #empTable td:nth-child(8) { min-width:210px; }
#empTable td:nth-child(8) { word-break:break-word; }

/* Профиль: компактно, без прокрутки страницы */
.profile-compact .card{padding:14px 16px}
.profile-compact .card h3{margin:0 0 8px}
.profile-compact label{margin:6px 0 2px;font-size:.72rem}
.profile-compact input{padding:6px 9px;font-size:.85rem}
.profile-compact p{margin:3px 0 8px!important;font-size:.72rem!important}
/* Часы на главной подсвечиваются при наведении, как плитки программ */
.hdr-clocks .wc-pill{transition:.15s}
.hdr-clocks .wc-pill:hover{background:rgba(var(--hover-rgb),.16)!important;border-color:var(--hover)!important;box-shadow:0 4px 14px rgba(var(--hover-rgb),.25);transform:translateY(-2px)}

/* Профиль: поля в две колонки, чтобы всё влезало без прокрутки */
.mp-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 14px}
@media (max-width:700px){.mp-grid{grid-template-columns:1fr}}

/* Экран блокировки */
#lockOverlay{position:fixed;inset:0;z-index:15000;background:rgba(15,23,42,.92);display:flex;align-items:center;justify-content:center}
#lockOverlay .lock-card{background:var(--card,#fff);border-radius:16px;padding:26px;width:300px;display:flex;flex-direction:column;gap:10px;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,.5)}
#lockOverlay input{padding:9px 11px;border:1px solid var(--border,#ccc);border-radius:9px}

/* Окно «Завершить работу?»: приглушённые цвета, цветная рамка при наведении */
.la-btn{border:2px solid transparent;border-radius:10px;padding:10px;cursor:pointer;font-weight:600;display:flex;flex-direction:column;align-items:center;gap:2px;transition:.15s}
.la-btn .la-sub{font-size:.72rem;font-weight:400;opacity:.75}
.la-red{background:rgba(239,68,68,.14);color:#b91c1c}
.la-red:hover{border-color:#ef4444}
.la-blue{background:rgba(59,130,246,.14);color:#1d4ed8}
.la-blue:hover{border-color:#3b82f6}
.la-green{background:rgba(16,185,129,.14);color:#047857}
.la-green:hover{border-color:#10b981}
body.light-mode .la-red{color:#b91c1c}
/* Замок: всё по центру, кнопки — синие */
#lockOverlay .lock-card{align-items:center}
#lockOverlay .lock-card b{display:block;text-align:center;width:100%}
#lockOverlay input{width:100%;box-sizing:border-box;text-align:center}
#lockOverlay button{background:#3b82f6!important;color:#fff!important;border:none;border-radius:9px;padding:10px;width:100%;cursor:pointer;font-weight:600}

/* Библиотека приглушённых кнопок подтверждения (hover — цветная рамка) */
.btn-soft-red,.btn-soft-blue,.btn-soft-green{border:2px solid transparent!important;font-weight:600;transition:.15s;border-radius:9px;cursor:pointer;padding:8px 14px}
.btn-soft-red{background:rgba(239,68,68,.14)!important;color:#b91c1c!important}
.btn-soft-red:hover{border-color:#ef4444!important}
.btn-soft-blue{background:rgba(59,130,246,.14)!important;color:#1d4ed8!important}
.btn-soft-blue:hover{border-color:#3b82f6!important}
.btn-soft-green{background:rgba(16,185,129,.14)!important;color:#047857!important}
.btn-soft-green:hover{border-color:#10b981!important}
body:not(.light-mode) .btn-soft-red{color:#f87171!important}
body:not(.light-mode) .btn-soft-blue{color:#93c5fd!important}
body:not(.light-mode) .btn-soft-green{color:#6ee7b7!important}

/* Авария: тикер виден — ужимаем вертикаль ровно на его высоту,
   чтобы нижний ряд юрлиц не уезжал за край экрана. */
.launcher-home:has(#alertTicker:not([hidden])) { padding-top:8px; padding-bottom:4px; }
.launcher-home:has(#alertTicker:not([hidden])) .header-toolbar { margin-top:12px; }
.launcher-home:has(#alertTicker:not([hidden])) .main-row { margin-top:10px; }
.launcher-home:has(#alertTicker:not([hidden])) .alert-ticker { margin-top:10px; }
.launcher-home:has(#alertTicker:not([hidden])) .alert-ticker-label { padding:5px 12px; }
.launcher-home:has(#alertTicker:not([hidden])) .alert-ticker-track { padding:5px 0; }
.launcher-home:has(#alertTicker:not([hidden])) .companies-bar { padding:6px 0 0; }

/* Заголовок раздела — кнопка одного роста с «Тёмная» и «Назад» */
.page-title-btn{font-size:.95rem}
.header .page-title-btn,.header .theme-btn,.header .btn-back{padding:8px 16px;line-height:1.2;display:inline-flex;align-items:center}

/* Главные кнопки (btn-primary) — утверждённый приглушённый синий */
.btn-primary{background:rgba(59,130,246,.14)!important;background-image:none!important;color:#1d4ed8!important;border:2px solid transparent!important;box-shadow:none!important;font-weight:600}
.btn-primary:hover{border-color:#3b82f6!important;background:rgba(59,130,246,.14)!important;color:#1d4ed8!important;opacity:1!important}
body:not(.light-mode) .btn-primary{color:#93c5fd!important}

/* Профиль: кнопки фото — высотой с поле ФИО; телефон — высотой с поля */
.ava-btn{height:38px;display:flex;align-items:center;justify-content:center;padding:0 14px;box-sizing:border-box}
.mp-grid input,.mp-grid select{height:38px;box-sizing:border-box}

/* Единая высота полей ввода по всему auth (эталон — поле телефона) */
input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range]),select{height:38px;box-sizing:border-box}

/* Тема «Вечерняя» — сумерки между светлой и тёмной */
body.evening-mode{--bg:#232833;--card:#2c3340;--card2:#353d4c;--border:#485164;--text:#d7dce6;--muted:#98a2b5}
/* Правило: все «внешние» кнопки — одной высоты с полями (38px) */
.btn-primary,.btn-secondary,.btn-danger,.btn-soft-red,.btn-soft-blue,.btn-soft-green,.ava-btn{height:38px;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;padding-top:0;padding-bottom:0}
.la-btn{height:auto;min-height:38px}

/* ── Главная и разделы с телефона (до 760px) ─────────────────────────
   Плитки и виджеты — одной колонкой, часы — компактной лентой с
   прокруткой вбок, календарь под плитками, ничего не наезжает. */
@media (max-width:760px) {
  .launcher { padding:14px 10px; }
  .header-toolbar { gap:6px !important; }
  .header-toolbar .nav-btn { padding:7px 10px; font-size:.8rem; flex:none; white-space:nowrap; }
  .header-clocks, .hdr-clocks { justify-content:flex-start !important; }
  .hdr-clocks { flex-wrap:nowrap !important; overflow-x:auto; width:100%;
    -webkit-overflow-scrolling:touch; padding-bottom:6px; }
  .hdr-clocks .wc-pill { flex:none; gap:8px !important; padding:6px 10px 6px 6px !important; }
  .hdr-clocks .wc-pill svg { width:52px !important; height:52px !important; }
  .launcher-home .main-row { flex-direction:column; }
  .apps-grid, .main-row .apps-grid { grid-template-columns:repeat(2, minmax(0,1fr)); gap:10px; width:100%; max-width:100%; }
  .app-tile { padding:14px 6px; }
  .app-tile .name { font-size:.92rem; line-height:1.2; overflow-wrap:anywhere; }
  .app-tile .access { font-size:.72rem; }
  .app-tile.wide { grid-column:span 2; }
  .apps-grid.list { width:100%; }
  .side-cals { width:100%; margin-top:12px; }
  th, td { padding:7px 8px; }
}

/* Роли × площадки — матрица */
.rm-wrap { overflow:auto; max-height:calc(100vh - 170px); border:1px solid var(--border); border-radius:10px; margin-bottom:14px; }
.rm-table { table-layout:auto; width:100%; border-collapse:separate; border-spacing:0; }
.rm-table thead th { position:sticky; top:0; z-index:3; background:var(--card); white-space:nowrap; }
.rm-table .rm-th span { writing-mode:vertical-rl; transform:rotate(180deg); display:inline-block; padding:6px 0; font-size:.78rem; }
.rm-table td.rm-role { position:sticky; left:0; z-index:2; background:var(--card); min-width:200px; }
.rm-table th:nth-child(2) { position:sticky; left:0; z-index:4; }
.rm-pos { font-size:.72rem; color:var(--muted); margin-top:2px; max-width:260px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.rm-cell { text-align:center; padding:4px 3px !important; }
.rm-sel { font-size:.72rem; font-weight:700; padding:3px 6px; border-radius:99px; border:1px solid transparent; cursor:pointer; appearance:none; -webkit-appearance:none; text-align:center; }
.rm-sel.access-full { background:rgba(16,185,129,.18); color:var(--green); }
.rm-sel.access-read { background:rgba(245,158,11,.18); color:#f59e0b; }
.rm-sel.access-none { background:rgba(var(--red-rgb),.20); color:var(--red); }
.rm-sel:disabled { opacity:.6; cursor:not-allowed; }
.rm-hint { font-size:.76rem; color:var(--muted); margin:-6px 0 14px; }

/* Карточка сотрудника: стартовые пароли выделены зелёным (в тёмной теме
   светлее, чтобы читались); подписи полей облака одной высоты, чтобы поля
   стояли на одной линии. */
.start-pass { color:#34d399; font-weight:800; text-transform:none; letter-spacing:0; }
body.light-mode .start-pass { color:#047857; }
#empModal label.lbl2 { min-height:2.3em; display:flex; align-items:flex-end; }

/* Праздники: именинник и виновники профессионального дня в «Сотрудниках» */
.staff-bday { border:2px solid #f59e0b !important; box-shadow:0 0 0 4px rgba(245,158,11,.15), 0 10px 28px rgba(245,158,11,.18); background:linear-gradient(135deg, rgba(245,158,11,.10), transparent 60%) , var(--card) !important; padding-top:34px !important; }
.staff-fest { border:2px solid #9f1d3c !important; background:linear-gradient(135deg, rgba(159,29,60,.07), transparent 60%), var(--card) !important; padding-top:34px !important; }
.staff-ribbon { position:absolute; top:0; left:0; right:0; padding:4px 12px; font-size:.76rem; font-weight:700; color:#7c2d12; background:linear-gradient(90deg,#fde68a,#fbbf24); border-radius:10px 10px 0 0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.staff-ribbon-fest { color:#fff; background:linear-gradient(90deg,#9f1d3c,#be3455); }

/* Пользователи: дата рождения под ФИО; плашка роли переносится по словам — колонка «Роль» уже */
#empTable .emp-birth { font-size:.72rem; color:var(--muted); margin-top:2px; white-space:nowrap; }
#empTable .emp-birth-edit { cursor:pointer; } #empTable .emp-birth-edit:hover { color:var(--hover,#14b8a6); }
#empTable th:nth-child(6), #empTable td:nth-child(6) { width:1%; max-width:150px; }
#empTable td:nth-child(6) [class*="badge"] { white-space:normal !important; display:inline-block; max-width:140px; line-height:1.2; border-radius:10px; padding:3px 8px; text-align:center; }
#empTable td:nth-child(7) { max-width:170px; }

/* Строка «поля + кнопка справа» (карточка сотрудника: Federated ID,
   Отсутствия). Кнопки одной ширины — левые края совпадают строка к строке;
   по высоте ровно как поле рядом. Отступы полей обнулены: общее правило
   input { margin-bottom } иначе растягивало строку, и кнопка вставала криво. */
.row-with-btn { display: flex; gap: 8px; align-items: stretch; }
.row-with-btn > * { margin: 0 !important; }
.row-with-btn > input:not([type="date"]):not([type="checkbox"]) { flex: 1 1 120px; min-width: 120px; }
.row-with-btn > span { align-self: center; }
.row-side-btn { flex: none; width: 140px; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  white-space: nowrap; margin-left: auto !important; }

/* tilejump3. Плитка при наведении не сдвигается, а вырастает ВВЕРХ на 3px: нижний край неподвижен, поэтому у нижнего
   края нечему уходить из-под курсора (translateY давал дрожание). 14px — действующий нижний отступ плитки
   (.app-tile { padding:14px … } выше); меняете его — поменяйте и 17px здесь. */
.app-tile:hover { transform:none; margin-top:-3px; padding-bottom:17px; }
.app-tile.disabled:hover, .app-tile.denied:hover { margin-top:0; padding-bottom:14px; }
.apps-grid.list .app-tile:hover { margin-top:0; padding-bottom:10px; }   /* в режиме «Списком» плитка не растёт; 10px — её отступ там */

/* Кнопка «Чат»: индикация непрочитанного (20.09.2026). Красный — единый #ef4444. */
.chat-btn { position:relative; overflow:visible !important; }
.chat-badge { position:absolute; top:-7px; right:-7px; min-width:20px; height:20px; padding:0 5px; box-sizing:border-box;
  border-radius:10px; background:#ef4444; color:#fff; font-size:.72rem; font-weight:700; line-height:20px; text-align:center;
  box-shadow:0 0 0 2px var(--bg); pointer-events:none; }
.chat-btn-new { border-color:#ef4444 !important; animation:chatBtnPulse 1.6s ease-in-out infinite; }
@keyframes chatBtnPulse { 0%,100% { box-shadow:0 0 0 0 rgba(239,68,68,.45); } 50% { box-shadow:0 0 0 6px rgba(239,68,68,0); } }
@media (prefers-reduced-motion: reduce) { .chat-btn-new { animation:none; } }

/* Запланированное обновление в бегущей строке — жёлтое: меры приняты, это не авария */
.alert-ticker-item.is-planned, a.alert-ticker-link.is-planned { color:#d97706; }

/* Область таблицы сотрудников прокручивается сама: вбок — полосой сверху
   (общий слой), вниз — внутри своей высоты. Без этого липкая шапка
   уезжала бы вместе со страницей (28.09.2026). */
#empWrap { max-height: calc(100vh - 235px); overflow: auto; }

/* «Пользователи»: шапка и фильтры остаются на экране при прокрутке (23.09.2026). */
#empTable thead th { position:sticky; z-index:5; }
#empTable thead tr:first-child th { top:0; background:var(--bg); }
#empTable thead tr.emp-filter-row th { top:var(--emp-th-h, 40px); box-shadow:0 2px 0 var(--border); }

/* cf-head-mobile: шапка окна «Совещания» на телефоне (23.09.2026) — переносится,
   кнопки одной высоты и компактнее, «Закрыть» не уезжает за край. */
@media (max-width:620px) {
  .calls-full-head { flex-wrap:wrap; gap:8px; padding:10px 12px; }
  .calls-full-head .calls-full-title { font-size:1rem; height:34px; padding:0 10px; }
  .calls-full-head .btn-secondary { height:34px; padding:0 10px !important; font-size:.8rem !important; white-space:nowrap; }
  .calls-full-head > span[style*="flex:1"] { display:none; }
  #callsFullCount { font-size:.8rem !important; }
  .calls-full-body { padding:12px 10px 24px; }
  .calls-full-acts { gap:8px; padding-left:0; }
}

/* Полосы-напоминания (привязка Telegram, двухфакторный вход):
   по центру страницы и с воздухом сверху — вплотную к ряду кнопок они
   читались как их продолжение (23.09.2026). Отступы со звёздочкой:
   в разметке у полос свой margin-bottom. */
.totp-banner-link {
  text-align: center;
  max-width: 820px;
  margin: 22px auto 18px !important;
}
