@import url('https://fonts.googleapis.com/css2?family=Assistant:wght@400;500;600;700;800&display=swap');
:root{
  /* Ярус D (заход 76). Без color-scheme браузер рисует СВОИ полосы прокрутки
     светлыми независимо от темы: в тёмном дашборде вдоль списка объектов шла
     белая полоса 22px (#fcfcfc), и цветная рамка карточки упиралась в неё.
     Дефект жил с появления тёмной темы и к цвету состояния отношения не имеет. */
  color-scheme:dark;
  /* Полоса прокрутки: тонкая, дорожка прозрачная. Обе свойства НАСЛЕДУЕМЫЕ —
     одно объявление на :root достаёт до всех десяти прокручиваемых контейнеров
     (#listPane, #pageSinun, .fs-scroll, .mk-right и остальных) и не устареет
     на одиннадцатом. Было: дорожка 23px серым #2c2c2c, ползунок 13px внутри неё —
     дорожка читалась отдельной полосой и «наезжала» на ползунок.
     ⚠️ scrollbar-color обязан быть объявлен и в body.light: источник --ctl-bd
     там другой, а значение застывает там, где объявлено. */
  scrollbar-width:thin; scrollbar-color:var(--scroll-thumb) transparent;
  --scroll-thumb:#6e7681;   /* 4.12:1 на фоне страницы · 3.77:1 на карточке, порог 3 */
  --bg:#0d1117; --surface:#161b22; --surface2:#21262d; --border:#30363d;
  --text:#e6edf3; --text-dim:#9aa7b5; --card-shadow:0 2px 12px rgba(0,0,0,.4);
  /* A-0 (заход 51). Закон 2 канона: токен называется по роли, а не по цвету.
     Роли объявлены ИСТОЧНИКОМ, старые цветовые имена оставлены псевдонимами —
     поэтому все 47 существующих обращений к --green продолжают работать без
     единой правки, а новые правила пишутся уже по роли. Значения не изменены
     ни на бит: A-0 не должен двигать ни одного пикселя. */
  --status-ok:#15803d; --status-fault:#dc2626; --status-warn:#c2410c; --status-pending:#6b7280;
  /* Ярус D, шаг 1 (заход 76). ДВЕ СТУПЕНИ НА РОЛЬ — вывод из чисел, не из вкуса:
     ни одно значение не проходит обе поверхности. #16a34a на тёмной карточке 4.62:1,
     на белой 3.30:1; #15803d наоборот — 5.02:1 и 3.03:1. Значит ступеней обязано быть две.
       --status-*     КРЕПКАЯ, одна на обе темы: заливка под белым текстом, маркер
                      на тайле OSM, цвет текста в СВЕТЛОЙ теме.
       --status-*-tx  МЯГКАЯ в тёмной теме, равна крепкой в светлой: текст, границы,
                      точки-индикаторы, полоса карточки.
     ⚠️ -tx объявлена в ОБОИХ тема-блоках, иначе псевдоним застывает там, где объявлен.
     Крепкая под белым текстом: ok 5.02 · fault 4.83 · warn 5.18 · pending 4.83 (порог 4.5).
     Мягкая на карточке #21262d:  ok 6.68 · fault 5.50 · warn 6.72 · pending 4.95 (порог 4.5).
     Было девять пар ниже порога, включая D-85 (белое число на .cnt — 3.56:1). */
  --status-ok-tx:#22c55e; --status-fault-tx:#f87171; --status-warn-tx:#fb923c; --status-pending-tx:#9aa3af;
  /* ⚠️ Источник смысла. Производные под другие фоны: --stripe-* (карточка),
     --marker-* (тайлы OSM). Правишь здесь — пересчитай оба (D-141). */
  --status-fixed:#93c5fd; --status-fixed-bg:#2563eb26;
  --action-primary:#2563eb; --action-primary-tx:#ffffff;
  --action-danger:#dc2626; --action-danger-tx:#f87171;
  /* A-1.2: выбранное — НЕ действие (D-55). Своя тихая пара.
     Рамка на ступень светлее действия: #2563eb на карточке даёт 2.94:1
     при пороге 3:1 для границ, #3b82f6 — 4.14:1. Текст на подсветке 7.4:1. */
  --sel-bg:#2563eb26; --sel-tx:#93c5fd; --sel-bd:#3b82f6;
  --focus-ring:#58a6ff;
  --green:var(--status-ok-tx); --green-soft:#16a34a22;
  /* Роль: текст ЗАПИСИ СОБЫТИЯ в карточке задачи, а не состояния.
     ⚠️ ПСЕВДОНИМ РАЗРЕШАЕТСЯ ТАМ, ГДЕ ОБЪЯВЛЕН, а не там, где используется.
     --evt-tx:var(--text) в :root застывает тёмным #e6edf3 навсегда; body.light меняет
     --text, но на уже вычисленный псевдоним это не действует — в светлой теме строка
     вышла почти белой на белом. Поэтому псевдоним ОБЯЗАН быть объявлен в КАЖДОЙ
     теме, где меняется его источник — точно так же, как сделано с --blue и --red. */
  --evt-tx:var(--text);
  --red:var(--status-fault-tx); --orange:var(--status-warn-tx); --orange-soft:#ea580c22;
  --grey:var(--status-pending-tx); --blue:var(--action-primary); --yellow:#ca8a04;
  --pp-accent-bg:#2563eb24; --pp-accent-tx:#93c5fd;
  --svc-bg:#ea580c1f; --svc-bd:#ea580c66; --svc-tx:#fdba74;
  --rev-bg:#ca8a041f; --rev-bd:#ca8a0466; --rev-tx:#fcd34d;
  --pp-hover:#ffffff0a;
  --legend-bg:#0d1117dd;
  --text-faint:#6e7681; --card-shadow-hover:0 6px 22px rgba(0,0,0,.55);
  --tint-blue:#2563eb26; --tint-green:#16a34a26; --tint-red:#ef44441f; --tint-orange:#ea580c26;
  --fault-plate:#2e181c; --fault-line:#7f2f34; --fault-fg:#f87171;
  --pop-bg:#21262d; --pop-bd:#3d444d; --pop-shadow:0 18px 44px -12px rgba(0,0,0,.72),0 4px 14px rgba(0,0,0,.45);
  /* ШКАЛА РАЗМЕРОВ. Ярус D, D-02 (заход 77): добавлены две ступени, --fs-h4 (20px)
     и --fs-display (24px) — они закрывали дыры 18->22 и 22->28, куда падали
     семнадцать размеров, писанных сырым числом. Лестница в px при базе 16:
     14 · 15 · 16 · 18 · 20 · 22 · 24 · 28 (см. подъём ниже). Верхней ступени 36px больше нет:
     --fs-h1 и --lh-tight не использовались ни разу ни в CSS, ни в HTML, ни в JS
     (грепнуто в заходе 77). Мёртвая ступень выглядит как разрешение, которого нет.
     --fs-display — крупное значение или заголовок экрана (число KPI, часы).
     ⚠️ Ступеней ДЕВЯТЬ, и все девять объявлены в app/style.css теми же значениями.
        Правишь здесь — правь и там: имена совпадут, значения разъедутся молча. */
  /* ПОДЪЁМ НИЗА ШКАЛЫ, заход 81. Владелец: «текст мелкий, приходится всматриваться».
     Измерено: 112 объявлений из 190 в дашборде были мельче 16px, самая частая
     ступень — 15px. Опыт с ползунком (110%) подтвердил: мелко именно внизу.
     Поднят низ, верх не тронут — числа KPI и заголовки не сдвинулись, поэтому
     раскладка осталась прежней. Лестница в px при базе 16:
     14 · 15 · 16 · 18 · 20 · 22 · 24 · 28.
     ⚠️ --fs-label теперь равен --fs-body (16px): ступень 15px схлопнулась.
        Ступень НЕ упразднена намеренно — упразднить значит переписать 102 места
        в 21 модуле, а грепа по ним ещё не было. До тех пор label остаётся ролью
        с тем же значением. Оба приложения правятся ОДНОЙ выдачей, иначе имена
        совпадут, а значения разъедутся молча. */
  --fs-micro:.875rem; --fs-small:.9375rem; --fs-label:1rem; --fs-body:1rem; --fs-lead:1.125rem;
  --fs-h4:1.25rem; --fs-h3:1.375rem; --fs-display:1.5rem; --fs-h2:1.75rem;
  --lh-body:1.5;
  /* ШКАЛА РАДИУСОВ. Ярус D, D-06 (заход 77). Радиус — признак ПОРОДЫ элемента,
     поэтому имена по роли, а не по величине. Было 25 разных значений в дашборде
     и 13 в полевом, через var() — ноль. Стало четыре ступени + две формы:
       xs    4px  — мелочь под 24px: счётчик порядка, пин парковки на карте
       chip  8px  — чипы, бейджи-прямоугольники, мелкие плашки
       ctl  12px  — контролы: кнопки, поля ввода, вкладки, иконочные кнопки
       card 14px  — карточки: объект, задача, KPI, секция
       panel 18px — модальные окна, листы, крупные панели
     ⚠️ Исключение — .kmed и .ig-icon: там радиус держится ПРОПОРЦИЕЙ к стороне
        квадрата (46/13, 40/11, 28/8 = ~28%), а не шкалой. Токен сломал бы форму
        на маленьком размере. Те же шесть значений объявлены в app/style.css. */
  --r-xs:.25rem; --r-chip:.5rem; --r-ctl:.75rem; --r-card:.875rem; --r-panel:1.125rem;
  --r-pill:999px; --r-circle:50%;
  /* ШКАЛА ПРОБЕЛОВ. Ярус D, D-06 (заход 77). Было 33 разных значения gap в
     дашборде и 13 в полевом, через var() — ноль; между .4rem и .45rem нет
     разницы для глаза, но есть для грепа. Семь ступеней, лестница в px:
       2xs 2 · xs 4 · sm 6 · md 8 · lg 12 · xl 16 · 2xl 24
     Те же семь объявлены в app/style.css теми же значениями.
     ⚠️ Шкала пока покрывает только gap. padding и margin остались сырыми
        числами — это отдельная работа, и её объём (сотни мест) не смешивается
        с этой, чтобы регрессию можно было отличить от наследства. */
  --sp-2xs:.125rem; --sp-xs:.25rem; --sp-sm:.375rem; --sp-md:.5rem; --sp-lg:.75rem;
  --sp-xl:1rem; --sp-2xl:1.5rem;
  /* ПЛАШКИ .b-* (D-09 ч.2, заход 77). Фон плашки — полупрозрачная заливка, одна на
     обе темы; цвет текста тему учитывает. Токенизированы ФОНЫ и те цвета текста,
     что были написаны литералом в обеих темах.
     ⚠️ Цвет текста .b-grey / .b-media / .b-access НАМЕРЕННО оставлен как var(--text-dim)
        прямо в правиле. Псевдоним --x:var(--text-dim) в :root разрешается ТАМ, ГДЕ
        ОБЪЯВЛЕН, то есть на html — и застывает мимо body.bold-ui, который меняет
        --text-dim ниже по дереву. Режим крупного текста потерял бы контраст молча. */
  --badge-red-bg:#dc262622;      --badge-grey-bg:#6b728022;
  --badge-overdue-bg:#ca8a0422;  --badge-overdue-tx:#fbbf24;
  --badge-blue-bg:#2563eb22;     --badge-blue-tx:#60a5fa;
  --badge-plan-bg:#7c3aed22;     --badge-plan-tx:#a78bfa;
  --badge-manual-bg:#7c3aed22;   --badge-manual-tx:#a78bfa;
  --badge-hoara-bg:#f59e0b22;    --badge-hoara-tx:#fbbf24;
  /* ПОДЛОЖКИ-ПЛИТЫ (D-09 ч.3, заход 77). Полупрозрачная заливка + рамка того же
     цвета — приём повторяется у опасности (список удаляемого, предупреждение сброса)
     и у замысла (шапка плановых задач). Работают на обеих темах, потому объявлены
     один раз. */
  --danger-plate-bg:#dc262614;   --danger-plate-bd:#dc262633;
  --plan-plate-bg:#7c3aed14;     --plan-plate-bd:#7c3aed55;
  /* Поля ввода. Рамка ЯРЧЕ обычной --border: в тёмной теме тень (--card-shadow) чёрная
     на чёрном и границу поля не рисует вовсе, поэтому её работу берёт на себя рамка.
     #6e7681 против фона карточки (--surface2) = 3.3:1 — порог WCAG для нетекстовых границ.
     Заливка (заход 42): было #161b22 — ТЕМНЕЕ карточки (--surface2 #21262d), на которой
     поле лежит, и РОВНО фон шапки (--surface) под полем поиска. Поле читалось как дыра,
     а в светлой теме оно белое на сером — смысл «сюда пишут» был перевёрнут между темами.
     Теперь ступень ВЫШЕ карточки. Текст --text на новой заливке = 10.3:1 (было 13.9:1) —
     запас огромен, пересчитывать контрасты текста не потребовалось. */
  --inp-bg:#2b323c; --inp-bd:#6e7681; --inp-focus:#58a6ff; --inp-ring:#58a6ff33;
  /* Карточка сотрудника: шапка и кружок номера. Свои переменные, не --tint-blue —
     та живёт в 10 местах дашборда и сдвигать её ради одной модалки нельзя. */
  --st-head:#2563eb4d; --st-num-bg:#2563eb; --st-num-tx:#ffffff; --tag-own-tx:#93c5fd;
  /* Модальный слой. В тёмной теме всплывающее окно не отделяется НИЧЕМ:
     заливка модалки против фона = 1.17:1, штатная рамка --border = 1.42:1,
     тень чёрная на чёрном. Границу берёт на себя своя яркая рамка (5.6:1) —
     на ступень выше рамки поля ввода (--inp-bd, 3.8:1), чтобы внешний контур
     окна читался раньше, чем контуры полей внутри него.
     Скрим глубже штатного .6: за окном лежит карта и светлые карточки. */
  /* Пустое значение паспорта (אין מידע). Было opacity:.7 — она мешает текст
     с фоном карточки и роняет 6.2:1 до 3.8:1 (в светлой теме до 3.35:1).
     Явный цвет: тише значения и метки, но выше порога 4.5:1 для текста. */
  /* Карточный ярус. Лестница отделения: модальное окно (--modal-bd, 5.6:1)
     > карточка и поле ввода (~3.3:1) > разделители внутри карточки (тихие).
     Штатная --border даёт на карточке 1.25:1 — края не рисует вовсе, и в
     тёмной теме подхватить их нечем: тень чёрная на чёрном. Тот же оттенок,
     что у --inp-bd, — новой краски не заводим.
     Трогать --border нельзя: она работает в 99 местах. */
  /* Лента объектов. Контура у карточки НЕТ: в списке из 121 штуки каждая линия
     умножается на сотню, а низ одной карточки и верх следующей склеиваются в
     грязную полосу. Смысл несёт только левая по потоку полоса статуса (в RTL
     она справа) — ей и отдана вся работа: шире и ярче базовых --green/--red/
     --grey, которые трогать нельзя (заняты в 47 строках). */
  --obj-bd:transparent; --obj-stripe:8px;
  --stripe-ok:var(--status-ok-tx); --stripe-fault:var(--status-fault-tx); --stripe-pending:var(--status-pending-tx);
  /* D-141 (заход 69). Цвет состояния жил в ТРЁХ независимых источниках, и один
     из них — литералы внутри markerColor() в map.js. Заход 68 поднял --stripe-ok
     ради контраста, маркер карты остался прежним: ОДИН СМЫСЛ, ДВА ЗЕЛЁНЫХ.
     Ярус D свёл их в две ступени: --stripe-* = мягкая (--status-*-tx, фон КАРТОЧКИ),
     --marker-* = крепкая (--status-*, ТАЙЛЫ OSM). Значения маркеров не изменились
     ни на бит — крепкая ступень и была взята из них. Отдельных литералов здесь больше нет,
     менять цвет состояния теперь можно ровно в одном месте — выше.
     ⚠️ --marker-* объявлены ОДИН раз и НЕ переопределяются в body.light намеренно:
     тайлы OSM в тёмной теме не темнеют (фильтра на .leaflet в проекте нет), фон
     маркера одинаков в обеих темах — второе объявление меняло бы цвет без причины.
     Считано против белой обводки маркера (2.5px #fff, она же отделяет от тайла) и
     против фона суши OSM #f2efe9. Порог 3:1 — носитель смысла; 4.5:1 — белая буква
     P на квадрате חניון, это обычный текст.
       --marker-fault  #dc2626 — 4.83:1 обводка · 4.21:1 тайл · 4.83:1 буква P
       --marker-pending#6b7280 — 4.83:1 обводка · 4.21:1 тайл · 4.83:1 буква P
       --marker-ok     #15803d — 5.02:1 обводка · 4.37:1 тайл · 5.02:1 буква P
     ⚠️ Прежний #16a34a давал 2.87:1 против тайла (порог 3:1) и 3.30:1 под белой
     буквой P (порог 4.5:1) — маркер חניון был честно нарисован и честно нечитаем.
     Взято значение --stripe-ok светлой темы: два зелёных схлопнулись в один. */
  --marker-ok:var(--status-ok); --marker-fault:var(--status-fault); --marker-pending:var(--status-pending);
  --card-bd:#6e7681;
  /* Контрольный ярус: кнопки-иконки шапки и off-состояние чипов/табов.
     Их край нёс штатный --border (1.4:1 в тёмной), а фон .icon-btn = фон
     шапки (--surface) → кнопку рисовала только рамка, и та не читалась.
     Тот же ярус, что --inp-bd/--card-bd (3.3:1). Своя переменная, не --border
     (та в 99 местах) и не --card-bd (контрол — не карточка). */
  --ctl-bd:#6e7681;
  /* Разделитель колонок в заголовке секции. Отдельный токен, а не --border:
     --border рисует рамки блоков и заведомо тише — на волосяной вертикали
     длиной в строку его не видно вовсе (осмотр владельца, заход 67).
     Значение — ступень «контрол»: 3.74:1 на --surface при пороге 3:1. */
  /* Заливка чипа номера: одно значение на обе темы — нейтральный серый с прозрачностью
     работает и на тёмной, и на светлой поверхности. Отделяет чип не она, а рамка. */
  --chip-num-bg:#78788c24;
  --acc-rule:#6e7681;
  /* D-124: текст чипа неисправности. Своя переменная, а не --fault-fg:
     в тёмной значения совпадают (#f87171 = 6.01:1 на плите --fault-plate),
     но в светлой --fault-fg #dc2626 даёт на плите #fef2f2 всего 4.41:1
     при пороге 4.5:1 для обычного текста. Объявлений два — по числу тем. */
  --fault-chip-tx:#f87171;
  --grp-head-bg:#1c232c; --grp-head-tx:#c9d4e0;
  --pp-empty:#8b949e;
  --modal-bd:#8b949e; --modal-scrim:rgba(0,0,0,.72);
  --modal-shadow:0 24px 64px -12px rgba(0,0,0,.85),0 8px 24px rgba(0,0,0,.55);
}
body.light{
  color-scheme:light;
  scrollbar-width:thin; scrollbar-color:var(--scroll-thumb) transparent;
  --scroll-thumb:#6b7280;   /* 4.11:1 на фоне · 4.83:1 на карточке. --ctl-bd тут давал 3.10:1 — впритык */
  /* Светлая тема, переработана 26.07.2026 (заход 38). Прежние значения были
     измерены и провалены: --border на белой карточке давал 1.25:1, фон страницы
     против карточки 1.07:1, тот же --border на --surface2 (кнопки, табы, чипы)
     1.11:1. Порог WCAG 1.4.11 для нетекстовых границ — 3:1. То есть блоки не
     "бледнили на плохом мониторе", они были вне нормы на любом; хорошая панель
     их вытягивала, дешёвая — нет. Комментарии здесь обещали, что работу берёт
     на себя тень, но тень стояла на альфе .04/.06 и не рисовалась вовсе.

     Прежняя ошибка структурная: лестница отделения, выстроенная в тёмной теме,
     тут схлопывалась — все пять ярусных переменных имели одно значение #e3e6ea.
     Восстановлена та же лестница, что наверху:
       окно --modal-bd #5b6675 .................. 5.8:1 на белом
       карточка/поле/контрол #7d8794 ............ 3.6:1 на белом, 3.3:1 на
                                                  --surface2, 3.1:1 на фоне
                                                  страницы (клирит все три)
       лента объектов --obj-bd #a8b2be .......... 2.1:1 — намеренно тише: 121
                                                  карточка подряд, а смысл несёт
                                                  полоса статуса (4.8:1) и разница
                                                  заливок; контуры такой плотности
                                                  склеились бы в грязную полосу
       разделители --border #d4d9e0 ............. 1.4:1, тихие и это правильно —
                                                  после свипа за ними остались
                                                  ТОЛЬКО разделители внутри блоков

     Признаков отделения теперь три независимых, чтобы потеря одного не убивала
     границу: (1) рамка ≥3:1, (2) фон страницы #e9edf3 заметно серее белой
     карточки, (3) тень с рабочей альфой .10/.07. Инструмент ЧС смотрят с чего
     попало — старый монитор в кабинете, телефон на солнце. Один признак здесь
     роскошь.

     --text-faint потемнён #64748b → #5c6b7f: фон страницы стал темнее, и на нём
     прежний оттенок падал до 4.05:1 (порог для текста 4.5). На новом — 4.6:1.
     Правило "яркость одного элемента может уронить соседний" отработано. */
  /* Ярус D: --status-fault:#dc2626 отсюда УБРАН — крепкая ступень одна на обе темы.
     В светлой теме мягкая ступень равна крепкой: тёмный текст на белой карточке. */
  --status-ok-tx:var(--status-ok); --status-fault-tx:var(--status-fault);
  --status-warn-tx:var(--status-warn); --status-pending-tx:var(--status-pending);
  --action-primary:#005eb8; --focus-ring:#005eb8;
  --action-danger-tx:#b91c1c;
  --sel-bg:#eff4ff; --sel-tx:#1d4ed8; --sel-bd:#005eb8;
  --status-fixed:#005eb8; --status-fixed-bg:#eff4ff;
  --bg:#e9edf3; --surface:#ffffff; --surface2:#f1f4f8; --border:#d4d9e0;
  --blue:var(--action-primary);
  /* ⚠️ Все четыре псевдонима обязаны быть переобъявлены здесь: их источник (-tx)
     в этой теме другой, а псевдоним разрешается там, где ОБЪЯВЛЕН. */
  --red:var(--status-fault-tx); --green:var(--status-ok-tx);
  --orange:var(--status-warn-tx); --grey:var(--status-pending-tx);
  --text:#0f172a; --text-dim:#475569; --text-faint:#5c6b7f;
  --evt-tx:var(--text);   /* переобъявление обязательно: источник --text здесь другой */
  --card-shadow:0 1px 2px rgba(16,24,40,.10),0 2px 6px rgba(16,24,40,.07); --card-shadow-hover:0 6px 18px rgba(16,24,40,.16);
  --tint-blue:#eff4ff; --tint-green:#ecfdf3; --tint-red:#fef2f2; --tint-orange:#fff7ed;
  --green-soft:#16a34a18; --orange-soft:#ea580c18; --legend-bg:#ffffffe6;
  --pp-accent-bg:#2563eb12; --pp-accent-tx:#1d4ed8;
  --svc-bg:#fff7ed; --svc-bd:#fdba74; --svc-tx:#9a3412;
  --rev-bg:#fffbeb; --rev-bd:#fcd34d; --rev-tx:#92400e;
  --pp-hover:#0f172a08;
  --fault-plate:#fef2f2; --fault-line:#dc262633; --fault-fg:#dc2626;
  --pop-bg:#ffffff; --pop-bd:#7d8794; --pop-shadow:0 16px 40px -12px rgba(16,24,40,.22),0 2px 8px rgba(16,24,40,.08);
  --inp-bg:#ffffff; --inp-bd:#7d8794; --inp-focus:#005eb8; --inp-ring:#eff4ff;
  --st-head:#e3edff; --st-num-bg:#005eb8; --st-num-tx:#ffffff; --tag-own-tx:#005eb8;
  --obj-bd:#a8b2be; --obj-stripe:8px;
  --stripe-ok:var(--status-ok-tx); --stripe-fault:var(--status-fault-tx); --stripe-pending:var(--status-pending-tx);   /* ok потемнел: #16a34a давал 2.80:1 против фона страницы при пороге 3:1 для носителя смысла. Стало 4.27:1 · 5.02:1 на карточке. Тот же зелёный, что у текста .b-green в светлой. */
  --card-bd:#7d8794;
  --ctl-bd:#7d8794;
  --acc-rule:#7d8794;   /* 3.65:1 на белой карточке */
  --grp-head-bg:#eef2f7; --grp-head-tx:#334155;
  --pp-empty:#5b6672;
  --modal-bd:#5b6675; --modal-scrim:rgba(0,0,0,.6);
  --modal-shadow:0 20px 50px -12px rgba(16,24,40,.28),0 6px 18px rgba(16,24,40,.14);
}
/* .b-green и .b-orange перешли на --status-*-tx: в светлой теме он равен крепкой ступени,
   значения те же, переопределять нечего. .b-red — ИСКЛЮЧЕНИЕ и остаётся литералом:
   его плашка лежит на розовой подложке #dc262622, а не на белом, и токен #dc2626 даёт
   там 3.92:1 при пороге 4.5. #b91c1c = 5.25:1. Порог считается против того фона,
   на котором элемент лежит на самом деле. */
body.light .b-red{color:#b91c1c} body.light .b-grey{color:#5b6470}
body.light{
  /* ⚠️ D-169 (заход 77): .b-manual в светлой теме оставалась #a78bfa — светло-сиреневый
     на бледной заливке, около 2:1. Её просто забыли в прежнем перечне body.light .b-*,
     и заметить это можно было только сверив два списка классов. Теперь у неё тот же
     тёмный сиреневый, что у .b-plan: роли разные, значения совпали. */
  --badge-hoara-tx:#b45309; --badge-overdue-tx:#a16207;
  --badge-plan-tx:#6d28d9;  --badge-manual-tx:#6d28d9; --badge-blue-tx:#1d4ed8;
}
body.light{--fault-chip-tx:#b91c1c}   /* 5.91:1 на --fault-plate #fef2f2 */
body.light .leg-dot{border-color:#1f2933}
*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%}
body{font-family:'Assistant','Heebo',system-ui,sans-serif; background:var(--bg); color:var(--text); line-height:1.5; -webkit-font-smoothing:antialiased; overflow:hidden}

/* ACCESS */
#accessScreen{position:fixed; inset:0; z-index:5000; background:var(--bg); display:flex; flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-xl); text-align:center; padding:1.5rem}
#accessScreen h1{font-size:var(--fs-h2); font-weight:700}
#accessScreen .sub{color:var(--text-dim); margin-bottom:.5rem}
#accessInput{background:var(--surface2); border:2px solid var(--border); color:var(--text); border-radius:var(--r-ctl); padding:.85rem 1.1rem; font-size:var(--fs-lead); font-family:inherit; text-align:center; width:min(320px,90vw); outline:none}
#accessInput:focus{border-color:var(--blue)}
#opOverlay{position:fixed; inset:0; z-index:6000; background:var(--modal-scrim); display:none; align-items:center; justify-content:center; padding:1.2rem}
#opOverlay.show{display:flex}
#opOverlay .op-card{background:var(--surface); border:1px solid var(--modal-bd); border-radius:var(--r-card); padding:1.4rem 1.2rem; width:min(360px,92vw); text-align:center; box-shadow:var(--modal-shadow)}
#opOverlay h2{font-size:var(--fs-h4); font-weight:700; margin-bottom:.25rem}
#opOverlay .op-sub{color:var(--text-dim); margin-bottom:1rem; font-size:var(--fs-body)}
#opOverlay .op-btn{display:block; width:100%; background:var(--surface2); border:2px solid var(--border); color:var(--text); border-radius:var(--r-ctl); padding:1rem; font-size:var(--fs-lead); font-weight:700; font-family:inherit; cursor:pointer; margin-bottom:.6rem}
#opOverlay .op-btn:hover{border-color:var(--blue)}
#opOverlay .op-btn.cur{border-color:var(--sel-bd)}
#opOverlay .op-close{margin-top:.3rem; background:none; border:none; color:var(--text-dim); font-family:inherit; font-size:var(--fs-body); cursor:pointer}
#accessBtn{background:var(--blue); color:var(--action-primary-tx); border:none; border-radius:var(--r-ctl); padding:.8rem 2rem; font-size:var(--fs-lead); font-weight:700; cursor:pointer; font-family:inherit}

#mainApp{display:none; flex-direction:column; height:100vh; height:100dvh; overflow-x:hidden}
header{display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:var(--sp-lg); padding:.55rem 1rem; background:var(--surface); border-bottom:1px solid var(--border); position:relative; z-index:1200}
.brand{cursor:pointer; font-size:var(--fs-body); font-weight:700; display:flex; align-items:center; gap:var(--sp-md); cursor:pointer; white-space:nowrap}
.brand span{color:var(--blue)}
.live-dot{width:9px; height:9px; border-radius:var(--r-circle); background:var(--green); animation:pulse 2s infinite}
@keyframes pulse{0%{box-shadow:0 0 0 0 #16a34a99}70%{box-shadow:0 0 0 7px #16a34a00}100%{box-shadow:0 0 0 0 #16a34a00}}
#clock{text-align:center; line-height:1.15; flex:1}
.clock-time{font-size:var(--fs-display); font-weight:700; letter-spacing:.5px; font-variant-numeric:tabular-nums}
.clock-date{font-size:var(--fs-small); color:var(--text-dim)}
.header-right{display:flex; gap:var(--sp-sm); align-items:center}
.icon-btn{background:var(--surface); border:1px solid var(--ctl-bd); color:var(--text); border-radius:var(--r-ctl); padding:.45rem .65rem; font-size:var(--fs-body); cursor:pointer; font-family:inherit; min-height:40px; box-shadow:var(--card-shadow); transition:border-color .12s; display:inline-flex; align-items:center; gap:var(--sp-sm)}
.icon-btn:hover{border-color:var(--blue)}
#setBtn.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.tasks-btn{background:var(--blue); color:var(--action-primary-tx); border:none; position:relative}
/* D-47 · ярус B. Счётчик висел абсолютно с выносом -7px по обеим осям при
   зазоре .toolbar в 8px — то есть выходил наружу ровно на величину зазора и
   утыкался в соседа при переносе строки. Подбирать отступы бессмысленно: они
   разъедутся при первой правке раскладки. Вынос убран совсем — счётчик стоит
   в потоке кнопки, обрезаться нечему. Побочно он перестал зависеть от
   position:relative у родителя (был инлайном в разметке) и получил --r-pill
   вместо 50%: канон отдаёт 999px именно круглым счётчикам. */
.cnt{background:var(--status-warn); color:var(--action-primary-tx); font-size:var(--fs-micro); font-weight:700; border-radius:var(--r-pill); min-width:1.25rem; padding:.0625rem .375rem; line-height:1.25; display:inline-flex; align-items:center; justify-content:center; flex:none}
.op-chip{cursor:pointer}
.cache-tag{font-size:var(--fs-micro); color:var(--text-dim); align-self:center; display:none}
.cache-tag.show{display:inline}

/* PAGES */
.page{display:none; flex:1; min-height:0; flex-direction:column}
.page.active{display:flex}
/* D-44, переосмыслено. Пределы на страницах (1760 / 1400 / 1060) были ошибкой:
   канонные «не шире 1060px» — про длину читаемой СТРОКИ, а не про ширину экрана.
   Применённые к странице, они не убирали пустоту, а выносили её из карточки к
   краям монитора: узкая колонка посреди 1900px. Ширину использует содержание —
   карточки в сетке (см. .obj-list ниже), а не поля по бокам. */

/* KPI */
.kpi-bar{display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:var(--sp-lg); padding:14px 16px; flex-shrink:0}
/* Иконка — часть показателя, а не украшение дальнего угла: space-between
   разносил число и его иконку на ~370px внутри одной плитки.
   ⚠️ Заход 68. Разъезд убрали, а разнобой остался: иконка стояла ПОСЛЕ текста,
   и её горизонталь зависела от длины подписи — четыре иконки одного ряда вставали
   на четырёх разных вертикалях («1 מקלט · 0 חניונים» короче «103 מקלטים · 18 חניונים»
   на треть плитки). Иконка переставлена в начало строки и стала колонкой: линия
   сильнее пустоты, а пустота ушла в конец строки, где читается полем.
   Текст забирает остаток (flex:1) — иначе на его месте открывается вторая дыра. */
.kpi{min-width:0; background:var(--surface); border:1px solid var(--card-bd); border-radius:var(--r-ctl); padding:14px 15px; display:flex; align-items:center; justify-content:flex-start; gap:var(--sp-lg); cursor:pointer; box-shadow:var(--card-shadow); transition:transform .12s,box-shadow .12s; text-align:right}
/* Ширина плитки. У .kpi есть min-width:0, а у его ребёнка — нет, и по умолчанию
   flex-элемент НЕ сжимается уже своего содержимого (min-width:auto). Строка распирала
   плитку изнутри и выталкивала иконку .kmed (flex:none) за край. Дефект был до яруса A:
   подпись плитки 121 тоже длинная. Проявлялся между 761px и шириной, где строка ещё
   влезала, — половина монитора попадает ровно туда. */
.kpi-txt{min-width:0; flex:1}
.kpi:hover{transform:translateY(-2px); box-shadow:var(--card-shadow-hover)}
.kpi.active{box-shadow:0 0 0 2px var(--kpi-accent), var(--card-shadow-hover)}
/* ===== D-213 (заход 82): чип объёма поломок в панели фильтров =====
   Заливка крепким красным, текст белый: пара --status-fault / --action-primary-tx
   уже стоит в продукте (.seg button.on-red) и даёт 4.83:1 при пороге 4.5 — одно
   значение на обе темы, потому что крепкая ступень одна.
   ⚠️ Имя класса .kpi-alert, и первое имя было ОШИБКОЙ. Оно называлось .fault-chip,
   а этот класс ЗАНЯТ: им рисуются чипы неисправностей на карточке объекта и строки
   истории проверок (histRowHTML в монолите). Слепое переименование в style.css
   оставило разметку без правил, а чип забрал чужую одежду. Имя проверяется грепом
   ДО того, как выбрано, и считается ДО вставки своих строк, а не после.
   ⚠️ Прежний вариант — розовая полоса во всю ширину под рядом KPI — отменён
   владельцем на живом экране: он стоил лишней строки, а тревога всё равно
   попадалась глазу позже, чем фильтры. Высота теперь не тратится вовсе.
   ⚠️ Механизм показа и раскладка не спорят за display (правило D-117):
   у [hidden] собственное правило, иначе display:inline-flex перебил бы его молча. */
.kpi-alert{
  display:inline-flex; align-items:center; gap:var(--sp-md);
  min-height:40px; padding:.5rem .8rem;
  background:var(--status-fault); color:var(--action-primary-tx);
  border-radius:var(--r-ctl); box-shadow:var(--card-shadow);
  font-size:var(--fs-body); font-weight:700; white-space:nowrap;
  cursor:pointer; flex:0 0 auto;
}
.kpi-alert[hidden]{display:none}
.kpi-alert:hover{filter:brightness(1.08)}
.kpi-alert .fl-ic{width:19px; height:19px; flex:none}
.kpi-alert .fl-go{font-weight:700; opacity:.85}
@media(max-width:760px){
  /* Узкое окно: чип занимает свою строку целиком и стоит ПЕРЕД поиском
     (у .search-wrap order:-1). Перенос внутри чипа разрешён — обрезать
     число тревоги нельзя, лучше две строки. */
  .kpi-alert{flex:1 1 100%; order:-2; justify-content:center; white-space:normal}
}

/* ===== D-212 (заход 82): единица измерения названа у каждого числа ряда =====
   Слово `אתרים` стоит рядом с числом во всех четырёх плитках, поэтому ряд
   виден однородным ДО чтения подписей, а не после. Из ярлыка `סה״כ אתרים`
   слово при этом убрано: оно не продублировано, а переехало к числу.
   ⚠️ Слово ставит JS через cnt-подобное согласование, а не разметка: при единице
   иврит требует `אתר`, и статическое `אתרים` дало бы `1 אתרים` —
   ту самую ошибку, видимую только на единице, которую ярус A вычищал два захода.
   ⚠️ Обёртка .kpi-numline заведена ради раскладки и только ради неё: механизм
   и раскладка не спорят за свойства одного элемента (правило D-117). */
.kpi-numline{display:flex; align-items:center; gap:var(--sp-sm); min-width:0; flex-wrap:wrap; margin-top:2px}
.kpi-unit{font-size:var(--fs-small); font-weight:600; color:var(--text-faint); white-space:nowrap}
@media(max-width:430px){
  /* Телефон: единица остаётся. Прежняя редакция снимала её — слово `אובייקטים`
     в плитку ~90px не вставало. После смены термина на `אתרים` (пять букв)
     оно помещается, и ряд на телефоне впервые называет свою единицу вслух.
     ⚠️ Страховка: .kpi-numline переносит слово под число, а не выпихивает
     за край. Если перенос случится — плитка вырастет на строку, и это
     видно на снимке; тогда снимаем правило одной строкой. */
  .kpi-numline{justify-content:center}
  /* Слово стало коротким (אתרים вместо אובייקטים) — на телефоне оно помещается
     и потому больше не снимается. Плитка ~90px; при нехватке .kpi-numline
     переносит слово под число, а не выпихивает его за край. */
  .kpi-unit{font-size:var(--fs-micro)}
}
.kpi-num{font-size:var(--fs-h2); font-weight:700; line-height:1; color:var(--text); font-variant-numeric:tabular-nums}
/* D-214 (заход 82): порядок внутри плитки — состояние, потом число, потом разбор.
   Читается сверху вниз как фраза: «טרם נבדקו — 114 אתרים — 98 מקלטים · 16 חניונים».
   Прежний порядок (число сверху) заставлял искать, к чему это число относится. */
.kpi-label{font-size:var(--fs-label); color:var(--text-dim); margin-top:0; font-weight:600}
.kpi-sub{font-size:var(--fs-small); color:var(--text-faint); margin-top:4px; font-weight:600}
/* D-215 (заход 82): значок переехал в строку числа — он красит состояние и обязан
   стоять у числа, а не у противоположного края плитки. Три следствия сразу:
   плитка стала уже (вклад в D-207/D-209), значок выровнен по построению у всех
   четырёх плиток (прежде он центрировался по всему столбцу, а подпись-разбор
   бывает пустой — тогда он садился на другой высоте, родня D-132), и связанное
   стоит рядом. Размер 46 → 32; радиус держится пропорцией ~28% к стороне. */
.kmed{width:32px; height:32px; border-radius:9px; display:flex; align-items:center; justify-content:center; flex:none}
.kmed svg{width:17px; height:17px}
.kpi-total{--kpi-accent:var(--blue)} .kpi-total .kmed{background:var(--tint-blue); color:var(--blue)}
.kpi-ready{--kpi-accent:var(--green)} .kpi-ready .kmed{background:var(--tint-green); color:var(--green)}
.kpi-fault{--kpi-accent:var(--red)} .kpi-fault .kmed{background:var(--tint-red); color:var(--red)}
/* D-32 · Ярус A. Подпись этой плитки — не разбор числа над ней, а второй
   самостоятельный показатель. Отличается от трёх соседних ступенью шкалы, а не только цветом.
   Вес не трогаем: по канону подпись — 600, акцент даёт размер, а не жир.
   var(--fs-label) — первое живое обращение к шкале типографики в файле (см. D-02:
   токены объявлены в шапке и не используются ни разу). Значение .9375rem совпадает
   со шкалой канона до знака — проверено перед правкой. */
/* D-211 (заход 82): красная подпись снята. Она выделяла разбор по типам, пока он был
   единственным местом, где стояло число объектов. Теперь объекты стоят крупно в самой
   плитке, роль подписи совпала с тремя соседями — значит и одежда обязана совпасть
   (идентичный стиль только для идентичных ролей). Цвет тревоги ушёл в чип .fault-chip. */
.kpi-pending{--kpi-accent:var(--orange)} .kpi-pending .kmed{background:var(--tint-orange); color:var(--orange)}

.toolbar{display:flex; gap:var(--sp-md); padding:0 1rem .6rem; flex-wrap:wrap; align-items:center; flex-shrink:0}
.filter-sel,.search-box,.inp{background:var(--inp-bg); border:1px solid var(--inp-bd); color:var(--text); border-radius:var(--r-ctl); padding:.5rem .8rem; font-size:var(--fs-body); font-family:inherit; outline:none; min-height:40px; box-shadow:var(--card-shadow); transition:border-color .12s, box-shadow .12s}
.search-box{flex:1; min-width:140px}
.filter-sel:focus,.search-box:focus,.inp:focus{border-color:var(--inp-focus); box-shadow:0 0 0 3px var(--inp-ring)}
/* Placeholder не был задан вовсе — рисовал браузер (свой серый + своя прозрачность).
   На посветлевшей заливке он стал бы мутным. Явный цвет: 5.1:1 в тёмной теме,
   тише значения, но выше порога 4.5:1. opacity:1 гасит фаерфоксовскую по умолчанию. */
.filter-sel::placeholder,.search-box::placeholder,.inp::placeholder{color:var(--text-dim); opacity:1}
button.filter-sel{cursor:pointer; display:inline-flex; align-items:center; gap:var(--sp-md)}
button.filter-sel:hover{border-color:var(--blue); color:var(--blue)}
button.filter-sel:hover .ti-ic{color:var(--blue)}
.ti-ic{width:17px; height:17px; color:var(--text-faint); flex:none}
.search-wrap{position:relative; flex:0 1 340px; min-width:200px; display:flex}
.search-wrap .search-box{flex:1; padding-inline-start:2.3rem}
.search-wrap .ti-ic{position:absolute; inset-inline-start:.75rem; top:50%; transform:translateY(-50%); pointer-events:none}
.view-toggle{display:flex; background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); overflow:hidden; margin-inline-start:auto}
.vt-btn{background:transparent; border:none; color:var(--text-dim); padding:.5rem .9rem; font-size:var(--fs-body); font-weight:700; cursor:pointer; font-family:inherit}
.vt-btn.active{background:var(--sel-bg); color:var(--sel-tx)}

/* Ярус C, D-43: пропорция перевёрнута. Было minmax(340px,1fr) 1.2fr — карта
   забирала 55 % ширины, список 45 %. Канон: карта — контекст, не работа, и не
   бывает шире рабочей области. Стало 3fr/2fr = 60/40 в пользу списка.
   minmax(0,2fr) у карты вместо голого 1.2fr: у грид-элемента min-width по
   умолчанию auto, и широкое содержимое могло раздуть колонку сверх доли. */
#layout{flex:1; display:grid; grid-template-columns:minmax(340px,3fr) minmax(0,2fr); gap:var(--sp-lg); padding:0 1rem 1rem; min-height:0}
#listPane{overflow-y:auto; min-height:0; min-width:0}
#mapPane{position:relative; border-radius:var(--r-ctl); overflow:hidden; border:1px solid var(--ctl-bd); min-height:0}
#mapEl{position:absolute; inset:0}
body.view-map #listPane{display:none}
body.view-list #mapPane{display:none}

/* 121 объект в одну колонку на широком мониторе — расточительство: карточка
   несёт мало данных, и справа от неё оставалось полметра. Сетка сама решает,
   сколько колонок влезет: одна на телефоне, две в колонке списка главного
   экрана, три-четыре на полноэкранных фильтре и истории. */
/* ⚠️ Заход 68. align-items:start противоречил правилу, введённому заходом 66
   вместе с самой сеткой (D-119): «дыра МЕЖДУ карточками читается как ошибка,
   воздух ВНУТРИ — как поле», и выравнивание по верху названо там худшим из двух
   миров. Правило записали, к .obj-list/.type-grp не применили — карточки в ряду
   стояли лесенкой, и любая новая плашка эту лесенку углубляла.
   Stretch без второй половины бесполезен: карточка тянется, а её содержимое
   остаётся вверху. Отсюда .obj-card колонкой и строка действия, прижатая к низу —
   воздух собирается в одном месте, а низы карточек ряда встают в линию. */
.obj-list{display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,26rem),1fr)); gap:var(--sp-xl); align-items:stretch; min-width:0}
/* Группа раскладывает свои карточки той же сеткой, её заголовок занимает всю
   строку. Заодно .type-grp перестаёт быть классом без единого правила (D-29). */
.obj-list > .type-grp{grid-column:1/-1; display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,26rem),1fr)); gap:var(--sp-xl); align-items:stretch}
.type-grp > .grp-head{grid-column:1/-1}
.obj-card{display:flex; flex-direction:column; background:var(--surface); border:1px solid var(--obj-bd); border-radius:var(--r-ctl); padding:.9rem 1rem; cursor:pointer; transition:transform .12s,box-shadow .12s,border-color .15s; border-inline-start:var(--obj-stripe) solid var(--stripe-pending); box-shadow:var(--card-shadow)}
/* ⚠️ РЕШЕНИЕ ВЛАДЕЛЬЦА, ПРИНЯТОЕ ДВАЖДЫ — не «чинить» в третий раз.
   Наведение красит ВСЕ стороны, включая полосу статуса. Сохранять на hover цвет
   статуса пробовали дважды, и оба раза владелец вернул как было:
     1) первый заход — «статус виден на остальных 120 карточках, а наведение длится
        секунду и отвечает на другой вопрос: где курсор»;
     2) заход 76 — правка внесена мной по формальному доводу «взаимодействие
        затирает информацию» и отменена владельцем ДО заливки: «так видно, что ты
        именно на этой карточке, а два цвета на одной рамке некрасивы».
   Довод владельца сильнее закона 2 здесь потому, что состояние на этой карточке
   продублировано плашкой и счётчиком тексту — рамка не единственный его носитель,
   а вот «где курсор» не говорит больше ничто. Запись реестра D-161 СНЯТА. */
.obj-card:hover{border-color:var(--blue); transform:translateY(-1px); box-shadow:var(--card-shadow-hover)}
/* Заход 68, просьба владельца «сделать заметнее». Усиливаем ИСКЛЮЧЕНИЕ, а не
   правило: תקין — 1 карточка из 121, תקלות — 9. Подсвечивать טרם נבדק было бы
   подсветкой всего экрана, и сигналом стало бы отсутствие цвета.
   Определённое состояние обводит карточку целиком (1px, цвет состояния),
   отсутствие проверки оставляет карточку нейтральной — только полоса.
   Контраст против фона страницы: зелёный 4.27:1 светлая / 8.31:1 тёмная,
   красный 4.11:1 / 5.03:1. Порог носителя смысла 3:1.
   Наведение по-прежнему перекрывает всё синим: .obj-card:hover весит (0,2,0)
   против (0,1,0) у этих правил — проверено по специфичности, не по памяти. */
.oc-ready{border-color:var(--stripe-ok)} .oc-fault{border-color:var(--stripe-fault)} .oc-pending{border-inline-start-color:var(--stripe-pending)}
/* Ярус C, sweep разъезда. Было display:flex + justify-content:space-between:
   название уходило к правому краю, чипы — к левому, между ними до 900px пустоты.
   «Колонка чипов у края помогает сканировать» — довод не подтверждался экраном:
   чипы разной длины, ровной колонки не образуют. Стало: блок, чипы в ряд под
   названием. Карточка ниже на 75–110px — на экран влезает вдвое больше объектов,
   а это главное, ради чего дашборд заменяет эксель. */
.oc-top{min-width:0}
.oc-top>*:not(.oc-badges){min-width:0}
/* Заход 68. Шапка карточки: название и учётные счётчики. Счётчики стоят у конца
   строки (в RTL — левый верхний угол) и не сжимаются: их место постоянно на всех
   карточках, поэтому по столбцу они выстраиваются в линию, а не пляшут вслед за
   длиной ряда состояний. Название забирает остаток и переносится само. */
.oc-head{display:flex; align-items:flex-start; gap:var(--sp-md); min-width:0}
.oc-head .oc-name{flex:1; min-width:0}
.oc-counts{flex:none; display:flex; align-items:center; gap:var(--sp-xs)}
.oc-name,.oc-meta{overflow-wrap:anywhere}
.oc-name{font-size:var(--fs-h4); font-weight:700; line-height:1.25}
.oc-meta{font-size:var(--fs-label); color:var(--text-dim); margin-top:.15rem; line-height:1.4}
.oc-badges{display:flex; flex-wrap:wrap; gap:var(--sp-xs); align-items:center; margin-top:.5rem}
.badge{font-size:var(--fs-small); font-weight:600; padding:.28rem .65rem; border-radius:var(--r-pill); white-space:nowrap; display:inline-flex; align-items:center; gap:var(--sp-xs)}
.badge.lg{font-size:var(--fs-body); padding:.4rem .8rem; border-radius:var(--r-pill)}
.brand-group{display:flex; align-items:center; gap:var(--sp-md); justify-self:start}
.hdr-sep{width:1px; height:24px; background:var(--border); margin-inline:.3rem; flex:none}
.header-right{justify-self:end}
/* הגדרות — центральное окно (заход 67). Панель была единственным местом продукта,
   живущим выпадашкой в углу: на узкой ширине название переносилось в три строки,
   а группы не помещались и потребовали складной секции. Механизм показа не тронут —
   класс .show на #setPop, как было; поменялась только раскладка. */
.set-pop{display:none; position:fixed; inset:0; z-index:2000; background:var(--modal-scrim);
  align-items:center; justify-content:center; padding:1rem}
.set-pop.show{display:flex; animation:setPopIn .15s cubic-bezier(.2,.8,.3,1)}
.set-card{background:var(--pop-bg); border:1px solid var(--modal-bd); border-radius:var(--r-card);
  box-shadow:var(--modal-shadow); width:min(56rem,100%); max-height:100%;
  display:flex; flex-direction:column; overflow:hidden}
.set-body{overflow:auto; min-height:0; padding:1rem}
/* Окно инструмента открывается ПОВЕРХ панели (z-index 3200 против 2000) — это и есть
   «назад»: закрыл инструмент, панель на месте. Но два затемнения подряд дают почти
   чёрный экран, поэтому на время открытого инструмента подложка панели снимается. */
body:has(.ziud-mov.show) .set-pop,
body:has(#ppio-overlay.show) .set-pop,
body:has(#modalOverlay.show) .set-pop,
body:has(#confirmOverlay.show) .set-pop,
body:has(#resetOverlay.show) .set-pop{background:transparent}
/* Колонки живут ВНУТРИ прокручиваемого контейнера, а не являются им (D-118).
   stretch, а не start: дыра между карточками читается как ошибка (D-119). */
.set-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,22rem),1fr));
  gap:var(--sp-xl); align-items:stretch}
.set-grp{background:var(--surface); border:1px solid var(--card-bd); border-radius:var(--r-ctl);
  padding:0 .9rem .7rem; display:flex; flex-direction:column; overflow:hidden}
.sr-txt{display:flex; flex-direction:column; gap:var(--sp-2xs); min-width:0; flex:1}
.sr-name{font-weight:600; display:flex; align-items:center; gap:var(--sp-sm)}
.sr-hint{font-size:var(--fs-small); font-weight:400; color:var(--text-dim); line-height:var(--lh-body)}
.sr-lock{width:.85rem; height:.85rem; color:var(--text-dim); flex:none}
@keyframes setPopIn{from{opacity:0; transform:translateY(-7px) scale(.97)} to{opacity:1; transform:none}}
.set-head{display:flex; align-items:center; gap:var(--sp-md); padding:.85rem 1rem; border-bottom:1px solid var(--border);
  color:var(--text); font-size:var(--fs-h3); font-weight:700; flex:none}
.set-head .modal-close{margin-inline-start:auto}
.set-head > svg{width:1.15rem; height:1.15rem; flex:none; color:var(--text-dim)}
.set-row{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-lg); padding:.45rem 0; font-size:var(--fs-label)}
.set-row+.set-row{border-top:1px solid var(--border)}
/* Строка настроек с двумя равноправными действиями (שמות שדות: מקלטים / חניונים).
   Без обёртки space-between развёл бы их по разным краям строки. */
.set-row-btns{display:flex; align-items:center; gap:var(--sp-md)}
.b-green{background:var(--green-soft); color:var(--status-ok-tx)} .b-orange{background:var(--orange-soft); color:var(--status-warn-tx)} .b-red{background:var(--badge-red-bg); color:var(--status-fault-tx)}
.b-grey{background:var(--badge-grey-bg); color:var(--text-dim)} .b-overdue{background:var(--badge-overdue-bg); color:var(--badge-overdue-tx)}
/* D-138 (заход 69). .b-media жила инлайном в index.html со СВОЕЙ палитрой из трёх
   литералов — и одним правилом на обе темы. Заливка #e6f7f4 давала 15.63:1 против
   тёмной карточки (единственное светлое пятно среди плашек) и 1.11:1 против белой
   в светлой теме: смысл был перевёрнут между темами. Медиа — учётный счётчик, а не
   состояние, поэтому нейтраль соседа .b-grey: 6.04:1 в тёмной, 5.30:1 в светлой. */
.b-media{background:var(--badge-grey-bg); color:var(--text-dim)}
/* Режим доступа חניון (פתוח/סגור). Своя роль: не готовность и не счётчик.
   Вид нейтральный, различают замок и слово — Закон 2 (заход 69). */
.b-access{background:var(--badge-grey-bg); color:var(--text-dim)}
.b-review{background:var(--rev-bg); color:var(--rev-tx); border:1px solid var(--rev-bd)}
.b-svc{background:var(--svc-bg); color:var(--svc-tx); border:1px solid var(--svc-bd)}
.b-blue{background:var(--badge-blue-bg); color:var(--badge-blue-tx)} .b-manual{background:var(--badge-manual-bg); color:var(--badge-manual-tx)} .b-hoara{background:var(--badge-hoara-bg); color:var(--badge-hoara-tx)}
.oc-faults{margin:.5rem 0 .55rem; display:flex; flex-wrap:wrap; gap:var(--sp-xs)}
/* Заход 68. Чип неисправности приведён к шкале (.5rem радиус, .25rem/.5rem отступы,
   вес 600 — было .18rem/.4rem, мимо шкалы) и получил свой токен текста.
   ⚠️ Он живёт не только у фолбэка на карточке: histRowHTML в монолите рисует им
   строки проверок в היסטוריה, красным и синим. Правка гоняется по обоим.
   .fault-ic — крупная плитка систем на карточке объекта. Оставлена как была:
   решение владельца (заход 68) — опознание одним взглядом, без чтения слова. */
.fault-chip{display:inline-flex; align-items:center; gap:var(--sp-xs); font-size:var(--fs-small); font-weight:600;
  background:var(--fault-plate); color:var(--fault-chip-tx); padding:.25rem .5rem;
  border-radius:var(--r-chip); border:1px solid var(--fault-line)}
.fault-chip .sdot,.fault-chip .eic{margin-inline-end:0}
.fault-ic{display:inline-flex; align-items:center; justify-content:center; width:58px; height:58px; border-radius:var(--r-ctl); background:var(--fault-plate); border:1px solid var(--fault-line)}
.fic{width:40px; height:40px; color:var(--fault-fg)}
.tri-warn{width:1.05em; height:1.05em; color:var(--fault-fg); vertical-align:-.16em; flex:none}
.badge .tri-warn{color:currentColor}
.mi{width:15px; height:15px; color:#94a3b8; vertical-align:-2px; margin-inline-end:.4rem; flex:none}
.bi{width:1em; height:1em; flex:none}
.mrow{display:flex; align-items:center; line-height:1.55}
/* Стрелка относится к заголовку группы, а не к дальнему краю строки:
   при 1030px между ними был метр пустоты. */
.grp-head{display:flex; justify-content:flex-start; gap:var(--sp-md); align-items:center; cursor:pointer; padding:.65rem .95rem; margin:.6rem 0; background:var(--surface); border:1px solid var(--card-bd); border-radius:var(--r-ctl); box-shadow:var(--card-shadow); user-select:none}
.grp-head:hover{border-color:var(--blue)}
/* Ярус C, добор: верхний край списка обязан совпадать с верхним краем карты.
   .grp-head несёт margin:.6rem 0, и первая группа начиналась на 9.6px ниже
   соседней колонки — глаз читает две колонки как съехавшие. Снимаем отступ
   ТОЛЬКО у первой группы: ритм между группами и внутри них не трогаем. */
.obj-list > .type-grp:first-child .grp-head{margin-top:0}
.grp-title{font-weight:700; font-size:var(--fs-body); display:inline-flex; align-items:center; gap:var(--sp-md)}
.grp-cnt{background:var(--tint-blue); color:var(--blue); font-size:var(--fs-label); font-weight:700; border-radius:var(--r-pill); padding:.1rem .6rem}
.grp-arr{opacity:.55; display:inline-flex; align-items:center}
.grp-arr svg{width:17px; height:17px; transition:transform .2s}
.grp-arr.coll svg{transform:rotate(-90deg)}
.empty{text-align:center; color:var(--text-dim); padding:2.5rem 1rem}
.empty .emo{margin-bottom:.5rem; color:var(--text-faint)}
.empty .emo svg{width:44px; height:44px}

/* ===== סינון (фильтр/сводка по паспорту) ===== */
.sn-filters{display:flex; gap:var(--sp-md); padding:.2rem 1.1rem .6rem; flex-wrap:wrap; align-items:center; flex-shrink:0}
.sn-chip{background:var(--surface2); border:1px solid var(--ctl-bd); color:var(--text-dim); border-radius:var(--r-chip); padding:.5rem .8rem; font-size:var(--fs-body); font-weight:600; cursor:pointer; font-family:inherit; white-space:nowrap}
.sn-chip.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.sn-chip.on-rev{background:var(--rev-bg); border-color:var(--rev-bd); color:var(--rev-tx)}
.sn-chip.on-svc{background:var(--svc-bg); border-color:var(--svc-bd); color:var(--svc-tx)}
/* D-60 · ярус B. Две зоны ряда סינון: фильтры у одного края, действия у другого.
   Авто-отступ переехал сюда с .sn-export — раньше он отбрасывал одну кнопку,
   теперь всю группу действий целиком. */
.sn-zone{display:flex; flex-wrap:wrap; gap:var(--sp-md); align-items:center; min-width:0}
/* Авто-отступ отбрасывал действия к дальнему краю. Пока фильтров мало, они
   помещались в ту же строку; как только строка заполнялась (или окно сужалось),
   группа уезжала на свою строку и прижималась к ЛЕВОМУ краю — против направления
   чтения, одинокий кластер в пустоте. Теперь действия всегда своя строка и всегда
   от начала строки: одно место при любой ширине вместо «иногда там, иногда тут». */
.sn-acts{width:100%; margin-inline-start:0; padding-top:.15rem; justify-content:space-between}
.sn-grp{display:flex; flex-wrap:wrap; gap:var(--sp-md); align-items:center; min-width:0}

/* ── Выпадающий список · D-57, ярус B ──────────────────────────────────────
   Кнопка носит и .filter-sel (вид поля — общий с остальными контролами),
   и .dd-btn (поведение). Меню — в <body>, position:fixed, координаты считает
   dropdown.js: панель фильтров переносится внутри прокручиваемого экрана,
   и absolute-меню обрезал бы первый же родитель с overflow.
   z-index ниже modalOverlay(3000) намеренно: список открывается только из ряда
   фильтров, и модальное окно обязано его перекрывать, а не наоборот. */
.dd-btn{display:inline-flex; align-items:center; gap:var(--sp-md); cursor:pointer;
  justify-content:space-between; min-width:8rem}
/* Выбранное значение видно на закрытой кнопке. Пара --sel-bg/--sel-tx/--sel-bd —
   та же, что у .sn-chip.on, .sn-pv.on и #setBtn.on: одна роль «здесь сделан выбор» —
   один вид, новых токенов и новых пар контраста не заводится. */
.dd-btn.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.dd-btn.on .dd-caret{color:var(--sel-tx)}
/* Оболочка ячейки в верхней панели. display:contents — чтобы флекс-элементом
   .toolbar осталась сама кнопка, как раньше был <select>. Соседи по ряду не сдвигаются. */
.dd-cell{display:contents}
.dd-lbl{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.dd-caret{width:1rem; height:1rem; color:var(--text-faint); flex:none}
.dd-menu{position:fixed; z-index:2900; background:var(--surface); border:1px solid var(--modal-bd);
  border-radius:var(--r-ctl); box-shadow:var(--card-shadow-hover); padding:.25rem; min-width:9rem;
  max-height:60vh; overflow-y:auto; display:flex; flex-direction:column; gap:var(--sp-2xs)}
/* ── בדיקת צירים · отчёт проверки осей (заход 60) ─────────────────────────
   Тревожный цвет — только у настоящей находки. «Нет данных» и «все в одной корзине»
   это состояние данных, а не поломка кода, и красить их оранжевым значит врать
   громче, чем дефект, который отчёт ищет. */
.ax-ov{position:fixed; inset:0; z-index:3600; background:rgba(0,0,0,.45);
  display:flex; align-items:flex-start; justify-content:center; padding:2rem 1rem; overflow-y:auto}
.ax-card{background:var(--surface); border:1px solid var(--modal-bd); border-radius:var(--r-card);
  box-shadow:var(--card-shadow-hover); padding:1rem; width:min(60rem,100%); max-width:100%}
.ax-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-md); margin-bottom:.75rem}
.ax-title{font-size:var(--fs-h3); font-weight:700}
.ax-sum{font-size:var(--fs-lead); font-weight:700; padding:.75rem 1rem; border-radius:var(--r-ctl)}
.ax-ok-bg{background:var(--tint-green); color:var(--status-ok-tx)}
.ax-bad-bg{background:var(--tint-red); color:var(--action-danger-tx)}
.ax-legend{font-size:var(--fs-small); color:var(--text-dim); line-height:var(--lh-body); margin:.6rem 0 .25rem}
.ax-sub{font-size:var(--fs-label); font-weight:700; margin:1.25rem 0 .4rem}
.ax-det{margin-top:1.25rem}
.ax-det>summary{font-size:var(--fs-label); font-weight:600; color:var(--text-dim); cursor:pointer; padding:.35rem 0}
.ax-tbl{width:100%; border-collapse:collapse; font-size:var(--fs-small)}
.ax-tbl th{font-size:var(--fs-micro); font-weight:600; color:var(--text-faint); text-align:start;
  padding:.25rem .5rem; border-bottom:1px solid var(--ctl-bd)}
.ax-tbl td{padding:.4rem .5rem; border-bottom:1px solid var(--border); text-align:start; vertical-align:top}
.ax-v{font-weight:600; white-space:nowrap}
.ax-dim{color:var(--text-dim)}
.ax-bad .ax-v{color:var(--action-danger-tx); font-weight:700}
.ax-ok .ax-v{color:var(--status-ok-tx)}
.ax-empty .ax-v, .ax-flat .ax-v{color:var(--text-dim)}
.dd-head{padding:.35rem .75rem .3rem; font-size:var(--fs-micro); font-weight:600;
  color:var(--text-faint); cursor:default; border-bottom:1px solid var(--border); margin-bottom:.125rem}
.dd-item{display:block; width:100%; text-align:start; background:none; border:none; color:var(--text);
  font-family:inherit; font-size:var(--fs-body); font-weight:600; padding:.5rem .75rem;
  border-radius:var(--r-chip); cursor:pointer; white-space:nowrap}
.dd-item:hover, .dd-item:focus-visible{background:var(--surface2); outline:none}
/* Выбранное — не действие: своя пара токенов, не цвет главного действия (Закон 3). */
.dd-item.on{background:var(--sel-bg); color:var(--sel-tx)}
/* Вес 700 одевал третий ярус как первый: после D-68 третий ярус носит 600. */
.sn-reset{background:transparent; border:none; color:var(--text-dim); border-radius:var(--r-chip); padding:.5rem .8rem; font-size:var(--fs-body); font-weight:600; cursor:pointer; font-family:inherit}
/* Нечего снимать — кнопка молчит. Гасим цветом, а не opacity: заблокированное
   состояние обязано читаться (4-й вопрос приёмки). --text-faint даёт 4.12:1
   в тёмной и 4.62:1 в светлой против фона страницы при пороге 3:1 для значимого
   элемента; opacity у соседней .sn-ord даёт .28 и не читается — приём не копируем. */
.sn-reset:disabled{color:var(--text-faint); cursor:default}
.sn-reset b{font-weight:700}
.sn-export{background:var(--action-primary); border:none; color:var(--action-primary-tx); border-radius:var(--r-chip); padding:.5rem .9rem; font-size:var(--fs-body); font-weight:700; cursor:pointer; font-family:inherit}
.sn-summary{padding:0 1.1rem .55rem; font-size:var(--fs-body); font-weight:600; color:var(--text); flex-shrink:0}
.sn-summary .muted{font-weight:400; color:var(--text-dim)}
.sn-pivot{padding:0 1.1rem; flex-shrink:0; display:flex; flex-direction:column; gap:var(--sp-sm)}
.sn-pivot:not(:empty){padding-bottom:.55rem}
.pv-row{display:flex; flex-wrap:wrap; gap:var(--sp-sm); align-items:center}
.sn-pivot .pv-title{font-size:var(--fs-label); font-weight:700; color:var(--text-dim); margin-inline-end:.2rem}
.sn-pv{background:var(--surface2); border:1px solid var(--ctl-bd); color:var(--text); border-radius:var(--r-card); padding:.28rem .35rem .28rem .75rem; font-size:var(--fs-label); font-weight:400; cursor:pointer; font-family:inherit; white-space:nowrap; display:inline-flex; align-items:center; gap:var(--sp-md)}
.sn-pv:hover{border-color:var(--blue)}
.sn-pv.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.sn-pv .pv-n{background:var(--bg); color:var(--text-dim); border-radius:var(--r-card); min-width:1.5rem; text-align:center; padding:.08rem .45rem; font-size:var(--fs-label); font-weight:700}
.sn-pv.on .pv-n{background:rgba(255,255,255,.28); color:var(--action-primary-tx)}
.sn-pv.empty-val{color:var(--text-dim); font-style:italic}
.sn-pv.empty-val .pv-n{font-style:normal}
.pv-hint{font-size:var(--fs-small); color:var(--text-dim); font-style:italic; align-self:center}
.sn-fields{margin-top:.5rem; display:flex; flex-wrap:wrap; gap:var(--sp-sm)}
.sn-f-bad{color:var(--red)}
.sn-f-bad b{font-weight:700}
.sn-f{font-size:var(--fs-small); background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.18rem .5rem; color:var(--text-dim)}
.sn-f b{color:var(--text); font-weight:600}
#pageSinun .fs-scroll{padding-top:.2rem}
/* Панель фильтров разрастается до восьми рядов и при своей flex-shrink:0
   съедала весь экран: список объектов уходил ниже сгиба, и объектов было
   не видно вовсе. Прокручивается вся страница целиком, список — вместе с ней;
   наверху липнет только строка заголовка с кнопкой возврата. */
#pageSinun{overflow-y:auto}
#pageSinun>.fs-head{position:sticky; top:0; z-index:5}
#pageSinun>.fs-scroll{overflow:visible; flex:none}
.sn-seg{display:inline-flex; border:1px solid var(--ctl-bd); border-radius:var(--r-chip); overflow:hidden}
.sn-seg button{background:var(--surface2); border:none; border-inline-start:1px solid var(--border); color:var(--text-dim); padding:.5rem .8rem; font-size:var(--fs-label); font-weight:700; cursor:pointer; font-family:inherit; white-space:nowrap}
.sn-seg button:first-child{border-inline-start:none}
.sn-seg button.on{background:var(--sel-bg); color:var(--sel-tx)}
.sn-seg button.on-red{background:var(--status-fault); color:var(--action-primary-tx)}
.sn-seg button.on-green{background:var(--status-ok); color:var(--action-primary-tx)}
.sn-seg button.on-grey{background:var(--status-pending); color:var(--action-primary-tx)}
.sn-bar{display:flex; gap:var(--sp-md); padding:.2rem 1.1rem .4rem; flex-wrap:wrap; align-items:center; flex-shrink:0}
.sn-search-res{display:none; margin:.1rem 1.1rem .35rem; flex-shrink:0; background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); overflow:hidden; overflow-y:auto; max-height:min(46vh,320px)}
.sn-sr-item{display:flex; justify-content:space-between; align-items:center; gap:var(--sp-md); width:100%; text-align:start; background:transparent; border:none; border-bottom:1px solid var(--border); color:var(--text); padding:.55rem .8rem; font-family:inherit; font-size:var(--fs-body); cursor:pointer}
.sn-sr-item:last-child{border-bottom:none}
.sn-sr-item:hover{background:var(--action-primary); color:var(--action-primary-tx)}
.sn-sr-item.on{background:var(--sel-bg); color:var(--sel-tx)}
.sn-sr-lbl{font-weight:600}
.sn-sr-grp{color:var(--text-dim); font-size:var(--fs-label); white-space:nowrap}
.sn-sr-item.on .sn-sr-grp,.sn-sr-item:hover .sn-sr-grp{color:rgba(255,255,255,.85)}
.sn-sr-empty{padding:.55rem .8rem; color:var(--text-dim); font-size:var(--fs-body)}
.sn-lbl{font-size:var(--fs-label); font-weight:600; color:var(--text-dim); margin-inline-start:.25rem}
.sn-chip.on-red{background:var(--status-fault); border-color:var(--status-fault); color:var(--action-primary-tx)}
.sn-chip.on-green{background:var(--status-ok); border-color:var(--status-ok); color:var(--action-primary-tx)}
.sn-chip.on-grey{background:var(--status-pending); border-color:var(--status-pending); color:var(--action-primary-tx)}
.sn-gear{background:transparent; border:1px solid var(--ctl-bd); color:var(--text-dim); border-radius:var(--r-chip); padding:.5rem .8rem; font-size:var(--fs-body); font-weight:700; cursor:pointer; font-family:inherit}
.sn-gear.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
/* ⚠️ flex-shrink:0 — не косметика. #pageSinun прокручивается целиком (заход 66),
   значит его дети — гибкие элементы колонки с заданной высотой и по умолчанию
   СЖИМАЮТСЯ прежде, чем страница переполнится. У панели overflow-y:auto, поэтому
   её минимальная высота не защищает: она схлопывалась в полоску со своей
   прокруткой. Все соседи по экрану (.sn-filters, .sn-summary, .sn-pivot, .sn-bar,
   .sn-search-res) несут flex-shrink:0 — панель תצוגה была единственной без него. */
/* Сетка, а не flex-wrap: колонки разной ширины давали рваный край и вид набора
   флажков вместо панели. Сетка ставится на сам .sn-settings — обёртки внутри
   нет, разметку рисует sinun.js. Высота в ряду равная (D-119). */
.sn-settings{margin:0 1.1rem .6rem; padding:.9rem; background:var(--surface); border:1px solid var(--card-bd);
  border-radius:var(--r-ctl); flex-shrink:0; max-height:55vh; overflow-y:auto;
  display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,13rem),1fr));
  gap:var(--sp-lg); align-items:stretch}
.sn-set-grp{display:flex; flex-direction:column; gap:var(--sp-2xs); min-width:0;
  background:var(--surface2); border:1px solid var(--border); border-radius:var(--r-chip);
  padding:0 .55rem .45rem; overflow:hidden}
.sn-set-title{font-size:var(--fs-micro); font-weight:700; color:var(--grp-head-tx);
  background:var(--grp-head-bg); border-bottom:1px solid var(--border);
  margin:0 -.55rem .3rem; padding:.4rem .55rem}
.sn-set-item{display:flex; align-items:center; gap:var(--sp-md); font-size:var(--fs-label); color:var(--text);
  cursor:pointer; padding:.22rem .3rem; border-radius:var(--r-chip); min-width:0}
.sn-set-item:hover{background:var(--surface)}
.sn-set-item span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.sn-set-item input{width:1rem; height:1rem; cursor:pointer; flex:none; accent-color:var(--action-primary)}
.sn-set-all{grid-column:1/-1; justify-self:start; background:transparent; border:1px solid var(--ctl-bd); color:var(--text-dim); border-radius:var(--r-chip); padding:.4rem .8rem; font-size:var(--fs-label); font-weight:600; cursor:pointer; font-family:inherit}
.sn-ord-wrap{display:inline-flex; gap:var(--sp-2xs); margin-inline-end:.3rem; vertical-align:middle}
.sn-ord{background:transparent; border:1px solid var(--ctl-bd); color:var(--text-dim); border-radius:var(--r-xs); width:20px; height:17px; font-size:var(--fs-micro); line-height:1; cursor:pointer; padding:0; font-family:inherit}
.sn-ord:hover:not(:disabled){border-color:var(--blue); color:var(--blue)}
.sn-ord:disabled{opacity:.28; cursor:default}
.sn-ord svg{width:12px; height:12px; display:block; margin:0 auto}
.sn-ord.up svg{transform:rotate(180deg)}
.sn-pill{font-size:var(--fs-small); font-weight:600; border-radius:var(--r-chip); padding:.18rem .5rem; white-space:nowrap}
.sn-pill.p-red{background:var(--status-fault); color:var(--action-primary-tx)}
.sn-pill.p-green{background:var(--status-ok); color:var(--action-primary-tx)}
.sn-pill.p-grey{background:var(--status-pending); color:var(--action-primary-tx)}

.leaflet-top,.leaflet-bottom{z-index:900}
.map-legend{position:absolute; bottom:10px; inset-inline-start:10px; z-index:500; background:var(--legend-bg); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.5rem .65rem; font-size:var(--fs-small); display:flex; flex-direction:column; gap:var(--sp-xs)}
.leg-row{display:flex; align-items:center; gap:var(--sp-sm)}
.leg-dot{width:11px; height:11px; border-radius:var(--r-circle); border:1.5px solid #fff}
/* Маркеры карты. D-141: раньше цвет приходил инлайном из markerColor() в map.js —
   три hex-литерала в скрипте, которых не видел ни один греп по токенам. Теперь JS
   выдаёт только КЛАСС СОСТОЯНИЯ, а цвет живёт здесь, рядом с легендой и полосами. */
.mk-pin{width:18px; height:18px; border-radius:var(--r-circle); background:var(--marker-pending);
  border:2.5px solid #fff; box-shadow:0 1px 5px rgba(0,0,0,.6)}
.mk-pin-p{width:21px; height:21px; border-radius:var(--r-xs); display:flex; align-items:center;
  justify-content:center; font:800 14px/1 system-ui,Arial; color:var(--action-primary-tx)}
.mk-ok{background:var(--marker-ok)} .mk-fault{background:var(--marker-fault)} .mk-pending{background:var(--marker-pending)}
/* Точка легенды = тот же токен, что маркер. Считано против фона легенды
   (--legend-bg): тёмная 3.77 · 3.92 · 3.91 · светлая 5.02 · 4.83 · 4.83 при пороге 3:1. */
.leg-ok{background:var(--marker-ok)} .leg-fault{background:var(--marker-fault)} .leg-pending{background:var(--marker-pending)}
#mapError{display:none; position:absolute; inset:0; z-index:600; background:var(--surface2); flex-direction:column; align-items:center; justify-content:center; gap:var(--sp-lg); text-align:center; padding:1rem}
#mapError button{background:var(--surface); border:2px solid var(--border); color:var(--text); border-radius:var(--r-chip); padding:.5rem 1.2rem; font-weight:700; cursor:pointer; font-family:inherit}
.leaflet-popup-content{font-family:'Heebo',sans-serif; direction:rtl; text-align:right}
/* Попап Leaflet белый в ОБЕИХ темах (переопределения .leaflet-popup-content-wrapper
   в проекте нет) — поэтому пары внутри него считаются против #fff, а не против --surface. */
.pop-card{min-width:11.5rem}
.pop-addr{color:#5b6470}   /* было #777 = 4.48:1 при пороге 4.5:1 для текста. Стало 6.00:1 */
.pop-open{margin-top:.4rem}
.pop-nav{display:flex; gap:var(--sp-sm); margin-top:.5rem}
/* Закон 3 канона: два соседних действия — два яруса, а не два цвета.
   ⚠️ Закон 2: у Waze стоял #16a34a — ЦВЕТ СОСТОЯНИЯ (=--status-ok) на ДЕЙСТВИИ,
   и белый текст на нём давал 3.30:1 при пороге 4.5:1. Первый ярус — Maps (заливка,
   белый на --action-primary = 5.17:1 в тёмной теме и выше в светлой), второй —
   Waze контуром того же цвета (текст 5.17:1, рамка 5.17:1). */
.pop-nav a{flex:1; text-align:center; text-decoration:none; background:var(--action-primary); color:var(--action-primary-tx); border-radius:var(--r-chip); padding:.35rem; font-size:var(--fs-label); font-weight:700; border:1px solid var(--action-primary)}
.pop-nav a.waze{background:transparent; color:var(--action-primary)}

/* ── FULL-SCREEN PAGES (miklat / tasks) ── */
.fs-scroll{flex:1; overflow-y:auto; padding:1rem; min-height:0}
.fs-head{display:flex; align-items:center; gap:var(--sp-lg); padding:.7rem 1rem; background:var(--surface); border-bottom:1px solid var(--border); flex-shrink:0}
.back-btn{background:var(--surface2); border:1px solid var(--ctl-bd); color:var(--text); border-radius:var(--r-chip); padding:.5rem .8rem; font-weight:600; cursor:pointer; font-family:inherit}
.fs-title{font-size:var(--fs-h4); font-weight:700}
.fs-sub{font-size:var(--fs-label); color:var(--text-dim)}
.sect{background:var(--surface); border:1px solid var(--card-bd); border-radius:var(--r-card); padding:1rem 1.1rem; margin-bottom:.9rem; max-width:780px}
.sect h3{font-size:var(--fs-body); font-weight:700; margin-bottom:.7rem; display:flex; align-items:center; gap:var(--sp-sm)}
.kv{display:grid; grid-template-columns:135px 1fr; gap:var(--sp-lg); padding:.45rem 0; border-bottom:1px solid var(--border); font-size:var(--fs-body); align-items:baseline}
.kv .k{color:var(--text-dim)}
.kv span:last-child{text-align:right; word-break:break-word}
.kv:last-child{border-bottom:none}
/* ── תעודת זהות (v160): сетка карточек вместо текстовых колонок ──
   Каждая тема — отдельная карточка: поверхность + рамка + скругление,
   шапка во всю ширину с акцентной планкой. Grid → верхние края выровнены,
   длинная группа не рвётся между колонками, узкий экран сваливается в одну колонку. */
/* Блоки паспорта разной высоты, и ровных линий при плотной укладке не бывает в
   принципе: группа из пяти полей длиннее группы из четырёх, всё ниже съезжает.
   Выбор из двух: колонки (плотно, но линии рвутся лесенкой) или сетка с равной
   высотой (линии ровные, внутри коротких групп воздух). Взято второе: у групп
   есть рамка, и она превращает пустоту в ПОЛЕ карточки, тогда как дыра МЕЖДУ
   карточками читается как ошибка. Линия для глаза сильнее пустоты.
   ⚠️ Ключ — stretch, а не start: при start получалось худшее из двух миров —
   и лесенка, и дыры между блоками (так было до захода 66). */
.pp-cols{--pp-pad:.85rem; display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,24rem),1fr)); gap:var(--sp-xl); align-items:stretch}
.pp-group{margin:0; padding:0 var(--pp-pad,.85rem) .8rem; background:var(--surface2); border:1px solid var(--card-bd); border-radius:var(--r-card); overflow:hidden}
.pp-group-title{display:flex; align-items:center; gap:var(--sp-md); margin:0 calc(-1 * var(--pp-pad,.85rem)) .5rem; padding:.62rem var(--pp-pad,.85rem) .58rem; background:var(--tint-blue); border-bottom:1px solid var(--border); border-inline-start:3px solid var(--blue); font-size:var(--fs-body); font-weight:700; color:var(--text); letter-spacing:.01em; line-height:1.3}
.pp-cols .pp-group>.field:last-child{margin-bottom:.15rem}
.pp-cols .kv{grid-template-columns:150px 1fr; gap:var(--sp-lg); padding:.5rem .35rem; font-size:var(--fs-body); align-items:baseline; border-bottom:1px solid var(--border); border-radius:var(--r-chip); transition:background .12s}
.pp-cols .kv:hover{background:var(--pp-hover)}
.pp-cols .kv:last-child{border-bottom:none}
.pp-cols .kv .k{color:var(--text-dim); font-weight:400}
.pp-cols .kv>span:last-child{color:var(--text); font-weight:600; text-align:start; word-break:break-word}
.pp-cols .kv .muted{font-size:var(--fs-label); font-weight:400; color:var(--pp-empty)}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size:var(--fs-body); letter-spacing:.01em}
.pp-nav-line{display:flex; gap:var(--sp-xl); align-items:center; flex-wrap:wrap; margin-top:1rem; padding-top:.7rem; border-top:1px solid var(--border); font-size:var(--fs-label); color:var(--text-dim)}
.pp-unit{display:grid; grid-template-columns:54px 1fr 1fr 34px; gap:var(--sp-md); align-items:center; margin-bottom:.45rem}
.pp-unit-n{font-size:var(--fs-label); color:var(--text-dim); font-weight:600}
.pp-unit-del{background:none; border:1px solid var(--ctl-bd); color:var(--text-dim); border-radius:var(--r-chip); cursor:pointer; padding:.3rem; font-size:var(--fs-label)}
.pp-unit-del:hover{color:var(--red); border-color:var(--red)}
.pp-unit .inp{width:100%; min-width:0}   /* инпуты заполняют ячейку и сжимаются — иначе מספר רישום вылезал за карточку */
.pp-accent{background:var(--pp-accent-bg); border-radius:var(--r-chip); padding:.4rem .55rem; margin:.15rem 0}
.pp-accent .k, .pp-accent label{color:var(--pp-accent-tx); font-weight:600}
/* ── редактор схемы паспорта (🏷️): имя категории + добавление категорий/полей ── */
.pp-cat-name{background:var(--pp-accent-bg); border:1px dashed var(--pp-accent-tx); border-radius:var(--r-chip); padding:.5rem .6rem .55rem; margin-bottom:.75rem}
.pp-cat-name label{display:flex; align-items:center; gap:var(--sp-sm); font-size:var(--fs-label); color:var(--pp-accent-tx); font-weight:600; margin-bottom:.35rem}
/* приписка при подписи: заголовок группы жирный (700), уточнение при нём — нет.
   Классом, а не инлайном: инлайн сильнее любого правила и потому глушил
   טקסט מודגש — в режиме жирного текста приписка оставалась тонкой. */
.pp-note{font-weight:400}
/* числовой чип в тексте паспорта: обычный и усиленный */
/* D-206 (заход 82): чип позиционного номера в תעודת זהות.
   Одежда была инлайном в pass-modal.js и потому глушила линзу подвала.
   Рамка переведена на --acc-rule: прежняя rgba(.3) давала 1.24:1 против заливки
   чипа при пороге 3:1 для значимых границ — её просто не было видно. Теперь
   3.19:1 в тёмной и 3.65:1 в светлой. Текст на --text-dim: 5.32…6.43:1 на всех
   четырёх сочетаниях тема × поверхность при пороге 4.5.
   ⚠️ font-size остаётся относительным (.9em) намеренно: ступень для чипов шкала
   ещё не назначила, и притянуть его к --fs-* сейчас значит выбрать наугад. */
.pp-num{font-weight:600; display:inline-block; margin-inline-end:.42em; padding:.06em .45em;
  border-radius:var(--r-chip); background:var(--chip-num-bg); border:1px solid var(--acc-rule);
  color:var(--text-dim); font-size:.9em; line-height:1.35; vertical-align:baseline; letter-spacing:.01em}
.pp-num-t{unicode-bidi:isolate; direction:ltr; font-variant-numeric:tabular-nums}
.pp-num.strong{font-weight:700}
.pp-cat-name input.inp{font-weight:600; background:var(--inp-bg)}
.pp-cf{border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.55rem .6rem .35rem; margin-bottom:.6rem; background:var(--surface2)}
.pp-cf-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-md); margin-bottom:.4rem}
.pp-cf-head .tag{font-size:var(--fs-small); font-weight:600; color:var(--pp-accent-tx); background:var(--pp-accent-bg); border-radius:var(--r-card); padding:.12rem .55rem}
.pp-cf-del{background:none; border:none; cursor:pointer; font-size:var(--fs-body); line-height:1; opacity:.6; padding:.1rem}
.pp-cf-del:hover{opacity:1}
.pp-cf-del.pp-off{opacity:1; color:var(--text-faint)}
.pp-tsel{flex:none; width:6.5rem; padding-inline:.4rem}
.field.pp-off, .pp-group.pp-off{opacity:.6}
#netList .switch{padding-block:.35rem}
#netQ{margin-bottom:.2rem}
.pp-cf-row{display:flex; gap:var(--sp-md); flex-wrap:wrap}
.pp-cf-row .field{flex:1 1 7rem; margin-bottom:.6rem}
.pp-add{margin-top:.45rem}
.pp-add .btn{font-size:var(--fs-label); padding:.42rem .8rem}
.pp-add-cat{margin-top:1rem; padding-top:.85rem; border-top:1px dashed var(--border)}
.pp-badge{border-radius:var(--r-chip); padding:.55rem .8rem; margin-bottom:.7rem; font-size:var(--fs-body); font-weight:600; display:flex; align-items:center; gap:var(--sp-md); flex-wrap:wrap; line-height:1.35}
.pp-badge.svc{background:var(--svc-bg); border:1px solid var(--svc-bd); color:var(--svc-tx)}
.pp-badge.rev{background:var(--rev-bg); border:1px solid var(--rev-bd); color:var(--rev-tx)}
.pp-rev-ok{margin-inline-start:auto; background:var(--surface); border:1px solid var(--ctl-bd); color:var(--text); border-radius:var(--r-chip); padding:.28rem .6rem; font-size:var(--fs-label); cursor:pointer; font-weight:600}
.pp-rev-ok:hover{border-color:var(--green); color:var(--green)}
.pp-group.pp-hl{background:var(--rev-bg); border-color:var(--rev-bd)}
.pp-group.pp-hl .pp-group-title{background:transparent; color:var(--rev-tx); border-inline-start-color:var(--rev-bd); border-bottom-color:var(--rev-bd)}
.pp-hl-tag{font-size:var(--fs-small); font-weight:600; color:var(--rev-tx); border:1px solid var(--rev-bd); border-radius:var(--r-card); padding:.04rem .5rem; margin-inline-start:auto}
.kv .k{color:var(--text-dim)}
/* Секция מערכות занимает всю ширину карточки объекта, а строка системы несёт
   короткий текст — слева оставалось до полуметра пустоты. Строки ложатся в
   сетку: при ~1000px две колонки, на телефоне одна.
   ⚠️ Сетка живёт на СОБСТВЕННОЙ обёртке, а не на .acc-body. Правило вида
   #acc_sys .acc-body{display:grid} перебивало .acc-body{display:none} по
   специфичности (id весит больше трёх классов) — секция переставала
   закрываться. Механизм раскрытия и раскладка не должны спорить за одно
   свойство одного элемента. */
/* Тот же приём, что в редакторе систем и в паспорте: равная высота в ряду,
   разделительные линии на одном уровне. */
.sys-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,30rem),1fr)); gap:0 var(--sp-2xl); align-items:stretch}
.sys-row{display:flex; align-items:center; gap:var(--sp-lg); padding:.6rem 0; border-bottom:1px solid var(--border)}
.sys-row:last-child{border-bottom:none}
.sys-row:last-child{border-bottom:none}
.sys-dot{width:13px; height:13px; border-radius:var(--r-circle); flex-shrink:0}
/* D-141 sweep (заход 69): цвет точки приходил инлайном из четырёх литералов в render.js.
   Те же классы состояния, что у плитки иконки, — один источник на оба носителя. */
.sys-dot.t-fault{background:var(--status-fault-tx)} .sys-dot.t-fixed{background:var(--status-fixed)}
.sys-dot.t-ok{background:var(--status-ok-tx)} .sys-dot.t-stale{background:var(--status-pending-tx)}
.sys-tile{width:44px; height:44px; border-radius:var(--r-ctl); border:1px solid transparent; display:flex; align-items:center; justify-content:center; flex:none}
/* Компактный вариант плитки для окна правки: тот же цвет состояния, меньше
   размер — строка редактора плотнее, чем карточка просмотра. */
.sys-tile.sm{width:30px; height:30px; border-radius:var(--r-chip)}
.sys-tile.sm svg{width:19px; height:19px}
.ser-head{display:flex; align-items:center; gap:var(--sp-md)}
.sys-tile.t-fault{background:var(--fault-plate); border-color:var(--red); color:var(--fault-fg)}
.sys-tile.t-fixed{background:var(--status-fixed-bg); border-color:var(--status-fixed); color:var(--status-fixed)}
.sys-tile.t-ok{background:var(--tint-green); border-color:var(--green); color:var(--green)}
.sys-tile.t-stale{background:var(--surface2); border-color:var(--border); color:var(--grey)}
.st-lab.t-fault{color:var(--fault-fg)} .st-lab.t-fixed{color:var(--blue)} .st-lab.t-ok{color:var(--green)} .st-lab.t-stale{color:var(--grey)}
.sys-tile svg{width:28px; height:28px}
.st-ic{width:1em; height:1em; vertical-align:-.14em; margin-inline-end:.35rem; flex:none}
.eic{width:1.05em; height:1.05em; vertical-align:-.16em; margin-inline-end:.35rem; flex:none}
.eic.tr{margin-inline-end:0; margin-inline-start:.35rem}
.eic.solo{margin:0}
.sdot{display:inline-block; width:.6em; height:.6em; border-radius:var(--r-circle); margin-inline-end:.4rem; flex:none}
.sdot.d-red{background:var(--red)} .sdot.d-green{background:var(--green)} .sdot.d-grey{background:var(--grey)} .sdot.d-blue{background:var(--blue)} .sdot.d-orange{background:var(--orange)}
.st-lab{display:inline-flex; align-items:center}
.ah-ic{width:20px; height:20px; color:var(--blue); flex:none}
/* D-51: имя системы и её состояние — одна строка, одним взглядом.
   flex:1 у имени убран: он растягивал надпись и уносил состояние к краю. */
.sys-hd{display:flex; align-items:baseline; gap:var(--sp-md); flex-wrap:wrap}
.sys-hd .st-lab{font-weight:700; flex:none}
.sys-name{font-size:var(--fs-body); font-weight:700; min-width:0}
.sys-state{font-size:var(--fs-label); color:var(--text-dim)}
/* Инлайн-цвета в render.js перекрывали --text-dim выше и проваливали порог 4.5:1
   каждый в своей теме: #64748b 3.63:1 в тёмной, #475569 2.28:1 в тёмной,
   #2563eb 3.35:1 в тёмной, #dc2626 3.58:1 в тёмной. Две строки просто отдали цвет
   классу (7.06:1 · 6.00:1), двум оставшимся заведены роли. */
.sys-state.sys-fixed{color:var(--status-fixed); font-weight:700}   /* 9.59:1 · 6.38:1 */
.sys-state.sys-flag{color:var(--status-fault-tx); font-weight:700}    /* 5.50:1 тёмная · 4.83:1 светлая */
.seg{display:flex; gap:var(--sp-sm); flex-wrap:wrap}
.seg button{background:var(--surface2); border:1px solid var(--ctl-bd); color:var(--text); border-radius:var(--r-chip); padding:.5rem .9rem; font-weight:700; cursor:pointer; font-family:inherit; font-size:var(--fs-body)}
.seg button.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.seg button.on-green{background:var(--status-ok); border-color:var(--status-ok); color:var(--action-primary-tx)}
.seg button.on-orange{background:var(--status-warn); border-color:var(--status-warn); color:var(--action-primary-tx)}
.seg button.on-red{background:var(--status-fault); border-color:var(--status-fault); color:var(--action-primary-tx)}
.row-inline{display:flex; gap:var(--sp-md); align-items:center; flex-wrap:wrap}
.switch{display:flex; align-items:center; gap:var(--sp-md); padding:.5rem 0; justify-content:space-between}
.tgl{width:50px; height:28px; border-radius:var(--r-pill); background:var(--surface2); border:1px solid var(--ctl-bd); position:relative; cursor:pointer; flex-shrink:0; transition:background .15s}
.tgl.on{background:var(--green)}
.tgl::after{content:''; position:absolute; top:2px; inset-inline-end:2px; width:22px; height:22px; border-radius:var(--r-circle); background:#fff; transition:transform .15s}
.tgl.on::after{transform:translateX(-22px)}
html[dir=rtl] .tgl.on::after{transform:translateX(22px)}
textarea.inp{width:100%; min-height:80px; resize:vertical; line-height:1.5}
.btn{background:var(--action-primary); color:var(--action-primary-tx); border:none; border-radius:var(--r-ctl); padding:.55rem 1.1rem; font-weight:700; cursor:pointer; font-family:inherit; font-size:var(--fs-body); transition:filter .12s}
.btn:hover{filter:brightness(1.08)}
.btn.ghost{background:var(--surface2); color:var(--text); border:1px solid var(--ctl-bd)}
.btn:hover{filter:brightness(1.08)}
.muted{color:var(--text-dim); font-size:var(--fs-label)}
.task-card{background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-ctl); padding:.7rem .8rem; margin-bottom:.55rem}
.hist-row{background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.6rem .7rem; margin-bottom:.5rem}
.hist-top{display:flex; justify-content:space-between; gap:var(--sp-md); flex-wrap:wrap; align-items:baseline}
.hist-tabs{display:flex; gap:var(--sp-sm); margin:0 0 .8rem}
.hist-tabs button{flex:1; padding:.6rem .5rem; border:1px solid var(--ctl-bd); background:var(--surface2); color:var(--text-dim); border-radius:var(--r-chip); font-weight:700; font-size:var(--fs-body); cursor:pointer}
.hist-tabs button.on{background:var(--sel-bg); color:var(--sel-tx); border-color:transparent}
.oc-actions{margin-top:auto; padding-top:.5rem; border-top:1px solid var(--border)}
/* Кнопка списка внутри карточки не растягивается на всю ширину: .dd-btn.inp даёт
   width:100%, и надпись «הקצה בדיקה מלאה ל…» уезжала на 700px от своей стрелки.
   В ФОРМЕ растянутое поле со стрелкой у края законно — это привычное поведение
   select. Здесь не форма, а одиночное второстепенное действие в карточке. */
.oc-actions .dd-btn.inp{width:auto; max-width:100%}
/* Селект живёт ВНУТРИ карточки. Когда это писалось, --inp-bg и --surface были одним цветом: от карточки
   его отличает только рамка. С ярусом полей (--inp-bd, 3.3:1) получались два
   равных по весу контура на всю ширину, вложенных друг в друга. Вложенный
   контрол опущен на тихий ярус. Дальше выяснилось, что этого мало: разделитель
   .oc-actions и верх селекта — две параллельные линии во всю ширину в 8px друг
   от друга, обе отделяют действие от сведений. Оставлена одна, разделитель;
   селект находят синий полужирный текст и шеврон, а не обводка.
   В формах и модалках ярус захода 31 не тронут.
   Заход 42: --inp-bg посветлел, но этот селект залит transparent — его правка не касается. */
.insp-assign{width:100%; font-size:var(--fs-label); padding:.4rem .5rem; color:var(--action-primary); font-weight:600; cursor:pointer; border-color:transparent; background:transparent; box-shadow:none}
.insp-assign:focus{border-color:var(--inp-focus); box-shadow:0 0 0 3px var(--inp-ring)}
.dash-toast{position:fixed; inset-inline:0; bottom:24px; margin-inline:auto; width:max-content; max-width:90vw; background:var(--status-ok); color:var(--action-primary-tx); font-weight:600; padding:12px 20px; border-radius:var(--r-ctl); box-shadow:0 10px 30px rgba(0,0,0,.3); opacity:0; transform:translateY(10px); transition:.22s; z-index:9999; pointer-events:none}
.dash-toast.show{opacity:1; transform:translateY(0)}
.hist-wrap{max-width:1060px; margin-inline:auto}
.hist-wrap .sect{max-width:none}
.hist-list{display:grid; grid-template-columns:repeat(auto-fill,minmax(330px,1fr)); gap:var(--sp-md)}
@media(max-width:720px){ .hist-list{grid-template-columns:minmax(0,1fr)} }
.chip-on{border-color:var(--orange)!important; color:var(--orange)!important; font-weight:700}
/* ── Форма «сообщение» · D-46, ярус B ─────────────────────────────────────
   Канон, «Компоновка»: индикатор не носит одежду кнопки — без рамки контрола,
   без радиуса кнопки, цвет --text-dim. Правило в каноне было, реализации не было,
   поэтому сообщения одевались кнопками. .cycle-bar несла ПЯТЬ признаков контрола
   сразу: рамку --ctl-bd, тень карточки, фон --surface, радиус 12px (= радиус
   .icon-btn) и min-height:40px (= высота .icon-btn) — и стояла в .toolbar между
   настоящими кнопками, неотличимая от них.
   Контраст посчитан ДО применения (фон снят, текст уходит с --surface на --bg):
   тёмная 7.72:1 · светлая 6.45:1 · bold-ui 11.85 / 8.81. Порог текста 4.5:1.
   cursor:default — вторая половина отличия: третий ярус действий тоже носит
   --text-dim, и разводит их указатель, а не цвет.
   ⚠️ .cache-tag (стр. 179) этой форме соответствовал изначально и в селектор
   НЕ входит намеренно: его display:none объявлен выше, и форма отсюда включила бы
   плашку кэша навсегда. */
.note-line, .cycle-bar{
  display:inline-flex; flex-wrap:wrap; min-width:0; align-items:center;
  gap:var(--sp-md); padding:.25rem 0;
  background:none; border:none; box-shadow:none; border-radius:0;
  font-size:var(--fs-small); line-height:var(--lh-body);
  color:var(--text-dim); cursor:default;
}
.cycle-bar{margin-inline-start:auto; white-space:nowrap}
/* Действие внутри сообщения остаётся действием и одето по своему ярусу. */
.cycle-bar .btn{font-size:var(--fs-small); padding:.25rem .75rem}
.task-card.done{opacity:.6}
.task-top{display:flex; justify-content:space-between; gap:var(--sp-md); align-items:flex-start}
.task-title{font-weight:700; font-size:var(--fs-body)}
.task-meta{font-size:var(--fs-small); color:var(--text-dim); margin-top:.2rem; line-height:1.5}
/* Строка события в карточке задачи (בוצע ע״י / בוטלה ע״י). Заход 62.
   Было --green: событие красилось цветом СОСТОЯНИЯ (зелёный = תקין), а у отмены это
   ещё и врало по смыслу: «была отменена» — не хорошее состояние. Закон полевого
   (заход 55) звучит так же и здесь: зелёный/красный = состояние, и только состояние.
   Главное же выяснилось при счёте: карточка закрытой задачи стоит под opacity:.6,
   и зелёный на ней давал 2.47:1 в тёмной теме и 1.93:1 в светлой — строку было
   просто плохо видно. Стало 5.54:1 и 4.60:1. Различие done/cancelled несут иконка,
   слово и таблетка состояния сверху — цвет здесь дублировал то, что уже сказано.
   Осталась одна строка — בוצע ע״י: строка отмены убрана как дубль ленты. */
.task-done{font-size:var(--fs-label); color:var(--evt-tx); font-weight:600; margin-top:.3rem}
.task-trail{margin-top:.45rem; padding-top:.4rem; border-top:1px dashed var(--border); display:flex; flex-direction:column; gap:var(--sp-2xs)}
.trail-row{font-size:var(--fs-small); color:var(--text-dim); line-height:1.45}
.task-actions{display:flex; flex-wrap:wrap; gap:var(--sp-sm); align-items:center; margin-top:.55rem}
.task-history{margin-top:.6rem; border-top:1px dashed var(--border); padding-top:.6rem}
.task-history>summary{cursor:pointer; font-weight:600; color:var(--text-dim); padding:.35rem 0; user-select:none; list-style:revert}
.tk-reassign{max-width:190px; font-size:var(--fs-label); padding:.35rem .5rem}
.mini-link{color:var(--blue); cursor:pointer; text-decoration:underline}
.field{margin-bottom:.7rem}
.field label{display:block; font-size:var(--fs-label); color:var(--text-dim); margin-bottom:.45rem; line-height:1.35}
.field{margin-bottom:1rem}
.tkpick-tabs{display:flex; gap:var(--sp-sm); margin-bottom:.4rem}
.tkpick-tab{flex:1; background:var(--surface2); border:1px solid var(--ctl-bd); color:var(--text-dim); border-radius:var(--r-chip); padding:.45rem .5rem; font-weight:700; font-size:var(--fs-body); font-family:inherit; cursor:pointer}
.tkpick-tab.on{background:var(--sel-bg); color:var(--sel-tx); border-color:var(--sel-bd)}
.tkpick-list{max-height:220px; overflow:auto; border:1px solid var(--ctl-bd); border-radius:var(--r-chip); background:var(--surface2)}
.tkpick-row{padding:.5rem .7rem; font-size:var(--fs-body); cursor:pointer; border-bottom:1px solid var(--border)}
.tkpick-row:last-child{border-bottom:none}
.tkpick-row:hover{background:var(--surface)}
.tkpick-row.sel{background:var(--blue); color:var(--action-primary-tx); font-weight:600}
.tkpick-empty{padding:.8rem; text-align:center; color:var(--text-dim); font-size:var(--fs-body)}
select.inp,.dd-btn.inp{width:100%}   /* кнопка общего списка в поле формы тянется так же, как тянулся <select> */

/* miklat: two columns + accordion + systems edit */
/* Ярус C, D-43 (карточка объекта). Было minmax(0,860px) 1fr — содержимое упиралось
   в потолок 860, а карта забирала ВЕСЬ остаток: на 1860 около 970 пикселей ради
   одной точки. Канон: на карточке одного объекта карта не больше трети экрана.
   Стало 2fr/1fr — ровно треть на любой ширине.
   ⚠️ Предел 1560px здесь стоял и снят вместе с пределами страниц: он давал
   поля по 170px по краям экрана объекта — та же ошибка, что и на страницах,
   просто в четвёртом месте. Ширину использует содержание (сетка систем),
   а не поля. */
.mk-layout{flex:1; display:grid; grid-template-columns:minmax(0,2fr) minmax(0,1fr); gap:var(--sp-lg); padding:.85rem 1.1rem 1rem; min-height:0}
.mk-head{display:flex; align-items:flex-start; gap:var(--sp-2xl); padding:.85rem 1.2rem; flex-wrap:wrap; justify-content:flex-start}
/* v212: выравнивание по ВЕРХУ. Было center — и блок заголовка, выросший на две кнопки,
   уезжал вниз вместе с названием. Верх фиксирован, растёт только низ. */
.mk-head .fs-title{font-size:var(--fs-display); font-weight:700}
.mk-head-title{min-width:170px}
/* v213: две колонки на весь блок, а не флекс в каждой строке по отдельности.
   Подписи разной длины (סטטוס · נבדק ע״י · סך משימות פתוחות) сдвигали значения каждое
   на своё место — колонки значений не было вовсе. Сетка держит общий край для всех строк:
   первая колонка по самой длинной подписи, вторая — значения. */
.mk-head-status{display:grid; grid-template-columns:max-content minmax(0,1fr); align-items:center; gap:var(--sp-xs) var(--sp-md); font-size:var(--fs-body); white-space:nowrap; margin-inline-start:2.5rem; padding-inline-start:1.5rem; border-inline-start:2px solid var(--border)}
/* строка растворяется: её дети становятся ячейками общей сетки выше */
.mk-head-status .row{display:contents}
/* строка без подписи (просрочки) — на всю ширину, иначе уедет в колонку подписей */
.mk-head-status .row .val:only-child{grid-column:1 / -1}
.mk-head-status .lbl{color:var(--text-dim)}
.mk-head-status .val{color:var(--text); font-weight:600}
/* #fbbf24 давал в СВЕТЛОЙ теме 1.67:1 — строка «просрочено» была практически
   невидима именно там, где её и читают днём. --status-warn: 4.86:1 · 5.18:1. */
.mk-head-status .val.val-late{color:var(--status-warn-tx)}
.mk-left{display:flex; flex-direction:column; gap:var(--sp-lg); min-height:0}
#mkMap{flex:1; min-height:240px; border-radius:var(--r-card); border:1px solid var(--ctl-bd); overflow:hidden}
.navbtns{display:flex; gap:var(--sp-md)}
.navbtns button{flex:1; text-align:center; background:var(--action-primary); color:var(--action-primary-tx); border:none; border-radius:var(--r-chip); padding:.65rem; font-weight:700; font-size:var(--fs-body); cursor:pointer; font-family:inherit}
.navbtns button.alt{background:var(--surface2); color:var(--text); border:1px solid var(--ctl-bd)}
.navbtns button:hover{filter:brightness(1.08)}
/* v210: две главные кнопки карточки переехали из-под карты в шапку. Под картой они лежали
   в самом низу левой колонки — дальше всего и от глаза, и от большого пальца.
   v212: живут ВНУТРИ блока заголовка, под названием объекта. Поэтому их край сам собой
   совпадает с краем названия и адреса — выравнивать вручную нечего, за это отвечает поток. */
/* v214: кнопки на всю ширину колонки заголовка — упираются в тот же край, что название
   и адрес. Ширину не задаём числом: её диктует самая длинная строка блока, поэтому
   край останется общим и на другом объекте с другим адресом. */
.mk-head-title .navbtns{margin-top:.55rem; width:100%}
.mk-head .navbtns button{flex:1; padding:.6rem 1.15rem}
/* v208: развилка «система ИЛИ свободная задача» в формах создания задачи */
.tk-or{position:relative; text-align:center; margin:.5rem 0 .45rem; font-size:var(--fs-small)}
.tk-or::before,.tk-or::after{content:""; position:absolute; top:50%; width:calc(50% - 1.3rem); border-top:1px solid var(--border)}
.tk-or::before{inset-inline-start:0}
.tk-or::after{inset-inline-end:0}
.mk-summary{background:var(--surface); border:1px solid var(--card-bd); border-radius:var(--r-card); padding:.85rem}
.mk-right{overflow-y:auto; min-height:0; padding-bottom:1rem}
.acc{background:var(--surface); border:1px solid var(--card-bd); border-radius:var(--r-card); margin-bottom:.7rem; overflow:hidden}
/* min-height — ради линии: без неё содержимое строки без кнопок ниже, чем
   со кнопками (кнопка = 2.5rem), и вертикаль получалась разной длины. */
.acc-head{display:flex; align-items:center; gap:var(--sp-md); padding:.85rem 1rem; cursor:pointer; user-select:none; min-height:2.5rem}
/* D-49: тот же механизм, что D-51. flex:1 растягивал заголовок и выталкивал
   кнопки правки на противоположный край строки — около 900px от того, что они
   правят. Заголовок теперь по содержимому, кнопки стоят рядом с ним.
   min-width по самому длинному заголовку (סימון ידני של מוכנות (מנהל) ≈ 13rem):
   кнопки правки всех секций встают в одну колонку вместо разнобоя по длине
   названия — но в 15rem от него, а не в метре, как было до яруса C. */
/* Заход 67, поправка по осмотру владельца: было min-width — ширина «не меньше»,
   и заголовок длиннее её сдвигал сводку вправо. Восемь сводок вставали по
   разным вертикалям и читались волной. Ширина ФИКСИРОВАНА: колонка одна на все
   секции. Длиннее — многоточие, а не сдвиг соседа. */
.acc-head h3{font-size:var(--fs-body); font-weight:700; margin:0; flex:none;
  width:min(15rem,100%); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* D-122 (заход 67) — сводка свёрнутой секции. Заголовок называет раздел,
   сводка говорит, что внутри: «6 \u05EA\u05E7\u05DC\u05D5\u05EA», «\u05DB\u05DC 90 \u05D9\u05DE\u05D9\u05DD», «\u05D0\u05D9\u05DF \u05D4\u05E2\u05E8\u05D5\u05EA».
   Своя min-width — по той же причине, что у h3 (D-49): две колонки постоянной
   ширины держат кнопки правки всех секций на одной вертикали. Ячейка печатается
   всегда, даже пустая, иначе колонка рассыпается на секциях без сводки.
   Цвет состояния — только у состояния (Закон 2): неисправность и просрочка. */
/* Волосяная линия — «מסגרת» строки: она делает колонку видимой и привязывает
   сводку к названию. Канон: линия сильнее пустоты. Тире-выноска (как в оглавлении)
   рассматривалась и отклонена — она чинит вид, но не вертикаль: рваный край
   остался бы, а чернил стало бы вдевятеро больше на восьми строках. */
.acc-sub{font-size:var(--fs-small); font-weight:600; color:var(--text-dim);
  flex:none; width:min(11rem,100%); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  align-self:stretch; display:flex; align-items:center;
  border-inline-start:1px solid var(--acc-rule); padding-inline-start:.9rem}
/* Пустая ячейка держит колонку кнопок, но палку без текста рисовать нельзя. */
.acc-sub:empty{border-inline-start:0; padding-inline-start:0}
.acc-sub .sub-fault{color:var(--status-fault-tx); font-weight:700}
.acc-sub .sub-late{color:var(--status-warn-tx); font-weight:700}
.acc-arrow{color:var(--text-dim); transition:transform .2s; width:16px; height:16px; display:inline-flex; align-items:center; justify-content:center; flex:none}
.acc-arrow svg{width:16px; height:16px}
.acc.open .acc-arrow{transform:rotate(180deg)}
.acc-edit{background:var(--surface2); border:1px solid var(--ctl-bd); color:var(--text); border-radius:var(--r-chip); padding:.4rem .65rem; cursor:pointer; font-size:var(--fs-body); margin-inline-start:.4rem}
.acc-edit.active{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.acc-body{display:none; padding:0 1rem 1rem}
.acc.open .acc-body{display:block}
.tk-grid{display:grid; grid-template-columns:minmax(260px,320px) minmax(260px,320px) minmax(0,1fr); gap:var(--sp-xl); align-items:start}
@media(max-width:1024px){ .tk-grid{grid-template-columns:minmax(0,1fr)} }
.tk-col{display:flex; flex-direction:column; gap:var(--sp-xl); min-width:0}
.fault-item{background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-ctl); padding:.7rem .85rem; margin-bottom:.6rem}
.fault-item:last-child{margin-bottom:0}
.fault-name{font-weight:700; font-size:var(--fs-body)}
.fault-meta{font-size:var(--fs-label); color:var(--text-dim); margin-top:.2rem}
.fault-note{margin-top:.45rem; font-size:var(--fs-body); line-height:1.35; white-space:pre-wrap; word-break:break-word}
.fault-note.muted{font-style:italic}
.fault-assign{margin-top:.45rem; font-size:var(--fs-lead); font-weight:600; color:#1d4ed8}
/* строка «\u05de\u05d5\u05e7\u05e6\u05d4 \u05dc\u05d8\u05d9\u05e4\u05d5\u05dc» в карточке миклата: своя переменная размера, чтобы не
   трогать .sys-state — он общий для шести строк состояния системы */
.asg-line{font-size:var(--fs-lead)}
/* кнопка назначения (заменила выпадающий список) */
/* «\u05e9\u05e0\u05d4 \u05de\u05d8\u05e4\u05dc\u05d9\u05dd» — вторичное действие: тихая текст-кнопка, выровненная в ту же
   колонку, что строки состояния. Отрицательное поле гасит внутренний отступ, иначе
   текст встаёт мимо колонки на величину padding. */
.asg-open{display:inline-flex; align-items:center; gap:var(--sp-sm); background:transparent; border:1px solid transparent; color:var(--action-primary); font-weight:700; font-size:var(--fs-body); font-family:inherit; border-radius:var(--r-ctl); padding:.25rem .6rem; min-height:34px; cursor:pointer; width:auto; justify-content:flex-start; margin-inline-start:-.6rem}
.asg-open:hover{background:rgba(37,99,235,.10)}
/* «\u05d4\u05e7\u05e6\u05d4 \u05dc\u05d8\u05d9\u05e4\u05d5\u05dc» — призыв: его нужно находить глазом, поэтому рамка */
.asg-open.new{border-color:var(--ctl-bd); border-style:dashed; padding:.5rem .85rem; margin-inline-start:0}
.asg-open.new:hover{border-color:#2563eb; border-style:solid}
/* окно выбора \u05de\u05d8\u05e4\u05dc\u05d9\u05dd — выше modalOverlay(3000) и confirmOverlay(3400): зовётся ИЗ них */
#asgOverlay{display:none; position:fixed; inset:0; z-index:3600; background:var(--modal-scrim); align-items:center; justify-content:center; padding:1rem}
#asgOverlay.show{display:flex}
.asg-card{background:var(--surface); border:1px solid var(--modal-bd); border-radius:var(--r-card); width:min(420px,94vw); max-height:88vh; display:flex; flex-direction:column; box-shadow:var(--modal-shadow); overflow:hidden}
.asg-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-xl); padding:1rem 1.1rem .4rem}
.asg-head h3{font-size:var(--fs-lead); font-weight:700}
.asg-sub{padding:0 1.1rem .7rem; color:var(--text-dim); font-size:var(--fs-label)}
.asg-list{overflow:auto; padding:.2rem .9rem .9rem; display:flex; flex-direction:column; gap:var(--sp-md)}
.asg-row{display:flex; align-items:center; gap:var(--sp-lg); width:100%; text-align:start; background:var(--inp-bg); border:1px solid var(--inp-bd); border-radius:var(--r-ctl); padding:.7rem .8rem; font-family:inherit; font-size:var(--fs-lead); font-weight:400; color:var(--text); cursor:pointer; min-height:50px}
.asg-row.on{border-color:var(--action-primary); background:rgba(37,99,235,.12); color:#1d4ed8}
.asg-box{width:24px; height:24px; border-radius:var(--r-chip); border:2px solid var(--inp-bd); display:inline-flex; align-items:center; justify-content:center; flex:none; color:transparent}
.asg-box .eic{width:15px; height:15px}
.asg-row.on .asg-box{background:var(--action-primary); border-color:var(--action-primary); color:var(--action-primary-tx)}
.asg-other{display:flex; flex-direction:column; gap:var(--sp-xs); margin-top:.4rem}
.asg-other label{color:var(--text-dim); font-size:var(--fs-small)}
.asg-foot{display:flex; gap:var(--sp-md); padding:.85rem .9rem; border-top:1px solid var(--border)}
.asg-foot .btn{flex:1; display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-sm)}
.tk-sum{background:var(--surface); border:1px solid var(--card-bd); border-radius:var(--r-card); padding:1rem 1.05rem}
.tk-sum h3{font-size:var(--fs-body); font-weight:700; margin:0 0 .7rem; display:flex; align-items:center; gap:var(--sp-sm)}
.tk-sum h4{font-size:var(--fs-small); font-weight:600; color:var(--text-dim); margin:.95rem 0 .35rem}
.tk-stat{display:flex; gap:var(--sp-md); margin-bottom:.3rem}
.tk-stat .s{flex:1; min-width:0; background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.5rem; text-align:center; font-family:inherit; cursor:pointer; transition:border-color .12s, background .12s}
.tk-stat .s:hover{border-color:var(--sel-bd)}
.tk-stat .s.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.tk-stat .s b{display:block; font-size:var(--fs-h3); font-weight:700; line-height:1.1}
.tk-stat .s span{font-size:var(--fs-micro); color:var(--text-dim)}
.tk-line{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-md); padding:.32rem 0; border-bottom:1px solid var(--border); font-size:var(--fs-label)}
.tk-line:last-child{border-bottom:none}
.tk-line .n{background:var(--surface2); border-radius:var(--r-chip); padding:.05rem .45rem; font-weight:700; font-size:var(--fs-label)}
.tk-old{font-size:var(--fs-label); padding:.42rem 0; border-bottom:1px solid var(--border)}
.tk-old:last-child{border-bottom:none}
.tk-old .t{font-weight:600} .tk-old .m{color:var(--text-dim); font-size:var(--fs-small); margin-top:.12rem}
.tk-tiles{display:flex; flex-wrap:wrap; gap:var(--sp-md); margin-bottom:.9rem}
.tk-tile{display:flex; flex-direction:column; align-items:center; gap:var(--sp-xs); min-width:92px; background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-ctl); padding:.55rem .6rem; cursor:pointer; font-family:inherit}
.tk-tile .lbl{font-size:var(--fs-label); font-weight:600; color:var(--text); white-space:nowrap}
.tk-tile .tk-tile-n{font-size:var(--fs-lead); font-weight:700; color:var(--text)}
.tk-tile.on{background:var(--sel-bg); border-color:var(--sel-bd); color:var(--sel-tx)}
.tk-tile.caban .tk-tile-n{color:var(--orange)}
.tk-tile.gen .tk-tile-n{color:var(--text-dim)}
/* ============================================================
   D-173 (заход 77). Вид действия «выполнено» на экране задач.
   .is-busy — кнопка ответила НЕМЕДЛЕННО, до ответа сервера. Раньше между
   нажатием и перерисовкой не было ничего, и человек нажимал второй раз.
   .just-done — карточка, отмеченная на этом экране и удержанная на своём месте:
   зелёная кромка и приглушённый фон говорят «сделано», список не съезжает.
   ⚠️ Кромка идёт border-inline-start, а не left: интерфейс RTL, «начало» строки
      справа. С left полоса встала бы у чужого края.
   ============================================================ */
.btn.is-busy{ opacity:.7; cursor:default; pointer-events:none }
/* D-174 (заход 77, уточнено после проверки на боевом DEV). Иконка системы в
   משימות. Тот же спрайт, что на карточках объектов, но роль другая: там иконка
   КРИЧИТ о поломке (58px, на плашке), здесь она НАЗЫВАЕТ систему и подсказывает
   её состояние — значит меньше, но не мелко и не бесцветно.
   ⚠️ Первый заход дал 20px и один серый цвет: владелец сказал «мелковатые и не
      красятся», и был прав — бесцветный значок не несёт ничего, кроме имени,
      которое и так написано рядом словами.
   Цвета — те же роли, что везде: поломка, порядок, не проверено. */
.task-sys-ic{ display:inline-flex; align-items:center; justify-content:center;
  width:2rem; height:2rem; border-radius:var(--r-chip); flex:none;
  margin-inline-end:var(--sp-md); vertical-align:-.45rem;
  background:var(--badge-grey-bg); }
.task-sys-ic .fic{ width:1.5rem; height:1.5rem; color:var(--text-dim) }
.task-sys-ic.s-fault{ background:var(--fault-plate); border:1px solid var(--fault-line) }
.task-sys-ic.s-fault .fic{ color:var(--fault-fg) }
.task-sys-ic.s-ok{ background:var(--green-soft) }
.task-sys-ic.s-ok .fic{ color:var(--green) }
.tk-line .task-sys-ic{ width:1.625rem; height:1.625rem; margin-inline-end:var(--sp-sm) }
.tk-line .task-sys-ic .fic{ width:1.125rem; height:1.125rem }
/* Сжатая строка обязана называть объект: три строки «שקעים» подряд из разных
   объектов были неразличимы (замечание владельца, заход 77). */
/* D-183 (заход 77). Строка «система неисправна» в форме создания задачи.
   Это не украшение формы, а переключатель правды об объекте, поэтому он ВИДЕН:
   рамка и своя заливка, а не голая галочка в ряду полей. Пояснение под ней —
   мелким и приглушённым: оно объясняет последствие, а не требует чтения. */
.tk-fault-row{ display:flex; align-items:flex-start; gap:var(--sp-md);
  margin-top:var(--sp-md); padding:var(--sp-md) var(--sp-lg);
  border:1px solid var(--fault-line); border-radius:var(--r-chip);
  background:var(--fault-plate); cursor:pointer }
.tk-fault-row input{ width:1.125rem; height:1.125rem; margin:.15rem 0 0; flex:none; accent-color:var(--fault-fg) }
.tk-fault-row span{ display:flex; flex-direction:column; gap:.1rem }
.tk-fault-row b{ font-size:var(--fs-label); color:var(--text) }
.tk-fault-row i{ font-style:normal; font-size:var(--fs-micro); color:var(--text-dim) }
.tk-fault-row.known{ cursor:default; color:var(--text-dim); font-size:var(--fs-label);
  align-items:center; gap:var(--sp-sm) }
/* D-185 (заход 77). Объект — не примечание в ряду фактов, а первое, что ищут
   глазами: «о каком מקלט речь». Поэтому плашка: свой фон, крупнее подписи, значок
   типа впереди. Подчёркивание убрано — на плашке оно лишний шум, а нажимаемость
   несут фон и курсор.
   ⚠️ Значок берётся по типу объекта: 18 из 121 — חניון, и домик на них врал. */
.tk-objchip{ display:inline-flex; align-items:center; gap:var(--sp-sm);
  padding:.15rem var(--sp-md); border-radius:var(--r-chip);
  background:var(--badge-blue-bg); color:var(--badge-blue-tx);
  font-size:var(--fs-label); font-weight:700; cursor:pointer; white-space:nowrap }
.tk-objchip .st-ic{ width:1.0625rem; height:1.0625rem; flex:none }
.tk-objchip:hover{ filter:brightness(1.06) }
.task-card.held .held-obj{ display:inline-flex; align-items:center;
  flex:none; margin-inline-end:auto }

/* D-179 (заход 77). Удержанная карточка в сжатом виде — одна строка вместо
   четверти экрана. Перечёркнутый заголовок читается как «сделано» без чтения слов.
   ⚠️ Строка кликабельна целиком (разворот), поэтому кнопка отмены внутри неё
      обязана гасить всплытие — иначе отмена сначала развернёт карточку. Это
      сделано в обработчике, здесь только вид. */
.task-card.held{
  display:flex; align-items:center; gap:var(--sp-lg);
  padding:var(--sp-md) var(--sp-lg); cursor:pointer;
  border-inline-start:3px solid var(--green); background:var(--green-soft);
}
.task-card.held.reopened{ border-inline-start-color:var(--action-primary); background:var(--badge-blue-bg) }
.task-card.held .held-tick{ color:var(--green); flex:none }
.task-card.held.reopened .held-tick{ color:var(--action-primary) }
.task-card.held .held-title{
  /* D-179 (правка, заход 77). Было flex:1 — заголовок распирал строку и уводил имя
     объекта в дальний край, где его никто не читает (замечание владельца). Теперь
     тянется не текст, а пустота ПОСЛЕ имени объекта: название задачи и объект
     стоят рядом, как одна мысль. */
  flex:0 1 auto; min-width:0; font-weight:600; text-decoration:line-through;
  color:var(--text-dim); overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.task-card.held .held-badge{ flex:none }
.task-card.held .held-undo{ flex:none }

.task-card.just-done{
  border-color:var(--border);
  border-inline-start:3px solid var(--green);
  background:var(--green-soft);
}
.dash-toast.has-act{ display:flex; align-items:center; gap:var(--sp-lg) }
.toast-act{
  background:transparent; border:1px solid currentColor; color:inherit;
  border-radius:var(--r-chip); padding:.2rem .6rem; font:inherit;
  font-weight:700; cursor:pointer; flex:none;
}
.toast-act:hover{ background:rgba(255,255,255,.14) }
.tk-tile.plan{border-style:dashed} .tk-tile.plan .tk-tile-n{color:var(--badge-plan-tx)}
.tk-segs{display:flex; flex-wrap:wrap; gap:var(--sp-sm); margin-bottom:.8rem}
/* Пять состояний в ряду (заход 62). Прежний flex:1 при переносе растягивал одинокую
   пятую кнопку на всю ширину строки — она читалась как отдельное действие, а не
   как продолжение ряда. Сетка auto-fit кладёт её в обычную колонку.
   Кнопка «новая задача» остаётся соседом по флексу и в сетку не попадает:
   иначе ярус A разрушился бы — главное действие сравнялось бы шириной с фильтром. */
.tk-seg-row{display:grid; grid-template-columns:repeat(auto-fit,minmax(5.25rem,1fr)); gap:var(--sp-sm); flex:1 1 16rem; min-width:0}
.tk-seg{flex:1; background:var(--surface2); border:1px solid var(--ctl-bd); color:var(--text-dim); border-radius:var(--r-chip); padding:.45rem; font-weight:700; font-size:var(--fs-label); font-family:inherit; cursor:pointer}
.tk-seg.on{background:var(--sel-bg); color:var(--sel-tx); border-color:var(--sel-bd)}
.tk-seg-new{display:inline-flex; align-items:center; justify-content:center; gap:var(--sp-sm); flex:0 0 auto; background:var(--action-primary); border:1px solid var(--action-primary); color:var(--action-primary-tx); border-radius:var(--r-chip); padding:.45rem .95rem; font-weight:700; font-size:var(--fs-label); font-family:inherit; cursor:pointer; white-space:nowrap; box-shadow:0 2px 8px color-mix(in srgb, var(--blue) 30%, transparent); transition:filter .15s}
.tk-seg-new:hover{filter:brightness(1.07)}
.tk-seg-new .eic{width:1em;height:1em}
.tk-genhint{display:flex; align-items:center; gap:var(--sp-md); background:var(--surface2); border:1px dashed var(--border); border-radius:var(--r-chip); padding:.7rem .8rem; color:var(--text-dim); font-size:var(--fs-label); line-height:1.45}
.tk-genhint .eic{flex:none; color:var(--blue)}
.tk-genobj{display:inline-flex; align-items:center; gap:var(--sp-xs); color:var(--text-dim)}
.tk-line.on{background:var(--surface2); border-radius:var(--r-chip); padding-inline:.4rem}
.plan-group{margin-bottom:1rem}
.plan-obj{display:flex; align-items:center; gap:var(--sp-md); font-weight:700; font-size:var(--fs-body); margin:.3rem 0 .5rem; padding-bottom:.3rem; border-bottom:1px solid var(--border)}
.plan-obj .n{background:var(--surface2); border-radius:var(--r-chip); padding:.05rem .45rem; font-size:var(--fs-label)}
.tk-planhead{background:var(--plan-plate-bg); border:1px dashed var(--plan-plate-bd); color:var(--text-dim); border-radius:var(--r-chip); padding:.55rem .7rem; font-size:var(--fs-label); margin-bottom:.8rem}
.b-plan{background:var(--badge-plan-bg); color:var(--badge-plan-tx)}
/* Окно редактора систем — 1080px, а строка несёт короткое название и три
   кнопки: слева оставалось до 860px пустоты, и так шестнадцать раз подряд.
   Строки ложатся в две колонки — то же решение, что в секции מערכות. Класс
   свой, чтобы не задеть окно ציוד, живущее на том же .ziud-modal-body. */
/* ⚠️ columns НЕЛЬЗЯ вешать на сам прокручиваемый контейнер. У .ziud-modal-body
   высота ограничена (flex:1; overflow:auto) — колонки заполняют высоту и текут
   ВПРАВО, давая горизонтальную полосу: половина систем уезжала за край, и чтобы
   отметить их, приходилось крутить вбок. Колонки живут на вложенной обёртке,
   прокручивает родитель — тогда они растут вниз. В паспорте (.pp-cols) так и
   было с самого начала, оттого там этой беды и не случилось. */
.sys-edit-cols{display:grid; grid-template-columns:repeat(auto-fill,minmax(min(100%,26rem),1fr)); gap:0 var(--sp-2xl); align-items:stretch}
/* Равная высота в ряду — то же решение, что в паспорте. Строка «בבדיקה: …» есть
   не у всех систем, и пары блоков в двух колонках расходились по высоте.
   При stretch разделительная линия под блоком встаёт на одной высоте у обоих:
   линии выстраиваются в сетку, а недостающая строка превращается в поле.
   Линия для глаза сильнее пустоты. */
.sys-edit-cols>.sys-edit-row{display:flex; flex-direction:column}
/* Кнопки состояния — главное действие окна. По содержимому они жались к краю,
   оставляя четверть колонки пустой; делят ширину поровну и заодно становятся
   крупнее — попасть легче. auto-fit, потому что кнопок бывает три или четыре
   (у оверрайда добавляется לפי בדיקה). */
.sys-edit-cols>.sys-edit-row>.seg{display:grid; grid-template-columns:repeat(auto-fit,minmax(0,1fr)); gap:var(--sp-sm)}
.sys-edit-row{padding:.65rem 0; border-bottom:1px solid var(--border)}
.sys-edit-row:last-child{border-bottom:none}
.who-inp{flex:1; min-width:110px}
.photos-stub{text-align:center; color:var(--text-dim); padding:1.5rem; border:1px dashed var(--border); border-radius:var(--r-ctl)}
#modalOverlay{display:none; position:fixed; inset:0; z-index:3000; background:var(--modal-scrim); align-items:center; justify-content:center; padding:1rem}
#modalOverlay.show{display:flex}
/* D-35: ширина окна следует содержимому там, где содержимое переменное.
   Форма задачи держит прежние 560px — ей эта ширина впору. Галерея получает
   .modal-fit: пустая («אין צילומים») сжимается до ~22rem вместо половины экрана,
   с миниатюрами растёт до 56rem и перестаёт ронять их в узкую колонку. */
#modalCard{background:var(--surface); border:1px solid var(--modal-bd); border-radius:var(--r-card); width:min(35rem,100%); max-height:85vh; overflow:auto; padding:1.3rem; box-shadow:var(--modal-shadow)}
#modalCard.modal-fit{width:fit-content; min-width:min(22rem,100%); max-width:min(56rem,100%)}
.modal-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-xl); margin-bottom:1rem}
.modal-head h3{font-size:var(--fs-lead); font-weight:700}
.modal-close{background:transparent; border:none; color:var(--text-dim); cursor:pointer; line-height:1; display:inline-flex; padding:.2rem}
.modal-close svg{width:20px; height:20px}
.modal-close:hover{color:var(--text)}
/* 🧰 ציוד — двухколоночный просмотр по категориям + модал редактирования */
.ziud-grid{column-count:2; column-gap:var(--sp-xl)}
@media(max-width:900px){ .ziud-grid{column-count:1} }
.ziud-cat{break-inside:avoid; -webkit-column-break-inside:avoid; margin-bottom:1rem}
.ziud-cat-h{font-weight:700; color:var(--blue); border-bottom:2px solid var(--border); padding-bottom:.3rem; margin-bottom:.35rem; display:flex; justify-content:space-between; align-items:center; gap:var(--sp-md)}
.ziud-cat-h .c{font-size:var(--fs-label); font-weight:600; color:var(--text-dim)}
.ziud-item{display:flex; gap:var(--sp-md); align-items:center; padding:.35rem 0; border-bottom:1px solid var(--border)}
.ziud-mov{display:none; position:fixed; inset:0; z-index:3200; background:var(--modal-scrim); align-items:center; justify-content:center; padding:1.5vh 1.5vw}
.ziud-mov.show{display:flex}
.ziud-modal{background:var(--surface); border:1px solid var(--modal-bd); border-radius:var(--r-card); width:min(1080px,97vw); height:min(94vh,960px); display:flex; flex-direction:column; overflow:hidden; box-shadow:var(--modal-shadow)}
.ziud-modal-head{display:flex; align-items:center; justify-content:space-between; gap:var(--sp-xl); padding:1rem 1.2rem; border-bottom:1px solid var(--border)}
.ziud-modal-head h3{font-size:var(--fs-lead); font-weight:700}
.ziud-modal-body{flex:1; overflow:auto; padding:1rem 1.2rem}
.ziud-modal-foot{display:flex; gap:var(--sp-md); align-items:center; padding:.85rem 1.2rem; border-top:1px solid var(--border); flex-wrap:wrap}
.ziud-erow{display:flex; gap:var(--sp-sm); align-items:center; flex-wrap:wrap; padding:.45rem 0; border-bottom:1px solid var(--border)}
.ziud-ecat{font-weight:700; color:var(--blue); margin:1rem 0 .3rem; border-bottom:2px solid var(--border); padding-bottom:.25rem}
/* app-confirm — центральное окно подтверждения в стиле приложения */
#confirmOverlay{display:none; position:fixed; inset:0; z-index:3400; background:var(--modal-scrim); align-items:center; justify-content:center; padding:1rem}
#confirmOverlay.show{display:flex}
.confirm-card{background:var(--surface); border:1px solid var(--modal-bd); border-radius:var(--r-panel); max-width:470px; width:100%; box-shadow:var(--modal-shadow); overflow:hidden; animation:cfIn .14s ease}
@keyframes cfIn{from{transform:translateY(8px) scale(.98); opacity:.4}to{transform:none; opacity:1}}
.confirm-head{font-size:var(--fs-h4); font-weight:700; padding:1.2rem 1.3rem .5rem}
.confirm-body{padding:0 1.3rem 1.1rem; color:var(--text); line-height:1.55; font-size:var(--fs-body)}
.confirm-flist{list-style:none; margin:.5rem 0 .9rem; padding:0; display:flex; flex-direction:column; gap:var(--sp-sm)}
.confirm-flist li{background:var(--danger-plate-bg); border:1px solid var(--danger-plate-bd); color:var(--text); border-radius:var(--r-chip); padding:.5rem .7rem; font-weight:600}
.confirm-foot{display:flex; gap:var(--sp-lg); padding:1rem 1.3rem; border-top:1px solid var(--border)}
.confirm-foot .btn{flex:1; justify-content:center; padding:.7rem; font-size:var(--fs-body)}
.btn.danger{background:var(--action-danger); color:var(--action-primary-tx); border-color:var(--action-danger)}
/* ── ניקוי נתוני בדיקה (v136) — виден только владельцу ── */
.rs-gate{width:min(400px,94vw); height:auto}
.rs-gate-t{font-size:var(--fs-body); font-weight:700; color:var(--text-dim); margin-bottom:.6rem}
.rs-gate .inp{width:100%; text-align:center; letter-spacing:.12em; font-size:var(--fs-lead)}
.rs-gate-err{margin-top:.5rem; color:var(--red); font-weight:600; font-size:var(--fs-label)}
.rs-gate-acts{display:flex; gap:var(--sp-md); margin-top:1rem}
.rs-gate-acts .btn{flex:1; justify-content:center}
.rs-modal{width:min(640px,97vw); height:auto; max-height:94vh}
.rs-warn{display:flex; align-items:center; gap:var(--sp-md); background:var(--danger-plate-bg); border:1px solid var(--danger-plate-bd); color:var(--text); border-radius:var(--r-chip); padding:.6rem .75rem; font-weight:600; font-size:var(--fs-label); margin-bottom:1rem}
.rs-warn .eic{flex:none; color:var(--red)}
.rs-sec-t{font-size:var(--fs-label); font-weight:700; color:var(--text-dim); margin:.9rem 0 .45rem}
.rs-cbs{display:flex; flex-direction:column; gap:var(--sp-sm)}
.rs-cb{display:flex; align-items:flex-start; gap:var(--sp-md); background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.6rem .75rem; cursor:pointer}
.rs-cb.on{border-color:var(--sel-bd)}
.rs-cb input{width:17px; height:17px; margin-top:.15rem; cursor:pointer; flex:none}
.rs-cb input:disabled{cursor:default; opacity:.4}
.rs-cb-t{display:flex; flex-direction:column; gap:var(--sp-2xs)}
.rs-cb-t b{font-size:var(--fs-body); font-weight:600}
.rs-cb-t i{font-style:normal; font-size:var(--fs-small); color:var(--text-dim)}
.rs-range{display:flex; gap:var(--sp-md); align-items:center; flex-wrap:wrap}
.rs-hint{margin-top:.45rem; font-size:var(--fs-label); color:var(--text-dim)}
.rs-dates{display:flex; gap:var(--sp-md); margin-top:.6rem; flex-wrap:wrap}
.rs-dates label{flex:1 1 150px; min-width:0; display:flex; flex-direction:column; gap:var(--sp-xs)}
.rs-dates label span{font-size:var(--fs-small); color:var(--text-dim); font-weight:600}
.rs-dates .inp{width:100%}
.rs-acts{margin-top:1rem}
.rs-plan{margin-top:1rem; background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-ctl); padding:.8rem .9rem}
.rs-plan-h{display:flex; align-items:center; gap:var(--sp-sm); font-weight:700; font-size:var(--fs-body); margin-bottom:.4rem}
.rs-plan-h.rs-del{color:var(--red)}
.rs-plan-h.rs-keep{color:var(--green); margin-top:.9rem}
.rs-line{display:flex; justify-content:space-between; align-items:center; padding:.28rem 0; border-bottom:1px solid var(--border); font-size:var(--fs-label)}
.rs-line:last-of-type{border-bottom:none}
.rs-line b{font-variant-numeric:tabular-nums; font-weight:600}
.rs-keeps{display:flex; flex-wrap:wrap; gap:var(--sp-xs)}
.rs-k{font-size:var(--fs-small); background:var(--tint-green); color:var(--green); border-radius:var(--r-chip); padding:.15rem .5rem; font-weight:600}
.rs-exec{display:flex; gap:var(--sp-md); align-items:center; flex-wrap:wrap; margin-top:.9rem}
.rs-pass{flex:1; min-width:130px}
.rs-prog{margin-top:.7rem; font-size:var(--fs-label); font-weight:600; color:var(--text-dim); min-height:1.2em}

/* ── דוח מערכת (v146): отчёт владельца + экран предохранителя ── */
#usageFuse{position:fixed; inset:0; z-index:9999; background:rgba(10,14,22,.92);
  display:flex; align-items:center; justify-content:center; padding:1.2rem}
.uf-box{background:var(--surface); border:1px solid var(--ctl-bd); border-radius:var(--r-ctl);
  padding:1.6rem 1.4rem; max-width:460px; text-align:center; box-shadow:0 18px 50px rgba(0,0,0,.35)}
.uf-ic{color:var(--red); line-height:0; margin-bottom:.6rem}
.uf-ic svg{width:46px; height:46px}
.uf-box h2{margin:.2rem 0 .7rem; font-size:var(--fs-h3)}
.uf-box p{margin:.4rem 0}
.uf-box .uf-sub{color:var(--text-dim); font-size:var(--fs-label)}
.uf-box button{margin-top:1rem; min-height:40px; padding:.5rem 1.1rem; border-radius:var(--r-chip);
  background:var(--blue); color:var(--action-primary-tx); border:0; font-weight:700; font-size:var(--fs-body); cursor:pointer; font-family:inherit}
.us-modal{width:min(520px,97vw); height:auto; max-height:94vh}
.us-tabs{margin-bottom:.8rem}
.us-gate{display:flex; flex-direction:column; gap:var(--sp-lg); align-items:stretch; padding:.5rem 0}
.us-gate p{font-weight:600}
.us-err{color:var(--red); font-weight:600; font-size:var(--fs-label)}
.us-card{background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-chip);
  padding:.8rem .9rem; margin-bottom:.7rem}
.us-card h4{margin:0 0 .5rem; font-size:var(--fs-label); color:var(--text-dim); display:flex; align-items:center; gap:var(--sp-sm)}
.us-sum{border-color:var(--blue)}
.us-role{background:var(--surface); border:1px solid var(--ctl-bd); border-radius:var(--r-pill);
  padding:.05rem .5rem; font-size:var(--fs-micro); font-weight:600; color:var(--text-dim)}
.us-row{display:flex; justify-content:space-between; align-items:center; padding:.28rem 0; font-size:var(--fs-body)}
.us-row b.warn{color:var(--orange)}
.us-row b.alarm{color:var(--red)}
.us-op{border-top:1px solid var(--border); padding-top:.45rem; margin-top:.45rem}
.us-op:first-of-type{border-top:0; margin-top:0}
.us-op-n{font-weight:700; margin-bottom:.15rem}
.us-sep{height:1px; background:var(--border); margin:.5rem 0}
.us-note{color:var(--text-dim); font-size:var(--fs-small); line-height:1.5}
.us-range{display:flex; gap:var(--sp-md); align-items:flex-end; flex-wrap:wrap; margin-bottom:.8rem}

/* ── טקסט מודגש (v138): контраст + вес приглушённого текста ── */
body.bold-ui{--text-dim:#c3ced9; --text-faint:#a3b0bd; --pp-empty:#c3ced9}
body.light.bold-ui{--text-dim:#334155; --text-faint:#475569; --pp-empty:#334155}
body.bold-ui .kpi-label,body.bold-ui .kpi-sub,body.bold-ui .oc-meta,body.bold-ui .fs-sub,
body.bold-ui .mk-head-status .lbl,body.bold-ui .kv .k,body.bold-ui .pp-cols .kv .k,
body.bold-ui .muted,body.bold-ui .sn-summary .muted,body.bold-ui .task-meta,body.bold-ui .trail-row,
body.bold-ui .fault-meta,body.bold-ui .field label,body.bold-ui .sys-state,body.bold-ui .clock-date,
body.bold-ui .tk-old .m,body.bold-ui .tk-stat .s span,body.bold-ui .sn-f,body.bold-ui .rs-cb-t i,
body.bold-ui .set-row,body.bold-ui .acc-sub,body.bold-ui .pp-num{font-weight:700}

/* ══════════ RESPONSIVE (v135) — desktop / tablet / phone ══════════ */
/* ≥1025px — десктоп: сплит «список | карта», переключатель не нужен */
@media(min-width:1025px){
  #mapPane{display:block!important}
  body.view-map #listPane,body.view-list #mapPane{display:block}
  .view-toggle{display:none}
}
/* ≤1024px — планшет: одна колонка + вкладки «список / карта» */
@media(max-width:1024px){
  header{grid-template-columns:auto 1fr}
  #clock{display:none}
  .header-right{justify-content:flex-end; flex-wrap:wrap}
  #layout{grid-template-columns:minmax(0,1fr)}
  .view-toggle{display:flex}
  /* один вертикальный скролл вместо двух зажатых колонок */
  .mk-layout{display:flex; flex-direction:column; overflow-y:auto; -webkit-overflow-scrolling:touch; padding:.75rem}
  .mk-right{overflow:visible; min-height:auto; padding-bottom:0}
  .mk-left{flex:none; min-height:auto}
  #mkMap{flex:none; height:280px; min-height:280px}
  .mk-head-title{flex:1 1 auto; min-width:0}
  .mk-head-status{margin-inline-start:0; padding-inline-start:0; border:none; width:100%}
}
/* ≤760px — телефон */
@media(max-width:760px){
  /* На телефоне колонок нет: ширины отпускаем, разделитель убираем —
     иначе строка заголовка секции не помещается и уезжает за край. */
  .acc-head h3{width:auto; max-width:none}
  .acc-sub{width:auto; min-width:0; border-inline-start:0; padding-inline-start:0}
  .kpi-bar{grid-template-columns:repeat(2,minmax(0,1fr)); gap:var(--sp-md); padding:10px 12px}
  .mk-head-status{white-space:normal}
  .kpi{padding:11px 12px}
  .kpi-num{font-size:var(--fs-display)}
  .kmed{width:29px; height:29px; border-radius:8px}
  .kmed svg{width:16px; height:16px}
  .toolbar{padding:0 .75rem .55rem; gap:var(--sp-sm)}
  .search-wrap{flex:1 1 100%; min-width:0; order:-1}
  .toolbar .dd-btn.filter-sel{flex:1 1 40%; min-width:0}   /* было select.filter-sel — два фильтра стали кнопками.
     Селектор сужен до .toolbar намеренно: те же кнопки есть в סינון, и там своя раскладка */
  .cycle-bar{margin-inline-start:0; width:100%; justify-content:space-between; white-space:normal}
  .toolbar{min-width:0}
  .obj-card{padding:.8rem .85rem}
  .view-toggle{margin-inline-start:0; flex:1 1 100%}
  .vt-btn{flex:1}
  #layout{padding:0 .75rem .75rem}
  .icon-btn .btxt{display:none}
  .icon-btn{padding:.45rem .6rem}
  .fs-scroll{padding:.75rem}
  .fs-head{padding:.6rem .75rem; gap:var(--sp-md)}
  .mk-head{gap:var(--sp-lg); padding:.7rem .8rem}
  .sect{padding:.85rem .9rem}
  .kv{grid-template-columns:108px 1fr; gap:var(--sp-md)}
  .pp-cols{--pp-pad:.7rem; gap:var(--sp-lg)}
  .sn-bar,.sn-filters{padding-inline:.75rem}
  .sn-summary,.sn-pivot{padding-inline:.75rem}
  .sn-settings{margin-inline:.75rem}
  .sn-set-grp{min-width:130px}
  .tk-reassign{max-width:none}
  .set-pop{padding:.5rem}
  .set-body{padding:.6rem}
  /* большие модалы — на весь экран */
  .ziud-mov{padding:0}
  .ziud-modal{width:100vw; height:100vh; height:100dvh; max-height:none; border-radius:0; border:none}
  #modalOverlay{padding:.6rem}
  /* тач-таргеты ≥44px */
  .icon-btn,.filter-sel,.vt-btn,.back-btn,.sn-chip,.sn-gear,.sn-reset,.sn-export,.hist-tabs button,.dd-item{min-height:44px}
}
/* ≤430px — узкий телефон */
@media(max-width:430px){
  /* Телефон: до списка уходило ~63% экрана, треть — блок KPI 2x2. Складываем
     4 плитки в один ряд (иконка над числом), третью строку (102 מקלטים · 18
     חניונים) прячем — общая сумма и так стоит в סה״כ. Список получает ~60%
     вместо 40%. Планшет 431–760px не тронут — там ширины на 2x2 хватает.
     Всё внутри @media: раскладка, обработчики и данные не трогаются. */
  .kpi-bar{grid-template-columns:repeat(4,minmax(0,1fr)); gap:var(--sp-sm); padding:8px 10px}
  .kpi{flex-direction:column; align-items:center; text-align:center; gap:var(--sp-xs); padding:8px 4px}
  .kpi-txt{display:flex; flex-direction:column; align-items:center; gap:0; min-width:0; flex:none}
  .kpi-sub{display:none}
  /* order:-1 снят в заходе 68: иконка стоит первой уже в разметке, правило стало мёртвым. */
  /* Телефон: значок занимает свою строку целиком. Инлайн он туда не встаёт —
     измерено: значок 20 + число ~36 + слово ~35 = ~99px при ширине плитки ~81px,
     и строка порвалась бы. Своя строка = ровно то, что было до этой правки,
     высота не меняется. */
  .kpi-numline .kmed{flex:0 0 100%}
  .kmed{width:28px; height:28px; border-radius:8px}
  .kmed svg{width:16px; height:16px}
  .kpi-num{font-size:var(--fs-h3); line-height:1.05}
  .kpi-label{font-size:var(--fs-micro); line-height:1.15; text-align:center}
  .vt-btn{min-height:38px}
  .brand{font-size:var(--fs-label)}
  .mk-head .fs-title{font-size:var(--fs-h4)}
  .kv{grid-template-columns:1fr; gap:var(--sp-2xs)}
  .kv .k{font-size:var(--fs-small)}
}

/* ── ניהול עובדים (v162) — редактор сотрудников. Виден только владельцу, под паролем ── */
.st-gate{width:min(400px,94vw); height:auto}
.st-gate-t{font-size:var(--fs-body); font-weight:700; color:var(--text-dim); margin-bottom:.6rem}
.st-gate .inp{width:100%; text-align:center; letter-spacing:.12em; font-size:var(--fs-lead)}
.st-gate-err{margin-top:.5rem; color:var(--red); font-weight:600; font-size:var(--fs-label)}
.st-gate-acts{display:flex; gap:var(--sp-md); margin-top:1rem}
.st-gate-acts .btn{flex:1; justify-content:center}
.st-modal{width:min(760px,97vw); height:auto; max-height:94vh}
.st-warn{display:flex; align-items:flex-start; gap:var(--sp-md); background:var(--tint-green); border:1px solid var(--ctl-bd);
  border-radius:var(--r-chip); padding:.6rem .75rem; font-size:var(--fs-label); line-height:1.5; margin-bottom:1rem}
.st-warn .eic{flex:none; color:var(--green); margin-top:.15rem}
.st-card{background:var(--surface2); border:1px solid var(--ctl-bd); border-radius:var(--r-ctl); padding:.75rem .85rem; margin-bottom:.7rem}
.st-card.off{opacity:.62; border-style:dashed}
.st-card.new{border-color:var(--blue)}
.st-top{display:flex; align-items:center; gap:var(--sp-md); flex-wrap:wrap; margin-bottom:.55rem}
.st-id{direction:ltr; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:var(--fs-small); font-weight:600;
  background:var(--surface); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.15rem .5rem; color:var(--text-dim)}
.st-idin{direction:ltr; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; width:170px; min-height:32px; padding:.25rem .5rem; font-size:var(--fs-label)}
.st-lock{font-style:normal; font-size:var(--fs-small); font-weight:600; color:var(--text-dim); display:inline-flex; align-items:center; gap:var(--sp-xs)}
.st-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(160px,100%),1fr)); gap:var(--sp-md)}
.st-grid label{display:flex; flex-direction:column; gap:var(--sp-xs); min-width:0}
.st-grid label span{font-size:var(--fs-micro); font-weight:600; color:var(--text-dim)}
.st-grid .inp{width:100%; min-height:36px}
.st-flags{display:flex; flex-wrap:wrap; gap:var(--sp-md); margin-top:.6rem}
.st-cb{display:inline-flex; align-items:center; gap:var(--sp-sm); background:var(--surface); border:1px solid var(--ctl-bd);
  border-radius:var(--r-chip); padding:.35rem .6rem; cursor:pointer; font-size:var(--fs-label); font-weight:400}
.st-cb input{width:16px; height:16px; cursor:pointer; flex:none}
.st-cb input:disabled{cursor:default; opacity:.4}
.st-alias{display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-xs); margin-top:.55rem; font-size:var(--fs-small); color:var(--text-dim)}
.st-alias b{background:var(--surface); border:1px solid var(--ctl-bd); border-radius:var(--r-chip); padding:.1rem .45rem; font-weight:600; color:var(--text)}
.st-msg{font-size:var(--fs-label); font-weight:600; color:var(--text-dim)}
.st-msg.ok{color:var(--green)}
.st-msg.bad{color:var(--red)}
/* v163 — подсказка под флагом (מפעיל ≠ עובד שטח: развели два смысла) */
.st-cb{align-items:flex-start}
.st-cb span{display:flex; flex-direction:column; gap:var(--sp-2xs); line-height:1.3}
.st-cb span i{font-style:normal; font-size:var(--fs-micro); font-weight:600; color:var(--text-dim)}
.st-cb.dis{opacity:.45; cursor:default}

/* v163 — переверстка карточки сотрудника: имя+id сверху, поля, две группы флагов */
.st-card{padding:.85rem .95rem}
.st-top{display:flex; align-items:flex-end; gap:var(--sp-lg); flex-wrap:wrap; margin-bottom:.65rem}
.st-nm{flex:1 1 220px; min-width:0; display:flex; flex-direction:column; gap:var(--sp-xs)}
.st-nm span{font-size:var(--fs-micro); font-weight:600; color:var(--text-dim)}
.st-nm .inp{width:100%; min-height:40px; font-weight:700; font-size:var(--fs-body)}
.st-idbox{display:flex; align-items:center; gap:var(--sp-md); flex-wrap:wrap; padding-bottom:.35rem}
.st-tag{font-style:normal; font-size:var(--fs-micro); font-weight:600; display:inline-flex; align-items:center; gap:var(--sp-xs);
  border-radius:var(--r-chip); padding:.12rem .45rem}
.st-tag.own{background:var(--tint-blue); color:var(--tag-own-tx)}   /* 2.0:1 -> 5.7:1 на яркой шапке */
.st-tag.off{background:var(--tint-red); color:var(--red)}
.st-rm{background:transparent; border:1px solid var(--ctl-bd); color:var(--red); border-radius:var(--r-chip);
  padding:.2rem .4rem; cursor:pointer; display:inline-flex; align-items:center; line-height:1}
.st-rm:hover{background:var(--tint-red); border-color:var(--red)}
.st-sec{margin-top:.6rem}
.st-sec-t{font-size:var(--fs-micro); font-weight:600; color:var(--text-dim); letter-spacing:.02em; margin-bottom:.3rem}
.st-flags{display:grid; grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr)); gap:var(--sp-md); align-items:stretch}
.st-cb{display:flex; align-items:flex-start; gap:var(--sp-md); background:var(--surface); border:1px solid var(--ctl-bd);
  border-radius:var(--r-chip); padding:.45rem .55rem; cursor:pointer; min-width:0}
.st-cb input{margin-top:.15rem}
.st-cb span{display:flex; flex-direction:column; gap:var(--sp-2xs); min-width:0; line-height:1.25}
.st-cb span b{font-size:var(--fs-label); font-weight:600}
.st-cb span i{font-style:normal; font-size:var(--fs-micro); font-weight:600; color:var(--text-dim)}
.st-cb:has(input:checked){border-color:var(--blue); background:var(--tint-blue)}
.st-cb.dis{opacity:.4; cursor:default; background:var(--surface2)}
.st-sum{display:flex; align-items:center; gap:var(--sp-xs); flex-wrap:wrap; font-size:var(--fs-label); color:var(--text-dim);
  margin:0 0 .7rem; padding-bottom:.5rem; border-bottom:1px solid var(--border)}
.st-sum b{color:var(--text); font-weight:600; font-variant-numeric:tabular-nums}
.st-sum span{opacity:.5}
.st-alias{margin-top:.6rem; padding-top:.5rem; border-top:1px dashed var(--border)}

/* v165 — карточка сотрудника: имя-шапкой (искать глазами при прокрутке) и честный замок владельца */
.st-card{position:relative; overflow:hidden; padding-inline-start:1.1rem}
.st-card::before{content:''; position:absolute; inset-inline-start:0; top:0; bottom:0; width:4px; background:var(--blue)}
.st-card.off::before{background:var(--text-dim)}
.st-card.new::before{background:var(--green)}
.st-top{align-items:center; background:var(--st-head); border:1px solid var(--ctl-bd);
  border-radius:var(--r-chip); padding:.45rem .6rem; margin:0 0 .75rem}
.st-card.off .st-top{background:var(--surface2)}
.st-card.new .st-top{background:var(--tint-green)}
.st-nm{gap:0}
.st-nm > span{display:none}                 /* подпись лишняя: шапка и есть имя */
.st-nm .inp{background:var(--inp-bg); font-size:var(--fs-lead); font-weight:700; min-height:38px}
.st-idbox{padding-bottom:0}
/* Порядковый номер карточки. ПОЗИЦИЯ в списке, а не личность: список сортируется
   по флагам (операторы -> полевые -> уволенные), поэтому номер за человеком не закреплён.
   Настоящий постоянный идентификатор — id (w_alexey) в шапке рядом. */
.st-num{flex:none; font-style:normal; font-size:var(--fs-small); font-weight:700; line-height:1;
  min-width:1.7rem; height:1.7rem; display:inline-flex; align-items:center; justify-content:center;
  border-radius:var(--r-circle); background:var(--st-num-bg); border:1px solid transparent; color:var(--st-num-tx);
  font-variant-numeric:tabular-nums; direction:ltr; user-select:none}
/* Цвет кружка повторяет полосу слева: синий — работает, серый — уволен, зелёный — не сохранён. */
.st-card.off .st-num{background:var(--status-pending)}
.st-card.new .st-num{background:var(--status-ok)}

/* Замок владельца: флаг НЕ выключен, он неизменяем. При 40% прозрачности галочка читалась как снятая. */
.st-cb.dis{opacity:.55}
.st-cb.dis:has(input:checked){opacity:.9; border-color:var(--blue); background:var(--tint-blue)}
.st-cb.dis:has(input:checked) span b{color:var(--text)}

/* ============================================================
   A-0 · состояния интерактивных элементов (заход 51)
   Канон, раздел "Состояния": пять состояний обязательны, ни одно
   не необязательно. В дашборде не было НИ ОДНОГО :active (D-08) и
   ни одного :focus-visible в обоих приложениях (D-07).

   Кольцо фокуса стоит в конце файла нарочно: поля ввода тушат
   контур строкой outline:none, и правило-победитель определяется
   порядком. Контраст кольца: 6.9:1 на карточке тёмной темы,
   5.4:1 на фоне светлой — порог для неткстовых элементов 3:1.
   ============================================================ */
button:active:not(:disabled),
.icon-btn:active,
.acc-edit:active{ filter:brightness(.92) }

button:focus-visible,
a:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible{
  outline:2px solid var(--focus-ring);
  outline-offset:2px;
}

/* ============================================================
   A-1.1 · панель הגדרות по канону (заход 51)

   Одиннадцать инлайновых min-height:34px и 30px убраны из разметки.
   Инлайн сильнее правила из файла: правило доступности (44px ниже
   760px) выглядело живым и не действовало ни разу (D-15).

   ⚠️ Мобильное переопределение обязано стоять ЗДЕСЬ. Селектор
   .set-row .icon-btn весит (0,2,0), а прежний медиазапрос — (0,1,0);
   без строки внизу телефон остался бы на 36px, то есть тот же самый
   дефект, только классом вместо инлайна.
   ============================================================ */
.set-row .icon-btn{ min-height:2.25rem; padding:.35rem .6rem }

/* Третий ярус действий. Канон, Закон 3: отмена, закрытие, возврат и
   деструктивное — всегда третий ярус. До сих пор во всём дашборде
   тихая кнопка существовала ровно одна, .vt-btn (D-16). */
.act-quiet{
  background:none; border:none; box-shadow:none; border-radius:var(--r-chip);
  color:var(--text-dim); font-family:inherit; font-size:var(--fs-label); font-weight:600;
  min-height:2.25rem; padding:.35rem .55rem; cursor:pointer;
  display:inline-flex; align-items:center; gap:var(--sp-sm);
}
.act-quiet:hover{ color:var(--text) }

/* Деструктивное действие — третий ярус ПЛЮС красный текст, не заливка.
   Свой токен обязателен: заливочный --action-danger в роли текста даёт
   4.04:1 на фоне окна тёмной темы при пороге 4.5:1 для текста.
   Текстовый оттенок — 5.5:1 в тёмной, 6.47:1 в светлой. */
.act-quiet.act-danger{ color:var(--action-danger-tx) }
.act-quiet.act-danger:hover{ filter:brightness(1.12) }

/* Заголовок группы настроек — был написан инлайном трижды (долг захода 50).
   opacity:.55 заменена явным цветом: прозрачность мешает текст с фоном и
   роняет контраст непредсказуемо, а --text-faint на фоне окна даёт 3.31:1
   при пороге 4.5:1. --text-dim даёт 6.21:1. */
/* Заголовок темы. Был служебной подписью в углу и терялся между строками;
   теперь это шапка карточки: своя подложка, свой цвет текста, отбивка снизу.
   Токены выделенные (--grp-head-bg / --grp-head-tx), а не глобальные:
   --surface2 и --text-dim работают в полусотне других мест. */
.set-grp-h{
  font-size:var(--fs-label); font-weight:700; color:var(--grp-head-tx);
  background:var(--grp-head-bg); border-bottom:1px solid var(--border);
  margin:0 -.9rem .35rem; padding:.5rem .9rem; border-radius:var(--r-ctl) var(--r-ctl) 0 0;
}
/* Метка «эту строку видит только владелец». Не замок: замок означает пароль,
   а это про видимость. Два разных факта — два разных знака. */
.sr-own{font-size:var(--fs-micro); font-weight:600; color:var(--text-dim);
  border:1px solid var(--border); border-radius:var(--r-chip); padding:0 .35rem; white-space:nowrap}
.set-head #verBadge{margin-inline-start:.2rem}

@media(max-width:760px){
  .set-row .icon-btn, .set-row .act-quiet{ min-height:2.75rem }
}

/* Значок внутри тихой кнопки несёт тот же смысл, что и её слово, и обязан
   быть того же цвета. Правило .ti-ic прибивает цвет всем значкам панели,
   поэтому у красной надписи корзина оставалась серой (осмотр захода 51). */
.act-quiet .ti-ic{ color:inherit }

/* Внутри выбранной плитки подпись и число принадлежат выбранному состоянию.
   Без этой строки .tk-stat .s span сохранял --text-dim и на подсветке
   выглядел выключенным, хотя элемент выбран. */
.tk-stat .s.on span{ color:inherit }
.tk-tile.on .lbl{ color:inherit }

/* ============================================================
   D-10 (заход 77). ДВИЖЕНИЕ ПО СОГЛАСИЮ. Дашборд держит 13 переходов и три
   анимации (pulse, setPopIn, cfIn), но системную настройку «меньше движения»
   не спрашивал вовсе — в полевом такой блок стоял с v51, в дашборде его не было.
   Для части людей движение на экране — не украшение, а тошнота и головная боль.
   Гасим длительности, а не сами свойства: `transition:none` у соседей ломало бы
   каскад, а нулевая длительность оставляет конечное состояние на месте.
   ⚠️ pulse — бесконечная пульсация тенью у маркера неисправности. Без анимации
      маркер остаётся своего цвета и на своём месте: сигнал несёт цвет, движение
      было усилением. Проверять после правки именно это — что маркер виден.
   ============================================================ */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    transition-duration:.01ms!important;
    animation-duration:.01ms!important;
    animation-iteration-count:1!important;
    scroll-behavior:auto!important;
  }
}
