/* ============================================================================
 * Genesis — единые дизайн-токены семейства (Suite-CDN, раскатка на все продукты).
 * Подключение в любом продукте (как suite-switcher.js):
 *   <link rel="stylesheet" href="https://suite.gdw.kz/suite-theme.css">
 * Зеркалит словарь токенов G-Tools (`shared/themes/m365/m365.css`): нейтральная
 * палитра + НАШ брендовый indigo #4f46e5. Источник правды по бренду — G-Suite
 * (process owner). Продукты мапят свои компоненты на эти переменные (--ge-color-*),
 * HTML-разметку не навязываем. Тон темы переключается ОДНИМ приёмом — атрибутом
 * :root[data-theme] (light | dark); правило :root[data-theme="base-dark"] и значения тёмного
 * тона живут только в shared/themes/base-dark/base-dark.css, этот файл их не держит.
 *
 * Иконки/фавикон (family-стандарт, см. docs/BRAND-KIT.md): скруглённая плитка
 * indigo-градиента + белый глиф (буква продукта). Радиус — var(--ge-radius-lg).
 * ========================================================================== */
:root {
  /* Макет — единый канон ширины левого сайдбара портала (один источник правды для
     ВСЕХ модулей: admin-shell .admin-nav и кастомные сайдбары продуктов ссылаются сюда). */
  --ge-side-w: 420px;

  /* ШИРИНА БОКОВОГО УЧАСТКА РАБОЧЕГО ЭКРАНА ПРОДУКТА (карта 10006565).
     ПРЕДМЕТ — боковой участок ВНУТРИ рабочего поля экрана: перечень расхождений, свойства
     выбранной строки, короткая сводка рядом с основным содержимым. Это НЕ левый рельс портала
     (--ge-side-w выше: навигация платформы, общая всем модулям) и НЕ каркас оболочки
     (--ge-shell-side-w ниже: shell-паттерны G-Tools). Три предмета — три записи; до сих пор
     объявления не было только у этого, и каждый экран брал ближайшее чужое имя либо писал
     литерал, расходясь с утверждённой раскладкой.
     ЗНАЧЕНИЯ ВЗЯТЫ У УТВЕРЖДЁННОГО ЭСКИЗА (запись 55 раздела «Дизайн», ревизия 1): 340 на
     широком экране, 300 на узкой ступени. Узкое значение объявляет САМА ТЕМА ниже — тем же
     именем в условии объявленной ступени семьи; потребитель читает ОДНО имя и своего условия
     по ширине ради ширины участка не держит. */
  --ge-panel-side-w: 340px;

  /* ШИРИНА РАБОЧЕЙ ПАНЕЛИ ЛЕВОЙ КОЛОНКИ — ОСТАТОК КОЛОНКИ (карта 10000612).
     Замечание Владельца 11.08: «рельс не уменьшает ширину второго сайдбара и это дергает
     границу между сайдбаром и основной зоной. не приятно. не должна менятся пропорция
     основного окна».

     ГЕОМЕТРИЮ КОЛОНКИ ОБЪЯВЛЯЛИ ДВОЕ. Каркас знал общую ширину и полосу, занятую рельсом
     (--gus-push, пишет сам рельс — он единственный, кто знает режим, свёрнутость и пин);
     продукт объявлял ширину своей панели ВСЕЙ колонкой, независимо от рельса. Сумма не
     сходилась ни при каком значении: пока показан один рельс, занято 420; свернулся рельс
     и встала вторая панель — занято 56 + 420 = 476, и граница с рабочим полем уезжала
     ровно на 56 px. Рывок был виден потому, что случался при смене экрана, а не по воле
     человека. Дефект принадлежал не продукту, а разделению владения, и потому проступал
     в четырёх продуктах разом.

     ТЕПЕРЬ ПИСАТЕЛЬ ОДИН: ширина рабочей панели ВЫВОДИТСЯ здесь и продуктом не
     переобъявляется. Сумма сходится при любом состоянии рельса — 56 + 364 = 420 и
     420 + 0 = 420, — поэтому граница стоит на месте, а пропорция рабочего поля не меняется.
     Выводится из ЗАНЯТОЙ полосы, а не из видимой ширины рельса: развёртывание свёрнутого
     рельса по наведению есть наложение поверх содержимого — оно ничего не сдвигает и
     --gus-push не трогает. Рельса на странице нет вовсе — полоса не объявлена, остаток
     равен всей колонке, и продукт получает прежнее поведение без единой своей строки. */
  --ge-side-work-w: max(0px, calc(var(--ge-side-w) - var(--gus-push, 0px)));

  /* Слой полноэкранного захвата (Focus Mode: читалка, студия, разбор записи). Поверхность
     несёт СВОЙ выход — панель с крошкой и «Закрыть», — поэтому обязана лежать ВЫШЕ
     платформенной шапки: объявленная ниже, она получает эту панель накрытой, и выйти
     становится нечем. Число слоя имеет ОДНОГО владельца — эту строку; продукт читает
     var(--ge-z-focus, 2147483400), а не повторяет литерал (повторённый литерал и был
     причиной: продукт, который его не знал, объявлял поверхность в своей шкале — 50, 70,
     200 — и уходил под шапку). Соседи поверхности по телу страницы — выдвижная панель,
     диалог, всплывающее сообщение — берут calc() от этого же токена и сохраняют взаимный
     порядок. Дети самой поверхности его не касаются: они уже в её контексте наложения. */
  --ge-z-focus: 2147483400;

  /* Бренд — ОДНО зерно акцента (единая точка управления, см. brand-router.js /suite-theme.css).
     Все оттенки выводятся из --ge-brand-seed через color-mix, поэтому центральная смена ОДНОГО
     значения (БД gsuite_brand_settings → :root в конце этого файла) перекрашивает и светлую, и
     тёмную тему согласованно. Тёмная (themes/base-dark/base-dark.css) выводит из того же зерна свои светлые
     оттенки для читаемости на холсте. */
  --ge-brand-seed:          #4f46e5;   /* indigo — зерно бренда Genesis (меняется централизованно) */
  --ge-color-brand:         var(--ge-brand-seed);
  --ge-color-brand-hover:   color-mix(in srgb, var(--ge-brand-seed) 84%, #000);
  --ge-color-brand-soft:    color-mix(in srgb, var(--ge-brand-seed) 9%, #fff);   /* фон активного пункта/выделения */
  --ge-color-brand-2:       color-mix(in srgb, var(--ge-brand-seed) 80%, #fff);  /* доп. для градиентов плиток/иконок */
  /* Знак ПОВЕРХ насыщенной заливки (кнопка бренда, плашка состояния, значок счётчика).
     Отдельное имя нужно потому, что белый знак на заливке и белая карточка — РАЗНЫЕ факты:
     в тёмной теме карточка перестаёт быть белой, а заливки остаются насыщенными, и знак
     на них обязан менять сторону. Пока оба писались одним литералом #fff, тема не могла
     развести их. */
  --ge-color-on-fill:       #ffffff;
  --ge-color-brand-ink:     var(--ge-color-on-fill);   /* знак поверх брендовой заливки (тёмная задаёт своё) */

  /* Цвет-акцент ТЕКУЩЕГО продукта. Значение приходит из каталога продуктов и ставится
     в разметку корня во время работы (suite-switcher.js), поэтому здесь объявлено
     ЗНАЧЕНИЕ ПО УМОЛЧАНИЮ — чтобы имя разрешалось до прихода данных и у продукта,
     которому акцент не задан. Инлайн-значение с корня перебивает объявленное. */
  --ge-accent:              var(--ge-color-brand);
  --ge-accent-soft:         color-mix(in srgb, var(--ge-color-brand) 13%, transparent);

  /* Текст */
  --ge-color-text:          #201f1e;
  --ge-color-text-mute:     #605e5c;
  --ge-color-text-faint:    #726f6d;

  /* Поверхности */
  --ge-color-bg:            #faf9f8;   /* холст */
  --ge-color-surface:       #ffffff;   /* карточка */
  /* Вторая поверхность — утопленная область ВНУТРИ карточки (шапка таблицы, вкладка,
     отключённое поле, вложенная панель). Значения не заводит: в светлой это цвет холста,
     в тёмной — своя ступень (themes/base-dark). Имя объявлено здесь, потому что его спрашивают
     поверхности десяти продуктов; пока оно не было объявлено, каждая из них падала на
     собственный литерал и тема до них не доставала. */
  --ge-color-surface-2:     var(--ge-color-bg);
  --ge-color-border:        #edebe9;
  --ge-color-border-strong: #d2d0ce;
  --ge-color-control-border:#8d8b88;   /* граница полей ввода: ≥3:1 к белому полю и холсту (WCAG 1.4.11) */
  --ge-color-hover:         #f3f2f1;
  --ge-color-pressed:       #edebe9;   /* нажатое/раскрытое состояние органа: на ступень плотнее наведения */
  /* Утопленная ПОЛОСА поверх карточки — шапка списка, панель действий, каркас загрузки.
     Отличается от --ge-color-surface-2 назначением: та — вложенная ОБЛАСТЬ (равна холсту),
     эта — служебная полоса, которая обязана быть отличима и от карточки, и от холста,
     иначе закреплённая шапка списка сливается с первой строкой при прокрутке. */
  --ge-color-surface-sunken:#f0efee;
  /* Кольцо фокуса. Один род на семейство: пока имени не было, каждая поверхность рисовала
     свой контур (где-то системный outline, где-то тень бренда), и клавиатурный обход
     выглядел по-разному на соседних экранах. Значение выводится от бренда смешиванием —
     смена зерна перекрашивает кольцо вместе с акцентом. */
  --ge-color-ring:          var(--ge-color-brand);  /* непрозрачное: различимость кольца ≥3:1 к холсту (WCAG 1.4.11) */
  /* Подложка полноэкранного слоя (режим полного экрана, подтверждение). Выезжающему окну
     подложка НЕ полагается — канон Dual-Mode: оно выезжает ПОВЕРХ контекста без тинта. */
  --ge-color-scrim:         rgba(15, 23, 42, .32);

  /* Семантика */
  --ge-color-accent-blue:   #0078d4;
  --ge-color-ok:            #15803d;
  --ge-color-warn:          #b45309;
  --ge-color-err:           #b91c1c;
  --ge-color-info:          #0969da;   /* информационный (синий) — НЕ привязан к бренду; тёмный вариант в themes/base-dark */
  /* Ярлык карточки доски БЕЗ выбранного цвета. Цвет, ВЫБРАННЫЙ человеком, — данные и
     приходит из записи ярлыка; нейтраль для ярлыка без цвета — поверхность темы. Прежде это
     значение объявляли пять мест в трёх продуктах (стилевая строка общей доски, её же код и
     код досок G-CRM и G-PM) — тема до него не доставала. Тёмный вариант в themes/base-dark. */
  --ge-color-label-default: #94a3b8;
  /* Семантические ФОНЫ статус-плашек (.err/.pill/.quota-warn и т.п.). Раньше их не было —
     продукты хардкодили светлые hex (#fde7e9/#dafbe1/#fef3c7), из-за чего в тёмной теме
     получался светлый фон со светлым (перевёрнутым) текстом = нечитаемо. Теперь токен:
     light здесь, dark — в themes/base-dark/base-dark.css. Ссылка `var(--ge-color-err-bg, #fde7e9)`
     в продуктах автоматически становится корректной в обеих темах. */
  --ge-color-err-bg:        #fde7e9;
  --ge-color-ok-bg:         #dafbe1;
  --ge-color-warn-bg:       #fef3c7;
  --ge-color-info-bg:       #ddf4ff;
  /* Парные оттенки СОСТОЯНИЯ и ВЫДЕЛЕНИЯ у семантики. Свести оттенок наведения к токену
     покоя значит стереть состояние, поэтому пока имени не было, каждая поверхность писала
     свой литерал — и один и тот же факт («заполненная информационная кнопка под курсором»)
     оказывался написан по-разному в разных файлах.
     Оттенки БРЕНДА выводятся смешиванием от зерна (выше): зерно меняется централизованно и
     обязано перекрашивать их согласованно. Семантические — наоборот, объявляются ЯВНЫМ
     значением: они не выводятся из зерна, а явное значение ПРОВЕРЯЕМО — сторож сверяет
     запасное значение в поверхности с объявленным здесь, тогда как значение через
     color-mix к литералу не сводится и сверке не поддаётся.
     Имя заводится вместе со своим читателем: имя без читателя — мёртвая запись словаря. */
  --ge-color-info-hover:    #0858b7;   /* заполненная информационная кнопка под курсором */
  --ge-color-info-border:   #93c5fd;   /* граница выделенной строки/плашки информационного рода */
  --ge-color-ok-border:     #86efac;   /* граница плашки согласия */
  --ge-color-err-border:    #fca5a5;   /* граница плашки ошибки */
  --ge-color-err-hover:     #9b1717;   /* заполненная кнопка опасности под курсором */
  --ge-color-warn-border:   #fcd34d;   /* граница плашки предупреждения */
  --ge-color-err-bg-hover:  #fee2e2;   /* фон плашки ошибки на ступень плотнее (наведение) */

  /* Типографика */
  --ge-font-family: 'Segoe UI', system-ui, -apple-system, 'SF Pro Text', sans-serif;
  --ge-font-mono:   'Cascadia Mono', 'SF Mono', Consolas, monospace;
  --ge-font-size-xs: 11px;
  --ge-font-size-sm: 12.5px;
  --ge-font-size-md: 13.5px;
  --ge-font-size-lg: 16px;
  --ge-font-size-h2: 21px;
  --ge-font-size-h1: 28px;
  --ge-line-height:  1.43;
  /* Иерархия держится ВЕСОМ, РИТМОМ и ЦВЕТОМ, а не размером: шкала размеров у рабочего
     интерфейса тесная (шаг ~1.2), иначе экран с сотней подписей превращается в шум.
     Имена ниже — то, чем эта иерархия набирается; каждое заведено вместе со своим
     читателем в общих компонентах (форма, список, пустое состояние). */
  --ge-line-height-tight: 1.2;         /* заголовки: строки не расползаются */
  /* Моноширинная правка исходника: строка кода стоит шире рабочей (1.43) и уже читательской
     (1.72). Отступ здесь несёт смысл — по нему совпадают базовые линии номеров строк и текста,
     и он же задаёт высоту строки гуттера. Величина объявлена ЗДЕСЬ, у единственного писателя
     перечня: у органа правки исходника она стояла литералом и темой не менялась. */
  --ge-line-height-code:  1.5;
  --ge-weight-regular:    400;         /* придаточное к подписи: помета, подсказка под полем */
  --ge-weight-medium:     500;         /* подписи полей, вторичные действия */
  --ge-weight-semibold:   600;         /* заголовки, шапка списка, главное действие */
  --ge-tracking-tight:  -.012em;       /* крупный заголовок: буквы собираются, но не слипаются */
  /* Разрядка рубрики верхним регистром. Прописные с разрядкой — ОДИН приём на
     поверхность (шапка списка), а не способ набирать каждую подпись: подпись поля,
     ошибка и пояснение в рабочей форме остаются строчными, иначе экран из сорока
     капс-меток превращается в шум и читается медленнее, чем плотная таблица. */
  --ge-tracking-label:   .06em;
  /* Имя раздела формы. Заголовок в рабочей форме держит группу ВЕСОМ и положением, а не
     кеглем: шкала здесь тесная (шаг ~1.15), и «плакатный» размер вместо иерархии даёт
     ещё один уровень шума. */
  --ge-font-size-section: 15px;
  /* Цифры в столбцах обязаны стоять по разрядам: суммы, остатки, номера документов. */
  --ge-numeric: tabular-nums;
  /* МЕРА ЧИТАЕМОЙ КОЛОНКИ. Режим полного экрана даёт форме всю ширину монитора — и это
     не подарок, а ловушка: на широком экране строка ввода растягивается на две с лишним
     тысячи пикселей, взгляд теряет начало поля, разделы сливаются в один список. Колонка
     формы ограничивается этой мерой и центрируется. Значение выбрано не «на глаз»: при
     980px раздел раскладывается на колонку имени (240px) и две колонки полей по ~300px —
     дальше поле становится шире, чем что-либо в него вводимое. */
  --ge-measure-form: 980px;
  /* Мера листа с широкой таблицей записей: рабочее поле окна целиком (form-kit, has-table). */
  --ge-measure-work: 100%;
  /* ── ЧИТАТЕЛЬСКИЙ СЛОЙ ──────────────────────────────────────────────────────
     Рабочий экран и СПЛОШНОЙ ТЕКСТ — разные роды набора, и шкала выше рассчитана
     на первый: тесный шаг, плотная строка, кегль под сотню подписей. Статья справки,
     описание регламента и текст соглашения читаются подряд, и на той же шкале строка
     идёт слишком узко, а колонка — слишком широко. Ниже вторая, ЧИТАТЕЛЬСКАЯ ступень
     тех же фактов: она НЕ заменяет рабочую, а объявляется рядом, чтобы длинный текст
     не набирался «на глаз» в каждом продукте заново. */
  --ge-measure-read:      68ch;      /* колонка сплошного текста: строка не длиннее взгляда */
  --ge-measure-lead:      58ch;      /* врезка/лид: короче основной колонки, читается быстрее */
  --ge-font-size-read:    15.5px;    /* кегль сплошного текста (рабочий — 13.5px) */
  --ge-line-height-read:  1.72;      /* интерлиньяж чтения подряд: строки не слипаются */
  --ge-font-size-code:    12.75px;   /* врезка кода внутри читаемого текста */
  --ge-font-size-eyebrow: 10.5px;    /* рубрика над заголовком плитки: прописные с разрядкой */
  /* Крупный заголовок раздела: строки собираются плотнее рабочей ступени, буквы — тоже.
     Тот же приём, что у `--ge-tracking-tight`, но ступенью выше — для витринного кегля. */
  --ge-line-height-display: 1.12;
  --ge-tracking-display:  -.024em;

  /* ── ОРГАНЫ: ВЫСОТА, РАДИУС, КОЛЬЦО ФОКУСА ─────────────────────────────────
     Поле ввода и кнопка — один род предмета и обязаны совпадать по высоте и радиусу:
     разнобой в несколько пикселей между соседями в одной полосе и есть то, из-за чего
     набор читается «собранным по месту». 36px — рабочая плотность профессионального
     инструмента: рука попадает уверенно, но форма из десяти полей помещается на экран
     без прокрутки. Главное действие берёт ступень выше — это вес действия, а не
     украшение.
     Кольцо фокуса — КОНТУР в 2px со смещением, а не размытое свечение: свечение
     читается как подсветка украшением и хуже различимо при обходе с клавиатуры. */
  --ge-control-h:      36px;
  --ge-control-h-lg:   40px;
  /* Компактная ступень: плотная полоса действий — тулбар раздела, строка под шапкой
     карты, строка ссылок сводки. Пока этой ступени в словаре не было, продукт задавал
     компактный орган по месту и каждый раз по-своему; живой случай — `.btn.sm` с
     контекстным `margin-top`, который держал ОДИН сценарий (кнопка последней строкой
     карты) и ломал второй (та же кнопка в тулбаре вставала ниже соседа). Граница
     проходит не по органу, а по контейнеру: контекст задаёт ступень, орган её
     принимает — см. примитив `.ge-actionbar` ниже. Основной орган ввода остаётся
     на `--ge-control-h`: 28px — не цель для пальца. */
  --ge-control-h-sm:   28px;
  /* Ступень строки таблицы: наименьшая высота строки реестра. Раньше высота выводилась
     отступом ячейки и кеглем (7+7px и 13px×1.43 ≈ 33px), и всё, что мерило тело таблицы,
     набиралось чужой ступенью органа. Строка с переносом растёт выше ступени. */
  --ge-row-h:          33px;
  --ge-grid-line-w:     1px;   /* волосяная граница органов таблицы (пейджер) */
  --ge-radius-control:  6px;
  --ge-focus-ring-w:    2px;
  /* Орган дерева узлов (shared/tree.js, карта 10111153): ступени строки, отступа вложенности, значка и окна прокрутки. */
  --ge-tree-row-h:      32px;
  --ge-tree-indent:     16px;
  --ge-tree-caret:      16px;
  --ge-tree-mark-w:     3px;
  --ge-tree-view-h:     60vh;
  --ge-size-20:         20px;
  --ge-gap-tool:        8px;
  --ge-icon-size-xs:    12px;
  --ge-icon-size-sm:    16px;
  --ge-radius-xs:       2px;

  /* ── ШИРИНА ПОЛЯ: ЧЕТЫРЕ СТУПЕНИ ────────────────────────────────────────────
     Высота органа объявлена ступенями выше, а ширина поля до сих пор набиралась
     числом на месте: обход общего набора давал десятки разных величин в полосе
     180–360px, и смена темы ни одной из них не касалась. Ступеней ровно четыре,
     пятой не заводится; второго места объявления у них нет — вариант темы их не
     повторяет. Приведение к ступени однозначно: берётся ближайшая, при равном
     удалении — большая.
       sm — короткий ввод в плотной полосе (поиск в тулбаре, отбор);
       md — обычное поле формы и селектор в шапке;
       lg — поле, читаемое вместе со значением (имя, обозначение);
       xl — поле с длинным значением (адрес, путь, строка запроса). */
  --ge-field-w-sm:    180px;
  /* Размер знака и наименьшая ширина плавающего слоя — СВОИ записи, а не заимствованные у кегля и поля ввода: правка типографики не двигает знак, правка поля не двигает меню. */
  --ge-icon-sm:       14px;
  --ge-icon-md:       16px;
  --ge-layer-w-min:   180px;
  --ge-field-w-md:    240px;
  --ge-field-w-lg:    280px;
  --ge-field-w-xl:    320px;
  --ge-measure-tag-entry: 7rem; /* базис строки ввода метки в поле меток (запись 10006147) */

  /* Слой всплывающего окна органа (список выбора, перечень колонок) и потолок высоты
     окна показа таблицы — записи темы, а не числа на месте (запись 10005525). Потолок
     один на плавающее окно и на тело таблицы: две близкие величины 65vh и 62vh сведены
     к одной ступени. */
  --ge-z-pop:          40;
  --ge-view-max-h:     64vh;

  /* Форма / отступы / тени */
  /* Ступень приглушения запертого показа: органы гасят недоступное этой величиной, не числом на месте (запись 10006143). */
  --ge-opacity-locked: 0.5;
  --ge-radius-sm: 3px;
  --ge-radius-md: 4px;
  --ge-radius-lg: 8px;
  --ge-radius-pill: 999px;
  --ge-space-1: 4px;
  --ge-space-2: 8px;
  --ge-space-3: 12px;
  --ge-space-4: 16px;
  --ge-space-5: 24px;
  --ge-space-6: 32px;
  --ge-radius-xl: 12px;                /* плавающий слой: полный экран, плитка пустого состояния */
  --ge-shadow-card:   0 1.6px 3.6px rgba(0,0,0,.13), 0 .3px .9px rgba(0,0,0,.11);
  --ge-shadow-drawer: -8px 0 28px rgba(0,0,0,.16);
  --ge-shadow-drawer-mirrored: 8px 0 28px rgba(0,0,0,.16); /* та же ступень при правостороннем письме: ящик у левого края */
  --ge-shadow-pop:    0 8px 28px rgba(0,0,0,.18);

  /* ── ШКАЛА ВЫСОТ ────────────────────────────────────────────────────────────
     Ступень означает РАССТОЯНИЕ ДО ХОЛСТА, а не «покрасивее»: 1 — приподнятая строка
     и закреплённая полоса, 2 — раскрывающийся список и всплывающая подсказка,
     3 — выезжающее окно, 4 — полный экран. Каждая тень составная: короткая контактная
     (предмет касается плоскости) плюс широкая рассеянная (предмет отбрасывает свет).
     ПРАВИЛО УПОТРЕБЛЕНИЯ, а не только значения: плоская панель держится ВОЛОСЯНОЙ
     ГРАНИЦЕЙ и тени не получает; тень получает только ПЛАВАЮЩИЙ слой, и тогда граница
     ему не нужна. Граница и широкая тень на одном предмете — «призрачная карточка»,
     самый частый признак интерфейса, собранного по инерции. В тёмной теме значения
     свои (themes/base-dark): на тёмном холсте тень почти не читается, и роль разделителя
     там берёт на себя волосяная граница. */
  --ge-elev-1: 0 1px 2px rgba(16,15,14,.07), 0 1px 1px rgba(16,15,14,.04);
  --ge-elev-2: 0 2px 6px rgba(16,15,14,.09), 0 1px 2px rgba(16,15,14,.05);
  --ge-elev-3: 0 8px 24px -8px rgba(16,15,14,.18), 0 2px 6px rgba(16,15,14,.06);
  --ge-elev-4: 0 24px 56px -16px rgba(16,15,14,.24), 0 4px 12px rgba(16,15,14,.08);

  /* ── ДВИЖЕНИЕ ───────────────────────────────────────────────────────────────
     Пользователь рабочего интерфейса находится в задаче, а не смотрит представление:
     движение сообщает СОСТОЯНИЕ (появилось, закрылось, загружается) и ничего больше.
     Поэтому длительности короткие, а не «кинематографические», и анимируются только
     смещение и прозрачность. Ступень 3 — предел: слой, который едет дольше, начинает
     задерживать работу. */
  --ge-dur-1: 120ms;                   /* смена оттенка, наведение */
  --ge-dur-2: 180ms;                   /* появление подсказки, разворот */
  --ge-dur-3: 260ms;                   /* выезд окна, вход полноэкранного слоя */
  --ge-ease-out: cubic-bezier(.22, 1, .36, 1);    /* затухание: быстро стартует, мягко встаёт */
  --ge-ease-spring: cubic-bezier(.2, .8, .2, 1);  /* пружина семейства (жёсткость ~100) */

  /* Каркас (для общих shell-паттернов G-Tools) */
  --ge-header-h:    48px;
  --ge-shell-side-w:260px;
  --ge-drawer-w:    440px;

  /* СМЕЩЕНИЕ ЛИПКОЙ ШАПКИ СПИСКА. Читает его один орган — общий реестр
     (`shared/data-grid.js`, `.sui-gr-table th`), а страница со своей полосой над списком
     переопределяет запись на СВОЁМ узле. Умолчание жило ЗАПАСНЫМ ЛИТЕРАЛОМ в самом
     органе — то есть писателя не имело вовсе: величина была, а объявления не было, и
     спросить её было не у кого. Здесь она объявлена один раз (карта 10005376). */
  --sui-gr-top:     0;

  /* ── ОБЛИК ГРАФИКА ВРЕМЕННОГО РЯДА (карта 10008345) ─────────────────────────
     Палитра общего органа `shared/components/suite-time-chart.js` жила кодами цвета
     в самом органе: смена вида семьи его не достигала. Здесь она объявлена один раз.
     Два вида разводятся ИМЕНЕМ, а не правилом показа: светлый вид — имя без окончания,
     тёмный — то же имя с окончанием `-dark`; орган выбирает набор сам, как выбирал
     раньше. Правил [data-theme] и prefers-color-scheme этот файл не держит: приём тона
     семьи один — :root[data-theme="base-dark"] в shared/themes/base-dark/base-dark.css.
     Значения перенесены знак в знак с прежних кодов органа. */
  --ge-chart-bg:                 #ffffff;
  --ge-chart-grid:               #e2e5e9;
  --ge-chart-text:               #334155;
  --ge-chart-axis:               #b6bcc4;
  --ge-chart-tip-bg:             rgba(255,255,255,.98);
  --ge-chart-tip-text:           #1f2937;
  --ge-chart-tip-border:         #d0d5dd;
  --ge-chart-bg-dark:            #1e1e1e;
  --ge-chart-grid-dark:          #3a3a3a;
  --ge-chart-text-dark:          #d4d4d4;
  --ge-chart-axis-dark:          #5a5a5a;
  --ge-chart-tip-bg-dark:        rgba(30,30,30,.96);
  --ge-chart-tip-text-dark:      #eaeaea;
  --ge-chart-tip-border-dark:    #4a4a4a;
  /* Наложения графика: черта стадии, её подпись и порог. Вид у них один — прежние
     запасные значения органа от вида не зависели. */
  --ge-chart-overlay-line:       #6a6a6a;
  --ge-chart-overlay-label:      #8a8a8a;
  --ge-chart-threshold:          #ff5252;

  /* ТОЛЩИНЫ ЛИНИЙ ГРАФИКА (карта 10011260). Жили литералами прямо в отрисовке органа —
     пять чисел в пяти местах, — и спросить толщину было не у кого. Значения перенесены
     с прежних литералов ДОСЛОВНО: смена облика у потребителей этой картой не делается.
     Толщин объявлено три, потому что различимых величин в органе три: волосяная (сетка,
     черта стадии, перекрестие), кривая и порог. Порог толще волосяной намеренно —
     он объявляет предел, а не разлиновку. */
  --ge-chart-grid-w:             1;
  --ge-chart-line-w:             2;
  --ge-chart-threshold-w:        1.5;

  /* КАТЕГОРИАЛЬНАЯ ШКАЛА СЕРИЙ (карта 10011260). Цвет кривой приходил ТОЛЬКО полем вызова,
     и продукт, рисующий несколько кривых, назначал цвета сам: одна и та же вторая кривая
     в двух продуктах выходила разного цвета. Шкала — УМОЛЧАНИЕ: цвет, заданный вызовом,
     старше её и ею не подменяется.
     Шкала КАТЕГОРИАЛЬНАЯ, а не статусная: статусные записи (`ok`, `warn`, `err`) под серии
     не берутся — зелёная кривая означала бы «хорошо», а не «вторая серия» (DESIGN.md р. 4).
     Порядок и сами коды взяты выверенной на цветовую слепоту шкалой (Okabe–Ito): соседние
     серии различаются и светлотой, а не одним лишь тоном. */
  --ge-chart-series-1:           #0072b2;
  --ge-chart-series-2:           #e69f00;
  --ge-chart-series-3:           #009e73;
  --ge-chart-series-4:           #cc79a7;
  --ge-chart-series-5:           #56b4e9;
  --ge-chart-series-6:           #d55e00;
  /* Тёмный набор шкалы разведён ИМЕНЕМ, как и вся палитра графика: коды те же шесть, но
     первый и пятый меняются местами. Тёмный синий #0072b2 на полотне #1e1e1e даёт 3,2:1
     и к тёмной разлиновке #3a3a3a — 2,2:1, то есть первая же кривая тонула бы в сетке;
     светлый #56b4e9 на том же полотне даёт 7,2:1, а слабый синий уезжает в пятый слот,
     до которого доходят немногие графики. */
  --ge-chart-series-1-dark:      #56b4e9;
  --ge-chart-series-2-dark:      #e69f00;
  --ge-chart-series-3-dark:      #009e73;
  --ge-chart-series-4-dark:      #cc79a7;
  --ge-chart-series-5-dark:      #0072b2;
  --ge-chart-series-6-dark:      #d55e00;

  /* Градиент бренда (иконки/плитки/акценты) */
  --ge-brand-gradient: linear-gradient(135deg, var(--ge-color-brand), var(--ge-color-brand-2));

  /* Токены-алиасы (семейная совместимость имён; см. docs/THEMES.md) */
  --ge-color-text-secondary: var(--ge-color-text-mute);
  --ge-color-danger:         var(--ge-color-err);
  --ge-color-danger-fill:    #b91c1c; /* заливка опасной кнопки под белый текст: одинакова в обеих темах, --ge-color-err в тёмной осветляется под текст-на-холсте */
  --ge-color-primary:        var(--ge-color-brand);

  /* Величины утверждённого облика (писатель — облик, значения равны ему) */
  --ge-color-rail-surface:   var(--ge-color-surface);
  --ge-color-rail-text:      var(--ge-color-text);
  --ge-color-rail-hover:     var(--ge-color-hover);
  --ge-color-rail-active-bg:   var(--ge-color-brand-soft);
  --ge-color-rail-active-text: var(--ge-color-brand);
  --ge-color-rail-control-bg:  var(--ge-color-surface-2);
  --ge-color-rail-control-border: var(--ge-color-border);
  --ge-color-rail-text-mute:   var(--ge-color-text-mute);
  --ge-color-surface-raised: var(--ge-color-surface);
  --ge-font-heading:         'Segoe UI', system-ui, -apple-system, 'SF Pro Text', sans-serif;
  --ge-grid-line-color:      var(--ge-color-border);
  --ge-grid-cell-w:          0px;
  --ge-label-transform:      none;
  --ge-label-tracking:       normal;
  --ge-drawer-w-sm:          400px;
  --ge-drawer-w-md:          480px;
  --ge-drawer-w-lg:          720px;
  --ge-scrollbar-w:          10px;
  --ge-scrollbar-radius:     var(--ge-radius-pill);
  --ge-color-scrollbar-thumb:       var(--ge-color-text-faint);
  --ge-color-scrollbar-thumb-hover: var(--ge-color-text-mute);
  --ge-color-scrollbar-track:       transparent;
  --ge-page-mode-data:       none;
  --ge-page-mode-form:       var(--ge-measure-form);
  --ge-page-mode-read:       var(--ge-measure-read);
}

/* УЗКАЯ СТУПЕНЬ БОКОВОГО УЧАСТКА РАБОЧЕГО ЭКРАНА (карта 10006565). Переопределяет ТО ЖЕ имя,
   а не заводит второе: два имени сделали бы потребителя вторым решающим — ему пришлось бы
   держать своё условие по ширине и самому выбирать, какое читать.
   Число условия взято у объявленной ступени семьи (--gs-bp-tablet ниже, владелец перечня —
   scripts/responsive-layout-owner.guard.test.mjs): порог принадлежит лестнице ступеней, а не
   эскизу. Пользовательское свойство в условии медиа-правила не разворачивается, поэтому
   число здесь набрано — и сторож требует его совпадения со значением токена. */
@media (max-width: 1023px) {
  :root { --ge-panel-side-w: 300px; }
}

/* НАБОР ТЕЛА СТРАНИЦЫ — ЕДИНСТВЕННЫЙ ПИСАТЕЛЬ ФАКТА (карта 10004388). Правило жило в своде
   правил портала-лендинга (styles.css), а его грузят 19 оболочек из 33; остальные набирали тело
   литералом у себя, то есть заводили второго писателя. Здесь оно досягаемо всем: suite-theme.css
   подключают все 33 оболочки семьи. Величины не набраны — только ступени, объявленные выше. */
body {
  font: var(--ge-font-size-md)/var(--ge-line-height) var(--ge-font-family);
}

/* Системная настройка «меньше движения» гасит длительности В ОДНОЙ ТОЧКЕ: компонент,
   выражающий переход токеном, получает уважение к настройке даром и не обязан помнить
   про отдельное правило у себя. Ноль ставить нельзя — событие окончания перехода тогда
   не приходит, и код, который его ждёт, не закрывает слой. */
@media (prefers-reduced-motion: reduce) {
  :root { --ge-dur-1: 1ms; --ge-dur-2: 1ms; --ge-dur-3: 1ms; }
}

/* Базовые семейные хелперы (опционально; продукт может игнорировать) */
.ge-brand-mark {
  display: grid; place-items: center; width: 32px; height: 32px;
  border-radius: var(--ge-radius-lg); color: #fff; font-weight: 800;
  background: var(--ge-brand-gradient);
}
.ge-btn-brand {
  background: var(--ge-color-brand); color: #fff; border: none;
  border-radius: var(--ge-radius-md); padding: var(--ge-space-2) var(--ge-space-4);
  font: 600 var(--ge-font-size-md)/1 var(--ge-font-family); cursor: pointer;
}
.ge-btn-brand:hover { background: var(--ge-color-brand-hover); }
/* Значок состояния объявлялся ЗДЕСЬ и ещё раз в общем списке (`shared/data-grid.js`,
   `SuiteUI.pill`) — один род предмета, два писателя. Здешнее объявление не имело ни
   одного читателя во всём семействе и снято; вид значка задаёт компонент, который его
   и выдаёт. Нужен значок без списка — берётся оттуда же, `SuiteUI.pill(текст, род)`. */

/* ============================================================================
 * СТРУКТУРНЫЕ ПРИМИТИВЫ СЕМЕЙСТВА
 *
 * Раскладочные приёмы, которые каждый продукт до сих пор собирал у себя: полоса
 * органов, плиточная сводка раздела и набор сплошного текста. Пока их не было в
 * Ядре, «одинаковое» получалось похожим, но не тем же самым — и расходилось при
 * первой же правке. Здесь они объявлены один раз и раздаются всем.
 *
 * Правило этого блока: примитив НЕ несёт собственных значений. Всё — цвет, ступень,
 * отступ, радиус, длительность — берётся именами из словаря выше, БЕЗ запасных
 * литералов: запасное значение рядом с объявленным есть второй писатель того же
 * факта, и расходятся они молча. Запасные литералы уместны в продукте, который
 * грузит словарь по сети, а не в файле, где имя объявлено двадцатью строками выше.
 * ========================================================================== */

/* ── Полоса органов ──────────────────────────────────────────────────────────
   Кнопки, селекторы и поля, стоящие в одну строку, приходят к общей высоте и
   общему радиусу. Ступень задаётся КОНТЕЙНЕРОМ, а не органом: компактная кнопка
   не носит с собой контекстный отступ и не ломает вторую строку, куда её поставят.
   Проверка на соответствие канону сводится к одному вопросу — обёрнута ли строка
   органов сюда, — вместо вычитывания отступов у каждой кнопки. */
.ge-actionbar {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: var(--ge-space-2);
}
.ge-actionbar > button,
.ge-actionbar > select,
.ge-actionbar > input,
.ge-actionbar > a[class*="btn"] {
  margin: 0;
  height: var(--ge-control-h-sm);
  padding: 0 10px;
  display: inline-flex; align-items: center;
  border-radius: var(--ge-radius-control);
  font-size: var(--ge-font-size-sm);
  line-height: 1;
}
/* Разделитель групп внутри полосы: волосяная черта, а не отступ на глаз. */
.ge-actionbar > .ge-actionbar-sep {
  width: 1px; height: var(--ge-font-size-lg); margin: 0 var(--ge-space-1);
  background: var(--ge-color-border);
}
/* Всё, что правее, уходит к дальнему краю: одна декларация вместо `margin-left:auto`
   по месту у каждой второй кнопки. */
.ge-actionbar > .ge-actionbar-gap { flex: 1 1 auto; }

/* ── Плиточная сводка раздела ────────────────────────────────────────────────
   Входной экран раздела — не список ссылок и не таблица: это несколько ВХОДОВ
   разного веса. Сетка из шести долей даёт три ходовые ступени плитки (половина,
   треть, вся строка) без того, чтобы каждый раздел заводил свою колоночную схему.
   Цветное пятно на таком экране ОДНО — правило облика семейства; поэтому акцентная
   плитка объявлена в единственном числе и соседей по заливке не имеет. */
.ge-bento { display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--ge-space-3); }
.ge-bento-tile {
  grid-column: span 3;
  display: flex; flex-direction: column;
  background: var(--ge-color-surface);
  border: 1px solid var(--ge-color-border);
  border-radius: var(--ge-radius-xl);
  padding: var(--ge-space-4) var(--ge-space-5) var(--ge-space-5);
  transition: border-color var(--ge-dur-2) var(--ge-ease-out),
              box-shadow   var(--ge-dur-2) var(--ge-ease-out),
              transform    var(--ge-dur-2) var(--ge-ease-out);
}
.ge-bento-tile:hover {
  border-color: color-mix(in srgb, var(--ge-accent) 34%, var(--ge-color-border));
  box-shadow: var(--ge-elev-2);
  transform: translateY(-1px);
}
.ge-bento-third { grid-column: span 2; }
.ge-bento-wide  { grid-column: span 6; }
.ge-bento-accent {
  background: var(--ge-color-brand-soft);
  border-color: color-mix(in srgb, var(--ge-accent) 18%, var(--ge-color-border));
}
.ge-bento-accent:hover { border-color: color-mix(in srgb, var(--ge-accent) 40%, var(--ge-color-border)); }
.ge-bento-accent .ge-eyebrow { color: var(--ge-accent); }
/* Ярус плиток: подпись на волосяной черте вместо второго уровня заголовков. */
.ge-bento-sep {
  display: flex; align-items: center; gap: var(--ge-space-3);
  margin: var(--ge-space-4) 0 var(--ge-space-1);
  font-size: var(--ge-font-size-xs); font-weight: var(--ge-weight-semibold);
  text-transform: uppercase; letter-spacing: var(--ge-tracking-label);
  color: var(--ge-color-text-faint);
}
.ge-bento-sep::after { content: ''; flex: 1; height: 1px; background: var(--ge-color-border); }

/* ── Набор текста ────────────────────────────────────────────────────────────
   Рубрика, витринный заголовок и сплошной текст. Прописные с разрядкой — приём
   рубрики, а не способ набирать каждую подпись: разрядка здесь та же, что у шапки
   списка, отличается только кегль. */
.ge-eyebrow {
  font-size: var(--ge-font-size-eyebrow); font-weight: var(--ge-weight-semibold);
  text-transform: uppercase; letter-spacing: var(--ge-tracking-label);
  color: var(--ge-color-text-faint);
}
.ge-display {
  font-size: var(--ge-font-size-h1);
  line-height: var(--ge-line-height-display);
  letter-spacing: var(--ge-tracking-display);
  font-weight: var(--ge-weight-semibold);
  text-wrap: balance;
}
.ge-read {
  max-width: var(--ge-measure-read);
  font-size: var(--ge-font-size-read);
  line-height: var(--ge-line-height-read);
  text-wrap: pretty;
}
.ge-lead {
  max-width: var(--ge-measure-lead);
  font-size: var(--ge-font-size-lg);
  line-height: var(--ge-line-height);
  color: var(--ge-color-text-mute);
  text-wrap: pretty;
}
.ge-read code, .ge-read kbd {
  font-family: var(--ge-font-mono); font-size: var(--ge-font-size-code);
}
/* Широкая таблица внутри читаемого текста уезжает в СВОЮ прокрутку, а не тащит
   вбок всю страницу. */
.ge-read table { display: block; overflow-x: auto; max-width: 100%; }

/* ── Узкий экран ─────────────────────────────────────────────────────────────
   Плитка складывается ступенями: половина → треть строки → вся строка. Полоса
   органов переносится сама (`flex-wrap`) и отдельного правила не требует. */
@media (max-width: 1023px) {
  .ge-bento-tile, .ge-bento-third { grid-column: span 3; }
}
@media (max-width: 640px) {
  .ge-bento { gap: var(--ge-space-2); }
  .ge-bento-tile, .ge-bento-third { grid-column: span 6; }
}
/* Настройка «меньше движения» гасит длительности выше в одной точке; сдвиг плитки
   под курсором — не длительность, а РАССТОЯНИЕ, и снимается отдельно. */
@media (prefers-reduced-motion: reduce) {
  .ge-bento-tile:hover { transform: none; }
}

/* ============================================================================
 * ЕДИНЫЙ ВИД ЛЕВОГО САЙДБАРА (interim-унификация геометрии, 2026-06-14).
 * Канон: ПЛОСКАЯ панель (не плавающая карточка), пункт-«пилюля» с одинаковыми
 * отступами/скруглением/высотой; активный пункт — ЗАЛИВКА цветом-акцентом продукта
 * (var(--ge-accent…)) БЕЗ рамки. Цвет-акцент остаётся per-product (настраивается
 * в админке «Продукты семейства»). `!important` — временный приём, чтобы перебить
 * локальные правила каждого модуля одним центральным файлом; перевод на общий
 * компонент без !important — отдельная веха «довести до совершенства».
 * Продукты грузят этот файл с suite-домена ⇒ правка раскатывается на все сразу.
 * ============================================================================ */
:root {
  --ge-nav-item-pad: 9px 12px;
  --ge-nav-item-radius: 8px;
  --ge-nav-item-gap: 10px;
  --ge-nav-item-mb: 2px;
  --ge-nav-active-bg: var(--ge-accent-soft);
  --ge-nav-active-fg: var(--ge-accent);
  --ge-nav-hover-bg: var(--ge-color-hover);
}
/* — Пункт навигации: единая геометрия (перечислены классы всех модулей) — */
.sidebar .nav-item, .dcc-nav-item, .om-tab,
.hr-nav-item, .fin-nav-item, .gm-nav-item, .svc-nav-item, .lg-nav-item,
.own-nav-item, .flw-nav-item, .admin-nav-item, .admin-nav .nav-item {
  padding: var(--ge-nav-item-pad) !important;
  border-radius: var(--ge-nav-item-radius) !important;
  border: 1px solid transparent !important;
  gap: var(--ge-nav-item-gap) !important;
  margin-bottom: var(--ge-nav-item-mb) !important;
  font-size: var(--ge-font-size-md) !important;
  font-weight: 500 !important;
}
/* — Hover: единый приглушённый фон — */
.sidebar .nav-item:hover, .dcc-nav-item:hover, .om-tab:hover,
.hr-nav-item:hover, .fin-nav-item:hover, .gm-nav-item:hover, .svc-nav-item:hover,
.lg-nav-item:hover, .own-nav-item:hover, .flw-nav-item:hover,
.admin-nav-item:hover, .admin-nav .nav-item:hover {
  background: var(--ge-nav-hover-bg) !important;
}
/* — Активный пункт: ЗАЛИВКА акцентом, БЕЗ рамки (убираем «обведённый» вид) — */
.sidebar .nav-item.active, .dcc-nav-item.active, .om-tab-on,
.hr-nav-item.active, .fin-nav-item.on, .gm-nav-item.active, .svc-nav-item.on,
.lg-nav-item.on, .own-nav-item.on, .flw-nav-item.on,
.admin-nav-item.active, .admin-nav .nav-item.active {
  background: var(--ge-nav-active-bg) !important;
  color: var(--ge-nav-active-fg) !important;
  border-color: transparent !important;
  font-weight: 600 !important;
}
/* — Списки проектов (G-Vault `.proj`, G-PM `.projects li`) — активную строку к общему виду
     (заливка-акцент вместо разнобойной левой полоски); геометрию списка не трогаем. — */
.proj.active, .side .proj.active, .projects li.active {
  background: var(--ge-nav-active-bg) !important;
  color: var(--ge-nav-active-fg) !important;
  border-inline-start-color: transparent !important;
  font-weight: 600 !important;
}
/* — Контейнеры-КАРТОЧКИ → ПЛОСКАЯ панель (DCC/HR/Management/OM): убираем
     скруглённую рамку и «короткую» высоту, оставляем правую границу-разделитель — */
.dcc-sidebar, .hr-sidebar, .gm-sidebar, .om-side {
  box-sizing: border-box !important;   /* padding входит в 420px (иначе G-OM был 445) */
  border: 0 !important;
  border-inline-end: 1px solid var(--ge-color-border) !important;
  border-radius: 0 !important;
  align-self: stretch !important;
  padding: 14px 12px !important;
  overflow-x: hidden !important;
}
/* — Фикс горизонтального скроллбара в сайдбарах (текст обрезается, не растягивает) — */
.dcc-nav-item .nm, .nav-item .nm, .om-tab .nm,
.hr-nav-item .nm, .fin-nav-item .nm, .gm-nav-item .nm, .svc-nav-item .nm,
.lg-nav-item .nm, .own-nav-item .nm, .flw-nav-item .nm {
  min-width: 0 !important;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* — Заголовок группы пунктов: единый стиль — */
.nav-group-label {
  font-size: 11px !important; text-transform: uppercase !important;
  letter-spacing: 1px !important; font-weight: 700 !important;
  color: var(--ge-color-text-faint) !important; margin: 14px 10px 6px !important;
}
/* — ПРАВИЛО (Пользователь 2026-06-14): НИ В ОДНОМ сайдбаре НЕ должно быть горизонтальной прокрутки.
     overflow-x:hidden на все контейнеры сайдбаров семейства (вкл. .admin-nav/#nav портала G-Dev). — */
.sidebar, .admin-sidebar, .admin-nav, .pnav, #pnav, #nav, #sideNav, #adminNav,
.dcc-sidebar, .hr-sidebar, .fin-sidebar, .gm-sidebar, .svc-sidebar,
.lg-sidebar, .own-sidebar, .flw-sidebar, .om-side, .side {
  overflow-x: hidden !important;
}
/* Пункты тоже не распирают контейнер (длинный текст — обрезкой, не скроллом). */
.admin-nav-item, .nav-item, .dcc-nav-item, .om-tab, .hr-nav-item, .fin-nav-item,
.gm-nav-item, .svc-nav-item, .lg-nav-item, .own-nav-item, .flw-nav-item {
  min-width: 0 !important; overflow: hidden !important; text-overflow: ellipsis !important;
}

/* ── a11y baseline (WCAG 2.1): видимый клавиатурный фокус, skip-link, sr-only, reduced-motion ──
   Семейный baseline (грузится всеми продуктами). Полный WCAG-аудит компонентов — отдельно. */
:focus-visible {
  outline: var(--ge-focus-ring-w) solid var(--ge-color-ring);
  outline-offset: 2px;
  border-radius: 3px;
}
.ge-skip-link {
  position: absolute; inset-inline-start: 8px; top: -48px; z-index:calc(var(--ge-z-focus) + 200);
  background: var(--ge-color-brand); color: #fff;
  padding: 8px 14px; border-radius: 8px; text-decoration: none; font: 600 13px system-ui;
  transition: top .15s;
}
.ge-skip-link:focus { top: 8px; }
/* ── Нетекстовый контраст границ полей ввода (WCAG 2.1 §1.4.11 ≥3:1) ──
   Нейтральные границы продуктов (#edebe9/#d2d0ce и аналоги) дают лишь ~1.2–1.5:1 к
   подложке — граница контрола неразличима. Поднимаем ТОЛЬКО ЦВЕТ уже видимых границ
   нативных контролов до --ge-color-control-border (border-width/style не трогаем —
   безрамочные поля остаются безрамочными). Состояния :focus(-visible) и [aria-invalid]
   исключены, чтобы сохранить брендовую/ошибочную обводку. Раздаётся всем продуктам с CDN. */
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not(:focus):not(:focus-visible):not([aria-invalid="true"]),
select:not(:focus):not(:focus-visible):not([aria-invalid="true"]),
textarea:not(:focus):not(:focus-visible):not([aria-invalid="true"]) {
  border-color: var(--ge-color-control-border) !important;
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
@media (prefers-reduced-motion: reduce) {
  *, ::before, ::after { animation-duration: .001ms !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* ═══ Режимы повышенного контраста ═══════════════════════════════════════════════
   Оба приходят ОТ СИСТЕМЫ, а не от нашего вкуса, и оба обрабатываются здесь —
   там же, где объявлены границы и ступени приподнятости. Продукт, закрывающий их
   у себя, чинит свои два экрана и оставляет остальные тридцать три.

   Что здесь НЕ понадобилось и почему — чтобы не искали пропущенного. Ступени
   --ge-elev-* тенью, а тень при принудительных цветах не рисуется вовсе; отсюда
   опасение, что всё приподнятое сольётся с фоном. Обход семейства: ступени
   употреблены в 14 правилах в 7 файлах, и каждая приподнятая ПОВЕРХНОСТЬ несёт
   границу своим базовым правилом (общая панель слоя — border у .sui-panel, плитка
   — border-color). Остальные четыре случая — состояния перетаскивания и нажатия у
   органов, у которых кромка уже есть. Компенсация приподнятости рамкой поэтому не
   вводится: правило, чинящее несуществующее, только мешает читать таблицу.
   Фокус в семействе рисуется outline (11 объявлений), а его режим не гасит. */

/* Система просит больше контраста: волосяная линия выходит на ступень органа —
   ту, что уже калибрована к 3:1 (WCAG 1.4.11) и в светлой, и в тёмной теме.
   Пишется ОДНО имя: --ge-color-control-border тема объявляет у себя, поэтому
   правило верно в обеих без второй записи. */
@media (prefers-contrast: more) {
  :root { --ge-color-border: var(--ge-color-control-border); }
}

/* Принудительные цвета (высокая контрастность): режим сам перекрашивает текст,
   фон и рамки, и своих цветов ему навязывать не нужно. Ломается здесь другое —
   состояние, которое опознавалось ТОЛЬКО заливкой: режим приводит заливки к
   системным, и «нажато» перестаёт отличаться от покоя. Состояние, объявленное
   СЕМАНТИКОЙ, получает системную пару состояния — единственную, которую режим не
   перекрашивает. Правило держится на признаках доступности, а не на именах классов
   продукта: класс у каждого свой, а объявление состояния — общее. */
@media (forced-colors: active) {
  [aria-pressed="true"],
  [aria-selected="true"],
  [aria-current="page"] { background: Highlight; color: HighlightText; }
}

/* ============================================================================
 * АДАПТИВНАЯ РАСКЛАДКА СЕМЕЙСТВА — ЕДИНСТВЕННЫЙ ВЛАДЕЛЕЦ ТРЁХ СТУПЕНЕЙ ШИРИНЫ
 * (карта 2209643).
 *
 * Зачем здесь. Раскладка семейства рассчитана на широкий экран: на планшете и
 * телефоне сайдбар занимал почти всю ширину, таблица тащила вбок всю страницу,
 * ящик и полноэкранный режим не помещались. Правило ширины обязано жить ОДНОЙ
 * реализацией и там, где его видят все продукты, — этот файл продукты грузят с
 * домена Suite, поэтому правка раскатывается на всех разом. Копия правила в
 * продукте есть вторая реализация того же факта и запрещена, включая копию
 * «пока только у нас».
 *
 * ПОЧЕМУ СТУПЕНЬ ЗАПИСАНА ДВАЖДЫ. Условие медиа-правила не принимает
 * пользовательское свойство: `@media (max-width: var(--gs-bp-phone))` не
 * работает ни в одном движке — это свойство языка, а не отступление от канона
 * токенов. Поэтому ступень объявлена здесь дважды и связанно: числом в условии
 * медиа-правила и тем же числом в токене для читателей на языке сценариев.
 * Второго писателя это не заводит — обе записи принадлежат одному владельцу, а
 * их совпадение сверяет сторож (`scripts/responsive-layout-owner.guard.test.mjs`):
 * расхождение числа в условии и в токене — находка, а не мелочь оформления.
 *
 * ПОЧЕМУ ЗДЕСЬ НЕТ ПЕРЕЧНЯ САЙДБАРОВ. У каждого продукта сайдбар зовётся своим
 * классом, и перечень этих классов — тоже ФАКТ, у которого обязан быть один
 * писатель. Писатель объявлен в общей шапке (`shared/app-header.js`, САЙДБАРЫ):
 * она узнаёт сайдбар страницы и метит его признаком `data-gs-side-panel`.
 * Здешние правила знают только признак. Перечисли мы классы ещё и тут — при
 * появлении нового продукта список разошёлся бы МОЛЧА, и сайдбар нового
 * продукта остался бы неадаптированным без единой красной проверки.
 *
 * ТРИ СТУПЕНИ.
 *   десктоп  от 1024px — канон широкого экрана, ничем ниже не отменяется;
 *   планшет  641…1023  — сайдбар сворачивается в тонкую полосу с раскрытием по
 *                        требованию, таблица прокручивается в СВОЁМ контейнере,
 *                        правый ящик занимает около 70% ширины;
 *   телефон  до 640    — сайдбар становится выдвижной панелью поверх содержимого,
 *                        ящик и полноэкранный режим разворачиваются на весь экран,
 *                        таблица переходит в карточный список.
 *
 * ЧТО УЗКАЯ ШИРИНА НЕ МЕНЯЕТ. Облик. Ни одного нового цвета, гарнитуры и тени
 * здесь не вводится — меняется только раскладка: положение, ширина, направление
 * потока и цель нажатия. Регистр интерфейса остаётся прежним.
 * ========================================================================== */
:root {
  /* Ступени — вход для сценариев; те же числа стоят в условиях ниже. */
  --gs-bp-phone: 640px;
  --gs-bp-tablet: 1023px;
  --gs-bp-desktop: 1024px;
  /* Наименьшая сторона цели нажатия на узком экране: палец не мельче. */
  --gs-tap-min: 44px;
  /* Сайдбар на планшете: полоса со значками, подписи прячутся до раскрытия. */
  --gs-side-narrow: 56px;
  /* Правый ящик по ступеням: на планшете доля ширины, на телефоне вся ширина. */
  --gs-drawer-tablet: 70vw;
  --gs-drawer-phone: 100vw;
}

/* ПОЛОСА ЗАНЯЛА КОЛОНКУ ЦЕЛИКОМ — РАБОЧЕЙ ПАНЕЛИ НЕТ ВОВСЕ (карта 10000612).
   Остаток здесь равен нулю, а панель нулевой ширины — это не «нет панели»: у неё
   остаётся волосяная граница, и человек видит лишнюю линию у самого рельса. Признак
   ставит РЕЛЬС в тот же миг, что и полосу (`suite-unified-sidebar.js`, applyPush): он
   единственный, кто знает, заняла ли полоса всю колонку, и второго писателя у этого
   факта не заводится. */
:root[data-gus-push-full] [data-gs-side-panel] { display: none; }

/* ── ПЛАНШЕТ И УЖЕ (до 1023px) ───────────────────────────────────────────────
   Переполнение принадлежит СВОЕМУ контейнеру, а не странице: страница вбок не
   ездит, ездит содержимое внутри своей рамки. */
@media (max-width: 1023px) {
  html, body { overflow-x: hidden; max-width: 100%; }
  /* Широкое содержимое уезжает в собственную прокрутку. Признак объявлен
     разметкой (`data-gs-scroll-x`), чтобы продукту не приходилось повторять
     правило у себя; общие контейнеры Ядра названы поимённо. */
  [data-gs-scroll-x], .ge-read table { overflow-x: auto; max-width: 100%; }

  /* Сайдбар — полоса; подписи прячутся, пункт остаётся нажимаемым. */
  [data-gs-side-panel] {
    width: var(--gs-side-narrow) !important;
    min-width: var(--gs-side-narrow) !important;
    flex: 0 0 var(--gs-side-narrow) !important;
    transition: width .16s ease, min-width .16s ease, flex-basis .16s ease;
  }
  /* Раскрытие ПО ТРЕБОВАНИЮ: объявленный шапкой признак раскрытия, наведение
     либо клавиатурный фокус внутри полосы. Три пути ведут в одно состояние —
     второй записи ширины ни один из них не заводит. */
  :root[data-gs-side="open"] [data-gs-side-panel],
  [data-gs-side-panel]:hover,
  [data-gs-side-panel]:focus-within {
    width: var(--ge-side-w) !important;
    min-width: var(--ge-side-w) !important;
    flex-basis: var(--ge-side-w) !important;
    max-width: 84vw !important;
  }
}

/* ── ТЕЛЕФОН (до 640px) ──────────────────────────────────────────────────────
   Сайдбар перестаёт занимать место постоянно: он выезжает ПОВЕРХ содержимого и
   уходит обратно. Открывает его орган общей шапки — он же и закрывает, так что
   состояние пишет ровно одно место (`:root[data-gs-side]`). */
@media (max-width: 640px) {
  [data-gs-side-panel] {
    position: fixed !important;
    inset-block: var(--ge-header-h) 0;
    inset-inline-start: 0;
    z-index: 9988;
    width: min(84vw, var(--ge-side-w)) !important;
    min-width: 0 !important;
    flex: 0 0 auto !important;
    background: var(--ge-color-surface);
    border-inline-end: 1px solid var(--ge-color-border);
    transform: translateX(-102%);
    transition: transform .18s ease;
  }
  :root[data-gs-side="open"] [data-gs-side-panel] { transform: none; }

  /* Цель нажатия не мельче пальца. Правило держится на признаках органа, а не на
     именах классов продукта: класс у каждого свой, а «это орган» — общее. */
  button, [role="button"], summary,
  input[type="button"], input[type="submit"], input[type="reset"],
  select, input[type="checkbox"], input[type="radio"] {
    min-height: var(--gs-tap-min);
    min-width: var(--gs-tap-min);
  }
  /* Поле ввода — не цель нажатия, а зона ввода: навязанная ширина в 44px порвала
     бы форму. Высоту всё же поднимаем — попасть в поле пальцем нужно так же. */
  input:not([type=button]):not([type=submit]):not([type=reset]):not([type=checkbox]):not([type=radio]):not([type=hidden]),
  textarea { min-height: var(--gs-tap-min); }

  /* Фиксированный подвал отдаёт высоту содержимому: на телефоне он уходит в
     поток, и резерв снизу становится не нужен. Высота объявлена НУЛЁМ, чтобы
     читатели токена (`--gsf-footer-h`) считали доступную высоту тем же числом,
     каким её считает раскладка. */
  :root { --gsf-footer-h: 0px; }

  /* Место, объявившее устройства без телефона, показывает сообщение вместо
     рабочего поля. Сообщение вкладывает общая шапка (`app-header.js`, РАБОТА НЕ
     ДЛЯ ТЕЛЕФОНА); здесь только ступень, на которой оно видно. */
  [data-gs-devices]:not([data-gs-devices~="phone"]) > :not([data-gs-phone-notice]) { display: none !important; }
  [data-gs-devices]:not([data-gs-devices~="phone"]) > [data-gs-phone-notice] { display: block; }
}

/* Вне ступени телефона сообщение о работе не для телефона не видно. */
[data-gs-phone-notice] { display: none; }

/* Настройка «меньше движения» отменяет ДВИЖЕНИЕ панели, но не её появление:
   содержимое остаётся видимым, исчезает только выезд. */
@media (max-width: 1023px) and (prefers-reduced-motion: reduce) {
  [data-gs-side-panel] { transition: none; }
}

/* Орган раскрытия сайдбара принадлежит общей шапке. На широком экране он не
   нужен — сайдбар стоит постоянно, открывать нечего; на странице без сайдбара
   он не нужен тем более, поэтому показывается только когда шапка САЙДБАР НАШЛА. */
.rs-side-toggle { display: none; }
@media (max-width: 1023px) {
  :root[data-gs-side-present="1"] .rs-side-toggle {
    display: inline-flex; align-items: center; justify-content: center;
  }
}

/* central brand override — gsuite_brand_settings (единая точка управления) */
:root{
  --ge-brand-seed: #4f46e5;
}
