:root{
  --bg:#eceef3; --bg-grad-1:#e9ebf1; --bg-grad-2:#eef0f5;
  /* Плотнее молочная вуаль поверх текстуры: прожилки читались как узор
     позади текста и спорили с содержимым. Мрамор остаётся узнаваемым. */
  --page-bg:linear-gradient(rgba(247,248,250,.62),rgba(242,244,247,.70)),url("/brand/marble-light.jpg");
  --surface:#ffffff; --surface-2:#f5f7fa; --surface-3:#eef1f6;
  /* Второстепенные цвета подобраны по контрасту, а не на глаз: прежние давали
   3.81 и 2.29 к светлым подложкам при норме 4.5, а именно ими набрано почти всё
   мелкое — подписи полей, время, счётчики. Оттенок сохранён, изменена светлота.

   Второй заход. Замер показал, что и подобранные значения не дотягивают:
   #666e7e давал 4.42, #676e7d — 4.41 при норме 4.5. Подводила подложка: считали
   к белому, а текст лежит на панели rgb(236,238,243), и на ней контраст ниже.
   Этим цветом набрано около 40 % текста экрана.

   Стало: muted 5.14, faint 4.76. Заодно они теперь и правда различаются —
   прежние отличались на единицу яркости и были одним цветом под двумя именами. */
--text:#191c26; --text-2:#3b4150; --muted:#5c6472; --faint:#616978;
  --border:#e5e8ef; --border-2:#dfe3ea;
  --accent:#4f6bff; --accent-2:#6b78e6; --accent-soft:rgba(79,107,255,.10); --accent-ink:#3644b8;
  --bronze:#b98a3e; --bronze-soft:rgba(185,138,62,.12);
  /* У каждого смыслового цвета две роли, и их нельзя путать.
     Заливка, точка, полоса — берут насыщенный тон: он и должен быть заметным.
     БУКВЫ берут тёмную пару (-ink). Замер контраста показал, что насыщенные
     тона как текст проваливаются все: красный 3.56, зелёный 3.30, оранжевый
     2.56, синий 3.87 при норме 4.5 — а красным набрана просрочка, то есть
     самый важный сигнал на экране оказался самым нечитаемым.
     Пары подобраны к собственной подложке плашки, не к белому. */
  --good:#16a34a; --good-soft:rgba(22,163,74,.12); --good-ink:#0f7038;
  --warn:#e0902b; --warn-soft:rgba(224,144,43,.14); --warn-ink:#8a5410;
  --bad:#dc5f6e; --bad-soft:rgba(220,95,110,.13); --bad-ink:#b52738;
  --info:#2f80ed; --info-soft:rgba(47,128,237,.12); --info-ink:#1a55a8;
  --sidebar:rgba(255,255,255,.44); --topbar:rgba(245,246,249,.40);
  --shadow-sm:0 1px 2px rgba(20,25,50,.05),0 1px 3px rgba(20,25,50,.04);
  --shadow:0 4px 16px -6px rgba(24,30,60,.14),0 2px 6px -2px rgba(24,30,60,.08);
  --shadow-lg:0 24px 60px -20px rgba(24,30,60,.28),0 8px 24px -12px rgba(24,30,60,.16);
  --chart-grid:rgba(20,25,50,.07); --tooltip-bg:rgba(22,25,38,.96);
  --ring:rgba(76,91,212,.35);
  --r:14px; --r-sm:10px; --r-lg:20px;
}
[data-theme="dark"]{
  --bg:#0b0d14; --bg-grad-1:#0a0c12; --bg-grad-2:#0e1119;
  --page-bg:linear-gradient(rgba(9,11,17,.58),rgba(9,11,17,.70)),url("/brand/marble-dark.jpg");
  --surface:#151824; --surface-2:#1a1e2c; --surface-3:#20263a;
  --text:#e9ebf2; --text-2:#c3c8d6; --muted:#949bad; --faint:#838aa3;
  --border:rgba(255,255,255,.075); --border-2:rgba(255,255,255,.11);
  --accent:#6e82ff; --accent-2:#9aa2ec; --accent-soft:rgba(110,130,255,.16); --accent-ink:#aeb5f2;
  --bronze:#cba35d; --bronze-soft:rgba(203,163,93,.16);
  /* На тёмном подложка чёрная, поэтому пара для букв здесь СВЕТЛЕЕ основного
     тона, а не темнее. Без этих строк переменная не определена и текст
     пропадает совсем. */
  --good:#3ecf7a; --good-soft:rgba(62,207,122,.15); --good-ink:#7ce0a5;
  --warn:#eab24e; --warn-soft:rgba(234,178,78,.16); --warn-ink:#f3ca86;
  --bad:#e97b89; --bad-soft:rgba(233,123,137,.16); --bad-ink:#f5a6b0;
  --info:#5aa0ff; --info-soft:rgba(90,160,255,.16); --info-ink:#95c1ff;
  --sidebar:rgba(13,16,25,.60); --topbar:rgba(11,13,20,.40);
  --shadow-sm:0 1px 2px rgba(0,0,0,.3);
  --shadow:0 8px 24px -10px rgba(0,0,0,.55),0 2px 8px -3px rgba(0,0,0,.4);
  --shadow-lg:0 30px 70px -24px rgba(0,0,0,.7),0 10px 30px -14px rgba(0,0,0,.5);
  --chart-grid:rgba(255,255,255,.07); --tooltip-bg:rgba(6,8,14,.96);
  --ring:rgba(124,134,223,.45);
}
/* Направление Design: тёмное меню слева, светлое рабочее поле справа.
 *
 * Раньше тёмным было всё, и читать длинные тексты на почти чёрном фоне было
 * тяжело — именно с этого начался этот пересмотр. Тёмный интерфейс хорош для
 * витрины, но здесь люди работают весь день: сравнивают суммы, читают
 * переписку, вычитывают комментарии. Для чтения светлый фон с тёмным текстом
 * даёт больший контраст при меньшей усталости.
 *
 * Меню оставлено тёмным намеренно: оно держит фирменный вид направления и
 * заодно отделяет навигацию от содержимого — взгляд не путает их между собой.
 *
 * Золото осталось акцентом, но для светлого фона потемнело: фирменный #b58a49
 * на кремовом даёт около 2.5:1 и для текста не годится. Заливки кнопок и
 * текстовые акценты теперь разные оттенки — это не небрежность, а требование
 * читаемости. */
.department-design{
  --bg:#f2ece1;--bg-grad-1:#f6f1e8;--bg-grad-2:#eae2d4;
  --page-bg:linear-gradient(rgba(247,243,235,.86),rgba(238,231,219,.92)),url("/brand/marble-light.jpg");
  --surface:#fffdf8;--surface-2:#f7f2e8;--surface-3:#ece4d5;
  /* Оттенки подобраны по контрасту, а не на глаз: --faint встречается и на
     панели, и прямо на фоне страницы, и проходить порог 4.5:1 должен в обоих
     случаях. #7c7264 давал на фоне 4.0 и не проходил. */
  --text:#241f18;--text-2:#443c30;--muted:#6a6053;--faint:#726858;
  --border:rgba(58,46,30,.14);--border-2:rgba(58,46,30,.24);
  --accent:#8a6526;--accent-2:#a87c33;--accent-soft:rgba(138,101,38,.13);--accent-ink:#6d4f16;
  --bronze:#8a6526;--bronze-soft:rgba(138,101,38,.14);
  --sidebar:rgba(8,10,11,.93);--topbar:rgba(10,12,13,.88);
  --shadow-sm:0 1px 3px rgba(60,45,25,.10);--shadow:0 10px 26px -14px rgba(60,45,25,.34);--shadow-lg:0 28px 60px -26px rgba(60,45,25,.42);
  --chart-grid:rgba(58,46,30,.10);--tooltip-bg:rgba(32,26,18,.96);--ring:rgba(138,101,38,.34);
}
/* Внутри меню и верхней полосы переменные возвращаются к тёмным значениям.
   Так и они, и содержимое пользуются одними и теми же правилами (.nav-item,
   .side-user, поля поиска), но каждое получает свой набор цветов — вместо
   десятка отдельных правил с переопределением цвета у каждого элемента.

   Тёмная рамка сверху и слева, светлое поле в середине: рабочая область
   отделена от навигации не линией, а тоном. */
.department-design .sidebar,.department-design .topbar{
  --surface:#141718;--surface-2:rgba(255,255,255,.07);--surface-3:rgba(255,255,255,.11);
  --text:#f0ede6;--text-2:#cfcabf;--muted:#9c968c;--faint:#8f8a80;
  --border:rgba(255,255,255,.09);--border-2:rgba(255,255,255,.16);
  --accent-soft:rgba(201,155,85,.18);--accent-ink:#e3bd7d;
  background-image:linear-gradient(rgba(8,10,11,.90),rgba(8,10,11,.95)),url("/brand/marble-dark.jpg");background-size:cover;background-position:center;
  color:var(--text);
}
.department-design .brand-gem{color:#d2a052}.department-design .panel,.department-design .design-panel{box-shadow:0 10px 30px -20px rgba(60,45,25,.38)}
.department-design .design-order-art{background:linear-gradient(145deg,#efe7d8,#dcd1bd)}
.design-product-cell{display:flex;align-items:center;gap:9px;min-width:220px}.design-product-thumb{width:48px;height:44px;border-radius:8px;overflow:hidden;flex:none;border:1px solid var(--border);background:var(--surface-3)}.design-product-thumb svg{width:100%;height:100%;display:block}
*{box-sizing:border-box}
/* Текст рисуется теми размерами, под которые меряна раскладка.
   На Андроиде WebView увеличивает его сам — системной настройкой размера
   шрифта и собственным автоувеличением. Ширины здесь в пикселях: текст растёт,
   коробки нет, и подписи садятся на рамки, а имена обрезаются там, где на
   другом устройстве помещаются с запасом.
   Увеличение щипком это не отменяет — оно масштабирует страницу целиком,
   вместе с коробками, и ничего не ломает. */
html{-webkit-text-size-adjust:100%;text-size-adjust:100%}
html,body{margin:0;padding:0}
body{
  font-family:'Inter',system-ui,-apple-system,Segoe UI,Roboto,sans-serif;
  color:var(--text); background:var(--bg);
  background-image:var(--page-bg);
  background-size:cover; background-position:center; background-attachment:fixed;
  -webkit-font-smoothing:antialiased; font-size:14px; line-height:1.5;
  transition:background-color .4s ease,color .3s ease;
}
h1,h2,h3,h4{font-family:'Manrope',sans-serif; margin:0; letter-spacing:-.01em; color:var(--text)}
/* Моноширинный подключался третьим семейством ради одного — чтобы цифры в
   столбце сумм стояли друг под другом. Это умеет и Inter: tabular-nums делает
   все цифры одной ширины. Семейство убрано, выравнивание осталось, из загрузки
   ушёл целый шрифт. */
.mono{font-variant-numeric:tabular-nums}
.num{font-variant-numeric:tabular-nums}
::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:var(--border-2);border-radius:20px;border:2px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:var(--muted);background-clip:content-box}
::selection{background:var(--accent-soft)}
a{color:inherit;text-decoration:none}
button{font-family:inherit;cursor:pointer}
/* Пункты выпадающих списков браузер рисует системным шрифтом: три десятка узлов
   на экране оказывались набраны Arial и выглядели чужими. */
select,option,input,textarea{font-family:inherit}
.muted{color:var(--muted)} .accent{color:var(--accent-ink)} .bronze{color:var(--bronze)}

/* ---------- Layout ---------- */
#app{display:grid; grid-template-columns:250px 1fr; min-height:100vh}
.sidebar{
  position:sticky; top:0; height:100vh; display:flex; flex-direction:column;
  background:var(--sidebar); backdrop-filter:blur(2px) saturate(120%); -webkit-backdrop-filter:blur(2px) saturate(120%);
  border-right:1px solid var(--border); z-index:40; transition:transform .3s ease;
}
.brand{display:flex; align-items:center; gap:12px; padding:14px 12px 12px}
.brand-tagline{font-size:12px;font-weight:600;color:var(--muted);letter-spacing:.03em;padding-left:2px}
.brand-gem{width:46px;height:46px;color:#C99A46;flex:none;filter:drop-shadow(0 1px 3px rgba(160,120,40,.25))}
.brand-mark{
  width:40px;height:40px;border-radius:12px;display:grid;place-items:center;flex:none;
  background:linear-gradient(145deg,var(--accent),var(--accent-2)); color:#fff;
  box-shadow:0 6px 16px -4px var(--ring); position:relative;
}
.brand-mark svg{width:22px;height:22px}
.brand-mark::after{content:"";position:absolute;inset:0;border-radius:12px;border:1px solid rgba(255,255,255,.25)}
/* Логотип направления целиком. Надпись у него внутри картинки, поэтому он
   заменяет собой и знак, и текстовое название — иначе имя стояло бы дважды. */
/* Исходник 1536×1024 с прозрачностью, знак занимает 971×845 — вокруг него
   прозрачные поля. Нижнее поле вдвое больше верхнего, поэтому знак садится
   выше центра; отрицательный нижний отступ съедает эту пустоту, иначе под
   логотипом зияет дыра шире, чем сам отступ панели.

   Свечение делает drop-shadow, а не box-shadow: первый повторяет форму по
   альфа-каналу, второй нарисовал бы прямоугольник вокруг прозрачных полей.
   Два слоя — ближний даёт плотность, дальний ореол; оба в синем самого знака,
   поэтому на тёмном мраморе логотип выглядит светящимся, а не наклеенным. */
.brand-full{width:100%;max-width:206px;height:auto;display:block;margin:0 auto -18px;
  filter:drop-shadow(0 1px 6px rgba(1,156,229,.34)) drop-shadow(0 0 22px rgba(1,156,229,.18))}
.department-design .brand{padding:16px 12px 14px;border-bottom:1px solid rgba(255,255,255,.07)}
.brand-text b{font-family:'Manrope';font-weight:700;font-size:18px;display:block;letter-spacing:-.02em}
.brand-text span{font-size:12px;color:var(--muted);letter-spacing:.02em}
.nav{flex:1; overflow-y:auto; padding:6px 12px 20px}
.nav-group{font-size:12px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--faint);padding:16px 12px 7px}
.nav-item{
  display:flex; align-items:center; gap:11px; padding:9px 12px; border-radius:10px;
  color:var(--text-2); font-weight:400; font-size:14px; margin-bottom:2px; position:relative;
  transition:background .16s,color .16s; user-select:none;
}
.nav-item svg{width:18px;height:18px;flex:none;opacity:.85}
.nav-item:hover{background:var(--surface-2);color:var(--text)}
.nav-item.active{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}
.nav-item.active svg{opacity:1}
.nav-item.active::before{content:"";position:absolute;left:-12px;top:8px;bottom:8px;width:3px;border-radius:0 3px 3px 0;background:var(--accent)}
.nav-badge{margin-left:auto;font-size:12px;font-weight:700;padding:1px 7px;border-radius:20px;background:var(--bad-soft);color:var(--bad-ink);display:inline-flex;align-items:center;gap:3px}
.nav-badge svg{width:11px;height:11px}
.nav-badge.comm-waiting{background:var(--warn-soft,#fff4d6);color:var(--warn,#a86200)}
.nav-badge.comm-overdue{background:var(--bad-soft);color:var(--bad-ink);animation:commPulse 1.8s ease-in-out infinite}
@keyframes commPulse{0%,100%{box-shadow:0 0 0 0 rgba(220,38,38,0)}50%{box-shadow:0 0 0 4px rgba(220,38,38,.14)}}
.sidebar-foot{padding:14px 16px;border-top:1px solid var(--border);display:flex;align-items:center;gap:10px}
.mini-user{display:flex;align-items:center;gap:10px;font-size:12px}
.mini-user .ava{width:32px;height:32px;border-radius:9px;display:grid;place-items:center;background:var(--bronze);color:#fff;font-weight:700;font-size:12px;font-family:'Manrope'}

.main{display:flex;flex-direction:column;min-width:0}
.topbar{
  position:sticky;top:0;z-index:30; display:flex;align-items:center;gap:16px;
  padding:14px 26px; background:var(--topbar); backdrop-filter:blur(5px) saturate(130%);-webkit-backdrop-filter:blur(5px) saturate(130%);
  border-bottom:1px solid var(--border);
}
.burger{display:none;width:38px;height:38px;border-radius:10px;border:1px solid var(--border);background:var(--surface);color:var(--text);align-items:center;justify-content:center}
.top-title h2{font-size:18px;font-weight:700}
.top-title p{margin:1px 0 0;font-size:12px;color:var(--muted)}
.top-search{margin-left:auto;position:relative;width:280px;max-width:34vw}
.top-search svg{position:absolute;left:12px;top:50%;transform:translateY(-50%);width:16px;height:16px;color:var(--faint)}
.top-search input{width:100%;padding:9px 12px 9px 36px;border-radius:10px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-size:14px;outline:none;transition:border .15s,box-shadow .15s}
.top-search input:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
/* padding:0 — у кнопки остаётся браузерная набивка 1px 6px, и на узкой
   кнопке 28px тексту «РУС» оставалось 14 пикселей при нужных 20: он не
   помещался и съезжал вправо. */
.icon-btn{padding:0;width:38px;height:38px;border-radius:10px;border:1px solid var(--border);background:var(--surface);color:var(--text-2);display:grid;place-items:center;transition:.15s;position:relative}
/* Единственная кнопка шапки с ТЕКСТОМ вместо значка. Размер жил в атрибуте
   style= прямо в разметке, и уменьшить его на телефоне было нельзя иначе как
   через !important: инлайновый стиль сильнее любого селектора. */
#langBtn{font-size:12px;font-weight:700;line-height:1;letter-spacing:0}
.icon-btn:hover{color:var(--accent-ink);border-color:var(--accent);background:var(--accent-soft)}
.icon-btn svg{width:18px;height:18px}
.icon-btn .dot{position:absolute;top:9px;right:9px;width:7px;height:7px;border-radius:50%;background:var(--bad);border:2px solid var(--surface)}

.content{padding:26px;max-width:1720px;width:100%;margin:0 auto;flex:1}
.view{animation:fade .35s ease}
@keyframes fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.view{animation:none}}

.page-head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;margin-bottom:16px;flex-wrap:wrap}
/* Заголовок внутри страницы вернулся по решению владельца.
   Я его прятал: название экрана есть и в верхней полосе, и повтор занимал
   семьдесят пикселей на каждом из тридцати экранов. Но на разделах без кнопок
   пряталась вся шапка целиком, и страница начиналась сразу с текста — человек
   читал это как «блок пропал». Верхняя полоса далеко от содержимого и мелкая,
   заголовок рядом с данными нужен. */
.page-head-text{min-width:0}
.page-head h1{font-size:23px;font-weight:700}
.page-head p{margin:5px 0 0;color:var(--muted);font-size:14px;max-width:60ch}
.page-actions{display:flex;gap:9px;flex-wrap:wrap}

/* ---------- Buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:8px;padding:9px 15px;border-radius:10px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-weight:600;font-size:14px;transition:.15s;white-space:nowrap}
.btn svg{width:16px;height:16px}
.btn:hover{border-color:var(--accent);color:var(--accent-ink);background:var(--accent-soft)}
.btn-primary{background:linear-gradient(145deg,var(--accent),var(--accent-2));border-color:transparent;color:#fff;box-shadow:0 6px 16px -6px var(--ring)}
.btn-primary:hover{color:#fff;filter:brightness(1.05)}
.btn-ghost{background:transparent;border-color:transparent}
.btn-sm{padding:6px 11px;font-size:14px;border-radius:8px}
.btn-danger:hover{border-color:var(--bad-ink);color:var(--bad-ink);background:var(--bad-soft)}

/* ---------- Cards / grid ---------- */
.grid{display:grid;gap:16px}
.kpis{grid-template-columns:repeat(auto-fill,minmax(210px,1fr))}
.cards-2{grid-template-columns:repeat(2,1fr)} .cards-3{grid-template-columns:repeat(3,1fr)} .cards-4{grid-template-columns:repeat(4,1fr)}
.span-2{grid-column:span 2} .span-3{grid-column:span 3}
@media(max-width:1200px){.cards-4{grid-template-columns:repeat(2,1fr)} .cards-3{grid-template-columns:1fr}}
/* minmax(0,…), а не 1fr: 1fr снизу равен min-content, и колонка не ужимается
   меньше самого широкого неразрывного содержимого. В настройках сетка была 294,
   а колонка 360 — поля формы канала торчали на 66 пикселей наружу. */
@media(max-width:900px){.cards-2,.span-2,.span-3{grid-template-columns:minmax(0,1fr);grid-column:auto}}
/* Переключатель направления. Виден только тому, кто закреплён больше чем за
   одним: у менеджера отдел один, и выбор из одного пункта — лишний шум. */
.dept-switch{display:flex;align-items:center;gap:4px;padding:3px;border-radius:10px;background:var(--surface-2);border:1px solid var(--border)}
.dept-btn{display:flex;align-items:center;gap:7px;padding:6px 11px;border:0;border-radius:8px;background:none;color:var(--muted);font:inherit;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background .13s,color .13s}
.dept-btn:hover{color:var(--text)}
.dept-btn i{width:8px;height:8px;border-radius:50%;flex:none;background:currentColor;opacity:.75}
.dept-btn.on{background:var(--surface);color:var(--text);box-shadow:var(--shadow-sm)}
.dept-btn.on i{opacity:1}
@media(max-width:900px){.dept-btn span{display:none}.dept-btn{padding:6px 8px}}
.design-dashboard{--design-gold:#b58a49;--design-ink:#171713;display:grid;gap:16px}
.design-hero{display:flex;align-items:flex-end;justify-content:space-between;gap:18px;padding:2px 2px 4px}
.design-hero h2{margin:0;font-family:Georgia,serif;font-size:30px;font-weight:400;letter-spacing:-.025em;color:var(--text)}
.design-hero p{margin:7px 0 0;color:var(--muted);font-size:14px}
.design-kpis{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:12px}
.design-kpi{position:relative;overflow:hidden;background:var(--surface);border:1px solid var(--border);border-radius:13px;padding:16px 48px 16px 16px;box-shadow:var(--shadow-sm)}
/* Явная бронзовая огранка вместо тонкой окружности: прежняя линия у края
   карточки визуально напоминала волос или царапину на экране. */
.design-kpi:after{content:"";position:absolute;right:0;bottom:0;width:52px;height:52px;background:linear-gradient(135deg,transparent 0 36%,rgba(181,138,73,.16) 36% 54%,rgba(181,138,73,.72) 54% 72%,#8b642b 72% 100%);clip-path:polygon(100% 0,100% 100%,0 100%);filter:drop-shadow(-4px -4px 8px rgba(139,100,43,.12))}
/* Значок по смыслу плитки вместо прежнего одинакового ромба. Лежит поверх
   углового треугольника, светлым по тёмному золоту — так он читается и не
   спорит с цифрой, которая здесь главная. */
.design-kpi-ic{position:absolute;right:7px;bottom:6px;z-index:1;display:flex;color:#f7ecd6;opacity:.92;filter:drop-shadow(0 1px 2px rgba(60,40,10,.45))}
.design-kpi span{display:block;color:var(--muted);font-size:12px;margin-bottom:9px}.design-kpi b{display:block;font-family:Georgia,serif;font-size:22px;font-weight:400}/* Зелёный потемнел под светлый фон: прежний #3a9b67 на кремовом давал около
   3:1, а это подпись в десять пикселей — её и так читать непросто. */
.design-kpi small{display:block;margin-top:8px;color:#2c7a4f;font-size:12px}
.design-main{display:grid;grid-template-columns:minmax(0,1.55fr) minmax(300px,.85fr);gap:14px}
.design-panel{background:var(--surface);border:1px solid var(--border);border-radius:14px;box-shadow:var(--shadow-sm);overflow:hidden}
.design-panel-head{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--border)}
.design-panel-head h3{margin:0;font-family:Georgia,serif;font-size:18px;font-weight:400}.design-panel-head button{border:0;background:none;color:var(--muted);font-size:12px;cursor:pointer}
.design-order-list{display:grid;gap:8px;padding:10px}.design-order{display:grid;grid-template-columns:66px minmax(0,1fr) auto;align-items:center;gap:11px;padding:8px;border:1px solid var(--border);border-radius:11px;background:var(--surface-2);cursor:pointer;text-align:left;color:inherit}
.design-order:hover{border-color:rgba(181,138,73,.55);transform:translateY(-1px)}.design-order-art{height:60px;border-radius:8px;overflow:hidden;background:linear-gradient(145deg,#ebe8e0,#cbc7bd)}.design-order-art svg{width:100%;height:100%;display:block}
.design-order strong{display:block;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.design-order em{display:block;margin-top:4px;color:var(--muted);font-size:12px;font-style:normal}.design-order .amount{font-weight:700;font-size:12px;white-space:nowrap}
.design-portfolio{display:grid;grid-template-columns:repeat(2,1fr);gap:10px;padding:12px}.design-portfolio article{padding:14px;border-radius:11px;background:var(--surface-2);border:1px solid var(--border)}.design-portfolio b{display:block;font-family:Georgia,serif;font-size:25px;font-weight:400}.design-portfolio span{font-size:12px;color:var(--muted)}
.design-production{display:grid;grid-template-columns:150px 1fr;gap:16px;align-items:center;padding:16px}.design-ring{position:relative;width:118px;height:118px;margin:auto;border-radius:50%;display:grid;place-items:center;background:conic-gradient(var(--design-gold) 0 64%,var(--surface-3) 64%)}.design-ring:before{content:"";width:82px;height:82px;border-radius:50%;background:var(--surface)}.design-ring b{position:absolute;font-family:Georgia,serif;font-size:24px}.design-stages{display:grid;gap:9px}.design-stage{display:grid;grid-template-columns:minmax(100px,1fr) 2fr 28px;align-items:center;gap:8px;font-size:12px}.design-stage i{height:5px;border-radius:9px;background:var(--surface-3);overflow:hidden}.design-stage i:after{content:"";display:block;width:var(--p);height:100%;background:var(--design-gold);border-radius:inherit}
.design-demo-note{padding:10px 14px;border:1px dashed rgba(181,138,73,.55);border-radius:10px;color:var(--muted);font-size:12px;background:rgba(181,138,73,.06)}
@media(max-width:1200px){.design-kpis{grid-template-columns:repeat(3,1fr)}.design-main{grid-template-columns:1fr}}
@media(max-width:700px){.design-kpis{grid-template-columns:1fr 1fr}.design-production{grid-template-columns:1fr}.design-order{grid-template-columns:58px minmax(0,1fr)}.design-order .amount{grid-column:2}}
/* Коммуникации: переписка с клиентами из мессенджеров. Три колонки — фильтры и
   каналы, список обращений, сама переписка. Разметка намеренно повторяет
   внутренний чат: это тот же жанр экрана, и второй набор правил здесь только
   разошёлся бы с первым. */
/* Метка направления в подзаголовке раздела: точка его цветом плюс название. */
.comm-where{display:inline-flex;align-items:center;gap:6px;font-weight:600;color:var(--text-2)}
.comm-where i{width:8px;height:8px;border-radius:50%;display:inline-block;flex:none}
.comm-wrap{display:grid;grid-template-columns:224px minmax(280px,340px) minmax(0,1fr);gap:14px;height:calc(100vh - 168px);min-height:460px}
.comm-col{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);box-shadow:var(--shadow-sm);display:flex;flex-direction:column;overflow:hidden;min-width:0}
.comm-side{padding:10px;gap:2px;overflow-y:auto}
.comm-filter{display:flex;align-items:center;gap:9px;width:100%;padding:8px 10px;border:0;border-radius:9px;background:none;color:var(--muted);font:inherit;font-size:12px;text-align:left;cursor:pointer}
.comm-filter:hover{background:var(--surface-2);color:var(--text)}
.comm-filter.on{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}
.comm-filter b{margin-left:auto;font-size:12px;color:var(--muted);font-weight:600}
.comm-side h4{margin:14px 0 6px;padding:0 10px;font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--faint)}
.comm-list{overflow-y:auto;padding:8px;display:grid;gap:5px;align-content:start}
.comm-item{display:grid;grid-template-columns:34px minmax(0,1fr);gap:10px;padding:9px;border:1px solid transparent;border-radius:11px;background:none;cursor:pointer;text-align:left;color:inherit;width:100%}
.comm-item:hover{background:var(--surface-2)}
.comm-item.on{background:var(--accent-soft);border-color:rgba(79,107,255,.25)}
.comm-item .ava{width:34px;height:34px;font-size:12px}
.comm-item-top{display:flex;align-items:baseline;gap:8px}
.comm-item-top b{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.comm-item-top span{margin-left:auto;font-size:12px;color:var(--faint);white-space:nowrap}
.comm-item p{margin:3px 0 0;font-size:12px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Строка под именем: канал, ответственный и метка ожидания.
   Ничему здесь нельзя переноситься — «Не розподілено» и «19 год» ломались
   каждое на свои строки, и вместо одной аккуратной строки выходил столбик.
   Длинное имя канала обрезается многоточием, а метка ожидания не сжимается:
   она короткая и должна остаться целой. */
.comm-item-meta{display:flex;align-items:center;gap:7px;margin-top:5px;font-size:12px;color:var(--faint);white-space:nowrap;overflow:hidden}
.comm-item-meta>span{overflow:hidden;text-overflow:ellipsis;min-width:0}
.comm-item-meta>svg{flex:0 0 auto}
.comm-done{padding:1px 7px;border-radius:20px;background:var(--surface-3);color:var(--muted);font-size:12px;font-weight:600}
.comm-unread{margin-left:auto;min-width:18px;height:18px;padding:0 5px;border-radius:9px;background:var(--accent);color:#fff;font-size:12px;font-weight:700;display:grid;place-items:center}
.comm-sla{margin-left:auto;flex:0 0 auto;display:inline-flex;align-items:center;gap:3px;padding:2px 7px;border-radius:8px;background:var(--warn-soft,#fff4d6);color:var(--warn,#a86200);font-weight:700;white-space:nowrap}
.comm-sla.overdue{background:var(--bad-soft);color:var(--bad-ink)}
.comm-head{display:flex;align-items:center;gap:11px;padding:12px 14px;border-bottom:1px solid var(--border);flex-wrap:wrap}
.comm-head h3{font-size:14px;font-weight:700;margin:0}
.comm-head .sub{font-size:12px;color:var(--muted)}
.comm-head .spacer{margin-left:auto}
.comm-thread{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:10px;background:var(--surface-2)}
.comm-msg{max-width:min(560px,78%);padding:9px 12px;border-radius:13px;background:var(--surface);border:1px solid var(--border);font-size:14px;line-height:1.5;box-shadow:var(--shadow-sm);word-break:break-word}
.comm-msg.out{align-self:flex-end;background:var(--accent);border-color:transparent;color:#fff}
.comm-msg .when{display:block;margin-top:5px;font-size:12px;opacity:.7}
.comm-msg.failed{border-color:var(--bad,#dc2626)}
.comm-msg img{max-width:100%;border-radius:9px;display:block;margin-bottom:6px}
.comm-compose{display:flex;gap:9px;padding:11px;border-top:1px solid var(--border);align-items:flex-end}
.comm-compose textarea{flex:1;resize:none;min-height:38px;max-height:130px;padding:9px 11px;border:1px solid var(--border);border-radius:10px;background:var(--surface);color:var(--text);font:inherit;font-size:14px}
.comm-empty{margin:auto;text-align:center;color:var(--muted);font-size:14px;padding:30px}
@media(max-width:1100px){.comm-wrap{grid-template-columns:1fr;height:auto}.comm-col{max-height:60vh}}
/* Файлы сделки: плитки с превью. Сетка, а не список — эскизы и фото
   опознаются по картинке быстрее, чем по имени файла. */
/* Редактор правил повторных продаж. */
.fr-list{display:flex;flex-direction:column;gap:12px}
.fr-row{padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2)}
.fr-on{display:flex;align-items:center;gap:9px;font-size:14px;font-weight:600;margin-bottom:10px;cursor:pointer}
.fr-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(165px,1fr));gap:10px}
.fr-grid label{display:flex;flex-direction:column;gap:5px;font-size:12px;color:var(--muted)}
.fr-grid input,.fr-grid select{padding:7px 9px;border-radius:9px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-size:12px}
.fr-grid select[multiple]{padding:4px;min-height:86px}
.fr-wide{grid-column:1/-1}
.fr-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.fr-name{flex:1;min-width:0;padding:6px 9px;border-radius:9px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-size:12px;font-weight:600}
.fr-actions{display:flex;align-items:center;gap:8px;margin-top:14px;flex-wrap:wrap}
.fr-actions .spacer{flex:1}

/* Путь сделки по этапам. */
.stage-path{margin-top:16px;padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2)}
.stage-path-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;margin-bottom:9px}
.stage-path-head b{font-size:14px}
.stage-path-head span{font-size:12px;color:var(--muted)}
.stage-path-head .is-done{display:inline-flex;align-items:center;gap:4px;color:var(--good,#1f7a45);font-weight:600}
.stage-dots{display:flex;gap:4px}
.stage-dot{flex:1;height:6px;border-radius:20px;background:var(--surface-3)}
.stage-dot.done{background:var(--good,#37a06a)}
.stage-dot.now{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.stage-path-foot{margin-top:8px;font-size:12px;color:var(--faint)}
/* Отказ — не «следующий этап», а выход из воронки, поэтому и вид другой. */
.stage-path.is-refused{display:flex;align-items:center;gap:9px;border-color:var(--bad-ink);background:var(--bad-soft);color:var(--bad-ink)}
.stage-path.is-refused b{font-size:14px}
.stage-path.is-refused span{font-size:12px;opacity:.85}

/* Оплата в карточке сделки. */
.dealpay{margin-top:16px;padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2)}
/* Маржа оформлена как продолжение блока оплаты, но со своей рамкой: это
   разные вопросы — сколько клиент заплатил и сколько сделка нам стоила. */
.deal-margin:not(:empty){margin-top:12px;padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2)}
.margin-rows .kv{padding:7px 0;font-size:14px}
.margin-rows .kv b{display:flex;align-items:center;gap:6px}
.margin-rows .kv .icon-btn{padding:2px;opacity:.5}
.margin-rows .kv .icon-btn:hover{opacity:1}
.margin-total{border-top:1px solid var(--border);margin-top:2px}
.margin-total:first-of-type{}
.margin-add{margin-top:10px}
.dealpay-head{display:flex;align-items:center;gap:10px;margin-bottom:10px}
.dealpay-head b{font-size:14px}
.dealpay-badge{margin-left:auto;padding:2px 9px;border-radius:20px;font-size:12px;font-weight:700}
.dealpay-badge.none{background:var(--surface-3);color:var(--muted)}
.dealpay-badge.part{background:var(--warn-soft,#fff4d6);color:var(--warn,#a86200)}
.dealpay-badge.full{background:var(--good-soft,#e8f6ee);color:var(--good,#1f7a45)}
/* Ячеек стало четыре — «Выставлено» добавилось к сумме, оплате и остатку.
   В сетке на три колонки четвёртая уезжала во вторую строку одна. */
.dealpay-nums{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:10px;margin-bottom:10px}
.dealpay-nums span{display:block;font-size:12px;color:var(--muted);margin-bottom:2px}
.dealpay-nums b{font-size:14px;font-variant-numeric:tabular-nums}
.dealpay-nums b.is-left{color:var(--warn,#a86200)}
/* Долг по выставленным счетам и кнопки под блоком оплаты: разметка была,
   а правил к ней я не написал — строка сливалась с цифрами выше. */
.dealpay-debt{margin:0 0 10px;padding:7px 10px;border-radius:9px;font-size:12px;
  background:var(--warn-soft,#fff4d6);color:var(--warn,#a86200)}
.dealpay-debt b{font-variant-numeric:tabular-nums}
.dealpay-acts{display:flex;flex-wrap:wrap;gap:8px}
/* Кнопка «Отметить оплату» тянется на всю строку, когда осталась одна. */
.dealpay-add{flex:1 1 auto}
.dealpay-bar{height:6px;border-radius:20px;background:var(--surface-3);overflow:hidden}
.dealpay-bar i{display:block;height:100%;border-radius:20px;background:var(--good,#37a06a)}
@media(max-width:560px){.dealpay-nums{grid-template-columns:1fr 1fr}}

/* Обучение: выбор роли и пошаговые указания. */
.guide-roles{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:10px;margin-bottom:18px}
.guide-role{display:flex;align-items:center;gap:11px;padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--surface);text-align:left;cursor:pointer;color:var(--text)}
.guide-role:hover{border-color:var(--accent)}
.guide-role.on{border-color:var(--accent);background:var(--accent-soft)}
.guide-role-ic{display:flex;align-items:center;justify-content:center;width:32px;height:32px;flex:none;border-radius:9px;background:var(--surface-2);color:var(--accent-ink)}
.guide-role b{display:block;font-size:14px}
.guide-role span span{display:block;font-size:12px;color:var(--muted);margin-top:2px}
.guide-block{padding:16px 18px;border:1px solid var(--border);border-radius:13px;background:var(--surface);margin-bottom:12px}
.guide-block h3{display:flex;align-items:center;gap:10px;font-size:14px;margin-bottom:12px}
.guide-num{display:flex;align-items:center;justify-content:center;width:23px;height:23px;flex:none;border-radius:50%;background:var(--accent);color:#fff;font-size:12px;font-weight:700}
.guide-steps{margin:0;padding-left:19px;display:flex;flex-direction:column;gap:11px}
.guide-steps li{font-size:14px;line-height:1.55;color:var(--text-2)}
/* Шаг-проверка отделён: человек должен видеть, что у него получилось, а не
   гадать, дошёл ли он до конца. */
.guide-steps li.is-check{list-style:none;margin-left:-19px;padding:8px 11px;border-radius:9px;background:var(--good-soft,#e8f6ee);color:var(--good,#1f7a45);font-weight:600}
/* Два столбца: слева инструкция, справа вопросы.
   На узком экране они встают друг под друга, и тогда шапка каждого столбца
   становится единственным способом понять, где кончилось одно и началось
   другое — поэтому она заметная, а не подпись мелким шрифтом. */
.guide-cols{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:18px;align-items:start}
.guide-col{min-width:0}
.guide-colhead{display:flex;align-items:center;gap:9px;margin-bottom:11px;padding-bottom:9px;border-bottom:2px solid var(--border);color:var(--accent-ink)}
.guide-colhead b{font-size:14px;color:var(--text)}
.guide-colhead span{font-size:12px;color:var(--muted)}
@media(max-width:1000px){
  .guide-cols{grid-template-columns:1fr;gap:8px}
  /* Разделитель между модулями: сложенные столбцы иначе читаются как один
     бесконечный список. */
  .guide-col+.guide-col{margin-top:14px;padding-top:18px;border-top:3px solid var(--border)}
  .guide-colhead{position:sticky;top:0;z-index:3;background:var(--bg);padding-top:8px;margin-bottom:12px}
  .guide-colhead span{display:none}
}

/* Частые вопросы: уровни и раскрывающиеся ответы. */
.faq-block{margin-top:0}
.faq-levels{display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap}
.faq-lvl{padding:7px 13px;border:1px solid var(--border);border-radius:10px;background:var(--surface-2);text-align:left;cursor:pointer;color:var(--text)}
.faq-lvl.on{border-color:var(--accent);background:var(--accent-soft)}
.faq-lvl b{display:block;font-size:12px}
.faq-lvl span{display:block;font-size:12px;color:var(--muted);margin-top:1px}
.faq-list{display:flex;flex-direction:column;gap:6px}
.faq-item{border:1px solid var(--border);border-radius:10px;background:var(--surface-2);overflow:hidden}
.faq-item.on{border-color:var(--accent)}
.faq-q{display:flex;align-items:center;gap:9px;width:100%;padding:10px 12px;background:none;border:0;text-align:left;cursor:pointer;color:var(--text);font-size:12px;font-weight:600}
.faq-q:hover{background:var(--surface-3)}
.faq-a{padding:0 12px 12px 33px;font-size:12px;line-height:1.55;color:var(--text-2)}
.faq-a .guide-show{display:flex;width:max-content}

/* Поиск по инструкции и найденное. */
.guide-search{margin-bottom:12px;max-width:520px}
.guide-found{display:none;flex-direction:column;gap:6px;margin-bottom:16px}
.guide-found.on{display:flex}
.guide-hit{display:flex;align-items:baseline;gap:10px;padding:9px 12px;border:1px solid var(--border);border-radius:10px;background:var(--surface);text-align:left;cursor:pointer;color:var(--text)}
.guide-hit:hover{border-color:var(--accent);background:var(--accent-soft)}
/* Вопрос в выдаче отличается от раздела: это разные виды ответа. */
.guide-hit.is-faq{border-left:3px solid var(--accent)}
.guide-hit b{font-size:12px}
.guide-hit span{margin-left:auto;font-size:12px;color:var(--muted)}

/* Полоса учебного режима: видно всегда, пока он включён. */
.guide-banner{position:fixed;left:0;right:0;top:0;z-index:100002;display:flex;align-items:center;gap:10px;padding:7px 16px;background:var(--warn,#a86200);color:#fff;font-size:12px;box-shadow:0 2px 10px rgba(0,0,0,.2)}
.guide-banner b{font-weight:700}
.guide-banner span{opacity:.9}
.guide-banner .btn{margin-left:auto;background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.35);color:#fff}
/* Высота полосы — переменная, а не число.
   Тридцать четыре пикселя — это высота полосы в ОДНУ строку. На телефоне текст
   «Навчальний режим · Дані вигадані, нічого не зберігається · Вийти» переносится
   на две, полоса вырастает вдвое, и под неё уезжает и содержимое страницы, и
   карточка проводника: заголовок с номером шага обрезался ровно по этой причине.
   Фактическую высоту замеряет guideBanner() и кладёт сюда. */
body.has-guide-banner{padding-top:var(--guide-banner-h,34px)}

/* Проводник: панель с текущим шагом поверх всей системы.
   Внизу по центру, а не сбоку: боковая перекрывала бы то самое меню, на
   которое половина шагов и указывает. Поверх окон — иначе она пропадала бы
   ровно тогда, когда открывается карточка сделки. */
.guide-tour{position:fixed;left:50%;bottom:18px;transform:translateX(-50%);z-index:100000;width:min(520px,calc(100vw - 32px));
  padding:13px 15px;border:1px solid var(--border-2);border-radius:14px;background:var(--surface);box-shadow:0 18px 44px -18px rgba(0,0,0,.5)}
/* Сверху отступаем от полосы учебного режима: она прибита к верху экрана и
   лежит выше по слоям, поэтому карточка просто уезжала под неё вместе с
   заголовком и номером шага. Без полосы переменная не задана и берётся ноль. */
.guide-tour.at-top{bottom:auto;top:calc(var(--guide-banner-h,0px) + 18px)}
.guide-tour-top{display:flex;align-items:center;gap:10px;margin-bottom:7px}
.guide-tour-top b{font-size:12px}
.guide-tour-top span{margin-left:auto;font-size:12px;color:var(--faint);font-variant-numeric:tabular-nums}
.guide-tour p{margin:0 0 11px;font-size:14px;line-height:1.55;color:var(--text-2)}
.guide-tour-note{display:block;margin:-4px 0 10px;padding:7px 10px;border-radius:8px;background:var(--warn-soft,#fff4d6);color:var(--warn,#a86200);font-size:12px;font-style:normal;line-height:1.45}
.guide-tour-nav{display:flex;gap:8px;justify-content:flex-end}
.guide-run{display:inline-flex;align-items:center;gap:5px;margin-left:auto;padding:3px 10px;border-radius:20px;border:1px solid var(--accent);background:var(--accent-soft);color:var(--accent-ink);font-size:12px;font-weight:600;cursor:pointer}
.guide-run:hover{background:var(--accent);color:#fff}
/* Кнопка «Показать» у шага и подсветка найденного элемента. */
.guide-show{display:inline-flex;align-items:center;gap:5px;margin-top:6px;padding:4px 10px;border-radius:20px;border:1px solid var(--border);background:var(--surface-2);color:var(--accent-ink);font-size:12px;font-weight:600;cursor:pointer}
.guide-show:hover{border-color:var(--accent);background:var(--accent-soft)}
/* Подсветка держится четыре секунды: этого хватает, чтобы взгляд нашёл
   элемент, и мало, чтобы она начала мешать работе. */
/* Затемнение с размытием на время шага.
 *
 * Подсветки одной мало: на плотном экране золотой ободок теряется среди
 * двадцати других элементов, и человек всё равно ищет глазами. Когда остальное
 * размыто, искать нечего — взгляд идёт туда, где резко.
 *
 * Размывается тело страницы, а панель проводника и подсвеченный элемент лежат
 * выше него и остаются чёткими. Снимается вместе с шагом. */
/* Затемнение «прожектором», а не размытием родителей.
 *
 * Размытие вешалось на детей body, и подсвеченный элемент размывался вместе с
 * родителем: фильтр наследуется вниз, и никакой filter:none у потомка его не
 * отменяет. Отдельно поднять элемент тоже нельзя — родитель с фильтром
 * создаёт свой слой, из которого не выбраться.
 *
 * Огромная тень вокруг самого элемента затемняет всё остальное и оставляет
 * его резким. Работает на любой глубине разметки, потому что ничего не
 * наследует. */
body.guide-blur .guide-point{position:relative;z-index:100001;border-radius:10px}

/* Подсветка мигает, пока шаг на экране, и не гаснет сама: проводник снимает
   её, когда переходит к следующему. Три пульса и тишина оставляли человека
   перед вопросом «а куда всё-таки смотреть». */
/* Мигающий ободок плюс затемнение всего вокруг одной и той же тенью:
   9999px разлетаются во все стороны и гасят экран, а сам элемент остаётся
   чётким и светлым. */
.guide-phone{position:fixed;right:32px;top:50%;transform:translateY(-50%);width:300px;z-index:100002;
  background:#0f1720;border:8px solid #0f1720;border-radius:30px;box-shadow:0 24px 60px rgba(0,0,0,.45);overflow:hidden}
.guide-phone-top{display:flex;align-items:center;gap:9px;padding:11px 13px;background:#517da2;color:#fff}
.guide-phone-av{width:30px;height:30px;border-radius:50%;background:#fff3;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:600}
.guide-phone-who{font-size:14px;font-weight:600;line-height:1.25}
.guide-phone-who small{display:block;font-size:12px;font-weight:400;opacity:.8}
.guide-phone-body{background:#d3e0e9;padding:12px 10px;min-height:210px;max-height:52vh;overflow:auto;display:flex;flex-direction:column;gap:7px}
.guide-phone-msg{max-width:84%;padding:7px 10px;border-radius:12px;font-size:12px;line-height:1.45;white-space:pre-line;
  background:#fff;color:#101820;align-self:flex-start;box-shadow:0 1px 1px rgba(0,0,0,.08)}
.guide-phone-msg.out{background:#effdde;align-self:flex-end}
/* Блок «На сегодня»: кому звонить и что просрочено. */
.today-panel{margin-bottom:16px}
.today-head{display:flex;align-items:center;gap:9px;padding:12px 16px;border-bottom:1px solid var(--border);color:var(--accent-ink)}
.today-head b{font-size:14px;color:var(--text)}
.today-head span{font-size:12px;color:var(--muted)}
.today-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:6px}
.today-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--border);
  border-radius:10px;background:var(--surface-2);text-align:left;cursor:pointer;color:var(--text)}
.today-row:hover{border-color:var(--accent);background:var(--accent-soft)}
.today-when{flex:none;min-width:62px;font-size:12px;font-weight:700;color:var(--muted)}
/* Просроченное подсвечено: это не «ещё одна строка», а долг. */
.today-row.late .today-when{color:var(--bad-ink,#b52738)}
.today-txt{flex:1;min-width:0}
.today-txt b{display:block;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.today-txt i{display:block;font-size:12px;font-style:normal;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.today-phone{flex:none;font-size:12px;color:var(--muted)}
@media(max-width:560px){.today-phone{display:none}}

/* Поиск по всей системе: список под полем. */
.find-box{position:fixed;z-index:100040;max-height:60vh;overflow:auto;padding:5px;
  border:1px solid var(--border-2);border-radius:12px;background:var(--surface);box-shadow:0 18px 40px -14px rgba(0,0,0,.45)}
.find-row{display:flex;align-items:center;gap:10px;width:100%;padding:8px 9px;border:0;border-radius:9px;
  background:none;text-align:left;cursor:pointer;color:var(--text)}
.find-row:hover,.find-row.on{background:var(--accent-soft)}
.find-ic{display:flex;align-items:center;justify-content:center;width:26px;height:26px;flex:none;
  border-radius:8px;background:var(--surface-2);color:var(--accent-ink)}
.find-txt{flex:1;min-width:0}
.find-txt b{display:block;font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.find-txt i{display:block;font-size:12px;font-style:normal;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.find-where{flex:none;font-size:12px;color:var(--muted);padding:2px 8px;border-radius:20px;background:var(--surface-2)}

/* Форма текстов: у каждого поля кнопка, по наведению — само сообщение. */
.ntf-head{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:5px}
.ntf-eye{display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border:1px solid var(--border);
  border-radius:20px;background:var(--surface-2);color:var(--muted);font-size:12px;cursor:pointer}
.ntf-eye:hover,.ntf-eye:focus{border-color:var(--accent);color:var(--accent-ink);background:var(--accent-soft);outline:none}
.ntf-tip{position:fixed;z-index:100050;width:min(320px,calc(100vw - 24px));padding:9px 11px;
  border-radius:12px;background:#0f1720;box-shadow:0 14px 34px rgba(0,0,0,.42);pointer-events:none}
.ntf-tip-top{font-size:12px;color:#9fb3c8;margin-bottom:6px}
.ntf-tip-msg{padding:8px 11px;border-radius:12px;background:#effdde;color:#101820;
  font-size:12px;line-height:1.45;white-space:pre-line}
.ntf-tip-msg.off{background:#3a3f47;color:#c3c9d1;text-decoration:line-through}
.guide-phone-sys{align-self:center;padding:3px 10px;border-radius:20px;background:rgba(0,0,0,.14);color:#fff;font-size:12px;line-height:1.35;text-align:center;max-width:92%}
.guide-phone-start{align-self:stretch;margin-top:auto;padding:11px 10px;border-radius:9px;background:#fff;color:#3390ec;
  font-size:12px;font-weight:700;text-align:center;letter-spacing:.04em;box-shadow:0 1px 2px rgba(0,0,0,.12)}
.guide-phone-row{display:flex;gap:5px;align-self:stretch}
.guide-phone-row span{flex:1;padding:8px 6px;border-radius:8px;background:rgba(255,255,255,.92);color:#3390ec;font-size:12px;font-weight:600;text-align:center;box-shadow:0 1px 2px rgba(0,0,0,.1)}
.guide-phone-btn{align-self:stretch;padding:8px 10px;border-radius:8px;background:rgba(255,255,255,.92);color:#3390ec;font-size:12px;font-weight:600;text-align:center;box-shadow:0 1px 2px rgba(0,0,0,.1)}
.guide-phone-note{background:#0f1720;color:#9fb3c8;font-size:12px;line-height:1.4;padding:9px 13px;text-align:center}
.guide-point{animation:guidePoint 1.4s ease-in-out infinite;border-radius:10px;position:relative;z-index:100001}
@keyframes guidePoint{
  0%,100%{box-shadow:0 0 0 2px rgba(181,138,73,.55),0 0 0 9999px rgba(12,10,6,.55)}
  50%{box-shadow:0 0 0 6px rgba(181,138,73,.95),0 0 0 9999px rgba(12,10,6,.55)}
}
/* У кнопки «Показать» вне проводника подсветка одноразовая — там она гаснет
   сама через несколько секунд, и бесконечное мигание мешало бы работать. */
/* Повторные продажи: карточка на одного клиента. */
.followup-list{display:flex;flex-direction:column;gap:10px}
.followup-card{display:flex;gap:12px;align-items:flex-start;padding:12px 14px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2);flex-wrap:wrap}
/* Учебная подсказка приглушена: механизм показывает, но в глаза не лезет. */
.followup-card.is-demo{opacity:.82;border-style:dashed}
.followup-main{flex:1;min-width:220px}
.followup-top{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:5px}
.followup-meta{display:flex;gap:14px;flex-wrap:wrap;font-size:12px;color:var(--muted)}
.followup-why{margin-top:6px;font-size:12px;color:var(--faint);line-height:1.45}
.followup-act{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
@media(max-width:640px){.followup-act{width:100%}.followup-act .btn{flex:1}}

/* Переписка в карточке сделки. Лента ограничена по высоте: карточку и без
   того длинную нельзя растягивать историей на сотню сообщений — за ней
   потеряются кнопки сохранения. */
.dealcomm-thread{max-height:210px;overflow-y:auto;display:flex;flex-direction:column;gap:7px;padding-right:4px;margin-bottom:10px}
.dealcomm-msg{max-width:82%;padding:7px 10px;border-radius:11px;background:var(--surface-2);border:1px solid var(--border)}
.dealcomm-msg.out{align-self:flex-end;background:var(--accent-soft,var(--surface-2));border-color:transparent}
.dealcomm-body{font-size:12px;line-height:1.45;white-space:pre-wrap;word-break:break-word}
.dealcomm-when{font-size:12px;color:var(--faint);margin-top:3px}
.dealcomm-send{display:flex;gap:8px;align-items:flex-end}
.dealcomm-send textarea{flex:1;padding:8px 10px;border-radius:9px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font-size:12px;resize:vertical;font-family:inherit}
.dealcomm-invite{display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.dealcomm-invite code{flex:1;min-width:200px;padding:7px 10px;border-radius:9px;background:var(--surface-2);border:1px solid var(--border);font-size:12px;word-break:break-all;color:var(--muted)}
.dealfiles-wrap{margin-top:18px;padding-top:16px;border-top:1px solid var(--border)}
.dealfiles-head{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}
.dealfiles-head b{font-size:14px}
.dealfiles-head select{margin-left:auto;padding:7px 10px;border-radius:9px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font-size:12px}
.dealfiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:12px}
.dealfile{margin:0;border:1px solid var(--border);border-radius:11px;overflow:hidden;background:var(--surface-2);display:flex;flex-direction:column}
.dealfile.ok{border-color:var(--good-ink)}
.dealfile-art{height:96px;background:var(--surface-3);display:grid;place-items:center;cursor:pointer;overflow:hidden}
.dealfile-art img{width:100%;height:100%;object-fit:cover;display:block}
.dealfile-ext{font-size:14px;font-weight:700;color:var(--muted);letter-spacing:.04em}
.dealfile figcaption{padding:8px 9px;display:grid;gap:3px;min-width:0}
.dealfile figcaption b{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dealfile figcaption span{font-size:12px;color:var(--muted)}
.dealfile-state{font-weight:600}
.dealfile-state.review{color:var(--warn-ink)}
.dealfile-state.approved{color:var(--good-ink)}
.dealfile-state.rework{color:var(--bad,#dc2626)}
.dealfile-acts{display:flex;gap:4px;padding:0 9px 9px;flex-wrap:wrap}
.dealfile-acts .mini-btn.on{background:var(--accent-soft);color:var(--accent-ink)}
.settings-page{display:grid;gap:16px}
.settings-top{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;align-items:start}
.settings-top .panel{height:auto}
.settings-columns{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;align-items:start}
.settings-column{display:grid;gap:16px;align-content:start;min-width:0}
.settings-column .span-2,.settings-column .span-3{grid-column:auto}
.manager-settings-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.manager-settings-field{display:flex;flex-direction:column;gap:5px;min-width:0;font-size:12px;font-weight:600;color:var(--muted)}
.manager-settings-field select{display:block;width:100%;min-width:0;padding:9px 11px;border:1px solid var(--border);border-radius:9px;background:var(--surface);color:var(--text);font-size:14px;font-family:inherit;outline:none}
.manager-settings-field select:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
@media(max-width:1300px){.settings-top{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:1100px){.settings-columns{grid-template-columns:1fr}}
/* Настройки: разделы слева, содержимое справа. Раньше все одиннадцать панелей
   лежали одним полотном в две колонки — открыв раздел, человек видел сразу всё
   и искал нужное прокруткой. */
/* Ширина ограничена: на широком мониторе строки «подпись — значение»
   разъезжались по краям и переставали читаться как пара. */
.set-shell{display:grid;grid-template-columns:212px minmax(0,1fr);gap:20px;align-items:start;max-width:1180px}
.set-rail{position:sticky;top:12px;display:grid;gap:1px;padding:0;border:0;background:none;box-shadow:none}
.set-item{display:flex;align-items:center;gap:10px;width:100%;padding:9px 10px;border:0;border-radius:9px;background:none;color:var(--muted);font:inherit;font-size:14px;text-align:left;cursor:pointer;transition:background .13s,color .13s}
.set-item:hover{background:var(--surface-2);color:var(--text)}
.set-item .set-ic{width:26px;height:26px;flex:none;display:grid;place-items:center;color:inherit;opacity:.85}
.set-item .set-ic svg{width:16px;height:16px}
.set-item b{font-weight:600;display:block;color:var(--text)}
.set-item span{display:block;font-size:12px;color:var(--muted);margin-top:1px;font-weight:400}
.set-item.on{background:var(--accent-soft);color:var(--accent)}
.set-item.on b{color:var(--accent-ink)}
.set-body{display:grid;gap:16px;align-content:start;min-width:0}
/* Сводка о системе: две колонки пар вместо одной растянутой. */
.set-facts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0 28px}
.set-facts .kv:nth-last-child(-n+2){border-bottom:0}
@media(max-width:760px){.set-facts{grid-template-columns:1fr}}
.set-body .span-2,.set-body .span-3{grid-column:auto}
.set-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;align-items:start}
/* Вложенные группы внутри раздела — на нативном <details>: раскрытие по клику
   и работа с клавиатуры достаются даром, без своего состояния в JS. */
.set-acc{border:1px solid var(--border);border-radius:12px;background:var(--surface-2);overflow:hidden}
.set-acc+.set-acc{margin-top:10px}
.set-acc>summary{display:flex;align-items:center;gap:10px;padding:12px 14px;cursor:pointer;list-style:none;font-size:14px;font-weight:600;user-select:none}
.set-acc>summary::-webkit-details-marker{display:none}
.set-acc>summary:hover{background:var(--surface)}
.set-acc>summary .set-chev{margin-left:auto;color:var(--muted);transition:transform .16s}
.set-acc[open]>summary .set-chev{transform:rotate(90deg)}
.set-acc>summary small{font-weight:400;color:var(--muted);font-size:12px}
.set-acc-body{padding:0 14px 14px;border-top:1px solid var(--border)}
.set-acc-body>:first-child{margin-top:14px}
/* На телефоне список разделов ложится горизонтальной лентой закладок: рельс
   на всю высоту съел бы экран прежде, чем человек увидит сами настройки.
   Лента липнет к верху, чтобы переключать разделы, не прокручивая обратно. */
@media(max-width:900px){
  .set-shell{grid-template-columns:1fr;gap:14px}
  .set-rail{position:sticky;top:0;z-index:4;grid-auto-flow:column;grid-auto-columns:max-content;
            overflow-x:auto;gap:6px;padding:8px 2px;margin:0 -2px;
            background:var(--bg);border-bottom:1px solid var(--border);
            scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .set-rail::-webkit-scrollbar{display:none}
  .set-item{padding:8px 13px;border:1px solid var(--border);border-radius:999px;background:var(--surface);white-space:nowrap}
  .set-item .set-ic{width:18px;height:18px}
  .set-item .set-ic svg{width:15px;height:15px}
  .set-item span{display:none}
  .set-item.on{border-color:transparent;background:var(--accent);color:#fff}
  .set-item.on b{color:#fff}
  .set-pair{grid-template-columns:1fr}
  /* Поля в две колонки на узком экране нечитаемы: подпись переносится, а
     ввод сжимается до нескольких символов. */
  .set-acc-body .grid.cards-2,.set-acc-body [style*="grid-template-columns:1fr 1fr"]{grid-template-columns:minmax(0,1fr)!important}
  .set-acc>summary{padding:11px 12px}
  .set-acc-body{padding:0 12px 12px}
}
@media(max-width:900px){.settings-top{grid-template-columns:1fr}}
@media(max-width:700px){.manager-settings-grid{grid-template-columns:1fr}}
/* Колоночный поток вместо сетки: группы разной высоты укладываются плотно,
   без провалов, которые давал grid с выравниванием по верху. */
.catalog-layout{columns:2;column-gap:16px}
.catalog-group{break-inside:avoid;-webkit-column-break-inside:avoid;page-break-inside:avoid;margin:0 0 16px;border:1px solid var(--border);border-radius:14px;background:var(--surface-2);padding:14px;display:grid;gap:12px}
.catalog-group-title{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:0 2px 2px}
.catalog-group-title h4{font-size:14px;font-weight:700;text-transform:uppercase;color:var(--muted);letter-spacing:.04em}
.catalog-group-title span{font-size:12px;color:var(--faint)}
.catalog-card{border:1px solid var(--border);border-radius:12px;background:var(--surface);padding:13px;display:grid;gap:12px}
.catalog-card .section-title{margin:0}
.catalog-card-list{max-height:240px;overflow:auto;padding-right:3px}
.catalog-card-list .chip-set{gap:8px}
.catalog-card-form{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px}
.catalog-card-form input{min-width:0;padding:9px 12px;border-radius:9px;border:1px solid var(--border);background:var(--surface-2);color:var(--text)}
.catalog-group.is-wide{grid-column:1/-1}
.catalog-subgrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.catalog-list-rows{display:grid;gap:8px}
.catalog-row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;border:1px solid var(--border);border-radius:10px;padding:8px 10px;background:var(--surface-2)}
.catalog-row b{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.catalog-row span{font-size:12px;color:var(--faint)}
.catalog-row-actions{display:flex;gap:6px;align-items:center}
.finance-category-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
@media(max-width:1100px){.catalog-layout{columns:1}.catalog-card-list{max-height:230px}}
@media(max-width:760px){.catalog-subgrid,.finance-category-grid{grid-template-columns:1fr}}

.kpi{position:relative;background:var(--surface);border:1px solid var(--border);border-radius:var(--r);padding:17px 17px 15px;box-shadow:var(--shadow-sm);overflow:hidden;transition:transform .18s,box-shadow .18s,border-color .18s}
.kpi::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--kc,var(--accent)),transparent 85%)}
.kpi:hover{transform:translateY(-3px);box-shadow:var(--shadow);border-color:var(--border-2)}
.kpi-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
.kpi-ic{width:36px;height:36px;border-radius:10px;display:grid;place-items:center;background:var(--kc-soft,var(--accent-soft));color:var(--kc,var(--accent))}
.kpi-ic svg{width:18px;height:18px}
/* Manrope остаётся фирменной надписью: логотип и шапка входа. В числах плиток
   он был третьим шрифтом рабочего экрана — ради начертания, разницу которого
   на цифрах никто не различает. */
.kpi-val{font-weight:700;font-size:25px;letter-spacing:-.02em;line-height:1.1}
.kpi-lbl{font-size:12px;color:var(--muted);margin-top:3px}
.kpi-sub{font-size:12px;color:var(--faint);margin-top:6px}
.delta{display:inline-flex;align-items:center;gap:3px;font-size:12px;font-weight:700;padding:3px 8px;border-radius:20px}
.delta svg{width:13px;height:13px}
.delta.up{color:var(--good-ink);background:var(--good-soft)} .delta.down{color:var(--bad-ink);background:var(--bad-soft)}
.spark{width:100%;height:34px;display:block;margin-top:10px}

.panel{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);box-shadow:var(--shadow-sm);overflow:hidden}
.panel-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 18px;border-bottom:1px solid var(--border)}
.panel-title{display:flex;align-items:center;gap:11px}
.panel-ic{width:32px;height:32px;border-radius:9px;background:var(--accent-soft);color:var(--accent);display:grid;place-items:center}
.panel-ic svg{width:17px;height:17px}
.panel-title h3{font-size:14px;font-weight:700} .panel-title p{margin:1px 0 0;font-size:12px;color:var(--muted)}
.panel-actions{display:flex;gap:8px;align-items:center}
.panel-body{padding:18px}
.panel-body.pad-0{padding:0}
.chart-box{position:relative;width:100%}
.chart-fallback{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;height:100%;color:var(--faint);text-align:center;padding:20px}
.chart-fallback svg{width:30px;height:30px;opacity:.6}

/* ---------- Tables ---------- */
.table-wrap{overflow-x:auto}
/* ---------------- Телефон ----------------
   Таблица шире экрана — это не «прокрутите вбок», а «не увидите половину
   данных»: вбок никто не прокручивает, потому что не видно, что там что-то
   есть. На узком экране строка разворачивается карточкой, где у каждого
   значения написано, что это. Подписи проставляет tableLabelsApply(): брать
   их из заголовка таблицы дешевле, чем дописывать data-label в три десятка
   мест разметки, и новые таблицы получают раскладку сами. */
@media(max-width:640px){
  .table-wrap{overflow-x:visible}
  .crm-top-scroll{display:none!important}
  table.tbl,table.tbl tbody,table.tbl tr,table.tbl td{display:block;width:auto}
  table.tbl thead{display:none}
  table.tbl tr{border:1px solid var(--border);border-radius:12px;padding:10px 12px;margin:0 0 10px;background:var(--surface)}
  /* Подпись отдельной строкой СВЕРХУ, а не колонкой слева.
     Сетка в две колонки выглядела аккуратнее, но раскладывала по клеткам
     КАЖДОГО ребёнка ячейки — а здесь почти всюду их несколько: номер плюс
     подпись мелким, значение плюс полоса готовности. Второй ребёнок уезжал
     в первую колонку следующей строки и налезал на заголовок: «ЗАМОВЛЕННЯ /
     КЛІЄНТ» и имя клиента печатались друг на друге. Обёртки, которая сделала
     бы содержимое одним элементом, в разметке нет, а дописывать её в три
     десятка функций отрисовки — не тот размен. Подпись сверху устойчива к
     любому числу детей. */
  table.tbl td{border:none;padding:6px 0;display:block}
  table.tbl td:before{content:attr(data-label);display:block;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.05em;line-height:1.4;margin-bottom:3px}
  /* Пустая подпись — это колонка действий: заголовок ей не нужен. */
  table.tbl td[data-label='']:before{display:none}
  table.tbl td[colspan]{text-align:center}
  table.tbl td[colspan]:before{display:none}
  /* Выравнивание вправо имеет смысл в таблице: там числа стоят столбцом и
     сравниваются взглядом. В карточке столбца нет — подпись слева, значение
     улетает к правому краю, и текст читается «то в одной стороне, то в
     другой». Возвращаем всё к левому краю. */
  table.tbl td.t-right{text-align:left}
  /* Строки внутри ячейки не должны сливаться с подписью следующего поля. */
  table.tbl td+td{border-top:1px solid var(--border);padding-top:8px}
  /* Переключатель видов — «Канбан · Список · Календар · Завантаження ·
     Прострочені · Архів». Шесть кнопок одной строкой дают 514 пикселей при
     экране 393: вбок страницу тянул именно он, а не таблица. Разрешаем
     перенос; прятать половину кнопок в боковую прокрутку нельзя — их не
     найдут. */
  .seg{display:flex;flex-wrap:wrap}
  table.tbl td .row-actions{justify-content:flex-start}
}
/* Отступы под вырез и системную полосу. Появляются только там, где они есть:
   на обычном экране env() возвращает ноль. */
body{padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}
.content{padding-bottom:calc(18px + env(safe-area-inset-bottom))}
/* Мини-приложение открывается поверх шапки Telegram, поэтому верх сдвигаем. */
body.in-telegram .topbar{padding-top:env(safe-area-inset-top)}
/* Крестик «Выйти» в Telegram убираем.
   У Telegram свой крестик — закрыть приложение, — и он оказывается почти над
   нашим: значки одинаковые, а последствия разные. Один сворачивает окно,
   другой разлогинивает. Промахнулись в первый же день работы с телефона.
   Выход остаётся в разделе «Профиль», где его ищут осознанно. */
body.in-telegram #signOutBtn{display:none}

/* column-reverse: в разметке полоса идёт ПЕРЕД таблицей, а показывать её надо
   под ней. Так она может прилипнуть к низу экрана, а не к верху — сверху она
   накрывала первую строку, а без залипания вовсе уезжала из виду, и в середине
   длинного списка прокрутить вправо было нечем. */
.crm-scroll-sync{display:flex;flex-direction:column-reverse;min-width:0;width:100%}
/* В обычном положении полоса просто стоит в потоке НАД таблицей.
   Прежнее position:sticky;top:67px прилипало под верхнюю панель и ложилось
   поверх первой строки — она оказывалась наполовину закрыта. Прокрутку при
   уходе таблицы вниз берёт на себя режим is-floating, он для этого и есть,
   так что липкий вариант только дублировал его и мешал.
   position:static, а не relative: иначе оставшийся top из медиазапроса ниже
   сдвинул бы полосу вниз на те же 63 пикселя. */
/* position:static, а НЕ sticky. Панель вокруг таблицы имеет overflow:hidden,
   а прилипание внутри такого предка не работает — элемент просто обрезается,
   и полоса исчезала совсем. Уход полосы за нижний край экрана берёт на себя
   режим is-floating ниже, он для этого и есть. */
/* Этап в строке: цветная плашка видна, а поверх неё лежит невидимый список.
   Так сохраняется прежний вид таблицы и появляется возможность сменить этап
   одним движением, не открывая карточку. */
/* Плашка этапа обрезается многоточием, а не распирает колонку: «Комерційна
   пропозиція» просила 206px при 150 доступных, и таблица переставала
   помещаться. Цвет и начало слова этап опознают; целиком он виден в карточке. */
.crm-stage-cell{position:relative;display:inline-block;max-width:100%;min-width:0}
.crm-stage-cell .pill{max-width:100%;overflow:hidden;text-overflow:ellipsis;display:inline-flex}
.crm-stage-sel{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:0;padding:0}
/* Только там, где наведение вообще есть. На сенсорном экране :hover ЗАЛИПАЕТ
   после касания, и обводка оставалась висеть у плашки этапа — тот самый
   грязный край рядом с кнопкой правки. По контуру она идёт и так: обёртка
   ровно по плашке, замерено 101 в 101. */
@media(hover:hover){
  .crm-stage-cell:hover{outline:2px solid var(--accent-soft);outline-offset:2px;border-radius:20px}
}
/* Кнопка отправки сообщения клиенту. Цвет намеренно отличается и от
   «Сохранить», и от остальных: это единственное действие в карточке, которое
   уходит наружу, живому человеку, и отменить его нельзя. */
.btn.btn-notify{background:var(--good,#1f7a45);border-color:var(--good,#1f7a45);color:#fff;font-weight:600}
.btn.btn-notify:hover{filter:brightness(1.08)}
.btn.btn-notify:disabled,.btn.btn-notify.is-busy{opacity:.6;cursor:default;filter:none}
.btn.btn-notify svg{opacity:.95}
/* Отметка о привязанном боте в карточке сделки. */
.dealcomm-bound{display:inline-flex;align-items:center;gap:3px;padding:1px 7px;border-radius:20px;background:var(--good-soft,#e6f6ec);color:var(--good,#1f7a45);font-size:12px;font-weight:700}
/* Выбор колонок таблицы сделок. */
.crm-cols{position:relative}
.crm-cols-menu{display:none;position:absolute;right:0;top:calc(100% + 6px);z-index:40;min-width:210px;padding:8px;border:1px solid var(--border);border-radius:11px;background:var(--surface);box-shadow:var(--shadow)}
.crm-cols-menu.on{display:block}
.crm-col-opt{display:flex;align-items:center;gap:8px;padding:5px 7px;border-radius:8px;font-size:12px;cursor:pointer}
.crm-col-opt:hover{background:var(--surface-2)}
.crm-col-opt.locked{cursor:default;opacity:.72}
.crm-col-opt i{margin-left:auto;font-style:normal;font-size:12px;color:var(--faint)}
/* Плотный вид для таблиц производства и монтажа.
 *
 * В обеих почти каждая ячейка двухэтажная: номер и договор, клиент и телефон,
 * изделие и адрес, срок и ответственный, а под этапом ещё и полоса готовности.
 * Из-за этого строка занимала под сорок пикселей, и на экран помещалось семь
 * записей — при том что заказов в работе два десятка.
 *
 * Убираем не данные, а воздух: вторая строка мельче и прижата к первой, полоса
 * готовности тоньше и без отступа. Всё, что было видно, видно и сейчас — просто
 * на экран теперь помещается вдвое больше. */
.tbl-compact td{padding:6px 12px}
.tbl-compact th{padding:7px 12px}
.tbl-compact td .hint{font-size:12px;line-height:1.3;margin-top:2px}
.tbl-compact td>div[style*="margin-top:6px"]{margin-top:3px!important;width:96px!important}
.tbl-compact .progress{height:5px}
.tbl-compact .badge,.tbl-compact .pill{padding-top:1px;padding-bottom:1px}
/* Стрелки показа колонок в шапке — в той клетке, что раньше пустовала. */
/* Обёртка фильтров: на широком экране её как будто нет — display:contents
   отдаёт поля прямо в панель, раскладка остаётся прежней. Сворачивание
   включается только на телефоне (см. медиазапрос). */
/* Короткая дата и словесная подпись у чисел — только для узкого экрана:
   в таблице колонка уже подписана заголовком, там это было бы дублем. */
.date-short{display:none}
.unit-word{display:none}
.crm-filters{display:contents}
/* Фильтры производства: на широком экране лежат в строке как были, на узком
   прячутся под кнопку со счётчиком включённых. Приём и классы поведения те же,
   что в CRM, — человек, привыкший к одному разделу, не переучивается в другом. */
.prod-filters{display:contents}
.prod-filters-toggle{display:none}
.prod-filters-count{display:none;min-width:17px;height:17px;padding:0 5px;border-radius:99px;
  background:var(--accent);color:#fff;font-size:12px;font-weight:700;line-height:17px;text-align:center;margin-left:6px}
.prod-filters-count.on{display:inline-block}
.prod-filters-toggle.has-active{border-color:var(--accent);color:var(--accent-ink)}
.crm-filters-toggle{display:none}
.crm-filters-count{display:none;min-width:17px;height:17px;padding:0 5px;border-radius:99px;
  background:var(--accent);color:#fff;font-size:12px;font-weight:700;line-height:17px;text-align:center;margin-left:6px}
.crm-filters-count.on{display:inline-block}
.crm-filters-toggle.has-active{border-color:var(--accent);color:var(--accent-ink)}
.crm-colnav{display:flex;gap:4px;align-items:center}
.crm-colnav .btn{padding:0;width:30px;justify-content:center}
.crm-colnav .btn:disabled{opacity:.35;cursor:default}
/* Подпись для чтения с экрана: заголовок колонки действий пустой визуально,
   но без текста строка таблицы теряет смысл при озвучивании. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* Кнопки строки закреплены у правого края: раньше до них надо было доезжать
   прокруткой в самый конец, а это самое частое действие в таблице. */
.crm-tbl .crm-act-th,.crm-tbl .crm-act-td{position:sticky;right:0;z-index:2;background:var(--surface);box-shadow:-8px 0 12px -10px rgba(0,0,0,.4)}
.crm-tbl tbody tr:hover .crm-act-td{background:var(--surface-2)}

/* ---------- КЛИК ПО СТРОКЕ CRM ----------

   Строка открывается целиком, поэтому она обязана выглядеть нажимаемой:
   курсор-палец и заметная подсветка под курсором. Без этого человек не
   догадается, что можно не целиться в карандаш.

   Ячейка действий исключена из курсора: там свои кнопки, и палец над ними
   обещал бы не то. */
.crm-tbl tbody tr.crm-row{cursor:pointer}
/* Строка-ссылка: щелчок открывает карточку. Один вид на все разделы —
   телефонию, производство, монтаж, доставку, склад, — чтобы приём узнавался
   без объяснений, куда бы человек ни зашёл. */
tr.row-open{cursor:pointer}
tr.row-open:hover{background:var(--surface-2)}
tr.row-open:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
/* Внутри кнопок курсор свой: там щелчок делает другое. */
tr.row-open .row-actions{cursor:default}
.crm-tbl tbody tr.crm-row .crm-act-td{cursor:default}
.crm-tbl tbody tr.crm-row:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

/* Отклик на нажатие. Строку нельзя двигать transform — таблица тут же
   поедет колонками, — поэтому отклик даётся цветом: короткая вспышка
   акцентом и возврат. Полторы десятых секунды: этого хватает, чтобы глаз
   заметил, и мало, чтобы задержать открытие карточки. */
@keyframes crm-tap{
  0%{background-color:var(--accent-soft)}
  60%{background-color:var(--accent-soft)}
  100%{background-color:transparent}
}
.crm-tbl tbody tr.tap>td{animation:crm-tap .34s ease-out}

/* Выбранная строка остаётся отмеченной, пока не выберут другую: вернувшись
   из карточки, человек должен увидеть, где остановился. Отметка сделана
   фоном и утолщённой полосой сегмента слева — не рамкой: рамка сдвинула бы
   содержимое ячеек на свою ширину и строка дёрнулась бы. */
.crm-tbl tbody tr.picked>td{background:color-mix(in srgb,var(--accent) 7%,transparent)}
.crm-tbl tbody tr.picked>td:first-child{box-shadow:inset 4px 0 0 var(--seg)}
.crm-tbl tbody tr.picked .crm-act-td{background:color-mix(in srgb,var(--accent) 7%,var(--surface))}

/* Кому анимация мешает — не показываем её вовсе. */
@media(prefers-reduced-motion:reduce){
  .crm-tbl tbody tr.tap>td{animation:none}
}
.crm-comment{display:inline-block;max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom;color:var(--muted)}
.crm-top-scroll{position:static;overflow-x:auto;overflow-y:hidden;height:14px;background:var(--surface-2);border-top:1px solid var(--border)}
/* position:fixed, а не sticky: только он выживает внутри .panel с
   overflow:hidden. left и width задаёт JS по фактическому положению таблицы. */
.crm-top-scroll.is-floating{position:fixed;right:auto;bottom:0;top:auto!important;z-index:35;border:1px solid var(--border);border-bottom:0;border-radius:10px 10px 0 0;box-shadow:0 -10px 24px -16px rgba(15,23,42,.55)}
.crm-top-scroll-inner{height:1px}
.crm-top-scroll::-webkit-scrollbar{height:10px}
.crm-table-scroll{border-top:0;max-width:100%;overflow-x:auto;scrollbar-gutter:stable}
table.tbl{width:100%;border-collapse:collapse;font-size:14px}
table.tbl th{position:sticky;top:0;text-align:left;font-weight:600;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:9px 13px;background:var(--surface-2);border-bottom:1px solid var(--border);white-space:nowrap}
table.tbl th.sortable{cursor:pointer;user-select:none}
table.tbl th.sortable:hover{color:var(--accent-ink)}
/* Стрелка сортировки.
   Сначала она была почти прозрачной, потом я поменял прозрачность, но знак
   остался прежним — «↕», а он в этом шрифте рисуется тонкой чёрточкой и на
   стрелку не похож вовсе. Теперь везде один и тот же треугольник, который
   заведомо рисуется: у неотсортированной колонки он бледный и смотрит вниз,
   у отсортированной — яркий, цветной и показывает направление. */
table.tbl th .sort-ar{opacity:.42;font-size:9px;margin-left:5px;display:inline-block;vertical-align:1px}
table.tbl th:hover .sort-ar{opacity:.8}
table.tbl th.sorted .sort-ar{opacity:1;font-size:12px}
table.tbl th.sorted .sort-ar{opacity:1;color:var(--accent-ink)}
/* Основной текст ячейки тёмный. Серым остаются только подписи под значением
   (.hint): раньше серого было больше, чем тёмного, и зацепиться было не за
   что. */
table.tbl td{padding:9px 13px;border-bottom:1px solid var(--border);color:var(--text);white-space:nowrap}

/* Отступы в таблице сделок уже, чем в остальных.
 *
 * ЗАЧЕМ. Замер на боевых данных: таблице нужно 1387px, а на экране 1296 —
 * не хватало 91. При этом на боковые отступы ячеек уходило 234px: по 13px с
 * каждой стороны на девять колонок. Колонка «Сумма» вылезала за край и
 * читалась как «152 00» — та самая цифра, ради которой в таблицу и смотрят.
 *
 * 13px → 8px возвращает 90px (9 колонок × 10px) и закрывает нехватку почти
 * целиком, не трогая размер шрифта и высоту строки. Правило ограничено
 * .crm-tbl: в остальных таблицах колонок меньше и теснить их незачем.
 *
 * ПОЧЕМУ ИМЕННО ЗДЕСЬ, А НЕ ВЫШЕ. Вес селектора совпадает с базовым
 * `table.tbl td`, поэтому решает порядок в файле. Стояло выше — базовое
 * правило перебивало, и padding-right оставался 13px при уже применённом
 * padding-left. Место сразу после базового — обязательное условие. */
table.crm-tbl th,table.crm-tbl td{padding-left:8px;padding-right:8px}
table.crm-tbl th:first-child,table.crm-tbl td:first-child{padding-left:14px}
/* CRM должна помещать рабочий набор колонок на обычном ноутбуке, но не
 * сжимать текст до нечитаемых обрезков, когда пользователь включает все
 * дополнительные поля. Ширины задаёт CRM_COLUMNS, а --crm-min растёт вместе
 * с числом видимых колонок: базовый набор занимает экран, расширенный честно
 * прокручивается внутри таблицы, не растягивая всю страницу. */
table.crm-tbl{table-layout:fixed;min-width:var(--crm-min,1410px)}

table.crm-tbl th,table.crm-tbl td{box-sizing:border-box}
.crm-client-cell{display:flex;align-items:center;gap:5px;min-width:0;max-width:100%}
.crm-client-cell>.t-strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm-ellipsis{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
table.crm-tbl td[data-k="phone"],table.crm-tbl td[data-k="source"],table.crm-tbl td[data-k="product"],table.crm-tbl td[data-k="comment"]{overflow:hidden;text-overflow:ellipsis}
table.crm-tbl td[data-k="manager"] .who{max-width:100%;min-width:0}
table.crm-tbl td[data-k="manager"] .who .t-strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.crm-tbl .crm-act-th,.crm-tbl .crm-act-td{width:78px;min-width:78px;max-width:78px}
/* На телефоне CRM превращается в карточки общим правилом выше. Десктопная
 * минимальная ширина не должна пережить это превращение и растянуть страницу
 * на 1400+ пикселей. Правило стоит после десктопных размеров намеренно. */
@media(max-width:640px){
  .crm-table-scroll{overflow-x:visible;scrollbar-gutter:auto}
  table.crm-tbl{width:100%;min-width:0;table-layout:auto}
}
table.tbl tbody tr{transition:background .12s}
table.tbl tbody tr:hover{background:var(--surface-2)}
table.tbl tbody tr:last-child td{border-bottom:none}
.t-strong{color:var(--text);font-weight:600}
.t-right{text-align:right}
table.tbl th.t-right{text-align:right}
.row-actions{display:flex;gap:6px;opacity:.35;transition:opacity .15s}
tr:hover .row-actions{opacity:1}
.mini-btn{position:relative;width:28px;height:28px;border-radius:7px;border:1px solid var(--border);background:var(--surface);display:grid;place-items:center;color:var(--muted)}
/* Зона нажатия шире самой кнопки, размеры при этом не меняются: увеличение
   кнопок до 36px разъехало бы ряды действий в таблицах всех разделов.
   32px даёт запас и при этом не перекрывает соседнюю кнопку (зазор 3px). */
.mini-btn::after{content:"";position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:32px;height:32px;border-radius:9px}

/* Видимый фокус для клавиатуры. Срабатывает только при управлении с
   клавиатуры (:focus-visible), поэтому клик мышью кольцо не рисует.
   Раньше в системе не было ни одного правила фокуса — перемещение по Tab
   было невидимым. */
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.chat-item:focus-visible,.chat-tab:focus-visible,.chat-quote:focus-visible,.chat-info-pin:focus-visible,.chat-info-file:focus-visible{outline-offset:-2px}
.chat-composer:focus-within textarea:focus-visible{outline:none}
.mini-btn svg{width:14px;height:14px}
.mini-btn:hover{color:var(--accent-ink);border-color:var(--accent)}
.mini-btn.del:hover{color:var(--bad-ink);border-color:var(--bad-ink)}

.pill{display:inline-flex;align-items:center;gap:6px;font-size:14px;font-weight:600;padding:4px 10px;border-radius:20px;
  color:color-mix(in srgb,var(--c,var(--accent)) 55%,#000);
  background:color-mix(in srgb,var(--c,var(--accent)) 13%,transparent);white-space:nowrap}
.pill .pd{width:6px;height:6px;border-radius:50%;background:var(--c,var(--accent))}
/* Плашка состояния — значение: «Прострочення 22 дн.» это то, ради чего
   строку читают. Кегль подписи ей не по чину. */
.badge{display:inline-flex;align-items:center;gap:5px;font-size:14px;font-weight:600;padding:3px 9px;border-radius:7px}
.badge.g{color:var(--good-ink);background:var(--good-soft)} .badge.y{color:var(--warn-ink);background:var(--warn-soft)}
.badge.r{color:var(--bad-ink);background:var(--bad-soft)}
/* Срочность — заливка, просрочка — приглушённая плашка. Одинаковые красные
   прямоугольники сливались в один сигнал, и чтобы отличить «нас торопят» от
   «мы опоздали», приходилось читать текст. */
.badge.is-rush{color:#fff;background:var(--bad-ink)}
/* Плашка состояния не переносится: перенос делал её вдвое выше строки, и
   красная плита перевешивала имя клиента — смысловым центром становилась она.
   Слово «Прострочення» из текста убрано, осталось число дней: колонка так и
   называется «Стан», повторять её название в каждой ячейке незачем. */
table.tbl td .badge{white-space:normal}
table.tbl td .badge.is-rush{align-items:flex-start} .badge.b{color:var(--info-ink);background:var(--info-soft)}
.badge.n{color:var(--muted);background:var(--surface-3)}
/* Прочерк вместо плашки: значение обычное, новости нет. */
.tbl-none{color:var(--faint)}
/* Вторая строка в ячейке бывает двух родов, и раньше обе шли через .hint.
   Подпись (договор, телефон) поясняет значение сверху — ей кегль подписи.
   Значение (готовность, ответственный) отвечает на свой вопрос — ему основной
   кегль и приглушённый цвет, чтобы не спорить с первой строкой. */
table.tbl td .tbl-val{font-size:14px;color:var(--muted);line-height:1.3;margin-top:2px}
/* Просроченный срок виден в своей же ячейке, а не только плашкой сбоку.
   Селектор с table впереди: правило table.tbl td задаёт цвет и без этого веса
   перебивает класс — дата оставалась тёмной, как у непросроченного заказа. */
table.tbl td.tbl-late{color:var(--bad-ink);font-weight:600}
/* Номер заказа опознают, а не читают: вес 700 делал его вторым центром строки
   наравне с именем клиента, и глазу было не за что зацепиться первым. */
.tbl-id{font-weight:400;color:var(--text-2)}
/* Сегмент клиента здесь нужен, а цвет в строке уже занят состоянием заказа:
   буква остаётся, окраска гасится, чтобы не спорить с просрочкой. */
.seg-quiet .seg-dot{--seg:var(--muted)!important;background:var(--surface-3);color:var(--muted)}
.who.is-quiet .avatar{background:var(--surface-3);color:var(--muted);box-shadow:inset 0 0 0 1px var(--border)}
/* Восемь колонок должны поместиться в область без горизонтальной прокрутки:
   про неё ничто не сообщает, и человек её не ищет. Поэтому длинные значения
   переносятся, а не растягивают таблицу. */
/* Селектор с table впереди намеренно: правило table.tbl td задаёт nowrap и
   без этого веса перебивает перенос — текст этапа наезжал на соседнюю колонку.

   Девятая колонка «1С» дописывается в готовую таблицу уже на странице
   (productionSyncTableBadges), поэтому её ширина учтена здесь: без этого сумма
   долей давала перебор, и таблица снова не помещалась. */
@media(min-width:641px){
  table.prod-tbl{table-layout:fixed}
  table.prod-tbl td,table.prod-tbl th{white-space:normal;overflow-wrap:anywhere;vertical-align:top}
  table.prod-tbl td .pill{max-width:100%;overflow:hidden;text-overflow:ellipsis;display:inline-flex}
  table.prod-tbl th:nth-child(1),table.prod-tbl td:nth-child(1){width:10%}
  table.prod-tbl th:nth-child(2),table.prod-tbl td:nth-child(2){width:14%}
  table.prod-tbl th:nth-child(3),table.prod-tbl td:nth-child(3){width:11%}
  table.prod-tbl th:nth-child(4),table.prod-tbl td:nth-child(4){width:12%}
  table.prod-tbl th:nth-child(5),table.prod-tbl td:nth-child(5){width:10%}
  table.prod-tbl th:nth-child(6),table.prod-tbl td:nth-child(6){width:8%}
  table.prod-tbl th:nth-child(7),table.prod-tbl td:nth-child(7){width:13%}
  table.prod-tbl th:nth-child(8),table.prod-tbl td:nth-child(8){width:9%}
  table.prod-tbl th:nth-child(9),table.prod-tbl td:nth-child(9){width:10%}
  table.prod-tbl th:nth-child(10),table.prod-tbl td:nth-child(10){width:3%}
}
.onec-sync-indicator{display:inline-grid;place-items:center;width:22px;height:22px;box-sizing:border-box;border:1px solid currentColor;border-radius:50%;vertical-align:middle;cursor:help;flex:none;background:var(--surface);color:var(--muted)}
.onec-sync-indicator svg{width:12px;height:12px;stroke-width:2.4}
.onec-sync-indicator.g{color:var(--good-ink);background:var(--good-soft)}
.onec-sync-indicator.y{color:var(--warn-ink);background:var(--warn-soft)}
.onec-sync-indicator.r{color:var(--bad-ink);background:var(--bad-soft)}
.onec-sync-indicator.b{color:var(--info-ink);background:var(--info-soft)}
.onec-sync-indicator.n{color:var(--muted);background:var(--surface-3)}
.onec-sync-detail{display:inline-flex;align-items:center;gap:7px;flex-wrap:wrap}
.onec-sync-detail>.hint{margin:0}
.onec-sync-alert{display:flex;align-items:flex-start;gap:10px;margin:0 0 14px;padding:10px 12px;border:1px solid var(--warn);border-left-width:4px;background:var(--warn-soft);color:var(--text);font-size:12px;line-height:1.4}
.onec-sync-alert.critical{border-color:var(--bad-ink);background:var(--bad-soft)}
.onec-sync-alert>svg{width:18px;height:18px;flex:none;color:var(--warn-ink);margin-top:1px}
.onec-sync-alert.critical>svg{color:var(--bad-ink)}
.onec-sync-alert b{display:block;margin-bottom:2px}
.onec-sync-alert p{margin:0;color:var(--text-2)}
.crm-demo-tag{font-size:9px;font-weight:700;letter-spacing:.06em;padding:1px 5px;border-radius:5px;vertical-align:middle}

/* ---------- Что нового (хронология) ---------- */
.cl-list{display:grid;gap:4px}
.cl-day{display:grid;grid-template-columns:190px minmax(0,1fr);gap:18px;padding:0 0 6px;position:relative}
/* Отметка «ознакомлен» под каждой записью. */
.cl-read{display:flex;align-items:center;gap:12px;margin-top:12px;padding-top:11px;border-top:1px solid var(--border)}
.cl-read-done{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;color:var(--good-ink)}
.cl-read-stat{margin-left:auto}
.cl-date{display:flex;align-items:center;gap:9px;padding:14px 0 0;font-size:14px;color:var(--text-2);position:sticky;top:0;align-self:start}
.cl-date b{font-weight:700}
.cl-dot{width:11px;height:11px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 4px var(--accent-soft);flex:none}
/* Вертикальная линия хронологии слева от записей */
.cl-entries{display:grid;gap:12px;border-left:2px solid var(--border);padding:14px 0 14px 20px}
.cl-entry{border:1px solid var(--border);border-radius:14px;background:var(--surface);padding:14px 16px;box-shadow:var(--shadow-sm)}
.cl-entry-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.cl-entry-head b{font-size:14px}
.cl-summary{margin:8px 0 0;font-size:14px;color:var(--muted);line-height:1.5}
.cl-items{list-style:none;margin:10px 0 0;padding:0;display:grid;gap:6px}
.cl-items li{display:flex;gap:8px;align-items:flex-start;font-size:14px;color:var(--text-2);line-height:1.45}
.cl-items li svg{width:14px;height:14px;color:var(--good-ink);flex:none;margin-top:2px}
@media(max-width:820px){
  .cl-day{grid-template-columns:1fr;gap:0}
  .cl-date{position:static;padding:16px 0 8px}
  .cl-entries{border-left:0;padding:0 0 10px}
}

/* ---------- Чат ---------- */
/* Высота: панель тянется от низа заголовка страницы до низа окна. Смещение
   измеряется в chatFitHeight(), потому что высота шапки зависит от переноса
   строк и масштаба — константа сломалась бы на другом экране. Значение в
   --chat-h ставит JS, а min(76vh,760px) остаётся страховкой до его первого
   запуска. */
.chat-layout{position:relative;display:grid;grid-template-columns:minmax(0,var(--chat-side,300px)) minmax(0,1fr);height:var(--chat-h,min(76vh,760px));overflow:hidden}
/* Третья колонка появляется только когда панель открыта: держать пустой
   столбец в сетке — значит без нужды сужать переписку. */
.chat-layout.has-info{grid-template-columns:minmax(0,var(--chat-side,300px)) minmax(0,1fr) var(--chat-info,340px)}
.chat-info{display:none;border-left:1px solid var(--border);background:var(--surface);min-height:0;overflow:hidden;flex-direction:column}
.chat-layout.has-info .chat-info{display:flex;animation:chatInfoIn .18s ease-out}
@keyframes chatInfoIn{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.chat-layout.has-info .chat-info{animation:none}}
.chat-info-head{flex:none;display:flex;align-items:center;gap:10px;padding:11px 14px;border-bottom:1px solid var(--border)}
.chat-info-head b{font-size:14px}
.chat-info-head .mini-btn{margin-left:auto;width:28px;height:28px}
.chat-info-body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:14px}
.chat-info-hero{display:grid;justify-items:center;gap:8px;text-align:center;padding:6px 0 14px;border-bottom:1px solid var(--border)}
.chat-info-hero .chat-ava{width:62px;height:62px;font-size:19px}
.chat-info-hero .chat-ava svg{width:26px;height:26px}
.chat-info-hero b{font-size:14px}
.chat-info-hero span{font-size:12px;color:var(--muted)}
.chat-info-sec{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);margin:15px 0 7px}
.chat-info-desc{font-size:12px;line-height:1.5;color:var(--text-2)}
.chat-info-row{display:flex;align-items:center;gap:9px;padding:6px 0;font-size:12px}
.chat-info-row .chat-ava{width:29px;height:29px;font-size:12px}
.chat-info-row i{font-style:normal;margin-left:auto;font-size:12px;color:var(--faint)}
.chat-info-row i.adm{color:var(--accent-ink);font-weight:700}
.chat-info-empty{font-size:12px;color:var(--faint);padding:3px 0}
.chat-info-card{display:grid;gap:5px;border:1px solid var(--border);border-radius:11px;padding:10px 11px;background:var(--surface-2)}
.chat-info-card b{font-size:12px}
.chat-info-card .kvp{display:flex;gap:8px;font-size:12px;color:var(--muted)}
.chat-info-card .kvp span{margin-left:auto;color:var(--text-2);text-align:right}
.chat-info-file{display:flex;align-items:center;gap:8px;width:100%;text-align:left;font-size:12px;color:var(--text-2);border:1px solid var(--border);border-radius:9px;background:var(--surface);padding:7px 9px;margin-bottom:5px}
.chat-info-file:hover{border-color:var(--accent)}
.chat-info-file span{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-info-file i{font-style:normal;font-size:12px;color:var(--faint);flex:none}
.chat-info-pin{display:block;width:100%;text-align:left;font-size:12px;color:var(--text-2);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:0 9px 9px 0;background:var(--surface);padding:6px 9px;margin-bottom:5px}
.chat-info-pin:hover{background:var(--surface-2)}
/* Узкий экран: панель ложится поверх переписки, а не сужает её до нечитаемого. */
@media(max-width:1200px){
  .chat-layout.has-info{grid-template-columns:minmax(0,var(--chat-side,300px)) minmax(0,1fr)}
  .chat-layout.has-info .chat-info{position:absolute;top:0;right:0;bottom:0;width:min(340px,86vw);z-index:20;box-shadow:var(--shadow-lg)}
}
@media(max-width:900px){.chat-layout.has-info .chat-info{width:100%}}
@media(min-width:1600px){.chat-layout{--chat-side:310px}}
@media(max-width:1340px){.chat-layout{--chat-side:266px}}
.chat-side{border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;min-height:0}
/* Вкладки и поиск закреплены сверху, прокручивается только список: иначе
   поле поиска уезжало бы вместе с диалогами. */
.chat-side-top{flex:none;padding:9px 9px 8px;border-bottom:1px solid var(--border);background:var(--surface)}
.chat-find{position:relative;display:flex;align-items:center;margin-top:7px}
.chat-find>svg{position:absolute;left:9px;width:15px;height:15px;color:var(--faint);pointer-events:none}
.chat-find input{width:100%;padding:7px 30px 7px 30px;border:1px solid var(--border);border-radius:9px;background:var(--surface-2);color:var(--text);font-family:inherit;font-size:12px;outline:none;transition:border-color .16s ease-out,box-shadow .16s ease-out,background .16s ease-out}
.chat-find input::-webkit-search-cancel-button{display:none}
.chat-find input:focus{background:var(--surface);border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.chat-find-clear{display:none;position:absolute;right:4px;width:22px;height:22px;border-radius:6px}
.chat-find.has-q .chat-find-clear{display:grid;place-items:center}
.chat-list{flex:1;min-height:0;overflow-y:auto;padding:8px;overscroll-behavior:contain}
/* Вкладки-папки над списком */
/* Одна строка с горизонтальной прокруткой: перенос делал последнюю вкладку
   «сиротой» на второй строке, а пользовательских папок может быть много. */
.chat-tabs{display:flex;flex-wrap:nowrap;gap:4px;padding-right:2px;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}
/* Затухание у правого края включается только когда ряд действительно не
   помещается: обрезанная вкладка без него читается как поломка вёрстки,
   а не как подсказка «здесь можно прокрутить». */
.chat-tabs.scrollable{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 18px),transparent);mask-image:linear-gradient(90deg,#000 calc(100% - 18px),transparent)}
.chat-tabs::-webkit-scrollbar{height:0}
/* Ряд вкладок со стрелками по краям. Кнопки лежат поверх ряда, а не отнимают
   у него ширину: иначе при трёх вкладках, которые и так помещаются, полоса
   без нужды сжималась бы на 44 пикселя. */
.chat-tabs-wrap{position:relative}
.chat-tabs-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:2;display:none;align-items:center;justify-content:center;width:22px;height:22px;border-radius:50%;border:1px solid var(--border);background:var(--surface);color:var(--muted);box-shadow:0 1px 5px rgba(0,0,0,.16);cursor:pointer;padding:0}
.chat-tabs-nav.on{display:flex}
.chat-tabs-nav:hover{color:var(--text);border-color:var(--accent)}
.chat-tabs-nav.prev{left:-4px}
.chat-tabs-nav.next{right:-4px}
.chat-tabs-wrap:has(.chat-tabs-nav.prev.on) .chat-tabs{padding-left:20px}
.chat-tabs-wrap:has(.chat-tabs-nav.next.on) .chat-tabs{padding-right:20px}
.chat-tab{display:inline-flex;align-items:center;gap:5px;flex:none;white-space:nowrap;font-size:12px;font-weight:600;color:var(--muted);background:var(--surface-2);border:1px solid var(--border);border-radius:20px;padding:4px 7px}
.chat-tab:hover{color:var(--text)}
.chat-tab.active{color:#fff;background:var(--accent);border-color:var(--accent)}
.chat-tab i{font-style:normal;font-size:12px;font-weight:700;background:var(--bad);color:#fff;border-radius:10px;padding:0 5px}
.chat-tab.active i{background:rgba(255,255,255,.28)}
/* Заголовок секции: группы и личные не должны сливаться в один поток */
.chat-sec{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--faint);padding:10px 8px 4px}
.chat-item-wrap{position:relative;display:flex;align-items:center;border:1px solid transparent;border-radius:11px;margin-bottom:3px;transition:background .16s ease-out,border-color .16s ease-out}
.chat-item-wrap:hover{background:var(--surface-2)}
/* Выбранный чат: мягкая заливка и левый индикатор вместо насыщенной рамки. */
.chat-item-wrap.active{background:var(--accent-soft);border-color:transparent}
.chat-item-wrap.active::before{content:"";position:absolute;left:0;top:9px;bottom:9px;width:3px;border-radius:0 3px 3px 0;background:var(--accent)}
.chat-item-wrap.active .chat-item-body b{color:var(--accent-ink)}
@media (prefers-reduced-motion:reduce){.chat-item-wrap,.chat-find input{transition:none}}
.chat-item-tools{display:none;gap:3px;padding-right:7px}
.chat-item-wrap:hover .chat-item-tools{display:flex}
.chat-item-tools .mini-btn{width:24px;height:24px;border-radius:6px}
/* Круглый аватар — человек, квадратная плашка — группа/отдел */
.chat-ava{width:41px;height:41px;flex:none;display:grid;place-items:center;border-radius:50%;background:var(--bronze);color:#fff;font-size:14px;font-weight:700;font-family:'Manrope'}
.chat-ava.group{border-radius:12px;background:var(--accent-soft);color:var(--accent-ink);border:1px solid var(--accent)}
/* Отдел и рабочая группа отличаются от обычной группы, иначе список
   превращается в ряд одинаковых квадратов. */
.chat-ava.dept{background:var(--surface-3);color:var(--text-2);border-color:var(--border)}
.chat-ava.ent{background:var(--warn-soft);color:var(--warn-ink);border-color:var(--warn-ink)}
.chat-ava svg{width:18px;height:18px}
/* Кучка чатов одного вида. Рамка нужна не ради красоты: без неё подписи
   читаются как ещё одна строка списка, а не как то, что его делит. */
.chat-pack{margin:6px 8px 10px;border:1px solid var(--border);border-radius:12px;
  background:var(--surface);overflow:hidden}
.chat-pack-head{display:flex;align-items:center;gap:8px;padding:8px 12px;
  background:var(--surface-2);border-bottom:1px solid var(--border);
  font-size:12px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.chat-pack-head span{margin-left:auto;font-weight:700;color:var(--muted);
  background:var(--surface-3);border-radius:999px;padding:1px 8px;letter-spacing:0}
.chat-pack .chat-item-wrap:last-child .chat-item{border-bottom:0}
.chat-item-folder{display:inline-block;font-size:12px;font-weight:700;letter-spacing:.03em;color:var(--muted);background:var(--surface-3);border-radius:5px;padding:1px 5px;margin-left:6px;vertical-align:middle}
.chat-item-body b svg{color:var(--accent);margin-right:3px;vertical-align:-1px}
.chat-item{display:flex;gap:11px;align-items:center;flex:1;min-width:0;text-align:left;padding:9px 10px;border:0;border-radius:11px;background:transparent;color:var(--text)}
.chat-item-body{flex:1;min-width:0;display:grid;gap:2px}
.chat-item-body b{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-item-last{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-item-meta{display:flex;flex-direction:column;align-items:flex-end;gap:5px;font-size:12px;color:var(--faint);flex:none}
.chat-dot{width:8px;height:8px;border-radius:50%;background:var(--accent);display:block}
.chat-count{min-width:18px;text-align:center;font-size:12px;font-weight:700;color:#fff;background:var(--accent);border-radius:20px;padding:1px 6px}
.chat-count.has-mention{background:var(--bad)}
.nav-badge.has-mention{background:var(--bad);color:#fff}
.chat-mention{font-weight:700;color:var(--accent-ink)}
.chat-mention.me{background:var(--warn-soft);color:var(--warn-ink);border-radius:5px;padding:0 3px}
.chat-mention-pop{position:absolute;bottom:100%;left:56px;right:auto;z-index:60;min-width:220px;display:grid;gap:2px;background:var(--surface);border:1px solid var(--border);border-radius:11px;padding:6px;box-shadow:var(--shadow-lg);margin-bottom:6px}
.chat-mention-pop button{display:flex;align-items:center;justify-content:space-between;gap:10px;text-align:left;font-size:14px;color:var(--text);border:0;background:transparent;border-radius:8px;padding:6px 8px}
.chat-mention-pop button:hover{background:var(--surface-2)}
.chat-mention-pop i{font-style:normal;font-size:12px;color:var(--faint)}
.chat-main{display:flex;flex-direction:column;min-width:0;min-height:0;overflow:hidden}
.chat-head{flex:none;padding:11px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;gap:12px}
.chat-head-who{display:flex;align-items:center;gap:11px;min-width:0}
.chat-head-txt{min-width:0}
.chat-head-txt b{display:block;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-head-sub{margin-top:1px;font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-system{align-self:center;font-size:12px;color:var(--muted);background:var(--surface-2);border:1px solid var(--border);border-radius:20px;padding:3px 12px;margin:2px 0}
.chat-head-tools{display:flex;align-items:center;gap:8px}
/* margin-left:auto прижимает поиск к правой группе: после выноса из блока
   кнопок он иначе встаёт по центру шапки (space-between на трёх элементах). */
.chat-search{margin-left:auto;display:flex;align-items:center;gap:4px;border:1px solid var(--border);border-radius:10px;background:var(--surface);padding:2px 6px}
.chat-search input{border:0;background:transparent;color:var(--text);font-size:12px;outline:none;width:170px;padding:5px 2px}
.chat-pinned{display:flex;gap:8px;overflow-x:auto;padding:8px 16px;border-bottom:1px solid var(--border);background:var(--surface-2)}
.chat-pin-item{display:flex;align-items:center;gap:6px;flex:none;max-width:320px;font-size:12px;color:var(--text-2);background:var(--surface);border:1px solid var(--border);border-radius:9px;padding:5px 9px}
.chat-pin-item span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-pin-item svg{color:var(--accent);flex:none}
.chat-msg{position:relative}
.chat-actions{display:none;position:absolute;top:-13px;gap:2px;background:var(--surface);border:1px solid var(--border);border-radius:9px;padding:2px 3px;box-shadow:var(--shadow-sm);z-index:5}
.chat-msg:not(.mine) .chat-actions{left:8px}
.chat-msg.mine .chat-actions{right:8px}
.chat-msg:hover .chat-actions{display:flex}
.chat-actions .mini-btn{font-size:14px;line-height:1}
.chat-quote{display:grid;gap:2px;text-align:left;width:100%;border-left:3px solid var(--accent);background:var(--surface);border-radius:0 9px 9px 0;padding:5px 9px;margin-bottom:4px;transition:background .16s ease-out}
.chat-quote:hover{background:var(--surface-3)}
.chat-quote b{font-size:12px;color:var(--accent-ink)}
/* Две строки исходного сообщения: одна строка с многоточием слишком часто
   обрывается на середине мысли, три уже спорят с самим ответом. */
.chat-quote span{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:12px;line-height:1.35;color:var(--muted)}
.chat-reactions{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
.chat-reaction{display:inline-flex;align-items:center;gap:3px;font-size:12px;line-height:1.6;border:1px solid var(--border);background:var(--surface);border-radius:20px;padding:0 6px;transition:border-color .16s ease-out,background .16s ease-out}
.chat-reaction:hover{border-color:var(--accent)}
.chat-reaction.mine{border-color:var(--accent);background:var(--accent-soft)}
@media (prefers-reduced-motion:reduce){.chat-reaction,.chat-quote{transition:none}}
.chat-reaction b{font-size:12px;font-weight:700;color:var(--muted)}
.chat-reaction.mine b{color:var(--accent-ink)}
.chat-emoji-pop{position:absolute;bottom:100%;left:0;z-index:60;display:grid;grid-template-columns:repeat(8,1fr);gap:2px;background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:7px;box-shadow:var(--shadow-lg);margin-bottom:6px}
.chat-emoji-pop button{font-size:18px;line-height:1;padding:3px;border:0;background:transparent;border-radius:7px}
.chat-emoji-pop button:hover{background:var(--surface-2)}
.chat-banner{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px;color:var(--muted);background:var(--surface-2);border-top:1px solid var(--border);padding:7px 16px}
.chat-banner span{display:flex;align-items:center;gap:6px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chat-composer-tools{display:flex;gap:4px;position:relative;align-items:center}
#chatEmojiBtn{font-size:18px;line-height:1}
.chat-files{display:flex;flex-wrap:wrap;gap:6px;margin:2px 0 3px}
.chat-file{display:inline-flex;align-items:center;gap:6px;max-width:260px;font-size:12px;color:var(--text-2);background:var(--surface);border:1px solid var(--border);border-radius:9px;padding:6px 9px}
.chat-file span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.chat-file i{font-style:normal;font-size:12px;color:var(--faint);flex:none}
.chat-file svg{color:var(--accent);flex:none}
.chat-file-img{display:block;max-width:260px;border-radius:10px;overflow:hidden;border:1px solid var(--border)}
.chat-file-img img{display:block;width:100%;height:auto;max-height:260px;object-fit:cover}
/* Панель режима поиска по переписке. */
.chat-searchbar:empty{display:none}
.chat-searchbar{display:flex;align-items:center;gap:7px;padding:6px 16px;border-bottom:1px solid var(--border);background:var(--surface-2);font-size:12px;color:var(--muted)}
.chat-searchbar svg{color:var(--faint);flex:none}
.chat-searchbar b{color:var(--text)}
.chat-searchbar .sp{margin-left:auto}
.chat-searchbar .mini-btn{width:26px;height:26px}
/* Палец — не мышь: 28 пикселей это попадание через раз. Правило по типу
   указателя, а не по ширине: планшет широкий, но трогают его так же.
   Стоит НИЖЕ всех правил .mini-btn намеренно: сила селектора у них равная,
   и при равной силе побеждает последний — с прежнего места правило просто
   не применялось. Частные размеры (колонки CRM, чат) остаются своими: их
   селекторы точнее и продолжают выигрывать. */
@media(pointer:coarse){
  .mini-btn{width:38px;height:38px}
  .row-actions{gap:8px}
}
.chat-mark{background:var(--warn-soft);color:var(--warn-ink);border-radius:4px;padding:0 2px}
.chat-msg.hit .chat-bubble{box-shadow:0 0 0 2px var(--accent)}
.chat-flash .chat-bubble{animation:chatFlash 1.6s ease-out}
@keyframes chatFlash{0%{box-shadow:0 0 0 3px var(--accent-soft)}100%{box-shadow:none}}
.chat-back{display:none}
.chat-load-older{display:flex;justify-content:center;padding:4px 0 10px}
/* Скелетон вместо надписи «Загрузка…»: полоса на месте будущего контента
   не даёт интерфейсу прыгнуть, когда данные приедут. */
.sk{background:linear-gradient(90deg,var(--surface-2) 25%,var(--surface-3) 37%,var(--surface-2) 63%);background-size:400% 100%;animation:skShine 1.4s ease-in-out infinite;border-radius:8px}
@keyframes skShine{from{background-position:100% 50%}to{background-position:0 50%}}
@media (prefers-reduced-motion:reduce){.sk{animation:none}}
.sk-item{display:flex;gap:11px;align-items:center;padding:9px 10px}
.sk-ava{width:41px;height:41px;border-radius:50%;flex:none}
.sk-lines{flex:1;min-width:0;display:grid;gap:6px}
.sk-line{height:9px}
.sk-msg{display:flex;padding:3px 0}
.sk-msg.mine{justify-content:flex-end}
.sk-bubble{height:38px;width:min(320px,58%);border-radius:16px}
.sk-row{display:flex;gap:9px;align-items:center;padding:6px 0}
.sk-row .sk-ava{width:29px;height:29px}
@media(max-width:900px){
  .chat-search input{width:110px}
  .chat-actions{display:flex;position:static;margin-top:4px;box-shadow:none}
  /* Один экран за раз: список ИЛИ переписка, между ними кнопка «назад». */
  .chat-back{display:inline-flex}
  .chat-layout.has-active .chat-side{display:none}
  .chat-layout:not(.has-active) .chat-main{display:none}
  .chat-layout:not(.has-active) .chat-side{max-height:none;border-bottom:none}
  .chat-msgs{max-height:none}
}
.chat-msgs{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:16px 18px;display:flex;flex-direction:column;gap:7px}
.chat-msg{display:flex;gap:8px;align-items:flex-end}
.chat-msg.mine{justify-content:flex-end}
/* Аватар отправителя — только в групповых чатах и только у первого сообщения
   серии: в личной переписке имя собеседника уже стоит в шапке. */
.chat-msg-ava{width:27px;height:27px;flex:none;display:grid;place-items:center;border-radius:50%;background:var(--bronze);color:#fff;font-size:12px;font-weight:700;font-family:'Manrope';margin-bottom:1px}
.chat-msg-ava.blank{visibility:hidden}
.chat-bubble{max-width:min(620px,74%);display:grid;gap:3px;padding:10px 13px;border-radius:16px;background:var(--surface-2);border:1px solid var(--border);box-shadow:0 1px 2px rgba(16,24,40,.05)}
.chat-msg.mine .chat-bubble{background:var(--accent-soft);border-color:transparent}
.chat-bubble.deleted{padding:7px 13px;font-size:12px;color:var(--faint);font-style:italic;box-shadow:none}
.chat-author{font-size:12px;font-weight:700;color:var(--accent-ink)}
/* anywhere, а не break-word: длинная ссылка или путь не должны растягивать
   пузырь, но обычные слова рвать посреди не надо. */
.chat-text{font-size:14px;line-height:1.5;overflow-wrap:anywhere}
.chat-text.clamped{max-height:224px;overflow:hidden;-webkit-mask-image:linear-gradient(#000 72%,transparent);mask-image:linear-gradient(#000 72%,transparent)}
.chat-more{justify-self:start;font-size:12px;font-weight:600;color:var(--accent-ink);background:none;border:0;padding:3px 0}
.chat-more:hover{text-decoration:underline}
.chat-stamp{display:flex;justify-content:flex-end;align-items:center;gap:5px;font-size:12px;color:var(--faint)}
.chat-edited{font-size:12px;opacity:.6}
/* Дата липнет к верху ленты: при долгой прокрутке видно, какой это день. */
.chat-day{position:sticky;top:-2px;z-index:3;display:flex;align-items:center;justify-content:center;margin:9px 0 5px;pointer-events:none}
.chat-day span{font-size:12px;font-weight:600;color:var(--muted);background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:3px 11px;box-shadow:0 1px 3px rgba(16,24,40,.07)}
/* Композер — одна панель: инструменты | ПОЛЕ ВВОДА | отправить. Рамка на
   обёртке, а не на textarea, иначе три элемента выглядят как три виджета. */
.chat-composer{flex:none;display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:8px;align-items:end;position:relative;margin:12px 16px 14px;padding:6px 6px 6px 8px;border:1px solid var(--border);border-radius:14px;background:var(--surface);transition:border-color .18s ease-out,box-shadow .18s ease-out}
.chat-composer:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.chat-composer textarea{width:100%;resize:none;min-height:38px;max-height:160px;padding:9px 4px;border:0;background:transparent;color:var(--text);font-family:inherit;font-size:14px;line-height:1.45;outline:none}
.chat-composer-tools .btn,.chat-send{width:36px;height:36px;padding:0;display:grid;place-items:center;border-radius:10px}
.chat-send{border:0;background:var(--accent);color:#fff;transition:opacity .16s ease-out,background .16s ease-out}
.chat-send:disabled{opacity:.45;cursor:default}
.chat-send:not(:disabled):hover{filter:brightness(1.06)}
@media (prefers-reduced-motion:reduce){.chat-composer,.chat-send{transition:none}}
.chat-empty,.chat-empty-side{display:grid;place-items:center;gap:9px;text-align:center;padding:34px 18px;color:var(--muted)}
.chat-empty h3{font-size:18px;color:var(--text)}
.chat-empty svg,.chat-empty-side svg{color:var(--faint)}
/* На узком экране показывается одна панель за раз (has-active), поэтому
   прежние потолки высоты (210px у списка, 46vh у ленты) только резали
   доступное место. */
@media(max-width:900px){.chat-layout{grid-template-columns:1fr}.chat-side{border-right:none;border-bottom:none;max-height:none}}
/* Узкий экран: шапка не помещалась — поле поиска и четыре кнопки требовали
   382px при колонке 341, инструменты уезжали за правый край и наползали
   друг на друга. Подписи прячем, поиск переносим отдельной строкой. */
/* Раздел чата на телефоне: прокручивается только лента, страница стоит. */
@media(max-width:900px){
  body.view-chat{overflow:hidden}
  body.view-chat .content{padding:0 0 0;max-width:none}
  body.view-chat .page-head{padding:12px 14px 0;margin-bottom:10px}
  body.view-chat .panel{border-radius:0;border-left:0;border-right:0}
  /* Клавиатура открыта: отдаём переписке место заголовка страницы. */
  body.view-chat.kb-open .page-head{display:none}
  body.view-chat.kb-open .content{padding-top:0}
  /* Заголовок раздела на телефоне занимал около 95px — примерно шестую часть
     экрана. Подзаголовок и подпись кнопки убираем, отступы ужимаем. */
  body.view-chat .page-head{align-items:center;padding:8px 12px 0;margin-bottom:6px;gap:10px}
  body.view-chat .page-head h1{font-size:18px}
  body.view-chat .page-head p{display:none}
  body.view-chat .page-head .lbl{display:none}
  body.view-chat .page-head .btn{width:36px;height:36px;padding:0;justify-content:center}
  /* Диалог открыт — заголовок раздела скрыт целиком. */
  body.view-chat.chat-open .page-head{display:none}
  body.view-chat.chat-open .content{padding-top:0}
}
@media(max-width:700px){
  /* Сетка, а не перенос строк: при wrap ширина блоков зависела от их
     содержимого и кнопки сжимались до нечитаемых 18px. */
  .chat-head{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px 10px;padding:9px 11px}
  .chat-head-who{grid-area:1/1;min-width:0}
  .chat-head-tools{grid-area:1/2;gap:5px}
  .chat-head-tools .btn{flex:none;width:34px;height:34px;padding:0;justify-content:center}
  .chat-head-tools .btn .lbl{display:none}
  .chat-search{grid-area:2/1/3/3;width:auto;margin-left:0}
  .chat-search input{width:100%;min-width:0}
  /* Семь кнопок в ряд не помещались под сообщением: быстрые реакции
     убираем, панель эмодзи остаётся и даёт весь набор. */
  .chat-act-quick{display:none}
  .chat-actions{flex-wrap:wrap;max-width:100%}
  .chat-msgs{padding:10px 11px}
  .chat-bubble{max-width:88%}
  .chat-composer{margin:8px 10px 10px}
  .chat-info-body{padding:11px}
}

/* Инициалы белым по цветному давали контраст 3.0. Кружок затемняем: оттенок
   остаётся узнаваемым, а буквы становятся читаемыми. */
.avatar{display:inline-grid;place-items:center;border-radius:8px;background:color-mix(in srgb,var(--av,var(--accent)) 68%,#000);color:#fff;font-weight:700;flex:none}
.avatar.has-photo{border-radius:50%;overflow:hidden;background:var(--surface-3);box-shadow:0 0 0 2px var(--surface),0 0 0 3px rgba(181,138,73,.38)}
.avatar.has-photo img{width:100%;height:100%;display:block;object-fit:cover}
.profile-avatar-editor{display:flex;align-items:center;gap:18px;padding:18px;border:1px solid var(--border);border-radius:16px;background:var(--surface-2)}
.profile-avatar-preview{width:96px;height:96px;border-radius:50%;overflow:hidden;display:grid;place-items:center;flex:none;background:linear-gradient(145deg,var(--accent),#8b642b);color:#fff;font:600 30px Georgia,serif;box-shadow:0 0 0 4px var(--surface),0 10px 28px rgba(23,23,19,.18)}
.profile-avatar-preview img{width:100%;height:100%;object-fit:cover;display:block}
.who{display:inline-flex;align-items:center;gap:9px}
.who .avatar{width:30px;height:30px;font-size:12px}

/* ---------- Организационная структура ----------
 *
 * Таблица сравнивает строки, а оргструктура показывает принадлежность. Здесь
 * нужна не ещё одна «красивая таблица», а устойчивые визуальные контейнеры:
 * департамент остаётся виден даже пустым, руководитель стоит в заголовке, а
 * должность сотрудника читается раньше технической роли доступа. */
.org-directory{padding:0;background:#fff;color:#171719}
.org-loading,.org-load-error{margin:0;padding:24px;color:#667085}
.org-load-error{color:#b42318}
.org-summary{display:grid;grid-template-columns:repeat(4,minmax(0,220px));gap:0;border-bottom:1px solid #d9dde7;background:#f7f7f8}
.org-summary>div{display:grid;gap:2px;padding:14px 18px;border-right:1px solid #d9dde7}
.org-summary span{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#667085}
.org-note{margin:10px 0 0;padding:10px 14px;border-radius:10px;background:var(--warn-soft);
  color:var(--warn-ink);font-size:14px;font-weight:600}
.org-summary b{font:800 18px/1.2 'Manrope',Arial,sans-serif;color:#111827}
.org-leadership{--org-color:#002fa7;position:relative;padding:16px 18px 28px;border-bottom:1px solid #d9dde7;background:#fff}
.org-leadership>header{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:10px}
.org-leadership>header span{font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#002fa7}
.org-leadership>header small{font-size:12px;color:#667085}
.org-leadership-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1px;background:#cfd5e1;border:1px solid #cfd5e1}
.org-leadership-cards .org-member{border:0;background:#f7f7f8}
.org-leadership-cards .org-member::before{width:5px;opacity:1;background:#002fa7}
.org-member.is-company-lead .org-member-role b{color:#002fa7}
.org-leadership-empty{padding:18px;background:#f7f7f8;color:#98a2b3;font-size:12px}
.org-tree-bridge{position:relative;height:38px;background:#fff;border-bottom:1px solid #d9dde7}
.org-tree-bridge::before{content:"";position:absolute;left:50%;top:0;width:2px;height:18px;background:#002fa7}
.org-tree-bridge::after{content:"";position:absolute;left:9%;right:9%;bottom:0;border-top:2px solid #cfd5e1}
.org-tree-bridge span{position:absolute;left:50%;top:12px;z-index:1;transform:translateX(-50%);padding:3px 9px;background:#fff;color:#667085;font-size:9px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
/* Колонки, а не сетка. В сетке короткий департамент и высокий сосед делят
 * один ряд, и под коротким остаётся дыра во всю его недостающую высоту:
 * следующая карточка обязана начаться с нового ряда. Колонки укладывают
 * карточки подряд и сами выравнивают высоту столбцов. */
.org-department-grid{columns:2;column-gap:14px;padding:14px;background:#fff}
.org-department{min-width:0;margin:0 0 14px;break-inside:avoid;background:#fff;border:1px solid #d9dde7;border-radius:10px;overflow:hidden;container:org-unit / inline-size}
/* Группа «руководитель и его подопечные». В департаменте их может быть
 * несколько — например, монтаж и производство, — и границу между ними
 * нужно видеть, иначе два списка сливаются в один. */
.org-group+.org-group{border-top:1px solid #d9dde7}
.org-department-head{display:grid;grid-template-columns:54px minmax(0,1fr) 34px;align-items:center;gap:12px;min-height:78px;padding:12px 16px;border-bottom:1px solid color-mix(in srgb,var(--org-color) 22%,#e5e7eb);background:color-mix(in srgb,var(--org-color) 9%,#fff);box-shadow:inset 5px 0 0 var(--org-color)}
.org-department-number{font:800 26px/1 'Manrope',Arial,sans-serif;letter-spacing:-.06em;color:var(--org-color);font-variant-numeric:tabular-nums}
.org-department-head h4{margin:0;font:800 13px/1.25 'Manrope',Arial,sans-serif;letter-spacing:.01em;color:#111827}
.org-department-head p{margin:4px 0 0;font-size:12px;color:#667085}
.org-department-head>b{display:grid;place-items:center;width:30px;height:30px;border:1px solid color-mix(in srgb,var(--org-color) 38%,#cfd5e1);background:#fff;color:var(--org-color);font:800 12px/1 'Manrope',Arial,sans-serif}
.org-department-body{display:grid;background:#fff}
.org-department-empty{display:flex;align-items:center;gap:8px;min-height:60px;padding:14px 18px;color:#98a2b3;font-size:12px}
.org-department-empty svg{color:#b4bbc7}
.org-member{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:9px 12px;padding:13px 16px;border-bottom:1px solid #edf0f4;position:relative}
.org-member:last-child{border-bottom:0}
.org-member::before{content:"";position:absolute;inset:0 auto 0 0;width:4px;background:var(--org-color,#002fa7);opacity:.18}
.org-member:hover{background:#f7f7f8}
.org-member.is-blocked{background:#fafafa;color:#777;filter:grayscale(.45)}
.org-member-main{grid-column:1;display:grid;grid-template-columns:minmax(205px,1.05fr) minmax(0,1fr);align-items:center;gap:10px;min-width:0}
.org-member-main>.who{min-width:0;font-weight:700}
.org-member-main>.who>span:last-child{white-space:normal;overflow-wrap:anywhere}
.org-member-role{display:grid;gap:2px;min-width:0}
.org-member-role b{font-size:12px;line-height:1.25;color:#111827;white-space:normal;overflow:visible;text-overflow:clip}
.org-member-role span{font-size:12px;line-height:1.25;color:#667085;white-space:normal;overflow:visible;text-overflow:clip}
.org-member-flags{grid-column:2;display:flex;align-items:center;justify-content:flex-end;gap:5px;flex-wrap:wrap}
.org-head-tag,.org-system-tag{display:inline-flex;align-items:center;min-height:22px;padding:3px 7px;border:1px solid var(--org-color,#002fa7);font-size:9px;font-weight:700;color:var(--org-color,#002fa7);text-transform:uppercase;letter-spacing:.04em}
.org-system-tag{border-color:#98a2b3;color:#667085}
.org-member-contact{grid-column:1;display:grid;grid-template-columns:minmax(120px,1fr) minmax(110px,.7fr);gap:2px 12px;min-width:0;padding-top:8px;border-top:1px solid #edf0f4;font-size:12px;color:#344054}
.org-member-contact>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.org-member-contact small{grid-column:1/3;font-size:12px;color:#98a2b3}
.org-member-actions{grid-column:2;justify-self:end}
.org-department-lead{position:relative;border-bottom:1px solid color-mix(in srgb,var(--org-color) 20%,#edf0f4)}
/* Ствол выходит из-под аватара руководителя, а не из угла карточки: линия
 * должна начинаться от человека. */
.org-group.has-team .org-department-lead::after{content:"";position:absolute;left:29px;top:44px;bottom:0;width:2px;background:color-mix(in srgb,var(--org-color) 55%,#c8cedb);z-index:2}
/* Ствол идёт вниз от аватара руководителя и проходит на уровне его строки
 * с контактами. Без отступа линия ложилась прямо поверх почты. */
.org-group.has-team .org-department-lead .org-member-contact{padding-left:20px}
.org-team-count{display:inline-flex;align-items:center;gap:4px;min-height:22px;padding:3px 8px;border-radius:999px;background:color-mix(in srgb,var(--org-color) 12%,#fff);color:var(--org-color);font-size:12px;font-weight:700;font-variant-numeric:tabular-nums}
.org-team-count svg{width:12px;height:12px}
.org-member.is-department-head{background:color-mix(in srgb,var(--org-color) 6%,#fff)}
.org-member.is-department-head::before{opacity:1;background:var(--org-color)}
.org-team-branch{position:relative}
.org-team-branch.has-lead{margin:0;padding:0;border-left:0}
.org-team-branch.without-lead{margin-left:0;padding-left:0;border-left:0}
.org-team-branch.without-lead .org-member{padding-left:16px}
/* Отрезок связи: вертикаль от верха строки до высоты аватара, затем
 * скруглённый локоть вправо. У последнего подопечного вертикаль дальше не
 * идёт — ветка заканчивается ровно на нём. */
.org-team-branch.has-lead .org-member{padding-left:58px}
.org-team-branch.has-lead .org-member::after{content:"";position:absolute;left:29px;top:-1px;width:16px;height:29px;border-left:2px solid color-mix(in srgb,var(--org-color) 55%,#c8cedb);border-bottom:2px solid color-mix(in srgb,var(--org-color) 55%,#c8cedb);border-bottom-left-radius:9px}
/* Подопечный тише руководителя: одинаковый вес карточек не давал
 * почувствовать, кто кому подчиняется. */
.org-team-branch.has-lead .org-member .who .avatar{width:26px;height:26px;font-size:12px}
.org-team-branch.has-lead .org-member .org-member-role b{font-weight:700}
.org-member.is-subordinate::before{background:var(--org-color);opacity:.32}
/* ---------- ОРГСХЕМА: отделы, секции, посты ---------- */
/* Схема глубокая: семь департаментов, двадцать три отдела, сто четырнадцать
 * секций. Разом это стена в несколько экранов, поэтому отдел раскрывается по
 * щелчку, а искать человека быстрее по фамилии. */
.org-search{display:flex;align-items:center;gap:9px;padding:12px 14px;border-bottom:1px solid #d9dde7;background:#fff}
.org-search svg{flex:none;color:#98a2b3}
.org-search input{flex:1;min-width:0;padding:8px 11px;border:1px solid #cfd5e1;border-radius:9px;background:#fff;color:#171719;font:inherit;font-size:14px}
.org-search input:focus{outline:0;border-color:#002fa7;box-shadow:0 0 0 3px rgba(0,47,167,.12)}
.org-chart-grid{display:grid;gap:14px;padding:14px;background:#fff}
.org-chart-grid .org-department{border:1px solid #d9dde7;border-radius:10px;overflow:hidden}
.org-chart-grid .org-department-body{display:grid;gap:0}

.org-division{border-top:1px solid #edf0f4}
.org-division:first-child{border-top:0}
.org-division-head{display:grid;grid-template-columns:46px minmax(0,1fr) auto 18px;align-items:center;gap:11px;width:100%;padding:11px 14px;border:0;background:none;color:inherit;font:inherit;text-align:left;cursor:pointer}
.org-division-head:hover{background:color-mix(in srgb,var(--org-color) 5%,#fff)}
.org-division-code{font:800 15px/1 'Manrope',Arial,sans-serif;color:var(--org-color);font-variant-numeric:tabular-nums}
.org-division-name{display:grid;gap:2px;min-width:0}
.org-division-name b{font-size:12px;color:#111827}
.org-division-name small{font-size:12px;color:#667085}
.org-division-name i{color:#98a2b3;font-style:normal}
/* Занято из общего числа постов. Вакансия на схеме — это дырка в штате, и
 * видеть её надо не разворачивая отдел. */
.org-division-count{padding:2px 8px;border:1px solid color-mix(in srgb,var(--org-color) 30%,#cfd5e1);border-radius:999px;color:var(--org-color);font:800 11px/1.6 'Manrope',Arial,sans-serif;font-variant-numeric:tabular-nums}
.org-division-count i{color:#98a2b3;font-style:normal;font-weight:600}
.org-division-chevron{display:grid;place-items:center;color:#98a2b3;transition:transform .15s}
.org-division.is-open .org-division-chevron{transform:rotate(180deg)}
.org-division.is-open .org-division-head{background:color-mix(in srgb,var(--org-color) 6%,#fff)}
.org-division-body{padding:2px 14px 12px 46px;background:#fcfcfd;border-top:1px solid #edf0f4}

.org-section{padding:9px 0;border-top:1px dashed #e5e7eb}
.org-section:first-child{border-top:0}
.org-section-name{margin-bottom:6px;color:#667085;font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase}
.org-section-posts{display:grid;gap:1px;background:#e9ecf1;border:1px solid #e9ecf1;border-radius:8px;overflow:hidden}
.org-section-empty{padding:10px 0;color:#98a2b3;font-size:12px}

/* Пост, за которым стоит человек, — кнопка: по нему открывается карточка с
 * телефоном, почтой и списком должностей. Пост без человека кнопкой не
 * становится: открывать нечего. */
.org-post.is-person{width:100%;border:0;font:inherit;text-align:left;cursor:pointer}
.org-post.is-person:hover{background:color-mix(in srgb,var(--org-color) 7%,#fff)}
.org-post.is-person:focus-visible{outline:2px solid var(--org-color);outline-offset:-2px}
.org-post-title small{display:block;margin-top:2px;font-size:12px;color:#98a2b3}
.org-post-nocontact{font-style:italic}
.org-person-posts{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:1px;
  background:var(--border);border:1px solid var(--border)}
.org-person-posts li{display:flex;justify-content:space-between;gap:12px;padding:8px 11px;
  background:var(--surface);font-size:12px}
.org-person-posts li span{color:var(--muted)}
/* Демонстрационные входы отделены рамкой и подписью: в общем списке они
 * выглядели сотрудниками, которых в компании нет. */
.org-unassigned.is-demo{background:repeating-linear-gradient(135deg,#fafafa,#fafafa 8px,#f4f4f6 8px,#f4f4f6 16px)}
.org-unassigned.is-demo>h4{color:#b4690e}
.org-post{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.9fr);align-items:center;gap:10px;padding:8px 11px;background:#fff}
.org-post-who{display:inline-flex;align-items:center;gap:8px;min-width:0}
.org-post-who b{font-size:12px;font-weight:700;color:#111827;overflow-wrap:anywhere}
.org-post-title{color:#667085;font-size:12px;overflow-wrap:anywhere}
/* Вакансия видна сразу и не притворяется человеком: без аватара, подпись
 * курсивом и приглушённый фон. */
.org-post.is-vacant{background:repeating-linear-gradient(135deg,#fff,#fff 7px,#fafbfc 7px,#fafbfc 14px)}
.org-post-vacant{color:#98a2b3;font-size:12px;font-style:italic}
.org-section-posts .org-member{padding:9px 11px;border-bottom:0;background:#fff}
/* Старший в секции и его люди. Отрезок связи тот же, что у департаментов:
 * вертикаль плюс скруглённый локоть одной фигурой на рамках. Отрезки
 * стыкуются встык, поэтому линия непрерывна, а у последнего в списке
 * обрывается на его локте сама собой. */
.org-post-branch{position:relative}
.org-post-branch .org-post,.org-post-branch .org-member{padding-left:44px}
.org-post-branch .org-post::after,.org-post-branch .org-member::after{content:"";position:absolute;left:18px;top:-1px;width:14px;height:22px;border-left:2px solid color-mix(in srgb,var(--org-color) 50%,#cfd5e1);border-bottom:2px solid color-mix(in srgb,var(--org-color) 50%,#cfd5e1);border-bottom-left-radius:8px}
.org-post-branch .org-post,.org-post-branch .org-member{position:relative}
.org-section.has-lead .org-post-lead .org-post{background:color-mix(in srgb,var(--org-color) 6%,#fff)}
.org-section.has-lead .org-post-lead .org-post-who b{font-weight:700}

.org-section-posts .org-member::before{display:none}

@media(max-width:700px){
  .org-division-head{grid-template-columns:38px minmax(0,1fr) auto 16px;gap:8px;padding:10px}
  .org-division-body{padding:2px 10px 10px 20px}
  .org-post{grid-template-columns:1fr;gap:4px}
}

/* Незанятые департаменты — строка чипов, а не пять пустых карточек. */
.org-vacant{padding:0 14px 16px;background:#fff}
.org-vacant>h4{margin:0 0 8px;font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#98a2b3}
.org-vacant>div{display:flex;flex-wrap:wrap;gap:6px}
.org-vacant-chip{display:inline-flex;align-items:center;gap:7px;padding:5px 10px;border:1px dashed color-mix(in srgb,var(--org-color) 45%,#cfd5e1);border-radius:999px;background:color-mix(in srgb,var(--org-color) 5%,#fff);color:#667085;font-size:12px}
.org-vacant-chip b{font:800 11px/1 'Manrope',Arial,sans-serif;color:var(--org-color);font-variant-numeric:tabular-nums}
.org-unassigned{padding:18px;border-top:1px solid #d9dde7;background:#f7f7f8}
.org-unassigned>h4{margin:0 0 10px;font-size:12px;text-transform:uppercase;letter-spacing:.06em}
.org-unassigned>div{display:grid;gap:1px;background:#d9dde7;border:1px solid #d9dde7}
.org-unassigned .org-member{background:#fff}
/* При открытом левом меню ширина всей страницы остаётся десктопной, но каждая
 * из двух колонок отделов сжимается примерно до 470 px. Обычный media query
 * этого не замечает, поэтому карточка перестраивается по собственной ширине:
 * сначала имя и должность, затем статусы, контакты и действия. */
@container org-unit (max-width:560px){
  .org-department-head{grid-template-columns:44px minmax(0,1fr) 30px;gap:9px;padding:11px 12px}
  .org-department-number{font-size:22px}
  .org-member{grid-template-columns:minmax(0,1fr) auto;gap:9px;padding:12px}
  .org-member-main{grid-column:1/3;grid-template-columns:1fr;gap:6px}
  .org-member-main>.who>span:last-child{white-space:normal;overflow:visible;text-overflow:clip}
  .org-member-flags{grid-column:1/3;justify-content:flex-start}
  .org-member-contact{grid-column:1/3;grid-template-columns:1fr;padding-top:8px;border-top:1px solid #edf0f4}
  .org-member-contact>span{white-space:normal;overflow-wrap:anywhere;text-overflow:clip}
  .org-member-contact small{grid-column:1}
  .org-member-actions{grid-column:1/3;grid-row:auto;justify-self:start;max-width:100%}
  .org-member-actions .row-actions{flex-wrap:wrap}
}
@media(max-width:1100px){
  .org-department-grid{columns:1}
}
@media(max-width:700px){
  .org-summary{grid-template-columns:1fr 1fr}
  .org-summary>div:last-child{grid-column:1/3;border-right:0}
  .org-summary>div{padding:12px}
  .org-leadership{padding:14px 12px 24px}
  .org-leadership>header{display:grid;gap:3px}
  .org-leadership-cards{grid-template-columns:1fr}
  .org-tree-bridge::after{left:16px;right:16px}
  .org-department-head{grid-template-columns:44px minmax(0,1fr) 30px;gap:9px;padding:11px 12px}
  .org-department-number{font-size:22px}
  .org-member{grid-template-columns:minmax(0,1fr) auto;gap:9px;padding:12px}
  .org-member-main{grid-column:1/3;grid-template-columns:1fr;gap:6px}
  .org-member-role b,.org-member-role span{white-space:normal;overflow:visible;text-overflow:clip}
  .org-member-flags{grid-column:1/3;justify-content:flex-start}
  .org-member-contact{grid-column:1/3;grid-template-columns:1fr;padding-top:8px;border-top:1px solid #edf0f4}
  .org-member-contact small{grid-column:1}
  .org-member-actions{grid-column:1/3;grid-row:auto;justify-self:start}
}

/* ---------- Toolbar (filters) ---------- */
.toolbar{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;margin-bottom:16px}
.field{display:flex;flex-direction:column;gap:5px}
.field>span{font-size:12px;font-weight:600;color:var(--muted);padding-left:2px}
.field input,.field select{padding:9px 12px;border-radius:10px;border:1px solid var(--border);background:var(--surface);color:var(--text);font-size:14px;outline:none;min-width:150px;transition:border .15s,box-shadow .15s}
.field input:focus,.field select:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.field.search input{padding-left:34px}
.field.search{position:relative} .field.search svg{position:absolute;left:11px;bottom:11px;width:15px;height:15px;color:var(--faint)}
.toolbar .spacer{margin-left:auto}

/* ---------- Progress / ring ---------- */
.progress{position:relative;height:8px;border-radius:20px;background:var(--surface-3);overflow:hidden}
.progress .bar{position:absolute;inset:0 auto 0 0;border-radius:20px;background:var(--accent);transition:width .6s cubic-bezier(.4,0,.2,1)}
.ring{position:relative;display:grid;place-items:center}
.ring svg{transform:rotate(0)} .ring .rl{position:absolute;font-family:'Manrope';font-weight:700;font-size:14px}

/* ---------- Funnel ---------- */
.funnel{display:flex;flex-direction:column;gap:9px}
.funnel-legend{display:grid;grid-template-columns:170px 1fr 90px 100px;gap:12px;font-size:12px;color:var(--faint);font-weight:600;text-transform:uppercase;letter-spacing:.04em;padding:0 4px 4px}
.funnel-row{display:grid;grid-template-columns:170px 1fr 90px 100px;gap:12px;align-items:center}
.funnel-name{font-size:14px;font-weight:600}
.funnel-track{height:34px;border-radius:9px;background:var(--surface-3);position:relative;overflow:hidden}
.funnel-bar{height:100%;border-radius:9px;background:linear-gradient(90deg,color-mix(in srgb,var(--c) 88%,#000 0%),color-mix(in srgb,var(--c) 60%,transparent));display:flex;align-items:center;padding:0 12px;color:#fff;font-weight:700;font-size:12px;min-width:44px;transition:width .7s cubic-bezier(.4,0,.2,1)}
.funnel-sum{font-size:12px;font-weight:600;color:var(--text-2);text-align:right}
.funnel-conv{font-size:12px;color:var(--muted);text-align:right}
.funnel-time{font-size:12px;color:var(--faint);margin-top:2px}
/* Воронка на телефоне.
   Колонки заданы жёстко: 170 + 90 + 100 плюс три отступа по 12 — это 396
   пикселей ещё до самой полосы, а экран телефона 393. Поэтому конверсия
   уезжала за правый край и читалась как «КОНВЕР». Раскладываем в две линии:
   сверху этап и сумма, снизу полоса и конверсия. Подпись колонок убираем —
   колонок, которые она называла, здесь больше нет. */
@media(max-width:640px){
  .funnel-legend{display:none}
  .funnel-row{grid-template-columns:minmax(0,1fr) auto;gap:6px 10px;align-items:center}
  .funnel-row>div:first-child{grid-column:1;grid-row:1}
  .funnel-sum{grid-column:2;grid-row:1;text-align:right}
  .funnel-track{grid-column:1;grid-row:2;height:26px}
  .funnel-conv{grid-column:2;grid-row:2;text-align:right}
}

/* ---------- Manager cards ---------- */
.mgr{background:var(--surface);border:1px solid var(--border);border-radius:var(--r);padding:18px;box-shadow:var(--shadow-sm);position:relative;overflow:hidden;transition:transform .18s,box-shadow .18s}
.mgr:hover{transform:translateY(-3px);box-shadow:var(--shadow)}
.mgr.best{border-color:color-mix(in srgb,var(--bronze) 50%,var(--border))}
.mgr.best::before{content:"";position:absolute;inset:0 0 auto 0;height:3px;background:linear-gradient(90deg,var(--bronze),transparent 80%)}
.mgr-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:16px}
.mgr-id{display:flex;align-items:center;gap:12px}
.mgr-id .avatar{width:44px;height:44px;font-size:14px}
.mgr-id h4{font-size:14px} .mgr-id span{font-size:12px;color:var(--muted)}
.mgr-tag{display:inline-flex;align-items:center;gap:5px;font-size:12px;font-weight:700;padding:4px 10px;border-radius:20px}
.mgr-tag svg{width:13px;height:13px}
.mgr-tag.best{color:color-mix(in srgb,var(--bronze) 62%,#000);background:var(--bronze-soft)} .mgr-tag.worst{color:var(--bad-ink);background:var(--bad-soft)}
.mgr-rank{font-size:12px;font-weight:700;color:var(--muted);background:var(--surface-3);padding:4px 10px;border-radius:20px}
.mgr-plan-top{display:flex;justify-content:space-between;font-size:12px;margin-bottom:7px}
.mgr-plan-nums{display:flex;justify-content:space-between;font-size:12px;margin-top:7px}
.mgr-metrics{display:grid;grid-template-columns:1fr 1fr;gap:11px 16px;margin-top:16px;padding-top:15px;border-top:1px solid var(--border)}
.mgr-metrics>div{display:flex;flex-direction:column;gap:2px}
.mgr-metrics span{font-size:12px;color:var(--muted)} .mgr-metrics b{font-size:14px;font-family:'Manrope';font-weight:700}

/* ---------- Stat tiles / stepper ---------- */
/* Сетка плиток. Правило было снесено вместе с CSS удалённого раздела
   «Клиенты»: удаление шло по номерам строк, и под нож попала соседняя
   строка. Без него .stat-tiles остаётся обычным блоком, и плитки в
   телефонии, доставке, бригадах и монтаже выстраиваются в столбик во всю
   ширину. Медиазапрос на узкий экран уцелел, поэтому ломалось только на
   широком — и заметить это на разработке было нечем. */
.stat-tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(168px,1fr));gap:10px}
/* Табель: месяц сеткой. Клетки узкие намеренно — месяц должен помещаться в
   ширину экрана целиком, иначе взгляд поперёк, ради которого табель и
   смотрят, распадается на прокрутку. */
/* Сетка между днями. Без линий тридцать одна колонка сливается в полосу, и
   попасть взглядом из строки сотрудника в нужное число нельзя — а табель
   именно так и читают: ведут пальцем от фамилии к дате.

   Линии светлее обычной границы таблицы: их много, и при обычной толщине
   сетка забивает сами отметки, ради которых сюда смотрят. */
.ts-table th,.ts-table td{padding:5px 4px;text-align:center;font-size:12px;
  border-right:1px solid color-mix(in srgb,var(--border) 55%,transparent)}
.ts-table tbody td{border-top:1px solid color-mix(in srgb,var(--border) 55%,transparent)}
.ts-table th:last-child,.ts-table td:last-child{border-right:0}
/* Столбец с фамилией и итог по часам отбиты сильнее: это границы самой
   сетки дней, а не деление внутри неё. */
.ts-table .ts-name{border-right:2px solid var(--border)}
.ts-table th:last-child,.ts-table tbody td:last-child{border-left:2px solid var(--border)}
.ts-table .ts-name{text-align:left;white-space:nowrap;padding:8px 12px;min-width:170px}
.ts-table .ts-name .hint{font-size:12px}
/* Заголовок отдела внутри сетки. Ячейка растянута на все колонки, поэтому
   вертикальные линии дней в ней убраны: они резали бы заголовок на части. */
.ts-table tr.ts-group td{text-align:left;padding:9px 12px;border-right:0;
  background:var(--surface-2);font-weight:700;white-space:nowrap}
.ts-table tr.ts-group td b{margin-left:8px;font-weight:600;color:var(--muted)}
.ts-group-dot{display:inline-block;width:9px;height:9px;border-radius:3px;
  background:var(--c,#94a3b8);margin-right:8px;vertical-align:middle}
/* Имя и кнопки в одной ячейке: имя занимает всё, кнопки прижаты вправо. Без
   явного распределения кнопки уезжали под фамилию и поднимали высоту строки —
   а строк в табеле тридцать одна на человека, каждый лишний пиксель виден. */
.ts-table tbody .ts-name{display:flex;align-items:center;gap:12px;justify-content:space-between}
.ts-name-copy{min-width:0}
.ts-table tbody .ts-name .row-actions{flex:0 0 auto}
/* На телефоне отдел — обычный заголовок над карточками своей группы. */
.ts-mobile-group{display:flex;align-items:center;margin:18px 0 8px;font-size:14px}
.ts-mobile-group:first-child{margin-top:0}
.ts-mobile-group b{margin-left:8px;font-weight:600;color:var(--muted)}
/* Список людей со схемы при заведении доступа. Высота ограничена: людей сорок
   один, и окно во весь экран пришлось бы прокручивать вместе со страницей. */
.ts-pick-list{display:flex;flex-direction:column;gap:6px;max-height:52vh;overflow:auto}
.ts-pick-person{display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  width:100%;text-align:left;padding:9px 12px;border:1px solid var(--border);
  border-radius:10px;background:var(--surface);cursor:pointer}
.ts-pick-person:hover{border-color:var(--accent);background:var(--surface-2)}
.ts-pick-person b{font-size:13px}
.ts-pick-person span{font-size:12px;color:var(--muted)}
/* Переключатель «Демо-данные» стоит в одной линии с выбором периода: это такой
   же фильтр отчёта, как и период, и жить он должен там же, а не в настройках. */
.fin-demo{min-width:120px}
.fin-demo-row{display:flex;align-items:center;gap:6px;height:38px;font-size:13px}
.fin-demo-row input{width:16px;height:16px;margin:0}
/* Подпись под P&L — то, без чего оценка читалась бы как факт. Не мельче
   остального текста намеренно: её задача — быть прочитанной. */
.fin-caption{font-size:13px;line-height:1.5}
.ts-day{width:26px;color:var(--muted);font-weight:600;padding:4px 2px}
.ts-day b{display:block;font-size:12px;line-height:1.2}
.ts-day i{display:block;font-style:normal;font-size:12px;opacity:.7;line-height:1.2}
.ts-day.we,.ts-cell.we{background:var(--surface-2)}
/* Понедельник открывает неделю: линия слева даёт опору взгляду, иначе
   месяц читается как сплошная лента без ритма. */
.ts-table .wk-start{border-left:2px solid var(--border)}
.ts-cell{width:26px;height:30px;cursor:pointer}
.ts-cell:hover{background:var(--accent-soft)}
.ts-mark{display:inline-grid;place-items:center;width:20px;height:20px;border-radius:6px;
  font-size:12px;font-weight:700;color:#fff;background:var(--c)}
.ts-legend{display:flex;flex-wrap:wrap;gap:14px;margin-top:12px}
.ts-leg{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}
.ts-pick{display:flex;flex-direction:column;gap:8px}
.ts-pick .btn{justify-content:flex-start;gap:10px}
.ts-dot{width:12px;height:12px;border-radius:4px;background:var(--c);flex:none}
/* Мобильный табель — не ужатая копия месячной таблицы, а карточка человека
   с мини-календарём. На десктопе остаётся привычная сетка, на телефоне
   руководителю важнее быстро увидеть сотрудника, итог часов и пробелы. */
.ts-mobile{display:none}
.ts-mobile-card{border:1px solid var(--border);border-radius:14px;background:var(--surface);padding:12px;box-shadow:var(--shadow-sm)}
.ts-mobile-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.ts-mobile-person{display:flex;align-items:center;gap:9px;min-width:0}
.ts-mobile-avatar{width:36px;height:36px;border-radius:11px;display:grid;place-items:center;flex:none;background:var(--accent-soft);color:var(--accent-ink);font-size:12px;font-weight:700}
.ts-mobile-person-copy{display:grid;gap:1px;min-width:0}
.ts-mobile-person-copy b{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ts-mobile-person-copy .hint{font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ts-mobile-hours{display:grid;justify-items:end;gap:0;flex:none}
.ts-mobile-hours b{font-size:18px;line-height:1.1}
.ts-mobile-hours span{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
.ts-mobile-stats{display:flex;flex-wrap:wrap;gap:5px;margin-top:10px}
.ts-mobile-stat{display:inline-flex;align-items:center;gap:4px;padding:3px 7px;border-radius:999px;background:var(--surface-2);font-size:12px;color:var(--muted)}
.ts-mobile-stat .ts-mark{width:17px;height:17px;border-radius:5px;font-size:9px}
.ts-mobile-stat b{color:var(--text);font-size:12px}
.ts-mobile-weekdays,.ts-mobile-calendar{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}
.ts-mobile-weekdays{margin-top:12px;color:var(--faint);font-size:9px;text-align:center;text-transform:uppercase;letter-spacing:.04em}
.ts-mobile-calendar{margin-top:4px}
.ts-mobile-day{min-width:0;min-height:31px;display:grid;place-items:center;align-content:center;gap:1px;padding:3px 1px;border:1px solid var(--border);border-radius:7px;background:var(--surface-2);color:var(--muted);font:inherit}
button.ts-mobile-day{cursor:pointer;transition:background .13s,border-color .13s,transform .13s}
button.ts-mobile-day:hover,button.ts-mobile-day:focus-visible{background:var(--accent-soft);border-color:var(--accent);transform:translateY(-1px)}
.ts-mobile-day.is-empty{border-color:transparent;background:transparent}
.ts-mobile-day.we{background:color-mix(in srgb,var(--surface-3) 60%,transparent)}
.ts-mobile-day.has-mark{border-color:color-mix(in srgb,var(--c,var(--accent)) 42%,var(--border));background:color-mix(in srgb,var(--c,var(--accent)) 9%,var(--surface))}
.ts-mobile-day-num{font-size:12px;line-height:1;color:var(--text-2)}
.ts-mobile-day .ts-mark{width:17px;height:17px;border-radius:5px;font-size:9px}
@media(max-width:640px){
  .ts-desktop{display:none}
  .ts-mobile{display:grid;gap:10px;padding:10px}
  .ts-legend{gap:7px 10px;padding:0 10px;margin-top:2px}
  .ts-leg{font-size:12px}
}
/* Список задач менеджера. Строка целиком — кнопка: попадать пальцем в
   мелкую ссылку, стоя у клиента, неудобно. */
/* Мои задачи: списки слева, календарь справа. Ширины неравные намеренно —
   у списка строка короткая, у календаря семь колонок. */
.tasks-split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:16px;align-items:start}
.tasks-lists{display:flex;flex-direction:column;gap:16px;min-width:0}
.tasks-cal{min-width:0;position:sticky;top:12px}
/* Длинный список прокручивается внутри себя, а не растягивает страницу. */
.tasks-lists .task-list{max-height:320px;overflow:auto}
@media(max-width:1100px){.tasks-split{grid-template-columns:1fr}.tasks-cal{position:static}}
.task-list{display:flex;flex-direction:column}
.task-row{display:flex;align-items:center;gap:12px;width:100%;padding:12px 15px;border:0;border-bottom:1px solid var(--border);
  background:none;color:var(--text);font:inherit;text-align:left;cursor:pointer}
.task-row:last-child{border-bottom:0}
.task-row:hover{background:var(--surface-2)}
.task-ic{width:30px;height:30px;flex:none;border-radius:9px;display:grid;place-items:center;
  background:color-mix(in srgb,var(--c) 14%,transparent);color:var(--c)}
.task-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.task-main b{font-size:14px}
.task-main span{font-size:12px;color:var(--muted)}
.task-when{font-size:12px;color:var(--muted);white-space:nowrap;font-variant-numeric:tabular-nums}
/* Просроченные подсвечены слева полосой, а не красным текстом: текста в
   строке и так три вида, четвёртый цвет читать мешает. */
.task-list.overdue .task-row{box-shadow:inset 3px 0 0 var(--bad)}
.task-list.overdue .task-when{color:var(--bad-ink);font-weight:600}
/* ПОЛОСА У ВСЕХ СТРОК ОДНОЙ ТОЛЩИНЫ.
   Раньше обязательная задача получала рамку слева в 3px, а список просроченных
   добавлял свою внутреннюю полосу ещё в 3px — вместе шесть. Рядом обычная
   задача с одной полосой выглядела тоньше, и разница читалась как сбой
   вёрстки, а не как разные виды заданий: толщина ничего не значит, её просто
   сложили два правила.

   Вид задания различают те признаки, которые для этого и заведены: значок
   слева, метка «Обязательно» и тёплая подложка. Полоса говорит одно — насколько
   горит: тёплая «скоро», красная «просрочено». */
.task-row.mandatory-task{box-shadow:inset 3px 0 0 #e0902b}
.task-row.mandatory-task.overdue,.task-row.mandatory-task.missing{
  box-shadow:inset 3px 0 0 var(--bad-ink);background:color-mix(in srgb,var(--bad) 7%,transparent)}
.mandatory-task .task-ic{background:color-mix(in srgb,#e0902b 16%,transparent);color:#e0902b}
.task-required{flex:none;border-radius:999px;padding:3px 7px;background:color-mix(in srgb,#e0902b 14%,transparent);color:#a75e0b;font-size:12px;font-weight:700;white-space:nowrap}
/* Приёмка монтажа: чек-лист и подпись. Всё крупное — заполняют пальцем на
   телефоне, стоя на кладбище, а не мышью за столом. */
.accept-box{display:flex;flex-direction:column}
.accept-row{display:flex;align-items:center;gap:11px;padding:11px 12px;margin-bottom:7px;
  border:1px solid var(--border);border-radius:11px;background:var(--surface-2);font-size:14px;cursor:pointer}
.accept-row input{width:21px;height:21px;flex:none;accent-color:var(--accent)}
.accept-row:has(input:checked){border-color:var(--good-ink);background:color-mix(in srgb,var(--good) 8%,transparent)}
/* Холст подписи белый в любой теме: клиент расписывается на «бумаге», и в
   тёмной теме росчерк должен остаться читаемым в сохранённой картинке. */
.sign-pad{width:100%;height:170px;border:1px dashed var(--border);border-radius:12px;background:#fff;touch-action:none;display:block}
.accept-acts{display:flex;gap:10px;align-items:center;margin-top:10px}
.sign-name{flex:1;padding:9px 12px;border-radius:10px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font-size:14px;font-family:inherit}
.accept-signed img{width:100%;max-height:170px;object-fit:contain;background:#fff;border:1px solid var(--border);border-radius:12px}
.accept-signed p{margin:8px 0 0}
/* ---------- Склад: нормы списания ---------- */
/* Строки сгруппированы по изделию: норма — это состав ОДНОГО изделия, и
   плоский список вперемешку заставлял бы собирать её глазами. */
.norm-group{border:1px solid var(--border);border-radius:10px;padding:10px 12px;margin-bottom:8px}
.norm-group-head{font-weight:700;font-size:14px;margin-bottom:6px}
.norm-row{display:grid;grid-template-columns:1fr auto auto;gap:10px;align-items:center;padding:4px 0;font-size:14px}
.norm-row+.norm-row{border-top:1px solid var(--border)}

/* ---------- Склад: нехватка ---------- */
/* Полоса над таблицей перечисляет, ЧТО именно заканчивается. Счётчик в плитке
   говорит, что проблема есть, но не говорит какая, и заставляет искать её
   глазами по всей таблице. */
.stock-low{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px;padding:10px 13px;
  border-radius:10px;font-size:14px;color:var(--bad-ink);
  background:color-mix(in srgb,var(--bad) 9%,transparent);border:1px solid color-mix(in srgb,var(--bad) 28%,transparent)}
.stock-low svg{flex:none}
/* Строка подсвечена мягко: она не ошибка, а повод заказать. Красная заливка
   строки читалась бы как поломка и обесценивала бы настоящие красные метки
   рядом — просрочку и отрицательный остаток. */
.stock-row-low>td:first-child{box-shadow:inset 3px 0 0 var(--bad)}
.t-bad{color:var(--bad-ink);font-weight:700}

/* ---------- Сегменты клиентов A/B/C/D ---------- */
/* Круг с буквой. Форма выбрана намеренно: в строке рядом уже стоят плашки
   статуса и этапа, и третья прямоугольная терялась среди них — глаз читал её
   как продолжение того же ряда. Круг отличается формой, а не только цветом,
   поэтому виден и при беглом взгляде, и тем, кто плохо различает оттенки. */
.seg-dot{display:inline-flex;align-items:center;justify-content:center;width:19px;height:19px;border-radius:50%;
  font-size:12px;font-weight:700;line-height:1;vertical-align:middle;flex:none;
  color:#fff;background:color-mix(in srgb,var(--seg) 68%,#000);box-shadow:0 0 0 2px color-mix(in srgb,var(--seg) 22%,transparent)}
.seg-name{color:var(--seg);font-weight:600;font-size:12px}
/* Полоса слева от строки CRM — тем же цветом. Значок отвечает на вопрос про
   одного человека, полоса — про список целиком: видно, сколько здесь спящих
   и не идут ли они подряд, не читая ни одной строки.
   Рисуется внутренней тенью первой ячейки, а не рамкой строки: рамка на <tr>
   в таблице не отображается в части браузеров, а на <td> сдвинула бы текст на
   свою ширину. */
.crm-seg-row>td:first-child{box-shadow:inset 3px 0 0 var(--seg)}
.crm-seg-row.has-mandatory.soon>td:first-child{box-shadow:inset 4px 0 0 #e0902b}
.crm-seg-row.has-mandatory.overdue>td:first-child,.crm-seg-row.has-mandatory.missing>td:first-child{box-shadow:inset 4px 0 0 var(--bad)}
/* Осталось от раздела «Клиенты», который убран: этими правилами оформлена
   панель клиента в карточке сделки — задача сегмента и плитки показателей. */
.clients-task{margin-top:10px;padding:10px 12px;border-radius:10px;background:var(--soft);font-size:14px;
  border-left:3px solid var(--seg,var(--accent))}
.clients-task b{color:var(--seg,inherit)}
/* В карточке клиента действие отделено от общей истории: менеджер сразу
   видит, что именно нельзя пропустить, даже если остальные блоки длинные. */
.crm-next-cell{display:flex;align-items:center;min-height:26px}
.mandatory-action{display:inline-flex;align-items:center;gap:4px;border-radius:999px;padding:3px 7px;font-size:12px;font-weight:700;white-space:nowrap;background:color-mix(in srgb,#e0902b 14%,transparent);color:#a75e0b}
.mandatory-action.planned{background:color-mix(in srgb,var(--good) 12%,transparent);color:var(--good-ink)}
.mandatory-action.soon{background:color-mix(in srgb,#e0902b 19%,transparent);color:#a75e0b}
.mandatory-action.overdue,.mandatory-action.missing{background:color-mix(in srgb,var(--bad) 12%,transparent);color:var(--bad-ink)}
.mandatory-action-date{font-weight:600}
.mandatory-action-card{margin-top:10px;padding:12px 13px;border:1px solid color-mix(in srgb,#e0902b 28%,var(--border));border-left:4px solid #e0902b;border-radius:12px;background:color-mix(in srgb,#e0902b 6%,var(--surface))}
.mandatory-action-card.soon{border-left-color:#e0902b;background:color-mix(in srgb,#e0902b 9%,var(--surface))}
.mandatory-action-card.overdue,.mandatory-action-card.missing{border-left-color:var(--bad-ink);background:color-mix(in srgb,var(--bad) 7%,var(--surface))}
.mandatory-action-card-head{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}
.mandatory-action-card-body{margin-top:8px;font-size:14px}
.mandatory-action-card-note{margin-top:5px;font-size:12px;color:var(--muted)}
.mandatory-field small{display:block;margin-top:4px;color:var(--muted);font-size:12px}
.required-mark{color:var(--bad-ink);font-weight:700}
.clients-metrics{display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));gap:8px}
.clients-metrics .kv{display:flex;flex-direction:column;gap:2px;padding:9px 11px;border:1px solid var(--line);border-radius:10px}
.clients-metrics .kv span{font-size:12px;color:var(--faint)}
.clients-metrics .kv b{font-size:14px}
/* Этап позиции меняется прямо в строке: заходить ради этого в отдельное окно
   значит терять из виду остальные позиции заказа, а сравнивают их как раз
   между собой — кто отстаёт. */
.crm-stage-sel-inline{width:100%;padding:5px 7px;border-radius:8px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font-size:12px;font-family:inherit}
.stat-tile{display:flex;gap:11px;align-items:center;padding:11px 13px;border:1px solid var(--border);border-radius:12px;background:var(--surface-2)}
.stat-tile .si{width:38px;height:38px;border-radius:10px;display:grid;place-items:center;background:color-mix(in srgb,var(--c) 14%,transparent);color:var(--c)}
.stat-tile .si svg{width:19px;height:19px}
/* Manrope здесь оставался третьим шрифтом рабочего экрана: правку прошлого
   круга я сделал в .kpi-val и не заметил, что плитки берут своё правило. */
.stat-tile b{font-size:18px;font-weight:700;display:block} .stat-tile span{font-size:12px;color:var(--muted)}

.stepper{display:flex;flex-wrap:wrap;gap:5px}
.step{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--faint)}
.step .sd{width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:12px;font-weight:700;border:1.5px solid var(--border);background:var(--surface)}
.step .sd svg{width:11px;height:11px}
.step.done{color:var(--good-ink)} .step.done .sd{background:var(--good);border-color:var(--good-ink);color:#fff}
.step.current{color:var(--accent-ink)} .step.current .sd{border-color:var(--accent);color:var(--accent-ink);background:var(--accent-soft)}
.step:not(:last-child)::after{content:"";width:12px;height:1.5px;background:var(--border);margin-left:2px}
.step.done:not(:last-child)::after{background:var(--good)}

/* ---------- Calendar ---------- */
.calendar{border:1px solid var(--border);border-radius:12px;overflow:hidden}
/* minmax(0,1fr), а не 1fr: у 1fr минимум равен содержимому, и одна длинная
   плашка вида «INST-0710 13:00 · Бригада №3 · Оліфер» распирала столбец —
   сетка вылезала за панель, а правый край недели обрезался без прокрутки.
   Обрезать текст до многоточия .cal-ev умеет и сам, но только когда ему
   разрешено сузиться, поэтому min-width:0 нужен и ячейке. */
.cal-head,.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr))}
.cal-dow{padding:10px;text-align:center;font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;background:var(--surface-2);border-bottom:1px solid var(--border)}
.cal-cell{min-height:96px;min-width:0;padding:7px;border-right:1px solid var(--border);border-bottom:1px solid var(--border);display:flex;flex-direction:column;gap:3px}
.cal-cell:nth-child(7n){border-right:none}
.cal-cell.empty{background:var(--surface-2)}
.cal-cell.today{background:var(--accent-soft)}
.cal-day{font-size:12px;font-weight:700;color:var(--muted)}
.cal-cell.today .cal-day{color:var(--accent-ink)}
.cal-ev{font-size:12px;padding:2px 6px;border-radius:6px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600}
/* Серийный номер монтажа впереди и жирным: по нему ищут, а время и бригада
   при нехватке места могут уйти в многоточие. */
.cal-ev b{font-weight:700}
.cal-ev.planned{background:var(--info-soft);color:var(--info-ink)} .cal-ev.today{background:var(--warn-soft);color:var(--warn-ink)}
.cal-ev.done{background:var(--good-soft);color:var(--good-ink)} .cal-ev.overdue{background:var(--bad-soft);color:var(--bad-ink)}
.cal-more{font-size:12px;color:var(--muted)}
.install-tools{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:16px}
.seg{display:inline-flex;align-items:center;gap:2px;padding:3px;border:1px solid var(--border);border-radius:12px;background:var(--surface)}
/* Переключатель вида — орган управления, а не подпись. Двенадцатым он был
   потому, что попал под общее сведение мелких размеров, а не по замыслу. */
.seg button{border:0;background:transparent;color:var(--muted);padding:7px 11px;border-radius:9px;font-weight:600;font-size:14px}
.seg button.active{background:var(--accent-soft);color:var(--accent-ink)}
.install-month{display:flex;align-items:center;gap:8px}
.install-month select{padding:8px 10px;border:1px solid var(--border);border-radius:10px;background:var(--surface);color:var(--text);font-weight:600}
.calendar.install-cal .cal-cell{min-height:126px;cursor:pointer}
.calendar.install-cal .cal-cell:hover{background:var(--surface-2)}
.calendar.install-cal .cal-cell.empty{cursor:default}
.cal-date-top{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-bottom:3px}
.cal-count{font-size:12px;color:var(--muted);background:var(--surface-3);border-radius:20px;padding:1px 6px}
.cal-ev{border:0;text-align:left;cursor:pointer;display:block;width:100%;font-family:inherit}
.cal-ev:hover{filter:brightness(1.04);transform:translateY(-1px)}
.install-card{display:flex;justify-content:space-between;gap:14px;align-items:flex-start;padding:14px;border:1px solid var(--border);border-radius:12px;background:var(--surface);box-shadow:var(--shadow-sm)}
.install-card-main{min-width:0}
.install-card-title{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
.install-card-title b{font-family:'Manrope';font-size:14px}
.install-meta{display:flex;gap:10px;flex-wrap:wrap;font-size:12px;color:var(--muted)}
.install-actions{display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end}
.production-kanban{display:grid;grid-template-columns:repeat(12,minmax(260px,1fr));gap:14px;overflow-x:auto;padding-bottom:8px}
.production-column{border:1px solid var(--border);border-radius:12px;background:var(--surface);min-height:240px;overflow:hidden}
.production-column h4{position:sticky;top:0;z-index:1;padding:13px 14px;border-bottom:1px solid var(--border);background:var(--surface-2);font-size:14px;display:flex;justify-content:space-between;gap:8px}
.production-column-body{padding:10px;display:grid;gap:10px}
.production-card{cursor:pointer;border-top:3px solid var(--accent)}
.production-card.blocked{border-top-color:var(--bad-ink)}
.production-card.done{border-top-color:var(--good-ink)}
.readiness{display:flex;align-items:center;gap:8px;min-width:130px}
.readiness .progress{flex:1;height:7px}
.readiness b{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
.install-board{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}
.brigade-box{border:1px solid var(--border);border-radius:12px;background:var(--surface);overflow:hidden}
.brigade-box h4{padding:14px 15px;border-bottom:1px solid var(--border);font-size:14px;display:flex;justify-content:space-between;gap:8px}
.brigade-box-body{padding:12px;display:grid;gap:10px}
.install-detail-grid{display:grid;grid-template-columns:1.2fr .8fr;gap:16px}
.history-list{display:grid;gap:8px}
.history-item{padding:10px 12px;border-radius:10px;background:var(--surface-2);font-size:12px;color:var(--text-2)}
.check-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
.check-grid label{display:flex;align-items:center;gap:8px;padding:8px 10px;border:1px solid var(--border);border-radius:10px;background:var(--surface-2);font-size:12px;color:var(--text-2)}
.check-grid input{width:auto}
.modal.wide{max-width:920px}
/* Карточка сделки с панелью клиента справа. Шире обычного окна, потому что
   слева форма, а справа история заказов — в 600 пикселях они встали бы одна
   под другой, и панель уехала бы под форму, то есть туда, где её не видно. */
.modal.deal-modal{max-width:1180px}
/* Колонки почти поровну: справа теперь не только сведения о клиенте, но и
   переписка с ним, и при прежнем перевесе влево чат оказывался в узкой полосе,
   где сообщения переносятся по два слова. */
.dealclient-split{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:20px;align-items:start}
/* Заказ — две строки, а не строка таблицы: названия изделий вроде
   «Пам'ятник вертикальний + плитка» не сжимаются, и в таблице колонки уезжали
   за край панели. Здесь ширина панели ничего не ограничивает. */
.dealclient-orders{display:grid;gap:8px}
.dealclient-order{border:1px solid var(--border);border-radius:10px;padding:9px 11px}
.dealclient-order.current{background:var(--accent-soft);border-color:var(--accent)}
.dealclient-order-top{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
.dealclient-order-sub{font-size:12px;margin-top:3px;word-break:break-word}
/* Кнопки прижаты вправо и не растягивают строку: при узкой панели номер и
   состояние важнее, они остаются на первой строке целиком. */
.dealclient-acts{margin-left:auto;display:flex;gap:4px}
/* На узком экране колонки складываются, и панель встаёт НАД формой: она
   отвечает на вопрос «что это за клиент», который возникает до правки полей,
   а не после. */
@media(max-width:980px){.dealclient-split{grid-template-columns:1fr}
  .dealclient-side{order:-1}}
.dealclient-form{min-width:0}
.dealclient-side{min-width:0;padding-left:20px;border-left:1px solid var(--border)}
@media(max-width:980px){.dealclient-side{padding-left:0;border-left:0;border-bottom:1px solid var(--border);padding-bottom:16px}}
.dealclient-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:14px}
.dealclient-head .hint{width:100%;margin:0}
.modal.install-modal{max-width:980px}
@media(max-width:780px){
  .install-detail-grid{grid-template-columns:1fr}
  .check-grid{grid-template-columns:1fr}
  .calendar.install-cal .cal-head{display:none}
  .calendar.install-cal .cal-grid{grid-template-columns:1fr}
  .calendar.install-cal .cal-cell{min-height:auto;border-right:none}
}
body.auth-lock #app{display:none}
body.auth-lock{min-height:100vh}
.login-shell{min-height:100vh;display:grid;place-items:center;padding:24px;background:#eceef2;
  --surface:#ffffff;--surface-2:#f6f8fb;--surface-3:#eef1f6;--text:#20242e;--text-2:#3b4150;--muted:#6b7280;--faint:#9aa1b0;--border:#e4e7ee;--border-2:#dbe0e8;
  --accent:#b98a3e;--accent-2:#cba35d;--accent-ink:#8a6524;--accent-soft:rgba(185,138,62,.14);--ring:rgba(185,138,62,.35)}
.login-card{width:min(430px,100%);background:linear-gradient(rgba(255,255,255,.30),rgba(255,255,255,.42)),url("/brand/marble-light.jpg");background-size:cover;background-position:center;border:1px solid var(--border);border-radius:20px;box-shadow:var(--shadow-lg);padding:28px}
.login-brand{display:flex;align-items:center;gap:12px;margin-bottom:22px}
.login-brand .brand-mark{position:relative}
.login-card h1{font-size:22px;margin-bottom:4px}
.login-card p{margin:0 0 18px;color:var(--muted);font-size:14px}
.login-logo{display:flex;align-items:center;justify-content:center;gap:18px;margin:6px 0 20px}
.login-logo-gem{width:88px;height:88px;color:#C99A46;flex:none;filter:drop-shadow(0 2px 7px rgba(160,120,40,.28))}
.login-logo-text{display:flex;flex-direction:column;align-items:flex-start;line-height:1}
.lg-granit{font-size:33px;font-weight:700;letter-spacing:.11em;color:#2b2f3a}
.lg-aesth{font-size:22px;font-weight:600;letter-spacing:.22em;color:#2b2f3a;margin-top:6px}
.lg-erp{display:flex;align-items:center;gap:9px;font-size:12px;font-weight:600;letter-spacing:.26em;color:#b98a3e;margin-top:8px}
.lg-erp span{height:1px;width:26px;background:#c9a24b;display:block}
@media(max-width:420px){.login-logo{gap:12px}.login-logo-gem{width:56px;height:56px}.lg-granit{font-size:26px}.lg-aesth{font-size:18px}}
.login-form{display:grid;gap:12px}
.login-form label{display:grid;gap:6px;font-size:12px;font-weight:700;color:var(--muted)}
.login-form input{padding:11px 12px;border-radius:11px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font-size:14px;outline:none}
.login-form input:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.login-password-field{position:relative}
.login-password-field input{width:100%;padding-right:44px}
.login-password-toggle{position:absolute;right:7px;top:50%;transform:translateY(-50%);width:32px;height:32px;border:0;border-radius:9px;background:transparent;color:var(--muted);display:grid;place-items:center;cursor:pointer}
.login-password-toggle:hover{background:var(--surface-3);color:var(--text)}
/* Кнопку рисует скрипт Телеграма — своей рамкой, в своих цветах. Наше здесь
   только место под неё и разделитель: без него кнопка липнет к «Забули пароль»
   и читается как ещё одно действие той же формы, а это отдельный путь входа. */
.tg-login{display:grid;gap:10px;margin-top:16px}
.tg-login-or{display:flex;align-items:center;gap:10px;color:var(--faint);font-size:12px}
.tg-login-or::before,.tg-login-or::after{content:"";flex:1;height:1px;background:var(--line)}
.tg-login iframe{margin:0 auto;display:block}
.tg-login-item{display:grid;gap:5px;justify-items:center}
.tg-login-item+.tg-login-item{margin-top:10px}
.tg-login-dep{font-size:12px;font-weight:600;color:var(--text-2)}
.tg-login-note{margin:0;text-align:center;font-size:12px;color:var(--muted)}
/* Вакансия, на которую можно завести человека, отзывается как кнопка: без
   этого она выглядит той же строкой схемы, что и раньше, и нажимать её никто
   не догадается. */
.org-post.is-addable{cursor:pointer;width:100%;text-align:left;font:inherit}
.org-post.is-addable:hover{border-color:var(--accent);background:var(--accent-soft)}
.org-post.is-addable:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Не кнопка: это запасной путь, и выглядеть он должен как подсказка, а не как
   ещё одно равноправное действие рядом с «Увійти». */
.login-link{background:none;border:0;padding:2px;font:inherit;font-size:12px;
  color:var(--muted);text-decoration:underline;cursor:pointer}
.login-link:hover{color:var(--text)}
.desk-code{display:grid;gap:10px;margin-top:16px;text-align:center}
.desk-code-lead{margin:0;font-size:13px;color:var(--text-2);line-height:1.45}
/* Код переписывают глазами с экрана на экран, поэтому крупно и вразрядку:
   слитные восемь знаков читаются с ошибкой на третьей попытке. */
.desk-code-value{font-size:30px;font-weight:700;letter-spacing:.16em;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:var(--text)}
.desk-code-state{font-size:12px;color:var(--muted)}
/* Читают её ровно в тот момент, когда открыли бота и не нашли «Профіль»,
   поэтому она стоит здесь, а не в справке. */
.desk-code-hint{margin:0;font-size:12px;line-height:1.45;color:var(--faint)}
.login-error{display:none;border:1px solid var(--bad-soft);background:var(--bad-soft);color:var(--bad-ink);border-radius:10px;padding:9px 11px;font-size:12px;font-weight:600}
.login-error.show{display:block}
.auth-user-btn{display:flex;align-items:center;gap:9px;border:1px solid var(--border);background:var(--surface);border-radius:12px;padding:6px 10px;color:var(--text);font-weight:700;font-size:14px}
.auth-user-btn small{display:block;color:var(--muted);font-weight:600;font-size:12px;line-height:1}
.auth-menu{display:flex;gap:8px;align-items:center;min-width:0}
/* На узком экране верхняя панель требовала 465px при окне 390: имя с ролью
   и подпись раздела распирали её, и вся страница тянулась вбок. Оставляем
   значки, текст прячем — профиль и выход доступны теми же кнопками. */
@media(max-width:700px){
  .topbar{padding:10px 12px;gap:8px}
  .top-title h2{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .top-title p{display:none}
  .top-title{min-width:0;flex:1 1 auto}
  .auth-user-btn{padding:5px;gap:0}
  .auth-user-btn>span:last-child{display:none}
  .icon-btn{width:34px;height:34px}
  .auth-menu{gap:6px;flex:none}
}

/* ---------- Roadmap ---------- */
.roadmap{position:relative;padding-left:28px}
.roadmap::before{content:"";position:absolute;left:9px;top:8px;bottom:8px;width:2px;background:linear-gradient(var(--accent),var(--bronze))}
.rm-phase{position:relative;margin-bottom:16px}
.rm-dot{position:absolute;left:-27px;top:20px;width:20px;height:20px;border-radius:50%;background:var(--surface);border:3px solid var(--accent);display:grid;place-items:center}
.rm-dot.b{border-color:var(--bronze)}
.rm-card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:16px 18px;box-shadow:var(--shadow-sm)}
.rm-week{font-size:12px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--accent-ink)}
.rm-card h4{font-size:14px;margin:4px 0 10px}
.rm-card ul{margin:0;padding-left:2px;list-style:none;display:grid;gap:7px}
.rm-card li{display:flex;gap:9px;align-items:flex-start;font-size:14px;color:var(--text-2)}
.rm-card li svg{width:16px;height:16px;color:var(--good-ink);flex:none;margin-top:1px}

/* ---------- Modal / toast ---------- */
.overlay{position:fixed;inset:0;background:rgba(12,15,26,.5);backdrop-filter:blur(3px);z-index:100;display:none;align-items:center;justify-content:center;padding:20px}
.overlay.show{display:flex;animation:fade .2s}
.modal{background:var(--surface);border:1px solid var(--border);border-radius:var(--r-lg);box-shadow:var(--shadow-lg);width:100%;max-width:600px;max-height:90vh;overflow:auto;animation:pop .25s cubic-bezier(.2,.9,.3,1.2)}
@keyframes pop{from{transform:scale(.94) translateY(10px);opacity:0}to{transform:none;opacity:1}}
/* z-index у прилипающей шапки обязателен: внутри модалки есть свои липкие
   элементы со своим z-index — заголовки таблиц и разделители дней в чате,
   который теперь живёт в правой панели карточки сделки. Без слоя они
   прокручиваются ПОВЕРХ шапки, и от неё остаётся висеть в воздухе одна
   кнопка закрытия. Подвал липкий по той же причине. */
.modal-head{display:flex;align-items:center;justify-content:space-between;padding:18px 22px;border-bottom:1px solid var(--border);position:sticky;top:0;z-index:20;background:var(--surface)}
.modal-head h3{font-size:18px}
.modal-body{padding:22px}
.modal-foot{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:10px;padding:16px 22px;border-top:1px solid var(--border);position:sticky;bottom:0;z-index:20;background:var(--surface)}
/* Выбор способа входа занимает всю ширину: это развилка, а не ещё одно поле
   в паре. */
.user-way{grid-column:1/-1}
/* minmax(0,…), а не 1fr: 1fr снизу равен min-content, и колонка не ужимается
   меньше самого широкого неразрывного содержимого — в профиле на телефоне
   сетка была 321, колонка 326, и поля торчали на пять пикселей за край. */
.form-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:14px}
.form-grid .full{grid-column:1/-1}
.form-grid label{display:flex;flex-direction:column;gap:5px;font-size:12px;font-weight:600;color:var(--muted)}
.form-grid input,.form-grid select,.form-grid textarea{padding:9px 12px;border-radius:10px;border:1px solid var(--border);background:var(--surface-2);color:var(--text);font-size:14px;font-family:inherit;outline:none}
.form-grid input:focus,.form-grid select:focus,.form-grid textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
/* Поля даты и времени получают ширину ЯВНО.
   Сейчас они помещаются только потому, что флекс-контейнер растягивает
   элемент по поперечной оси. На это нельзя полагаться: WebKit на iOS
   поля даты так не растягивает — они берут свою ширину и вылезают из
   контейнера вместе со значком календаря.
   Оговорка честности: воспроизвести жалобу владельца в эмуляторе Chrome на
   390px не удалось — там значок сидит внутри поля. Правка сделана не по
   найденной причине, а как страховка от известного расхождения движков:
   ширина здесь не следствие раскладки, а требование.
   И отдельно: getComputedStyle для input[type=date] в Chrome возвращает
   310px даже при заданном width:100%, когда по факту поле занимает 291.
   Диагностировать по этому числу нельзя — мерить надо getBoundingClientRect. */
.form-grid input[type="date"],.form-grid input[type="datetime-local"],
.form-grid input[type="time"],.form-grid input[type="month"]{
  width:100%;min-width:0;box-sizing:border-box}
@media(max-width:560px){.form-grid{grid-template-columns:minmax(0,1fr)}}

#toasts{position:fixed;right:20px;bottom:20px;z-index:200;display:flex;flex-direction:column;gap:10px}
.toast{display:flex;align-items:center;gap:11px;background:var(--surface);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:12px;padding:12px 16px;box-shadow:var(--shadow-lg);min-width:250px;animation:slidein .3s cubic-bezier(.2,.9,.3,1.1)}
.toast.g{border-left-color:var(--good-ink)} .toast.r{border-left-color:var(--bad-ink)} .toast.b{border-left-color:var(--info-ink)}
.toast svg{width:19px;height:19px;flex:none}
.toast.g svg{color:var(--good-ink)} .toast.r svg{color:var(--bad-ink)} .toast svg{color:var(--accent)}
.toast b{font-size:14px;display:block} .toast span{font-size:12px;color:var(--muted)}
@keyframes slidein{from{transform:translateX(120%);opacity:0}to{transform:none;opacity:1}}

.section-title{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin:24px 0 12px}
.hint{font-size:12px;color:var(--faint)}
.kv{display:flex;justify-content:space-between;align-items:baseline;gap:16px;padding:11px 0;border-bottom:1px solid var(--border);font-size:14px}
.kv:last-child{border-bottom:none}
/* Общие расходы стоят под таблицей направлений, отбитые линией: визуально
   видно, что строка относится к компании целиком, а не к последнему юрлицу. */
.pnl-shared{margin:0 16px 4px;padding-top:4px;border-top:1px solid var(--border)}
.pnl-shared .kv:last-child b{font-size:14px} .kv b{font-family:'Manrope';font-weight:700;text-align:right}
.kv>span{flex-shrink:0}
.chip-set{display:flex;flex-wrap:wrap;gap:8px}
.chip{display:inline-flex;align-items:center;gap:7px;padding:6px 12px;border-radius:20px;background:var(--surface-2);border:1px solid var(--border);font-size:12px;font-weight:400}
.chip .x{cursor:pointer;color:var(--faint);display:grid;place-items:center}
.chip .x:hover{color:var(--bad-ink)} .chip .x svg{width:13px;height:13px}
.legend{display:flex;flex-wrap:wrap;gap:14px;font-size:12px;color:var(--muted)}
.legend i{width:10px;height:10px;border-radius:3px;display:inline-block;margin-right:5px;vertical-align:middle}

/* ---------- Responsive / drawer ---------- */
.backdrop{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:35;display:none}
@media(max-width:1024px){
  #app{grid-template-columns:1fr}
  .sidebar{position:fixed;left:0;top:0;bottom:0;width:250px;transform:translateX(-100%)}
  #app.nav-open .sidebar{transform:none}
  #app.nav-open .backdrop{display:block}
  .burger{display:grid}
  .top-search{width:200px}
}
@media(max-width:640px){
  .content{padding:16px} .topbar{padding:12px 16px} .top-search{display:none}
  /* Шапка на телефоне — ОДНА строка.

     Раньше она переносилась: название занимало первую строку целиком, всё
     управление уезжало во вторую, а у кого включён переключатель направлений —
     кнопке профиля не хватало четырёх пикселей, и она срывалась на третью,
     упираясь в край экрана: крестик выхода обрезался.

     Убирать что-либо из шапки нельзя, поэтому в одну строку всё сжато: значки
     30 вместо 34, промежутки 4 вместо 8, точки направлений мельче. Названию
     остаётся около восьмидесяти пикселей — «Дашборд» помещается целиком,
     длинное обрезается многоточием.

     Обрезка здесь стоит немного: название раздела печатается ещё раз в самой
     странице, крупным заголовком под шапкой. В шапке оно — напоминание, а не
     единственное место, где его можно прочитать. */
  /* Поля по краям и промежутки урезаны до предела, за которым начинается
     слипание: это пятнадцать пикселей названию, и достаются они даром — в
     отличие от размера кнопок, который дальше уменьшать нельзя, пальцем по
     ним всё-таки попадают. */
  .topbar{flex-wrap:nowrap;gap:2px;padding:12px 7px}
  /* Шапка панели: заголовок и действия в одну строку. На телефоне в «Доставке»
     там заголовок в две строки плюс поле поиска — строка требовала больше, чем
     есть, и поле уезжало за правый край панели на тридцать пикселей: ровно то,
     что видно на снимке. Разрешаем перенос — поиск занимает свою строку
     целиком, а не остаток от заголовка. */
  .panel-head{flex-wrap:wrap;gap:10px;padding:14px}
  .panel-actions{flex-wrap:wrap;width:100%;min-width:0}
  .panel-actions>*{min-width:0}
  .panel-actions .field,.panel-actions input[type="search"],.panel-actions input[type="text"]{flex:1 1 100%}
  .burger{width:28px;height:28px;flex:0 0 auto}
  .top-title{flex:1 1 auto;min-width:0}
  .icon-btn{width:28px;height:28px;flex:0 0 auto}
  /* «РУС»/«УКР» — три буквы жирным. Двенадцатый кегль остался от кнопки 38px,
     а здесь она 28: подписи нужно 30, внутри 26, и она садилась на рамку. */
  #langBtn{font-size:10px}
  .auth-menu{gap:3px;flex:0 0 auto}
  /* Ещё шесть пикселей названию. Дело не в педантизме: без них «Виробництво»
     не влезало ровно на ОДИН пиксель — 118 при 117 — и получало многоточие,
     хотя помещается целиком. */
  .auth-user-btn{padding:1px}
  .auth-user-btn .avatar{width:24px!important;height:24px!important;font-size:10px!important}
  .dept-switch{gap:2px;flex:0 0 auto}
  .dept-btn{padding:2px}
  .top-title h2{font-size:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Подзаголовок дублирует заголовок страницы в самом разделе, а высоту на
     телефоне занимает заметную. */
  .top-title p{display:none}
  .topbar .auth-menu{margin-left:auto}
  .crm-top-scroll{top:63px}
  .page-head h1{font-size:20px}

  /* ---------- Шапка раздела: вернуть экран списку ----------

     Заголовок с подзаголовком, две кнопки, подпись «Пошук» над полем и сама
     строка поиска — это ещё триста пикселей поверх фильтров. На телефоне
     список начинался там, где его уже не видно.

     Подзаголовок убираем: он объясняет раздел, а название раздела и так стоит
     в шапке приложения. Подпись над полем поиска тоже — в самом поле написано,
     что искать. Поиск и «Фильтры» встают в одну строку. */
  .page-head{margin-bottom:12px;gap:10px}
  .page-head p{display:none}
  .page-head h1{font-size:19px}

  /* Карточка сделки на телефоне: в подвале бывает до шести действий
     (уведомить, переписка, монтаж, удалить, отмена, сохранить). Общий flex
     переносил их по одной кнопке и съедал почти половину экрана. Две плотные
     колонки сохраняют все действия, но укладывают их в три коротких ряда;
     длинные подписи переносятся внутри кнопки, не распирая модалку. */
  .modal.deal-modal{max-height:calc(100vh - 16px);border-radius:16px}
  .modal.deal-modal .modal-head{padding:12px 14px}
  .modal.deal-modal .modal-head h3{font-size:14px;line-height:1.25}
  .modal.deal-modal .modal-body{padding:14px}
  .modal.deal-modal .modal-foot{
    display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px;
    padding:8px 10px calc(8px + env(safe-area-inset-bottom));
  }
  .modal.deal-modal .modal-foot .btn{
    min-width:0;min-height:36px;justify-content:center;gap:5px;
    padding:7px 6px;font-size:12px;line-height:1.2;white-space:normal;
    text-align:center;
  }
  .modal.deal-modal .modal-foot .btn svg{width:14px;height:14px;flex:none}

  .toolbar{gap:8px;margin-bottom:12px}
  .field.search>span{display:none}
  .field.search svg{bottom:auto;top:50%;transform:translateY(-50%)}
  .date-full{display:none}
  .date-short{display:inline}
  .unit-word{display:inline}
  /* Плитки-итоги над списком: втроём в столбик они занимали треть экрана,
     а нужны для одного взгляда. Значок убираем, ставим три в ряд — цифру
     видно, а место остаётся списку. */
  .stat-tiles{grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}
  .stat-tile{flex-direction:column;align-items:flex-start;gap:2px;padding:9px 10px}
  .stat-tile .si{display:none}
  .stat-tile b{font-size:14px}
  .stat-tile span{font-size:12px;line-height:1.3}
  /* Выгрузку с телефона делают редко, а сто пикселей она занимает наравне с
     «Добавить». Кнопка не исчезает совсем — она есть на компьютере. */
  .page-actions .hide-on-phone{display:none}
  /* Кнопки раздела ровными парами.
     На складе их восемь, разной ширины, и переносились они как придётся:
     3-2-2-1, с рваным краем и дырами. Сумма ширин около тысячи пикселей при
     358 доступных — перенос неизбежен, вопрос лишь в том, ровный он или нет.
     Кнопка растёт до половины строки; если в строке она одна — занимает её
     целиком, на телефоне это удобнее половинки у левого края. */
  .page-actions{gap:8px;width:100%}
  /* Перенос ВНУТРИ кнопки. Пары сделаны по складу, где подписи короткие; в
     телефонии они длинные — «Сымитировать входящий звонок», — а у .btn стоит
     white-space:nowrap, и текст лез за границу кнопки на соседнюю.
     Обрезать многоточием нельзя: «Сымитировать входящий» и «Сымитировать
     пропущенный» различаются последним словом, и с многоточием их не
     различить. Поэтому кнопка растёт вниз, а пары остаются ровными. */
  .page-actions>.btn{flex:1 1 calc(50% - 4px);justify-content:center;min-width:0;
    white-space:normal;text-align:center;line-height:1.25;padding-top:8px;padding-bottom:8px}

  /* Фильтры под кнопку. Четыре списка занимали пол-экрана, и сделки
     начинались там, где их уже не видно. Поиск остаётся снаружи. */
  .crm-filters-toggle{display:inline-flex;align-items:center;flex:0 0 auto}
  .crm-filters{display:none;flex-wrap:wrap;gap:10px;width:100%;margin-top:2px}
  .crm-toolbar.filters-open .crm-filters{display:flex}
  .prod-filters-toggle{display:inline-flex;align-items:center;flex:0 0 auto}
  .prod-filters{display:none;flex-wrap:wrap;gap:10px;width:100%;margin-top:2px}
  #productionToolbar.filters-open .prod-filters{display:flex}
  /* ОДНА раскладка фильтров на все разделы.
     Раньше правило «два поля в ряд» стояло только у CRM, а в телефонии и
     производстве ширины определял сам контент: у полей задан жёсткий
     min-width:150px, и одни списки растягивались во всю строку, другие вставали
     парами, третьи оставляли дыру справа. Получалась лесенка.
     Константа та же, что у кнопок раздела: половина строки, а последний в
     строке и единственный — вся строка. Пусто справа не остаётся.
     Флажки не трогаем: у них своя ширина в 16px, растягивать квадратик
     до половины экрана незачем. */
  .toolbar,.crm-filters,.prod-filters,.tel-filter-row{align-items:flex-end}
  .toolbar>*,.crm-filters>*,.prod-filters>*,.tel-filter-row>*{flex:1 1 calc(50% - 5px);min-width:0}
  /* Сама панель фильтров лежит внутри панели инструментов и под то же правило
     попадала: становилась половиной строки, а её пять списков делили эту
     половину пополам — по 83 пикселя вместо 175. Раскрытая панель занимает
     строку целиком, пары строятся уже внутри неё. */
  .crm-filters,.prod-filters{flex:1 1 100%}
  /* Распорка отодвигает кнопку сброса вправо на широком экране. На телефоне
     разделять нечего, а под общим правилом она сама занимала половину строки,
     и слева от «Скинути фільтри» оставалась пустая клетка. У CRM это уже было
     учтено отдельным правилом — теперь во всех панелях. */
  .toolbar .spacer,.tel-filter-row .spacer,.prod-filters .spacer{display:none}
  .field input:not([type="checkbox"]),.field select{min-width:0;width:100%}
  /* Половина строки — про ШИРИНУ. По высоте фильтры съедали пол-экрана:
     подпись двенадцатым кеглем, поле с набивкой в девять пикселей, промежутки
     по десять. Ужимаем всё вместе — поле становится ниже примерно на треть. */
  .toolbar,.crm-filters,.prod-filters,.tel-filter-row{gap:6px}
  .toolbar .field,.crm-filters .field,.prod-filters .field,.tel-filter-row .field{gap:2px}
  .toolbar .field>span,.crm-filters .field>span,
  .prod-filters .field>span,.tel-filter-row .field>span{font-size:11px}
  .toolbar .field input:not([type="checkbox"]),.toolbar .field select,
  .crm-filters .field input:not([type="checkbox"]),.crm-filters .field select,
  .prod-filters .field input:not([type="checkbox"]),.prod-filters .field select,
  .tel-filter-row .field input:not([type="checkbox"]),.tel-filter-row .field select{
    padding:6px 10px;font-size:13px}
  /* Слева под значок лупы: он лежит поверх поля, и сжатая набивка его на текст
     и посадила. Контейнеры перечислены поимённо не для красоты: у правила
     сжатия на один класс больше, и короткий селектор .field.search input ему
     проигрывал — отступ не применялся вовсе. */
  .toolbar .field.search input,.crm-filters .field.search input,
  .prod-filters .field.search input,.tel-filter-row .field.search input{padding-left:34px}
  .crm-filters .field{flex:1 1 calc(50% - 5px);min-width:0}
  .crm-filters .spacer{display:none}
  .crm-filters .crm-cols,.crm-filters>.btn{flex:1 1 calc(50% - 5px)}
  /* Поиск и кнопка фильтров — одной строкой: по отдельности они съедали две. */
  .crm-toolbar .field.search{flex:1 1 auto;min-width:0}

  /* ---------- CRM на телефоне: список сделок вместо таблицы ----------

     Общий режим карточек — «подпись сверху, значение снизу» — честно
     показывает любую таблицу, но здесь это двенадцать полей столбиком:
     на одну сделку уходил весь экран, а взгляд прыгал слева направо между
     клиентом и суммой. Сделке нужен не перечень полей, а строка списка:
     кто, на сколько, до какого числа, на каком этапе.

     Раскладку делает сетка по именам колонок — разметка остаётся одна на
     оба экрана, второй отрисовки нет. Колонки, которых в раскладке нет,
     на телефоне не показываются; на широком экране всё как было. */
  .crm-tbl thead,.list-tbl thead{display:none}
  .crm-tbl,.crm-tbl tbody,.list-tbl,.list-tbl tbody{display:block}
  .crm-tbl tbody tr,.list-tbl tbody tr{
    display:grid;grid-template-columns:34px minmax(0,1fr) auto;
    grid-template-areas:"ava name sum" "ava sub date" "ava stage act";
    /* Промежутки и набивка ужаты по тому же правилу, что и фильтры: карточек
       на экране два десятка, и каждый лишний пиксель множится на двадцать. */
    gap:1px 9px;align-items:start;
    padding:9px 11px;margin:0 0 7px;background:var(--surface);
    border:1px solid var(--border);border-radius:14px;box-shadow:var(--shadow-sm)}
  /* Кружок с инициалами: содержимое берётся из атрибута строки, цвет — из
     переменной. Ради него не пришлось трогать разметку ячеек. */
  .crm-tbl tbody tr:before,.list-tbl tbody tr:before{
    content:attr(data-ini);grid-area:ava;width:34px;height:34px;border-radius:50%;
    background:var(--ava,var(--accent));color:#fff;display:grid;place-items:center;
    font-size:12px;font-weight:700;margin-top:2px}
  /* Разделители и отступы из общего режима карточек здесь не нужны: там они
     отделяют поле от поля, а тут ячейки — части одной строки списка. */
  .crm-tbl tbody td,.crm-tbl tbody td+td,
  .list-tbl tbody td,.list-tbl tbody td+td{display:block;border:none;padding:0;min-width:0}
  .crm-tbl tbody td:before,.list-tbl tbody td:before{display:none}
  /* Кнопки в строке списка меньше, чем в таблице: там они единственная цель
     на строку, здесь рядом сама строка и плашка этапа. */
  .crm-tbl tbody .crm-act-td .mini-btn{width:32px;height:32px}
  .crm-tbl tbody td[data-k="client"]{grid-area:name;font-size:14px;font-weight:700;line-height:1.25;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .crm-tbl tbody td[data-k="phone"]{grid-area:sub;font-size:12px;color:var(--muted);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .crm-tbl tbody td[data-k="amount"]{grid-area:sum;text-align:right;font-size:14px;font-weight:700;white-space:nowrap}
  /* Плашка срока переезжает на свою строку, а из третьей колонки уходит.
     Колонка объявлена auto — по самому широкому в ней, — и самым широким была
     не сумма («22 000 грн» ≈ 90px), а «Прострочено 16.08.2026» ≈ 147px. Имени
     оставалось 123 при нужных 173, и фамилия с именем не помещались. */
  /* Кнопки занимают ОБЕ строки с плашками справа: раньше они стояли в своей
     строке, и слева от них — во всю ширину карточки — оставалось пусто.
     Теперь пустоты нет, а сами кнопки встают по центру этих двух строк. */
  .crm-tbl tbody tr{grid-template-areas:"ava name sum" "ava sub sub" "ava date act" "ava stage act"}
  .crm-tbl tbody .crm-act-td{align-self:center;margin-top:0}
  /* Снимаем оформление ЛИПКОЙ КОЛОНКИ. В таблице колонка действий прибита к
     правому краю и едет вместе с ним: своё положение, свой фон, мягкая тень
     слева и жёсткие 78 пикселей. В карточке ехать нечему — фон ложится поверх
     карточки другим оттенком, тень даёт слева серую полосу, ширина держит
     пустое место. Вместе это и есть тот прямоугольник грязного цвета возле
     кнопки правки. */
  .crm-tbl tbody .crm-act-td,
  .crm-tbl tbody tr:hover .crm-act-td,
  .crm-tbl tbody tr.picked .crm-act-td{
    position:static;background:none;box-shadow:none;
    width:auto;min-width:0;max-width:none}
  .crm-tbl tbody td[data-k="next"]{grid-area:date;text-align:left;font-size:12px;color:var(--faint);white-space:nowrap;margin-top:2px}
  /* Плашки в карточке ниже, чем в таблице: там они единственное содержимое
     строки, здесь их две подряд. */
  .crm-tbl tbody .pill,.crm-tbl tbody .badge{padding-top:2px;padding-bottom:2px;font-size:13px}
  .crm-tbl tbody td[data-k="stage"]{grid-area:stage;margin-top:3px;min-width:0}
  .crm-tbl tbody .crm-act-td{grid-area:act;margin-top:6px}
  .crm-tbl tbody .crm-act-td .row-actions{opacity:1;justify-content:flex-end}
  /* Остальное открывается в карточке сделки: в строке списка это шум. */
  .crm-tbl tbody td[data-k="id"],
  .crm-tbl tbody td[data-k="created"],
  .crm-tbl tbody td[data-k="source"],
  .crm-tbl tbody td[data-k="manager"],
  .crm-tbl tbody td[data-k="product"],
  .crm-tbl tbody td[data-k="status"],
  .crm-tbl tbody td[data-k="comment"]{display:none}
  /* Строка-заглушка «ничего не найдено» под сетку не попадает. */
  .crm-tbl tbody tr:has(td[colspan]),.list-tbl tbody tr:has(td[colspan]){display:block;text-align:center}
  .crm-tbl tbody tr:has(td[colspan]):before,.list-tbl tbody tr:has(td[colspan]):before{display:none}

  /* Клиенты. Каркас тот же, отличается только тем, какое поле куда встаёт:
     имя и сумма сверху, телефон и дата последней сделки во вторую строку,
     счётчик сделок в третью. Источник, менеджер и число успешных — в карточке
     клиента; в строке списка они не помогают выбрать, кому звонить. */
  #clTable .list-tbl tbody td[data-k="client"]{grid-area:name;font-size:14px;font-weight:700;line-height:1.25;
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  #clTable .list-tbl tbody td[data-k="phone"]{grid-area:sub;font-size:12px;color:var(--muted)}
  #clTable .list-tbl tbody td[data-k="amount"]{grid-area:sum;text-align:right;font-size:14px;font-weight:700;white-space:nowrap}
  #clTable .list-tbl tbody td[data-k="last"]{grid-area:date;text-align:right;font-size:12px;color:var(--faint);white-space:nowrap}
  #clTable .list-tbl tbody td[data-k="deals"]{grid-area:stage;margin-top:5px;font-size:12px;color:var(--text-2);text-align:left}
  /* who() рисует собственный кружок с инициалами — вместе с кружком строки
     их было бы два подряд. Оставляем тот, что у строки: он крупнее и стоит
     на своём месте в сетке. */
  #clTable .list-tbl tbody td[data-k="client"] .who .avatar{display:none}
  #clTable .list-tbl tbody td[data-k="client"] .who{gap:0}
  #clTable .list-tbl tbody td[data-k="source"],
  #clTable .list-tbl tbody td[data-k="manager"],
  #clTable .list-tbl tbody td[data-k="won"]{display:none}

  /* ---------- Звонки, монтажи, производство ----------

     Здесь таблицы собираются строкой вручную, имён у ячеек нет, а колонок
     до девятнадцати. Опираемся на порядок: номер колонки проставляет
     tableLabelsApply. Правило обратное — сначала прячем всё, потом называем
     четыре-пять нужных. Так новая колонка не появится в карточке сама по
     себе и не сломает раскладку молча.

     Кружка с инициалами здесь нет: эти строки его не задают, а пустой круг
     хуже, чем его отсутствие. Сетка на две колонки. */
  #telephonyCallTable table.tbl thead,
  #installWorkspace table.tbl thead,
  #productionWorkspace table.tbl thead{display:none}
  #telephonyCallTable table.tbl,#telephonyCallTable table.tbl tbody,
  #installWorkspace table.tbl,#installWorkspace table.tbl tbody,
  #productionWorkspace table.tbl,#productionWorkspace table.tbl tbody{display:block}
  #telephonyCallTable table.tbl tbody tr,
  #installWorkspace table.tbl tbody tr,
  #productionWorkspace table.tbl tbody tr{
    display:grid;grid-template-columns:minmax(0,1fr) auto;
    grid-template-areas:"name sum" "sub date" "stage act";
    /* По центру строки, а не по её верху. Имя клиента — кнопка, и на длинном
       имени она в две строки: «7м 45с» прижималось к верхнему краю и висело
       над серединой имени вместо того, чтобы стоять напротив него. */
    gap:3px 10px;align-items:center;
    padding:12px 13px;margin:0 0 9px;background:var(--surface);
    border:1px solid var(--border);border-radius:14px;box-shadow:var(--shadow-sm)}
  #telephonyCallTable table.tbl tbody td,
  #installWorkspace table.tbl tbody td,
  #productionWorkspace table.tbl tbody td{display:none;border:none;padding:0;min-width:0}
  #telephonyCallTable table.tbl tbody td:before,
  #installWorkspace table.tbl tbody td:before,
  #productionWorkspace table.tbl tbody td:before{display:none}
  /* Имя клиента здесь — кнопка: по ней проваливаются в карточку. Кнопка
     меряется по содержимому и не ужимается, поэтому длинное имя с номером
     вылезало за край карточки — до пятнадцати пикселей в двенадцати строках
     из двадцати. Ужимаем кнопку и обрезаем ПОДПИСЬ, а не саму кнопку: рамка и
     отступы остаются целыми. */
  #telephonyCallTable table.tbl tbody td .btn,
  #installWorkspace table.tbl tbody td .btn,
  #productionWorkspace table.tbl tbody td .btn{max-width:100%;min-width:0;
    white-space:normal;text-align:left;line-height:1.25}
  #telephonyCallTable table.tbl tbody td .btn>span,
  #installWorkspace table.tbl tbody td .btn>span,
  #productionWorkspace table.tbl tbody td .btn>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  /* Значок сегмента стоит ПОСЛЕ подписи: когда подпись ужалась, наружу вылезал
     он. Расти и сжиматься ему нельзя — ужимается только текст. */
  #telephonyCallTable table.tbl tbody td .btn>.seg-dot,
  #installWorkspace table.tbl tbody td .btn>.seg-dot,
  #productionWorkspace table.tbl tbody td .btn>.seg-dot{flex:0 0 auto}
  /* Строка «название — значение»: обе части не ужимаются, и длинное значение
     («Прострочено» с датой и временем) уезжало за край панели на семьдесят
     пять — девяносто четыре пикселя. Разрешаем перенос: значение встаёт под
     подписью и читается целиком. Обрезать его многоточием нельзя — это как раз
     то, ради чего строку и смотрят. */
  /* Подпись объясняет, а не называет: перенос в ней безобиден, а вылет за край
     панели — нет. Без white-space:normal overflow-wrap бессилен: разрывать
     нечего, когда переносить запрещено. */
  .hint{white-space:normal;overflow-wrap:anywhere}
  /* Строка задачи: имя внутри не ужимается и торчит за край. Обрезаем
     многоточием — строка ведёт в карточку, где имя написано полностью, а
     торчащий за край текст не читается вовсе. */
  .task-main,.task-main>*{min-width:0;overflow:hidden;text-overflow:ellipsis}
  .kv{flex-wrap:wrap;gap:2px 12px}
  /* Длинное неразрывное слово — имя бота, адрес — не переносится и торчит за
     край. Значение объясняет, а не называет: разрыв в нём безобиден.
     Правило распространяется и на вложенные элементы: имя бота лежит в span
     внутри значения, и до прямых детей оно не доставало. */
  .kv>*{min-width:0}
  .kv,.kv *{overflow-wrap:anywhere}

  /* Общий вид четырёх мест раскладки. */
  /* Производство получает четвёртую строку под состояние заказа: просрочка —
     то, ради чего раздел и открывают, и делить место с датой она не должна.
     У телефонии и монтажа состояния в строке нет, поэтому у них раскладка
     прежняя. */
  #productionWorkspace table.tbl tbody tr{
    grid-template-areas:"name sum" "sub sub" "state state" "stage date" "mgr act"}
  #productionWorkspace table.tbl tbody td.f-mgr{grid-area:mgr;display:block;
    font-size:14px;color:var(--text);align-self:center;
    min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  #productionWorkspace table.tbl tbody td.f-state{
    grid-area:state;display:block;text-align:left;margin:2px 0}
  #productionWorkspace table.tbl tbody td.f-act{justify-self:start}

  #telephonyCallTable table.tbl tbody td.f-name,
  #installWorkspace table.tbl tbody td.f-name,
  #productionWorkspace table.tbl tbody td.f-name{grid-area:name;display:block;font-size:14px;font-weight:700;
    line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Имя клиента — то, по чему карточку узнают. Обрезать его многоточием на
     телефоне значит превратить «Бондар Віктор Миколайович» в «Бондар Віктор
     Миколайови…»: две карточки подряд станут неразличимы. Переносим в две
     строки, места на это хватает. */
  #productionWorkspace table.tbl tbody td.f-name{
    white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere}
  #telephonyCallTable table.tbl tbody td.f-sub,
  #installWorkspace table.tbl tbody td.f-sub,
  #productionWorkspace table.tbl tbody td.f-sub{grid-area:sub;display:block;font-size:12px;color:var(--muted);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* Изделие — значение, а не подпись: его ищут глазами наравне с именем. */
  #productionWorkspace table.tbl tbody td.f-sub{font-size:14px;color:var(--text)}
  #telephonyCallTable table.tbl tbody td.f-sum,
  #installWorkspace table.tbl tbody td.f-sum,
  #productionWorkspace table.tbl tbody td.f-sum{grid-area:sum;display:block;text-align:right;
    font-size:14px;font-weight:600;white-space:nowrap}
  #telephonyCallTable table.tbl tbody td.f-date,
  #installWorkspace table.tbl tbody td.f-date,
  #productionWorkspace table.tbl tbody td.f-date{grid-area:date;display:block;text-align:right;
    font-size:14px;color:var(--text);white-space:nowrap}
  #telephonyCallTable table.tbl tbody td.f-stage,
  #installWorkspace table.tbl tbody td.f-stage,
  #productionWorkspace table.tbl tbody td.f-stage{grid-area:stage;display:block;margin-top:6px}
  #telephonyCallTable table.tbl tbody td.f-act,
  #installWorkspace table.tbl tbody td.f-act,
  #productionWorkspace table.tbl tbody td.f-act{grid-area:act;display:block;margin-top:6px}
  #telephonyCallTable table.tbl tbody td.f-act .row-actions,
  #installWorkspace table.tbl tbody td.f-act .row-actions,
  #productionWorkspace table.tbl tbody td.f-act .row-actions{opacity:1;justify-content:flex-end}
  #telephonyCallTable table.tbl tbody td.f-act .mini-btn,
  #installWorkspace table.tbl tbody td.f-act .mini-btn,
  #productionWorkspace table.tbl tbody td.f-act .mini-btn{width:32px;height:32px}

  /* Заглушка «ничего не найдено» остаётся обычной строкой. */
  #telephonyCallTable table.tbl tbody tr:has(td[colspan]),
  #installWorkspace table.tbl tbody tr:has(td[colspan]),
  #productionWorkspace table.tbl tbody tr:has(td[colspan]){display:block;text-align:center}
  #telephonyCallTable table.tbl tbody td[colspan],
  #installWorkspace table.tbl tbody td[colspan],
  #productionWorkspace table.tbl tbody td[colspan]{display:block}
}
@media print{
  .sidebar,.topbar,.backdrop,#toasts,.page-actions,.no-print{display:none!important}
  #app{display:block} .content{padding:0;max-width:none}
  body{background:#fff} .panel,.kpi{box-shadow:none;border-color:#ddd;break-inside:avoid}
  body.print-report .view:not(#report-print-area){display:none}
}


/* ---------------- Телефония ---------------- */
.call-row-missed{background:var(--bad-soft)}
.call-row-overdue{box-shadow:inset 3px 0 0 var(--bad)}
.telephony-popup{position:fixed;right:22px;top:78px;width:min(390px,calc(100vw - 32px));max-height:calc(100vh - 96px);z-index:150;background:var(--surface);border:1px solid var(--border);border-left:4px solid var(--accent);border-radius:var(--r);box-shadow:var(--shadow-lg);animation:slidein .25s cubic-bezier(.2,.9,.3,1.1);overflow:auto}
.telephony-popup-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 16px;border-bottom:1px solid var(--border);background:var(--surface-2)}
.telephony-popup-body{padding:16px;display:grid;gap:10px}
.telephony-popup-actions{display:flex;gap:8px;flex-wrap:wrap;padding:0 16px 16px}
.telephony-popup-body .tp-field{display:flex;flex-direction:column;gap:4px;font-size:12px;font-weight:600;color:var(--muted)}
.telephony-popup-body .tp-field input,.telephony-popup-body .tp-field select,.telephony-popup-body .tp-field textarea{padding:8px 10px;border:1px solid var(--border);border-radius:9px;background:var(--surface-2);color:var(--text);font-size:14px;font-family:inherit;outline:none}
.telephony-popup-body .tp-field input:focus,.telephony-popup-body .tp-field select:focus,.telephony-popup-body .tp-field textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.telephony-popup .tp-badge{display:flex;align-items:center;justify-content:center;gap:5px;font-size:12px;font-weight:700;color:var(--warn-ink);background:var(--warn-soft);border-radius:8px;padding:6px 9px}
.recording-box{border:1px dashed var(--border-2);border-radius:12px;padding:14px;background:var(--surface-2);color:var(--muted);font-size:14px}
.tel-filter-row{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap}
.tel-filter-row .field input[type="checkbox"]{min-width:auto;width:16px;height:16px}
.tel-switch{display:flex;align-items:center;gap:7px;border:1px solid var(--border);border-radius:10px;padding:9px 12px;background:var(--surface);font-size:12px;font-weight:600;color:var(--muted)}
.tel-switch input{accent-color:var(--accent)}


/* Звание менеджера рядом с направлением. Не плашка-«достижение»: это рабочая
   характеристика месяца, от неё считается процент, и выглядеть она должна как
   подпись, а не как награда. */
.mgr-level{display:block;margin-top:2px;font-size:12px;font-weight:700;color:var(--accent-ink)}
.mgr-next{margin:6px 0 0;font-size:12px;color:var(--muted)}

/* Сумма ниже минимального чека. Не «ошибка» — предупреждение: дешёвая сделка
   бывает законной, и запрещать её никто не просил. Поэтому цвет и подчёркивание
   пунктиром, а не красная рамка. */
.amount-low{color:var(--bad-ink);border-bottom:1px dashed var(--bad);cursor:help}
.amount-hint{display:block;margin-top:4px;font-size:12px;color:var(--muted)}
.amount-hint.is-low{color:var(--bad-ink);font-weight:600}

/* Колонки итогов по видам. Уже колонок дня и с левой границей: тридцать одна
   клетка календаря и пять итогов иначе сливаются в одну ленту, и глаз не
   находит, где кончился месяц. */
.ts-total{width:34px;min-width:34px;padding-left:4px;padding-right:4px}
table.ts-table th.ts-total:first-of-type,table.ts-table td.ts-total:first-of-type{border-left:2px solid var(--border)}
