/* AgentGraph — граф штата. Одна вёрстка на три поверхности (T4, 05.08.2026).
 *
 * ЗАЧЕМ КОМПОНЕНТ. До 05.08 граф жил инлайном в investors.html вместе со
 * своим массивом узлов. Дашборду нужен был такой же — и он получил бы вторую
 * копию разметки со второй копией правды о штате. Ровно та болезнь, из-за
 * которой на витрине сошлись «5 в работе» и «6 в разработке» при штате 10.
 * Теперь разметка одна, конфигурации три, данные — из /api/roster.
 *
 * Визуальный язык (стекло, оранжевый акцент, точка статуса) взят с прода
 * без изменений: он принят владельцем в C51/C55/C56 и проверен на 375/1440.
 * Правила Stitch v2 — функциональные правки можно, визуальные только по макету.
 */

.nbg {
  --nbg-accent: #FF8C42;
  --nbg-cyan: #00C9DB;
  /* Чернила компонента одной тройкой RGB: полтора десятка полупрозрачных
     оттенков (линии, стекло, точки статуса, подписи) строились из литерала
     255,255,255 и поэтому были намертво привязаны к тёмной подложке. */
  --nbg-ink-rgb: 255, 255, 255;
  --nbg-ink: #fff;
  --nbg-dim: rgba(var(--nbg-ink-rgb), .55);
  --nbg-glass: rgba(var(--nbg-ink-rgb), .06);
  --nbg-edge: rgba(var(--nbg-ink-rgb), .12);
  position: relative;
  /* Явно, а не наследованием от страницы: узлы объявляют `color: inherit`, и
     на новой поверхности цвет подписей молча определялся бы вёрсткой вокруг. */
  color: var(--nbg-ink);
}

/* C102 — светлая поверхность (/investors).
 *
 * ПОПРАВКА 13.08: фраза «витрина светлая всегда» устарела. Свой :root у
 * страницы убран, она поехала на tokens.css, и у неё появилась ночная тема
 * (по настройке ОС, тумблера по-прежнему нет). Ночная ветка витрины — ниже,
 * блоком `[data-theme="night"] .nbg--investors`. Значения в самом
 * `.nbg--investors` остаются ДНЕВНЫМИ.
 *
 * Компонент приехал с дашборда, где подложка тёмная, и рисовал
 * белым по почти белому: узлы и подписи читались только на выделении.
 *
 * Тёмная поверхность после правки рендерится байт-в-байт как раньше — там
 * тройка остаётся 255,255,255, меняется только запись.
 *
 * Прозрачности, настроенные для «белым по тёмному», для «тёмным по светлому»
 * переиспользуются не везде: у текста при инверсии падает контраст (.40 от
 * тёмного по #F8F9FA — это ~3:1). Поэтому текстовые роли получают свои
 * значения, а заливки и рамки наследуют прежние альфы — там инверсия честная.
 */
.nbg--investors {
  --nbg-ink-rgb: 28, 35, 51;      /* --nb-text-1 витрины */
  --nbg-ink: #1C2333;
  --nbg-dim: #4A5163;             /* --nb-text-2: сплошной, а не альфа */
  --nbg-glass: #FFFFFF;           /* карточка узла — белая, как .card рядом */
  --nbg-edge: #E6E8EF;            /* --nb-border витрины */
}
.nbg--investors .nbg-line          { stroke: rgba(28, 35, 51, .22); }
.nbg--investors .nbg-line.is-soon  { stroke: rgba(28, 35, 51, .16); }
/* C102 (11.08.2026): три цвета подняты по замеру Cowork на живом /investors.
   `#6B7280` на белой карточке узла даёт 4.59 — формально проход, но впритык, и
   сам замер отметил его «следующим кандидатом». `#5F667A` = 5.72 при той же
   роли «приглушённый». Тёмная ветка графа (дашборд) не затронута: правила
   scoped на `.nbg--investors`. */
.nbg--investors .nbg-node[data-status="soon"]    .nbg-ms  { color: #5F667A; }
.nbg--investors .nbg-node[data-status="soon"]    .nbg-dot { background: #B9BEC9; }
.nbg--investors .nbg-node[data-status="unknown"] .nbg-dot { background: #C7CBD4; }
.nbg--investors .nbg-slot-s        { color: #5F667A; }

/* Ночная ветка витрины (13.08). Правила выше жёстко светлые: без этого блока
 * граф остался бы белым островом на ночной странице — тот же дефект, что
 * лечился в дневную сторону, только зеркальный.
 *
 * Тёмная ветка ДАШБОРДА (`.nbg` в начале файла) не затронута: всё здесь
 * scoped на `.nbg--investors`, и на это есть гард
 * `test_tyomnaya_vetka_grafa_ne_zatronuta`.
 *
 * Значения берём из ночной половины tokens.css, чтобы граф и страница вокруг
 * него не разъезжались: --nb-text-1 #F4F5F7, --nb-card #1A1A2E,
 * --nb-border rgba(255,255,255,.10). */
[data-theme="night"] .nbg--investors {
  --nbg-ink-rgb: 244, 245, 247;
  --nbg-ink: #F4F5F7;
  --nbg-dim: rgba(244, 245, 247, .65);
  --nbg-glass: #1A1A2E;
  --nbg-edge: rgba(255, 255, 255, .10);
}
[data-theme="night"] .nbg--investors .nbg-line         { stroke: rgba(244, 245, 247, .22); }
[data-theme="night"] .nbg--investors .nbg-line.is-soon { stroke: rgba(244, 245, 247, .16); }
/* Приглушённый на тёмной карточке: #5F667A ночью даёт 2.2 — берём
   --nb-ink-dim-on-dark #9CA3AF (6.18 на #1A1A2E), он ровно для этого и заведён. */
[data-theme="night"] .nbg--investors .nbg-node[data-status="soon"]    .nbg-ms  { color: #9CA3AF; }
[data-theme="night"] .nbg--investors .nbg-node[data-status="soon"]    .nbg-dot { background: #4B5163; }
[data-theme="night"] .nbg--investors .nbg-node[data-status="unknown"] .nbg-dot { background: #3C4152; }
[data-theme="night"] .nbg--investors .nbg-slot-s       { color: #9CA3AF; }
.nbg--investors .nbg-sect          { color: #5F667A; }
/* «работает» зелёным: #22C55E на белом = 2.28 при пороге 4.5. Тот же зелёный
   как ЗАЛИВКА точки остаётся — у неё контраст считается по рамке, не по тексту. */
.nbg--investors .nbg-node[data-status="works"]   .nbg-sttext { color: #15803D; }
/* Подпись ядра: ядро на витрине залито акцентом, и `--nbg-dim` (#4A5163) на
   #FF8C42 даёт 3.43. Тёмные чернила на акценте — 7.52. */
.nbg--investors .nbg-coresub       { color: #2C1400; }
.nbg--investors .nbg-coretitle     { color: #2C1400; }
.nbg--investors .nbg-task          { color: #3A4152; }
.nbg--investors .nbg-kpi           { background: #FFFFFF; }
.nbg--investors .nbg-dava          { background: #EEF0F5; }

/* Заголовок — ОДНА формулировка на все ширины (C62). Строка приходит готовой
   из roster_counts()['headline']; разметка её не режет и не пересобирает,
   поэтому 375 утверждает ровно то же, что 1440. */
.nbg-title {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 0 12px;
}
.nbg-title h3 { margin: 0; font: 600 17px/1.25 Unbounded, Onest, sans-serif; color: var(--nbg-ink); }
.nbg-headline { font: 500 13px/1.3 Onest, sans-serif; color: var(--nbg-dim); }

/* Полотно. Кнопки «на весь экран» здесь нет и не будет (C63): на 1440 у графа
   ровно те же органы управления, что на 375. Кнопка, которая есть только на
   широком экране, — это два разных продукта под одним адресом. */
.nbg-ws {
  position: relative;
  height: 520px;
  border: 1px solid var(--nbg-edge);
  border-radius: 16px;
  background: radial-gradient(120% 90% at 50% 12%, rgba(255, 140, 66, .10), transparent 60%);
  overflow: hidden;
}
.nbg--mini .nbg-ws { height: 300px; }
@media (max-width: 700px) { .nbg-ws { height: 460px; } }

.nbg-svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.nbg-line { stroke: rgba(var(--nbg-ink-rgb), .13); stroke-width: 1; }
.nbg-line.is-soon { stroke-dasharray: 4 4; stroke: rgba(var(--nbg-ink-rgb), .09); }

.nbg-nodes { position: absolute; inset: 0; }
.nbg-drag { position: absolute; z-index: 2; }

.nbg-node {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 176px;
  padding: 9px 11px;
  border: 1px solid var(--nbg-edge);
  border-radius: 13px;
  background: var(--nbg-glass);
  backdrop-filter: blur(9px);
  cursor: pointer;
  text-align: left;
  color: inherit;
  font: inherit;
}
.nbg-node:hover { border-color: rgba(255, 140, 66, .45); }
.nbg-node:focus-visible { outline: 2px solid var(--nbg-accent); outline-offset: 2px; }

.nbg-icon {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: 9px;
  background: rgba(var(--nbg-ink-rgb), .07);
}
.nbg-ms { font-family: 'Material Symbols Outlined'; font-size: 19px; line-height: 1; }

/* C62: подпись у КАЖДОГО узла. Раньше имя было только у «активных», а серые
   узлы стояли одними иконками — посетитель видел кружки и не мог сказать, что
   это. Имя + роль + состояние печатаются всегда, для всех статусов. */
/* C54: подписи ПЕРЕНОСЯТСЯ, а не обрезаются. «Видеоаналити…» и «Контент-Фаб…»
   уже уезжали на прод — многоточие в имени сотрудника делает узел нечитаемым,
   а именно имя и есть смысл подписи. min-width:0 обязателен: без него flex не
   даёт блоку сжаться и перенос не срабатывает. */
.nbg-info { min-width: 0; }
.nbg-name {
  font: 600 13px/1.2 Onest, sans-serif;
  color: var(--nbg-ink);
  overflow-wrap: anywhere;
}
.nbg-role {
  font: 400 11px/1.3 Onest, sans-serif;
  color: var(--nbg-dim);
  overflow-wrap: anywhere;
}
.nbg-st { display: flex; align-items: center; gap: 5px; margin-top: 3px; }
.nbg-dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; }
.nbg-sttext { font: 500 11px/1 Onest, sans-serif; }

.nbg-node[data-status="works"]     .nbg-dot { background: #22C55E; }
.nbg-node[data-status="works"]     .nbg-sttext { color: #22C55E; }
.nbg-node[data-status="works"]     .nbg-ms { color: var(--nbg-accent); }
.nbg-node[data-status="connected"] .nbg-dot { background: var(--nbg-cyan); }
.nbg-node[data-status="connected"] .nbg-sttext { color: var(--nbg-cyan); }
.nbg-node[data-status="connected"] .nbg-ms { color: var(--nbg-cyan); }
.nbg-node[data-status="soon"]      .nbg-dot { background: rgba(var(--nbg-ink-rgb), .32); }
.nbg-node[data-status="soon"]      .nbg-sttext { color: var(--nbg-dim); }
.nbg-node[data-status="soon"]      .nbg-ms { color: rgba(var(--nbg-ink-rgb), .40); }
.nbg-node[data-status="unknown"]   .nbg-dot { background: rgba(var(--nbg-ink-rgb), .22); }
.nbg-node[data-status="unknown"]   .nbg-sttext { color: var(--nbg-dim); }

/* «Скоро» — приглушены и обведены пунктиром: роль, которой ещё нет, не должна
   выглядеть так же плотно, как работающая. Это же отделяет их от ядра. */
.nbg-node[data-status="soon"] { border-style: dashed; opacity: .78; }

/* Свободный слот. Не сотрудник и не роль — заявление, что место есть.
   Кликом ничего не открывает: за ним нет данных, а пустой drawer — обман. */
.nbg-slot {
  display: grid;
  place-items: center;
  width: 176px; min-height: 56px;
  padding: 10px;
  border: 1px dashed rgba(var(--nbg-ink-rgb), .22);
  border-radius: 13px;
  background: transparent;
  text-align: center;
}
.nbg-slot-t { font: 600 12px/1.25 Onest, sans-serif; color: var(--nbg-dim); }
.nbg-slot-s { font: 400 11px/1.3 Onest, sans-serif; color: rgba(var(--nbg-ink-rgb), .38); margin-top: 2px; }

/* ЯДРО. Отделено от «Скоро» тремя признаками сразу — сплошная рамка против
   пунктирной, оранжевое свечение против его отсутствия, полная непрозрачность
   против приглушённой. Требование T4: ядро не должно читаться как «ещё одна
   роль, которой пока нет». */
.nbg-corenode {
  display: flex; flex-direction: column; align-items: center;
  gap: 7px; width: 152px; padding: 15px 13px;
  border: 1px solid rgba(255, 140, 66, .45);
  border-radius: 17px;
  background: rgba(255, 140, 66, .10);
  box-shadow: 0 0 0 6px rgba(255, 140, 66, .05), 0 10px 34px rgba(255, 140, 66, .13);
  backdrop-filter: blur(9px);
  text-align: center;
  opacity: 1;
}
.nbg-coreicon {
  width: 42px; height: 42px; display: grid; place-items: center;
  border-radius: 50%; background: rgba(255, 140, 66, .18);
}
.nbg-coreicon .nbg-ms { font-size: 23px; color: var(--nbg-accent); }
.nbg-coretitle { font: 600 14px/1.2 Unbounded, Onest, sans-serif; color: var(--nbg-ink); }
.nbg-coresub { font: 400 11px/1.3 Onest, sans-serif; color: var(--nbg-dim); }

/* Сетка — фолбэк C55: если кольцо не влезло, секция переключается в сетку.
   Те же карточки и статусы, без наездов и обрезки. */
.nbg--grid .nbg-ws { height: auto; padding: 14px; }
.nbg--grid .nbg-svg { display: none; }
.nbg--grid .nbg-nodes {
  position: static; display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(176px, 1fr));
}
.nbg--grid .nbg-drag {
  position: static !important; left: auto !important; top: auto !important;
  transform: none !important;
}
.nbg--grid .nbg-core { grid-column: 1 / -1; }
.nbg--grid .nbg-corenode { width: auto; flex-direction: row; text-align: left; }
.nbg--grid .nbg-node, .nbg--grid .nbg-slot { width: auto; }

.nbg-hint { margin-top: 10px; font: 400 12px/1.4 Onest, sans-serif; color: var(--nbg-dim); }

/* Честные состояния полотна: пусто и ошибка выглядят по-разному и оба
   называют причину. Молча показать пустой круг — значит соврать, что штата нет. */
.nbg-msg {
  position: absolute; inset: 0; display: grid; place-items: center;
  padding: 24px; text-align: center;
  font: 400 13px/1.5 Onest, sans-serif; color: var(--nbg-dim);
}

/* ---- Drawer (T5) ------------------------------------------------------- */
.nbg-drawer {
  position: fixed; z-index: 60; top: 0; right: 0; bottom: 0;
  width: min(420px, 100vw);
  display: flex; flex-direction: column;
  background: #14142B;
  border-left: 1px solid var(--nbg-edge);
  box-shadow: -18px 0 46px rgba(0, 0, 0, .42);
  transform: translateX(100%);
  transition: transform .22s ease;
}
.nbg-drawer[data-open="1"] { transform: none; }
.nbg-scrim {
  position: fixed; inset: 0; z-index: 59;
  background: rgba(6, 6, 18, .55);
  opacity: 0; pointer-events: none; transition: opacity .22s ease;
}
.nbg-scrim[data-open="1"] { opacity: 1; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) {
  .nbg-drawer, .nbg-scrim { transition: none; }
}
/* На узком экране лист выезжает снизу — правая шторка в 420px на 375
   закрывает экран целиком и читается как «страница сломалась». */
@media (max-width: 560px) {
  .nbg-drawer {
    top: auto; left: 0; width: auto; max-height: 86vh;
    border-left: 0; border-top: 1px solid var(--nbg-edge);
    border-radius: 18px 18px 0 0;
    transform: translateY(100%);
  }
}

.nbg-dhead { display: flex; align-items: flex-start; gap: 12px; padding: 18px 18px 14px; border-bottom: 1px solid var(--nbg-edge); }
.nbg-dava { width: 46px; height: 46px; border-radius: 12px; object-fit: cover; flex: 0 0 auto; background: rgba(var(--nbg-ink-rgb), .06); }
/* C91 · заглушка вместо портрета, пока арт породы не нарисован */
.nbg-dava--ini { display: flex; align-items: center; justify-content: center;
  font-family: Unbounded, sans-serif; font-size: 18px; font-weight: 700; line-height: 1;
  color: var(--nbg-ava-c, #FF8C42);
  background: color-mix(in srgb, var(--nbg-ava-c, #FF8C42) 22%, transparent); }
.nbg-dname { font: 600 16px/1.2 Unbounded, Onest, sans-serif; color: var(--nbg-ink); }
.nbg-drole { font: 400 12px/1.35 Onest, sans-serif; color: var(--nbg-dim); margin-top: 3px; }
.nbg-dclose {
  margin-left: auto; flex: 0 0 auto;
  width: 32px; height: 32px; display: grid; place-items: center;
  border: 1px solid var(--nbg-edge); border-radius: 9px;
  background: transparent; color: var(--nbg-dim); cursor: pointer;
}
.nbg-dclose:hover { color: var(--nbg-ink); }
.nbg-dbody { padding: 16px 18px 22px; overflow-y: auto; }
.nbg-sect { font: 600 11px/1 Onest, sans-serif; letter-spacing: .06em; text-transform: uppercase; color: rgba(var(--nbg-ink-rgb), .42); margin: 16px 0 8px; }
.nbg-sect:first-child { margin-top: 0; }

.nbg-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(96px, 1fr)); gap: 8px; }
.nbg-kpi { padding: 10px; border: 1px solid var(--nbg-edge); border-radius: 11px; background: rgba(var(--nbg-ink-rgb), .03); }
.nbg-kpi b { display: block; font: 600 17px/1.15 Unbounded, Onest, sans-serif; color: var(--nbg-ink); }
.nbg-kpi span { font: 400 11px/1.3 Onest, sans-serif; color: var(--nbg-dim); }

.nbg-tasks { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.nbg-task { display: flex; gap: 9px; align-items: baseline; font: 400 12px/1.4 Onest, sans-serif; color: rgba(var(--nbg-ink-rgb), .78); }
.nbg-task i { font-style: normal; font-size: 11px; color: var(--nbg-dim); flex: 0 0 auto; }
.nbg-empty { font: 400 12px/1.5 Onest, sans-serif; color: var(--nbg-dim); }

/* «Нужен этот сотрудник» — только у ролей, которых ещё нет. */
.nbg-demand { margin-top: 6px; }
.nbg-demand-btn {
  width: 100%; padding: 11px 14px;
  border: 1px solid rgba(255, 140, 66, .5); border-radius: 11px;
  background: rgba(255, 140, 66, .12);
  color: var(--nbg-accent);
  font: 600 13px/1.2 Onest, sans-serif; cursor: pointer;
}
.nbg-demand-btn:hover { background: rgba(255, 140, 66, .19); }
.nbg-demand-btn[disabled] { cursor: default; opacity: .75; }
.nbg-demand-n { display: block; margin-top: 7px; font: 400 12px/1.4 Onest, sans-serif; color: var(--nbg-dim); }
