/* ═══════════════════════════════════════════════════════════════════════
   «ПОЛНОЧЬ» — оформление кабинета. Утверждено владельцем 28.07.2026.
   Отдельным слоем поверх app.css: app.css держит раскладку и поведение,
   этот файл — цвет, глубину, свет и движение. Так их можно править
   независимо и не бояться задеть работающую механику.
   Подключается в index.html после app.css и кэшируется в sw.js.
   ═══════════════════════════════════════════════════════════════════════ */
/* ============================================================================
   ПОЛНОЧЬ · midnight.css
   Накладка оформления поверх /app/app.css (подключается ПОСЛЕ него).
   Правит только цвет, фон, границы, тени, радиусы, типографику и анимации.
   Геометрию .shell / .side / .board / .col не трогает.

   ГЛАВНАЯ ИДЕЯ
   Кабинет — это ночная студия: глубокий сине-чёрный воздух, над рабочей
   областью висит северное сияние, а всё, с чем работают, поднято к свету
   слоями и обведено тонким светящимся кантом.

   ПАЛИТРА (роль → значение)
     фон страницы .............. --bg      #2B2B2B   глубокая ночь
     панель / модалка / шапка .. --panel   #303030   холодный графит
     карточка .................. --card    #363636   поднятый слой
     вложенный слой / чип ...... --card2   #3E3E3E   самая светлая поверхность
     корыто колонки ............ --dp-trough #2A2A2A глубже, чем страница
     основной текст ............ --tx      #F0F0F0   лунно-белый
     второстепенный текст ...... --tx-mut  #B9B9B9   холодный серо-голубой
     третичный текст / мета .... --tx-dim  #9B9B9B   приглушённый
     акцент (текст, кант) ...... --acc     #9F9F9F   электрический индиго
     акцент-ссылка / hover ..... --acc-d   #BCBCBC   светлая сирень
     акцентная ЗАЛИВКА ......... #585858 → #4A4A4A   глубокий индиго
     успех ..................... --ok      var(--ok)   бирюза сияния
     внимание .................. --warn    var(--warn)   янтарь
     ошибка (текст) ............ --danger  var(--danger)   коралл
     ошибка (заливка) .......... #BB1637              тёмный гранат
     линия покоя / активная .... --line #414141 / --line2 #525252

   ПОСЧИТАННЫЙ КОНТРАСТ (WCAG 2.1, отношение яркостей)
     --tx  → --bg .............. 17.4 : 1   (норма ≥ 7)
     --tx  → --card2 (худшая) ... 13.4 : 1  (норма ≥ 7)
     --tx-mut → --bg ............ 9.8 : 1   (норма ≥ 4.5)
     --tx-mut → --card2 ......... 7.6 : 1
     --tx-dim → --bg ............ 6.6 : 1
     --tx-dim → --card2 ......... 5.1 : 1
     --acc (текст) → --bg ....... 7.3 : 1 ; → --card2 5.7 : 1
     --acc-d (ссылка) → --bg .... 10.3 : 1
     белый на акцентной заливке . 7.2 : 1 (светлая точка градиента) … 9.8 : 1
     витринные числа (градиент
       #FFFFFF→#B3B3B3) ......... не ниже 7.2 : 1 на любой поверхности
     белый на гранатовой заливке  8.0 : 1
     --ok 11.9 : 1 · --warn 11.5 : 1 · --danger 7.9 : 1 (всё к --bg)

   ТЕМА
   Кабинет здесь ТЁМНЫЙ ВСЕГДА: светлая тема забракована, поэтому
   [data-theme="light"] получает те же поверхности и тот же текст.
   Переключатель темы остаётся живым, но меняет только цвет «сияния»:
   ночь (индиго + бирюза) ⇄ заря (розовый + янтарь). Читаемость одинакова.

   ДВИЖЕНИЕ
   Постоянно ничего не анимируется (это рабочий инструмент, а не заставка):
   только наведение, появление блоков и переходы. Всё гасится
   в prefers-reduced-motion.

   ВНЕШНИХ РЕСУРСОВ НЕТ: только CSS-градиенты и тени.
   ============================================================================ */


/* ═══════════════════════════════════════════════════════════════════════════
   1 · ТОКЕНЫ ПАЛИТРЫ. Одинаковые в обеих темах — кабинет всегда тёмный.
   ═══════════════════════════════════════════════════════════════════════════ */
/* ТЁМНАЯ ТЕМА = Ant Design v5, algorithm.darkAlgorithm.
   Значения взяты 1-в-1 из токенов Ant, а не подобраны на глаз:
   colorBgLayout #000, colorBgContainer #141414, colorBgElevated #1F1F1F,
   текст — белый с прозрачностью 85/65/45%, границы #303030 / #424242,
   colorPrimary в тёмной теме #1668DC (не #1677FF — Ant затемняет его сам). */
:root{
  --bg:#000000;           /* colorBgLayout */
  --panel:#141414;        /* colorBgContainer */
  --card:#1F1F1F;         /* colorBgElevated */
  --card2:#262626;        /* ступень выше карточки */

  --tx:rgba(255,255,255,.85);       /* colorText */
  --tx-mut:rgba(255,255,255,.65);   /* colorTextSecondary */
  --tx-dim:rgba(255,255,255,.52);   /* colorTextTertiary, поднят: .45 давал 4.4:1 на фоне страницы */

  --acc:#1668DC;          /* colorPrimary (dark) */
  --acc-d:#3C89E8;        /* colorPrimaryHover */
  --acc-tx:#4096FF;       /* акцент как ТЕКСТ: #1668DC на #1F1F1F даёт 3.2:1 */
  --acc-on-fill:#1668DC;  /* заливка под БЕЛЫМ мелким текстом: нужно ≥4.5:1 */
  --hi:#1668DC;

  --line:#303030;         /* colorBorderSecondary */
  --line2:#424242;        /* colorBorder */
  --edge:#4E4E4E;         /* грань чуть светлее line2 — для color-mix бордюров */
  --glow:color-mix(in srgb, var(--acc) 25%, transparent);

  --ok:#49AA19;           /* colorSuccess (dark) */
  --warn:#D89614;         /* colorWarning (dark) */
  --danger:#DC4446;       /* colorError (dark) */

  --t-task:rgba(255,255,255,.65);
  --t-feature:#3C89E8;
  --t-bug:#DC4446;
  --t-design:rgba(255,255,255,.65);
  --t-content:#D89614;
  --t-deploy:#49AA19;

  --on-acc:#FFFFFF;       /* текст на акцентной заливке */

  /* --- собственные токены оформления --- */
  /* Ant заливает первичную кнопку ПЛОСКИМ colorPrimary, без градиента —
     поэтому обе точки одинаковые, «фаска» гасится (см. блок кнопок ниже). */
  --mn-fill-1:#1668DC;
  --mn-fill-2:#1668DC;
  --mn-fill-edge:#1668DC;
  --mn-glow:color-mix(in srgb, var(--acc) 35%, transparent);
  --mn-glow-soft:color-mix(in srgb, var(--acc) 14%, transparent);
  --mn-teal:#49AA19;
  --mn-red:#DC4446;
  --mn-hair:rgba(255,255,255,.06);
  --mn-num:linear-gradient(135deg,rgba(255,255,255,.92) 0%,#3C89E8 100%);
  --mn-ease:cubic-bezier(.22,.72,.28,1);

  /* Ant не рисует «сияние» на фоне — поверхности плоские. Гасим до нуля. */
  --mn-sky-1:transparent;
  --mn-sky-2:transparent;
  --mn-sky-3:transparent;
  --mn-sky-4:transparent;
}

/* СВЕТЛАЯ ТЕМА = Ant Design v5, стандартный (light) алгоритм.
   colorBgLayout #F5F5F5, контейнер и «поднятая» поверхность — белые,
   текст чёрный с прозрачностью 88/65/45%, границы #F0F0F0 / #D9D9D9. */
[data-theme="light"],
:root[data-theme="light"]{
  --bg:#F5F5F5;           /* colorBgLayout */
  --panel:#FFFFFF;        /* colorBgContainer */
  --card:#FFFFFF;         /* colorBgElevated */
  --card2:#FAFAFA;

  --tx:rgba(0,0,0,.88);       /* colorText */
  --tx-mut:rgba(0,0,0,.65);   /* colorTextSecondary */
  --tx-dim:rgba(0,0,0,.56);   /* colorTextTertiary, поднят: .45 давал 3.3:1 на #F5F5F5 */

  --acc:#1677FF;          /* colorPrimary */
  --acc-d:#0958D9;        /* colorPrimaryActive — для ссылок на белом читаемее hover */
  --acc-tx:#0958D9;       /* акцент как ТЕКСТ: #1677FF на белом даёт 4.1:1 */
  --acc-on-fill:#0958D9;  /* белым по #1677FF всего 4.1:1 — под мелкий текст ступень темнее */
  --hi:#1677FF;

  --line:#F0F0F0;         /* colorBorderSecondary */
  --line2:#D9D9D9;        /* colorBorder */
  --edge:#BFBFBF;
  --glow:rgba(22,119,255,.15);

  --ok:#52C41A;           /* colorSuccess */
  --warn:#FAAD14;         /* colorWarning */
  --danger:#FF4D4F;       /* colorError */

  --t-task:rgba(0,0,0,.65);
  --t-feature:#1677FF;
  --t-bug:#FF4D4F;
  --t-design:rgba(0,0,0,.65);
  --t-content:#FAAD14;
  --t-deploy:#52C41A;

  --on-acc:#FFFFFF;

  /* первичная кнопка Ant — плоская заливка colorPrimary под белым текстом */
  --mn-fill-1:#1677FF;
  --mn-fill-2:#1677FF;
  --mn-fill-edge:#1677FF;
  --mn-glow:rgba(22,119,255,.22);
  --mn-glow-soft:rgba(22,119,255,.10);
  --mn-teal:#52C41A;
  --mn-red:#FF4D4F;
  --mn-hair:rgba(0,0,0,.04);
  --mn-num:linear-gradient(135deg,rgba(0,0,0,.88) 0%,#1677FF 100%);
  --mn-ease:cubic-bezier(.22,.72,.28,1);

  /* поверхности Ant плоские — фоновое «сияние» не рисуем */
  --mn-sky-1:transparent;
  --mn-sky-2:transparent;
  --mn-sky-3:transparent;
  --mn-sky-4:transparent;
}


/* ═══════════════════════════════════════════════════════════════════════════
   2 · СЛОЙ ГЛУБИНЫ --dp-*. Тени холодные (сине-чёрные), не нейтральные.
   Через эти токены перекрашивается почти вся «материальность» кабинета.
   ═══════════════════════════════════════════════════════════════════════════ */
:root{
  /* Тени — точные токены Ant Design v5, без «усиления под тёмный фон».
     В тёмной теме Ant разделяет слои НЕ тенью (на #000 её всё равно не видно),
     а ступенью фона #000 → #141414 → #1F1F1F плюс границей #303030.
     --dp-e1 = boxShadowTertiary, --dp-e3/e4 = boxShadow/boxShadowSecondary. */
  --dp-e1: 0 1px 2px 0 rgba(0,0,0,.03), 0 1px 6px -1px rgba(0,0,0,.02), 0 2px 4px 0 rgba(0,0,0,.02);
  --dp-e2: 0 2px 8px 0 rgba(0,0,0,.06), 0 1px 4px -2px rgba(0,0,0,.08);
  --dp-e3: 0 6px 16px 0 rgba(0,0,0,.08), 0 3px 6px -4px rgba(0,0,0,.12), 0 9px 28px 8px rgba(0,0,0,.05);
  --dp-e4: 0 6px 16px 0 rgba(0,0,0,.08), 0 3px 6px -4px rgba(0,0,0,.12), 0 9px 28px 8px rgba(0,0,0,.05);

  /* Ant не рисует ни «фаску», ни внутренний блик — поверхности плоские,
     объём даёт только тень и граница. Поэтому rim/face гасим. */
  --dp-rim:   none;
  --dp-rim-s: none;
  --dp-well:  none;
  --dp-face:  none;

  --dp-trough:#141414;    /* колонка-корыто: colorBgContainer */
  --dp-lift:  #1F1F1F;    /* карточка: colorBgElevated */
  --dp-lid:   #1F1F1F;    /* крышка колонки */

  --dp-glass: color-mix(in srgb, #141414 82%, transparent);
  --dp-scr:   rgba(0,0,0,.45);
  --dp-veil:  rgba(0,0,0,.45);
  --dp-focus: #1668DC;
  --dp-glow:  var(--mn-glow-soft);

  /* Боковое меню — плотная тёмная панель НЕЗАВИСИМО от темы (как в Linear/Notion):
     собственные токены текста/поверхностей, не привязанные к --tx/--card, которые
     в светлой теме становятся тёмными — иначе текст меню гаснет на своём же тёмном фоне. */
  --side-tx:rgba(255,255,255,.85);
  --side-tx-mut:rgba(255,255,255,.65);
  --side-tx-dim:rgba(255,255,255,.45);
  --side-line:#303030;
  --side-card:#1F1F1F;
  --side-card2:#1668DC;   /* активный пункт меню Ant — заливка colorPrimary */
  --side-acc:#4096FF;   /* синий Ant на ступень светлее: 6.2:1 на #141414 */
}
/* Светлая тема: тени остаются тёмными (тень — всегда «недостаток света», и на
   белой поверхности тоже тёмная), а вот сами материальные поверхности —
   корыто колонки, поднятая карточка, крышка меню, стеклянная подложка —
   должны стать светлыми, иначе кабинет остаётся тёмным под белым текстом. */
[data-theme="light"],
:root[data-theme="light"]{
  --dp-rim:   none;
  --dp-rim-s: none;
  --dp-well:  none;
  --dp-face:  none;

  --dp-trough:#FAFAFA;
  --dp-lift:  #FFFFFF;
  --dp-lid:   #FFFFFF;

  --dp-glass: color-mix(in srgb, #FFFFFF 82%, transparent);
  --dp-scr:   rgba(0,0,0,.45);
  --dp-veil:  rgba(0,0,0,.45);
  --dp-focus: #1677FF;
  --dp-glow:  var(--mn-glow-soft);
}


/* ═══════════════════════════════════════════════════════════════════════════
   3 · НЕБО. Сияние живёт на фоне страницы и вверху рабочей области.
   Никаких псевдоэлементов и смены position — только background-image.
   ═══════════════════════════════════════════════════════════════════════════ */
/* тонкое киношное зерно поверх фона — деталь, по которой тёмный интерфейс
   читается как «сделанный», а не как плоская заливка одним цветом */
/* Ant Layout: фон — ровный colorBgLayout. Ни «неба», ни киношного зерна:
   в системе Ant глубину даёт только ступень поверхностей и граница. */
body{
  background-color:var(--bg);
  background-image:none;
}
@media print{body{background-image:
  radial-gradient(120% 78% at 12% -18%, var(--mn-sky-1), transparent 62%),
  radial-gradient(95% 62% at 88% -12%, var(--mn-sky-2), transparent 60%),
  radial-gradient(140% 100% at 50% 122%, rgba(74,74,74,.11), transparent 66%)}}

/* мягкое сияние над рабочей областью — то, что видно сразу при открытии */
#view{
  background-image:
    radial-gradient(115% 340px at 16% -80px, var(--mn-sky-3), transparent 68%),
    radial-gradient(85% 260px at 84% -60px, var(--mn-sky-4), transparent 66%);
  background-repeat:no-repeat;
}

/* экран входа: Ant — ровная карточка на ровном фоне, без сияний */
.login-wrap{background:var(--bg)}
.login{
  background:var(--card);
  border-color:var(--line2);
  box-shadow:var(--dp-e3);
}


/* ═══════════════════════════════════════════════════════════════════════════
   4 · БОКОВОЕ МЕНЮ. Плотная тёмная панель, активный пункт светится.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Ant Sider — ровная тёмная панель без градиента и тени */
.side{
  background:#141414;
  border-right-color:var(--line);
  box-shadow:none;
}
.side .brand{color:var(--side-tx)}
.side .brand .dot,
.login .brand .dot{
  background:linear-gradient(140deg,#6C6C6C 0%,#434343 100%);
  color:#FFFFFF;
  box-shadow:0 6px 18px -8px var(--mn-glow), inset 0 1px 0 rgba(255,255,255,.30);
}

.navitem{position:relative; transition:background .16s var(--mn-ease), color .16s var(--mn-ease)}
.navitem:hover{background:rgba(159,159,159,.09); color:var(--tx)}
.navitem.on{
  background:linear-gradient(90deg, color-mix(in srgb, var(--acc) 20%, transparent) 0%, color-mix(in srgb, var(--acc) 5%, transparent) 58%, transparent 100%);
  color:var(--tx);
  box-shadow:none;                 /* базовую врезку заменяет светящаяся полоса ниже */
}
.navitem.on::before{
  content:''; position:absolute; left:0; top:6px; bottom:6px; width:3px;
  border-radius:0 3px 3px 0; pointer-events:none;
  background:linear-gradient(180deg, var(--acc) 0%, #DADADA 100%);
  box-shadow:0 0 12px 0 var(--mn-glow);
}
.navitem .cnt{
  background:rgba(159,159,159,.12); color:var(--tx-mut);
  border:1px solid rgba(159,159,159,.16);
}
.navitem.on .cnt{background:rgba(159,159,159,.22); color:var(--tx)}
.navitem.more{border-color:rgba(159,159,159,.22)}
.navitem.more:hover{border-color:var(--acc); background:rgba(159,159,159,.08)}

.side-lbl{color:var(--tx-dim)}
.side-n{background:rgba(159,159,159,.12); color:var(--tx-mut)}
.side .foot{border-top-color:rgba(193,193,193,.08)}
.psearch input{
  background:#2D2D2D; border-color:rgba(159,159,159,.14);
  transition:border-color .16s var(--mn-ease), box-shadow .16s var(--mn-ease);
}
.psearch input:focus{
  border-color:var(--acc);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 16%, transparent), 0 0 20px -8px var(--mn-glow);
}
.psx:hover{background:rgba(159,159,159,.14); color:var(--tx)}
.pin.on,.pin:hover{color:var(--warn)}
.pin:hover{background:rgba(255,187,86,.12)}

/* полоски прокрутки боковых списков */
.side-projects::-webkit-scrollbar-thumb{background:rgba(159,159,159,.28); border-radius:6px}
.side-projects::-webkit-scrollbar-thumb:hover{background:rgba(159,159,159,.45)}


/* ═══════════════════════════════════════════════════════════════════════════
   5 · ВЕРХНЯЯ ПАНЕЛЬ — стекло с размытием и световой линией снизу.
   blur остаётся на ::before (в app.css это осознанный фикс для .udrop).
   ═══════════════════════════════════════════════════════════════════════════ */
/* Ant Header — ровный фон и одна разделительная линия, без подсветки и тени */
.topbar::before{
  background:var(--panel);
  border-bottom:1px solid var(--line);
  box-shadow:none;
}
/* тонкая световая нить под шапкой — «горизонт» */
.topbar::after{
  content:''; position:absolute; left:0; right:0; bottom:-1px; height:1px;
  pointer-events:none; opacity:.8;
  background:linear-gradient(90deg,
    transparent 0%, rgba(255,255,255,.35) 50%, transparent 100%);
}
.topbar h1{color:var(--tx)}

.iconbtn{
  background:#3B3B3B;
  border-color:rgba(159,159,159,.16); color:var(--tx-mut);
  transition:border-color .16s var(--mn-ease), color .16s var(--mn-ease), box-shadow .16s var(--mn-ease);
}
.iconbtn:hover{
  color:var(--tx); border-color:rgba(159,159,159,.5);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--acc) 14%, transparent), 0 10px 24px -16px var(--mn-glow);
}
.ubtn{
  background:#3B3B3B;
  border-color:rgba(159,159,159,.16);
  transition:border-color .16s var(--mn-ease), box-shadow .16s var(--mn-ease);
}
.ubtn:hover{border-color:rgba(159,159,159,.5); box-shadow:0 10px 24px -16px var(--mn-glow)}
.uav{
  background:linear-gradient(140deg,#6C6C6C,#434343);
  color:#FFFFFF;
  box-shadow:0 4px 12px -6px var(--mn-glow), inset 0 1px 0 rgba(255,255,255,.28);
}
.udrop{
  background:#353535;
  border-color:rgba(159,159,159,.18);
  box-shadow:var(--dp-e3), var(--dp-rim-s);
}
.udrop .who{border-bottom-color:rgba(193,193,193,.08)}
.nbadge{background:var(--mn-red); color:#FFFFFF; border-color:var(--bg)}

.app-foot{
  background:linear-gradient(180deg, color-mix(in srgb, var(--acc) 4%, transparent), rgba(43,43,43,0)), var(--bg);
  border-top-color:rgba(193,193,193,.07);
}
.app-foot a:hover{color:var(--acc-d)}


/* ═══════════════════════════════════════════════════════════════════════════
   6 · ДОСКА. Колонка — корыто, шапка колонки — крышка, карточка — фишка.
   ═══════════════════════════════════════════════════════════════════════════ */
.col{
  background:#2C2C2C;
  border-color:rgba(159,159,159,.09);
  box-shadow:var(--dp-well);
}
.col-h{
  background:#3A3A3A;
  border-bottom-color:rgba(159,159,159,.13);
  box-shadow:0 1px 0 rgba(36,36,36,.7), inset 0 1px 0 rgba(193,193,193,.10);
}
.col-h .t{color:var(--tx)}
.col-h .dot{box-shadow:0 0 10px 0 currentColor, 0 0 3px 0 currentColor}
.col-collapsed{
  background:#383838;
  border-color:rgba(159,159,159,.10);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.col-exp:hover{background:rgba(159,159,159,.10)}
.col-exp .n{background:rgba(159,159,159,.16); color:var(--tx)}
.col-tool:hover{color:var(--tx); background:rgba(159,159,159,.16)}
.col.drop{outline-color:var(--acc); box-shadow:var(--dp-well), inset 0 0 0 1px var(--acc), inset 0 0 40px -6px color-mix(in srgb, var(--acc) 35%, transparent)}

.addtask{border-color:rgba(159,159,159,.20); color:var(--tx-dim); transition:.16s var(--mn-ease)}
.addtask:hover{
  color:var(--acc); border-color:var(--acc);
  background:color-mix(in srgb, var(--acc) 8%, transparent); box-shadow:0 0 20px -12px var(--mn-glow);
}
.col-addcol{border-color:rgba(159,159,159,.20)}
.col-addcol:hover{border-color:var(--acc); color:var(--acc); background:color-mix(in srgb, var(--acc) 6%, transparent)}

/* --- карточка задачи: подъём и цветной кант по типу задачи --- */
.card{
  background-color:var(--dp-lift);
  border-color:rgba(159,159,159,.09);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:transform .16s var(--mn-ease), box-shadow .16s var(--mn-ease),
             border-color .16s var(--mn-ease);
}
.card:hover{
  transform:translateY(-3px);
  border-color:color-mix(in srgb, var(--tc,var(--acc)) 40%, var(--line2));
  border-left-color:var(--tc,var(--acc));
  box-shadow:
    var(--dp-e2), var(--dp-rim-s),
    0 0 0 1px color-mix(in srgb, var(--tc,var(--acc)) 20%, transparent),
    0 20px 38px -26px color-mix(in srgb, var(--tc,var(--acc)) 70%, #000);
}
.card:active{transform:translateY(0); box-shadow:var(--dp-e1), var(--dp-rim)}
.card.drag{box-shadow:var(--dp-e4), 0 0 0 1px var(--acc); opacity:.55}
.card .ttl{color:var(--tx)}
.card .meta .pchip,.card .meta .due{background:rgba(159,159,159,.11)}
.pchip.high{color:#BFBFBF; background:color-mix(in srgb, var(--acc) 18%, transparent)}
.card .cprog{background:rgba(36,36,36,.45)}
.card .cprog i{
  background:linear-gradient(90deg, var(--mn-fill-edge) 0%, var(--acc) 45%, #DADADA 100%);
  box-shadow:0 0 12px -3px var(--mn-glow);
}
.card .qadv{
  background:#3E3E3E;
  border-color:rgba(159,159,159,.22); color:var(--tx-mut);
}
.card .qadv:hover{
  background:linear-gradient(180deg,var(--mn-fill-1),var(--mn-fill-2));
  border-color:var(--mn-fill-edge); color:#FFFFFF;
  box-shadow:0 6px 18px -10px var(--mn-glow);
}
.card .qadv.qc.ok:hover{
  background:linear-gradient(180deg,#16AD91,#0D947C);
  border-color:var(--mn-teal); color:#FFFFFF;
}
.tag{background:rgba(159,159,159,.11); color:var(--tx-mut)}
.col-body>.empty{border-color:rgba(159,159,159,.18)}
.board:has(.card.drag) .col-body>.empty{
  border-color:var(--acc); color:var(--tx);
  background:color-mix(in srgb, var(--acc) 10%, transparent);
}

/* полосы прокрутки доски и колонок */
.board-wrap::-webkit-scrollbar-thumb{
  background:linear-gradient(90deg,#585858,#808080);
  border:3px solid var(--bg); border-radius:10px;
}
.board-wrap::-webkit-scrollbar-thumb:hover{background:linear-gradient(90deg,#6C6C6C,#9F9F9F)}
.col-body::-webkit-scrollbar-thumb{background:rgba(159,159,159,.26); border-radius:8px}
.col-body::-webkit-scrollbar-thumb:hover{background:rgba(159,159,159,.44)}
.cmts::-webkit-scrollbar-thumb{background:rgba(159,159,159,.26)}


/* ═══════════════════════════════════════════════════════════════════════════
   7 · КНОПКИ, ЧИПЫ, ПЕРЕКЛЮЧАТЕЛИ.
   Акцентная заливка ВСЕГДА глубокий индиго под белым текстом (7.2:1).
   ═══════════════════════════════════════════════════════════════════════════ */
.btn{
  background:#3B3B3B;
  border-color:rgba(159,159,159,.16);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:transform .14s var(--mn-ease), border-color .14s var(--mn-ease),
             box-shadow .14s var(--mn-ease), color .14s var(--mn-ease);
}
.btn:hover{
  color:var(--tx); border-color:rgba(159,159,159,.52); transform:translateY(-1px);
  box-shadow:var(--dp-e2), var(--dp-rim-s), 0 12px 28px -20px var(--mn-glow);
}
.btn:active{transform:translateY(0)}

.btn-primary,
.btn-primary:disabled,
.btn-primary:disabled:hover{
  background:linear-gradient(180deg, var(--mn-fill-1) 0%, var(--mn-fill-2) 100%);
  border-color:var(--mn-fill-edge);
  color:#FFFFFF;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.20), 0 10px 26px -14px var(--mn-glow);
}
/* при наведении меняется только свет, а не заливка — контраст 7.2:1 держится */
.btn-primary:hover{
  background:linear-gradient(180deg, var(--mn-fill-1) 0%, var(--mn-fill-2) 100%);
  border-color:#9F9F9F; color:#FFFFFF; transform:translateY(-1px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.26),
             0 0 0 1px color-mix(in srgb, var(--acc) 25%, transparent), 0 16px 34px -16px var(--mn-glow);
}
.btn-primary:disabled::after{border-color:rgba(255,255,255,.28); border-top-color:#FFFFFF}

.btn-ghost{color:var(--tx-mut); background:none; box-shadow:none}
.btn-ghost:hover{color:var(--tx); background:rgba(159,159,159,.10); box-shadow:none}
.btn-danger:hover{border-color:var(--danger); color:var(--danger); box-shadow:0 10px 24px -18px rgba(255,127,140,.8)}
.btn-danger-solid,
.btn-danger-solid:hover{background:var(--mn-red); border-color:#D62651; color:#FFFFFF}
.btn-danger-solid:hover{box-shadow:0 12px 28px -16px rgba(187,22,55,.9)}

/* группы «включено» — одна и та же акцентная заливка */
.seg button.on,
.schip.on,
.psel.on,
.pb-chip.on,
.mv-chip.on{
  background:linear-gradient(180deg, var(--mn-fill-1) 0%, var(--mn-fill-2) 100%);
  border-color:var(--mn-fill-edge);
  color:#FFFFFF;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18), 0 8px 20px -14px var(--mn-glow);
}
.seg button,.schip,.psel,.pb-chip,.mv-chip,.tf,.bchip{
  background:#3B3B3B;
  border-color:rgba(159,159,159,.16);
  transition:border-color .14s var(--mn-ease), color .14s var(--mn-ease), box-shadow .14s var(--mn-ease);
}
.seg button:hover,.schip:hover,.psel:hover,.pb-chip:hover,.mv-chip:hover,.tf:hover,.bchip:hover{
  border-color:rgba(159,159,159,.46); color:var(--tx);
}
.tf.on{
  border-color:var(--acc); color:var(--tx);
  background:color-mix(in srgb, var(--acc) 14%, transparent);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--acc) 18%, transparent), 0 8px 20px -16px var(--mn-glow);
}
.bchip.on{
  background:color-mix(in srgb, var(--acc) 14%, transparent); border-color:var(--acc); color:var(--tx);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--acc) 15%, transparent);
}
.bchip i{background:rgba(159,159,159,.14); color:var(--tx-mut)}
.chip{background:rgba(159,159,159,.11); color:var(--tx-mut)}
.chip.hi{color:#BFBFBF}
.dept{background:rgba(159,159,159,.09); border-color:rgba(159,159,159,.14)}
.dept.on{background:color-mix(in srgb, var(--acc) 16%, transparent); border-color:var(--acc)}
.dept.on b{color:var(--acc-d)}

/* вкладки Доска / Аналитика — активная светится сверху */
.ptab{transition:color .14s var(--mn-ease), background .14s var(--mn-ease)}
.ptab.on{
  background:linear-gradient(180deg, color-mix(in srgb, var(--acc) 20%, transparent) 0%, #353535 72%);
  border-color:rgba(159,159,159,.24);
  box-shadow:inset 0 1px 0 rgba(193,193,193,.14);
}
.ptab.exp:hover,.ptab.set:hover{color:var(--acc-d)}

/* спиннер — светящееся кольцо */
.spin{
  border-color:rgba(159,159,159,.16);
  border-top-color:var(--acc);
  box-shadow:0 0 26px -10px var(--mn-glow);
}


/* ═══════════════════════════════════════════════════════════════════════════
   8 · ПОЛЯ ВВОДА. Фокус — светящийся кант, а не просто рамка.
   ═══════════════════════════════════════════════════════════════════════════ */
.field input,.field textarea,.field select,
.pb-field input,.pb-field textarea,.pb-field select,
.stginput,.tagin,.sub-add input,.cmt-url,.cmt-edit-ta,.ro-edit textarea,.tsearch{
  background:#2F2F2F;
  border-color:rgba(159,159,159,.16);
}
.field input:focus,.field textarea:focus,.field select:focus,
.pb-field input:focus,.pb-field textarea:focus,.pb-field select:focus{
  border-color:var(--acc);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 17%, transparent), 0 0 22px -8px var(--mn-glow);
}
.stginput:focus,.sub-add input:focus,.cmt-url:focus,
.cmt-edit-ta:focus,.ro-edit textarea:focus{
  border-color:var(--acc); box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 17%, transparent);
}
.tagin:focus-within,.tsearch:focus-within{
  border-color:var(--acc); box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 17%, transparent), 0 0 22px -8px var(--mn-glow);
}
.tsearch{box-shadow:var(--dp-e1), var(--dp-rim)}
.tp{background:rgba(159,159,159,.13)}
.rng{background:#303030; box-shadow:inset 0 1px 3px rgba(36,36,36,.6)}
.rng::-webkit-slider-thumb{
  background:linear-gradient(180deg,#808080,#585858);
  border-color:#303030; box-shadow:0 0 12px -2px var(--mn-glow);
}
.rng::-moz-range-thumb{background:#7A7A7A; border-color:#303030}
.switch .sw{background:#303030; border-color:rgba(159,159,159,.18)}
.switch .sw::after{background:var(--tx-dim)}
:focus-visible{outline-color:var(--dp-focus)!important}


/* ═══════════════════════════════════════════════════════════════════════════
   9 · МОДАЛКИ. Глубокое стекло с сиянием под шапкой.
   ═══════════════════════════════════════════════════════════════════════════ */
.ov{
  background:rgba(39,39,39,.74);
  backdrop-filter:blur(9px) saturate(1.1);
  -webkit-backdrop-filter:blur(9px) saturate(1.1);
}
.modal,.confirm-modal,.qjmodal{
  background:var(--card);
  border-color:var(--line2);
  box-shadow:var(--dp-e4), var(--dp-rim-s), 0 0 0 1px rgba(159,159,159,.05);
}
.mhead{border-bottom:none}
.tasktitle{color:var(--tx)}
.tasktitle:focus,.tasktitle.tt-area:focus{border-bottom-color:var(--acc)}
.confirm-modal .cf-ic{background:rgba(159,159,159,.12); border-color:rgba(159,159,159,.2); color:var(--tx-mut)}
.confirm-modal .cf-ic.danger{
  background:rgba(255,127,140,.14); border-color:rgba(255,127,140,.34); color:var(--danger);
}
.mv-sec,.bdmode,.sub{
  background:#353535;
  border-color:rgba(159,159,159,.12);
}
.sub-ck{border-color:rgba(159,159,159,.24)}
.sub.done .sub-ck{background:rgba(66,226,196,.18); border-color:var(--ok)}
.subs-n,.badge-n{background:rgba(159,159,159,.13); color:var(--tx-mut)}
.subs-sec{border-top-color:rgba(193,193,193,.08)}
.qj #qjq{border-bottom-color:rgba(159,159,159,.16)}
.qj-i.on,.qj-i:hover{background:color-mix(in srgb, var(--acc) 14%, transparent)}
.qj-hint{border-top-color:rgba(193,193,193,.08)}
.ro-block{
  background:rgba(255,127,140,.10);
  border-color:rgba(255,127,140,.32);
  box-shadow:0 0 24px -18px rgba(255,127,140,.9);
}
.rochips .chip{background:rgba(159,159,159,.11)}


/* ═══════════════════════════════════════════════════════════════════════════
   10 · АНАЛИТИКА. Числа, кольца и полосы — лицо кабинета.
   ═══════════════════════════════════════════════════════════════════════════ */
/* --- большая сводка над доской --- */
/* Ant: панель — ровный colorBgContainer, граница и тень, без «сияний» */
.analytics{
  background:var(--panel);
  border-color:var(--line2);
  box-shadow:var(--dp-e1);
}
/* Ant Progress не светится: дуга — плоский colorPrimary на ровной дорожке.
   Конические ореолы за кольцами/бубликом убраны целиком (::before гасим,
   а не просто прячем — иначе они остались бы висеть слоем над карточкой). */
.an-ringbox::before,.donut-wrap::before,.pt-ring::before{content:none}
.an-ring{position:relative; z-index:1}
.an-ring .an-bg{stroke:var(--line2)}
.an-ring .an-fg{stroke:var(--acc); filter:none}

.donut-wrap{position:relative; display:inline-flex; flex:none}
.donut-wrap svg{position:relative; z-index:1}
.dseg{filter:none}

.pt-ring .miniring{position:relative; z-index:1}
/* ВНИМАНИЕ: position здесь не трогать — в app.css .an-ringtxt абсолютно
   спозиционирован внутри кольца (inset:0). Нужен только слой поверх ореола. */
.an-ringtxt{z-index:2}
.an-ringtxt b{
  background:var(--mn-num); -webkit-background-clip:text; background-clip:text; color:transparent;
}
.an-bar{
  background:#2C2C2C; border-radius:8px; height:11px;
  box-shadow:inset 0 1px 4px rgba(36,36,36,.7), inset 0 0 0 1px rgba(193,193,193,.05);
}
/* цвета сегментов приходят инлайном из данных — добавляем только блик сверху */
.an-bar i{
  background-image:linear-gradient(180deg, rgba(255,255,255,.26), rgba(255,255,255,0) 70%)!important;
}
.an-cell b{color:var(--tx)}
.an-dot{box-shadow:0 0 8px -1px currentColor}

/* --- панели дашборда --- */
.dcard{
  position:relative;
  background:linear-gradient(168deg,#363636 0%,#2F2F2F 100%);
  border-color:rgba(159,159,159,.11);
  box-shadow:var(--dp-e2), var(--dp-rim);
}
/* световая нить по верхней кромке панели */
.dcard::before{
  content:''; position:absolute; left:18px; right:18px; top:-1px; height:1px; pointer-events:none;
  background:linear-gradient(90deg, transparent, rgba(255,255,255,.4) 50%, transparent);
}
.dcard.attention{border-color:rgba(255,127,140,.34)}
.dc-t{color:var(--tx)}
.dc-t svg{color:var(--acc); filter:none}
.attention .dc-t svg{color:var(--danger); filter:none}

/* --- KPI-плитки: градиентное число + световое пятно в углу --- */
.kpic{
  position:relative; overflow:hidden;
  background:linear-gradient(160deg,#3B3B3B 0%,#323232 100%);
  border-color:rgba(159,159,159,.14);
  box-shadow:var(--dp-e2), var(--dp-rim);
  transition:border-color .2s var(--mn-ease), box-shadow .2s var(--mn-ease), transform .2s var(--mn-ease);
}
.kpic::after{content:none}   /* Ant: карточка ровная, без светового пятна в углу */
.kpic:hover{
  transform:translateY(-2px);
  border-color:rgba(159,159,159,.32);
  box-shadow:var(--dp-e3), var(--dp-rim-s), 0 18px 36px -26px var(--mn-glow);
}
.kpic:hover::after{opacity:.95}
.kpic b{
  position:relative;
  background:var(--mn-num); -webkit-background-clip:text; background-clip:text; color:transparent;
}
.kpic.good b{
  background:linear-gradient(135deg,#EAFFFA 0%,var(--ok) 100%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
/* «плохой» KPI должен читаться как тревожный с одного взгляда,
   поэтому коралл берётся насыщеннее: белый→#FF8997 даёт 7.2:1 на карточке */
.kpic.bad b{
  background:linear-gradient(135deg,#FFD9DE 0%,#FF8997 100%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
}
/* Светлая тема: градиенты выше рассчитаны на тёмную карточку и начинаются
   почти с белого — на белой карточке число пропадало. Берём те же оттенки,
   но затемнённые: старт — насыщенный тон, финиш — базовый семантический.
   ВАЖНО: именно background-IMAGE, а не сокращение background — сокращение
   сбрасывает background-clip:text, и число заливалось сплошным прямоугольником. */
[data-theme="light"] .kpic.good b{background-image:linear-gradient(135deg,#0B7A66 0%,#52C41A 100%)}
[data-theme="light"] .kpic.bad b{background-image:linear-gradient(135deg,#A81733 0%,#FF4D4F 100%)}
.kpi-ic{
  position:relative;
  background:linear-gradient(160deg, rgba(255,255,255,.14), rgba(255,255,255,.04));
  border:1px solid rgba(159,159,159,.28);
  color:#BCBCBC;
  box-shadow:0 6px 16px -10px var(--mn-glow);
}
.kpic.good .kpi-ic{background:linear-gradient(160deg, rgba(66,226,196,.26), rgba(66,226,196,.06)); border-color:rgba(66,226,196,.3)}
.kpic.bad .kpi-ic{background:linear-gradient(160deg, rgba(255,127,140,.24), rgba(255,127,140,.05)); border-color:rgba(255,127,140,.3)}

/* --- витринные числа во всём кабинете --- */
.hb-val,.th-num b,.inv-sum,.mtile b,.dc-total{
  background:var(--mn-num); -webkit-background-clip:text; background-clip:text; color:transparent;
}
/* SVG-текст не умеет background-clip — вместо градиента задаём fill.
   Именно var(--tx), а не фиксированный светлый: это число лежит на карточке,
   которая в светлой теме белая, и захардкоженный near-white на ней исчезал. */
.dc-total{fill:var(--tx)}
.miniring .mrt{fill:var(--tx)}
/* stroke дуги теперь задаёт сам SVG (градиент, см. svgRing в app.js) — здесь только свечение */
.miniring circle:last-of-type{filter:none}
.pt-ring{position:relative}

/* --- горизонтальные полосы --- */
.hb-t{background:#2C2C2C; box-shadow:inset 0 1px 3px rgba(36,36,36,.65)}
.hb-t i{background-image:linear-gradient(180deg, rgba(255,255,255,.24), rgba(255,255,255,0) 72%)!important}
.prog{background:#2C2C2C; box-shadow:inset 0 1px 3px rgba(36,36,36,.6)}
.prog i{background:linear-gradient(90deg,var(--mn-fill-edge),var(--acc) 55%,#DADADA); box-shadow:0 0 12px -4px var(--mn-glow)}

/* --- графики --- */
.cgrid{stroke:rgba(193,193,193,.10)}
/* ВНИМАНИЕ: fill столбцам и площади burn-up здесь НЕ задаём — они приходят
   градиентом из разметки (см. svgBars/svgBurnup в app.js), а CSS-свойство fill
   перебивает атрибут fill в SVG и градиент бы не показался. Оставляем только свечение. */
.barsvg .bar{filter:none}
.barsvg .bar.cur{filter:none}
.barsvg .bar.zero{fill:rgba(159,159,159,.14); filter:none}
.burnup .bu-done{stroke:var(--acc); filter:none}
.burnup .bu-dot.done{fill:var(--acc-d)}
.bu-k.done{background:var(--acc-d)}
.bu-ot{color:var(--ok)}
.heatmap rect:hover{stroke:var(--acc); stroke-width:1.5}
.hk.h0{background:rgba(159,159,159,.12)}
.charttip{
  background:#3B3B3B;
  border-color:rgba(159,159,159,.26);
  box-shadow:var(--dp-e3), var(--dp-rim-s);
}
.charttip b{color:#BFBFBF}

/* --- плитки проектов и списки --- */
.pcard,.ptile{
  position:relative; overflow:hidden;
  background:linear-gradient(165deg,#363636 0%,#2F2F2F 100%);
  border-color:rgba(159,159,159,.11);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.pcard::after,.ptile::after{content:none}
.pcard:hover,.ptile:hover{
  border-color:rgba(159,159,159,.36);
  box-shadow:var(--dp-e3), var(--dp-rim-s), 0 22px 44px -30px var(--mn-glow);
}
.pcard:hover::after,.ptile:hover::after{opacity:.85}
.pcard h3{color:var(--tx)}
.drow{transition:background .14s var(--mn-ease)}
.drow:hover{background:color-mix(in srgb, var(--acc) 10%, transparent)}
.fe:hover{background:color-mix(in srgb, var(--acc) 9%, transparent)}
.frow{border-bottom-color:rgba(193,193,193,.07)}
.fic{background:rgba(159,159,159,.12); color:var(--tx-mut)}
.frow.done .fic{background:rgba(66,226,196,.18); color:var(--ok)}
.pill-blk{background:rgba(255,127,140,.14)}
.mstrip .mtile{border-right-color:rgba(193,193,193,.07)}
.emptybox .ei{
  background:linear-gradient(150deg, rgba(255,255,255,.12), rgba(255,255,255,.03));
  border-color:rgba(159,159,159,.26); color:#BCBCBC;
  box-shadow:0 18px 44px -26px var(--mn-glow), inset 0 1px 0 rgba(255,255,255,.10);
}
.dash-empty svg{color:var(--tx-dim)}


/* ═══════════════════════════════════════════════════════════════════════════
   11 · КОМАНДА. Ролевые цвета переведены в полуночную гамму (синий убран).
   ═══════════════════════════════════════════════════════════════════════════ */
.team-hero{background:var(--panel); border-color:var(--line2)}
.th-num{border-right-color:rgba(193,193,193,.10)}
.th-num b{background:linear-gradient(135deg,#FFFFFF 0%,#B3B3B3 55%,#E1E1E1 100%);
  -webkit-background-clip:text; background-clip:text; color:transparent}
.tm{background:linear-gradient(165deg,#383838 0%,#323232 100%); border-color:rgba(159,159,159,.11)}
.tm.r-pm{--tc:#9F9F9F}
.tm.r-pm .tm-av{
  background:linear-gradient(140deg,#6C6C6C,#434343); color:#FFFFFF; border-color:var(--mn-fill-edge);
}
.tm.r-lead .tm-av{
  background:linear-gradient(140deg,#6C6C6C,#434343); color:#FFFFFF; border-color:var(--mn-fill-edge);
}
.tm-av{background:rgba(159,159,159,.12); border-color:rgba(159,159,159,.2)}
.tm:not(.ghost) .tm-av::after{border-color:#363636}
.tm-st.active{background:color-mix(in srgb, var(--acc) 16%, transparent); color:var(--acc-d)}
.live-card .live-badge,.feed-live{background:var(--mn-red); color:#FFFFFF}
.live-wrap{background:#2B2B2B; border-color:rgba(159,159,159,.16); box-shadow:var(--dp-e3)}
/* аватары-инициалы приходят с жёстко зашитыми цветами из app.js —
   приводим их к полуночной гамме, сохраняя белый текст (≈7:1) */
.asa,.fe-av{
  background-color:#383838!important;
  background-image:linear-gradient(150deg, rgba(255,255,255,.24), rgba(255,255,255,.06))!important;
  color:#FFFFFF; border-color:rgba(159,159,159,.28);
}
.asa.more{background-color:#383838!important; color:var(--tx-mut)}


/* ═══════════════════════════════════════════════════════════════════════════
   12 · КОММЕНТАРИИ. Чат должен читаться первым делом — фон спокойный.
   ═══════════════════════════════════════════════════════════════════════════ */
.cmt-bubble{
  background:#393939;
  border-color:rgba(159,159,159,.10);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.cmt.mine .cmt-bubble{
  background:#3D3D3D;
  border-color:rgba(159,159,159,.32);
  box-shadow:var(--dp-e1), var(--dp-rim-s), 0 10px 24px -18px var(--mn-glow);
}
.cmt-av{background:rgba(159,159,159,.14); border-color:rgba(159,159,159,.22); color:var(--tx-mut)}
.cmt.adm .cmt-av{
  background:linear-gradient(140deg,#6C6C6C,#434343); color:#FFFFFF;
  border-color:var(--mn-fill-edge); box-shadow:0 4px 12px -6px var(--mn-glow);
}
.cmt-meta b{color:var(--tx)}
.cmt-t:hover{background:rgba(159,159,159,.16); color:var(--tx)}
.cmt-link{color:var(--acc-d)}
.cmt-attach,.btn-file,.doc-add,.doc-dl,.cmt-file,.cef-x,.cef-add{
  background:#3B3B3B; border-color:rgba(159,159,159,.16);
}
.cmt-attach:hover,.btn-file:hover,.doc-add:hover,.doc-dl:hover,.cmt-file:hover{
  border-color:var(--acc); color:var(--acc-d);
}
.cmt-img{background:#323232; border-color:rgba(159,159,159,.16)}
.cmt-img:hover{border-color:var(--acc)}
.doc-th{background:#323232}
.docs-head{color:var(--tx-mut)}
#cb.drop{border-color:var(--acc); background:color-mix(in srgb, var(--acc) 10%, transparent)}


/* ═══════════════════════════════════════════════════════════════════════════
   13 · ПЛОТНЫЕ ДАННЫЕ: счета, часы, таблицы, библиотека.
   Здесь декора минимум — важна только читаемость строк.
   ═══════════════════════════════════════════════════════════════════════════ */
.tblwrap{
  background:#333333;
  border-color:rgba(159,159,159,.12);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.tbl th{
  background:color-mix(in srgb, var(--acc) 7%, transparent);
  color:var(--tx-dim);
  border-bottom-color:rgba(159,159,159,.18);
}
.tbl td{border-bottom-color:rgba(193,193,193,.07); color:var(--tx)}
.tbl tbody tr{transition:background .13s linear}
.tbl tbody tr:nth-child(even) td{background:rgba(193,193,193,.022)}
.tbl tbody tr:hover td{background:color-mix(in srgb, var(--acc) 10%, transparent)}
.rowact{border-color:rgba(159,159,159,.18)}
.rowact:hover{border-color:var(--acc); color:var(--acc-d)}
.rowdel:hover{background:rgba(255,127,140,.14); border-color:rgba(255,127,140,.34); color:var(--danger)}

.inv-kpi{
  background:linear-gradient(160deg,#393939,#2F2F2F);
  border-color:rgba(159,159,159,.14);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.inv-kpi b{background:var(--mn-num); -webkit-background-clip:text; background-clip:text; color:transparent}
.inv{
  background:linear-gradient(170deg,#363636,#2F2F2F);
  border-color:rgba(159,159,159,.11);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:border-color .16s var(--mn-ease), transform .16s var(--mn-ease), box-shadow .16s var(--mn-ease);
}
.inv:hover{
  transform:translateY(-2px); border-color:rgba(159,159,159,.34);
  box-shadow:var(--dp-e2), var(--dp-rim-s), 0 18px 36px -28px var(--mn-glow);
}
.ivx{border-color:rgba(159,159,159,.18)}
.ivx:hover{color:var(--danger); border-color:var(--danger)}
.ivtotal b{color:var(--tx)}

.hbal{
  background:var(--panel);
  border-color:var(--line2);
  box-shadow:var(--dp-e2), var(--dp-rim);
}
.hbal.low{border-color:rgba(255,127,140,.38)}
.hb-bar{background:#2C2C2C; box-shadow:inset 0 1px 4px rgba(36,36,36,.7)}
.hb-bar i{
  background:linear-gradient(90deg,var(--ok) 0%,#7A7A7A 62%,#9F9F9F 100%);
  box-shadow:0 0 16px -4px var(--mn-glow);
}
.hbal.low .hb-bar i{background:linear-gradient(90deg,var(--warn),var(--danger)); box-shadow:0 0 16px -5px rgba(255,127,140,.8)}
.hb-sub b{color:var(--tx)}
.hrow{
  background:linear-gradient(170deg,#363636,#2F2F2F);
  border-color:rgba(159,159,159,.11);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:border-color .14s var(--mn-ease);
}
.hrow:hover{border-color:rgba(159,159,159,.28)}
.hrow.purchase .hr-k{color:var(--ok)}
.hr-x:hover{background:rgba(255,127,140,.14); color:var(--danger)}

.lib{
  background:linear-gradient(170deg,#363636,#2F2F2F);
  border-color:rgba(159,159,159,.11);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.lib:hover{border-color:rgba(159,159,159,.36); box-shadow:var(--dp-e2), var(--dp-rim-s), 0 18px 34px -28px var(--mn-glow)}
.lib-dl{color:var(--acc-d)}
.doc-x:hover{background:rgba(255,127,140,.14); color:var(--danger)}

.toast{
  background:#3B3B3B;
  border-color:rgba(159,159,159,.26);
  box-shadow:var(--dp-e4), var(--dp-rim-s);
}
.toast.err{border-color:rgba(255,127,140,.5)}
.pmchip{background:rgba(159,159,159,.10); border-color:rgba(159,159,159,.18)}
.pmchip.is-owner{background:color-mix(in srgb, var(--acc) 16%, transparent); border-color:rgba(159,159,159,.4)}
.pmbadge{color:var(--acc-d); background:color-mix(in srgb, var(--acc) 18%, transparent)}
.pmx:hover{background:var(--mn-red); color:#FFFFFF}
.scrim{background:rgba(39,39,39,.62); backdrop-filter:blur(2px); -webkit-backdrop-filter:blur(2px)}
.vw{background:rgba(39,39,39,.94)}
.vw-card{background:#353535; border-color:rgba(159,159,159,.18)}
.vw-btn{background:rgba(159,159,159,.12); border-color:rgba(159,159,159,.22)}
.vw-btn:hover{background:rgba(159,159,159,.26); border-color:rgba(159,159,159,.5)}
.vw-nav{background:rgba(53,53,53,.82); border-color:rgba(159,159,159,.22)}
.vw-nav:hover{background:color-mix(in srgb, var(--acc) 34%, transparent)}


/* ═══════════════════════════════════════════════════════════════════════════
   14 · ДВИЖЕНИЕ. Мягкое появление панелей. Ambient-анимаций нет намеренно:
   кабинет открыт по 8 часов в день, фон не должен мерцать и жечь батарею.
   ═══════════════════════════════════════════════════════════════════════════ */
@keyframes mnRise{from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none}}
@keyframes mnFade{from{opacity:0} to{opacity:1}}

.dcard,.pcard,.inv,.hrow,.ptile,.lib,.inv-kpi,.hbal,#view.intro > .analytics{
  animation:mnRise .38s var(--mn-ease) backwards;
}
.kpis .kpic{animation:mnRise .34s var(--mn-ease) backwards}
.kpis .kpic:nth-child(2){animation-delay:.05s}
.kpis .kpic:nth-child(3){animation-delay:.10s}
.kpis .kpic:nth-child(4){animation-delay:.15s}
.kpis .kpic:nth-child(5){animation-delay:.20s}
.kpis .kpic:nth-child(6){animation-delay:.25s}
/* ⚠️ Было просто .col — проявление проигрывалось на КАЖДУЮ перерисовку доски,
   а она случается на каждый ввод в поиск по задачам и на каждое живое событие:
   доска мигала. Привязано к тому же классу .intro, что и остальное движение —
   один проход при открытии. */
#view.intro .col{animation:mnFade .3s ease both}
.modal,.confirm-modal{animation:mnRise .22s var(--mn-ease) backwards}

/* прикосновением к тач-экрану ховер «залипает» — гасим подъём */
@media(hover:none){
  .card:hover,.kpic:hover,.pcard:hover,.ptile:hover,.inv:hover,.btn:hover,.btn-primary:hover{
    transform:none;
  }
}

@media(prefers-reduced-motion:reduce){
  .dcard,.pcard,.inv,.hrow,.ptile,.lib,.inv-kpi,.analytics,.hbal,
  .kpis .kpic,.col,.modal,.confirm-modal{animation:none}
  .card,.btn,.btn-primary,.kpic,.pcard,.ptile,.inv,.hrow,.navitem,.drow,
  .tbl tbody tr,.seg button,.schip,.psel,.pb-chip,.mv-chip,.tf,.bchip,
  .iconbtn,.ubtn,.addtask,.psearch input{transition:none}
  .card:hover,.kpic:hover,.pcard:hover,.ptile:hover,.inv:hover,
  .btn:hover,.btn-primary:hover{transform:none}
  .kpic::after,.pcard::after,.ptile::after{transition:none}
}


/* ═══════════════════════════════════════════════════════════════════════════
   15 · ТЕЛЕФОН (≤760px и ≤400px). Блюр и тяжёлые тени упрощаются:
   на мобильных GPU backdrop-filter и большие размытия дорого стоят.
   Проверено на 390px — раскладка не меняется, меняется только «вес» эффектов.
   ═══════════════════════════════════════════════════════════════════════════ */
@media(max-width:760px){
  /* сияние перестаёт быть fixed — иначе на iOS дёргается при скролле */
  body{background-attachment:scroll}

  :root,[data-theme="light"],:root[data-theme="light"]{
    --dp-e2: 0 2px 5px -1px rgba(20,20,20,.36), 0 6px 14px -8px rgba(20,20,20,.22);
    --dp-e3: 0 4px 10px -3px rgba(15,15,15,.38), 0 10px 20px -12px rgba(15,15,15,.24);
    --dp-e4: 0 6px 14px -6px rgba(10,10,10,.4), 0 16px 34px -20px rgba(10,10,10,.26);
  }
  .topbar::before{
    backdrop-filter:blur(10px) saturate(1.2);
    -webkit-backdrop-filter:blur(10px) saturate(1.2);
  }
  .ov{backdrop-filter:blur(5px); -webkit-backdrop-filter:blur(5px)}
  .scrim{backdrop-filter:none; -webkit-backdrop-filter:none}
  /* конический ореол кольца — самый дорогой эффект, на телефоне мягче */
  .an-ringbox::before{filter:blur(8px); opacity:.26}
  .donut-wrap::before{filter:blur(9px); opacity:.2}
  .pt-ring::before{filter:blur(5px); opacity:.16}
  .kpic::after{width:88px; height:88px; right:-26px; top:-30px; opacity:.42}
  .pcard::after,.ptile::after{width:104px; height:104px; opacity:.28}
  .card:hover{transform:none}
  .barsvg .bar,.barsvg .bar.cur,.burnup .bu-done,
  .an-ring .an-fg,.miniring circle:last-of-type,.dseg{filter:none}
}

@media(max-width:400px){
  /* самые узкие экраны: сияние ниже по яркости, чтобы мелкий текст
     на прозрачных участках не терял контраст */
  :root,[data-theme="light"],:root[data-theme="light"]{
    --mn-sky-3:rgba(255,255,255,.04);
    --mn-sky-4:rgba(255,255,255,.03);
  }
  .dcard::before{left:12px; right:12px}
  .topbar::after{opacity:.6}
}

/* ▼▼▼ ПРОРАБОТКА: ПОЛЯ ВВОДА ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   «ПОЛНОЧЬ» · семейство ПОЛЯ ВВОДА И ФОРМЫ
   Подключать ПОСЛЕ app.css (или дописывать в её конец).
   Ничего, кроме собственного семейства, файл не трогает:
   display / grid-template / position у .shell, .side, .board, .col не меняются.

   Все селекторы сверены с разметкой app.js и portal-brief.js — мёртвых нет.
   Собственный префикс токенов --fi-* (грепом по app.css/app.js: 0 совпадений),
   поэтому переопределить чужое значение нечаянно нельзя.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 0. Токены семейства ───────────────────────────────────────────────────
   Отдельные токены нужны по двум причинам.
   1) Утопленный фон поля должен быть ТЕМНЕЕ карточки, на которой лежит,
      иначе «утопленности» не читается; --card2 для этого светловат.
   2) Замер контраста: --tx-dim даёт на фоне поля 4.46 (тёмная) и 4.26 (светлая) —
      ниже порога 4.5, поэтому у плейсхолдера и подсказок свои цвета:
      плейсхолдер 6.42 / 5.38, подсказка 7.38 / 6.06.
   Иконки — только inline-SVG в data:URI: внутрь data:URI переменные не попадают,
   поэтому цвет штриха зашит в сам URI, а сам URI лежит в токене и меняется темой. */
:root{
  --fi-bg:#2D2D2D;                    /* покой: утопленный фон */
  --fi-bg-hover:#2F2F2F;
  --fi-bg-focus:#2F2F2F;
  --fi-bg-off:#2F2F2F;                /* disabled / readonly */
  --fi-line:var(--line2);
  --fi-line-hover:var(--edge);
  --fi-ph:#9A9A9A;                    /* плейсхолдер: приглушён, но 6.4:1 */
  --fi-hint:#A7A7A7;                  /* .hint 12px → 7.4:1 */
  --fi-label:#B3B3B3;                 /* .field label 11px капсом → нужно ≥7:1 */
  --fi-err:var(--danger);
  --fi-err-bg:rgba(255,99,128,.13);
  --fi-err-line:rgba(255,99,128,.34);
  --fi-knob:#F3F3F3;                  /* бегунок ползунка / шарик тумблера */
  --fi-well:inset 0 2px 6px -2px rgba(36,36,36,.75), inset 0 1px 0 rgba(199,199,199,.045);
  --fi-ring:0 0 0 3px var(--glow);
  --fi-r:6px;
  --fi-scheme:dark;                   /* нативные календарь/спиннеры/выпадашка */
  --fi-ic-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238A94AF' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.6-3.6'/%3E%3C/svg%3E");
  --fi-ic-chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238A94AF' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9.5 6 6 6-6'/%3E%3C/svg%3E");
  --fi-ic-chev-on:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239B84FF' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9.5 6 6 6-6'/%3E%3C/svg%3E");
  --fi-ic-cal:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238A94AF' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.25' y='5.25' width='17.5' height='15.5' rx='2.5'/%3E%3Cpath d='M8 3.25v4M16 3.25v4M3.25 10h17.5'/%3E%3C/svg%3E");
  --fi-ic-cal-on:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239B84FF' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.25' y='5.25' width='17.5' height='15.5' rx='2.5'/%3E%3Cpath d='M8 3.25v4M16 3.25v4M3.25 10h17.5'/%3E%3C/svg%3E");
  --fi-ic-alert:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FF5C7A' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.75'/%3E%3Cpath d='M12 7.5v5.2M12 16.2h.01'/%3E%3C/svg%3E");
  --fi-ic-check:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FFFFFF' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7'/%3E%3C/svg%3E");
  --fi-ic-grip:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%238A94AF' stroke-width='1.5' stroke-linecap='round'%3E%3Cpath d='M11 4 4 11M11 8l-3 3'/%3E%3C/svg%3E");
}
:root[data-theme="light"]{
  --fi-bg:#F5F5F5;
  --fi-bg-hover:#F1F1F1;
  --fi-bg-focus:#FFFFFF;
  --fi-bg-off:#EFEFEF;
  --fi-ph:#717171;                    /* 5.38:1 на поле, 5.85:1 на белом */
  --fi-hint:#707070;                  /* 6.06:1 */
  --fi-label:#5D5D5D;                 /* 8.66:1 на белом, 7.82:1 на --bg */
  --fi-err:#FF4D4F;                   /* #D93A5A на розовой подложке даёт 4.25 — мало */
  --fi-err-bg:rgba(219,33,72,.09);
  --fi-err-line:rgba(219,33,72,.3);
  --fi-knob:#FFFFFF;
  --fi-well:inset 0 2px 5px -2px rgba(56,56,56,.16);
  --fi-scheme:light;
  --fi-ic-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235C6480' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.6-3.6'/%3E%3C/svg%3E");
  --fi-ic-chev:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235C6480' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9.5 6 6 6-6'/%3E%3C/svg%3E");
  --fi-ic-chev-on:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235B3FE0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9.5 6 6 6-6'/%3E%3C/svg%3E");
  --fi-ic-cal:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235C6480' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.25' y='5.25' width='17.5' height='15.5' rx='2.5'/%3E%3Cpath d='M8 3.25v4M16 3.25v4M3.25 10h17.5'/%3E%3C/svg%3E");
  --fi-ic-cal-on:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235B3FE0' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.25' y='5.25' width='17.5' height='15.5' rx='2.5'/%3E%3Cpath d='M8 3.25v4M16 3.25v4M3.25 10h17.5'/%3E%3C/svg%3E");
  --fi-ic-alert:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23C81E42' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='8.75'/%3E%3Cpath d='M12 7.5v5.2M12 16.2h.01'/%3E%3C/svg%3E");
  --fi-ic-grip:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='none' stroke='%235C6480' stroke-width='1.5' stroke-linecap='round'%3E%3Cpath d='M11 4 4 11M11 8l-3 3'/%3E%3C/svg%3E");
}

/* ── 1. Общая «шкура» поля ─────────────────────────────────────────────────
   Один вид у всех вводов проекта: и у модалки задачи, и у брифа, и у счёта,
   и у списка клиентов проекта (.pmadd select до сих пор был чистым нативом).
   Покой — тонкая грань + утопленный фон; наведение — грань светлеет;
   фокус — индиговая грань + мягкое кольцо. */
.field input, .field textarea, .field select,
.pb-field input, .pb-field textarea, .pb-field select,
.pmadd select, .stginput, .cmt-url, .sub-add input,
.cmt-form textarea, .cmt-edit-ta, .ro-edit textarea{
  background-color:var(--fi-bg);
  color:var(--tx);
  border:1px solid var(--fi-line);
  border-radius:var(--fi-r);
  box-shadow:var(--fi-well);
  caret-color:var(--acc-d);
  color-scheme:var(--fi-scheme);
  transition:border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}
/* .pmadd select в app.js рисуется вне .field, поэтому у него не было ни отступов,
   ни высоты — только flex:1. Добираем до общего вида. */
.pmadd select{padding:10px 12px;min-height:40px;width:100%}

.field input:hover, .field textarea:hover, .field select:hover,
.pb-field input:hover, .pb-field textarea:hover, .pb-field select:hover,
.pmadd select:hover, .stginput:hover, .cmt-url:hover, .sub-add input:hover,
.cmt-form textarea:hover, .cmt-edit-ta:hover, .ro-edit textarea:hover{
  border-color:var(--fi-line-hover);
  background-color:var(--fi-bg-hover);
}

/* Фокус. Кольцо рисуем тенью, а системный outline гасим ПРОЗРАЧНЫМ (не none):
   в app.css есть глобальное `:focus-visible{outline:2px solid !important}` —
   без этого поверх мягкого кольца ложился второй, жёсткий контур.
   Прозрачный outline сохраняется в режиме высокой контрастности (см. блок 20). */
.field input:focus, .field textarea:focus, .field select:focus,
.pb-field input:focus, .pb-field textarea:focus, .pb-field select:focus,
.pmadd select:focus, .stginput:focus, .cmt-url:focus, .sub-add input:focus,
.cmt-form textarea:focus, .cmt-edit-ta:focus, .ro-edit textarea:focus{
  outline:2px solid transparent!important;
  outline-offset:0!important;
  border-color:var(--acc);
  background-color:var(--fi-bg-focus);
  box-shadow:var(--fi-well), var(--fi-ring);
}

/* Плейсхолдер приглушён, но читаем; в фокусе гаснет ещё на треть —
   подсказка своё отработала, дальше она мешает набору. */
.field input::placeholder, .field textarea::placeholder,
.pb-field input::placeholder, .pb-field textarea::placeholder,
.stginput::placeholder, .cmt-url::placeholder, .sub-add input::placeholder,
.cmt-form textarea::placeholder, .cmt-edit-ta::placeholder,
.ro-edit textarea::placeholder, .tagin .tgi::placeholder,
.tsearch input::placeholder, .psearch input::placeholder, .qj #qjq::placeholder{
  color:var(--fi-ph);
  opacity:1;                       /* Firefox по умолчанию гасит до .54 */
  transition:opacity .15s ease;
}
.field input:focus::placeholder, .field textarea:focus::placeholder,
.pb-field input:focus::placeholder, .pb-field textarea:focus::placeholder,
.cmt-form textarea:focus::placeholder, .cmt-edit-ta:focus::placeholder,
.ro-edit textarea:focus::placeholder{opacity:.62}

/* Заполненное поле отличается от пустого: грань плотнее, текст в полную силу.
   Оговорка: у полей без placeholder :placeholder-shown не срабатывает никогда,
   поэтому они всегда читаются как «заполненные» — разница намеренно тихая. */
.field input:not(:placeholder-shown), .field textarea:not(:placeholder-shown),
.pb-field input:not(:placeholder-shown), .pb-field textarea:not(:placeholder-shown),
.stginput:not(:placeholder-shown), .cmt-url:not(:placeholder-shown),
.sub-add input:not(:placeholder-shown), .cmt-form textarea:not(:placeholder-shown){
  border-color:color-mix(in srgb, var(--edge) 55%, var(--line2));
  color:var(--tx);
}

/* Недоступное поле не притворяется живым: гасим фон, снимаем «утопленность». */
.field input:disabled, .field textarea:disabled, .field select:disabled,
.pb-field input:disabled, .pb-field select:disabled, .pmadd select:disabled{
  background-color:var(--fi-bg-off);
  color:var(--tx-dim);
  border-color:var(--line);
  box-shadow:none;
  cursor:not-allowed;
  opacity:1;                        /* iOS Safari сам гасит до .4 — читать нечем */
  -webkit-text-fill-color:var(--tx-dim);
}
.field input[readonly], .field textarea[readonly]{
  background-color:var(--fi-bg-off);
  border-style:dashed;
}

/* ── 2. Автозаполнение ─────────────────────────────────────────────────────
   Chrome/Safari красят автозаполненное поле своим жёлто-белым и снаружи это
   не отключается: цвет фона рисуется поверх background. Классический обход —
   залить фон толстой внутренней тенью и подменить цвет текста -webkit-text-fill-color.
   Сюда же переехали «колодец» и кольцо фокуса, иначе тень их затирает. */
.field input:-webkit-autofill,
.field input:-webkit-autofill:hover,
.field input:-webkit-autofill:active,
.pb-field input:-webkit-autofill,
.sub-add input:-webkit-autofill,
.cmt-url:-webkit-autofill,
.psearch input:-webkit-autofill{
  -webkit-text-fill-color:var(--tx);
  caret-color:var(--acc-d);
  -webkit-box-shadow:inset 0 0 0 100px var(--fi-bg), var(--fi-well);
  box-shadow:inset 0 0 0 100px var(--fi-bg), var(--fi-well);
  border-color:var(--fi-line);
  /* фон Chrome дорисовывает с анимацией — отодвигаем её за горизонт событий */
  transition:background-color 100000s ease-in-out 0s;
}
.field input:-webkit-autofill:focus,
.pb-field input:-webkit-autofill:focus,
.sub-add input:-webkit-autofill:focus,
.cmt-url:-webkit-autofill:focus,
.psearch input:-webkit-autofill:focus{
  -webkit-box-shadow:inset 0 0 0 100px var(--fi-bg-focus), var(--fi-well), var(--fi-ring);
  box-shadow:inset 0 0 0 100px var(--fi-bg-focus), var(--fi-well), var(--fi-ring);
  border-color:var(--acc);
}
/* стандартный псевдокласс — на будущее, поверх вебкитового */
.field input:autofill, .pb-field input:autofill{-webkit-text-fill-color:var(--tx)}

/* ── 3. Выпадающий список ──────────────────────────────────────────────────
   Родной select в тёмной теме — серый прямоугольник с системной стрелкой.
   Снимаем системный вид целиком и рисуем свой шеврон (штрих 1.5, как у всех
   иконок семейства). Место под стрелку резервируем padding-right. */
.field select, .pb-field select, .pmadd select{
  -webkit-appearance:none; -moz-appearance:none; appearance:none;
  background-image:var(--fi-ic-chev);
  background-repeat:no-repeat;
  background-position:right 11px center;
  background-size:17px 17px;
  padding-right:36px;
  cursor:pointer;
  text-overflow:ellipsis;           /* длинное имя клиента не лезет под стрелку */
}
.field select:hover, .pb-field select:hover, .pmadd select:hover{background-image:var(--fi-ic-chev-on)}
.field select:focus, .pb-field select:focus, .pmadd select:focus{background-image:var(--fi-ic-chev-on)}
/* выпадающий список рисует ОС: без явных цветов в тёмной теме он белый */
.field select option, .pb-field select option, .pmadd select option{
  background:var(--panel); color:var(--tx);
}
/* Firefox подсвечивает текст выбранного пункта своим цветом */
.field select:-moz-focusring, .pb-field select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--tx)}

/* ── 3b. Свой выпадающий список ───────────────────────────────────────────
   Родной <select> ни в одном движке не даёт стилизовать сам открытый попап —
   он всегда рисуется системой (светлый, вне темы кабинета). Прячем select
   (value/change остаются настоящими — см. enhanceSelects в app.js) и рисуем
   поверх кнопку со списком в общем языке кабинета. */
select[data-csel]{position:absolute;width:1px;height:1px;overflow:hidden;opacity:0;pointer-events:none}
.csel{position:relative}
.csel.disabled{opacity:.6}
.csel-btn{
  display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;
  font:inherit;text-align:left;
  background-color:var(--fi-bg);color:var(--tx);
  border:1px solid var(--fi-line);border-radius:var(--fi-r);
  box-shadow:var(--fi-well);
  padding:10px 12px;min-height:40px;cursor:pointer;
  transition:border-color .15s ease,box-shadow .15s ease,background-color .15s ease;
}
.csel-btn:hover{border-color:var(--fi-line-hover);background-color:var(--fi-bg-hover)}
.csel-btn:focus-visible{outline:2px solid transparent;outline-offset:0;border-color:var(--acc);background-color:var(--fi-bg-focus);box-shadow:var(--fi-well),var(--fi-ring)}
.csel-btn[aria-expanded="true"]{border-color:var(--acc);background-color:var(--fi-bg-focus);box-shadow:var(--fi-well),var(--fi-ring)}
.csel.disabled .csel-btn{cursor:not-allowed;background-color:var(--fi-bg-off);color:var(--tx-dim)}
.csel-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.csel-chev{
  width:17px;height:17px;flex:none;
  background-image:var(--fi-ic-chev);background-repeat:no-repeat;background-position:center;background-size:17px 17px;
  transition:transform .15s ease;
}
.csel-btn:hover .csel-chev,.csel-btn:focus-visible .csel-chev,.csel-btn[aria-expanded="true"] .csel-chev{background-image:var(--fi-ic-chev-on)}
.csel-btn[aria-expanded="true"] .csel-chev{transform:rotate(180deg)}
.csel-list{
  position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:80;
  max-height:280px;overflow-y:auto;padding:6px;
  background:linear-gradient(180deg,var(--ct-lid-a),var(--ct-lid-b));
  border:1px solid var(--line2);border-radius:8px;
  box-shadow:var(--dp-e3),var(--dp-rim-s);
  animation:ctDropIn .14s var(--ct-ease);
}
.csel-list.hidden{display:none}
.csel-opt{
  padding:9px 11px;border-radius:6px;font-size:14px;color:var(--tx-mut);
  cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:background .12s ease,color .12s ease;
}
.csel-opt:hover,.csel-opt.hover{background:var(--ct-wash);color:var(--tx)}
.csel-opt.on{background:var(--ct-wash-s);color:var(--tx);font-weight:600}
.csel-opt.disabled{opacity:.45;cursor:not-allowed}
@media(prefers-reduced-motion:reduce){.csel-list{animation:none}.csel-chev{transition:none}}

/* ── 4. Дата ───────────────────────────────────────────────────────────────
   Нативная иконка календаря в тёмной теме почти невидима. Меняем её на свою
   (background-image у ::-webkit-calendar-picker-indicator подменяет глиф),
   а color-scheme из блока 1 заодно перекрашивает сам выпадающий календарь. */
.field input[type="date"]{cursor:text;font-variant-numeric:tabular-nums}
.field input[type="date"]::-webkit-calendar-picker-indicator{
  width:18px; height:18px; padding:0; margin-left:6px;
  background-image:var(--fi-ic-cal);
  background-size:18px 18px;
  background-repeat:no-repeat;
  background-position:center;
  opacity:.85; cursor:pointer; border-radius:6px;
  transition:opacity .15s ease, background-image .15s ease;
}
.field input[type="date"]:hover::-webkit-calendar-picker-indicator,
.field input[type="date"]:focus::-webkit-calendar-picker-indicator{
  opacity:1; background-image:var(--fi-ic-cal-on);
}
/* пустая дата в Chrome показывает «дд.мм.гггг» — это не текст, а поля-заглушки */
.field input[type="date"]::-webkit-datetime-edit-text,
.field input[type="date"]::-webkit-datetime-edit-day-field,
.field input[type="date"]::-webkit-datetime-edit-month-field,
.field input[type="date"]::-webkit-datetime-edit-year-field{color:var(--tx)}
.field input[type="date"]:invalid::-webkit-datetime-edit{color:var(--fi-ph)}
.field input[type="date"]::-webkit-datetime-edit-day-field:focus,
.field input[type="date"]::-webkit-datetime-edit-month-field:focus,
.field input[type="date"]::-webkit-datetime-edit-year-field:focus{
  background:color-mix(in srgb, var(--acc) 30%, transparent);
  color:var(--tx); border-radius:4px; outline:none;
}

/* ── 5. Число ──────────────────────────────────────────────────────────────
   Стрелки-спиннеры не убираем (ими пользуются в счетах и часах), но в покое
   держим невидимыми: место они занимают всегда, поэтому текст не прыгает. */
.field input[type="number"]{font-variant-numeric:tabular-nums}
.field input[type="number"]::-webkit-outer-spin-button,
.field input[type="number"]::-webkit-inner-spin-button{
  opacity:0; height:22px; margin-left:4px; cursor:pointer;
  transition:opacity .15s ease;
}
.field input[type="number"]:hover::-webkit-inner-spin-button,
.field input[type="number"]:focus::-webkit-inner-spin-button{opacity:.9}
/* позиции счёта: количество и цена — по правому краю, столбиком цифра в цифру */
.ivrow .ivq, .ivrow .ivp{text-align:right;font-variant-numeric:tabular-nums}
.ivrow{align-items:center}
.ivrow .ivx{
  border-radius:var(--fi-r); color:var(--tx-dim); background:transparent;
  border:1px solid var(--line); transition:.15s ease;
}
.ivrow .ivx:hover{color:var(--danger);border-color:var(--fi-err-line);background:var(--fi-err-bg)}

/* ── 6. Поле со списком (этап задачи) ──────────────────────────────────────
   У <input list> Chrome рисует тот же ::-webkit-calendar-picker-indicator —
   маленький системный треугольник. Подменяем его нашим шевроном, чтобы
   «свой этап» выглядел роднёй селекта, а не случайным полем. */
.stginput{padding-right:30px}
.stginput::-webkit-calendar-picker-indicator{
  width:15px; height:15px; margin:0; opacity:.8; cursor:pointer;
  background-image:var(--fi-ic-chev);
  background-size:15px 15px; background-repeat:no-repeat; background-position:center;
}
.stginput:hover::-webkit-calendar-picker-indicator{opacity:1;background-image:var(--fi-ic-chev-on)}

/* ── 7. Многострочные поля ─────────────────────────────────────────────────
   Уголок растяжения в тёмной теме сливается — рисуем свой (две насечки). */
.field textarea, .pb-field textarea, .cmt-form textarea,
.cmt-edit-ta, .ro-edit textarea{
  scrollbar-width:thin;
  scrollbar-color:var(--line2) transparent;
}
.field textarea::-webkit-scrollbar, .cmt-form textarea::-webkit-scrollbar,
.ro-edit textarea::-webkit-scrollbar{width:8px}
.field textarea::-webkit-scrollbar-thumb, .cmt-form textarea::-webkit-scrollbar-thumb,
.ro-edit textarea::-webkit-scrollbar-thumb{background:var(--line2);border-radius:8px}
.field textarea::-webkit-scrollbar-track, .cmt-form textarea::-webkit-scrollbar-track,
.ro-edit textarea::-webkit-scrollbar-track{background:transparent}
.field textarea::-webkit-resizer, .cmt-form textarea::-webkit-resizer,
.ro-edit textarea::-webkit-resizer{
  background-image:var(--fi-ic-grip);
  background-size:11px 11px; background-repeat:no-repeat; background-position:right 2px bottom 2px;
}
/* поле комментария: при перетаскивании картинки — пунктир и индиговая подсветка */
#cb.drop{
  border-color:var(--acc);
  border-style:dashed;
  background-color:color-mix(in srgb, var(--acc) 9%, var(--fi-bg));
  box-shadow:var(--fi-well), var(--fi-ring);
}
/* заголовок задачи: подчёркивание было только в фокусе и сдвигало текст на 1px */
.tasktitle, .tasktitle.tt-area{
  border:0; border-bottom:1px solid transparent;
  caret-color:var(--acc-d);
  transition:border-color .15s ease;
}
.tasktitle:focus, .tasktitle.tt-area:focus{border-bottom-color:var(--acc);outline:none!important}
.tasktitle::placeholder{color:var(--fi-ph)}

/* ── 8. Поиск ──────────────────────────────────────────────────────────────
   Три поиска в кабинете (по задачам, по проектам в меню, Cmd+K) получают одну
   лупу в одном штрихе 1.5. У .tsearch иконка уже есть разметкой — ей правим
   толщину штриха и цвет; двум другим кладём ту же лупу фоном. */
.tsearch{transition:border-color .15s ease, box-shadow .15s ease}
.tsearch:focus-within{border-color:var(--acc);box-shadow:var(--dp-e1), var(--fi-ring)}
.ts-ic{color:var(--fi-ph);transition:color .15s ease}
.ts-ic svg{width:17px;height:17px;stroke-width:1.5}
.tsearch:focus-within .ts-ic{color:var(--acc-d)}
.tsearch input{caret-color:var(--acc-d)}
.ts-x{width:28px;height:28px;border-radius:8px;transition:.15s ease}
.ts-x:hover{background:var(--fi-err-bg);color:var(--danger)}

.psearch input{
  background-color:var(--fi-bg);
  border-color:var(--fi-line);
  border-radius:var(--fi-r);
  box-shadow:var(--fi-well);
  caret-color:var(--acc-d);
  padding-left:34px; padding-right:32px;
  background-image:var(--fi-ic-search);
  background-repeat:no-repeat;
  background-position:11px center;
  background-size:15px 15px;
  transition:border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}
.psearch input:hover{border-color:var(--fi-line-hover);background-color:var(--fi-bg-hover)}
.psearch input:focus{
  outline:2px solid transparent!important; outline-offset:0!important;
  border-color:var(--acc); background-color:var(--fi-bg-focus);
  box-shadow:var(--fi-well), var(--fi-ring);
}
.psx{width:28px;height:28px;display:grid;place-items:center;border-radius:8px;padding:0;transition:.15s ease}

.qj #qjq{
  padding-left:52px;
  background-image:var(--fi-ic-search);
  background-repeat:no-repeat;
  background-position:20px center;
  background-size:19px 19px;
  caret-color:var(--acc-d);
  color-scheme:var(--fi-scheme);
}
.qj #qjq:focus{outline:none!important;border-bottom-color:var(--acc)}

/* ── 9. Ввод меток ─────────────────────────────────────────────────────────
   Контейнер ведёт себя как одно поле: грань и кольцо принадлежат ему,
   а не внутреннему input, иначе рамка в рамке. */
.tagin{
  background-color:var(--fi-bg);
  border-color:var(--fi-line);
  border-radius:var(--fi-r);
  box-shadow:var(--fi-well);
  transition:border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
}
.tagin:hover{border-color:var(--fi-line-hover)}
.tagin:focus-within{
  border-color:var(--acc);
  background-color:var(--fi-bg-focus);
  box-shadow:var(--fi-well), var(--fi-ring);
}
.tagin .tgi{caret-color:var(--acc-d)}
.tagin .tgi:focus{outline:2px solid transparent!important;outline-offset:0!important}
.tp{
  border:1px solid var(--line2);
  background:color-mix(in srgb, var(--card) 70%, transparent);
  padding:3px 5px 3px 9px;
  transition:border-color .14s ease, background .14s ease;
}
.tp:hover{border-color:var(--edge)}
.tp .td{box-shadow:0 0 7px -1px hsl(var(--h,30) 60% 55%)}
.tp .tx{
  width:18px;height:18px;display:inline-grid;place-items:center;
  border-radius:5px;font-size:13px;transition:.14s ease;
}
.tp .tx:hover{background:var(--fi-err-bg);color:var(--danger)}

/* ── 10. Ползунок готовности ───────────────────────────────────────────────
   Дорожка и бегунок нарисованы целиком: системного вида не остаётся.
   Заливка слева от бегунка — приём с огромной тенью бегунка, обрезанной
   overflow:hidden самого input; в Firefox то же делает ::-moz-range-progress.
   Прозрачная рамка 6px расширяет зону нажатия, не трогая вид дорожки. */
.rngrow{gap:14px}
.rng{
  -webkit-appearance:none; appearance:none;
  flex:1; min-width:0;
  height:24px;                       /* 12px дорожка + 6px прозрачной рамки сверху и снизу */
  border:6px solid transparent;
  border-radius:999px;
  background-color:var(--fi-bg);
  background-clip:padding-box;
  box-shadow:var(--fi-well);
  overflow:hidden;                   /* обрезает тень-заливку по дорожке */
  cursor:pointer;
  color-scheme:var(--fi-scheme);
}
.rng::-webkit-slider-runnable-track{height:12px;background:transparent;border:none;border-radius:999px}
.rng::-webkit-slider-thumb{
  -webkit-appearance:none;
  width:12px; height:12px; border-radius:50%;
  background:var(--fi-knob);
  border:none; cursor:grab;
  box-shadow:
    -1000px 0 0 994px var(--acc),                  /* заливка пройденного пути */
    0 0 0 1px rgba(36,36,36,.28);                     /* кант, чтобы бегунок читался на заливке */
  transition:box-shadow .15s ease;
}
.rng:hover::-webkit-slider-thumb{box-shadow:-1000px 0 0 994px var(--acc-d), 0 0 0 1px rgba(36,36,36,.28)}
.rng:active::-webkit-slider-thumb{cursor:grabbing}
.rng::-moz-range-track{height:12px;background:transparent;border:none;border-radius:999px}
.rng::-moz-range-progress{height:12px;background:var(--acc);border-radius:999px}
.rng::-moz-range-thumb{
  width:12px;height:12px;border-radius:50%;border:none;
  background:var(--fi-knob);box-shadow:0 0 0 1px rgba(36,36,36,.28);cursor:grab;
}
.rng:focus-visible{outline:2px solid var(--dp-focus);outline-offset:3px}
.rngv{color:var(--tx);min-width:48px}

/* ── 11. Тумблер ───────────────────────────────────────────────────────────
   Единственный тумблер кабинета — «Заблокировано, ждём клиента», поэтому
   включённое состояние красное осознанно: это предупреждение, а не успех.
   Дорожка утоплена, шарик приподнят тенью — состояние видно и без цвета. */
.switch{gap:11px;padding:2px 0}
.switch .sw{
  width:42px;height:24px;border-radius:999px;
  background:var(--fi-bg);
  border:1px solid var(--fi-line);
  box-shadow:var(--fi-well);
  transition:background .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.switch .sw::after{
  top:2px;left:2px;width:18px;height:18px;
  background:var(--fi-ph);
  box-shadow:0 1px 3px rgba(36,36,36,.5);
  transition:left .2s cubic-bezier(.2,.8,.3,1), background .2s ease, width .12s ease;
}
.switch:hover .sw{border-color:var(--fi-line-hover)}
.switch:hover .sw::after{background:var(--tx-mut)}
.switch input:checked+.sw{
  background:color-mix(in srgb, var(--danger) 30%, var(--fi-bg));
  border-color:var(--danger);
  box-shadow:var(--fi-well), 0 0 14px -6px var(--danger);
}
.switch input:checked+.sw::after{left:20px;background:var(--danger);box-shadow:0 1px 4px rgba(36,36,36,.5)}
.switch:active .sw::after{width:21px}                 /* нажатие «продавливает» шарик */
.switch input:focus-visible+.sw{
  outline:2px solid var(--dp-focus); outline-offset:3px;
}
.switch .swl{color:var(--tx-mut);transition:color .15s ease}
.switch:hover .swl{color:var(--tx)}

/* ── 12. Флажок режима колонок ─────────────────────────────────────────────
   Нативный чекбокс с accent-color всё равно рисуется системой и в тёмной теме
   выглядит чужим. Рисуем свой: утопленная клетка, галочка — inline-SVG. */
.bdmode{transition:border-color .15s ease, background .15s ease}
.bdmode:hover{border-color:var(--line2)}
.bdmode input{
  -webkit-appearance:none; appearance:none;
  width:19px;height:19px;flex:none;
  border:1px solid var(--fi-line);
  border-radius:6px;
  background-color:var(--fi-bg);
  box-shadow:var(--fi-well);
  transition:background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.bdmode:hover input{border-color:var(--fi-line-hover)}
.bdmode input:checked{
  background-color:var(--acc);
  border-color:var(--acc);
  background-image:var(--fi-ic-check);
  background-size:15px 15px;
  background-repeat:no-repeat;
  background-position:center;
  box-shadow:0 2px 10px -4px var(--acc);
}
.bdmode:has(input:checked){border-color:color-mix(in srgb, var(--acc) 40%, var(--line))}

/* ── 13. Выбор цвета колонки ───────────────────────────────────────────────
   Отметка выбранного была только кольцом; добавляем галочку — на пёстрых
   плашках кольцо читается хуже, чем знак внутри. */
.csw{position:relative;border-radius:9px;transition:transform .12s ease, box-shadow .12s ease}
.csw.on::after{
  content:''; position:absolute; inset:0;
  background-image:var(--fi-ic-check);
  background-size:16px 16px; background-repeat:no-repeat; background-position:center;
  filter:drop-shadow(0 1px 2px rgba(36,36,36,.65));      /* белая галочка живёт и на светлой плашке */
}

/* ── 14. Кнопки прикрепления ───────────────────────────────────────────────
   Скрепка в разметке уже есть (ICON.paperclip, штрих 1.8) — приводим её
   к общему для семейства штриху 1.5, чтобы иконки читались одним набором. */
.cmt-attach svg, .btn-file svg, .cef-add svg, .cef-cur svg,
.docs-head svg, .doc-ic svg, .cmt-file svg{stroke-width:1.5}
.cmt-attach, .btn-file, .doc-add, .cef-add{
  border-radius:9px;
  transition:border-color .15s ease, background .15s ease, color .15s ease, box-shadow .15s ease;
}
.cmt-attach:hover, .btn-file:hover, .doc-add:hover, .cef-add:hover{
  border-color:var(--acc);
  color:var(--acc-d);
  background:color-mix(in srgb, var(--acc) 10%, transparent);
}
.cmt-attach:active, .btn-file:active, .doc-add:active, .cef-add:active{transform:translateY(1px)}
.btn-file{border-style:dashed}
.btn-file:hover{border-style:solid}
.cef-x:hover{background:var(--fi-err-bg)}
/* имя выбранного файла: точка-маркер, чтобы строка не выглядела оборванной */
.docpick-name:not(:empty)::before, .cf-name.has::before{
  content:''; width:6px; height:6px; border-radius:50%;
  background:var(--ok); flex:none; margin-right:2px; align-self:center;
}

/* ── 15. Подписи, подсказки, ошибки ────────────────────────────────────────
   Подпись — 11px капсом (шкала проекта), поэтому нужен контраст ≥7:1:
   у --tx-mut на светлой теме поверх --bg выходит 6.8 — берём свой --fi-label. */
.field label, .pb-field>label, .ro-edit label{color:var(--fi-label)}
.field label{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.hint, .ro-edit-act .hint, .field label .hint, .pb-field>label .hint{color:var(--fi-hint)}
/* обязательное поле помечаем сами: в разметке есть только атрибут required */
.field:has(input:required) label::after,
.field:has(textarea:required) label::after{
  content:'*'; color:var(--acc-d); font-weight:700; margin-left:-3px;
}
.pb-req{color:var(--acc-d)}

/* Пустой .err — это распорка на 16px в каждой форме. Пусть он просто исчезает,
   а появившись, читается как настоящее сообщение: знак, подложка, грань. */
.err:empty{display:none}
.err:not(:empty){
  display:flex; align-items:flex-start; gap:9px;
  margin-top:2px; padding:9px 12px 9px 36px;
  min-height:0;
  color:var(--fi-err);
  background:var(--fi-err-bg);
  border:1px solid var(--fi-err-line);
  border-radius:var(--fi-r);
  line-height:1.4;
  background-image:var(--fi-ic-alert);
  background-repeat:no-repeat;
  background-position:12px 10px;
  background-size:16px 16px;
  animation:fiErrIn .18s ease-out;
}
@keyframes fiErrIn{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}
/* поле, которое браузер считает незаполненным, подсвечиваем только после попытки
   отправки — :user-invalid, а не :invalid: иначе пустая форма краснеет сразу */
.field input:user-invalid, .field textarea:user-invalid{
  border-color:var(--fi-err-line);
}
.field input:user-invalid:focus, .field textarea:user-invalid:focus{
  border-color:var(--fi-err);
  box-shadow:var(--fi-well), 0 0 0 3px var(--fi-err-bg);
}

/* ── 16. Мелочи раскладки форм ─────────────────────────────────────────────
   Ссылки «обновить список клиентов» / «сгенерировать» лежат прямо в .field
   сразу за полем и слипались с ним. */
.field a{align-self:flex-start;margin-top:2px;color:var(--acc-d);border-bottom:1px solid transparent}
.field a:hover{border-bottom-color:currentColor}
.sub-add{align-items:center}
.docpick{gap:10px}
.cmt-tools{gap:10px}

/* ── 17. Узкий экран: зоны нажатия и размер шрифта ─────────────────────────
   16px обязателен — иначе iOS зумит страницу при фокусе. В app.css это правило
   уже есть, но оно ВЫШЕ по файлу и слабее по специфичности, поэтому повторяем
   его здесь, иначе мои селекторы его перебьют. */
@media(max-width:760px){
  .field input, .field textarea, .field select,
  .pb-field input, .pb-field textarea, .pb-field select,
  .pmadd select, .stginput, .cmt-url, .sub-add input,
  .cmt-form textarea, .cmt-edit-ta, .ro-edit textarea,
  .tagin .tgi, .tsearch input, .psearch input{font-size:16px}

  .field input, .field select, .pmadd select, .sub-add input, .cmt-url, .stginput{min-height:44px}
  .field textarea, .ro-edit textarea{min-height:88px}
  .ts-x, .psx, .ivrow .ivx, .cef-x, .tp .tx{min-width:44px;min-height:44px}
  .ts-x, .psx{width:44px;height:44px}
  .psearch input{padding-right:46px}
  .tp{padding-right:0}
  .tp .tx{border-radius:7px}
  .switch{min-height:44px;align-items:center}
  .bdmode input{width:24px;height:24px}
  .csw{width:44px;height:44px}
  /* ползунок: дорожка та же, прозрачная рамка растёт — палец попадает в 44px */
  .rng{height:44px;border-width:16px}
  .cmt-attach, .btn-file, .doc-add{min-height:44px}
  .err:not(:empty){padding:11px 13px 11px 38px}
}
/* 390px и уже: строка позиции счёта не должна выдавливать поле наименования */
@media(max-width:430px){
  .ivrow{grid-template-columns:1fr 62px 84px 44px;gap:6px}
  .ivrow input{min-width:0;padding-left:9px;padding-right:9px}
  .rngrow{gap:10px}
  .rngv{min-width:42px}
  .field a{font-size:12px}
}

/* ── 18. Светлая тема: точечные поправки ───────────────────────────────────
   На кремово-белом «колодец» должен быть тише, а заливка ползунка — плотнее,
   иначе индиго на белом выглядит выцветшим. */
:root[data-theme="light"] .rng::-webkit-slider-thumb{
  box-shadow:-1000px 0 0 994px var(--acc), 0 0 0 1px rgba(56,56,56,.22);
}
:root[data-theme="light"] .rng::-moz-range-thumb{box-shadow:0 0 0 1px rgba(56,56,56,.22)}
:root[data-theme="light"] .switch .sw::after{box-shadow:0 1px 3px rgba(56,56,56,.28)}
:root[data-theme="light"] .field input[readonly],
:root[data-theme="light"] .field textarea[readonly]{color:var(--tx-mut)}

/* ── 19. Меньше движения ───────────────────────────────────────────────────
   Гасим всю анимацию семейства, оставляя мгновенную смену состояний. */
@media(prefers-reduced-motion:reduce){
  .field input, .field textarea, .field select,
  .pb-field input, .pb-field textarea, .pb-field select,
  .pmadd select, .stginput, .cmt-url, .sub-add input,
  .cmt-form textarea, .cmt-edit-ta, .ro-edit textarea,
  .tagin, .tsearch, .psearch input, .tasktitle,
  .switch .sw, .switch .sw::after, .switch .swl,
  .bdmode, .bdmode input, .csw, .tp, .tp .tx, .ts-ic, .ts-x,
  .rng::-webkit-slider-thumb,
  .cmt-attach, .btn-file, .doc-add, .cef-add,
  .field input[type="date"]::-webkit-calendar-picker-indicator,
  .field input[type="number"]::-webkit-inner-spin-button,
  .field input::placeholder, .field textarea::placeholder{
    transition:none;
  }
  .err:not(:empty){animation:none}
  .cmt-attach:active, .btn-file:active, .doc-add:active, .cef-add:active{transform:none}
  .csw:hover{transform:none}
}

/* ── 20. Режим высокой контрастности ───────────────────────────────────────
   Там цвета задаёт система: возвращаем настоящий контур фокуса вместо
   прозрачного, которым мы гасили дублирующий outline. */
@media(forced-colors:active){
  .field input:focus, .field textarea:focus, .field select:focus,
  .pb-field input:focus, .pb-field textarea:focus, .pb-field select:focus,
  .pmadd select:focus, .stginput:focus, .cmt-url:focus, .sub-add input:focus,
  .cmt-form textarea:focus, .cmt-edit-ta:focus, .ro-edit textarea:focus,
  .psearch input:focus, .tagin .tgi:focus{
    outline:2px solid Highlight!important; outline-offset:2px!important;
  }
  .field select, .pb-field select, .pmadd select,
  .psearch input, .qj #qjq{background-image:none;padding-right:12px}
  .bdmode input:checked{background-image:none;border-width:5px}
  .rng::-webkit-slider-thumb{box-shadow:none}
}

/* ▲▲▲ конец ▲▲▲ */

/* ═══ Номера задач, графы колонок, шапка блокировки, свойства ═══════════
   Разметку добавляет app.js; здесь — вид под «Полночь». */

/* Номер задачи — как позиция в спецификации: моно, приглушённый,
   выделяется одним кликом, чтобы скопировать в переписку. */
.card .chead{display:flex;align-items:baseline;gap:8px;margin-bottom:5px;min-width:0}
.card .tid,.tno{font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.05em;
  color:var(--tx-dim);background:color-mix(in srgb,var(--acc) 10%,transparent);
  border:1px solid color-mix(in srgb,var(--acc) 26%,transparent);
  padding:0 5px;line-height:16px;border-radius:4px;flex:none;user-select:all;cursor:text}
.card:hover .tid{color:var(--acc-d);border-color:color-mix(in srgb,var(--acc) 45%,transparent)}
.tno{font-size:11px;line-height:18px;padding:0 7px}
.card .chead .cstage{margin:0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Блокировка — шапка карточки во всю ширину: мяч на стороне клиента,
   это надо видеть, не вчитываясь в мелочь. */
.card.blocked{border-color:color-mix(in srgb,var(--danger) 48%,var(--line))}
.card .blk{margin:-11px -13px 9px;padding:5px 13px;
  background:color-mix(in srgb,var(--danger) 16%,transparent);
  border-bottom:1px solid color-mix(in srgb,var(--danger) 32%,transparent);
  font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
  border-radius:var(--r) var(--r) 0 0}

/* Графа колонки слева от названия. .col-h стоит на space-between,
   поэтому названию нужен margin-right:auto, иначе оно уедет в середину. */
.col-h .cix{font-family:var(--mono);font-size:10px;font-weight:600;color:var(--tx-dim);
  letter-spacing:.05em;margin-right:9px;flex:none;opacity:.75}
.col-h .t{margin-right:auto;min-width:0}

/* Сводка задачи пилюлями + свойства в сворачиваемом блоке */
.tmeta{display:flex;flex-wrap:wrap;align-items:center;gap:7px;margin:0 0 15px}
details.props{border:1px solid var(--line);border-radius:var(--r);
  background:color-mix(in srgb,var(--card2) 60%,transparent);margin:0 0 18px}
details.props>summary{list-style:none;cursor:pointer;display:flex;align-items:baseline;gap:10px;
  padding:11px 14px;font-size:13px;font-weight:600;color:var(--tx-mut);user-select:none}
details.props>summary::-webkit-details-marker{display:none}
details.props>summary::before{content:'▸';font-size:11px;color:var(--tx-dim);
  transition:transform .16s var(--mn-ease,ease);display:inline-block}
details.props[open]>summary::before{transform:rotate(90deg)}
details.props>summary:hover{color:var(--tx)}
details.props>summary:hover::before{color:var(--acc)}
details.props .ps-h{font-size:11.5px;font-weight:400;color:var(--tx-dim);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
details.props[open] .ps-h{display:none}
.props-body{padding:2px 14px 14px;border-top:1px solid var(--line)}
@media(max-width:560px){details.props .ps-h{display:none}}
@media(prefers-reduced-motion:reduce){details.props>summary::before{transition:none}}

/* ▼▼▼ ПРОРАБОТКА: КНОПКИ, МЕНЮ, ВКЛАДКИ, МОДАЛКИ, СКРОЛЛБАРЫ ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   «ПОЛНОЧЬ» · СЕМЕЙСТВО «ЭЛЕМЕНТЫ УПРАВЛЕНИЯ»
   Кнопки · сегменты · вкладки · чипы досок · меню пользователя · модалки ·
   тосты · подсказки · скроллбары · выделение текста.

   Файл добавляется В КОНЕЦ app.css: при равной специфичности перебивает базу.
   Геометрия оболочки не трогается (.shell/.side/.board/.col — не в файле).

   Все селекторы сверены с app.js: мёртвых нет. Отсутствующий в разметке
   .wtabs НЕ стилизуется — такого класса в проекте не существует.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   0 · ТОКЕНЫ СЕМЕЙСТВА
   Свой префикс --ct-* (грепом по app.css и app.js совпадений 0), чтобы не
   спорить с палитрой «Полночи» и со шкалой высот --dp-*.
   ─────────────────────────────────────────────────────────────────────────── */
:root{
  /* Ant заливает поверхности ПЛОСКО, без «фаски»: обе точки каждого градиента
     одинаковые, поэтому все linear-gradient(--ct-*-a, --ct-*-b) по файлу
     превращаются в ровную заливку без правки самих правил.
     Кнопка по умолчанию — colorBgContainer + colorBorder. */
  --ct-face-a:#141414; --ct-face-b:#141414;
  --ct-face-h-a:#141414; --ct-face-h-b:#141414;

  /* Первичная кнопка Ant — плоский colorPrimary под белым текстом
     (а не инвертированная светлая заливка прежней Ч/Б-палитры). */
  --ct-fill-a:#1668DC; --ct-fill-b:#1668DC;
  --ct-fill-h-a:#3C89E8; --ct-fill-h-b:#3C89E8;   /* colorPrimaryHover */
  --ct-on:#FFFFFF;

  --ct-wash:  color-mix(in srgb, var(--acc) 12%, transparent);   /* наведение */
  --ct-wash-s:color-mix(in srgb, var(--acc) 20%, transparent);   /* включено  */
  --ct-ring:  color-mix(in srgb, var(--acc) 32%, transparent);   /* фокус     */
  --ct-halo:  none;                                              /* Ant не светит кнопками */
  --ct-press: none;

  /* поверхность «меню/модалка» — colorBgElevated, тоже плоская */
  --ct-lid-a:#1F1F1F; --ct-lid-b:#1F1F1F;
  --ct-glass: rgba(31,31,31,.9);

  /* скроллбар: не серый, а в тон индиго — деталь, по которой видно уровень */
  /* 3.19:1 к дну модалки и 3.64:1 к «корыту» колонки — ползунок обязан
     читаться как элемент управления, а не как шов */
  --ct-bar:      color-mix(in srgb, var(--acc) 70%, var(--edge));
  --ct-bar-hover:color-mix(in srgb, var(--acc-d) 88%, var(--edge));

  --ct-mo:160ms;                       /* базовая длительность перехода */
  --ct-ease:cubic-bezier(.2,.8,.25,1); /* «мягкий выход» — общий для семейства */
}
[data-theme="light"]{
  --ct-face-a:#FFFFFF; --ct-face-b:#FFFFFF;
  --ct-face-h-a:#FFFFFF; --ct-face-h-b:#FFFFFF;

  --ct-fill-a:#1677FF; --ct-fill-b:#1677FF;
  --ct-fill-h-a:#4096FF; --ct-fill-h-b:#4096FF;   /* colorPrimaryHover */
  --ct-on:#FFFFFF;

  --ct-press: none;
  --ct-lid-a:#FFFFFF; --ct-lid-b:#FFFFFF;
  --ct-glass: rgba(255,255,255,.9);

  --ct-bar:      color-mix(in srgb, var(--acc) 62%, var(--edge));   /* 5.06:1 к белому */
  --ct-bar-hover:var(--acc-d);
}


/* ───────────────────────────────────────────────────────────────────────────
   1 · ВЫДЕЛЕНИЕ ТЕКСТА
   Индиго вместо системного синего: иначе выделение выпадает из оформления.
   Контраст текста на выделении: тёмная 8.34:1, светлая 8.22:1.
   ─────────────────────────────────────────────────────────────────────────── */
::selection{background:color-mix(in srgb, var(--acc) 45%, transparent);color:var(--tx);text-shadow:none}


/* ───────────────────────────────────────────────────────────────────────────
   2 · ФОКУС С КЛАВИАТУРЫ
   Базовый файл уже объявил :focus-visible с !important — перебиваем таким же
   !important (ниже по источнику), иначе смещение кольца не применится.
   Контур (outline) + мягкое кольцо тенью: контур виден на любом фоне,
   кольцо даёт «индиговое сияние», о котором просил владелец.
   ─────────────────────────────────────────────────────────────────────────── */
:focus-visible{outline:2px solid var(--dp-focus)!important;outline-offset:2px!important}

.btn:focus-visible,
.iconbtn:focus-visible,
.col-tool:focus-visible,
.card .qadv:focus-visible,
.addtask:focus-visible,
.col-addcol:focus-visible,
.doc-add:focus-visible,
.seg button:focus-visible,
.schip:focus-visible,
.ptab:focus-visible,
.bchip:focus-visible,
.ubtn:focus-visible,
.udrop .navitem:focus-visible,
.qj-i:focus-visible{box-shadow:0 0 0 4px var(--ct-ring)}
/* у основной кнопки собственное свечение сохраняем, кольцо добавляем сверху */
.btn-primary:focus-visible,
.btn-danger-solid:focus-visible{box-shadow:0 0 0 4px var(--ct-ring), var(--ct-halo)}
/* .qadv в покое скрыта (opacity:0) и показывается по наведению на карточку —
   при переходе табом её было не видно вовсе. Проявляем на фокусе. */
.card .qadv:focus-visible{opacity:1;transform:none}
/* внутри доски фокус не должен обрезаться краем прокрутки колонки */
.col-body :focus-visible{outline-offset:1px!important}


/* ───────────────────────────────────────────────────────────────────────────
   3 · КНОПКИ · .btn и семейство
   Покой → наведение → нажатие: три ступени высоты, а не три оттенка серого.
   ─────────────────────────────────────────────────────────────────────────── */
.btn{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border:1px solid var(--line2);
  color:var(--tx);                      /* 15:1 к поверхности кнопки */
  border-radius:10px;
  box-shadow:var(--dp-e1), var(--dp-rim);
  /* явный список свойств: «transition:.15s» в базе означает transition:all и
     тянет за собой перерисовку теней при любом изменении */
  transition:background var(--ct-mo) ease, border-color var(--ct-mo) ease,
             box-shadow var(--ct-mo) ease, color var(--ct-mo) ease,
             transform 90ms var(--ct-ease);
}
.btn:hover{
  background:linear-gradient(180deg, var(--ct-face-h-a), var(--ct-face-h-b));
  border-color:var(--edge);
  box-shadow:var(--dp-e2), var(--dp-rim-s);
}
/* тактильность: кнопка уходит под палец и теряет высоту */
.btn:active:not(:disabled){transform:translateY(1px);box-shadow:var(--ct-press);border-color:var(--line2)}

/* иконка внутри кнопки живёт вместе с ней */
.btn .pl-ic svg{transition:transform var(--ct-mo) var(--ct-ease)}
.btn:hover .pl-ic svg{transform:scale(1.08)}

/* --- основная --- */
.btn-primary{
  background:linear-gradient(180deg, var(--ct-fill-a), var(--ct-fill-b));
  border-color:color-mix(in srgb, var(--ct-fill-b) 70%, #000);
  color:var(--ct-on);
  /* верхний блик — «стеклянная» кромка, ради неё и держим глубокую заливку */
  box-shadow:inset 0 1px 0 rgba(255,255,255,.34), var(--ct-halo), var(--dp-e1);
}
.btn-primary:hover{
  background:linear-gradient(180deg, var(--ct-fill-h-a), var(--ct-fill-h-b));
  border-color:color-mix(in srgb, var(--ct-fill-h-b) 70%, #000);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.40), 0 14px 34px -12px var(--glow), var(--dp-e2);
}
.btn-primary:active:not(:disabled){
  box-shadow:inset 0 2px 7px -2px rgba(36,36,36,.5), inset 0 1px 0 rgba(255,255,255,.18);
}

/* --- призрачная --- */
.btn-ghost{
  background:none;border-color:transparent;color:var(--tx-mut);   /* 8:1 к фону */
  box-shadow:none;
}
.btn-ghost:hover{
  background:var(--ct-wash);border-color:color-mix(in srgb, var(--acc) 26%, transparent);
  color:var(--tx);box-shadow:none;
}
.btn-ghost:active:not(:disabled){background:var(--ct-wash-s);box-shadow:none}

/* --- опасная, контурная --- */
/* база красила её в #D03E2F/#E26455 — кирпич из прежней оранжевой темы */
.btn-danger{color:var(--tx)}
.btn-danger:hover{
  color:var(--danger);                               /* 5.87:1 тёмная, 4.86:1 светлая */
  border-color:color-mix(in srgb, var(--danger) 55%, var(--line2));
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--danger) 14%, var(--ct-face-a)),
    color-mix(in srgb, var(--danger) 9%,  var(--ct-face-b)));
  box-shadow:var(--dp-e2), var(--dp-rim-s);
}
.btn-danger:active:not(:disabled){box-shadow:var(--ct-press)}
.btn-danger .pl-ic svg{transition:transform var(--ct-mo) var(--ct-ease)}

/* --- опасная, залитая (подтверждение удаления) --- */
/* было color:#fff на #FF6380 = 2.97:1. --on-danger даёт 6.14:1 (тёмная)
   и 4.86:1 (светлая) — токен ровно для этого и заведён в палитре */
.btn-danger-solid,
.btn-danger-solid:hover{
  color:var(--on-danger);
  border-color:color-mix(in srgb, var(--danger) 72%, #000);
}
.btn-danger-solid{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--danger) 92%, #FFF),
    var(--danger));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32), 0 10px 26px -12px color-mix(in srgb, var(--danger) 55%, transparent), var(--dp-e1);
  filter:none;
}
.btn-danger-solid:hover{
  background:linear-gradient(180deg, color-mix(in srgb, var(--danger) 80%, #FFF), color-mix(in srgb, var(--danger) 96%, #FFF));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.38), 0 14px 32px -12px color-mix(in srgb, var(--danger) 62%, transparent), var(--dp-e2);
  /* база подсвечивала наведение через filter:brightness — с ним заливка
     светлеет и контраст текста падает; осветляем самой заливкой */
  filter:none;
}
.btn-danger-solid:active:not(:disabled){box-shadow:inset 0 2px 7px -2px rgba(36,36,36,.45)}

/* --- состояние «занят» ---
   В app.js .btn отключается ТОЛЬКО на время запроса (сохранение, удаление,
   отправка комментария) — проверено по всем 8 местам с btn.disabled = true.
   Поэтому disabled здесь честно означает «работаю», а не «нельзя». */
.btn:disabled{cursor:progress;transform:none}
.btn:disabled,.btn:disabled:hover{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border-color:var(--line2);box-shadow:var(--dp-e1), var(--dp-rim);
  color:transparent;opacity:.92;
}
.btn-ghost:disabled,.btn-ghost:disabled:hover{background:none;border-color:transparent;box-shadow:none}
.btn-primary:disabled,.btn-primary:disabled:hover{
  background:linear-gradient(180deg, var(--ct-fill-a), var(--ct-fill-b));
  border-color:color-mix(in srgb, var(--ct-fill-b) 70%, #000);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.2);opacity:.85;
}
.btn-danger-solid:disabled,.btn-danger-solid:disabled:hover{
  background:var(--danger);border-color:var(--danger);opacity:.85;box-shadow:none;
}
/* сам волчок: тонкое кольцо с ярким сегментом, без «пропеллера» */
.btn:disabled::after{
  width:16px;height:16px;border-width:2px;
  border-color:color-mix(in srgb, var(--tx) 18%, transparent);
  border-top-color:var(--tx);
}
.btn-primary:disabled::after,
.btn-danger-solid:disabled::after{
  border-color:rgba(255,255,255,.28);border-top-color:var(--ct-on);
}


/* ───────────────────────────────────────────────────────────────────────────
   4 · КНОПКИ-ГЛИФЫ · .iconbtn
   38×38 в шапке (тема, колокол, бургер) и «✕/ссылка» в шапках модалок.
   ─────────────────────────────────────────────────────────────────────────── */
.iconbtn{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border:1px solid var(--line2);color:var(--tx-mut);
  border-radius:6px;
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:background var(--ct-mo) ease, border-color var(--ct-mo) ease,
             color var(--ct-mo) ease, box-shadow var(--ct-mo) ease,
             transform 90ms var(--ct-ease);
}
.iconbtn:hover{
  background:linear-gradient(180deg, var(--ct-face-h-a), var(--ct-face-h-b));
  border-color:color-mix(in srgb, var(--acc) 40%, var(--line2));
  color:var(--tx);box-shadow:var(--dp-e2), var(--dp-rim-s), 0 0 18px -10px var(--glow);
}
.iconbtn:active{transform:translateY(1px);box-shadow:var(--ct-press)}
.iconbtn svg{transition:transform var(--ct-mo) var(--ct-ease)}
.iconbtn:hover svg{transform:scale(1.06)}
/* переключатель темы: «луна» доворачивается — микрожест, который замечают */
#theme:hover svg{transform:rotate(-18deg) scale(1.06)}

/* .btn + .iconbtn в одной кнопке (закрыть модалку, скопировать ссылку):
   .btn отдаёт padding 7/13 в 38-пиксельный грид — иконка уезжала из центра */
.btn.iconbtn{padding:0;gap:0}
.btn-ghost.iconbtn{background:none;border-color:transparent;box-shadow:none;color:var(--tx-mut)}
.btn-ghost.iconbtn:hover{
  background:var(--ct-wash);border-color:color-mix(in srgb, var(--acc) 24%, transparent);
  color:var(--tx);box-shadow:none;
}
.btn-ghost.iconbtn:active{transform:translateY(1px);background:var(--ct-wash-s)}

/* «✕» текстом рисуется разными шрифтами по-разному — заменяем векторной
   маской: одинаковая толщина штриха и точный центр в любой системе */
.iconbtn[data-close]{font-size:0}
.iconbtn[data-close]::before{
  content:'';width:15px;height:15px;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center/15px 15px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M6 6l12 12M18 6L6 18'/%3E%3C/svg%3E") center/15px 15px no-repeat;
  transition:transform var(--ct-mo) var(--ct-ease);
}
.iconbtn[data-close]:hover::before{transform:rotate(90deg)}
.iconbtn[data-tlink]:hover{color:var(--acc-d)}

/* колокол уведомлений: счётчик — не наклейка, а часть кнопки */
.bellbtn{overflow:visible}
.nbadge{
  background:var(--danger);color:var(--on-danger);   /* 6.14:1 тёмная / 4.86:1 светлая при 12px */
  border:2px solid var(--bg);
  box-shadow:0 0 0 1px color-mix(in srgb, var(--danger) 45%, transparent),
             0 4px 12px -4px color-mix(in srgb, var(--danger) 70%, transparent);
}


/* ───────────────────────────────────────────────────────────────────────────
   5 · ИНСТРУМЕНТЫ КОЛОНКИ И КАРТОЧКИ
   .col-tool (свернуть / настроить) и .qadv (следующий статус, принять, вернуть)
   ─────────────────────────────────────────────────────────────────────────── */
/* было opacity:.55 на --tx-dim = ниже 3:1: кнопки читались как артефакт.
   Полная непрозрачность на --tx-mut даёт 7.5:1 и остаётся тихой за счёт размера */
.col-tool{
  width:26px;height:26px;padding:0;opacity:1;
  display:inline-grid;place-items:center;font-size:0;
  color:var(--tx-mut);border-radius:8px;background:none;border:1px solid transparent;
  transition:background var(--ct-mo) ease, color var(--ct-mo) ease,
             border-color var(--ct-mo) ease, transform 90ms var(--ct-ease);
}
.col-tool:hover{color:var(--tx);background:var(--ct-wash);border-color:color-mix(in srgb, var(--acc) 26%, transparent)}
.col-tool:active{transform:translateY(1px)}
.col-tool::before{content:'';width:15px;height:15px;background:currentColor;transition:transform var(--ct-mo) var(--ct-ease)}
/* «‹» и «⚙» текстом — разного веса в разных шрифтах; ставим векторные маски */
.col-tool[data-collapse]::before{
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 5l-7 7 7 7'/%3E%3C/svg%3E") center/15px 15px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 5l-7 7 7 7'/%3E%3C/svg%3E") center/15px 15px no-repeat;
}
.col-tool[data-collapse]:hover::before{transform:translateX(-2px)}   /* «уезжает» в сторону сворачивания */
.col-tool[data-coledit]::before{
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='3.4'/%3E%3Cpath d='M12 2.6v3M12 18.4v3M2.6 12h3M18.4 12h3M5.4 5.4l2.1 2.1M16.5 16.5l2.1 2.1M18.6 5.4l-2.1 2.1M7.5 16.5l-2.1 2.1'/%3E%3C/svg%3E") center/15px 15px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='3.4'/%3E%3Cpath d='M12 2.6v3M12 18.4v3M2.6 12h3M18.4 12h3M5.4 5.4l2.1 2.1M16.5 16.5l2.1 2.1M18.6 5.4l-2.1 2.1M7.5 16.5l-2.1 2.1'/%3E%3C/svg%3E") center/15px 15px no-repeat;
}
.col-tool[data-coledit]:hover::before{transform:rotate(60deg)}

/* перестановка колонок (только супер-админ). Инструментов в шапке и так трое,
   поэтому стрелки не занимают место постоянно: в покое их ширина 0, при
   наведении на шапку они выезжают. На тач-экранах наведения нет — там видны
   всегда. Ширина 0 требует и min-width:0 — иначе мобильное правило .col-tool
   держит 44px. */
.col-mv{width:0;min-width:0;border-width:0;opacity:0;overflow:hidden;
  transition:width var(--ct-mo) var(--ct-ease), opacity var(--ct-mo) ease,
             background var(--ct-mo) ease, color var(--ct-mo) ease}
.col-h:hover .col-mv,.col-mv:focus-visible{width:26px;border-width:1px;opacity:1}
.col-mv::before{width:14px;height:14px}
.col-mv[data-dir="-1"]::before{
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 12H4M10 6l-6 6 6 6'/%3E%3C/svg%3E") center/14px 14px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 12H4M10 6l-6 6 6 6'/%3E%3C/svg%3E") center/14px 14px no-repeat;
}
.col-mv[data-dir="1"]::before{
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h16M14 6l6 6-6 6'/%3E%3C/svg%3E") center/14px 14px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h16M14 6l6 6-6 6'/%3E%3C/svg%3E") center/14px 14px no-repeat;
}
.col-mv[data-dir="-1"]:hover::before{transform:translateX(-2px)}
.col-mv[data-dir="1"]:hover::before{transform:translateX(2px)}
@media(hover:none){
  .col-mv{width:44px;min-width:44px;border-width:1px;opacity:1}
}

/* быстрый перевод статуса прямо на карточке */
.card .qadv{
  /* без backdrop-filter: на доске бывает до 200+ карточек, и каждое «стекло»
     стоит отдельного слоя композитора. Здесь достаточно плотной заливки. */
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border:1px solid var(--line2);color:var(--tx-mut);
  border-radius:9px;box-shadow:var(--dp-e1), var(--dp-rim);
  transition:opacity var(--ct-mo) ease, transform var(--ct-mo) var(--ct-ease),
             background var(--ct-mo) ease, color var(--ct-mo) ease,
             border-color var(--ct-mo) ease, box-shadow var(--ct-mo) ease;
}
.card .qadv:hover{
  background:linear-gradient(180deg, var(--ct-fill-a), var(--ct-fill-b));
  border-color:color-mix(in srgb, var(--ct-fill-b) 70%, #000);
  color:var(--ct-on);                                  /* было #482114 — след оранжевой темы */
  box-shadow:var(--ct-halo), inset 0 1px 0 rgba(255,255,255,.3);
}
.card .qadv:active{transform:translateY(1px) scale(.96)}
.card .qadv.qc.ok:hover{
  background:linear-gradient(180deg, color-mix(in srgb, var(--ok) 88%, #FFF), var(--ok));
  border-color:color-mix(in srgb, var(--ok) 70%, #000);
  color:#0F4A29;                                       /* тёмный на мятном: 9.1:1 */
  box-shadow:0 10px 24px -12px color-mix(in srgb, var(--ok) 60%, transparent);
}


/* ───────────────────────────────────────────────────────────────────────────
   6 · КНОПКИ «ДОБАВИТЬ» · .addtask · .col-addcol · .doc-add
   Пунктир = приглашение. При наведении пунктир собирается в сплошную рамку,
   плюс доворачивается — жест «здесь появится новое».
   ─────────────────────────────────────────────────────────────────────────── */
.addtask,.col-addcol{
  border:1px dashed var(--line2);background:none;color:var(--tx-mut);  /* было --tx-dim: 4.3:1 */
  transition:color var(--ct-mo) ease, border-color var(--ct-mo) ease,
             background var(--ct-mo) ease, box-shadow var(--ct-mo) ease,
             transform 90ms var(--ct-ease);
}
/* цвет задаём отдельно, чтобы фиолетовая «wish»-колонка сохранила свой тон */
.addtask:hover,.addtask:focus-visible,
.col-addcol:hover,.col-addcol:focus-visible{color:var(--acc-d)}
.addtask.wish:hover,.addtask.wish:focus-visible{color:#A2A2A2}
.addtask:hover,.addtask:focus-visible,
.col-addcol:hover,.col-addcol:focus-visible{
  border-style:solid;border-color:currentColor;
  background:color-mix(in srgb, currentColor 12%, transparent);
  box-shadow:0 8px 22px -14px currentColor;
}
.addtask:active,.col-addcol:active{transform:translateY(1px);box-shadow:var(--ct-press)}
.addtask .pl-ic svg,.col-addcol .pl-ic svg{transition:transform var(--ct-mo) var(--ct-ease)}
.addtask:hover .pl-ic svg,.col-addcol:hover .pl-ic svg{transform:rotate(90deg)}

.doc-add{
  border:1px solid var(--line2);
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  color:var(--acc-d);box-shadow:var(--dp-e1), var(--dp-rim);
  transition:border-color var(--ct-mo) ease, background var(--ct-mo) ease,
             box-shadow var(--ct-mo) ease, transform 90ms var(--ct-ease);
}
.doc-add:hover{
  border-color:color-mix(in srgb, var(--acc) 55%, var(--line2));
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--acc) 14%, var(--ct-face-a)),
    color-mix(in srgb, var(--acc) 8%,  var(--ct-face-b)));
  box-shadow:var(--dp-e2), var(--dp-rim-s), 0 0 18px -10px var(--glow);
}
.doc-add:active{transform:translateY(1px);box-shadow:var(--ct-press)}


/* ───────────────────────────────────────────────────────────────────────────
   7 · СЕГМЕНТНЫЕ ПЕРЕКЛЮЧАТЕЛИ · .seg / .schip
   ─────────────────────────────────────────────────────────────────────────── */
.seg button,.schip{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border:1px solid var(--line2);color:var(--tx-mut);
  border-radius:9px;box-shadow:var(--dp-e1);
  transition:background var(--ct-mo) ease, color var(--ct-mo) ease,
             border-color var(--ct-mo) ease, box-shadow var(--ct-mo) ease,
             transform 90ms var(--ct-ease);
}
.seg button:hover,.schip:hover{
  color:var(--tx);border-color:var(--edge);
  background:linear-gradient(180deg, var(--ct-face-h-a), var(--ct-face-h-b));
}
.seg button:active,.schip:active{transform:translateY(1px);box-shadow:var(--ct-press)}
.seg button.on,.schip.on{
  background:linear-gradient(180deg, var(--ct-fill-a), var(--ct-fill-b));
  border-color:color-mix(in srgb, var(--ct-fill-b) 70%, #000);
  color:var(--ct-on);                       /* было #313131 — тёмно-коричневый из старой темы */
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), var(--ct-halo);
}
.seg button.on:hover,.schip.on:hover{
  background:linear-gradient(180deg, var(--ct-fill-h-a), var(--ct-fill-h-b));
  color:var(--ct-on);
}
/* цветные точки типов задач. В app.js это .tdot.t-<ключ>, а окраска в базе
   объявлена только для .typedot.* — точки были прозрачными, то есть невидимыми */
.seg .tdot{box-shadow:0 0 0 1px rgba(36,36,36,.25)}
.seg .tdot.t-task{background:var(--t-task)}
.seg .tdot.t-feature{background:var(--t-feature)}
.seg .tdot.t-bug{background:var(--t-bug)}
.seg .tdot.t-design{background:var(--t-design)}
.seg .tdot.t-content{background:var(--t-content)}
.seg .tdot.t-deploy{background:var(--t-deploy)}
/* на залитой кнопке точка обводится светлым, иначе тонет в индиго */
.seg button.on .tdot{box-shadow:0 0 0 2px rgba(255,255,255,.75)}


/* ───────────────────────────────────────────────────────────────────────────
   8 · ВКЛАДКИ ПРОЕКТА · .ptabs / .ptab
   Активная вкладка физически срастается с панелью под собой: светлая кромка
   сверху, и никакого шва снизу.
   ─────────────────────────────────────────────────────────────────────────── */
.ptab{
  color:var(--tx-mut);border-radius:11px 11px 0 0;
  transition:background var(--ct-mo) ease, color var(--ct-mo) ease,
             box-shadow var(--ct-mo) ease, transform 90ms var(--ct-ease);
}
.ptab:hover{color:var(--tx);background:var(--ct-wash)}
.ptab:active{transform:translateY(1px)}
.ptab svg{transition:transform var(--ct-mo) var(--ct-ease), color var(--ct-mo) ease}
.ptab:hover svg{transform:translateY(-1px)}
.ptab.on{
  background:linear-gradient(180deg, var(--ct-lid-a), var(--panel));
  border-color:var(--line);color:var(--tx);
  /* верхняя индиговая кромка + подсветка «изнутри» вкладки */
  box-shadow:inset 0 2px 0 var(--acc), 0 -10px 26px -18px var(--glow);
}
.ptab.on svg{color:var(--acc-d)}
.ptab.on:hover{background:linear-gradient(180deg, var(--ct-lid-a), var(--panel))}
/* сервисные вкладки — тише основных, но с тем же поведением */
.ptab.exp:hover,.ptab.set:hover{color:var(--acc-d);background:var(--ct-wash)}


/* ───────────────────────────────────────────────────────────────────────────
   9 · ЧИПЫ ДОСОК · .bbar / .bchip
   ─────────────────────────────────────────────────────────────────────────── */
.bchip{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border:1px solid var(--line);color:var(--tx-mut);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:background var(--ct-mo) ease, color var(--ct-mo) ease,
             border-color var(--ct-mo) ease, box-shadow var(--ct-mo) ease,
             transform 90ms var(--ct-ease);
}
.bchip:hover{
  color:var(--tx);border-color:var(--line2);
  background:linear-gradient(180deg, var(--ct-face-h-a), var(--ct-face-h-b));
  box-shadow:var(--dp-e2), var(--dp-rim-s);
}
.bchip:active{transform:translateY(1px);box-shadow:var(--ct-press)}
.bchip.on{
  color:var(--tx);
  border-color:color-mix(in srgb, var(--acc) 60%, var(--line2));
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--acc) 16%, var(--ct-face-a)),
    color-mix(in srgb, var(--acc) 8%,  var(--ct-face-b)));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 0 22px -12px var(--glow), var(--dp-e1);
}
/* счётчик задач на активной доске подсвечивается — сразу видно, где ты */
.bchip i{background:var(--card2);color:var(--tx-mut);transition:background var(--ct-mo) ease, color var(--ct-mo) ease}
.bchip.on i{background:color-mix(in srgb, var(--acc) 26%, transparent);color:var(--tx)}
/* «⚙» переименования — тоже вектор вместо глифа */
.bchip .bedit{
  width:20px;height:20px;padding:0;opacity:.75;font-size:0;
  display:inline-grid;place-items:center;border-radius:6px;
  transition:opacity var(--ct-mo) ease, background var(--ct-mo) ease, transform var(--ct-mo) var(--ct-ease);
}
.bchip .bedit::before{
  content:'';width:13px;height:13px;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='3.4'/%3E%3Cpath d='M12 2.6v3M12 18.4v3M2.6 12h3M18.4 12h3M5.4 5.4l2.1 2.1M16.5 16.5l2.1 2.1M18.6 5.4l-2.1 2.1M7.5 16.5l-2.1 2.1'/%3E%3C/svg%3E") center/13px 13px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='3.4'/%3E%3Cpath d='M12 2.6v3M12 18.4v3M2.6 12h3M18.4 12h3M5.4 5.4l2.1 2.1M16.5 16.5l2.1 2.1M18.6 5.4l-2.1 2.1M7.5 16.5l-2.1 2.1'/%3E%3C/svg%3E") center/13px 13px no-repeat;
}
.bchip .bedit:hover{opacity:1;background:var(--ct-wash-s);transform:rotate(60deg)}
.bchip.add{border-style:dashed;color:var(--tx-mut);background:none;box-shadow:none}
.bchip.add:hover{
  color:var(--acc-d);border-style:solid;border-color:currentColor;
  background:color-mix(in srgb, var(--acc) 10%, transparent);box-shadow:none;
}


/* ───────────────────────────────────────────────────────────────────────────
   10 · МЕНЮ ПОЛЬЗОВАТЕЛЯ · .umenu / .ubtn / .uav / .uchev / .udrop
   ─────────────────────────────────────────────────────────────────────────── */
.ubtn{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border:1px solid var(--line2);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:background var(--ct-mo) ease, border-color var(--ct-mo) ease,
             box-shadow var(--ct-mo) ease, transform 90ms var(--ct-ease);
}
.ubtn:hover{
  border-color:color-mix(in srgb, var(--acc) 45%, var(--line2));
  background:linear-gradient(180deg, var(--ct-face-h-a), var(--ct-face-h-b));
  box-shadow:var(--dp-e2), var(--dp-rim-s), 0 0 18px -10px var(--glow);
}
.ubtn:active{transform:translateY(1px);box-shadow:var(--ct-press)}
/* открытое меню подсвечивает свою кнопку — связь «кнопка ↔ панель» */
.ubtn[aria-expanded="true"]{
  border-color:var(--acc);
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--acc) 18%, var(--ct-face-a)),
    color-mix(in srgb, var(--acc) 9%,  var(--ct-face-b)));
  box-shadow:0 0 0 3px var(--ct-ring);
}
.uav{
  background:linear-gradient(150deg, var(--ct-fill-h-a), var(--ct-fill-b));
  color:var(--ct-on);                    /* было #4A150C — 4.3:1 и чужой оттенок */
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35), 0 3px 10px -5px var(--glow);
}
/* «▾» текстом кривится в системных шрифтах — ставим вектор и вращаем при открытии */
.uchev{
  width:11px;height:11px;font-size:0;flex:none;
  background:currentColor;color:var(--tx-mut);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E") center/11px 11px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E") center/11px 11px no-repeat;
  transition:transform var(--ct-mo) var(--ct-ease), color var(--ct-mo) ease;
}
.ubtn:hover .uchev{color:var(--tx)}
.ubtn[aria-expanded="true"] .uchev{transform:rotate(180deg);color:var(--acc-d)}

@keyframes ctDropIn{from{opacity:0;transform:translateY(-8px) scale(.97)}to{opacity:1;transform:none}}
.udrop{
  background:linear-gradient(180deg, var(--ct-lid-a), var(--ct-lid-b));
  border:1px solid var(--line2);border-radius:8px;
  box-shadow:var(--dp-e3), var(--dp-rim-s);
  transform-origin:top right;
  animation:ctDropIn .16s var(--ct-ease);
  /* overflow здесь НЕ ставим: он обрезал бы «носик» ::before.
     В меню три пункта и шапка — прокрутка ему не нужна ни на одном экране. */
}
/* «носик» к кнопке: повёрнутый квадрат в цвет верхней кромки панели */
.udrop::before{
  content:'';position:absolute;top:-6px;right:15px;width:11px;height:11px;
  background:var(--ct-lid-a);
  border-left:1px solid var(--line2);border-top:1px solid var(--line2);
  transform:rotate(45deg);border-radius:3px 0 0 0;
}
.udrop .who{border-bottom:1px solid var(--line)}
.udrop .navitem{
  min-height:44px;border-radius:10px;color:var(--tx-mut);
  transition:background var(--ct-mo) ease, color var(--ct-mo) ease, transform 90ms var(--ct-ease);
}
.udrop .navitem:hover{background:var(--ct-wash);color:var(--tx)}
.udrop .navitem:active{transform:translateY(1px);background:var(--ct-wash-s)}
.udrop .navitem .ni-ic{color:var(--tx-dim);transition:color var(--ct-mo) ease}
.udrop .navitem:hover .ni-ic{color:var(--acc-d)}
/* «Выйти» — единственный необратимый пункт, окрашиваем только при наведении */
.udrop .navitem[data-logout]:hover{background:color-mix(in srgb, var(--danger) 13%, transparent);color:var(--danger)}
.udrop .navitem[data-logout]:hover .ni-ic{color:var(--danger)}


/* ───────────────────────────────────────────────────────────────────────────
   11 · МОДАЛЬНЫЕ ОКНА · .ov / .modal / .mhead / .confirm-modal
   ─────────────────────────────────────────────────────────────────────────── */
@keyframes ctOvIn{from{opacity:0}to{opacity:1}}
@keyframes ctModalIn{from{opacity:0;transform:translateY(16px) scale(.985)}to{opacity:1;transform:none}}

/* затемнение: не плоская чернота, а «вуаль» оформления + размытие фона */
.ov{
  background:var(--dp-veil);
  -webkit-backdrop-filter:blur(12px) saturate(.85);
          backdrop-filter:blur(12px) saturate(.85);
  animation:ctOvIn .18s ease-out;
}
/* подтверждение приходит ПОВЕРХ уже открытой модалки — второй слой затемнения
   держим лёгким, иначе карточка задачи под ним превращается в кашу */
.confirm-ov{
  background:rgba(40,40,40,.5);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
}
[data-theme="light"] .confirm-ov{background:rgba(56,56,56,.34)}

.modal{
  /* база задавала модалке жёсткий тёмный градиент — в светлой теме окно
     оставалось чёрным. Переводим на токены: работает в обеих темах */
  background:linear-gradient(180deg, var(--ct-lid-a), var(--ct-lid-b));
  border:1px solid var(--line2);border-radius:8px;
  box-shadow:var(--dp-e4), var(--dp-rim-s);
  animation:ctModalIn .24s var(--ct-ease) both;
}
/* тени прокрутки внутри окна: видно, что контент продолжается за краем.
   Слои local закрывают слои scroll, пока прокрутка в крайнем положении.
   .qjmodal исключён: у него overflow:hidden и своя внутренняя прокрутка */
.modal:not(.qjmodal){
  background:
    linear-gradient(var(--ct-lid-a) 34%, transparent) top/100% 22px no-repeat local,
    linear-gradient(transparent, var(--ct-lid-b) 66%) bottom/100% 22px no-repeat local,
    radial-gradient(farthest-side at 50% 0, var(--dp-scr), transparent) top/100% 12px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%, var(--dp-scr), transparent) bottom/100% 12px no-repeat scroll,
    linear-gradient(180deg, var(--ct-lid-a), var(--ct-lid-b));
}
/* шапка окна отделяется волоском — заголовок перестаёт «липнуть» к телу */
.mhead{
  padding-bottom:14px;
  border-bottom:1px solid color-mix(in srgb, var(--line) 85%, transparent);
}
.mhead .iconbtn{flex:none}

/* подтверждение удаления */
.confirm-modal{
  animation:ctModalIn .2s var(--ct-ease) both;
  border-color:color-mix(in srgb, var(--danger) 22%, var(--line2));
}
/* иконка получает гало — взгляд идёт «иконка → вопрос → кнопки» */
.confirm-modal .cf-ic.danger{
  box-shadow:0 0 0 6px color-mix(in srgb, var(--danger) 9%, transparent),
             0 14px 34px -18px color-mix(in srgb, var(--danger) 60%, transparent);
}
.confirm-modal .cf-ic:not(.danger){
  box-shadow:0 0 0 6px var(--ct-wash), 0 14px 34px -18px var(--glow);
}
.cf-actions .btn{min-height:44px}

/* быстрый переход Cmd+K — тот же язык меню, что и у .udrop */
.qj-i{transition:background var(--ct-mo) ease, transform 90ms var(--ct-ease)}
.qj-i.on,.qj-i:hover{background:var(--ct-wash)}
.qj-i:active{transform:translateY(1px);background:var(--ct-wash-s)}


/* ───────────────────────────────────────────────────────────────────────────
   12 · ТОСТЫ · .toast
   Появление снизу вверх, стекло, слева — статусная иконка вектором.
   ─────────────────────────────────────────────────────────────────────────── */
@keyframes ctToastIn{
  from{opacity:0;transform:translateX(-50%) translateY(14px) scale(.96)}
  to  {opacity:1;transform:translateX(-50%)}
}
.toast{
  display:flex;align-items:center;gap:10px;
  padding:12px 17px 12px 15px;border-radius:13px;
  max-width:min(560px, calc(100vw - 28px));
  background:var(--ct-glass);
  -webkit-backdrop-filter:blur(16px) saturate(1.3);
          backdrop-filter:blur(16px) saturate(1.3);
  border:1px solid var(--line2);color:var(--tx);
  box-shadow:var(--dp-e3), var(--dp-rim-s);
  animation:ctToastIn .26s var(--ct-ease);
}
.toast::before{
  content:'';flex:none;width:18px;height:18px;background:var(--ok);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.6l5 5 10-11'/%3E%3C/svg%3E") center/18px 18px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.6l5 5 10-11'/%3E%3C/svg%3E") center/18px 18px no-repeat;
}
.toast.err{
  border-color:color-mix(in srgb, var(--danger) 55%, var(--line2));  /* было #D03E2F из прежней темы */
  box-shadow:var(--dp-e3), var(--dp-rim-s), 0 0 26px -14px color-mix(in srgb, var(--danger) 70%, transparent);
}
.toast.err::before{
  background:var(--danger);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.4v5.6M12 16.6h.01'/%3E%3C/svg%3E") center/18px 18px no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.4v5.6M12 16.6h.01'/%3E%3C/svg%3E") center/18px 18px no-repeat;
}


/* ───────────────────────────────────────────────────────────────────────────
   13 · ВСПЛЫВАЮЩАЯ ПОДСКАЗКА · .charttip
   Единственная нестандартная подсказка проекта (wireTips в app.js).
   transform ей ставит JS инлайном — здесь его не трогаем, анимируем прозрачность.
   Стрелку не рисуем: подсказка переворачивается у верхней кромки экрана,
   и стрелка в половине случаев смотрела бы в пустоту.
   ─────────────────────────────────────────────────────────────────────────── */
.charttip{
  background:var(--ct-glass);
  -webkit-backdrop-filter:blur(14px) saturate(1.25);
          backdrop-filter:blur(14px) saturate(1.25);
  border:1px solid var(--line2);border-radius:11px;
  padding:8px 12px;color:var(--tx);
  box-shadow:var(--dp-e3), var(--dp-rim-s);
  transition:opacity .14s ease;
}
.charttip b{color:var(--acc-d);font-variant-numeric:tabular-nums}


/* ───────────────────────────────────────────────────────────────────────────
   14 · СКРОЛЛБАРЫ
   Тонкие, в тон индиго, с воздухом вокруг ползунка (прозрачная рамка +
   background-clip:padding-box) — чтобы не резать скруглённые углы панелей.
   Перечислены только реальные контейнеры прокрутки, найденные в app.css/app.js.
   .ptabs сознательно НЕ трогаем: там на ≤560px полоса намеренно скрыта.
   ─────────────────────────────────────────────────────────────────────────── */
.col-body,.cmts,.side-projects,.modal,.qj-list,.tblwrap,.heatwrap{
  scrollbar-width:thin;
  scrollbar-color:var(--ct-bar) transparent;
}
.col-body::-webkit-scrollbar,
.cmts::-webkit-scrollbar,
.side-projects::-webkit-scrollbar,
.modal::-webkit-scrollbar,
.qj-list::-webkit-scrollbar,
.tblwrap::-webkit-scrollbar,
.heatwrap::-webkit-scrollbar{width:11px;height:11px;background:transparent}

.col-body::-webkit-scrollbar-thumb,
.cmts::-webkit-scrollbar-thumb,
.side-projects::-webkit-scrollbar-thumb,
.modal::-webkit-scrollbar-thumb,
.qj-list::-webkit-scrollbar-thumb,
.tblwrap::-webkit-scrollbar-thumb,
.heatwrap::-webkit-scrollbar-thumb{
  background:var(--ct-bar);
  border:3px solid transparent;background-clip:padding-box;
  border-radius:99px;min-height:36px;
  transition:background-color var(--ct-mo) ease;
}
.col-body::-webkit-scrollbar-thumb:hover,
.cmts::-webkit-scrollbar-thumb:hover,
.side-projects::-webkit-scrollbar-thumb:hover,
.modal::-webkit-scrollbar-thumb:hover,
.qj-list::-webkit-scrollbar-thumb:hover,
.tblwrap::-webkit-scrollbar-thumb:hover,
.heatwrap::-webkit-scrollbar-thumb:hover{background:var(--ct-bar-hover)}

.col-body::-webkit-scrollbar-track,
.cmts::-webkit-scrollbar-track,
.side-projects::-webkit-scrollbar-track,
.modal::-webkit-scrollbar-track,
.qj-list::-webkit-scrollbar-track,
.tblwrap::-webkit-scrollbar-track,
.heatwrap::-webkit-scrollbar-track{background:transparent}
.modal::-webkit-scrollbar-corner,.tblwrap::-webkit-scrollbar-corner{background:transparent}

/* Горизонтальная полоса доски остаётся ТОЛСТОЙ и всегда видимой — так решено
   в базе (на macOS тонкая прячется, и кажется, что колонки не влезают).
   Меняем только материал: индиговый ползунок с широким полем вокруг. */
.board-wrap{scrollbar-width:auto;scrollbar-color:var(--ct-bar-hover) transparent}
.board-wrap::-webkit-scrollbar{height:13px;background:transparent}
.board-wrap::-webkit-scrollbar-thumb{
  background:var(--ct-bar-hover);
  border:4px solid transparent;background-clip:padding-box;
  border-radius:99px;min-width:80px;
  transition:background-color var(--ct-mo) ease;
}
.board-wrap::-webkit-scrollbar-thumb:hover{background:var(--acc-d)}
.board-wrap::-webkit-scrollbar-track{background:transparent}


/* ───────────────────────────────────────────────────────────────────────────
   15 · ТЕЛЕФОН · тап-зоны ≥44×44 и раскладка на 390px
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:760px){
  /* повторяем селекторы базы: правила из её медиазапросов идут выше по файлу */
  .iconbtn,.ubtn{min-width:44px;min-height:44px}
  .col-tool{width:44px;height:44px;min-width:44px;min-height:44px;border-radius:11px}
  .card .qadv{width:44px;height:44px;top:4px;right:4px;opacity:1;transform:none}
  /* сегменты в базе 32px — для пальца мало */
  .seg button,.schip{min-height:44px;padding:10px 14px}
  /* «⚙» внутри чипа доски: растягиваем зону нажатия на всю высоту чипа */
  .bchip .bedit{width:44px;height:44px;margin:-9px -13px -9px 0;opacity:1;border-radius:0 10px 10px 0}
  .doc-add{min-height:44px}

  /* Меню пользователя. В базе на телефоне оно было position:fixed «шторкой» у
     нижнего края — но .topbar получил backdrop-filter, а это делает шапку
     containing block для fixed-потомков, и шторку выбрасывало под шапку.
     Держим меню абсолютным относительно .umenu — работает независимо от шапки. */
  .udrop{
    position:absolute;top:calc(100% + 10px);right:0;left:auto;bottom:auto;
    width:min(320px, calc(100vw - 24px));min-width:0;
  }
  .udrop::before{right:13px}
  /* тяжёлое стекло на телефоне стоит дорого — размытие подложки уменьшаем */
  .ov{-webkit-backdrop-filter:blur(8px) saturate(.9);backdrop-filter:blur(8px) saturate(.9)}
}
@media(max-width:640px){
  /* база даёт окну 14px на узких экранах; держим тот же порядок скругления */
  .modal{border-radius:15px}
}
@media(max-width:480px){
  /* тост на узком экране прижимаем к полям: центрирование через translateX
     на 390px обрезало бы длинные сообщения */
  .toast{left:12px;right:12px;transform:none;max-width:none;animation-name:ctToastInNarrow}
  @keyframes ctToastInNarrow{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
  .cf-actions .btn{min-width:0}
}
@media(max-width:400px){
  .ubtn{padding:0 8px 0 6px}
  .udrop{width:calc(100vw - 20px)}
  /* шапка окна: заголовок и «✕» не должны толкаться */
  .mhead{gap:8px;padding-bottom:12px}
  .ptab{border-radius:10px 10px 0 0}
}


/* ───────────────────────────────────────────────────────────────────────────
   16 · «МЕНЬШЕ ДВИЖЕНИЯ»
   Гасим всё: появления окон, смещения нажатия, повороты иконок.
   Держать последним блоком файла.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .ov,.modal,.modal:not(.qjmodal),.confirm-modal,.udrop,.toast{animation:none!important}

  .btn,.btn .pl-ic svg,.iconbtn,.iconbtn svg,.iconbtn[data-close]::before,
  .col-tool,.col-tool::before,.card .qadv,.addtask,.col-addcol,
  .addtask .pl-ic svg,.col-addcol .pl-ic svg,.doc-add,
  .seg button,.schip,.ptab,.ptab svg,.bchip,.bchip i,.bchip .bedit,
  .ubtn,.uchev,.udrop .navitem,.udrop .navitem .ni-ic,.qj-i,.charttip{transition:none}
  /* Псевдоэлементы WebKit — ОТДЕЛЬНЫМ правилом. В одном списке с обычными
     селекторами неизвестный псевдоэлемент отменяет весь список целиком,
     и вне WebKit (Firefox) «меньше движения» переставало работать
     для всех перечисленных выше элементов. */
  .col-body::-webkit-scrollbar-thumb,
  .board-wrap::-webkit-scrollbar-thumb{transition:none}

  .btn:active:not(:disabled),.btn-ghost:active:not(:disabled),
  .iconbtn:active,.btn-ghost.iconbtn:active,.col-tool:active,.card .qadv:active,
  .addtask:active,.col-addcol:active,.doc-add:active,
  .seg button:active,.schip:active,.ptab:active,.bchip:active,
  .ubtn:active,.udrop .navitem:active,.qj-i:active{transform:none}

  .btn:hover .pl-ic svg,.iconbtn:hover svg,#theme:hover svg,.ptab:hover svg,
  .iconbtn[data-close]:hover::before,.col-tool[data-collapse]:hover::before,
  .col-tool[data-coledit]:hover::before,.bchip .bedit:hover,
  .addtask:hover .pl-ic svg,.col-addcol:hover .pl-ic svg,
  .ubtn[aria-expanded="true"] .uchev{transform:none}

  /* вращающийся индикатор заменяем статичным многоточием: движения нет,
     но «идёт сохранение» по-прежнему читается (плюс cursor:progress) */
  .btn:disabled::after{
    content:'…';border:0;background:none;width:auto;height:auto;
    color:var(--tx);font-size:19px;line-height:1;animation:none;
  }
  .btn-primary:disabled::after,.btn-danger-solid:disabled::after{color:var(--ct-on)}
}

/* ▲▲▲ конец: КНОПКИ, МЕНЮ, ВКЛАДКИ, МОДАЛКИ, СКРОЛЛБАРЫ ▲▲▲ */

/* ▼▼▼ ПРОРАБОТКА: ДАННЫЕ: ТАБЛИЦЫ, КОММЕНТАРИИ, ВЛОЖЕНИЯ, KPI ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   ПОЛНОЧЬ · СЕМЕЙСТВО «ДАННЫЕ»
   Таблицы · счета · часы · библиотека документов · комментарии · вложения ·
   KPI-плитки · графики · пустые состояния · индикатор загрузки.

   Зачем этот слой. Крупная форма «Полночи» уже собрана: цвет, глубина,
   свечение. Здесь — то, что решает читаемость плотных данных и чего в
   цветовом слое нет: ритм отступов, волосяные разделители, иерархия кегля,
   дисциплина чисел (моно + tabular-nums), иконки вместо текстовых глифов,
   честные пустые состояния, тап-зоны и контраст мелкого кегля.

   ПРИНЦИПЫ
   1. Числа — главный герой: моноширинный, tabular-nums, вес на ступень выше
      подписи. Разряды в колонке обязаны совпадать по вертикали.
   2. Плотность держат волосок в 1px и отступы, а не рамки и заливки.
   3. Только токены палитры. Свои значения выводятся через color-mix ОТ токенов,
      поэтому правила остаются верными и в тёмной, и в светлой теме.
   4. Ни одного выдуманного класса: каждый селектор сверен по app.js.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   0 · ТОКЕНЫ СЕМЕЙСТВА
   Выводятся из палитры смешиванием с --tx. Смысл: --tx всегда «самый
   контрастный текст темы», поэтому подмешивание к нему в тёмной теме
   осветляет, а в светлой — затемняет, и контраст растёт В ЛЮБОЙ теме сам.
   Один расчёт держит норму без ветвлений на [data-theme].
   ─────────────────────────────────────────────────────────────────────────── */
:root{
  /* Подпись-капслок 10–11px. Норма для такого кегля 7:1, а базовый --tx-dim
     даёт ~4:1 на карточке. Смесь --tx-mut с --tx даёт ≥9.6:1 в тёмной теме
     и ≥8.5:1 в светлой на всех поверхностях кабинета. */
  --d-cap: color-mix(in srgb, var(--tx-mut) 55%, var(--tx));
  /* Мета 12–13px: норма 4.5:1, --tx-mut даёт ≥6.9:1 — берём как есть. */
  --d-sec: var(--tx-mut);

  /* Смысловые цвета ДЛЯ ТЕКСТА. Чистые --ok/--warn/--danger рассчитаны на
     заливки и точки; как текст на светлой теме они проваливаются (3.2–4.4:1).
     Подмешивание --tx поднимает их до нормы, не меняя оттенка. */
     Доли подобраны по худшей поверхности каждой темы: зелёному нужно больше
     подмешивания (на светлом фоне он самый слабый), коралл проходит раньше. */
  --d-ok:     color-mix(in srgb, var(--ok) 64%, var(--tx));
  --d-danger: color-mix(in srgb, var(--danger) 78%, var(--tx));

  /* Материалы плотных списков */
  --d-hair: color-mix(in srgb, var(--line) 78%, transparent);  /* волосок-разделитель */
  --d-well: color-mix(in srgb, var(--bg) 62%, var(--card));    /* утопленная клетка: трек, миниатюра */
  --d-hov:  color-mix(in srgb, var(--acc) 9%, transparent);    /* наведение на строку */
  --d-wash: color-mix(in srgb, var(--acc) 13%, transparent);   /* лёгкая акцентная подложка */
  --d-t: .14s cubic-bezier(.22,.72,.28,1);

  /* Иконки — только inline-SVG в data:URI, красятся currentColor через маску.
     Внешних файлов и иконочных шрифтов нет. */
  --d-i-pencil:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h4L19.4 8.6a2.1 2.1 0 0 0-3-3L5 17v3z'/%3E%3Cpath d='M14.6 6.4l3 3'/%3E%3C/svg%3E");
  --d-i-trash:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7h16M10 11v6M14 11v6M6.5 7l.9 12.1A2 2 0 0 0 9.4 21h5.2a2 2 0 0 0 2-1.9L17.5 7M9.5 7V4.6a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1V7'/%3E%3C/svg%3E");
  --d-i-x:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='M6.5 6.5l11 11M17.5 6.5l-11 11'/%3E%3C/svg%3E");
  --d-i-trend:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 16.5l6-6 4 4 6-7'/%3E%3Cpath d='M15 7.5h5v5'/%3E%3C/svg%3E");
  --d-i-alert:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 9.4v4.2M12 17.3h.01'/%3E%3Cpath d='M10.3 4 2.6 17.8a2 2 0 0 0 1.7 3h15.4a2 2 0 0 0 1.7-3L13.7 4a2 2 0 0 0-3.4 0z'/%3E%3C/svg%3E");
  --d-i-inbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 12h-6l-2 3h-4l-2-3H2'/%3E%3Cpath d='M5.5 5.5 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.5-6.5A2 2 0 0 0 16.8 4H7.2a2 2 0 0 0-1.7 1.5z'/%3E%3C/svg%3E");
}


/* ───────────────────────────────────────────────────────────────────────────
   1 · ДИСЦИПЛИНА ЧИСЕЛ
   Разряды обязаны совпадать по вертикали, иначе колонка сумм читается как
   случайный набор. tabular-nums уравнивает ширину цифр, моноширинный
   добавляет к этому одинаковый шаг знаков и разделителей тысяч.
   ─────────────────────────────────────────────────────────────────────────── */
.tbl th,.tbl td,
.inv-num,.inv-sum,.inv-kpi b,.inv-kpi em,.inv-meta,
.hr-k,.hr-d,.hb-val,.hb-sub b,.hb-l b,
.kpic b,.mtile b,.lg b,.an-cell b,.bu-ot,
.doc-dl em,.cmt-file em,.cmt-img-n em,.docpick-name em,.cef-cur,
.cmt-meta span,.mi2,.fdt,.daybadge,.badge-n,.dc-s,.charttip{
  font-variant-numeric:tabular-nums;
}
/* Витринные числа — моноширинным. Цифра получает свой шаг и перестаёт
   «дышать» при перерисовке (счётчики .mtile b анимируются в app.js). */
.kpic b,.inv-kpi b,.inv-sum,.hb-val,.hr-k,.dc-total,.miniring .mrt{
  font-family:var(--mono);
  letter-spacing:-.02em;                 /* моно шире sans — компенсируем трекингом */
}


/* ───────────────────────────────────────────────────────────────────────────
   2 · ТАБЛИЦЫ · .tblwrap / .tbl (раздел «Клиенты»)
   Зебры нет намеренно: при наведении на строку и волоске в 1px зебра даёт
   третий уровень шума и мешает вести глаз по строке. Ритм держат разделители.
   ─────────────────────────────────────────────────────────────────────────── */
.tblwrap{border-radius:14px}

/* Шапка — «крышка» таблицы: капслок, разрядка, кант снизу плотнее строк */
.tblwrap .tbl th{
  color:var(--d-cap);                    /* базовый --tx-dim на 11px давал ~4:1 — мало */
  font-weight:600;
  border-bottom:1px solid var(--line2);
  white-space:nowrap;
  vertical-align:middle;
}
.tblwrap .tbl td{
  border-bottom:1px solid var(--d-hair);
  vertical-align:middle;
}
.tblwrap .tbl tbody tr:last-child td{border-bottom:0}   /* последний волосок лишний — есть кант обёртки */
.tblwrap .tbl tbody tr:hover td{background:var(--d-hov)}
/* Наведённая строка получает акцентный корешок слева: взгляд цепляется за
   начало строки, а не за подсветку целиком. */
.tblwrap .tbl tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--acc)}
.tblwrap .tbl td:first-child b{font-weight:600}

/* Числовая колонка «Проектов» — по правому краю.
   Привязка к 3-й колонке, а не к классу: в app.js (renderClients) разметка
   ровно одна — Имя · Почта · Проектов · Создан · действия, и класса у
   счётчика нет. Поменяется состав колонок — править этот блок вместе с ним. */
.tblwrap .tbl th:nth-child(3),
.tblwrap .tbl td:nth-child(3){text-align:right}
.tblwrap .tbl td:nth-child(3){font-family:var(--mono);color:var(--tx)}
/* Дата: приглушена, но не ниже нормы. !important перебивает инлайновый
   color:var(--tx-dim) из app.js, который давал ~4:1. */
.tblwrap .tbl td.mono{color:var(--d-sec)!important}

.tblwrap .tbl td.tar{white-space:nowrap}
.rowact,.rowdel{transition:border-color var(--d-t),color var(--d-t),background var(--d-t)}

/* Пустая таблица — не дыра в вёрстке, а подпись с иконкой по центру ячейки */
.tbl td.empty{padding:34px 16px;color:var(--d-sec);border-bottom:0}
.tbl td.empty::before{
  content:'';display:block;width:26px;height:26px;margin:0 auto 10px;
  background:currentColor;opacity:.55;
  -webkit-mask:var(--d-i-inbox) center/contain no-repeat;
          mask:var(--d-i-inbox) center/contain no-repeat;
}


/* ───────────────────────────────────────────────────────────────────────────
   3 · СЧЕТА · .inv-kpi / .inv / .inv-badge
   ─────────────────────────────────────────────────────────────────────────── */
.inv-kpi{position:relative;overflow:hidden;padding:14px 18px 15px}
.inv-kpi .l{color:var(--d-cap)}                       /* 11px капслок → нужно 7:1 */
.inv-kpi b{margin-top:6px;line-height:1.15}
.inv-kpi em{display:block;margin-top:5px}
/* Тонкая акцентная нить по верхней кромке: плитка читается как «сводка чисел»,
   а не как обычный блок текста. */
.inv-kpi::before{
  content:'';position:absolute;left:0;right:0;top:0;height:2px;pointer-events:none;
  background:linear-gradient(90deg,var(--acc),color-mix(in srgb,var(--ok) 70%,var(--acc)) 70%,transparent);
  opacity:.7;
}

/* Номер счёта — техническая метка, поэтому чип, а не просто серый текст */
.inv-num{
  display:inline-block;padding:2px 8px;border-radius:7px;
  background:var(--d-well);border:1px solid var(--d-hair);
  font-family:var(--mono);
}
/* Статус. Цвет приходит инлайном в --c, поэтому правим не сам цвет, а его
   читаемость: подмешиваем --tx (в тёмной теме осветляет, в светлой темнит).
   На штатной подложке в 15% того же цвета получаем ≥4.5:1 для всех четырёх
   статусов (черновик · выставлен · оплачен · отменён) в обеих темах. */
.inv-badge{
  display:inline-flex;align-items:center;gap:6px;
  color:color-mix(in srgb, var(--c) 66%, var(--tx));
  font-weight:700;padding:3px 10px;
}
.inv-badge::before{
  content:'';width:6px;height:6px;border-radius:50%;flex:none;
  background:var(--c);box-shadow:0 0 7px -1px var(--c);
}
.inv-ttl{margin-top:8px;line-height:1.3}
.inv-meta{margin-top:5px;line-height:1.45}
.inv-sum{line-height:1.15}


/* ───────────────────────────────────────────────────────────────────────────
   4 · ЧАСЫ ПОДДЕРЖКИ · .hbal / .hrow
   ─────────────────────────────────────────────────────────────────────────── */
.hbal .hb-lbl{color:var(--d-cap)}                     /* 11px капслок */
.hb-val{line-height:1.05}
.hb-warn{color:var(--d-danger);display:flex;align-items:center;gap:7px}
.hb-warn::before{
  content:'';width:15px;height:15px;flex:none;background:currentColor;
  -webkit-mask:var(--d-i-alert) center/contain no-repeat;
          mask:var(--d-i-alert) center/contain no-repeat;
}
/* Четвертные засечки на треке: видно не только «сколько осталось»,
   но и «где мы» относительно пакета. Селектор с .hbal — чтобы засечки
   пережили заливку трека из цветового слоя (там правило .hb-bar). */
.hbal .hb-bar{
  background-image:repeating-linear-gradient(90deg,
    transparent 0 calc(25% - 1px),
    color-mix(in srgb,var(--tx) 14%,transparent) calc(25% - 1px) 25%);
}
.hbal .hb-bar i{position:relative;z-index:1}          /* заливка поверх засечек */
.hb-sub{gap:10px 22px}
.hb-sub b{font-family:var(--mono);font-weight:700}

.hrow{padding:12px 16px}
.hr-l{gap:12px}
/* Ключевое число движения — правым краем в фиксированной колонке: «+2,5» и
   «−0,5» встают друг под другом, знак читается первым. */
.hr-k{min-width:66px;text-align:right;font-weight:700}
.hrow.purchase .hr-k{color:var(--d-ok)}
.hr-n{line-height:1.35}
.hr-t{color:var(--d-sec);line-height:1.35}
/* Глиф «✕» из разметки заменяем маской-корзиной: смысл кнопки — удаление */
.hr-x[data-hdel]{
  position:relative;width:30px;height:30px;font-size:0;
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--d-t),color var(--d-t);
}
.hr-x[data-hdel]::before{
  content:'';width:15px;height:15px;background:currentColor;
  -webkit-mask:var(--d-i-trash) center/contain no-repeat;
          mask:var(--d-i-trash) center/contain no-repeat;
}


/* ───────────────────────────────────────────────────────────────────────────
   5 · БИБЛИОТЕКА ДОКУМЕНТОВ · .lib
   ─────────────────────────────────────────────────────────────────────────── */
/* Эмодзи-иконка документа посажена в тайл-миниатюру: строки выравниваются по
   одной сетке, а разнокалиберные эмодзи перестают прыгать по базовой линии. */
.lib-ic{
  width:40px;height:40px;border-radius:11px;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--d-well);border:1px solid var(--d-hair);
  font-size:20px;line-height:1;
}
.lib-dl{gap:7px;transition:gap var(--d-t)}
.lib:hover .lib-dl{gap:10px}                 /* стрелка чуть отъезжает — жест «скачать» */
.lib-note{color:var(--d-sec)}                /* было --tx-dim: ~4:1 на 12px */


/* ───────────────────────────────────────────────────────────────────────────
   6 · КОММЕНТАРИИ · .cmt
   ─────────────────────────────────────────────────────────────────────────── */
.cmts{gap:12px;scrollbar-width:thin;scrollbar-color:var(--line2) transparent}
.cmts-head{letter-spacing:-.01em}

/* Аватар: инициал моноширинным — буквы разной ширины перестают гулять в круге */
.cmt-av{font-family:var(--mono);font-weight:700;letter-spacing:0}
.cmt-bubble{padding:9px 13px 10px}
.cmt-meta{gap:10px;margin-bottom:4px}
/* Время и пометка «изменён» приходят одной строкой из app.js — держим их
   единым тихим блоком, но не ниже 4.5:1 (было --tx-dim, ~4:1). */
.cmt-meta span{color:var(--d-sec);font-family:var(--mono)}

/* Кнопки правки и удаления: в разметке текстовые глифы «✎» и «✕» — заменяем
   их масками-иконками. Глиф гасим кеглем 0, aria-label в кнопке остаётся. */
.cmt-act{gap:3px}
.cmt-t{position:relative;transition:background var(--d-t),color var(--d-t)}
.cmt-t[data-cedit],.cmt-t[data-cdel]{font-size:0}
.cmt-t[data-cedit]::before,.cmt-t[data-cdel]::before{
  content:'';width:14px;height:14px;background:currentColor;
}
.cmt-t[data-cedit]::before{
  -webkit-mask:var(--d-i-pencil) center/contain no-repeat;
          mask:var(--d-i-pencil) center/contain no-repeat;
}
.cmt-t[data-cdel]::before{
  -webkit-mask:var(--d-i-trash) center/contain no-repeat;
          mask:var(--d-i-trash) center/contain no-repeat;
}
/* Страховка на будущее: если в наборе ICON появится готовая pencil-иконка,
   маска отключится и в кнопке не окажется двух иконок сразу. */
.cmt-t:has(svg){font-size:14px}
.cmt-t:has(svg)::before{display:none}
.cmt-t[data-cdel]:hover{color:var(--d-danger)}
/* Зона нажатия шире картинки: кнопка визуально мелкая, промахнуться нельзя */
.cmt-t::after{content:'';position:absolute;inset:-7px}

/* Ссылка в комментарии — чип, а не строка текста: её кликают, это видно */
.cmt-link{
  display:inline-flex;align-items:center;gap:6px;
  padding:4px 9px;margin-top:8px;border-radius:8px;
  background:var(--d-wash);font-weight:600;
}
.cmt-link:hover{background:color-mix(in srgb,var(--acc) 20%,transparent)}
.cmt-edit-ta{line-height:1.5}
.cef-x[data-efdel]{position:relative;font-size:0;min-width:30px;justify-content:center}
.cef-x[data-efdel]::before{
  content:'';width:12px;height:12px;background:currentColor;
  -webkit-mask:var(--d-i-x) center/contain no-repeat;
          mask:var(--d-i-x) center/contain no-repeat;
}
.cef-x[data-efdel]:hover{color:var(--d-danger)}

/* Панель «Файл / ссылка» под полем ввода */
.cf-name{align-items:center}
.cf-x{
  position:relative;font-size:0;width:22px;height:22px;flex:none;border-radius:6px;
  display:inline-flex;align-items:center;justify-content:center;
  transition:background var(--d-t),color var(--d-t);
}
.cf-x::before{
  content:'';width:11px;height:11px;background:currentColor;
  -webkit-mask:var(--d-i-x) center/contain no-repeat;
          mask:var(--d-i-x) center/contain no-repeat;
}
.cf-x::after{content:'';position:absolute;inset:-9px}   /* тап-зона 40px при иконке 11px */
.cf-x:hover{color:var(--d-danger);background:color-mix(in srgb,var(--danger) 14%,transparent)}


/* ───────────────────────────────────────────────────────────────────────────
   7 · ВЛОЖЕНИЯ И ДОКУМЕНТЫ ЗАДАЧИ · .cmt-file / .cmt-img / .doc
   ─────────────────────────────────────────────────────────────────────────── */
.cmt-file{gap:9px;padding:8px 12px;align-items:center;max-width:100%}
.cmt-file span{flex:1;min-width:0}
/* Размер файла — число, значит моно и приглушённо, но не ниже нормы:
   базовый --tx-dim давал ~4:1 на 12px. */
.cmt-file em,.doc-dl em,.cmt-img-n em,.docpick-name em{
  color:var(--d-sec);font-family:var(--mono);
}
.cmt-file em{margin-left:auto;padding-left:4px}

/* Картинка-вложение: рамка-паспарту и подпись отдельной полкой снизу */
.cmt-img{overflow:hidden}
.cmt-img img{transition:transform .25s cubic-bezier(.22,.72,.28,1)}
.cmt-img:hover img{transform:scale(1.02)}
.cmt-img-n{
  color:var(--d-sec);
  border-top:1px solid var(--d-hair);
  background:color-mix(in srgb,var(--bg) 45%,transparent);
}

.docs-sec .docs-head{color:var(--d-cap);letter-spacing:.01em}
.doc-dl{gap:10px;padding:8px 11px;align-items:center;transition:border-color var(--d-t),background var(--d-t)}
/* Иконка типа файла занимает ровно ту же клетку 34×34, что и миниатюра
   .doc-th, поэтому строки с картинкой и без неё стоят в одной сетке. */
.doc-ic{
  width:34px;height:34px;border-radius:9px;
  align-items:center;justify-content:center;
  background:var(--d-well);border:1px solid var(--d-hair);
  font-size:12px;color:var(--acc-d);
}
.doc-ic svg{width:16px;height:16px}
.doc-th{border:1px solid var(--d-hair)}
.doc-dl em{margin-left:auto;padding-left:4px}
/* «✕» удаления документа → корзина; ссылка-скачивание оставляет свой SVG */
.doc-x{position:relative;transition:background var(--d-t),color var(--d-t)}
.doc-x[data-docdel]{font-size:0}
.doc-x[data-docdel]::before{
  content:'';width:14px;height:14px;background:currentColor;
  -webkit-mask:var(--d-i-trash) center/contain no-repeat;
          mask:var(--d-i-trash) center/contain no-repeat;
}
.doc-x[data-docdel]:hover{color:var(--d-danger)}
.doc-x::after{content:'';position:absolute;inset:-6px}


/* ───────────────────────────────────────────────────────────────────────────
   8 · KPI-ПЛИТКИ · .kpic / .mtile
   ─────────────────────────────────────────────────────────────────────────── */
.kpic{padding:14px 16px 15px;gap:3px}
.kpi-ic{margin-bottom:8px;border-radius:10px}
.kpic b{line-height:1.1}
.kpi-l{display:flex;align-items:center;gap:6px;line-height:1.35}
/* Дельта. Отдельного элемента под неё в разметке нет, но состояние приходит
   классом .good / .bad — рисуем маркер прямо перед подписью:
   good = движение вверх, bad = требует внимания. */
.kpic.good .kpi-l::before,
.kpic.bad .kpi-l::before{content:'';width:13px;height:13px;flex:none;background:currentColor}
.kpic.good .kpi-l{color:var(--d-ok)}
.kpic.good .kpi-l::before{
  -webkit-mask:var(--d-i-trend) center/contain no-repeat;
          mask:var(--d-i-trend) center/contain no-repeat;
}
.kpic.bad .kpi-l{color:var(--d-danger)}
.kpic.bad .kpi-l::before{
  -webkit-mask:var(--d-i-alert) center/contain no-repeat;
          mask:var(--d-i-alert) center/contain no-repeat;
}

/* Полоса метрик студии */
.mtile b{line-height:1.05}
.mtile .mpct{font-size:.62em;color:var(--d-sec);margin-left:1px}  /* «%» — единица, а не число */


/* ───────────────────────────────────────────────────────────────────────────
   9 · ГРАФИКИ · оси, сетка, подписи, легенда
   ─────────────────────────────────────────────────────────────────────────── */
/* Подписи осей — 10px, значит норма 7:1; базовый --tx-dim давал ~4:1. */
.axl,.barsvg .bx,.dc-cap{fill:var(--d-cap)}
/* Подписи недель под burn-up: правило было только для .barsvg .bx, а этот
   график рисуется в .burnup — текст оставался дефолтным SVG-чёрным 16px.
   Проверено по svgBurnup в app.js: класс тот же, родитель другой. */
.burnup .bx{fill:var(--d-cap);font-family:var(--mono);font-size:10px}
.cgrid{stroke-dasharray:1 5;stroke-linecap:round}   /* сетка подсказывает, а не расчерчивает */

/* Столбики: пустая неделя не исчезает совсем — она тоже данные */
.barsvg .bar{transition:opacity var(--d-t)}
.barsvg .bar:hover{opacity:.85}
.barsvg .bar.zero{opacity:.55}

/* Burn-up: «всего» — тихий пунктир, «готово» — акцентная линия.
   Кант цвета панели вокруг конечных точек: они читаются поверх линии. */
.burnup .bu-scope{stroke-dasharray:5 4;opacity:.75}
.burnup .bu-dot.scope,.burnup .bu-dot.done{stroke:var(--panel);stroke-width:2}
.bu-legend{gap:10px 18px;margin-top:14px}
.bu-legend span{gap:8px}
.bu-k{height:3px;border-radius:2px}
/* Отметка «в срок» — итоговое число, поэтому чип, а не строка текста */
.bu-ot{
  color:var(--d-ok);font-weight:700;
  background:color-mix(in srgb,var(--ok) 13%,transparent);
  padding:3px 10px;border-radius:20px;
}

/* Легенда пончика: подпись слева, число прижато вправо — колонка чисел ровная.
   margin-left:auto работает по анонимному флекс-элементу с текстом подписи. */
.lg{gap:9px}
.lg b{margin-left:auto;font-family:var(--mono);padding-left:12px}
.lgd{box-shadow:0 0 8px -2px currentColor,inset 0 1px 0 rgba(255,255,255,.25)}

/* Горизонтальные полосы (этапы, нагрузка) */
.hbars{gap:14px}
.hb-l{align-items:baseline;gap:12px}
.hb-l span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hb-l b{font-family:var(--mono);flex:none;color:var(--tx)}
.hb-t,.hb-t i{border-radius:20px}

/* Сегментная полоса статусов и её легенда */
.an-bar i:first-child{border-radius:6px 0 0 6px}
.an-bar i:last-child{border-radius:0 6px 6px 0}
.an-cells{gap:10px 18px}
.an-cell{gap:7px}
.an-cell b{font-family:var(--mono);font-weight:700}

/* Ключ тепловой карты — 11px, значит 7:1 */
.heat-leg{color:var(--d-cap);gap:6px}
.heat-leg .hk{border-radius:3px;box-shadow:inset 0 0 0 1px var(--d-hair)}

/* Тултип графиков: число внутри — тоже число, значит моно */
.charttip{padding:7px 11px;border-radius:10px}
.charttip b{font-family:var(--mono);font-weight:700}


/* ───────────────────────────────────────────────────────────────────────────
   10 · ПУСТЫЕ СОСТОЯНИЯ
   Пустой экран должен выглядеть как решение, а не как сбой загрузки:
   у него есть иконка, заголовок, объяснение и место под действие.
   ─────────────────────────────────────────────────────────────────────────── */
.emptybox{padding:64px 20px}
.emptybox .ei{border-radius:20px}

/* Мини-заглушка внутри карточки дашборда */
.dash-empty{
  border:1px dashed var(--d-hair);
  border-radius:12px;
  background:color-mix(in srgb,var(--bg) 35%,transparent);
  color:var(--d-sec);
  padding:26px 14px;
}
.dash-empty svg{opacity:.8}

/* Список документов задачи пуст */
.docs-empty{
  font-style:normal;                        /* курсив читался как сообщение об ошибке */
  color:var(--d-sec);
  border:1px dashed var(--d-hair);
  border-radius:10px;
  padding:12px;
  text-align:center;
}

/* Общая заглушка списков. Вариант внутри колонки доски (.col-body>.empty)
   специфичнее и остаётся как есть — свою подпись «Пусто» он рисует сам. */
.empty{color:var(--d-sec);line-height:1.5}   /* было --tx-dim: ~4:1, ниже нормы */

/* Подсказка в пустой колонке «Пожелания» — акцентный корешок слева */
.col-hint{border-left-width:3px;border-left-style:solid}


/* ───────────────────────────────────────────────────────────────────────────
   11 · ЗАГРУЗКА · .spin
   Вместо кольца с обрезанной кромкой — трек плюс дуга с затухающим хвостом.
   Хвост показывает направление вращения, трек не даёт индикатору «пропадать»
   на тёмном фоне. Внешних ресурсов не нужно: это два псевдоэлемента.
   ─────────────────────────────────────────────────────────────────────────── */
@keyframes dSpin{to{transform:rotate(1turn)}}
.spin{
  width:30px;height:30px;border:0;background:none;border-radius:50%;
  position:relative;animation:none;
}
.spin::before{
  content:'';position:absolute;inset:0;border-radius:50%;
  border:2.5px solid color-mix(in srgb,var(--tx) 12%,transparent);
}
.spin::after{
  content:'';position:absolute;inset:0;border-radius:50%;
  background:conic-gradient(from 0deg,
    transparent 0 22%,
    color-mix(in srgb,var(--acc) 30%,transparent) 58%,
    var(--acc-d) 100%);
  -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 2.5px),#000 calc(100% - 2.4px));
          mask:radial-gradient(farthest-side,transparent calc(100% - 2.5px),#000 calc(100% - 2.4px));
  animation:dSpin .78s linear infinite;
}


/* ───────────────────────────────────────────────────────────────────────────
   12 · ТЕЛЕФОН
   Проверочная ширина 390px: ничего не выезжает, у всего интерактивного зона
   нажатия ≥44×44. Мелкие иконки добирают её псевдоэлементом ::after, чтобы
   не раздувать высоту строки списка.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:760px){
  .tblwrap .tbl th,.tblwrap .tbl td{padding-top:13px;padding-bottom:13px}
  .rowact{position:relative;height:40px;padding:0 12px}
  .rowdel{position:relative;width:40px;height:40px}
  .rowact::after,.rowdel::after{content:'';position:absolute;inset:-2px}

  .inv-kpi{flex:1 1 140px;min-width:0}
  .inv-acts .btn{flex:1 1 auto;justify-content:center}

  .hr-k{min-width:58px}
  .hr-x[data-hdel]{width:38px;height:38px}
  .hr-x[data-hdel]::after{content:'';position:absolute;inset:-3px}

  .lib-ic{width:38px;height:38px;font-size:19px}

  .cmt{max-width:92%}                       /* на узком экране 86% съедали строку */
  .cmt-t{width:34px;height:34px}
  .cmt-t::after{inset:-5px}
  .cf-x{width:26px;height:26px}
  .cef-x[data-efdel]{min-width:38px;min-height:38px}
  .cef-x[data-efdel]::after{content:'';position:absolute;inset:-3px}

  .doc-dl{padding:9px 11px}
  .doc-x{width:38px;height:38px}
  .doc-x::after{inset:-3px}

  .an-cells{gap:9px 14px}
  .bu-legend{gap:8px 14px}
}
@media(max-width:400px){
  .inv-sum{font-size:18px}
  .hbal .hb-sub{gap:6px 16px}
  .hr-l{gap:9px}
  .hr-k{min-width:52px}
  .mtile{padding:14px 8px}
  .tblwrap .tbl th,.tblwrap .tbl td{padding-left:12px;padding-right:12px}
  .emptybox{padding:48px 16px}
}


/* ───────────────────────────────────────────────────────────────────────────
   13 · «МЕНЬШЕ ДВИЖЕНИЯ»
   Гасим всё, что двигается в этом слое. Индикатор загрузки остаётся видимым,
   но становится статичной дугой — так он читается как состояние, а не как
   сломанное кольцо.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .tblwrap .tbl tbody tr,.rowact,.rowdel,
  .hr-x[data-hdel],.doc-x,.cmt-t,.cf-x,
  .lib-dl,.doc-dl,.cmt-img img,.barsvg .bar{transition:none}
  .cmt-img:hover img{transform:none}
  .lib:hover .lib-dl{gap:7px}
  .spin::after{
    animation:none;
    background:conic-gradient(from -90deg,var(--acc-d) 0 72%,transparent 72% 100%);
  }
}

/* ▲▲▲ конец: ДАННЫЕ: ТАБЛИЦЫ, КОММЕНТАРИИ, ВЛОЖЕНИЯ, KPI ▲▲▲ */

/* ▼▼▼ ПРОРАБОТКА: ИКОНКИ, АВАТАРЫ, МЕТКИ И ДВИЖЕНИЕ ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   «ПОЛНОЧЬ» · семейство «ИКОНКИ, АВАТАРЫ, МЕТКИ И ДВИЖЕНИЕ»
   Дописывается В КОНЕЦ app.css. Здесь только графика мелких элементов и
   движение; цвет крупных поверхностей — не моя зона, её я не переопределяю.

   Разделение труда с оформлением «Полночи»: оно отвечает за ЦВЕТ и СВЕЧЕНИЕ,
   этот файл — за ГЕОМЕТРИЮ (размер, радиус, штрих, толщина) и ВРЕМЯ.
   Поэтому пересечений почти нет: я задаю свойства, которых там нет.
   Все селекторы сверены с app.js — того, что не рендерится, здесь нет
   (например, .tk-dot в app.css есть, а в app.js его никто не выводит —
   не трогаю, чтобы не плодить мёртвые правила).
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   0 · ТОКЕНЫ. Длительности, кривые, ступени иконок, ступени точек.
   Без них «единая система» превращается в 40 разных значений по файлу.
   ─────────────────────────────────────────────────────────────────────────── */
:root{
  /* Четыре длительности — больше не нужно. Правило простое:
     реакция на курсор < появление объекта < заполнение шкалы. */
  --mo-1x:110ms;   /* цвет иконки, рамка, прозрачность — «мгновенно» */
  --mo-2x:180ms;   /* фон, тень, подъём карточки */
  --mo-3x:280ms;   /* появление элемента списка, схлопывание вуали темы */
  --mo-4x:620ms;   /* заполнение полос и колец — единственное «долгое» */
  --mo-step:34ms;  /* шаг лесенки в списке; 8 шагов = 272мс, глаз не устаёт */

  /* Кривые. --mo-out для всего, что появляется (быстрый старт, мягкий стоп),
     --mo-soft для числовых величин (ширина полосы, длина дуги). */
  --mo-out:cubic-bezier(.22,.72,.28,1);
  --mo-soft:cubic-bezier(.4,0,.2,1);

  /* Иконки: 4 ступени размера. Штрих у каждой ступени свой, потому что
     все иконки нарисованы в сетке 24 и при уменьшении линия худеет.
     Значения подобраны так, чтобы фактическая толщина везде была ≈1.4px:
     24 / размер × 1.4. Иначе крупная иконка выглядит жирнее мелкой. */
  --ic-sm:15px; --ic-sm-w:2.2;
  --ic-md:17px; --ic-md-w:2;
  --ic-lg:20px; --ic-lg-w:1.7;
  --ic-xl:26px; --ic-xl-w:1.35;
  --ic-rest:var(--tx-mut);   /* покой: тише текста, но контраст к фону > 3:1 */
  --ic-on:var(--acc-d);      /* активное/наведённое состояние */

  /* Точки: ровно два размера. «В строке» и «самостоятельная».
     Образцы цвета серий на графиках — отдельный вид, скруглённый квадрат:
     так глаз отличает «статус объекта» от «цвет линии на графике». */
  --dot-s:7px;
  --dot-m:9px;
  --sw-s:10px; --sw-r:3px;
  /* Фаска бусины: сверху свет, снизу собственная тень. На 7–9px читается
     как объём, а не как грязь. */
  --dot-bevel:inset 0 1px 0 rgba(255,255,255,.34), 0 1px 2px rgba(36,36,36,.42);

  /* Счётчики: одна высота и один радиус на все шесть мест в кабинете. */
  --cnt-h:18px; --cnt-r:9px;

  /* «Корыто» шкалы и внутренний блик заливки. Свечение у полос обязано быть
     inset: у всех дорожек overflow:hidden, наружная тень просто срежется. */
  --mg-well:inset 0 1px 3px rgba(36,36,36,.5), inset 0 0 0 1px rgba(199,199,199,.06);
  --mg-gloss:inset 0 1px 0 rgba(255,255,255,.3), inset 0 -1px 0 rgba(36,36,36,.2);
}
[data-theme="light"]{
  --ic-on:var(--acc);        /* на светлом --acc-d слишком тёмный и «грязнит» */
  --dot-bevel:inset 0 1px 0 rgba(255,255,255,.55), 0 1px 2px rgba(56,56,56,.2);
  --mg-well:inset 0 1px 3px rgba(56,56,56,.13), inset 0 0 0 1px rgba(56,56,56,.06);
  --mg-gloss:inset 0 1px 0 rgba(255,255,255,.45), inset 0 -1px 0 rgba(56,56,56,.1);
}


/* ───────────────────────────────────────────────────────────────────────────
   1 · ИКОНКИ. Один штрих, одна сетка, одно выравнивание.
   ─────────────────────────────────────────────────────────────────────────── */
/* Все иконки интерфейса приходят из объекта ICON (app.js) и у всех
   viewBox="0 0 24 24" — это единственная общая примета, по ней и ловим.
   Проверено грепом: остальные SVG кабинета (кольца, столбцы, спарклайн,
   пончик, burn-up, тепловая карта) строятся с вычисляемым viewBox
   ("0 0 84 84", "0 0 ${w} ${h}") и под этот селектор не попадают —
   их stroke-width из разметки остаётся нетронутым. */
svg[viewBox="0 0 24 24"]{
  width:var(--ic-md); height:var(--ic-md);
  stroke-width:var(--ic-md-w);
  /* у ICON.theme в разметке нет скруглений торцов, у ICON.search/link штрих 2,
     у остальных 1.8 — здесь все три расхождения снимаются разом */
  stroke-linecap:round; stroke-linejoin:round;
  vertical-align:-.14em;   /* оптическая посадка на базовую линию текста */
  flex:none;               /* в flex-строке иконка не сплющивается длинным текстом */
  transition:color var(--mo-1x) var(--mo-out), opacity var(--mo-1x) var(--mo-out);
}

/* Ступень SM · плотные ряды рядом с текстом 13px */
.pl-ic svg,.rowact .pl-ic svg,.btn-danger .pl-ic svg,.btn-file .pl-ic svg,
.doc-ic svg,.doc-x svg,.lib-dl svg,.cmt-file svg,.docs-head svg,
.cef-cur svg,.cef-add svg,.card .qadv svg{
  width:var(--ic-sm); height:var(--ic-sm); stroke-width:var(--ic-sm-w);
}
/* Ступень MD задана базовым правилом; здесь только те места, где раньше
   стояло 16 или 19 и надо перебить более специфичный селектор */
.ptab svg,.ptab.exp svg,.ptab.set svg,.dc-t svg,.kpi-ic svg,
.cmt-attach svg,.rowdel svg,.vw-btn svg{
  width:var(--ic-md); height:var(--ic-md); stroke-width:var(--ic-md-w);
}
/* Ступень LG · навигация и кнопки-иконки */
.ni-ic svg,.iconbtn svg,.tm-av svg,.cmt-form [data-cmt] svg{
  width:var(--ic-lg); height:var(--ic-lg); stroke-width:var(--ic-lg-w);
}
/* Ступень XL · пустые состояния и диалог подтверждения */
.emptybox .ei svg,.dash-empty svg,.confirm-modal .cf-ic svg{
  width:var(--ic-xl); height:var(--ic-xl); stroke-width:var(--ic-xl-w);
}
.ni-ic{width:var(--ic-lg); height:var(--ic-lg)}
.pl-ic{width:var(--ic-sm); height:var(--ic-sm)}

/* Цвет: в покое тише подписи, в активном — акцент.
   Это единственный способ отличить «где я» без лишней заливки. */
.navitem .ni-ic{color:var(--ic-rest); transition:color var(--mo-1x) var(--mo-out)}
.navitem:hover .ni-ic,.navitem.on .ni-ic{color:var(--ic-on)}
.iconbtn{color:var(--ic-rest); transition:color var(--mo-1x) var(--mo-out),
  border-color var(--mo-2x) var(--mo-out), background var(--mo-2x) var(--mo-out)}
.iconbtn:hover,.iconbtn:focus-visible{color:var(--ic-on)}
.ptab svg{color:var(--ic-rest)}
.ptab:hover svg{color:var(--tx)}
.ptab.on svg{color:var(--ic-on)}
/* лупа в поиске по задачам подсвечивается вместе с полем — маленький,
   но очень «дорогой» отклик: видно, что фокус именно здесь */
.ts-ic{color:var(--ic-rest); transition:color var(--mo-1x) var(--mo-out)}
.tsearch:focus-within .ts-ic{color:var(--ic-on)}
/* служебные глифы-кнопки: тише всех, пока к ним не потянулись */
.cmt-t svg,.cef-cur svg,.doc-x svg,.rowdel svg{color:currentColor}
.dash-empty svg{opacity:.75}


/* ───────────────────────────────────────────────────────────────────────────
   2 · АВАТАРЫ. Градиент вместо плоской заливки, тонкая грань, читаемые буквы.
   ─────────────────────────────────────────────────────────────────────────── */
/* Общее для всех пяти: инициалы по центру, табличные цифры не нужны,
   а вот моноширинный кегль — нужен, буквы не пляшут по ширине. */
.uav,.cmt-av,.asa,.tm-av,.fe-av{
  letter-spacing:-.01em;
  transition:box-shadow var(--mo-2x) var(--mo-out), transform var(--mo-2x) var(--mo-out);
}

/* Аватар в шапке. Индиго берём из токена, но принудительно затемняем:
   чистый --acc под белым текстом даёт 4.35:1 — мало. Смесь 86% с чёрным
   даёт 5.4:1 на тёмной теме и 7.8:1 на светлой, и остаётся «полночной». */
.uav{
  background:linear-gradient(145deg,
    color-mix(in srgb, var(--acc) 86%, #000),
    color-mix(in srgb, var(--acc) 50%, #313131));
  color:#FFFFFF;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32),
             inset 0 0 0 1px rgba(255,255,255,.1),
             0 3px 10px -5px var(--glow);
}
.ubtn:hover .uav{box-shadow:inset 0 1px 0 rgba(255,255,255,.4),
  inset 0 0 0 1px rgba(255,255,255,.16), 0 5px 14px -5px var(--glow)}

/* Аватар в чате. Нейтральный материал, а не цветное пятно: в переписке
   цветом выделяется только автор-админ, иначе лента рябит. */
.cmt-av{
  background:linear-gradient(150deg,
    color-mix(in srgb, var(--tx) 13%, var(--card2)), var(--card2));
  color:var(--tx-mut);                       /* 6.2:1 в обеих темах */
  border:1px solid var(--line2);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.1);
}
.cmt.adm .cmt-av{
  background:linear-gradient(145deg,
    color-mix(in srgb, var(--acc) 86%, #000),
    color-mix(in srgb, var(--acc) 50%, #313131));
  color:#FFFFFF; border-color:color-mix(in srgb, var(--acc) 55%, transparent);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 3px 10px -6px var(--glow);
}

/* Аватар участника команды. Цвет роли уже лежит в --tc на .tm — используем
   его и для заливки, и для грани, и для букв. Смесь 70% роли с --tx даёт
   читаемые инициалы в ОБЕИХ темах (--tx переворачивается вместе с темой):
   светлая 4.8–5.5:1, тёмная 10–11:1. Перечисляю роли поимённо, иначе
   правила вида «.tm.r-lead .tm-av» из app.css перевесят по специфичности. */
.tm-av,
.tm.r-pm .tm-av,.tm.r-lead .tm-av,.tm.r-support .tm-av,.tm.r-design .tm-av,
.tm.r-frontend .tm-av,.tm.r-backend .tm-av,.tm.r-qa .tm-av,.tm.r-devops .tm-av,
.tm.r-analytics .tm-av,.tm.r-content .tm-av,.tm.ghost .tm-av{
  background:linear-gradient(150deg,
    color-mix(in srgb, var(--tc, var(--acc)) 26%, var(--card2)),
    color-mix(in srgb, var(--tc, var(--acc)) 9%,  var(--card2)));
  border:1px solid color-mix(in srgb, var(--tc, var(--acc)) 42%, var(--line2));
  color:color-mix(in srgb, var(--tc, var(--acc)) 70%, var(--tx));
  box-shadow:inset 0 1px 0 rgba(255,255,255,.1),
             0 6px 16px -10px color-mix(in srgb, var(--tc, var(--acc)) 70%, #000);
}
.tm:hover .tm-av{box-shadow:inset 0 1px 0 rgba(255,255,255,.16),
  0 8px 20px -10px color-mix(in srgb, var(--tc, var(--acc)) 80%, #000)}
/* индикатор присутствия: чуть меньше и с ободком под материал карточки */
.tm:not(.ghost) .tm-av::after{
  width:11px; height:11px; right:-3px; bottom:-3px;
  border:2px solid var(--card);
  box-shadow:0 0 0 1px rgba(36,36,36,.35), 0 0 8px -2px var(--tc, var(--acc));
}

/* Стопка аватаров команды и ленты. Цвет роли сюда приходит ИНЛАЙНОМ из
   app.js (style="background:var(--ok)" и т.п.), поэтому:
   1) поверх кладём тёмную вуаль — иначе белые инициалы на мятном и жёлтом
      нечитаемы (было бы 2.6:1, стало ≥4.8:1 на самом светлом фоне);
   2) !important обязателен: инлайновый background — это ещё и
      background-image:none на уровне элемента, обычное правило его не перебьёт.
   .asa.more исключён — там нейтральная плашка «+N» со своим цветом текста. */
.asa:not(.more),.fe-av{
  background-image:linear-gradient(155deg, rgba(41,41,41,.46), rgba(41,41,41,.68))!important;
  color:#FFFFFF;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3),
             inset 0 0 0 1px rgba(255,255,255,.2),
             0 2px 6px -3px rgba(36,36,36,.7);
}
/* .fe-av в базе был 9px — на таком кегле нужно 7:1, чего цветной аватар
   не даёт физически. Поднимаю до 12px (ступень остальных аватаров) и
   расширяю кружок на 2px, чтобы двухбуквенные инициалы «ВР»/«ТП» дышали. */
.fe-av{width:26px; height:26px; font-size:12px; letter-spacing:-.03em}
.asa.more{
  background-image:linear-gradient(150deg,
    color-mix(in srgb, var(--tx) 10%, transparent), transparent)!important;
  color:var(--tx-mut);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.12);
}
/* стопка «слипается» — при наведении на конкретного человека он выходит вперёд */
.avstack .asa{transition:transform var(--mo-2x) var(--mo-out)}
.avstack:hover .asa:hover{transform:translateY(-3px)}


/* ───────────────────────────────────────────────────────────────────────────
   3 · ТОЧКИ И МЕТКИ. Две величины точки, три радиуса метки — и всё.
   ─────────────────────────────────────────────────────────────────────────── */
/* Самостоятельная точка-состояние (9px, круг). Кружок, а не квадратик:
   квадратные оставлены только образцам цвета на графиках — так две сущности
   не путаются. Селекторы продублированы с их «родными» префиксами
   (.card .meta .typedot, .drow-t .typedot), иначе не перебьют базовые. */
.typedot,.card .meta .typedot,.drow-t .typedot,
.col-h .dot,.col-exp .dot,.mv-dot,.seg .tdot,.an-dot,.th-online .od{
  width:var(--dot-m); height:var(--dot-m);
  border-radius:50%; flex:none;
  box-shadow:var(--dot-bevel);
}
/* Точка-маркер внутри строки текста (7px). Мельче, чтобы не спорить с буквами. */
.tag .td,.tf .td,.tp .td,.pdot.blk,
.card .blk .pulse,.ro-block .pulse,.tm-now .nd,
.live-card .live-badge .d,.feed-live .d{
  width:var(--dot-s); height:var(--dot-s);
  border-radius:50%; flex:none;
}
.tag .td,.tf .td,.tp .td{box-shadow:var(--dot-bevel)}
/* Образец цвета серии на графике: скруглённый квадрат, один размер. */
.lgd,.heat-leg .hk{
  width:var(--sw-s); height:var(--sw-s);
  border-radius:var(--sw-r); flex:none;
  box-shadow:inset 0 0 0 1px rgba(36,36,36,.25);
}

/* Цвет метки считается из строки (--h приходит инлайном из tagHue).
   Разводим по темам: на тёмной нужна светлота выше, на светлой — ниже,
   иначе половина меток «пропадает» на своём фоне. */
.tag .td,.tf .td,.tp .td{background:hsl(var(--h,258) 62% 64%)}
[data-theme="light"] .tag .td,
[data-theme="light"] .tf .td,
[data-theme="light"] .tp .td{background:hsl(var(--h,258) 58% 44%)}

/* В сегменте выбора типа задачи точки .tdot.t-* рендерятся (app.js, segHTML
   с dot:1), но цвета им не задавал НИКТО — во всём проекте есть только
   размеры .seg .tdot. То есть кружки были невидимыми. Возвращаем им тип. */
.seg .tdot.t-task{background:var(--t-task)}
.seg .tdot.t-feature{background:var(--t-feature)}
.seg .tdot.t-bug{background:var(--t-bug)}
.seg .tdot.t-design{background:var(--t-design)}
.seg .tdot.t-content{background:var(--t-content)}
.seg .tdot.t-deploy{background:var(--t-deploy)}
/* на выбранной кнопке сегмента фон акцентный — точке нужен свой ободок */
.seg button.on .tdot{box-shadow:var(--dot-bevel), 0 0 0 1.5px rgba(36,36,36,.22)}

/* Радиусы меток. Три класса формы, читаемые с одного взгляда:
   ▸ «метка-факт» (не кликается)      — 6px
   ▸ «пилюля-состояние» (не кликается) — капсула
   ▸ «кнопка-фильтр» (кликается)       — 9px */
.tag,.tp,.card .meta .pchip,.card .meta .due{border-radius:6px}
.chip,.tm-st,.pill-blk,.inv-badge,.dept,.pmchip,.pmbadge,
.feed-live,.live-card .live-badge,.badge-n{border-radius:999px}
.tf,.schip,.mv-chip,.psel,.pb-chip,.bchip{border-radius:9px}
/* один вертикальный ритм у микро-меток: высота строки 16px как у .meta */
.tag{padding:0 7px; min-height:16px; line-height:16px; gap:5px}
.tp{padding:2px 6px 2px 9px; min-height:22px; gap:6px}


/* ───────────────────────────────────────────────────────────────────────────
   4 · СЧЁТЧИКИ И БЕЙДЖИ. Шесть разных плашек сводятся к одной.
   ─────────────────────────────────────────────────────────────────────────── */
/* Заодно чиним контраст: --tx-dim на --line давал 3.6:1 у .side-n и .bchip i
   и 4.07:1 у .col-h .n — при кегле 12px это ниже нормы. --tx-mut на той же
   подложке даёт 6.7–8.5:1 на тёмной и 6.0–6.5:1 на светлой. */
.navitem .cnt,.side-n,.subs-n,.badge-n,.bchip i,.col-exp .n,.col-h .n{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:20px; height:var(--cnt-h); padding:0 6px;
  border-radius:var(--cnt-r);
  font-family:var(--mono); font-size:12px; line-height:1; letter-spacing:0;
  font-variant-numeric:tabular-nums;   /* 9 и 11 не прыгают по ширине */
  color:var(--tx-mut);
  background:color-mix(in srgb, var(--tx) 7%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--tx) 5%, transparent);
  transition:color var(--mo-1x) var(--mo-out), background var(--mo-1x) var(--mo-out);
}
/* активный пункт меню подтягивает и счётчик — иначе он выглядит «чужим» */
.navitem.on .cnt,.navitem:hover .cnt{
  color:var(--tx); background:color-mix(in srgb, var(--acc) 20%, transparent);
}
.bchip.on i{color:var(--tx); background:color-mix(in srgb, var(--acc) 22%, transparent)}

/* Колокольчик. Плоский --danger под белым текстом — 2.97:1, читать нечем.
   Смесь 45% с почти-чёрным вишнёвым: 8.8:1 на тёмной, ещё выше на светлой,
   и бейдж остаётся откровенно красным. */
.nbadge{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:18px; height:18px; padding:0 5px; border-radius:9px;
  font-family:var(--mono); font-size:12px; font-weight:700; line-height:1;
  font-variant-numeric:tabular-nums;
  background:color-mix(in srgb, var(--danger) 45%, #2B2B2B);
  color:#FFFFFF;
  border:2px solid var(--bg);
  box-shadow:0 2px 8px -3px color-mix(in srgb, var(--danger) 75%, transparent);
  /* класс .hidden снимает display:none — анимация стартует именно в этот
     момент, ровно один раз на каждое появление счётчика */
  animation:mgPop 260ms var(--mo-out);
}


/* ───────────────────────────────────────────────────────────────────────────
   5 · ПОЛОСЫ ПРОГРЕССА. Утопленная дорожка, заливка со светом внутри.
   ─────────────────────────────────────────────────────────────────────────── */
.prog,.card .cprog,.hb-t,.an-bar,.hb-bar{box-shadow:var(--mg-well)}
/* Свечение только inset: у всех дорожек overflow:hidden, наружная тень
   от заливки была бы срезана краем и дала бы грязный шов. */
.prog i,.card .cprog i,.hb-t i,.hb-bar i,.an-bar i{
  box-shadow:var(--mg-gloss);
  transition:width var(--mo-4x) var(--mo-soft);
}
/* Единая акцентная заливка: индиго → мята. Ставится там, где цвет НЕ приходит
   инлайном из данных (.hb-t i и .an-bar i красятся по статусу — их не трогаем,
   им достаётся только блик выше). */
.prog i{
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--acc) 78%, #000) 0%, var(--acc) 52%, var(--ok) 100%);
  border-radius:6px;
}
.hb-bar i{
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--acc) 78%, #000) 0%, var(--acc) 52%, var(--ok) 100%);
}
/* Аккуратный торец: полоса готовности на карточке всего 3px, но скруглённый
   правый край сразу читается как «дошло досюда», а не как обрезка. */
.card .cprog i{border-radius:0 2px 2px 0}
.hb-t i{border-radius:0 6px 6px 0}
/* Сегменты сводной полосы разделяем волоском, а не только зазором:
   на светлой теме зазор в 2px почти не виден. */
.an-bar i+i{box-shadow:var(--mg-gloss), inset 1px 0 0 rgba(36,36,36,.28)}


/* ───────────────────────────────────────────────────────────────────────────
   6 · КОЛЬЦА ПРОГРЕССА. Толщина, торцы, свечение, отрисовка дуги.
   ─────────────────────────────────────────────────────────────────────────── */
/* Большое кольцо проекта (renderStats). Специфичность (0,3,0) взята намеренно:
   так правило работает и когда файл дописан в app.css, и когда оформление
   «Полночи» подключено отдельным листом поверх. */
.an-ringbox .an-ring .an-bg{
  stroke:color-mix(in srgb, var(--tx) 9%, transparent);
  stroke-width:8;
}
.an-ringbox .an-ring .an-fg{
  stroke-width:8;
  stroke-linecap:round;   /* оба торца дуги — скруглённые */
  /* «градиент» дуги без <defs>: два ореола разного цвета поверх сплошного
     штриха. Внутренний индиговый + внешний мятный дают на глаз переход. */
  filter:none;
  /* дуга дорисовывается от нуля к своему значению. Стартовое смещение равно
     длине окружности r=34 (2πr = 213.6) — она в разметке фиксированная.
     Конечный кадр не задан специально: он берётся из инлайнового
     stroke-dashoffset, то есть из реального процента. */
  animation:none;   /* дугу набирает animateProgress при открытии доски */
}
.an-ringtxt b{font-variant-numeric:tabular-nums; letter-spacing:-.02em}
.an-ringtxt span{letter-spacing:.08em}

/* Малые кольца (svgRing: плитки проектов, шапка аналитики).
   Здесь дуга — последний circle, дорожка — первый. */
.miniring circle:first-of-type{stroke:color-mix(in srgb, var(--tx) 9%, transparent)}
.miniring circle:last-of-type{
  stroke-linecap:round;
  filter:none;
}
.miniring .mrt{font-variant-numeric:tabular-nums; letter-spacing:-.02em}
/* Пончик статусов: скруглять торцы нельзя (сегменты сомкнуты), но сегмент
   под курсором должен выходить вперёд мягко, а не скачком. */
.dseg{transition:stroke-width var(--mo-2x) var(--mo-out), opacity var(--mo-1x) linear}
.dc-total{font-variant-numeric:tabular-nums}


/* ───────────────────────────────────────────────────────────────────────────
   7 · ДВИЖЕНИЕ. Заметно только там, где его ждёшь.
   ─────────────────────────────────────────────────────────────────────────── */
@keyframes mgRise{from{opacity:0; transform:translateY(6px)}}
@keyframes mgPop{from{opacity:0; transform:scale(.6)} 60%{transform:scale(1.08)}}
/* 213.6px = длина окружности r=34 в пользовательских единицах viewBox
   («px» для геометрических свойств SVG и есть пользовательская единица);
   то же число app.js кладёт в инлайновый stroke-dasharray */
@keyframes mgRing{from{stroke-dashoffset:213.6px}}
@keyframes mgHalo{
  0%{box-shadow:0 0 0 0 color-mix(in srgb, var(--danger) 70%, transparent)}
  70%{box-shadow:0 0 0 8px transparent}
  100%{box-shadow:0 0 0 0 transparent}
}
@keyframes mgFlash{from{background:color-mix(in srgb, var(--ok) 22%, transparent)}}
@keyframes mgAvIn{from{opacity:0; transform:translateX(-10px) scale(.7)}}
@keyframes mgFade{from{opacity:0}}

/* Появление списков. Лесенкой уходят ТОЛЬКО те списки, которые строятся
   один раз при открытии экрана. Карточки доски сознательно не анимируются:
   renderBoard() вызывается на каждый символ в поиске по задачам — доска
   моргала бы при наборе. Лента команды тоже нет: она целиком
   перерисовывается каждые 4.6 с, ей достаётся только .fe-new ниже. */
.dlist .drow,.lib-list .lib{animation:mgRise var(--mo-3x) var(--mo-out) backwards}
.dlist .drow:nth-child(2),.lib-list .lib:nth-child(2){animation-delay:calc(var(--mo-step) * 1)}
.dlist .drow:nth-child(3),.lib-list .lib:nth-child(3){animation-delay:calc(var(--mo-step) * 2)}
.dlist .drow:nth-child(4),.lib-list .lib:nth-child(4){animation-delay:calc(var(--mo-step) * 3)}
.dlist .drow:nth-child(5),.lib-list .lib:nth-child(5){animation-delay:calc(var(--mo-step) * 4)}
.dlist .drow:nth-child(6),.lib-list .lib:nth-child(6){animation-delay:calc(var(--mo-step) * 5)}
.dlist .drow:nth-child(n+7),.lib-list .lib:nth-child(n+7){animation-delay:calc(var(--mo-step) * 6)}

/* Стопка аватаров въезжает по одному — единственный «показательный» жест
   на экране «Команда», строится один раз на заход. */
.avstack .asa{animation:mgAvIn 340ms var(--mo-out) backwards; --d:0}
.avstack .asa{animation-delay:calc(var(--d) * 42ms)}
.avstack .asa:nth-child(2){--d:1}  .avstack .asa:nth-child(3){--d:2}
.avstack .asa:nth-child(4){--d:3}  .avstack .asa:nth-child(5){--d:4}
.avstack .asa:nth-child(6){--d:5}  .avstack .asa:nth-child(7){--d:6}
.avstack .asa:nth-child(8){--d:7}  .avstack .asa:nth-child(9){--d:8}
.avstack .asa:nth-child(10){--d:9} .avstack .asa:nth-child(n+11){--d:10}

/* Столбики и линия burn-up уже вырастают по barIn/drawLine из app.css —
   здесь только заливка-градиент под ними проявляется вместе с ними. */
.burnup .bu-area,.spark polygon{animation:mgFade var(--mo-4x) var(--mo-soft) backwards}

/* Подсветка изменённого. Никаких выдуманных классов — берём те состояния,
   которые app.js действительно навешивает. */
.fe-new{animation:mgRise var(--mo-3x) var(--mo-out), mgFlash 1.1s var(--mo-soft)}
.fe-new .fe-av{box-shadow:inset 0 1px 0 rgba(255,255,255,.3),
  inset 0 0 0 1px rgba(255,255,255,.2), 0 0 0 2px color-mix(in srgb, var(--ok) 45%, transparent)}
.tm.pulse .tm-av{animation:mgPop 420ms var(--mo-out)}
/* цель переноса и поле, в которое тащат картинку: спокойное свечение
   вместо мигания — рука в этот момент занята, дёргать глаз нельзя */
.col.drop{transition:box-shadow var(--mo-2x) var(--mo-out)}
.col.drop .col-h .dot{box-shadow:var(--dot-bevel), 0 0 10px 0 var(--acc)}
#cb.drop{transition:border-color var(--mo-1x) linear, background var(--mo-1x) linear}
.card.drag{transition:none}   /* под пальцем/курсором задержка читается как лаг */

/* Пульсация заблокированной задачи. Было: два оборота однослойной волны.
   Стало: три оборота с паузой — успевает попасть в поле зрения и
   гарантированно замолкает, а не жужжит фоном весь день. */
.card .blk .pulse,.ro-block .pulse{
  animation:mgHalo 2s var(--mo-soft) 3;
}
.card .blk,.ro-block{transition:color var(--mo-1x) linear}

/* Смена темы. app.js на два кадра вешает html.dp-swap и глушит ВСЕ переходы,
   поэтому «плавно перекрасить» переменные невозможно в принципе.
   Обходим с другой стороны: вуаль цвета НОВОГО фона появляется мгновенно
   (transition:none, пока класс висит), а гаснет уже своим переходом, когда
   класс снят — то есть новая тема проявляется из-под неё.
   В покое элемент прозрачный и не отрисовывается. */
body::after{
  content:''; position:fixed; inset:0; z-index:9990;
  pointer-events:none; background:var(--bg); opacity:0;
  transition:opacity var(--mo-3x) var(--mo-out);
}
html.dp-swap body::after{opacity:.55; transition:none}

/* Индикатор загрузки: вместо «бублика из рамки» — настоящая дуга с сужением.
   Крутится он же, ключевые кадры sp из app.css не трогаем. */
.spin{
  border:none;
  background:conic-gradient(from 0deg,
    transparent 0 18%, color-mix(in srgb, var(--acc) 35%, transparent) 55%, var(--acc) 100%);
  -webkit-mask:radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
  mask:radial-gradient(farthest-side, transparent calc(100% - 3px), #000 calc(100% - 3px));
}


/* ───────────────────────────────────────────────────────────────────────────
   8 · ТЕЛЕФОН. 390px: ничего не разъезжается, до всего можно дотянуться.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:760px){
  /* иконка на кнопке «следующий статус» растёт вместе с кнопкой (44px) */
  .card .qadv svg{width:17px; height:17px; stroke-width:2}
  /* конические ореолы дуг — самый дорогой эффект на мобильном GPU */
  .an-ringbox .an-ring .an-fg{
    filter:none;
  }
  .miniring circle:last-of-type{filter:none}
  /* стопка аватаров на узком экране переносится, а не выдавливает соседей */
  .avstack{flex-wrap:wrap; row-gap:6px}
  .avstack:hover .asa:hover{transform:none}
}
/* Тап-зоны у мелких кнопок-глифов. Только для сенсорного ввода: на десктопе
   раздутые зоны воровали бы клики у соседей.
   Расширяю сами кнопки, а не прозрачные «поля» поверх: у .cmt-t их две
   вплотную (правка и удаление), и наложенные зоны 44×44 перекрывались бы —
   пользователь целился бы в «изменить», а удалял комментарий. */
@media(max-width:760px) and (pointer:coarse){
  .cmt-t,.ts-x,.sub-x,.cf-x,.hr-x,.cef-x,.doc-x,.rowdel,.psx{
    width:44px; height:44px; min-width:44px; min-height:44px; padding:0;
    display:inline-flex; align-items:center; justify-content:center;
  }
  .cef-add,.doc-add{min-height:44px}
  /* «×» внутри чипа (участник проекта, метка задачи): квадрат 44px накрыл бы
     сам чип вместе с его подписью. Растим кнопку до 26px и добираем высоту
     невидимым расширением — по горизонтали чип остаётся кликабельным. */
  .pmx,.tp .tx{width:26px; height:26px; padding:0; position:relative}
  .pmx::after,.tp .tx::after{
    content:''; position:absolute; top:50%; left:50%;
    width:30px; height:44px; transform:translate(-50%,-50%);
  }
}
@media(max-width:400px){
  /* самые узкие: счётчик в меню не отбирает ширину у названия проекта */
  .navitem .cnt,.side-n{min-width:18px; padding:0 5px}
  .fe-av{width:24px; height:24px}
}


/* ───────────────────────────────────────────────────────────────────────────
   9 · «МЕНЬШЕ ДВИЖЕНИЯ». Гасим всё, что двигается в этом файле.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  /* .spin в списке НЕТ намеренно: его вращение — не украшение, а единственный
     признак, что запрос ещё идёт. Гасим у него только конический градиент. */
  .dlist .drow,.lib-list .lib,.avstack .asa,.fe-new,.nbadge,
  .tm.pulse .tm-av,.card .blk .pulse,.ro-block .pulse,
  .an-ringbox .an-ring .an-fg,
  .burnup .bu-area,.spark polygon{
    animation:none!important;
  }
  svg[viewBox="0 0 24 24"],.navitem .ni-ic,.iconbtn,.ts-ic,
  .uav,.cmt-av,.asa,.tm-av,.fe-av,.avstack .asa,
  .navitem .cnt,.side-n,.subs-n,.badge-n,.bchip i,.col-exp .n,.col-h .n,
  .prog i,.card .cprog i,.hb-t i,.hb-bar i,.an-bar i,
  .dseg,.col.drop,#cb.drop,.card .blk,.ro-block,body::after{
    transition:none!important;
  }
  .avstack:hover .asa:hover{transform:none}
  /* вуаль темы без перехода просто не успевает проявиться — смена мгновенная */
  html.dp-swap body::after{opacity:0}
  /* индикатору возвращаем базовый вид из app.css: вращение оставляем (без него
     непонятно, идёт ли запрос), а бегущий перепад яркости конуса убираем */
  .spin{
    background:none; -webkit-mask:none; mask:none;
    border:3px solid var(--line); border-top-color:var(--acc);
  }
}

/* ▲▲▲ конец: ИКОНКИ, АВАТАРЫ, МЕТКИ И ДВИЖЕНИЕ ▲▲▲ */



/* ═══ Светлые переопределения карточных поверхностей (сгенерировано) ═══ */
[data-theme="light"] .iconbtn{background:#FFFFFF;}
[data-theme="light"] .ubtn{background:#FFFFFF;}
[data-theme="light"] .udrop{background:#F9F9F9;}
[data-theme="light"] .col{background:#F3F3F3;}
[data-theme="light"] .col-h{background:#FFFFFF;}
[data-theme="light"] .col-collapsed{background:#FFFFFF;}
[data-theme="light"] .card .qadv{background:#FFFFFF;}
[data-theme="light"] .btn:not(.btn-primary):not(.btn-danger-solid){background:#FFFFFF;}
/* :not(.on) обязателен. Без него это правило имеет ту же специфичность,
   что и «.seg button.on{background:синий}» выше, но стоит ниже по файлу —
   и выбранный чип в светлой теме заливался белым поверх синего, а белая
   подпись на нём становилась невидимой (пустая рамка вместо «Задача»). */
[data-theme="light"] .seg button:not(.on),
[data-theme="light"] .schip:not(.on),
[data-theme="light"] .psel:not(.on),
[data-theme="light"] .pb-chip:not(.on),
[data-theme="light"] .mv-chip:not(.on),
[data-theme="light"] .tf:not(.on),
[data-theme="light"] .bchip:not(.on){background:#FFFFFF;}
[data-theme="light"] .ptab.on{background:linear-gradient(180deg, color-mix(in srgb, var(--acc) 20%, transparent) 0%, #F9F9F9 72%);}
[data-theme="light"] .mv-sec,
[data-theme="light"] .bdmode,
[data-theme="light"] .sub{background:#F9F9F9;}
[data-theme="light"] .dcard{background:linear-gradient(168deg,#F9F9F9 0%,#F3F3F3 100%);}
[data-theme="light"] .kpic{background:linear-gradient(160deg,#FFFFFF 0%,#F3F3F3 100%);}
[data-theme="light"] .charttip{background:#FFFFFF;}
[data-theme="light"] .pcard,
[data-theme="light"] .ptile{background:linear-gradient(165deg,#F9F9F9 0%,#F3F3F3 100%);}
[data-theme="light"] .tm{background:linear-gradient(165deg,#FFFFFF 0%,#F3F3F3 100%); border-color:rgba(159,159,159,.11);}
[data-theme="light"] .cmt-bubble{background:#FFFFFF;}
[data-theme="light"] .cmt.mine .cmt-bubble{background:#FFFFFF;}
[data-theme="light"] .cmt-attach,
[data-theme="light"] .btn-file,
[data-theme="light"] .doc-add,
[data-theme="light"] .doc-dl,
[data-theme="light"] .cmt-file,
[data-theme="light"] .cef-x,
[data-theme="light"] .cef-add{background:#FFFFFF; border-color:rgba(159,159,159,.16);}
[data-theme="light"] .tblwrap{background:#F9F9F9;}
[data-theme="light"] .inv-kpi{background:linear-gradient(160deg,#FFFFFF,#F3F3F3);}
[data-theme="light"] .inv{background:linear-gradient(170deg,#F9F9F9,#F3F3F3);}
[data-theme="light"] .hrow{background:linear-gradient(170deg,#F9F9F9,#F3F3F3);}
[data-theme="light"] .lib{background:linear-gradient(170deg,#F9F9F9,#F3F3F3);}
[data-theme="light"] .toast{background:#FFFFFF;}
[data-theme="light"] .vw-card{background:#F9F9F9; border-color:rgba(159,159,159,.18);}
[data-theme="light"] .login{background:var(--card)}
[data-theme="light"] .field input,
[data-theme="light"] .field textarea,
[data-theme="light"] .field select,
[data-theme="light"] .pb-field input,
[data-theme="light"] .pb-field textarea,
[data-theme="light"] .pb-field select,
[data-theme="light"] .stginput,
[data-theme="light"] .tagin,
[data-theme="light"] .sub-add input,
[data-theme="light"] .cmt-url,
[data-theme="light"] .cmt-edit-ta,
[data-theme="light"] .ro-edit textarea,
[data-theme="light"] .tsearch{background:#F3F3F3;}
[data-theme="light"] .rng{background:#F3F3F3;}
[data-theme="light"] .switch .sw{background:#F3F3F3;}
[data-theme="light"] .modal,
[data-theme="light"] .confirm-modal,
[data-theme="light"] .qjmodal{background:var(--card)}
[data-theme="light"] .analytics{background:var(--panel)}
[data-theme="light"] .an-bar{background:#F3F3F3;}
[data-theme="light"] .hb-t{background:#F3F3F3;}
[data-theme="light"] .prog{background:#F3F3F3;}
[data-theme="light"] .team-hero{background:var(--panel)}
[data-theme="light"] .asa,
[data-theme="light"] .fe-av{background-color:#FFFFFF!important;}
[data-theme="light"] .asa.more{background-color:#FFFFFF!important;}
[data-theme="light"] .cmt-img{background:#F3F3F3;}
[data-theme="light"] .doc-th{background:#F3F3F3;}
[data-theme="light"] .hbal{background:var(--panel)}
[data-theme="light"] .hb-bar{background:#F3F3F3;}

/* ═══════════════════════════════════════════════════════════════════════════
   КОНТРАСТ: правки по итогам аудита WCAG (скрипт обходит весь текст в обеих
   темах и считает реальный контраст к вычисленному фону).
   Блок держим В КОНЦЕ файла — он обязан побеждать по порядку каскада.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. Боковое меню всегда тёмное, в ЛЮБОЙ теме ──────────────────────────
   Правила выше красят его элементы через --tx-* / color-mix(--tx …), а эти
   токены в светлой теме становятся ЧЁРНЫМИ — на тёмной панели текст исчезал
   (замеренный контраст 1.07–1.12 при норме 4.5). Возвращаем всё, что лежит
   внутри .side, на фиксированные --side-*, не привязанные к теме. */
.side{color:var(--side-tx)}
.side .brand{color:var(--side-tx)}
.side .side-lbl{color:var(--side-tx-dim)}
.side .side-n,
.side .navitem .cnt{
  color:var(--side-tx-mut);
  background:rgba(255,255,255,.08);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);
  border-color:rgba(255,255,255,.10);
}
.side .navitem{color:var(--side-tx-mut)}
.side .navitem:hover{color:var(--side-tx); background:rgba(255,255,255,.08)}
/* Ant Menu: активный пункт — сплошная заливка colorPrimary под белым текстом */
.side .navitem.on{color:#FFFFFF; background:var(--side-card2)}
/* Значки пунктов меню. Общее правило .navitem .ni-ic красит их в --ic-rest,
   а это --tx-mut: в светлой теме почти чёрный, и на тёмной панели значки
   пропадали (замерено 1.09 при норме 3). Внутри .side — только --side-*. */
.side .navitem .ni-ic,.side .navitem .pl-ic,.side .navitem>svg{color:var(--side-tx-mut)}
.side .navitem:hover .ni-ic,.side .navitem:hover .pl-ic,.side .navitem:hover>svg{color:var(--side-tx)}
.side .navitem.on .ni-ic,.side .navitem.on svg{color:#FFFFFF}
/* акцентные пункты («Новый проект») — значок в цвет самого пункта */
.side .navitem[id="addp"] .ni-ic,.side .navitem.acc .ni-ic,
.side .navitem[data-newproject] .ni-ic,.side .navitem.more .ni-ic{color:inherit}
.side .navitem.on .cnt,
.side .navitem:hover .cnt{color:#FFFFFF; background:rgba(255,255,255,.20)}
.side .who{color:var(--side-tx-mut)}
.side .who b{color:var(--side-tx)}
.side .foot{border-top-color:var(--side-line)}
.side .psx,.side .pin{color:var(--side-tx-dim)}
.side .psx:hover{color:var(--side-tx)}
.side .navitem.more{color:var(--side-tx-mut); border-color:var(--side-line)}
.side .navitem.more:hover{color:#FFFFFF; border-color:var(--side-acc); background:rgba(255,255,255,.06)}
/* «Новый проект»: --acc (var(--acc)) на #141414 даёт всего 3.55:1.
   Берём светлую ступень синего Ant — 6.2:1, и это по-прежнему тот же синий. */
.side .navitem[id="addp"],.side .navitem.more,.side .navitem.acc{color:var(--acc-d)}
.side .brand .dot{background:var(--side-acc); color:#08121F}

/* ── 2. Зелёный «успех» как ТЕКСТ на светлой теме ─────────────────────────
   colorSuccess #52C41A — заливочный тон: на белом это 2.27:1, подписи
   «71 онлайн», «✓», «в срок» не читались. Для текста берём green-8 Ant
   (#237804, 5.8:1); заливки и дуги графиков остаются прежнего яркого тона. */
[data-theme="light"] .th-online,
[data-theme="light"] .tm-st.online,
[data-theme="light"] .fe-ic.ok,
[data-theme="light"] .bu-ot,
[data-theme="light"] .kpic.good .kpi-l,
[data-theme="light"] .hsum-c.good .hsum-ic,
[data-theme="light"] .pc-st.done{color:#237804}

/* ── 3. Бейдж LIVE ────────────────────────────────────────────────────────
   Белым по var(--danger) — 4.24:1. Красный на ступень темнее (Ant red-7) даёт 5.9:1
   и читается как тот же «тревожный красный». */
.live-card .live-badge,.feed-live{background:#CF1322}

/* ── 4. Активный пункт меню стал синим (Ant Menu) — содержимое на нём ──────
   Звёздочка и счётчик наследовали приглушённый белый: на var(--acc) это
   2.22:1 и 3.63:1. На цветной заливке приглушать нельзя. */
.side .navitem.on .pin{color:rgba(255,255,255,.85)}
.side .navitem.on .cnt{color:#FFFFFF; background:rgba(0,0,0,.28); box-shadow:none}

/* ── 5. Акцент в роли текста и мелочи на синей заливке ────────────────────
   colorPrimary у Ant рассчитан на заливку под белым текстом; как текст поверх
   поверхности он не дотягивает (3.2:1 на тёмной, 4.1:1 на белой).
   Для таких мест — отдельный --acc-tx на ступень контрастнее. */
.fe-ic.acc{color:var(--acc-tx)}
.side .navitem.on .pin{color:#FFFFFF}
.col-h .cix{color:var(--tx-mut)}


/* ═══════════════════════════════════════════════════════════════════════════
   ЭКРАН ВХОДА. Единственная страница до кабинета — здесь можно позволить
   акцентную подачу: слева тёмная брендовая колонка, справа форма на чистом
   фоне. Внутри кабинета оформление остаётся плоским по Ant.
   ═══════════════════════════════════════════════════════════════════════════ */
.login-wrap.auth{
  display:grid; grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  place-items:stretch; padding:0; min-height:100vh; background:var(--bg);
}

/* ── левая колонка: тёмная в ЛЮБОЙ теме, как боковое меню кабинета ──────── */
.auth-side{
  position:relative; overflow:hidden;
  background:#141414; color:var(--side-tx);
  display:flex; align-items:center; padding:56px clamp(32px,5vw,72px);
}
/* Один мягкий синий свет из левого верхнего угла + тонкая инженерная сетка.
   Это «витрина», а не рабочий экран, поэтому декор здесь уместен. */
.auth-side::before{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(90% 65% at 8% -8%, rgba(64,150,255,.20), transparent 62%);
}
.auth-side::after{
  content:''; position:absolute; inset:0; pointer-events:none; opacity:.5;
  background-image:linear-gradient(rgba(255,255,255,.028) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.028) 1px,transparent 1px);
  background-size:56px 56px;
  -webkit-mask-image:radial-gradient(120% 90% at 10% 0%,#000 25%,transparent 75%);
          mask-image:radial-gradient(120% 90% at 10% 0%,#000 25%,transparent 75%);
}
.auth-side-in{position:relative; z-index:1; width:100%; max-width:460px; margin-inline:auto}
.auth-side .brand{
  display:flex; align-items:center; gap:11px;
  font-size:19px; font-weight:800; color:var(--side-tx); margin-bottom:auto;
}
.auth-side .brand .dot{
  width:28px; height:28px; border-radius:8px; flex:none;
  /* панель слева тёмная в обеих темах, поэтому и синий берём тёмный (var(--acc)):
     светлый var(--acc) из светлой темы давалбелый на нём всего 4.1:1 */
  background:var(--acc); color:#FFFFFF;
  display:grid; place-items:center; font-weight:900; font-size:15px;
}
.auth-hero{margin:44px 0 34px}
.auth-hero .auth-hero-t{
  font-size:clamp(26px,2.6vw,34px); line-height:1.18; letter-spacing:-.02em;
  font-weight:800; color:#FFFFFF; margin:0 0 14px;
}
.auth-hero p{font-size:15px; line-height:1.6; color:var(--side-tx-mut); margin:0; max-width:40ch}
.auth-pts{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:18px}
.auth-pts li{display:flex; gap:14px; align-items:flex-start}
.auth-pts .ap-ic{
  width:36px; height:36px; border-radius:9px; flex:none;
  display:grid; place-items:center;
  background:rgba(64,150,255,.14); color:var(--acc-d);
  border:1px solid rgba(64,150,255,.22);
}
.auth-pts b{display:block; font-size:14.5px; font-weight:650; color:var(--side-tx); margin-bottom:3px}
.auth-pts span{display:block; font-size:13.5px; line-height:1.5; color:var(--side-tx-mut)}
.auth-side-foot{margin-top:44px; font-size:12.5px; color:var(--side-tx-dim)}

/* ── правая колонка: форма без карточки, прямо на фоне ─────────────────── */
.auth-main{display:grid; place-items:center; padding:48px 24px}
.login-wrap.auth .login{
  max-width:400px; background:none; border:none; box-shadow:none; padding:0;
}
.login-wrap.auth .login h1{font-size:27px; letter-spacing:-.02em; margin:0 0 6px}
.login-wrap.auth .login .auth-sub{font-size:14.5px; margin-bottom:28px}
.login-wrap.auth .field{margin-bottom:16px}
.login-wrap.auth .login input{padding:13px 14px; font-size:15px}
.auth-go{width:100%; justify-content:center; padding:13px 16px!important; font-size:15px; margin-top:4px}
.auth-alt{text-align:center; margin-top:18px}
.auth-alt a{font-size:13.5px; font-weight:600; color:var(--acc-tx)}
.auth-back{text-align:center; margin-top:10px}
.auth-back a{font-size:13px; color:var(--tx-mut)}
.auth-back a:hover,.auth-alt a:hover{text-decoration:underline}

/* ── показать пароль ──────────────────────────────────────────────────── */
.pw-wrap{position:relative; display:block}
.pw-wrap input{width:100%; padding-right:44px!important}
.pw-eye{
  position:absolute; right:6px; top:50%; transform:translateY(-50%);
  width:32px; height:32px; display:grid; place-items:center;
  border:none; background:none; cursor:pointer; border-radius:6px;
  color:var(--tx-dim); transition:color var(--mo-1x) var(--mo-out), background var(--mo-1x) var(--mo-out);
}
.pw-eye:hover{color:var(--tx); background:var(--ct-wash)}
.pw-eye.on{color:var(--acc-tx)}
/* включённое состояние — перечёркиваем «глаз», иначе непонятно, что он нажат */
.pw-eye.on::after{
  content:''; position:absolute; left:50%; top:50%; width:20px; height:1.8px;
  background:currentColor; border-radius:2px; transform:translate(-50%,-50%) rotate(-45deg);
}

/* ── ошибка входа: плашка в манере Ant Alert, а не голый красный текст ── */
.login-wrap.auth .err{min-height:0; margin:0 0 14px}
/* Живая область регистрируется в момент вставки текста. Если узел до этого
   display:none, часть дикторов молчит. Держим пустой блок в потоке нулевой
   высотой — вид формы не меняется, число потомков .login тоже. */
.login-wrap.auth .err:empty{display:block; min-height:0; margin:0}
.login-wrap.auth .err.on{
  display:block; padding:9px 12px; border-radius:var(--fi-r);
  font-size:13.5px; line-height:1.45; color:var(--danger);
  background:color-mix(in srgb, var(--danger) 12%, transparent);
  border:1px solid color-mix(in srgb, var(--danger) 32%, transparent);
}
/* кнопка в состоянии отправки: крутилка вместо подписи, ширина не скачет */
.auth-go.loading{color:transparent; position:relative; pointer-events:none}
.auth-go.loading::after{
  content:''; position:absolute; left:50%; top:50%; width:17px; height:17px;
  margin:-8.5px 0 0 -8.5px; border-radius:50%;
  border:2px solid rgba(255,255,255,.35); border-top-color:#FFFFFF;
  animation:authSpin .7s linear infinite;
}
@keyframes authSpin{to{transform:rotate(360deg)}}

/* ── узкий экран: брендовая колонка сжимается в шапку ─────────────────── */
@media(max-width:900px){
  /* строки задаём явно: иначе грид делит высоту поровну и шапка растягивается
     на пол-экрана пустотой, отодвигая форму вниз */
  .login-wrap.auth{grid-template-columns:1fr; grid-template-rows:auto 1fr; min-height:100vh}
  .auth-side{padding:26px 22px; align-items:flex-start}
  .auth-side-in{max-width:none}
  .auth-side .brand{margin-bottom:0}
  /* на телефоне ценностные блоки только удлиняют путь до формы */
  .auth-hero,.auth-pts,.auth-side-foot{display:none}
  .auth-main{padding:32px 22px 48px}
}
@media(prefers-reduced-motion:reduce){
  .auth-go.loading::after{animation-duration:1.6s}
}

/* ═══════════════════════════════════════════════════════════════════════
   ИСПРАВЛЕНИЯ ДЕФЕКТОВ (не смена оформления — только починка).
   Каждый пункт подтверждён замером computed-стилей в браузере.
   ═══════════════════════════════════════════════════════════════════════ */

/* 1. Токен --on-danger используется, но нигде не объявлен. В CSS невалидный
      var() убивает ВСЮ декларацию целиком, а не одно свойство — поэтому
      правила у .btn-danger-solid и .nbadge не применялись, и заявленный
      в комментарии контраст 6.14:1 по факту не работал (текст оставался
      наследуемым белым 0.85). Палитра Ant Design v5: --danger var(--danger). */
:root{ --on-danger:#FFFFFF; }

/* 2. Класс .sub в кабинете означает ТРИ разные вещи: подзаголовок на входе,
      строку счёта и строку подзадачи. Панельное оформление задумано для
      подзадачи (у неё есть data-sub), но красило и подзаголовок — на экране
      входа он выглядел как пустое поле ввода. */
.login .sub, .login-wrap .sub, .inv .sub{
  background:none;border:none;padding:0;box-shadow:none;border-radius:0;
}

/* 3. «Отключено» и «грузится» были одним состоянием: любая disabled-кнопка
      прятала подпись (color:transparent) и крутила волчок. Человек видел
      вечную загрузку там, где действие просто недоступно. */
.btn:disabled,.btn[disabled]{color:inherit;opacity:.45;cursor:not-allowed}
.btn:disabled::after,.btn[disabled]::after{content:none}
.btn.is-loading,.btn[aria-busy="true"]{color:transparent;pointer-events:none;position:relative}
.btn.is-loading::after,.btn[aria-busy="true"]::after{
  content:'';position:absolute;inset:0;margin:auto;width:16px;height:16px;border-radius:50%;
  border:2px solid color-mix(in srgb,currentColor 22%,transparent);
  border-top-color:var(--tx);animation:sp .7s linear infinite;
}
@media(prefers-reduced-motion:reduce){
  .btn.is-loading::after,.btn[aria-busy="true"]::after{animation-duration:1.6s}
}

/* 4. Смысловые состояния перебивались базовыми правилами по специфичности:
      у .card .meta .due она (0,3,0), у .due.over — (0,2,0). Из-за этого
      «просрочено» красилось приглушённым серым, а «высокий приоритет» —
      обычным серым: тревога и срочность не читались вообще.
      Один цвет — один смысл: красный тревога, охра срочность. */
.card .meta .due.over, .chip.due.over, .due.over{
  color:var(--danger);
  background:color-mix(in srgb,var(--danger) 14%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--danger) 32%,transparent);
  font-weight:600;
}
.card .meta .due.today, .chip.due.today, .due.today{
  color:var(--warn);
  background:color-mix(in srgb,var(--warn) 14%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--warn) 32%,transparent);
  font-weight:600;
}
.card .meta .pchip.high, .chip.hi, .pchip.high{
  color:var(--warn);
  background:color-mix(in srgb,var(--warn) 14%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--warn) 34%,transparent);
  font-weight:700;
}

/* ═══════════════════════════════════════════════════════════════════════
   ПАЛИТРА ЛЕНДИНГА В КАБИНЕТЕ
   Источник истины — site/index.html: тёплый уголь #0C0B09, панели #16140F,
   текст #F0ECE3, акцент #FF5A32 / #FF8256, бирюза #4FE3C6, скругление 14px,
   волосяные линии из тёплого белого, тень 0 40px 80px -40px.
   Клиент приходит с лендинга — кабинет должен читаться как его продолжение,
   а не как другой продукт.

   Контраст (посчитан): #F0ECE3 на #0C0B09 — 15.9:1; #9C9488 — 7.0:1;
   тёмный текст #1A0B05 на оранжевой заливке — 5.9:1 (белый дал бы 3.2:1,
   поэтому на акценте текст ТЁМНЫЙ, как на кнопках лендинга).
   ═══════════════════════════════════════════════════════════════════════ */
:root, [data-theme="dark"]{
  /* поверхности */
  --bg:#0C0B09; --panel:#16140F; --card:#1D1A14; --card2:#232019;
  /* текст */
  --tx:#F0ECE3; --tx-mut:#9C9488; --tx-dim:#8A8276;
  /* акцент — оранжевый лендинга */
  --acc:#FF5A32; --acc-d:#FF8256; --acc-2:#FF8256; --acc-tx:#FF8256;
  --acc-on-fill:#FF5A32; --hi:#FF5A32;
  --on-acc:#1A0B05;              /* тёмный по оранжевому: 5.9:1 против 3.2:1 у белого */
  --on-danger:#2A0A06;
  /* линии — тёплый белый на просвет, как на лендинге */
  --line:rgba(255,246,232,.09); --line2:rgba(255,246,232,.17); --edge:rgba(255,246,232,.30);
  --glow:rgba(255,90,50,.28);
  /* смысловые */
  --ok:#4FE3C6; --warn:#F0B429; --danger:#FF6B5A;
  /* типы задач */
  --t-task:#9C9488; --t-feature:#FF5A32; --t-bug:#FF6B5A;
  --t-design:#B48CFF; --t-content:#F0B429; --t-deploy:#4FE3C6;
  /* внутренние переменные темы — на оранжевый строй */
  --mn-fill-1:#FF6A3F; --mn-fill-2:#E24E1B; --mn-fill-edge:#FF8256;
  --mn-glow:rgba(255,90,50,.40); --mn-glow-soft:rgba(255,90,50,.16);
  --mn-teal:#4FE3C6; --mn-red:#FF6B5A;
  --mn-hair:rgba(255,246,232,.07);
  --mn-num:linear-gradient(135deg,#FFF6EC 0%,#FFB08C 100%);
  --mn-sky-1:rgba(255,90,50,.15); --mn-sky-2:rgba(79,227,198,.05);
  --mn-sky-3:rgba(255,90,50,.20); --mn-sky-4:rgba(79,227,198,.07);
  /* глубина: одна мягкая дальняя тень, как на лендинге */
  --dp-e1:0 1px 2px rgba(0,0,0,.5), 0 2px 8px -4px rgba(0,0,0,.6);
  --dp-e2:0 4px 14px -6px rgba(0,0,0,.62), 0 18px 36px -20px rgba(0,0,0,.7);
  --dp-e3:0 8px 24px -10px rgba(0,0,0,.66), 0 30px 60px -28px rgba(0,0,0,.78);
  --dp-e4:0 40px 80px -40px rgba(0,0,0,.82), 0 2px 0 rgba(255,246,232,.04);
  --dp-rim:inset 0 1px 0 rgba(255,246,232,.05);
  --dp-rim-s:inset 0 1px 0 rgba(255,246,232,.09);
  --dp-trough:#0A0907; --dp-lift:#221E17; --dp-lid:#16140F;
  --dp-glass:rgba(12,11,9,.74);   /* --topbar-bg лендинга */
  --dp-focus:#FF8256; --dp-glow:var(--mn-glow-soft);
  /* скругление лендинга */
  --r:14px;
}

/* Скругления к масштабу лендинга: у него 14px, у кабинета было 8px —
   на одинаковых карточках разница читается как «другой продукт». */
.pcard,.dcard,.kpic,.inv,.inv-kpi,.hbal,.lib,.ptile,.tm,.analytics,
.col,.card,.modal,.tsearch,.emptybox,.docs-sec,.login,.auth-side{border-radius:14px}
.btn,.field input,.field textarea,.field select,.chip,.tag{border-radius:10px}
.pchip,.due,.tid,.tno,.nbadge{border-radius:6px}

/* Тёплое свечение над рабочей областью — как радиальные подсветки лендинга */
.main::before{
  background:
    radial-gradient(90% 150% at 20% -35%, var(--mn-sky-1), transparent 62%),
    radial-gradient(70% 130% at 85% -30%, var(--mn-sky-2), transparent 60%);
}

/* ── Семейство --ct-* (кнопки, крышки, полосы) — на палитру лендинга.
   Оно объявлено отдельно от основных токенов, поэтому переопределяем явно,
   иначе первичная кнопка остаётся синей при оранжевом акценте. ── */
:root, [data-theme="dark"], :root[data-theme="dark"]{
  --ct-face-a:#1D1A14; --ct-face-b:#16140F;
  --ct-face-h-a:#232019; --ct-face-h-b:#1D1A14;
  --ct-fill-a:#FF6A3F; --ct-fill-b:#E24E1B;
  --ct-fill-h-a:#FF8256; --ct-fill-h-b:#F05A22;
  --ct-on:#1A0B05;                       /* тёмный по оранжевому — 5.9:1 */
  --ct-halo:0 8px 26px -10px rgba(255,90,50,.55);
  --ct-lid-a:#1D1A14; --ct-lid-b:#16140F;
  --ct-glass:rgba(12,11,9,.74);
  --side-tx:#F0ECE3;
}

/* Витрина входа: тёплый уголь вместо чёрного и оранжевое свечение вместо
   синего — иначе первый экран спорит с лендингом, с которого пришёл клиент. */
.auth-side{background:linear-gradient(180deg,#16140F,#0F0D0A)}
.auth-side::before{
  background:
    radial-gradient(90% 65% at 8% -8%, rgba(255,90,50,.20), transparent 62%),
    radial-gradient(70% 60% at 100% 100%, rgba(79,227,198,.07), transparent 60%);
}
.auth-side::after{
  background-image:linear-gradient(rgba(255,246,232,.028) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,246,232,.028) 1px,transparent 1px);
}
.auth-side .brand .dot{
  background:linear-gradient(140deg,#FF8256,#E24E1B);color:#1A0B05;
  box-shadow:0 6px 20px -6px rgba(255,90,50,.7), inset 0 1px 0 rgba(255,255,255,.3);
}
.ap-ic{background:rgba(255,90,50,.13);border-color:rgba(255,90,50,.26);color:var(--acc-d)}

/* ── Тревога против акцента.
   На лендинге палитра из оранжевого и бирюзы, красного там нет. Если взять
   «опасность» тоже тёплой, кнопка удаления становится неотличима от главной —
   а это разные по последствиям действия. Уводим тревогу в розово-красный:
   тон явно другой, а на тёмном фоне читается лучше оранжевого.
   Контраст: #FF6E7A на #0C0B09 — 6.8:1 (текст);
             белый на заливке #D32F3F — 5.2:1 (кнопка, счётчик). ── */
:root, [data-theme="dark"], :root[data-theme="dark"]{
  --danger:#FF6E7A;        /* текст, рамки, метки просрочки */
  --t-bug:#FF6E7A;
  --mn-red:#D32F3F;        /* заливка */
  --on-danger:#FFFFFF;
}
.btn-danger-solid,.btn-danger-solid:hover{
  background:linear-gradient(180deg,#E13B4A,#C42A38);
  border-color:#B02430;color:#FFFFFF;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), var(--dp-e1);
}
.nbadge{background:#D32F3F;color:#FFFFFF}

/* ── Семейство --side-* (боковое меню) объявлено отдельно от основных токенов,
   поэтому синий держался в нём даже после смены палитры: активный пункт
   заливался colorPrimary Ant Design. Переводим на оранжевый лендинга.
   Контраст: тёмный текст #1A0B05 на заливке #FF5A32 — 5.9:1. ── */
:root, [data-theme="dark"], :root[data-theme="dark"]{
  --side-tx:#F0ECE3;
  --side-tx-mut:#9C9488;
  --side-tx-dim:#8A8276;
  --side-line:rgba(255,246,232,.09);
  --side-card:#1D1A14;
  --side-card2:rgba(255,90,50,.16);   /* подложка активного пункта, не заливка */
  --side-acc:#FF8256;
}
/* Активный пункт: мягкая оранжевая подложка + грань слева, а не сплошная
   заливка. Сплошной оранжевый в меню перетягивал на себя внимание с доски. */
.side .navitem.on, .navitem.on{
  background:linear-gradient(90deg, rgba(255,90,50,.20), rgba(255,90,50,.05));
  color:#FFF3EC;
  box-shadow:inset 2px 0 0 var(--acc), 0 0 22px -12px rgba(255,90,50,.6);
}
.navitem.on .cnt{background:rgba(255,90,50,.22); color:#FFD9C9}
.side .brand .dot{
  background:linear-gradient(140deg,#FF8256,#E24E1B); color:#1A0B05;
  box-shadow:0 5px 16px -6px rgba(255,90,50,.65), inset 0 1px 0 rgba(255,255,255,.28);
}

/* ═══════════════════════════════════════════════════════════════════════
   СВЕТЛАЯ ТЕМА — из светлой палитры лендинга (кремовая бумага).
   Источник истины: блок [data-theme="light"] в site/index.html.
   Селектор :root[data-theme="light"] (0,2,0) специально сильнее групповых
   правил выше по файлу, иначе тёмные значения протекают в светлую тему.

   Контраст (посчитан): #26211A на #F4EDE1 — 13.6:1; #564D40 — 7.4:1;
   #645B4F — 5.9:1; белый на акценте #D93C13 — 4.8:1; белый на
   тревоге #C81E3A — 5.8:1; #0E9E86 на кремовом — 3.4:1 (только заливки
   и графика, для текста берём затемнённый #0B7A66 — 4.9:1).
   ═══════════════════════════════════════════════════════════════════════ */
:root[data-theme="light"]{
  /* поверхности — кремовая бумага лендинга */
  --bg:#F4EDE1; --panel:#FDFAF4; --card:#FDFAF4; --card2:#F1E9DA;
  /* текст */
  --tx:#26211A; --tx-mut:#564D40; --tx-dim:#645B4F;
  /* акцент — на светлом оранжевый берём глубже, иначе слепит и не читается */
  --acc:#D93C13; --acc-d:#F0592B; --acc-2:#F0592B; --acc-tx:#B8300E;
  --acc-on-fill:#D93C13; --hi:#D93C13;
  --on-acc:#FFFFFF;              /* белый по #D93C13 — 4.8:1 */
  /* линии — тёплый коричневый на просвет, как на лендинге */
  --line:rgba(58,42,24,.13); --line2:rgba(58,42,24,.22); --edge:rgba(58,42,24,.38);
  --glow:rgba(217,60,19,.18);
  /* смысловые */
  --ok:#0B7A66; --warn:#9A6A0B; --danger:#C81E3A; --on-danger:#FFFFFF;
  /* типы задач — затемнены под светлый фон */
  --t-task:#645B4F; --t-feature:#D93C13; --t-bug:#C81E3A;
  --t-design:#6D28D9; --t-content:#9A6A0B; --t-deploy:#0B7A66;
  /* внутренние переменные темы */
  --mn-fill-1:#E4491C; --mn-fill-2:#C33410; --mn-fill-edge:#F0592B;
  --mn-glow:rgba(217,60,19,.30); --mn-glow-soft:rgba(217,60,19,.12);
  --mn-teal:#0B7A66; --mn-red:#C81E3A;
  --mn-hair:rgba(58,42,24,.08);
  --mn-num:linear-gradient(135deg,#2A241C 0%,#B8300E 100%);
  --mn-sky-1:rgba(217,60,19,.10); --mn-sky-2:rgba(14,158,134,.06);
  --mn-sky-3:rgba(217,60,19,.13); --mn-sky-4:rgba(14,158,134,.07);
  /* глубина: тень ТЁПЛАЯ (сепия), не чёрная — на кремовом чёрный даёт грязь */
  --dp-e1:0 1px 2px rgba(90,60,25,.07), 0 2px 8px -4px rgba(90,60,25,.10);
  --dp-e2:0 4px 14px -6px rgba(90,60,25,.12), 0 18px 36px -20px rgba(90,60,25,.16);
  --dp-e3:0 8px 24px -10px rgba(90,60,25,.13), 0 30px 60px -28px rgba(90,60,25,.20);
  --dp-e4:0 30px 60px -32px rgba(90,60,25,.24), 0 2px 0 rgba(255,255,255,.6);
  --dp-rim:inset 0 1px 0 rgba(255,255,255,.75);
  --dp-rim-s:inset 0 1px 0 #FFFFFF;
  --dp-well:inset 0 2px 8px -2px rgba(90,60,25,.12);
  --dp-face:none;
  --dp-trough:#EDE4D4; --dp-lift:#FFFFFF; --dp-lid:#FDFAF4;
  --dp-glass:rgba(244,237,225,.84);      /* --topbar-bg лендинга */
  --dp-scr:rgba(58,42,24,.34);
  --dp-veil:radial-gradient(120% 90% at 50% 0, rgba(217,60,19,.14), rgba(58,42,24,.42));
  --dp-focus:#D93C13; --dp-glow:var(--mn-glow-soft);
  /* кнопки и крышки */
  --ct-face-a:#FDFAF4; --ct-face-b:#F6F0E5;
  --ct-face-h-a:#FFFFFF; --ct-face-h-b:#FAF5EC;
  --ct-fill-a:#E4491C; --ct-fill-b:#C33410;
  --ct-fill-h-a:#F0592B; --ct-fill-h-b:#D33F16;
  --ct-on:#FFFFFF;
  --ct-halo:0 8px 22px -10px rgba(217,60,19,.42);
  --ct-lid-a:#FDFAF4; --ct-lid-b:#F4EDE1;
  --ct-glass:rgba(253,250,244,.86);
  /* боковое меню */
  --side-tx:#26211A; --side-tx-mut:#564D40; --side-tx-dim:#645B4F;
  --side-line:rgba(58,42,24,.13); --side-line-s:rgba(58,42,24,.26); --side-well:rgba(58,42,24,.055); --side-well-sh:inset 0 1px 2px rgba(58,42,24,.07); --side-card:#FDFAF4;
  --side-card2:rgba(217,60,19,.12); --side-acc:#B8300E;
}

/* Кнопка удаления и счётчик в светлой: белый по глубокому красному */
:root[data-theme="light"] .btn-danger-solid,
:root[data-theme="light"] .btn-danger-solid:hover{
  background:linear-gradient(180deg,#D2263F,#B01A31);
  border-color:#96162A;color:#FFFFFF;
}
:root[data-theme="light"] .nbadge{background:#C81E3A;color:#FFFFFF}

/* Активный пункт меню в светлой — та же логика, что в тёмной */
:root[data-theme="light"] .side .navitem.on,
:root[data-theme="light"] .navitem.on{
  background:linear-gradient(90deg, rgba(217,60,19,.14), rgba(217,60,19,.04));
  color:#8F2408;
  box-shadow:inset 2px 0 0 var(--acc), 0 0 20px -14px rgba(217,60,19,.5);
}
:root[data-theme="light"] .navitem.on .cnt{background:rgba(217,60,19,.16); color:#8F2408}
:root[data-theme="light"] .side .brand .dot{
  background:linear-gradient(140deg,#F0592B,#C33410); color:#FFFFFF;
  box-shadow:0 5px 14px -6px rgba(217,60,19,.5), inset 0 1px 0 rgba(255,255,255,.4);
}

/* Витрина входа в светлой — кремовая, свечение мягче */
:root[data-theme="light"] .auth-side{background:linear-gradient(180deg,#FDFAF4,#F1E8D9)}
:root[data-theme="light"] .auth-side::before{
  background:
    radial-gradient(90% 65% at 8% -8%, rgba(217,60,19,.13), transparent 62%),
    radial-gradient(70% 60% at 100% 100%, rgba(14,158,134,.07), transparent 60%);
}
:root[data-theme="light"] .auth-side::after{
  background-image:linear-gradient(rgba(58,42,24,.05) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(58,42,24,.05) 1px,transparent 1px);
}
:root[data-theme="light"] .ap-ic{
  background:rgba(217,60,19,.10);border-color:rgba(217,60,19,.24);color:#B8300E;
}

/* ── Сайдбар был зашит #141414, поэтому в светлой теме оставался тёмным,
   а текст на нём — тёмным по тёмному. Переводим на токены: в тёмной теме
   вид тот же, в светлой он становится кремовым. ── */
.side{background:var(--side-card); border-right:1px solid var(--side-line)}
:root[data-theme="light"] .side{
  background:linear-gradient(180deg,#FDFAF4,#F4EDE1);
}
:root[data-theme="light"] .side .navitem{color:var(--side-tx-mut)}
:root[data-theme="light"] .side .navitem:hover{color:var(--side-tx); background:rgba(58,42,24,.05)}
:root[data-theme="light"] .side .brand{color:var(--side-tx)}
:root[data-theme="light"] .side-n{background:rgba(58,42,24,.09); color:var(--side-tx-mut)}
:root[data-theme="light"] .side-projects::-webkit-scrollbar-thumb{background:rgba(58,42,24,.22)}
:root[data-theme="light"] .side-projects::-webkit-scrollbar-thumb:hover{background:rgba(58,42,24,.34)}

/* ▼▼▼ ЭКРАНЫ: ДОСКА И КАРТОЧКИ ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   СЕМЕЙСТВО «ДОСКА И КАРТОЧКИ ЗАДАЧ» · палитра лендинга roboweb.team
   Подключать ПОСЛЕ app.css и theme.css.

   Что здесь чинится (найдено чтением app.css / theme.css / app.js):
   ▸ поверхности доски остались от Ant-темы холодными серыми литералами
     (.col var(--card2), .col-h #3A3A3A, .col-collapsed var(--card2), .tsearch var(--card2),
     .tf var(--line2), .an-bar var(--card2), .tag / .pchip / .due rgba(159,159,159,…),
     хвост градиента готовности #DADADA). На тёплом угле var(--bg) они читаются
     как «другой продукт» — ровно то, от чего уходили;
   ▸ колонка «Пожелания» была переведена на серый #A2A2A2, хотя точка её
     статуса приходит из app.js как var(--t-design) — колонка потеряла тон;
   ▸ контраст мелкого текста считали к фону страницы, а карточка стоит на
     --dp-lift var(--card2): там --tx-dim даёт 4.37:1 — ниже нормы даже для 12px;
   ▸ смысловые состояния снова перебивались базой по специфичности: .due.soon
     объявлен как (0,2,0), а .card .meta .due — (0,3,0), и «завтра» ничем не
     отличалось от любой другой даты;
   ▸ .sub значит три разные вещи; на карточке счётчик подзадач получал
     панельное оформление подзадачи из модалки и вырастал в серую плашку;
   ▸ радиус доски вырос до 14px, а вложенные элементы (крышка колонки, полоса
     готовности) остались на 8px и выходили за скруглённые углы.

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

   Контраст (посчитан к реальной подложке элемента, а не к фону страницы):
     --tx      на карточке var(--card2) — 14.07:1
     --tx-mut  на карточке        — 5.53:1   (было --tx-dim 4.37:1)
     --tx-mut  на колонке var(--panel) — 6.14:1
     --danger  на карточке        — 6.13:1
     --warn    на карточке        — 8.90:1
     --ok      на карточке        — 10.37:1
     --t-design на колонке        — 7.13:1
     --on-acc  на оранжевой заливке — 6.18:1 (белый дал бы 3.2:1)
     --bg      на бирюзовой заливке — 12.31:1
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   0 · ТОКЕНЫ СЕМЕЙСТВА
   Свой префикс --bd-* (грепом по app.css, theme.css и app.js совпадений 0),
   чтобы ничего не перебить и ничего не «занять» у соседних семейств.
   Все значения выведены из палитры лендинга, собственных цветов не заводим.
   ─────────────────────────────────────────────────────────────────────────── */
:root{
  /* Радиусы. Лендинг: 14px у панелей и карточек. Вложенное внутрь рамки
     скругляется на её толщину меньше, иначе между рамкой и заливкой на дуге
     остаётся заметный серп. */
  --bd-r:14px;          /* колонка, карточка, панель сводки */
  --bd-r-in:13px;       /* изнутри 1px рамки — крышка и дно колонки */
  --bd-rail:4px;        /* толщина полосы типа задачи слева у карточки */
  --bd-r-rail:10px;     /* изнутри этой полосы — левый нижний угол карточки */

  /* Материал мелких плашек (метка, чип приоритета, срок). Тёплый белый на
     просвет вместо серого литерала: тон подхватывает подложку, на какой бы
     ступени поверхностей плашка ни стояла. */
  --bd-chip:color-mix(in srgb, var(--tx) 7%, transparent);
  --bd-chip-line:color-mix(in srgb, var(--tx) 6%, transparent);

  /* Колонка «Пожелания». В app.js её точка приходит как var(--t-design),
     поэтому и рамка, и подсказка, и кнопка добавления берут тот же тон —
     иначе колонка выглядит как две разные колонки. */
  --bd-wish:var(--t-design);

  /* Ползунки прокрутки доски и колонок. Оранжевый им не положен: полос на
     экране до семи, и «здесь ты» перестало бы что-либо значить. Тёплая
     нейтраль в покое, акцент — только под курсором. */
  --bd-bar:color-mix(in srgb, var(--tx) 22%, transparent);
  --bd-bar-h:color-mix(in srgb, var(--acc) 62%, var(--edge));
}


/* ───────────────────────────────────────────────────────────────────────────
   1 · ПОЛОТНО ДОСКИ · .board-wrap / .col-body
   ─────────────────────────────────────────────────────────────────────────── */
/* Горизонтальная полоса остаётся толстой и всегда видимой (на macOS тонкая
   прячется, и кажется, что колонки кончились). Меняем только материал. */
.board-wrap{scrollbar-color:var(--bd-bar) transparent}
.board-wrap::-webkit-scrollbar-thumb{
  background:var(--bd-bar);
  border:4px solid transparent; background-clip:padding-box;
  border-radius:99px; min-width:80px;
  transition:background-color var(--mo-1x) var(--mo-out);
}
.board-wrap::-webkit-scrollbar-thumb:hover{background:var(--bd-bar-h)}

/* Вертикальная прокрутка внутри колонки — тоньше и тише: она появляется
   в каждой колонке сразу, и семь оранжевых полос забивали бы акцент. */
.col-body{scrollbar-color:var(--bd-bar) transparent}
.col-body::-webkit-scrollbar-thumb{
  background:var(--bd-bar);
  border:3px solid transparent; background-clip:padding-box;
  border-radius:99px; min-height:36px;
}
.col-body::-webkit-scrollbar-thumb:hover{background:var(--bd-bar-h)}


/* ───────────────────────────────────────────────────────────────────────────
   2 · КОЛОНКА · .col / .col-h / .col-body
   Метафора прежняя: колонка — корыто, шапка — крышка, карточка — фишка.
   Новое только то, что все три ступени теперь тёплые и идут по светлоте
   вверх: страница var(--bg) → колонка --panel → крышка --card → карточка.
   ─────────────────────────────────────────────────────────────────────────── */
.col{
  background:var(--panel);                 /* было var(--card2) — холодный серый */
  border-color:var(--line);
  border-radius:var(--bd-r);
  box-shadow:var(--dp-well), 0 1px 0 rgba(255,246,232,.03);
}

/* Крышка колонки. Радиус обязателен: у .col нет overflow:hidden, и заливка
   шапки квадратными углами вылезала за скруглённый верх колонки. */
.col-h{
  background:linear-gradient(180deg, var(--card2), var(--card));
  border-bottom-color:var(--line2);
  border-radius:var(--bd-r-in) var(--bd-r-in) 0 0;
  box-shadow:inset 0 1px 0 rgba(255,246,232,.06), 0 1px 0 rgba(0,0,0,.45);
}
.col-h .t{color:var(--tx)}
/* Графа колонки («00», «01»). Была на --tx-mut, но с opacity .75: смесь
   с подложкой даёт ~4.0:1 при кегле 10px. Прозрачность снимаем. */
.col-h .cix{color:var(--tx-mut); opacity:1}
/* Дно колонки скругляем тоже: при прокрутке карточка доезжает до самого низа
   и без этого срезала бы угол корыта прямым краем. */
.col-body{border-radius:0 0 var(--bd-r-in) var(--bd-r-in)}

/* Колонка «Пожелания» — единственная, куда пишет клиент. Её тон приходит
   из app.js (var(--t-design)); повторяем его в рамке и крышке, чтобы колонка
   читалась как отдельный вход, а не как сбой темы. Было: серый #A2A2A2. */
.col-wish{
  border-color:color-mix(in srgb, var(--bd-wish) 30%, var(--line));
  box-shadow:var(--dp-well),
             inset 0 0 0 1px color-mix(in srgb, var(--bd-wish) 8%, transparent);
}
.col-wish .col-h{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--bd-wish) 10%, var(--card2)),
    color-mix(in srgb, var(--bd-wish) 5%,  var(--card)));
  border-bottom-color:color-mix(in srgb, var(--bd-wish) 26%, var(--line));
}

/* Своя колонка админа: пунктир крышки задан в базе — здесь только цвет,
   чтобы пунктир не тонул в заливке. */
.col-custom .col-h{border-bottom-color:var(--line2)}

/* Цель переноса. Спокойная подсветка, а не мигание: рука в этот момент занята
   карточкой, дёргать глаз нельзя. Оранжевый здесь уместен — это «сюда». */
.col.drop{
  outline:2px dashed var(--acc); outline-offset:-4px;
  border-color:color-mix(in srgb, var(--acc) 45%, var(--line2));
  background:color-mix(in srgb, var(--acc) 5%, var(--panel));
  box-shadow:var(--dp-e2),
             inset 0 0 0 1px color-mix(in srgb, var(--acc) 40%, transparent),
             inset 0 26px 56px -30px color-mix(in srgb, var(--acc) 70%, transparent);
}
.col.drop .col-h{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--acc) 14%, var(--card2)),
    color-mix(in srgb, var(--acc) 6%,  var(--card)));
  border-bottom-color:color-mix(in srgb, var(--acc) 34%, var(--line));
}

/* ── свёрнутая колонка · .col-collapsed / .col-exp ──
   Свёрнутая колонка — это и есть крышка, поставленная на ребро: тот же
   материал, что у .col-h, иначе на доске возникает лишняя ступень серого. */
.col-collapsed{
  background:linear-gradient(180deg, var(--card2), var(--card));
  border-color:var(--line);
  border-radius:var(--bd-r);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.col-exp{border-radius:var(--bd-r); transition:background var(--mo-1x) var(--mo-out)}
.col-exp:hover{background:var(--ct-wash)}      /* было rgba(159,159,159,.10) */
/* В свёрнутом виде вертикальная подпись — единственный опознавательный знак
   колонки, поэтому она полноконтрастная, а не приглушённая. */
.col-exp .col-vt{color:var(--tx)}
.col-collapsed.drop{
  border-color:var(--acc);
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--acc) 16%, var(--card2)),
    color-mix(in srgb, var(--acc) 8%,  var(--card)));
}


/* ───────────────────────────────────────────────────────────────────────────
   3 · ИНСТРУМЕНТЫ КОЛОНКИ · .col-tool
   Векторные маски «‹» и «⚙» заданы в theme.css — здесь только материал.
   ─────────────────────────────────────────────────────────────────────────── */
.col-tool{color:var(--tx-mut); border-radius:9px}
.col-tool:hover{
  color:var(--tx);
  background:var(--ct-wash);
  border-color:color-mix(in srgb, var(--acc) 30%, transparent);
}
.col-tool:active{background:var(--ct-wash-s)}


/* ───────────────────────────────────────────────────────────────────────────
   4 · КАРТОЧКА · .card
   Главный объект экрана. Три требования: тип виден с расстояния, тревога
   не путается с акцентом, при наведении карточка ощущается поднятой.
   ─────────────────────────────────────────────────────────────────────────── */
.card{
  background-color:var(--dp-lift);
  border-color:var(--line);
  border-radius:var(--bd-r);
  /* Полоса типа — левая грань карточки. 4px вместо 3px: на скруглении 14px
     три пикселя съедаются дугой, и цвет перестаёт читаться через всю доску. */
  border-left-width:var(--bd-rail);
  border-left-style:solid;
  border-left-color:var(--tc, var(--t-task));
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:transform var(--mo-2x) var(--mo-out),
             box-shadow var(--mo-2x) var(--mo-out),
             border-color var(--mo-1x) var(--mo-out),
             background-color var(--mo-1x) var(--mo-out);
}

/* Подъём. Тень уходит вниз и вширь, к ней добавляется кант в цвете типа —
   карточка буквально отрывается от корыта, а не просто светлеет. */
.card:hover{
  transform:translateY(-3px);
  background-color:color-mix(in srgb, var(--tx) 3%, var(--dp-lift));
  border-color:color-mix(in srgb, var(--tc, var(--acc)) 38%, var(--line2));
  border-left-color:var(--tc, var(--acc));
  box-shadow:
    var(--dp-e3), var(--dp-rim-s),
    0 0 0 1px color-mix(in srgb, var(--tc, var(--acc)) 22%, transparent),
    0 22px 40px -26px color-mix(in srgb, var(--tc, var(--acc)) 65%, #000);
}
/* Нажатие возвращает карточку на место — щелчок «фишкой по столу». */
.card:active{transform:translateY(0); box-shadow:var(--dp-e1), var(--dp-rim)}

/* Карточка в руке. Оставшийся на месте оригинал становится гнездом, куда она
   вернётся, если отпустить мимо. Тень снимаем: поднятой сейчас выглядит не он,
   а перетаскиваемый снимок. Полосу типа оставляем сплошной — по ней видно,
   какую именно карточку несут. */
.card.drag{
  opacity:.55;
  background-color:var(--dp-trough);
  border-style:dashed;
  border-color:var(--edge);
  border-left-style:solid;
  border-left-color:color-mix(in srgb, var(--tc, var(--acc)) 55%, transparent);
  box-shadow:none;
  transform:none;
}

/* Заблокировано = мяч на стороне клиента. Тревога розово-красная и никогда
   не оранжевая: «заблокировано» и «первичное действие» не должны выглядеть
   одинаково. Специфичность (0,2,0) — ровно чтобы перебить базовую .card. */
.card.blocked{
  border-color:color-mix(in srgb, var(--danger) 50%, var(--line));
  box-shadow:var(--dp-e1), var(--dp-rim),
             inset 0 0 0 1px color-mix(in srgb, var(--danger) 40%, transparent);
}
/* (0,3,0): иначе .card:hover выше по файлу снял бы тревожный кант при наведении */
.card.blocked:hover{
  border-color:color-mix(in srgb, var(--danger) 70%, var(--line2));
  box-shadow:var(--dp-e3), var(--dp-rim-s),
             inset 0 0 0 1px color-mix(in srgb, var(--danger) 45%, transparent),
             0 22px 40px -26px color-mix(in srgb, var(--danger) 55%, #000);
}

/* Шапка блокировки. Была на -11px/-13px при padding карточки 12px: справа
   налезала на волосок рамки, слева срезала полосу типа. Выравниваем ровно
   по внутренней границе и скругляем по внутренним радиусам. */
.card .blk{
  margin:-12px -12px 9px;
  padding:5px 12px;
  padding-right:38px;                       /* место под .qadv в правом углу */
  background:color-mix(in srgb, var(--danger) 15%, transparent);
  border-bottom:1px solid color-mix(in srgb, var(--danger) 30%, transparent);
  border-radius:var(--bd-r-rail) var(--bd-r-in) 0 0;
  color:var(--danger);
}
.card .blk .pulse{background:var(--danger)}

/* Полоса приоритета поверх карточки. Была оранжевой — то есть высокий
   приоритет красился акцентом, тогда как чип «⚑ Высокий» уже охра.
   Один смысл — один цвет: срочность всегда охра. */
.pr-high{
  background:linear-gradient(90deg,
    var(--warn), color-mix(in srgb, var(--warn) 35%, transparent));
  box-shadow:0 0 10px -3px var(--warn);
}

/* Номер задачи. Раньше стоял в акцентной рамке — оранжевый прямоугольник
   на КАЖДОЙ из двух сотен карточек, после чего «здесь ты» переставало
   что-либо значить. В покое номер нейтральный, акцент приходит на наведение
   карточки: тогда он и подсказывает «это можно выделить и скопировать». */
.card .tid{
  color:var(--tx-mut);
  background:var(--bd-chip);
  border-color:var(--line2);
  border-radius:5px;
}
.card:hover .tid{
  color:var(--acc-d);
  background:color-mix(in srgb, var(--acc) 12%, transparent);
  border-color:color-mix(in srgb, var(--acc) 42%, transparent);
}
/* .qadv стоит абсолютно в правом верхнем углу и на наведении накрывал этап. */
.card .chead{padding-right:30px}

/* Этап. 11px капслоком при --tx-dim и opacity .85 давал ~3.9:1 на карточке —
   ниже нормы. Убираем прозрачность и поднимаем на ступень. */
.card .cstage{color:var(--tx-mut); opacity:1}

.card .ttl{color:var(--tx)}


/* ───────────────────────────────────────────────────────────────────────────
   5 · МЕТКИ · .ctags / .tag
   ─────────────────────────────────────────────────────────────────────────── */
/* Материал общий со счётчиками кабинета: тёплый белый на просвет вместо
   серого литерала rgba(159,159,159,.11). */
.tag{
  background:var(--bd-chip);
  color:var(--tx-mut);
  box-shadow:inset 0 0 0 1px var(--bd-chip-line);
}
/* «+2» — не метка, а указание, что метки спрятаны: пунктирный контур без
   заливки. Контур тенью, а не рамкой: рамка добавила бы 2px высоты и сбила
   бы ряд меток, у которых высота строки жёстко 16px. */
.tag.more{
  color:var(--tx-mut);
  background:none;
  box-shadow:inset 0 0 0 1px var(--line2);
}
/* Цвет метки считается из её строки (--h приходит инлайном из tagHue).
   На тёплом тёмном фоне точке нужна светлота выше средней, иначе половина
   оттенков проваливается в подложку. */
.ctags .tag .td{background:hsl(var(--h,30) 58% 66%); box-shadow:var(--dot-bevel)}


/* ───────────────────────────────────────────────────────────────────────────
   6 · МЕТА-СТРОКА КАРТОЧКИ · .typedot / .pchip / .due / .mi
   Здесь живёт вся смысловая раскраска — за ней следим строже всего.
   ─────────────────────────────────────────────────────────────────────────── */
/* --tx-dim на карточке var(--card2) даёт 4.37:1 — ниже нормы даже для 12px
   (привычные 5.4:1 посчитаны к фону страницы, а мета стоит на карточке). */
.card .meta{color:var(--tx-mut)}
.card .meta .mi{color:var(--tx-mut)}

/* Точка типа задачи дублирует левую полосу: вблизи она называет тип словом
   в подсказке, а полоса работает на расстоянии. */
.card .meta .typedot{box-shadow:var(--dot-bevel)}

/* Высокий приоритет — охра (срочность). Специфичность (0,4,0) обязательна:
   базовое .card .meta .pchip — (0,3,0), и одиночный .pchip.high ей проигрывал. */
.card .meta .pchip{
  background:var(--bd-chip);
  color:var(--tx-mut);
  box-shadow:inset 0 0 0 1px var(--bd-chip-line);
}
.card .meta .pchip.high{
  color:var(--warn);
  background:color-mix(in srgb, var(--warn) 14%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--warn) 34%, transparent);
  font-weight:var(--w-bd);
}

/* Срок. Лестница из четырёх ступеней, каждая следующая громче предыдущей:
     обычная дата                   — нейтраль
     «завтра / через 3 дня» (.soon) — охра текстом, почти без заливки
     «сегодня» (.today)             — охра заливкой
     «просрочено» (.over)           — розово-красный заливкой и жирным
   .soon в базе объявлен как .due.soon (0,2,0) и перебивался правилом
   .card .meta .due (0,3,0) — «завтра» ничем не отличалось от любой даты.
   Поэтому все четыре ступени пишем на одной специфичности (0,4,0). */
.card .meta .due{
  background:var(--bd-chip);
  color:var(--tx-mut);
  box-shadow:inset 0 0 0 1px var(--bd-chip-line);
  font-weight:var(--w-sb);
}
.card .meta .due.soon{
  color:var(--warn);
  background:color-mix(in srgb, var(--warn) 8%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--warn) 20%, transparent);
}
.card .meta .due.today{
  color:var(--warn);
  background:color-mix(in srgb, var(--warn) 16%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--warn) 38%, transparent);
  font-weight:var(--w-bd);
}
.card .meta .due.over{
  color:var(--danger);
  background:color-mix(in srgb, var(--danger) 16%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--danger) 40%, transparent);
  font-weight:var(--w-bd);
}

/* Счётчик подзадач «☑ 2/5». Класс .sub в кабинете значит три разные вещи,
   и панельное оформление подзадачи из модалки (заливка, рамка, padding 9/11)
   доставалось этому счётчику: внутри мета-строки вырастала плашка в две
   строки высотой. Раздеваем его обратно до обычной микроподписи. */
.card .meta .mi.sub{
  display:inline-flex; align-items:center; gap:4px;
  background:none; border:0; box-shadow:none;
  border-radius:0; padding:0; min-height:0;
}
/* Все подзадачи закрыты — бирюза, единственное значение «успех». */
.card .meta .mi.sub.all{color:var(--ok); font-weight:var(--w-sb)}


/* ───────────────────────────────────────────────────────────────────────────
   7 · ПОЛОСА ГОТОВНОСТИ · .cprog
   ─────────────────────────────────────────────────────────────────────────── */
/* Дорожка прижата к самому низу карточки (margin −12px). При радиусе 14px
   её собственные 8px оставляли на дне две заметные ступеньки. Слева радиус
   меньше — там 4px полосы типа. */
.card .cprog{
  background:var(--dp-trough);
  border-radius:0 0 var(--bd-r-in) var(--bd-r-rail);
  box-shadow:var(--mg-well);
}
/* Заливка идёт от акцента к бирюзе: движение к готовности заканчивается
   цветом «готово». Раньше хвост градиента был серым #DADADA — остаток
   чёрно-белой темы, из-за которого 100% выглядели выцветшими. */
.card .cprog i{
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--acc) 80%, #000) 0%,
    var(--acc) 45%,
    var(--ok) 100%);
  box-shadow:var(--mg-gloss);
  border-radius:0 2px 2px 0;
}


/* ───────────────────────────────────────────────────────────────────────────
   8 · БЫСТРОЕ ДЕЙСТВИЕ НА КАРТОЧКЕ · .qadv
   Три роли одной кнопки: «→ следующий статус» (команда), «✓ принять»
   и «↩ вернуть на проверку» (клиент). Первые две разные по смыслу —
   значит, и заливка у них разная.
   ─────────────────────────────────────────────────────────────────────────── */
.card .qadv{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border-color:var(--line2);
  color:var(--tx-mut);
  border-radius:9px;
  box-shadow:var(--dp-e1), var(--dp-rim);
}
/* Первичное действие — оранжевая заливка, текст ТЁМНЫЙ (6.18:1).
   Белый на этом оранжевом дал бы 3.2:1 и не прошёл бы. */
.card .qadv:hover{
  background:linear-gradient(180deg, var(--ct-fill-a), var(--ct-fill-b));
  border-color:color-mix(in srgb, var(--ct-fill-b) 70%, #000);
  color:var(--on-acc);
  box-shadow:var(--ct-halo), inset 0 1px 0 rgba(255,255,255,.28);
}
/* «Принять» — это успех, а не «здесь ты»: бирюза. Текст на ней — цвет фона
   страницы (12.31:1), никаких посторонних зелёных литералов. */
.card .qadv.qc.ok:hover{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--ok) 88%, #FFF), var(--ok));
  border-color:color-mix(in srgb, var(--ok) 70%, #000);
  color:var(--bg);
  box-shadow:0 10px 24px -12px color-mix(in srgb, var(--ok) 60%, transparent);
}
.card .qadv:active{transform:translateY(1px) scale(.96)}
/* Клавиатура. Заливку показываем ту же, но box-shadow отдаём кольцу фокуса
   целиком: если написать её в одном правиле с :hover, кольцо из theme.css
   (0,3,0) будет перебито этим файлом, и на Tab кнопка станет невидимой. */
.card .qadv:focus-visible{
  background:linear-gradient(180deg, var(--ct-fill-a), var(--ct-fill-b));
  border-color:color-mix(in srgb, var(--ct-fill-b) 70%, #000);
  color:var(--on-acc);
  box-shadow:0 0 0 4px var(--ct-ring);
}
.card .qadv.qc.ok:focus-visible{
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--ok) 88%, #FFF), var(--ok));
  border-color:color-mix(in srgb, var(--ok) 70%, #000);
  color:var(--bg);
  box-shadow:0 0 0 4px var(--ct-ring);
}


/* ───────────────────────────────────────────────────────────────────────────
   9 · ДОБАВИТЬ И ПУСТОТА · .addtask / .col-addcol / .col-hint / .empty
   Пунктир = приглашение. При наведении пунктир собирается в сплошную рамку.
   ─────────────────────────────────────────────────────────────────────────── */
.addtask,.col-addcol{
  border-color:var(--line2);
  color:var(--tx-mut);
  border-radius:10px;                    /* кнопочный радиус лендинга */
}
.addtask:hover,.col-addcol:hover{
  color:var(--acc-d);
  border-style:solid;
  border-color:currentColor;
  background:color-mix(in srgb, var(--acc) 10%, transparent);
  box-shadow:0 8px 22px -14px var(--glow);
}
/* Кнопка в «Пожеланиях» держит тон своей колонки — иначе клиент видит на
   одной доске два разных приглашения. Была серой (#A2A2A2). */
.addtask.wish{border-color:color-mix(in srgb, var(--bd-wish) 40%, var(--line2))}
.addtask.wish:hover{
  color:var(--bd-wish);
  border-style:solid;
  border-color:currentColor;
  background:color-mix(in srgb, var(--bd-wish) 12%, transparent);
  box-shadow:0 8px 22px -14px color-mix(in srgb, var(--bd-wish) 70%, transparent);
}
/* Фокус — отдельными правилами: box-shadow здесь занят кольцом, и смешивать
   его с «подсветкой наведения» нельзя, иначе кольцо пропадёт. */
.addtask:focus-visible,.col-addcol:focus-visible{
  color:var(--acc-d);
  border-style:solid;
  border-color:currentColor;
  background:color-mix(in srgb, var(--acc) 10%, transparent);
  box-shadow:0 0 0 4px var(--ct-ring);
}
.addtask.wish:focus-visible{
  color:var(--bd-wish);
  background:color-mix(in srgb, var(--bd-wish) 12%, transparent);
}

/* Подсказка в пустых «Пожеланиях». Корешок слева задуман акцентным
   (theme.css задаёт ему border-left:3px solid), но цвет приходил серым —
   возвращаем тон колонки. */
.col-hint{
  color:var(--tx-mut);
  background:color-mix(in srgb, var(--bd-wish) 8%, var(--card));
  border:1px dashed color-mix(in srgb, var(--bd-wish) 28%, var(--line2));
  border-left:3px solid var(--bd-wish);
  border-radius:10px;
}

/* Заглушка пустой колонки. В theme.css ей красили border-color, но ни ширины,
   ни стиля рамки у .empty нет нигде — оба правила были мёртвыми, и подсветка
   «сюда можно бросить» не появлялась вовсе. Даём рамку, чтобы они ожили.
   За пределы колонки не выходим: .empty переиспользуется на восьми экранах. */
.col-body>.empty{
  border:1px dashed var(--line2);
  border-radius:10px;
  color:var(--tx-mut);
  transition:border-color var(--mo-1x) var(--mo-out),
             background var(--mo-1x) var(--mo-out),
             color var(--mo-1x) var(--mo-out);
}
.board:has(.card.drag) .col-body>.empty{
  border-color:var(--acc);
  color:var(--tx);
  background:color-mix(in srgb, var(--acc) 10%, transparent);
}


/* ───────────────────────────────────────────────────────────────────────────
   10 · ПОЛОСА ДОСОК · .bbar / .bchip
   Активная доска — единственное место в этой полосе, где уместен акцент.
   ─────────────────────────────────────────────────────────────────────────── */
.bchip{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border-color:var(--line);
  color:var(--tx-mut);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.bchip:hover{
  color:var(--tx);
  border-color:var(--line2);
  background:linear-gradient(180deg, var(--ct-face-h-a), var(--ct-face-h-b));
  box-shadow:var(--dp-e2), var(--dp-rim-s);
}
/* «Здесь ты»: тёплая подложка и оранжевый корешок слева. Корешок, а не
   заливка целиком — чип остаётся читаемым и не спорит с кнопками. */
.bchip.on{
  color:var(--tx);
  border-color:color-mix(in srgb, var(--acc) 55%, var(--line2));
  background:linear-gradient(180deg,
    color-mix(in srgb, var(--acc) 16%, var(--ct-face-a)),
    color-mix(in srgb, var(--acc) 8%,  var(--ct-face-b)));
  box-shadow:inset 3px 0 0 var(--acc),
             inset 0 1px 0 rgba(255,246,232,.10),
             0 0 22px -12px var(--glow), var(--dp-e1);
}
.bchip i{background:var(--bd-chip); color:var(--tx-mut)}
.bchip.on i{
  background:color-mix(in srgb, var(--acc) 26%, transparent);
  color:var(--tx);
}
.bchip .bedit:hover{background:var(--ct-wash-s); color:var(--acc-d)}
.bchip.add{
  border-style:dashed;
  border-color:var(--line2);
  color:var(--tx-mut);
  background:none;
  box-shadow:none;
}
.bchip.add:hover{
  color:var(--acc-d);
  border-style:solid;
  border-color:currentColor;
  background:color-mix(in srgb, var(--acc) 10%, transparent);
  box-shadow:none;
}


/* ───────────────────────────────────────────────────────────────────────────
   11 · ВКЛАДКИ ПРОЕКТА · .ptabs / .ptab
   ─────────────────────────────────────────────────────────────────────────── */
.ptab{color:var(--tx-mut); border-radius:12px 12px 0 0}
.ptab:hover{color:var(--tx); background:var(--ct-wash)}
/* Активная вкладка — крышка с оранжевой кромкой сверху. Кромка внутренняя
   (inset), чтобы содержимое вкладки не сдвигалось на 2px при переключении. */
.ptab.on{
  background:linear-gradient(180deg, var(--card2), var(--panel));
  border-color:var(--line);
  color:var(--tx);
  box-shadow:inset 0 2px 0 var(--acc), 0 -10px 26px -18px var(--glow);
}
.ptab.on svg{color:var(--acc-d)}
.ptab.exp:hover,.ptab.set:hover{color:var(--acc-d); background:var(--ct-wash)}


/* ───────────────────────────────────────────────────────────────────────────
   12 · ПОИСК ПО ЗАДАЧАМ · .tsearch
   ─────────────────────────────────────────────────────────────────────────── */
.tsearch{
  background:var(--card);                 /* было var(--card2) — холодный серый */
  border-color:var(--line2);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
/* Фокус — акцент: это ровно тот случай «здесь ты». */
.tsearch:focus-within{
  border-color:var(--acc);
  box-shadow:var(--dp-e1),
             0 0 0 3px color-mix(in srgb, var(--acc) 26%, transparent);
}
.tsearch:focus-within .ts-ic{color:var(--acc-d)}
.tsearch input{color:var(--tx); caret-color:var(--acc-d)}
/* Число найденного — не результат и не ошибка, просто счётчик. */
.ts-n{color:var(--tx-mut)}
/* Крестик очистки был окрашен в тревожный красный (--fi-err-bg / --danger).
   Очистка поиска ничего не разрушает — тревога здесь означала бы, что
   красный в кабинете значит две разные вещи. Возвращаем нейтраль. */
.ts-x{color:var(--tx-mut); border-radius:8px}
.ts-x:hover{
  color:var(--tx);
  background:color-mix(in srgb, var(--tx) 9%, transparent);
}


/* ───────────────────────────────────────────────────────────────────────────
   13 · ФИЛЬТР МЕТОК · .tagfilter / .tf
   ─────────────────────────────────────────────────────────────────────────── */
.tagfilter .tf-lbl{color:var(--tx-mut)}
.tagfilter .tf{
  background:linear-gradient(180deg, var(--ct-face-a), var(--ct-face-b));
  border-color:var(--line2);
  color:var(--tx-mut);
  border-radius:10px;
  box-shadow:var(--dp-e1);
}
.tagfilter .tf:hover{color:var(--tx); border-color:var(--edge)}
/* Включённый фильтр — акцент: именно он определяет, что сейчас видно. */
.tagfilter .tf.on{
  color:var(--tx);
  border-color:var(--acc);
  background:color-mix(in srgb, var(--acc) 14%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--acc) 20%, transparent),
             0 8px 20px -16px var(--glow);
}
.tagfilter .tf .td{background:hsl(var(--h,30) 58% 66%); box-shadow:var(--dot-bevel)}
/* «сбросить» — служебная команда, а не метка: без точки и без заливки. */
.tagfilter .tf.clr{
  color:var(--tx-mut);
  background:none;
  border-style:dashed;
  box-shadow:none;
}
.tagfilter .tf.clr:hover{color:var(--acc-d); border-color:currentColor}


/* ───────────────────────────────────────────────────────────────────────────
   14 · СВОДКА ПРОГРЕССА · .analytics
   Селекторы .an-* переиспользуются на экране «Аналитика» (.dcard.hero-an),
   поэтому всё, что меняет цвет, обязательно начинается с .analytics —
   иначе правило уедет на чужой экран.
   ─────────────────────────────────────────────────────────────────────────── */
.analytics{
  background:linear-gradient(160deg, var(--card), var(--panel));
  border-color:var(--line2);
  border-radius:var(--bd-r);
  box-shadow:var(--dp-e2), var(--dp-rim);
}
/* Кольцо подписано «готово», и на полосе ниже сегмент «Готово» бирюзовый.
   Дуга была оранжевой: одно и то же число называлось двумя цветами. */
.analytics .an-ring .an-fg{stroke:var(--ok)}
.analytics .an-ring .an-bg{stroke:color-mix(in srgb, var(--tx) 9%, transparent)}
/* Мягкое свечение вокруг дуги — единственный декор панели. Фильтр только на
   svg: на .an-ringbox он задел бы и число, набранное градиентом по маске.
   Смещение строго нулевое: у .an-ring стоит transform:rotate(-90deg), а filter
   считается в локальных координатах — смещённая тень уехала бы вбок. */
.analytics .an-ring{
  filter:drop-shadow(0 0 14px color-mix(in srgb, var(--ok) 22%, transparent));
}
/* Подпись «ГОТОВО» — 11px капслоком, ей нужен запас по контрасту. */
.analytics .an-ringtxt span{color:var(--d-cap)}
.analytics .an-head>span:first-child{color:var(--tx)}
.analytics .an-sum{color:var(--tx-mut)}
/* Дорожка сводной полосы: тёплое дно вместо холодного var(--card2).
   Цвета сегментов приходят инлайном из данных — их не трогаем. */
.analytics .an-bar{
  background:var(--dp-trough);
  box-shadow:var(--mg-well);
  border-radius:8px;
}
.analytics .an-bar i+i{box-shadow:var(--mg-gloss), inset 1px 0 0 rgba(12,11,9,.45)}
.analytics .an-cell{color:var(--tx-mut)}
.analytics .an-cell b{color:var(--tx)}
.analytics .an-dot{box-shadow:var(--dot-bevel)}


/* ───────────────────────────────────────────────────────────────────────────
   15 · ТЕЛЕФОН
   Доской пользуются с телефона, в том числе клиенты без технического опыта.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:640px){
  /* В базе ширину телефонной колонки задавали через grid-template-columns,
     но .board — флексбокс, и свойство не делало ничего: колонка оставалась
     270px при включённом scroll-snap, то есть «прилипала» полупустой.
     Задаём ту же ширину тем свойством, которое во флексе работает. */
  .col{flex:0 0 min(86vw, 320px)}
  .col-collapsed{flex:0 0 46px}
}
@media(max-width:760px){
  /* Ховера нет — кнопка быстрого действия видна всегда и крупнее (44px).
     Освобождаем под неё место в первой строке карточки и в шапке блокировки,
     иначе она ложится поверх номера задачи и слова «Заблокировано». */
  .card .chead{padding-right:48px}
  .card .blk{padding-right:52px}
  /* Свечение под дугой — самый дорогой эффект панели на мобильном GPU. */
  .analytics .an-ring{filter:none}
}


/* ───────────────────────────────────────────────────────────────────────────
   16 · «МЕНЬШЕ ДВИЖЕНИЯ»
   Медиазапросы не добавляют специфичности: правила этого файла стоят ниже,
   чем блоки reduced-motion в app.css и theme.css, и без повторения вернули бы
   подъём карточки тем, кто движение отключил.
   Подъём при этом не пропадает — его продолжают показывать тень и кант.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .card,.card:hover,.card:active,.card.drag,
  .col-tool,.col-exp,.col-body>.empty,
  .addtask,.col-addcol,.bchip,.ptab,.tsearch,.tagfilter .tf{
    transition:none;
  }
  .card:hover,.card:active{transform:none}
  .card .qadv:active{transform:none}
  /* Полосы прокрутки — ОТДЕЛЬНЫМИ правилами. ::-webkit-scrollbar-thumb вне
     WebKit/Blink нераспознан, а один непонятый селектор в списке отменяет
     ВЕСЬ список: в Firefox с ним отвалилось бы и «.card{transition:none}».
     (Тем же способом сломано правило в theme.css — там они в общем списке.) */
  .board-wrap::-webkit-scrollbar-thumb{transition:none}
  .col-body::-webkit-scrollbar-thumb{transition:none}
}

/* ▲▲▲ конец: ДОСКА И КАРТОЧКИ ▲▲▲ */

/* ▼▼▼ ЭКРАНЫ: ДАШБОРДЫ И ГРАФИКИ ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   ДАШБОРДЫ · АНАЛИТИКА · ГРАФИКИ
   Подключать ПОСЛЕ app.css и theme.css: файл рассчитан на то, что при равной
   специфичности он идёт последним.

   Здесь живут цифры, по которым клиент судит о работе. Правила ниже решают
   три задачи:
     1. увести семейство с холодной серой палитры Ant на тёплую палитру
        лендинга (остатков нашлось много — они перечислены по месту);
     2. вернуть цвету смысл: оранжевый — «здесь ты», розово-красный — тревога,
        охра — срочность, бирюза — успех. Ни один из них не должен означать
        «просто украшение»;
     3. довести графики до состояния, когда данные видно раньше, чем сетку.

   Каждый селектор сверен по app.js (renderStats, projectDash, overviewDash,
   svgDonut/svgRing/svgBars/svgSpark/svgBurnup/svgHeatmap, hbars, legend, kpi).
   Выдуманных классов нет.

   Контраст (посчитан для тёмной темы, фон панели var(--panel)):
     --tx #F0ECE3 — 15.6:1 · --tx-mut #9C9488 — 6.1:1 · --acc #FF5A32 — 5.5:1
     на карточке · --danger #FF6E7A — 6.8:1 · --warn #F0B429 — 9.9:1
     --ok #4FE3C6 — 11.5:1. Ниже 4.5:1 в этом файле нет ничего.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   1 · ПОВЕРХНОСТИ. Главный остаток прежнего оформления.

   theme.css красил всё семейство холодным серым мимо токенов:
     .dcard      — linear-gradient(var(--card2) → var(--card2))
     .kpic       — linear-gradient(var(--line2) → var(--card2))
     .pcard/.ptile — linear-gradient(var(--card2) → var(--card2))
     .charttip   — var(--line2)
     границы     — rgba(159,159,159,.11 … .36)
   На тёплом угле var(--bg) это читается буквально как чужой продукт: страница
   тёплая, а карточки на ней синевато-серые. Возвращаем поверхности на токены.
   Правила ниже — про тёмную тему: у светлой свои, специфичнее (0,2,0),
   и они разобраны отдельно в разделе 13.
   ─────────────────────────────────────────────────────────────────────────── */
.dcard{
  background:linear-gradient(168deg,
    color-mix(in srgb, var(--card) 55%, var(--panel)) 0%,
    var(--panel) 100%);
  border-color:var(--line);
}
/* световая нить по верхней кромке была чисто белой — на тёплой палитре
   она отсвечивала голубым. Берём тёплый белый лендинга (--edge). */
.dcard::before{
  background:linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--edge) 62%, transparent) 50%, transparent);
}
:root[data-theme="light"] .dcard::before{
  background:linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--edge) 22%, transparent) 50%, transparent);
}

.kpic{
  background:linear-gradient(160deg, var(--card2) 0%, var(--card) 100%);
  border-color:var(--line);
}
.kpic:hover{border-color:var(--line2)}

.pcard,.ptile{
  background:linear-gradient(165deg,
    color-mix(in srgb, var(--card) 58%, var(--panel)) 0%,
    var(--panel) 100%);
  border-color:var(--line);
}
.pcard:hover,.ptile:hover{border-color:var(--line2)}

/* Панель дашборда на телефоне: 24px по бокам съедали ширину графика. */
@media(max-width:520px){
  .dcard{padding:16px}
}

/* Ритм сетки. .dash даёт 16px, .kpis — 16px, а .dgrid стоял на 20px:
   разнобой заметен там, где блоки стыкуются по вертикали. */
.dgrid{gap:16px}


/* ───────────────────────────────────────────────────────────────────────────
   2 · ЗАГОЛОВКИ КАРТОЧЕК. Дисциплина акцента.

   .dc-t svg был оранжевым у КАЖДОЙ карточки — на сводке студии это 12+
   оранжевых значков подряд. Оранжевый обязан значить «здесь ты / главное»;
   когда он становится украшением, он перестаёт работать как указатель.
   Значок по умолчанию — тихий, а цвет получают только карточки, где он
   действительно про смысл. Признак берём из СОДЕРЖИМОГО карточки, а не из
   выдуманного класса: «блок» рисуется как .pill-blk, просрочка — как .due.over.
   ─────────────────────────────────────────────────────────────────────────── */
.dc-t svg{color:var(--tx-mut)}
.dcard:has(.pill-blk) .dc-t svg,
.dcard:has(.due.over) .dc-t svg{color:var(--danger)}
/* «Требует вашего внимания» — единственная карточка, обращённая к клиенту
   лично, поэтому у неё и рамка, и счётчик тревожные (рамка задавалась
   литералом rgba(255,127,140,.34) — тем же цветом, но мимо токена). */
.dcard.attention{
  border-color:color-mix(in srgb, var(--danger) 38%, transparent);
  box-shadow:var(--dp-e2), var(--dp-rim),
             0 0 0 1px color-mix(in srgb, var(--danger) 10%, transparent);
}
/* Счётчик у заголовка был серым (rgba(159,159,159,.13)) в любой карточке —
   и у «Отделов», и у «Просроченных». Число тревоги красим тревогой. */
.badge-n{
  background:color-mix(in srgb, var(--tx) 9%, transparent);
  color:var(--tx-mut);
}
.attention .badge-n,
.dcard:has(.due.over) .badge-n,
.dcard:has(.pill-blk) .badge-n{
  background:color-mix(in srgb, var(--danger) 16%, transparent);
  color:var(--danger);
}
/* Подзаголовок карточки («задач/неделю, 8 недель») стоял на --tx-dim — это
   ровно нижняя граница нормы для 12px. На телефоне это первое, что теряется. */
.dc-s{color:var(--tx-mut)}


/* ───────────────────────────────────────────────────────────────────────────
   3 · KPI-ПЛИТКИ · .kpic / .mtile / .inv-kpi
   ─────────────────────────────────────────────────────────────────────────── */
/* Значок плитки был выкрашен в #BCBCBC — серый литерал поверх заданного
   в app.css акцента. Возвращаем акцент и даём ему тёплую подложку вместо
   белёсой rgba(255,255,255,.14), которая в светлой теме вообще невидима. */
.kpi-ic{
  background:linear-gradient(160deg,
    color-mix(in srgb, var(--acc) 20%, transparent),
    color-mix(in srgb, var(--acc) 6%, transparent));
  border:1px solid color-mix(in srgb, var(--acc) 28%, transparent);
  color:var(--acc);
  box-shadow:0 6px 16px -12px color-mix(in srgb, var(--acc) 45%, transparent);
}
/* Состояние плитки — смысловым цветом, тем же, что у числа и подписи. */
.kpic.good .kpi-ic{
  background:linear-gradient(160deg,
    color-mix(in srgb, var(--ok) 24%, transparent),
    color-mix(in srgb, var(--ok) 6%, transparent));
  border-color:color-mix(in srgb, var(--ok) 30%, transparent);
}
.kpic.bad .kpi-ic{
  background:linear-gradient(160deg,
    color-mix(in srgb, var(--danger) 24%, transparent),
    color-mix(in srgb, var(--danger) 6%, transparent));
  border-color:color-mix(in srgb, var(--danger) 30%, transparent);
}
/* Градиенты чисел задавались литералами (#EAFFFA/#FFD9DE/#FF8997) — при смене
   палитры они бы «отстали» от --ok/--danger. Выводим их из токенов.
   Именно background-image: сокращение background сбросило бы clip:text. */
.kpic.good b{
  background-image:linear-gradient(135deg,
    color-mix(in srgb, var(--ok) 26%, var(--tx)) 0%, var(--ok) 100%);
}
.kpic.bad b{
  background-image:linear-gradient(135deg,
    color-mix(in srgb, var(--danger) 30%, var(--tx)) 0%, var(--danger) 100%);
}
/* Значение KPI не всегда число: в плитке «ближайший срок» стоит фраза
   («просрочено 12 дней»). На 28px она уезжала в три рваные строки. */
.kpic b{
  line-height:1.1;
  overflow-wrap:anywhere;
  text-wrap:balance;
  font-variant-numeric:tabular-nums;
}
.kpic{min-width:0}
.kpi-l{color:var(--tx-mut)}

/* Полоса метрик студии. Числа уже моноширинные — добиваем разряды
   табличными цифрами, чтобы «1 240» и «980» стояли по одной сетке. */
.mstrip,.mtile b,.mtile .mpct{font-variant-numeric:tabular-nums}
.mtile b{letter-spacing:-.02em}

/* KPI счетов: подпись капслоком, число крупно, единица тише числа. */
.inv-kpi b{font-variant-numeric:tabular-nums; letter-spacing:-.02em}
.inv-kpi em{color:var(--tx-mut)}


/* ───────────────────────────────────────────────────────────────────────────
   4 · КОЛЬЦА ПРОГРЕССА · svgRing / .an-ring
   Дуга — единственный элемент дашборда, который читают с двух метров.
   Ей нужен скруглённый торец (уже есть), тёплое свечение и дорожка, которая
   не спорит с дугой. Специфичность (0,3,0) и (0,2,1) взята намеренно: в
   theme.css те же селекторы гасят filter, и без этого свечение не появится.
   ─────────────────────────────────────────────────────────────────────────── */
.an-ringbox .an-ring .an-fg{
  stroke:var(--acc);
  filter:drop-shadow(0 0 6px color-mix(in srgb, var(--acc) 55%, transparent));
}
.miniring circle:last-of-type{
  filter:drop-shadow(0 0 4px color-mix(in srgb, var(--acc) 45%, transparent));
}
/* Дорожка кольца — утопленная, не светлее карточки. */
.an-ringbox .an-ring .an-bg{stroke:color-mix(in srgb, var(--tx) 8%, transparent)}
.miniring circle:first-of-type{stroke:color-mix(in srgb, var(--tx) 8%, transparent)}
/* Процент в центре — число, значит табличные цифры и плотный трекинг. */
.an-ringtxt b,.miniring .mrt,.dc-total{
  font-variant-numeric:tabular-nums; letter-spacing:-.02em;
}
.an-ringtxt span{color:var(--tx-mut)}


/* ───────────────────────────────────────────────────────────────────────────
   5 · СЕГМЕНТНЫЕ И ГОРИЗОНТАЛЬНЫЕ ПОЛОСЫ
   ─────────────────────────────────────────────────────────────────────────── */
/* Дорожки стояли на var(--card2) — сером СВЕТЛЕЕ тёплой панели, из-за чего пустая
   часть полосы выглядела заполненной. Дорожка обязана быть корытом.
   Цвет считаем от --bg, а не пишем hex: одно выражение даёт углубление
   и в тёмной теме (≈#0F0D0B под панелью var(--panel)), и в кремовой светлой
   (≈#F6EFE4 под карточкой #FDFAF4) — чинить каждую тему отдельно не нужно. */
:root{ --dash-well:color-mix(in srgb, var(--bg) 78%, var(--card)); }
.an-bar,
.hb-t,
.pcard .prog{
  background:var(--dash-well);
  box-shadow:inset 0 1px 3px color-mix(in srgb, var(--bg) 70%, transparent);
}
/* Сегмент в 0,4% давал долю пикселя и просто исчезал — статус переставал
   существовать. min-width не спорит с инлайновым width из данных: это разные
   свойства, инлайн остаётся в силе.
   Блик задаём background-image со звёздочкой, потому что цвет заливки
   приходит инлайном, а в theme.css этот же блик стоит с !important. */
.an-bar i{
  min-width:4px;
  background-image:linear-gradient(180deg,
    rgba(255,246,232,.22), rgba(255,246,232,0) 70%)!important;
}
/* Блик-тень тоже была холодной: --mg-gloss это rgba(255,255,255,.3) сверху и
   серый rgba(36,36,36,.2) снизу. Правило намеренно ловит .an-bar i целиком,
   а не только i+i: иначе первый сегмент оставался с прежним холодным бликом,
   а соседние получали тёплый — посреди полосы читался шов. */
.an-bar i,.hbars .hb-t i,.pcard .prog i{
  box-shadow:inset 0 1px 0 rgba(255,246,232,.22),
             inset 0 -1px 0 color-mix(in srgb, var(--bg) 38%, transparent);
}
/* Разделитель сегментов был серым литералом rgba(36,36,36,.28): на тёплой
   палитре он холоднее фона и на светлых сегментах почти не виден. */
.an-bar i+i{
  box-shadow:inset 0 1px 0 rgba(255,246,232,.22),
             inset 0 -1px 0 color-mix(in srgb, var(--bg) 38%, transparent),
             inset 1px 0 0 color-mix(in srgb, var(--bg) 72%, transparent);
}
.hbars .hb-t i{
  background-image:linear-gradient(180deg,
    rgba(255,246,232,.20), rgba(255,246,232,0) 72%)!important;
}
/* Полоса готовности в карточке проекта заливалась градиентом «акцент → --ok»:
   любая полоса, хоть на 15%, заканчивалась бирюзой, то есть цветом «готово».
   Бирюза остаётся только за успехом — прогресс идёт тёплым.
   Тот же дефект живёт в .roprog .prog i (карточка задачи) — это чужое
   семейство, оставляю владельцу. */
.pcard .prog i{
  background-image:linear-gradient(90deg, var(--acc-d), var(--acc));
}
/* «Прогресс по этапам» красился hsl((i*47)%360, 60%, 55%) — то есть радугой:
   первый этап получался красным (читается как тревога), шестой — синим
   #5C78E0, прямым родственником прежнего Ant-синего. Цвет здесь ничего не
   кодирует, у каждой строки есть своя подпись, поэтому полосы одного тона.
   Карточка «Нагрузка по часам» этого правила не получает — там цвет ЗНАЧИМЫЙ
   (красный = перегруз >40 ч), и отличается она наличием .dc-s в заголовке. */
.dcard:not(:has(.dc-s)) .hbars .hb-t i{
  background-image:
    linear-gradient(180deg, rgba(255,246,232,.20), rgba(255,246,232,0) 72%),
    linear-gradient(90deg,
      color-mix(in srgb, var(--acc) 82%, var(--acc-d)), var(--acc-d))!important;
}
.hbars .hb-l b{font-variant-numeric:tabular-nums}


/* ───────────────────────────────────────────────────────────────────────────
   6 · ГРАФИКИ · оси, сетка, столбцы, линии
   ─────────────────────────────────────────────────────────────────────────── */
/* Сетка стояла на сером rgba(193,193,193,.10). Ей положено подсказывать
   уровень, а не расчерчивать карточку, поэтому тёплая и очень тихая. */
.cgrid{stroke:color-mix(in srgb, var(--tx) 9%, transparent)}
/* Нулевой уровень — не такая же пунктирная линия, как остальные: это ось,
   от неё растут столбцы. niceTicks отдаёт [0, середина, максимум], значит
   первый <line> в разметке и есть основание графика. */
.barsvg .cgrid:first-of-type,
.burnup .cgrid:first-of-type{
  stroke:color-mix(in srgb, var(--tx) 22%, transparent);
  stroke-dasharray:none;
}
.axl,.barsvg .bx,.burnup .bx{font-variant-numeric:tabular-nums}

/* Верхушка столбца текущей недели заливалась чистым #FFFFFF — единственный
   холодный белый на всём тёплом экране, рядом с кремовым #FFF6EC он отдаёт
   голубизной. stop-color — свойство CSS, поэтому атрибут разметки
   переопределяется без правки app.js. */
.barsvg stop[stop-color="#FFFFFF"]{stop-color:#FFF6EC}
/* Пустая неделя — тоже данные: призрак столбца вместо серого литерала. */
.barsvg .bar.zero{fill:color-mix(in srgb, var(--tx) 12%, transparent)}
.barsvg .bar{cursor:default}

/* Burn-up. «Всего в проекте» — тихий пунктир, «Готово» — акцентная линия;
   на тёмном фоне линия в 2.2px без ореола теряется на градиентной площади. */
.burnup .bu-scope{stroke:var(--tx-mut); opacity:.8}
.burnup .bu-done{
  stroke:var(--acc);
  filter:drop-shadow(0 1px 5px color-mix(in srgb, var(--acc) 50%, transparent));
}
.burnup .bu-dot.done{fill:var(--acc-d)}
.burnup .bu-dot.scope{fill:var(--tx-mut)}
.bu-k.done{background:var(--acc-d)}
/* «в срок 92%» — итог, а не подпись: бирюза здесь честно значит успех. */
.bu-ot{color:var(--ok); font-variant-numeric:tabular-nums}

/* Спарклайн в плитке проекта. У SVG стоит preserveAspectRatio="none", а слот
   был 70px при viewBox 116 — линию сжимало в 1,7 раза и она худела до
   волоска. Слот шире, толщина фиксируется независимо от масштаба. */
.pt-spark{width:88px; opacity:1}
.spark polyline{vector-effect:non-scaling-stroke}
@media(max-width:400px){ .pt-spark{width:64px} }

/* Пончик. Обёртка уже flex:none, но легенде нужно право сжиматься,
   иначе длинное название статуса выталкивает круг за край карточки. */
.donutrow{gap:16px}
.legend{flex:1 1 150px; min-width:0}
.lg b{font-variant-numeric:tabular-nums}


/* ───────────────────────────────────────────────────────────────────────────
   7 · ТЕПЛОВАЯ КАРТА АКТИВНОСТИ
   ─────────────────────────────────────────────────────────────────────────── */
/* Разметка отдаёт viewBox 125×109 (8 недель × 7 дней, клетка 13px), а в CSS
   стояло height:auto + max-width:100%. SVG без атрибута width занимает всю
   ширину контейнера, поэтому карта растягивалась до ~400px и уезжала в
   высоту на ~350px: вместо календаря получалось панно из огромных квадратов.
   Фиксируем высоту — ширину SVG посчитает сам по своей пропорции. */
.heatmap{height:126px; width:auto; max-width:none; display:block}
.heatwrap{
  scrollbar-width:thin;
  scrollbar-color:var(--line2) transparent;
}
.heatwrap::-webkit-scrollbar{height:6px}
.heatwrap::-webkit-scrollbar-thumb{background:var(--line2); border-radius:6px}
.heatwrap::-webkit-scrollbar-track{background:transparent}
/* Ключ легенды обязан совпадать с тем, чем реально залиты клетки:
   svgHeatmap считает color-mix(--acc 30…100%, --card2), а первая клетка
   легенды стояла серым литералом rgba(159,159,159,.12) и обещала не тот цвет. */
.hk.h0{background:var(--card2)}
.hk.h1{background:color-mix(in srgb, var(--acc) 32%, var(--card2))}
.hk.h2{background:color-mix(in srgb, var(--acc) 65%, var(--card2))}
.hk.h3{background:var(--acc)}
.heat-leg .hk{box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--tx) 7%, transparent)}


/* ───────────────────────────────────────────────────────────────────────────
   8 · ТУЛТИП ГРАФИКОВ
   ─────────────────────────────────────────────────────────────────────────── */
/* Фон был литералом var(--line2), а тень — rgba(36,36,36,.6): на угле var(--bg)
   такая «тень» СВЕТЛЕЕ фона и работает не тенью, а грязным ореолом. */
.charttip{
  background:var(--card2);
  border-color:var(--line2);
  box-shadow:var(--dp-e3), var(--dp-rim-s);
  color:var(--tx);
}
/* Число в тултипе было серым #BFBFBF — тише окружающего текста, хотя ради
   него тултип и открывают. Оранжевым его тоже красить нельзя: акцент здесь
   ничего не указывает. Самый контрастный текст + моно из theme.css. */
.charttip b{color:var(--tx)}


/* ───────────────────────────────────────────────────────────────────────────
   9 · СПИСКИ ДАШБОРДА · .dlist / .drow / лента изменений
   ─────────────────────────────────────────────────────────────────────────── */
/* Строка списка ведёт себя как кнопка (button data-opentask) — и скругление
   берёт кнопочное, 10px, а не случайные 9px. */
.drow{border-radius:10px}
.drow:focus-visible{background:color-mix(in srgb, var(--acc) 10%, transparent)}
.drow-t{color:var(--tx)}
.mi2{color:var(--tx-dim)}
/* Срочность — охра, тревога — розово-красный. Разные смыслы, разные цвета. */
.daybadge.warn{color:var(--warn); font-weight:600}
.daybadge.bad{color:var(--danger); font-weight:700}
.pill-blk{
  color:var(--danger);
  background:color-mix(in srgb, var(--danger) 15%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--danger) 30%, transparent);
}
/* Лента последних изменений. Класс строки — это статус задачи (friendlyChange
   отдаёт c.status), поэтому значок можно окрасить по статусу, а не оставлять
   все шесть видов событий одинаково серыми. Ключи сверены по STATUSES. */
.fic{background:color-mix(in srgb, var(--tx) 8%, transparent); color:var(--tx-mut)}
.frow.done .fic{
  background:color-mix(in srgb, var(--ok) 18%, transparent); color:var(--ok);
}
.frow.review .fic{
  background:color-mix(in srgb, var(--acc) 16%, transparent); color:var(--acc-d);
}
.frow.in_progress .fic{
  background:color-mix(in srgb, var(--warn) 16%, transparent); color:var(--warn);
}
.frow.wish .fic{
  background:color-mix(in srgb, var(--t-design) 18%, transparent); color:var(--t-design);
}
.frow.rejected .fic{
  background:color-mix(in srgb, var(--danger) 16%, transparent); color:var(--danger);
}
.frow{border-bottom-color:var(--line)}
.fdt{color:var(--tx-dim); font-variant-numeric:tabular-nums}

/* Мини-заглушка внутри карточки: «Просрочек нет» — это хорошая новость,
   а не сбой загрузки. Пунктирная рамка уже есть, добавляем спокойный тон. */
.dash-empty{color:var(--tx-mut)}
.dash-empty svg{color:var(--tx-dim)}


/* ───────────────────────────────────────────────────────────────────────────
   10 · ПЛИТКИ И КАРТОЧКИ ПРОЕКТОВ
   ─────────────────────────────────────────────────────────────────────────── */
.pt-name{color:var(--tx)}
.pt-sub{color:var(--tx-dim)}
.pt-counts{color:var(--tx-mut); font-variant-numeric:tabular-nums}
.pt-counts .bad{color:var(--danger); font-weight:600}
/* Статус проекта: «в работе» — акцент (проект живой), «готово» — бирюза,
   «риск» — тревога. Заливки нет, только тон и рамка: три статуса рядом
   в сетке не должны спорить за внимание. */
.pc-st{background:color-mix(in srgb, var(--tx) 5%, transparent)}
.pc-st.live{color:var(--acc-d); border-color:color-mix(in srgb, var(--acc) 40%, transparent)}
.pc-st.done{color:var(--ok); border-color:color-mix(in srgb, var(--ok) 40%, transparent)}
.pc-st.risk{color:var(--danger); border-color:color-mix(in srgb, var(--danger) 42%, transparent)}
.pc-meta{color:var(--tx-dim)}
.pc-chip{background:color-mix(in srgb, var(--tx) 6%, transparent); border-color:var(--line)}
.pc-chip .d.live{background:var(--acc)}
.pc-chip .d.ok{background:var(--ok)}
.pc-chip .d.bad{background:var(--danger)}
.pc-chip .d.wish{background:var(--t-design)}
.pc-chip .d.idle{background:var(--tx-dim)}
.pc-go{color:var(--acc-d)}


/* ───────────────────────────────────────────────────────────────────────────
   11 · МЕСТО ПОД ГРАФИК И СКЕЛЕТ ЗАГРУЗКИ
   ─────────────────────────────────────────────────────────────────────────── */
/* .chost наполняется из JS уже после раскладки (fitCharts меряет ширину),
   поэтому карточка сначала схлопывается, а потом прыгает на 170–260px.
   Резервируем высоту заранее — экран собирается без рывка. */
.chost{min-height:150px}
/* Скелет дашборда рисовал панели с прежним радиусом 8px и отступом 18/20,
   а настоящая панель — 14px и 20/24: при подмене содержимое дёргалось. */
.sk-dash{gap:16px}
.sk-dash .sk-wide{border-radius:14px; padding:20px 24px; gap:14px}


/* ───────────────────────────────────────────────────────────────────────────
   12 · ТЕЛЕФОН. Дашборд читают в дороге — с одной рукой и на солнце.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:640px){
  /* два KPI в ряд: 28px число + фраза «просрочено 12 дней» в узкой колонке
     складывались в четыре строки */
  .kpic b{font-size:24px}
  .kpic{padding:13px 14px 14px}
  .donutrow{gap:14px}
  .legend{flex:1 1 100%}
  /* карта активности целиком помещается по высоте, ширину листаем */
  .heatmap{height:112px}
  .chost{min-height:132px}
}
@media(max-width:400px){
  .kpic b{font-size:22px}
  .heatmap{height:104px}
}


/* ───────────────────────────────────────────────────────────────────────────
   13 · СВЕТЛАЯ ТЕМА
   Светлая тема тоже переехала на палитру лендинга (кремовый #F4EDE1 / #FDFAF4,
   терракота #D93C13), но правила семейства остались от Ant: поверхности
   дашборда заливались холодным #F9F9F9 → #F3F3F3, дорожки — #F3F3F3, тултип —
   чистым #FFFFFF. На кремовой странице это те же серые пятна, что и в тёмной
   теме, только наоборот. Специфичность (0,3,0) — ровно на ступень выше
   прежних [data-theme="light"] .dcard (0,2,0).
   ─────────────────────────────────────────────────────────────────────────── */
:root[data-theme="light"] .dcard{
  background:linear-gradient(168deg, var(--card) 0%,
    color-mix(in srgb, var(--bg) 45%, var(--card)) 100%);
}
:root[data-theme="light"] .kpic{
  background:linear-gradient(160deg, var(--card) 0%,
    color-mix(in srgb, var(--bg) 38%, var(--card)) 100%);
}
:root[data-theme="light"] .pcard,
:root[data-theme="light"] .ptile{
  background:linear-gradient(165deg, var(--card) 0%,
    color-mix(in srgb, var(--bg) 45%, var(--card)) 100%);
}
:root[data-theme="light"] .inv-kpi{
  background:linear-gradient(160deg, var(--card),
    color-mix(in srgb, var(--bg) 38%, var(--card)));
}
:root[data-theme="light"] .charttip{background:var(--card)}
:root[data-theme="light"] .an-bar,
:root[data-theme="light"] .hb-t,
:root[data-theme="light"] .pcard .prog{background:var(--dash-well)}
/* «Успех» как текст брался ступенью Ant green-8 (#237804) — на кремовом это
   чужой холодный зелёный рядом с бирюзой --ok. Токен светлой темы (#0B7A66)
   даёт 5.0:1 на карточке — норму проходит и остаётся тем же цветом успеха. */
:root[data-theme="light"] .bu-ot,
:root[data-theme="light"] .kpic.good .kpi-l,
:root[data-theme="light"] .pc-st.done{color:var(--ok)}
/* Числа KPI: градиенты заканчивались Ant-зелёным #52C41A и Ant-красным #FF4D4F
   (3.3:1 — для числа мало). Ведём их к токенам темы: 5.0:1 и 5.4:1. */
:root[data-theme="light"] .kpic.good b{
  background-image:linear-gradient(135deg,
    color-mix(in srgb, var(--ok) 70%, var(--tx)) 0%, var(--ok) 100%);
}
:root[data-theme="light"] .kpic.bad b{
  background-image:linear-gradient(135deg,
    color-mix(in srgb, var(--danger) 70%, var(--tx)) 0%, var(--danger) 100%);
}


/* ───────────────────────────────────────────────────────────────────────────
   14 · СПОКОЙНЫЙ РЕЖИМ
   Свечения — это filter, они не анимируются и остаются: убирать нужно
   движение, а не контраст.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .an-bar i,.hbars .hb-t i,.pcard .prog i{transition:none}
  .barsvg .bar,.burnup .bu-done,.burnup .bu-area,.spark polygon{animation:none}
}

/* ▲▲▲ конец: ДАШБОРДЫ И ГРАФИКИ ▲▲▲ */

/* ▼▼▼ ЭКРАНЫ: ДАННЫЕ: ТАБЛИЦЫ, СЧЕТА, КОММЕНТАРИИ ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   СЕМЕЙСТВО «ДАННЫЕ» · таблицы · счета · часы · документы · комментарии
   Подключать ПОСЛЕ app.css и theme.css.

   Зачем слой. Кабинет переведён на палитру лендинга, но переведены только
   ТОКЕНЫ. Плотные списки в theme.css покрашены холодными литералами мимо
   токенов — #333333, var(--card2), var(--card2), #393939, var(--line2), var(--card2), var(--card2),
   rgba(159,159,159,…), rgba(193,193,193,…). Токены их не достают, поэтому
   таблица, счёт, строка часов и пузырь комментария остались серо-синими
   плитами на тёплом угле: ровно тот стык, из-за которого кабинет читается
   как другой продукт. Этот слой переводит поверхности семейства на токены
   и доводит смысл: числа, статусы, «команда / клиент», плотность.

   ПРИНЦИПЫ
   1. Числа — моно, tabular-nums, правый край. Разряды обязаны совпадать.
   2. Плотность держат волосок и отступ, а не рамка и заливка.
   3. Один цвет — один смысл: оранжевый «здесь ты», бирюза «готово/оплачено»,
      охра «скоро кончится», розово-красный «просрочка/блокировка/удаление».
   4. Ни одного выдуманного класса: каждый селектор сверен по app.js.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   0 · ПОЧИНКА СЛОМАННОГО ТОКЕНА --d-ok

   theme.css:2700–2706. В комментарии над объявлением стоит ЛИШНЯЯ закрывающая
   пара «звёздочка-слэш»: комментарий закрывается на строке 2702, а
   прозаический хвост 2703–2704 остаётся в потоке объявлений. Парсер считает
   его невалидным свойством и доедает всё до ближайшей точки с запятой —
   то есть вместе с хвостом съедает и сам --d-ok. Токена не существует,
   а var(--d-ok) «невалиден на этапе вычисления»: свойство не откатывается
   на предыдущее правило каскада, а становится unset, для color это inherit.
   Видимое последствие в нашем семействе: theme.css:2865 .hrow.purchase .hr-k
   наследовал --tx, и «+2,5 ч» (пополнение пакета) переставало отличаться
   от «−0,5 ч» (списание). Объявляем токен формулой автора — правила оживают.
   ─────────────────────────────────────────────────────────────────────────── */
:root{
  --d-ok: color-mix(in srgb, var(--ok) 64%, var(--tx));   /* ≈11.8:1 на --card */

  /* Тёплая поверхность строки списка вместо холодных var(--card2) → var(--card2).
     Выведена из токенов, поэтому верна и в светлой теме. */
  --dx-row: linear-gradient(170deg,
              var(--card),
              color-mix(in srgb, var(--panel) 55%, var(--card)));
  --dx-edge-h: color-mix(in srgb, var(--edge) 60%, transparent);  /* рамка под курсором */
  --dx-rail-w: 3px;                                              /* корешок принадлежности */
}


/* ───────────────────────────────────────────────────────────────────────────
   1 · ТАБЛИЦЫ · .tblwrap / .tbl   (раздел «Клиенты», renderClients в app.js)

   Разметка ровно одна: Имя · Почта · Проектов · Создан · действия.
   Поменяется состав колонок — править этот блок вместе с ним.
   ─────────────────────────────────────────────────────────────────────────── */

/* Обёртка была #333333 — холодная плита. Заодно подсказка о горизонтальной
   прокрутке: таблица шире телефона (min-width:540px), и без тени у края не
   видно, что справа есть ещё колонки. Слои local закрывают слои scroll,
   когда прокрутка дошла до края — тот же приём, что у .col-body. */
.tblwrap{
  background:
    linear-gradient(90deg,  var(--panel) 34%, transparent) left /22px 100% no-repeat local,
    linear-gradient(270deg, var(--panel) 34%, transparent) right/22px 100% no-repeat local,
    radial-gradient(farthest-side at 0    50%, rgba(0,0,0,.40), transparent) left /13px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(0,0,0,.40), transparent) right/13px 100% no-repeat scroll,
    var(--panel);
  border-color:var(--line);
}

/* Шапка — «крышка» таблицы. Была залита оранжевым на 7% (theme.css:903),
   а наведение на строку — оранжевым на 9% (theme.css:2768): два разных
   смысла одним цветом и почти одной плотностью. Шапка переставала читаться
   как шапка, а ховер терял смысл «здесь ты». Шапку уводим в нейтральный
   тёплый материал, оранжевый остаётся только за наведением. */
.tblwrap .tbl th{background:var(--card2)}

/* Зебра. theme.css:909 красит чётные строки в rgba(193,193,193,.022) —
   холодный литерал, который вдобавок противоречит замыслу самого файла
   (theme.css:2750 «зебры нет намеренно»). Снимаем: ритм держат волосок и
   ховер. :not(:hover) — чтобы не перебить подсветку строки: у неё ровно та
   же специфичность (0,3,3), но объявлена она выше по каскаду. */
.tblwrap .tbl tbody tr:nth-child(even):not(:hover) td{background:none}

/* Иерархия колонок: имя ведёт, почта поддерживает, число считается. */
.tblwrap .tbl td:nth-child(2){color:var(--d-sec);overflow-wrap:anywhere}
/* Правый край и моно у колонки «Проектов» уже заданы в theme.css:2778 по
   индексу колонки. Здесь только запрет переноса: трёхзначный счётчик на
   телефоне рвался на две строки и ломал высоту всей строки таблицы. */
.tblwrap .tbl td:nth-child(3){white-space:nowrap}

/* Действия в строке: тёплые рамки вместо rgba(159,159,159,…) */
.rowact{border-color:var(--line2)}
.rowact:hover{border-color:var(--acc);color:var(--acc-d);background:var(--ct-wash)}
.rowdel:hover{
  background:color-mix(in srgb, var(--danger) 14%, transparent);
  border-color:color-mix(in srgb, var(--danger) 34%, transparent);
  color:var(--danger);
}


/* ───────────────────────────────────────────────────────────────────────────
   2 · СЧЕТА · .inv-kpi / .inv / .inv-badge   (renderInvoices в app.js)

   Цвет статуса приходит инлайном в --c: черновик --t-task, выставлен --warn,
   оплачен --ok, отменён --danger. Сам цвет не трогаем — доводим носители.
   ─────────────────────────────────────────────────────────────────────────── */
.inv-kpi{
  background:linear-gradient(160deg, var(--card), var(--panel));
  border-color:var(--line);
}
/* Первая плитка — «К оплате» (деньги в работе, акцент), вторая — «Оплачено»,
   и это бирюза «готово». Порядок задан разметкой renderInvoices: ровно две
   плитки, всегда в этом порядке. Появится третья — правило дописать. */
.inv-kpis .inv-kpi:nth-child(2)::before{
  background:linear-gradient(90deg,
    var(--ok),
    color-mix(in srgb, var(--ok) 35%, transparent) 70%,
    transparent);
}

.inv{background:var(--dx-row);border-color:var(--line)}
.inv:hover{border-color:var(--dx-edge-h)}

/* Просрочка. В разметке это ВТОРОЙ бейдж подряд: он выводится только при
   status==='issued' и наступившей дате (app.js:2724). Отличить просрочку от
   отменённого счёта иначе нельзя — оба приходят с --c:var(--danger).
   Просрочка это не оттенок, а тревога, поэтому не контурный чип, а заливка. */
.inv-top .inv-badge + .inv-badge{
  background:var(--mn-red);                 /* #D32F3F — заливка тревоги */
  border-color:var(--mn-red);
  color:var(--on-danger);                   /* белый: ≈4.9:1 на этой заливке */
}
.inv-top .inv-badge + .inv-badge::before{background:var(--on-danger);box-shadow:none}

/* Просроченная строка целиком: корешок слева и подкрашенная рамка. Клиент
   находит проблемный счёт, не вчитываясь в бейджи. */
.inv:has(.inv-badge + .inv-badge){
  border-color:color-mix(in srgb, var(--danger) 40%, var(--line));
  box-shadow:var(--dp-e1), var(--dp-rim), inset var(--dx-rail-w) 0 0 var(--danger);
}
/* Ховер этой строки объявлен слабее (theme.css:927 — 0,2,0), поэтому подъём
   при наведении повторяем здесь, иначе просроченный счёт переставал
   откликаться на курсор. */
.inv:has(.inv-badge + .inv-badge):hover{
  box-shadow:var(--dp-e2), var(--dp-rim-s), inset var(--dx-rail-w) 0 0 var(--danger);
}

/* Слева «что это», справа «сколько»: волосок между смыслами. Только на
   широком экране — на телефоне .inv складывается в колонку (app.css:1057)
   и вертикальная линия оказалась бы поперёк. */
@media(min-width:761px){
  .inv-side{padding-left:18px;border-left:1px solid var(--d-hair);align-self:stretch}
}


/* ───────────────────────────────────────────────────────────────────────────
   3 · ЧАСЫ ПОДДЕРЖКИ · .hbal / .hrow / .hb-*   (renderHours в app.js)
   ─────────────────────────────────────────────────────────────────────────── */

/* Трек шкалы был var(--card2) — холодный. Берём «корыто» палитры.
   Именно background-color, а не background: на .hbal .hb-bar в theme.css:2851
   лежат четвертные засечки через background-image, и шорткат стёр бы их. */
.hbal .hb-bar,.hb-t{background-color:var(--dp-trough)}

/* Заливка шкалы = ИЗРАСХОДОВАНО (app.js:3009: pct = spent / purchased),
   крупное число над ней — остаток. Раньше заливка уходила из бирюзы в серый
   #7A7A7A → #9F9F9F: бирюза здесь означала бы «успех», хотя это просто
   расход, а серый хвост выглядел мёртвым. Ставим акцент — «сколько пройдено». */
.hbal .hb-bar i{
  background:linear-gradient(90deg, var(--acc-d), var(--acc));
  box-shadow:0 0 16px -6px var(--glow);
}

/* Состояние «пакет заканчивается». Было розово-красным (theme.css:940, 946,
   2842) — тем же цветом, что просрочка счёта и удаление записи. Но часы ещё
   есть (порог 20% в app.js:3010), это «скоро кончится», а не авария: по
   дисциплине цвета — ОХРА. Красный возвращаем просрочке и удалению. */
.hbal.low{border-color:color-mix(in srgb, var(--warn) 45%, var(--line))}
.hbal.low .hb-bar i{
  background:linear-gradient(90deg, var(--acc), var(--warn));
  box-shadow:0 0 16px -6px color-mix(in srgb, var(--warn) 80%, transparent);
}
.hb-warn{color:var(--warn)}                 /* ≈10:1 на --panel; иконка идёт currentColor */

/* Строка движения по часам */
.hrow{
  position:relative;overflow:hidden;
  background:var(--dx-row);
  border-color:var(--line);
}
.hrow:hover{border-color:var(--dx-edge-h)}
/* Корешок направления: приход виден раньше, чем прочитан знак у числа */
.hrow::before{
  content:'';position:absolute;left:0;top:0;bottom:0;width:var(--dx-rail-w);
  background:color-mix(in srgb, var(--tx-mut) 45%, transparent);
}
.hrow.purchase::before{background:var(--ok)}
.hrow.purchase .hr-k{color:var(--d-ok)}     /* оживает вместе с токеном из блока 0 */
.hrow.spend .hr-k{color:var(--tx)}
.hr-n{min-width:0;overflow-wrap:anywhere}   /* длинное примечание не рвёт строку */
.hr-x:hover{
  background:color-mix(in srgb, var(--danger) 14%, transparent);
  color:var(--danger);
}


/* ───────────────────────────────────────────────────────────────────────────
   4 · ДОКУМЕНТЫ · .lib (библиотека) · .docs / .doc (файлы задачи) · .docpick
   ─────────────────────────────────────────────────────────────────────────── */
.lib{background:var(--dx-row);border-color:var(--line)}
.lib:hover{border-color:color-mix(in srgb, var(--acc) 45%, var(--line2))}

/* Строка файла: var(--line2) и var(--card2) → тёплый материал. Геометрию и ховер
   .doc-add / .cmt-attach / .btn-file / .cef-add получают в слое кнопок —
   здесь только поверхность, которую тот слой не задаёт. */
.doc-dl,.cmt-file,.cmt-attach,.btn-file,.cef-x,.cef-add{
  background:var(--card2);
  border-color:var(--line2);
}
.doc-dl:hover,.cmt-file:hover{
  border-color:var(--acc);
  background:color-mix(in srgb, var(--acc) 8%, var(--card2));
}
/* Клетка иконки и миниатюра стоят в одной сетке 34×34 (theme.css:2993),
   поэтому строки с картинкой и без неё не «прыгают». Здесь — материал. */
.doc-th{background:var(--d-well)}
.doc-dl:hover .doc-ic{border-color:color-mix(in srgb, var(--acc) 40%, transparent)}
.doc-x:hover{
  background:color-mix(in srgb, var(--danger) 14%, transparent);
  color:var(--danger);
}


/* ───────────────────────────────────────────────────────────────────────────
   5 · КОММЕНТАРИИ · .cmt   (renderComment в app.js: классы mine / adm)

   Требование: комментарий команды и комментарий клиента должны различаться.
   В разметке два независимых признака — .mine (мой) и .adm (от команды),
   и один комментарий может нести оба сразу. Разводим их по РАЗНЫМ носителям,
   чтобы совпадение не превращалось в кашу:
     · .mine — сторона пузыря и лёгкая акцентная подложка («здесь ты»);
     · .adm  — корешок у аватара и заливной аватар («это ответ команды»).
   ─────────────────────────────────────────────────────────────────────────── */
.cmt-bubble{background:var(--card);border-color:var(--line)}
.cmt.mine .cmt-bubble{
  background:color-mix(in srgb, var(--acc) 11%, var(--card));
  border-color:color-mix(in srgb, var(--acc) 30%, var(--line2));
}

/* Корешок «от команды» ставим со стороны аватара: у обычного комментария
   аватар слева, у своего (.mine) строка развёрнута (app.css:171) и аватар
   справа — иначе корешок оказался бы на «хвосте» пузыря. */
.cmt.adm .cmt-bubble{
  background:var(--card2);
  box-shadow:var(--dp-e1), var(--dp-rim),
             inset var(--dx-rail-w) 0 0 color-mix(in srgb, var(--acc) 70%, transparent);
}
.cmt.adm.mine .cmt-bubble{
  background:color-mix(in srgb, var(--acc) 11%, var(--card2));
  box-shadow:var(--dp-e1), var(--dp-rim),
             inset calc(var(--dx-rail-w) * -1) 0 0 color-mix(in srgb, var(--acc) 70%, transparent);
}

/* Аватар: клиент — тихий тёплый кружок, команда — заливка акцентом.
   На оранжевом текст ТЁМНЫЙ (--on-acc, 5.9:1); белый дал бы 3.2:1, а именно
   белый и стоял тут после перевода палитры (theme.css:873). */
.cmt-av{background:var(--card2);border-color:var(--line2);color:var(--tx-mut)}
.cmt.adm .cmt-av{
  background:linear-gradient(140deg, var(--acc-d), var(--acc));
  color:var(--on-acc);
  border-color:var(--acc);
  box-shadow:0 4px 12px -6px var(--glow);
}
.cmt-t:hover{background:var(--card2);color:var(--tx)}


/* ───────────────────────────────────────────────────────────────────────────
   6 · ВЛОЖЕНИЯ И ИХ ПРЕВЬЮ · .cmt-img / .cf-name
   ─────────────────────────────────────────────────────────────────────────── */
.cmt-img{background:var(--d-well);border-color:var(--line2)}
.cmt-img:hover{border-color:var(--acc)}
/* Имя выбранного, но ещё не отправленного файла: пока файл «в руках» —
   он полноценный текст, а не подпись. Точку-маркер рисует theme.css:1633. */
.cf-name.has{color:var(--tx)}


/* ───────────────────────────────────────────────────────────────────────────
   7 · МОДАЛКИ И ПОДТВЕРЖДЕНИЕ · .modal / .mhead / .confirm-modal
   Корпус окна и волосок под .mhead уже на токенах (theme.css:2415, 2437) —
   их не трогаем. Остатки прежней палитры здесь два: вуаль второго слоя
   (rgba(40,40,40,.5), холодная поверх тёплой страницы) и кружок иконки
   подтверждения на rgba(159,159,159,…).
   ─────────────────────────────────────────────────────────────────────────── */
.confirm-ov{background:color-mix(in srgb, var(--bg) 62%, transparent)}
.confirm-modal .cf-ic{background:var(--card2);border-color:var(--line2);color:var(--tx-mut)}
.confirm-modal .cf-ic.danger{
  background:color-mix(in srgb, var(--danger) 15%, var(--card2));
  border-color:color-mix(in srgb, var(--danger) 35%, transparent);
  color:var(--danger);
}


/* ───────────────────────────────────────────────────────────────────────────
   8 · ПОДЗАДАЧИ · .subs / .sub

   ВНИМАНИЕ: класс .sub означает три разные вещи (подзаголовок входа, строка
   в печатной форме счёта, строка подзадачи). Поэтому всё — только через
   контейнер .subs, который есть лишь у подзадач (app.js:3148).
   ─────────────────────────────────────────────────────────────────────────── */
.subs .sub{background:var(--card2);border-color:var(--line)}
.subs .sub:hover{border-color:var(--line2)}
.subs .sub.done{background:color-mix(in srgb, var(--card2) 70%, transparent)}
.subs .sub-ck{border-color:var(--line2)}
.subs .sub-ck:hover:not(:disabled){border-color:var(--ok)}
.subs .sub.done .sub-ck{
  background:color-mix(in srgb, var(--ok) 18%, transparent);
  border-color:var(--ok);
}
/* 11px мономаркер статуса: на этой плашке --tx-dim давал ~4,3:1 */
.subs .sub-st{color:var(--d-sec)}
.subs-empty{color:var(--d-sec)}
.subs-sec{border-top-color:var(--d-hair)}
.subs-n,.badge-n{background:var(--card2);color:var(--d-sec)}


/* ───────────────────────────────────────────────────────────────────────────
   9 · ПЛОТНЫЕ СПИСКИ · .dlist / .drow
   Просрочки, блокеры, застрявшие задачи, уведомления. Строка-кнопка: слева
   название, справа метка времени или состояния.
   ─────────────────────────────────────────────────────────────────────────── */
.drow:active{background:var(--ct-wash-s)}
/* Метки справа не должны сжиматься: у них nowrap, и при сжатии текст
   вылезал за границу вместо того, чтобы отодвинуть название. */
.drow .mi2,.drow .daybadge,.drow .due,.drow .pill-blk{flex:none}
.drow .mi2{color:var(--d-sec)}              /* 12px в плотном списке → ≥7:1 */
/* «блок» / «ждём вас» — тревога, а не оттенок серого: theme.css:819 подменил
   токенную подложку литералом rgba(255,127,140,.14) от прежней палитры. */
.pill-blk{
  color:var(--danger);
  background:color-mix(in srgb, var(--danger) 14%, transparent);
}
/* Волосок между строками: список читается как список, а не как облако слов.
   :not(:last-child) — чтобы нижний волосок не спорил с кантом карточки. */
.dlist .drow:not(:last-child){box-shadow:inset 0 -1px 0 var(--d-hair)}


/* ───────────────────────────────────────────────────────────────────────────
   10 · КЛИЕНТЫ И КОМАНДА · .tm
   Карточка была залита var(--card2) → var(--card2) с серым кантом и серым кольцом
   присутствия: холодный островок на тёплой странице.
   ─────────────────────────────────────────────────────────────────────────── */
.tm{
  background:linear-gradient(168deg,
    var(--card) 0%,
    color-mix(in srgb, var(--panel) 55%, var(--card)) 100%);
  border-color:var(--line);
}
/* Ролевой тон. Был набором холодных серых (#9F9F9F, #ABABAB, #979797,
   #AFAFAF, #9A9A9A) — на тёплом фоне они читались как грязь. Роль не
   является состоянием, поэтому смысловые цвета ей не отдаём: всем тёплый
   нейтральный тон, акцент — только ведущему и фронтенду, как в базовом слое. */
.tm.r-pm,.tm.r-support,.tm.r-design,.tm.r-backend,
.tm.r-qa,.tm.r-devops,.tm.r-analytics,.tm.r-content{--tc:var(--tx-mut)}
.tm.r-lead,.tm.r-frontend{--tc:var(--acc)}   /* повтор app.css:902–903: карта ролей должна читаться целиком в одном месте */

.tm-av{background:var(--card2);border-color:var(--line2);color:var(--tx-mut)}
/* Ведущий — заливной аватар. Текст на оранжевом ТЁМНЫЙ: 5.9:1 против 3.2:1
   у белого, который стоял здесь до перевода на палитру (theme.css:841). */
.tm.r-lead .tm-av{
  background:linear-gradient(140deg, var(--acc-d), var(--acc));
  color:var(--on-acc);
  border-color:var(--acc);
}
.tm.r-pm .tm-av{background:var(--card2);color:var(--tx);border-color:var(--line2)}
/* Та же причина, что и у --tc, но носитель другой: инициалы и кант аватара
   до сих пор красились смысловыми цветами (app.css:742–745, 783–784,
   854–855) — бирюза у бэкенда и поддержки, охра у QA и контента, фиолет у
   дизайна и devops. Бирюза и охра уже заняты: «готово» и «скоро срок».
   Роль — не состояние, поэтому уводим её в тёплый нейтральный тон.
   .r-frontend не трогаем: у него акцент, и он совпадает с --tc. */
.tm.r-design .tm-av,.tm.r-backend .tm-av,.tm.r-qa .tm-av,.tm.r-devops .tm-av,
.tm.r-analytics .tm-av,.tm.r-content .tm-av,.tm.r-support .tm-av{
  background:var(--card2);color:var(--tx-mut);border-color:var(--line2);
}
/* Кольцо вокруг точки присутствия обязано совпадать с фоном карточки: в
   theme.css:845 оно осталось var(--card2) и на тёплой карточке светилось серым. */
.tm:not(.ghost) .tm-av::after{border-color:var(--card)}
/* Подвал 10,5px требует ≥7:1, --tx-dim давал ~4,3:1 */
.tm-foot,.tm-seen,.tm-now .nowl{color:var(--d-cap)}
.tm-note{color:var(--d-sec)}


/* ───────────────────────────────────────────────────────────────────────────
   11 · ПУСТЫЕ СОСТОЯНИЯ · .emptybox
   Пустой экран — приглашение, а не сбой загрузки. Значок обесцветили до
   #BCBCBC при уходе от синего (theme.css:823), и на тёплой странице он стал
   похож на недогруженную картинку. Возвращаем акцент: единственный цветной
   элемент экрана показывает, куда смотреть.
   ─────────────────────────────────────────────────────────────────────────── */
.emptybox .ei{
  background:linear-gradient(150deg, var(--card2), var(--panel));
  border-color:color-mix(in srgb, var(--acc) 26%, var(--line2));
  color:var(--acc-d);
  box-shadow:0 18px 44px -26px var(--glow), var(--dp-rim);
}


/* ───────────────────────────────────────────────────────────────────────────
   12 · ТЕЛЕФОН
   Проверочные ширины 390px и 360px. Плотные списки на телефоне ломаются
   первыми: цифры уезжают из колонки, действия слипаются.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:760px){
  /* Корешок «команда» тоньше: пузырь на телефоне и так узкий (theme.css:3185) */
  .cmt.adm .cmt-bubble,.cmt.adm.mine .cmt-bubble{--dx-rail-w:2px}
}
@media(max-width:400px){
  /* Края подсказки о прокрутке ужимаем: на 360px они съедали первую колонку */
  .tblwrap{background-size:16px 100%,16px 100%,10px 100%,10px 100%}
  /* Волоски между строками списка здесь единственные разделители */
  .dlist .drow:not(:last-child){box-shadow:inset 0 -1px 0 var(--line)}
}


/* ───────────────────────────────────────────────────────────────────────────
   13 · «МЕНЬШЕ ДВИЖЕНИЯ»
   Гасим то, что двигается именно в этом слое. Цвет и контраст остаются:
   состояние обязано читаться и без анимации.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .inv,.hrow,.lib,.drow,.doc-dl,.cmt-file,.rowact,.rowdel{transition:none}
  .inv:hover,.inv:has(.inv-badge + .inv-badge):hover{transform:none}
}

/* ▲▲▲ конец: ДАННЫЕ: ТАБЛИЦЫ, СЧЕТА, КОММЕНТАРИИ ▲▲▲ */

/* ▼▼▼ ЭКРАНЫ: ОБОЛОЧКА: МЕНЮ, ШАПКА, МОБИЛЬНЫЙ ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   ROBOWEB · КАБИНЕТ · семейство «ОБОЛОЧКА»
   боковое меню · верхняя панель · выпадающие меню · тосты · мобильный

   Подключать ПОСЛЕДНИМ (после app.css и theme.css): почти все правила ниже
   спорят с уже существующими и берут верх порядком в каскаде при равной
   специфичности. Где база специфичнее — селектор повторён с её префиксом,
   это отмечено в комментарии к правилу.

   Все классы сверены с разметкой app.js (renderApp / renderSide / quickJump /
   toast). Мёртвых селекторов нет. Сознательно НЕ стилизуются:
     .side .foot и .side .who — меню пользователя переехало в шапку,
        в renderSide этих узлов больше нет (правила в базе остались висеть);
     .side.collapsed / рельса-иконки — такого состояния в проекте не существует,
        «свёрнутое» в меню — это свёрнутый СПИСОК ПРОЕКТОВ (.navitem.more).

   Дисциплина цвета в этом файле:
     оранжевый  — «здесь ты»: активный пункт меню, фокус, первичное действие;
     розовый    — тревога: «ждёт вас», непрочитанные, выход;
     охра       — НЕ используется (она занята срочностью на доске),
                  поэтому избранный проект помечен светом, а не золотом;
     бирюза     — успех: включённые уведомления, удачный тост.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   0 · ТОКЕНЫ

   Боковое меню тёмное в ЛЮБОЙ теме, поэтому у него отдельное семейство
   --side-*, не привязанное к --tx/--card. Именно из-за этой обособленности
   оно и пережило переезд на палитру лендинга: в theme.css остались
   --side-card2:#1668DC (синяя заливка активного пункта Ant) и
   --side-acc:#4096FF. Их не видно в общей палитре — и они не поменялись.
   Здесь семейство переводится на тёплый строй целиком.

   Контраст посчитан к фактическому фону панели var(--panel):
     #F0ECE3 — 15.6:1 · #B7AEA0 — 8.4:1 · #9C9488 — 6.1:1 · #FF8256 — 7.5:1
   ─────────────────────────────────────────────────────────────────────────── */
:root,
[data-theme="dark"], :root[data-theme="dark"],
[data-theme="light"], :root[data-theme="light"]{
  --side-bg-a:#17150F;                  /* верх панели — на тон выше --panel */
  --side-bg-b:#100E0B;                  /* низ — уходит к фону страницы */
  --side-tx:#F0ECE3;
  --side-tx-mut:#B7AEA0;                /* пункты в покое: тише текста, но 8.4:1 */
  --side-tx-dim:#9C9488;                /* 10.5px рубрики; ниже опускаться нельзя */
  --side-line:rgba(255,246,232,.10);
  --side-line-s:rgba(255,246,232,.20);
  --side-card:rgba(255,246,232,.06);    /* наведение */
  --side-card2:rgba(255,90,50,.18);     /* активный пункт */
  --side-well:rgba(0,0,0,.30);
  --side-well-sh:inset 0 1px 2px rgba(0,0,0,.34);          /* утопленные поверхности: поле, счётчик */
  /* «Новый проект» красится ИНЛАЙНОМ из app.js: style="color:var(--side-acc)".
     Инлайн перебить нечем, кроме !important, — поэтому чиним сам токен. */
  --side-acc:#FF8256;

  /* собственные токены оболочки (грепом по app.css/app.js/theme.css: 0 совпадений) */
  --sh-glass-a:rgba(12,11,9,.92);       /* стекло шапки: плотнее вверху… */
  --sh-glass-b:rgba(12,11,9,.70);       /* …прозрачнее у нижней кромки */
  --sh-bar:rgba(255,246,232,.18);       /* ползунок прокрутки — тёплый нейтральный */
  --sh-bar-h:rgba(255,246,232,.34);
  --sh-veil:rgba(7,6,4,.66);            /* затемнение под мобильным меню */
  --sh-r:14px;                          /* панели и выпадашки — скругление лендинга */
  --sh-r-btn:10px;                      /* кнопки и поля */
  --sh-ring:0 0 0 4px color-mix(in srgb, var(--acc) 26%, transparent);
}


/* ───────────────────────────────────────────────────────────────────────────
   1 · ОБЩЕЕ ДЛЯ ВСЕЙ ОБОЛОЧКИ: выделение, фокус, скроллбары
   ─────────────────────────────────────────────────────────────────────────── */

/* Выделение текста: тёплый уголёк. Прежнее значение — 45% акцента на просвет:
   поверх карточек оно уходило в мутный кирпич, а на белом тексте давало
   меньше 4.5:1. Здесь фиксированная пара, контраст 8.9:1 на любом фоне. */
::selection{background:#5F2716; color:#FFF6EC; text-shadow:none}

/* Кольцо фокуса. Базовый :focus-visible уже оранжевый (--dp-focus #FF8256) —
   добавляем мягкий ореол там, где элемент лежит на цветной или стеклянной
   поверхности и один контур читается слабо. .side .navitem и .app-foot a
   в исходном перечне отсутствовали вовсе — до них доходили табом вслепую. */
.side .navitem:focus-visible,
.side .pin:focus-visible,
.side .psx:focus-visible,
.side .psearch input:focus-visible,
.burger:focus-visible,
.bellbtn:focus-visible,
.ubtn:focus-visible,
.udrop .navitem:focus-visible,
.qj-i:focus-visible,
.app-foot a:focus-visible{
  outline:2px solid var(--acc-d)!important;
  outline-offset:2px!important;
  box-shadow:var(--sh-ring);
  border-radius:var(--sh-r-btn);
}
/* внутри прокручиваемого списка проектов контур на 2px обрезается краем —
   уводим его внутрь, видно так же, но ничего не срезается */
.side-projects .navitem:focus-visible,
.side-projects .pin:focus-visible{outline-offset:-2px!important}

/* Скроллбары оболочки. В общем правиле темы ползунок собран из акцента
   (--ct-bar = 70% --acc), и после перехода на оранжевую палитру полоса
   прокрутки в меню стала оранжевой — тем же цветом, которым помечен
   активный пункт. Один цвет — один смысл: полосе достаётся тёплый нейтрал. */
.side-projects,
.qj-list{scrollbar-width:thin; scrollbar-color:var(--sh-bar) transparent}
.side-projects::-webkit-scrollbar,
.qj-list::-webkit-scrollbar{width:10px; height:10px; background:transparent}
.side-projects::-webkit-scrollbar-thumb,
.qj-list::-webkit-scrollbar-thumb{
  background:var(--sh-bar);
  border:3px solid transparent; background-clip:padding-box;
  border-radius:99px; min-height:32px;
  transition:background-color .16s ease;
}
.side-projects::-webkit-scrollbar-thumb:hover,
.qj-list::-webkit-scrollbar-thumb:hover{background:var(--sh-bar-h); background-clip:padding-box}
.side-projects::-webkit-scrollbar-track,
.qj-list::-webkit-scrollbar-track{background:transparent}
/* прокрутка списка проектов не должна утаскивать за собой страницу */
.side-projects{overscroll-behavior:contain}


/* ───────────────────────────────────────────────────────────────────────────
   2 · БОКОВОЕ МЕНЮ · панель и бренд
   ─────────────────────────────────────────────────────────────────────────── */
.side{
  background:linear-gradient(180deg, var(--side-bg-a) 0%, var(--side-bg-b) 100%);
  border-right:1px solid var(--side-line);
  color:var(--side-tx);
  padding:14px 10px;
  gap:4px;
}
/* 100vh на телефоне считается по развёрнутому браузеру: нижний край панели
   уезжает под адресную строку. 100dvh считается по видимой части. */
@supports (height:100dvh){ .side{height:100dvh} }

.side .brand{
  color:var(--side-tx);
  padding:6px 8px 16px;
  gap:10px;
  letter-spacing:-.01em;
}
/* Знак бренда был синим (--side-acc #4096FF) с почти чёрно-синей буквой
   #08121F — единственный синий пиксель, который клиент видит первым.
   Оранжевый градиент лендинга, буква тёмная (--on-acc, 5.9:1). */
.side .brand .dot{
  background:linear-gradient(140deg, #FF8256 0%, #E24E1B 100%);
  color:var(--on-acc);
  border-radius:8px;
  box-shadow:0 6px 18px -8px rgba(255,90,50,.70), inset 0 1px 0 rgba(255,255,255,.28);
}

.side-lbl{color:var(--side-tx-dim)}
.side .side-lbl{color:var(--side-tx-dim); padding:14px 8px 5px}


/* ───────────────────────────────────────────────────────────────────────────
   3 · ПУНКТЫ МЕНЮ · покой → наведение → «здесь ты»
   ─────────────────────────────────────────────────────────────────────────── */
.side .navitem{
  color:var(--side-tx-mut);
  border-radius:var(--sh-r-btn);
  padding:9px 11px;
  transition:background-color .16s ease, color .16s ease;
}
/* наведение — тёплая подложка без цвета: наведение это ещё не «здесь ты» */
.side .navitem:hover{color:var(--side-tx); background:var(--side-card)}
.side .navitem:active{background:rgba(255,246,232,.10)}

/* Активный пункт — ЕДИНСТВЕННОЕ место оранжевого в меню.
   Было: сплошная синяя плашка #1668DC (--side-card2) с белым текстом —
   заливка Ant, пережившая смену палитры. Здесь тёплый градиент, гаснущий
   вправо, и сплошная оранжевая рельса слева: рельса читается даже боковым
   зрением и не спорит с красной точкой «ждёт вас» на той же строке. */
.side .navitem.on{
  color:var(--side-tx);
  font-weight:700;
  background:linear-gradient(90deg,
    var(--side-card2) 0%,
    color-mix(in srgb, var(--acc) 7%, transparent) 54%,
    transparent 100%);
  box-shadow:none;
}
/* .navitem.on::before в базе — (0,2,0), поэтому повторяем с префиксом .side.
   Заодно убираем серый #DADADA в нижней точке градиента рельсы. */
.side .navitem.on::before{
  content:''; position:absolute; left:0; top:5px; bottom:5px; width:3px;
  border-radius:0 3px 3px 0; pointer-events:none;
  background:linear-gradient(180deg, var(--acc-d) 0%, var(--acc) 100%);
  box-shadow:0 0 10px 0 rgba(255,90,50,.55);
}
/* значки: в покое тише текста, на активном пункте — в цвет акцента.
   Базовое правило красит их в #FFFFFF (остаток от белого текста на синем). */
.side .navitem .ni-ic,
.side .navitem .pl-ic,
.side .navitem>svg{color:var(--side-tx-dim)}
.side .navitem:hover .ni-ic,
.side .navitem:hover .pl-ic,
.side .navitem:hover>svg{color:var(--side-tx)}
.side .navitem.on .ni-ic,
.side .navitem.on svg{color:var(--acc-d)}

/* Счётчики у пунктов и число проектов у рубрики.
   Было rgba(0,0,0,.22) поверх холодной панели и белая обводка сверху.
   Утопленная тёплая ямка: на ней --side-tx-dim даёт 6.5:1 при 11px. */
.side .navitem .cnt,
.side .side-n{
  color:var(--side-tx-dim);
  background:var(--side-well);
  border:0;
  box-shadow:inset 0 0 0 1px rgba(255,246,232,.06);
  border-radius:999px;
  padding:1px 7px;
  font-variant-numeric:tabular-nums;
}
.side .navitem:hover .cnt{color:var(--side-tx); background:rgba(255,246,232,.12)}
/* на активном пункте счётчик тоже уходит в тёплый: белый на оранжевой
   подложке давал 3.2:1 и выпадал из нормы */
.side .navitem.on .cnt{
  color:var(--side-tx);
  background:rgba(255,90,50,.24);
  box-shadow:inset 0 0 0 1px rgba(255,138,100,.34);
}

/* «Новый проект» — первичное действие, поэтому оранжевый уместен.
   Цвет приходит инлайном (--side-acc), нам остаётся подложка и значок. */
.side .navitem[data-newproject]{margin-top:4px; font-weight:700}
.side .navitem[data-newproject] .ni-ic{color:inherit}
.side .navitem[data-newproject]:hover{
  color:var(--acc-d);
  background:color-mix(in srgb, var(--acc) 13%, transparent);
}

/* «Показать все · N» / «Свернуть» — свёрнутое состояние списка проектов.
   Пунктир по границе был синим при наведении (--side-acc). Наведение здесь
   не «здесь ты» и не действие с последствиями — значит, нейтральное. */
.side .navitem.more{
  color:var(--side-tx-mut);
  border:1px dashed var(--side-line-s);
  background:none;
  border-radius:var(--sh-r-btn);
  min-height:36px;
  margin-top:4px;
}
.side .navitem.more:hover{
  color:var(--side-tx);
  background:var(--side-card);
  border-style:solid;
  border-color:var(--side-line-s);
}
.side .navitem.more .ni-ic{color:inherit}


/* ───────────────────────────────────────────────────────────────────────────
   4 · СПИСОК ПРОЕКТОВ · поиск, избранное, точка «ждёт вас»
   ─────────────────────────────────────────────────────────────────────────── */

/* Поле поиска. Общий стиль полей берёт --fi-bg (#2D2D2D в тёмной, #F5F5F5 в
   светлой) — но меню тёмное в ОБЕИХ темах, и в светлой поле становилось почти
   белым под белым текстом --side-tx: 1.07:1, то есть строка поиска исчезала.
   Поэтому у поля в меню собственная тёплая ямка, независимая от темы. */
.side .psearch{margin:2px 0 8px}
.side .psearch input{
  background-color:var(--side-well);
  border:1px solid var(--side-line);
  border-radius:var(--sh-r-btn);
  color:var(--side-tx);
  box-shadow:var(--side-well-sh);
  caret-color:var(--acc-d);
  /* лупа из общего набора нарисована холодным сине-серым #8A94AF (тёмная) и
     #5C6480 (светлая) — оба из прежней палитры. Своя, тёплая и одинаковая. */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239C9488' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.6-3.6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:11px center;
  background-size:15px 15px;
  transition:border-color .16s ease, background-color .16s ease, box-shadow .16s ease;
}
.side .psearch input::placeholder{color:var(--side-tx-dim); opacity:1}
.side .psearch input:hover{border-color:var(--side-line-s)}
.side .psearch input:focus{
  border-color:var(--acc);
  box-shadow:var(--side-well-sh),
             0 0 0 3px color-mix(in srgb, var(--acc) 26%, transparent);
}
/* Кольцо фокуса у поиска рисует box-shadow выше; отдельный outline поверх него
   давал третий контур подряд — рамка, ореол и системный контур, и поле выглядело
   обведённым в три кольца. Держим один ореол: он одинаково заметен и мышью,
   и с клавиатуры, поэтому доступность не страдает. */
.side .psearch input:focus-visible{outline:2px solid transparent!important; outline-offset:0!important}

.side .psx{
  color:var(--side-tx-dim);
  border-radius:8px;
  transition:color .14s ease, background-color .14s ease;
}
.side .psx:hover{color:var(--side-tx); background:rgba(255,246,232,.12)}

/* Избранное. Дефект специфичности: .side .pin (0,2,0) идёт в файле ПОЗЖЕ,
   чем .pin.on (0,2,0), — и закрашивал отмеченную звезду обратно в серый.
   Отмеченный проект был неотличим от неотмеченного.
   Цвет намеренно не золотой: охра в кабинете означает срочность, и звезда
   «избранное» дала бы ей второй смысл. Отличие — светом и весом. */
.side .pin{
  color:var(--side-tx-dim);
  opacity:0;
  width:24px; height:24px; padding:0;
  border-radius:7px;
  transition:opacity .14s ease, color .14s ease, background-color .14s ease, transform .12s ease;
}
.side .navitem.proj:hover .pin,
.side .pin.on,
.side .pin:focus-visible{opacity:1}
.side .pin.on{color:var(--side-tx); text-shadow:0 0 10px rgba(255,246,232,.5)}
.side .pin:hover{color:var(--side-tx); background:rgba(255,246,232,.12); transform:scale(1.12)}
.side .pin:active{transform:scale(.94)}

/* Точка «Ждёт вас» — блокировка на стороне клиента, это тревога.
   Даём ей мягкий ореол: 6px розового на тёплом фоне читались как соринка,
   а на активном (оранжевом) пункте почти сливались. */
.side .pdot.blk{
  width:7px; height:7px;
  background:var(--danger);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--danger) 20%, transparent);
}

/* название проекта: две строки, длинные имена не растягивают колонку */
.side .navitem.proj{align-items:flex-start; padding-top:8px; padding-bottom:8px}
.side .navitem.proj .pmeta{padding-top:1px}


/* ───────────────────────────────────────────────────────────────────────────
   5 · ВЕРХНЯЯ ПАНЕЛЬ · стекло
   ─────────────────────────────────────────────────────────────────────────── */

/* Стекло было выключено: blur остался на ::before (осознанный фикс, чтобы
   backdrop-filter на самой .topbar не делал её containing block для .udrop),
   но фоном псевдоэлемента поставили СПЛОШНОЙ var(--panel) — сквозь
   непрозрачную заливку размывать нечего, и шапка читалась как обычная плашка.
   Возвращаем стекло: плотнее вверху (текст шапки не спорит с фоном),
   прозрачнее у нижней кромки. brightness приглушает то, что проезжает под
   шапкой, — так контент не «мылится» поверх заголовка, а уходит в тень. */
.topbar::before{
  background:linear-gradient(180deg, var(--sh-glass-a) 0%, var(--sh-glass-b) 100%);
  backdrop-filter:blur(18px) saturate(1.18) brightness(.84);
  -webkit-backdrop-filter:blur(18px) saturate(1.18) brightness(.84);
  border-bottom:1px solid var(--line);
  box-shadow:0 14px 28px -24px rgba(0,0,0,.9);
}
/* без поддержки backdrop-filter стекла не будет — тогда честная плотная плашка,
   иначе текст под полупрозрачной шапкой останется читаемым насквозь */
@supports not ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .topbar::before{background:var(--panel)}
}
/* световая нить под шапкой: была чисто белой (rgba(255,255,255,.35)) —
   на тёплом угле она отдавала синевой. Тёплый белый и вдвое тише. */
.topbar::after{
  background:linear-gradient(90deg,
    transparent 0%, rgba(255,246,232,.16) 30%, rgba(255,246,232,.16) 70%, transparent 100%);
  opacity:1;
}

.topbar h1,#crumb h1{color:var(--tx)}
.topbar .desc{color:var(--tx-mut)}
.topbar .sp{margin-left:auto}

/* Кнопки-глифы шапки. В одном ряду было три разных скругления: 6px у
   .iconbtn (бургер, тема, колокол) и 11px у .ubtn при 10px у всех остальных
   кнопок кабинета — ряд выглядел собранным из разных наборов. */
.iconbtn,.ubtn{border-radius:var(--sh-r-btn)}
.iconbtn:hover{border-color:color-mix(in srgb, var(--acc) 38%, var(--line2))}

/* Переключатель темы: доворот «луны» был написан на #theme, а кнопка в
   разметке — #themeBtn. Правило не срабатывало ни разу. */
#themeBtn:hover svg{transform:rotate(-18deg) scale(1.06)}

/* Колокол и счётчик непрочитанного.
   Счётчик — пилюля, а не чип: в группе скруглений он получил 6px, и
   двузначное «9+» в 18-пиксельной коробке выглядело квадратной наклейкой. */
.nbadge{
  border-radius:999px;
  min-width:19px; height:19px; padding:0 5px;
  border:2px solid var(--bg);
  background:#D32F3F; color:#FFFFFF;          /* 5.2:1 */
  font-variant-numeric:tabular-nums; letter-spacing:0;
  box-shadow:0 0 0 1px rgba(211,47,63,.45), 0 4px 12px -4px rgba(211,47,63,.7);
}
/* когда есть непрочитанные — кнопка это подхватывает рамкой: счётчик и
   колокол читаются как одна вещь, а не как наклейка поверх */
.bellbtn:has(.nbadge:not(.hidden)){border-color:color-mix(in srgb, #D32F3F 38%, var(--line2))}


/* ───────────────────────────────────────────────────────────────────────────
   6 · МЕНЮ ПОЛЬЗОВАТЕЛЯ · .ubtn / .uav / .uchev / .udrop
   ─────────────────────────────────────────────────────────────────────────── */
.uav{
  background:linear-gradient(150deg, var(--acc-d) 0%, var(--acc) 100%);
  color:var(--on-acc);                        /* тёмный по оранжевому — 5.9:1 */
  border-radius:8px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.32), 0 3px 10px -6px var(--glow);
}
.ubtn[aria-expanded="true"]{
  border-color:var(--acc);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 24%, transparent);
}
.ubtn[aria-expanded="true"] .uchev{color:var(--acc-d)}

/* Крышка меню: 8px против 14px у карточек и модалок — мелочь, по которой
   меню выглядело «не отсюда». Скругление и материал как у панелей лендинга. */
.udrop{
  border-radius:var(--sh-r);
  border:1px solid var(--line2);
  box-shadow:var(--dp-e4);
  padding:8px;
  max-width:calc(100vw - 24px);
}
.udrop::before{border-radius:4px 0 0 0}
.udrop .who{
  border-bottom:1px solid var(--line);
  color:var(--tx-mut);                        /* было --tx-dim: 4.6:1 при 12.5px */
  padding:8px 10px 12px;
  margin-bottom:6px;
}
.udrop .who b{color:var(--tx)}
/* пункты меню — основные цели клика, поэтому в полный текст, а не в mut */
.udrop .navitem{color:var(--tx); border-radius:var(--sh-r-btn); min-height:44px}
.udrop .navitem .ni-ic{color:var(--tx-mut)}
.udrop .navitem:hover{background:var(--ct-wash); color:var(--tx)}
.udrop .navitem:hover .ni-ic{color:var(--acc-d)}
/* «Включить уведомления» получает inline color:var(--ok), когда они включены.
   Значок наследует цвет — состояние читается целиком, а не половиной строки. */
.udrop .navitem[data-push] .ni-ic{color:inherit}
/* «Выйти» — единственное необратимое действие в меню */
.udrop .navitem[data-logout]:hover{
  background:color-mix(in srgb, var(--danger) 14%, transparent);
  color:var(--danger);
}
.udrop .navitem[data-logout]:hover .ni-ic{color:var(--danger)}


/* ───────────────────────────────────────────────────────────────────────────
   7 · БЫСТРЫЙ ПЕРЕХОД · Cmd/Ctrl+K
   ─────────────────────────────────────────────────────────────────────────── */
.qj #qjq{color:var(--tx); border-bottom:1px solid var(--line)}
.qj #qjq::placeholder{color:var(--tx-mut); opacity:1}
.qj #qjq:focus{border-bottom-color:var(--acc)}

/* Курсор клавиатуры (.on) и наведение мышью выглядели одинаково: при мыши над
   третьей строкой и курсоре на первой «выбранными» казались обе, а Enter
   открывал первую. Разводим: наведение — нейтральная подложка, курсор —
   акцент и рельса, то есть то же «здесь ты», что и в меню. */
.qj-i{border-radius:var(--sh-r-btn); position:relative}
.qj-i:hover{background:rgba(255,246,232,.07)}
.qj-i.on{
  background:color-mix(in srgb, var(--acc) 15%, transparent);
  color:var(--tx);
}
.qj-i.on::before{
  content:''; position:absolute; left:0; top:6px; bottom:6px; width:3px;
  border-radius:0 3px 3px 0; background:var(--acc); pointer-events:none;
}
.qj-s{color:var(--tx-mut)}                   /* было --tx-dim: 4.6:1 при 11.5px */
.qj-hint{color:var(--tx-mut); border-top:1px solid var(--line)}
.qj-empty{color:var(--tx-mut)}


/* ───────────────────────────────────────────────────────────────────────────
   8 · ТОСТЫ
   ─────────────────────────────────────────────────────────────────────────── */
.toast{
  border-radius:var(--sh-r);
  border:1px solid var(--line2);
  color:var(--tx);
  box-shadow:var(--dp-e4);
}
.toast.err{border-color:color-mix(in srgb, var(--danger) 55%, var(--line2))}


/* ───────────────────────────────────────────────────────────────────────────
   9 · ФУТЕР
   ─────────────────────────────────────────────────────────────────────────── */
.app-foot{
  /* было ...rgba(43,43,43,0) — прозрачный СЕРЫЙ: середина градиента уходила
     в холодную муть. Тёплый акцентный подсвет и честная прозрачность. */
  background:linear-gradient(180deg, color-mix(in srgb, var(--acc) 4%, transparent), transparent), var(--bg);
  border-top:1px solid var(--line);
  color:var(--tx-mut);                        /* было --tx-dim: 5.2:1 при 12.5px */
}
.app-foot a{color:var(--tx-mut); border-radius:6px}
.app-foot a:hover{color:var(--acc-d); text-decoration:underline; text-underline-offset:3px}


/* ───────────────────────────────────────────────────────────────────────────
   10 · ЗАТЕМНЕНИЕ И МОБИЛЬНЫЙ ЯЩИК
   ─────────────────────────────────────────────────────────────────────────── */
/* было rgba(39,39,39,.62) — серая вуаль поверх тёплого угля */
.scrim{background:var(--sh-veil); backdrop-filter:blur(2px); -webkit-backdrop-filter:blur(2px)}

@media(max-width:820px){
  /* Закрытый ящик оставался в порядке обхода табом: клавиатура уходила в
     невидимое меню за левым краем экрана. visibility убирает его из обхода,
     задержка снятия — чтобы уезд по-прежнему анимировался. */
  .side{
    visibility:hidden;
    transition:transform .26s cubic-bezier(.2,.8,.25,1), visibility 0s linear .26s;
    will-change:transform;
  }
  .side.open{
    visibility:visible;
    transition:transform .28s cubic-bezier(.2,.8,.25,1), visibility 0s;
    box-shadow:0 0 0 1px var(--side-line), 24px 0 60px -20px rgba(0,0,0,.85);
  }
  /* вырез и нижняя шторка телефона: панель не должна упираться в них вплотную */
  .side{
    padding-left:calc(10px + env(safe-area-inset-left, 0px));
    padding-bottom:calc(14px + env(safe-area-inset-bottom, 0px));
  }
  /* страховка от горизонтальной прокрутки страницы: overflow:clip (в отличие
     от hidden) не создаёт контейнер прокрутки, поэтому липкая шапка внутри
     продолжает работать */
  @supports (overflow:clip){ .shell{overflow-x:clip} }
}

/* ───────────────────────────────────────────────────────────────────────────
   11 · ТЕЛЕФОН · зоны нажатия, безопасные отступы, облегчённое стекло
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:760px){
  .iconbtn,.burger,.ubtn{min-width:44px; min-height:44px}
  .side .navitem{min-height:46px; padding:11px 12px}
  .side .navitem.more{min-height:44px}
  /* базовое правило показывает звёзды на тач-экранах (ховера нет), но оно
     записано как .pin (0,1,0) и слабее нашего .side .pin — повторяем */
  .side .pin{opacity:1; width:36px; height:36px; margin:-6px -6px -6px 0}
  .side .psx{width:44px; height:44px}
  .side .psearch input{padding-right:46px; font-size:16px}  /* 16px — iOS не зумит */
  .app-foot a{min-height:40px; display:inline-flex; align-items:center}

  .topbar{
    padding-left:max(var(--sp-4), env(safe-area-inset-left, 0px));
    padding-right:max(var(--sp-4), env(safe-area-inset-right, 0px));
  }
  .app-foot{padding-bottom:calc(15px + env(safe-area-inset-bottom, 0px))}
  .toast{bottom:calc(18px + env(safe-area-inset-bottom, 0px))}

  /* стекло на телефоне дешевле: blur — самый дорогой эффект для мобильного GPU */
  .topbar::before{
    backdrop-filter:blur(12px) saturate(1.12) brightness(.86);
    -webkit-backdrop-filter:blur(12px) saturate(1.12) brightness(.86);
  }
  .scrim{backdrop-filter:none; -webkit-backdrop-filter:none}

  /* меню пользователя держим абсолютным относительно .umenu: у шапки
     backdrop-filter, а он делает её containing block для fixed-потомков */
  .udrop{
    position:absolute; top:calc(100% + 10px); right:0; left:auto; bottom:auto;
    width:min(320px, calc(100vw - 24px)); min-width:0;
  }
}
@media(max-width:560px){
  /* на узком экране крошка важнее кнопок — отдаём ей всю свободную ширину */
  #crumb{flex:1 1 auto; min-width:0}
  .topbar{gap:8px}
}
@media(max-width:400px){
  .side{width:min(84vw, 268px)}
  .udrop{width:calc(100vw - 20px)}
  /* сияние под шапкой на самых узких экранах тише — мелкий текст на
     полупрозрачных участках не должен терять контраст */
  .topbar::after{opacity:.65}
  .topbar::before{
    backdrop-filter:blur(9px) saturate(1.1) brightness(.88);
    -webkit-backdrop-filter:blur(9px) saturate(1.1) brightness(.88);
  }
}


/* ───────────────────────────────────────────────────────────────────────────
   12 · СИСТЕМНЫЕ ПРЕДПОЧТЕНИЯ
   ─────────────────────────────────────────────────────────────────────────── */

/* «меньше прозрачности» (iOS/macOS): стекло меняется на плотную плашку */
@media(prefers-reduced-transparency: reduce){
  .topbar::before{
    background:var(--panel);
    backdrop-filter:none; -webkit-backdrop-filter:none;
  }
  .scrim{backdrop-filter:none; -webkit-backdrop-filter:none; background:rgba(7,6,4,.82)}
}

@media(prefers-reduced-motion: reduce){
  .side{transition:none}
  .side .navitem,.side .pin,.side .psx,.side .psearch input,
  .udrop .navitem,.qj-i,.app-foot a{transition:none}
  .side .pin:hover,.side .pin:active{transform:none}
  #themeBtn:hover svg{transform:none}
}

/* Высококонтрастный режим Windows: фон и тени там игнорируются, и активный
   пункт остался бы неотличимым. Отмечаем его системным контуром. */
@media(forced-colors: active){
  .side .navitem.on{outline:2px solid Highlight; outline-offset:-2px}
  .side .navitem.on::before{background:Highlight}
  .qj-i.on{outline:2px solid Highlight; outline-offset:-2px}
  .nbadge{border-color:CanvasText}
}

/* ▲▲▲ конец: ОБОЛОЧКА: МЕНЮ, ШАПКА, МОБИЛЬНЫЙ ▲▲▲ */

/* ── Токены оболочки в блоке светлой темы были заданы ТЁМНЫМИ значениями
   (копипаста из тёмной): стекло шапки оставалось почти чёрным на кремовом
   фоне, и заголовок раздела читался тёмным по тёмному. Задаём светлые. ── */
:root[data-theme="light"]{
  --sh-glass-a:rgba(253,250,244,.94);   /* стекло шапки: плотнее вверху… */
  --sh-glass-b:rgba(244,237,225,.78);   /* …прозрачнее у нижней кромки */
  --sh-bar:rgba(58,42,24,.22);          /* ползунок прокрутки */
  --sh-bar-h:rgba(58,42,24,.36);
  --sh-veil:rgba(58,42,24,.42);         /* затемнение под мобильным меню */
}

/* ── В блоке светлой темы токены сайдбара тоже были заданы ТЁМНЫМИ значениями:
   --side-tx:#F0ECE3 (почти белый) на кремовом фоне давал 1,13:1 у бренда
   и 2,11:1 у пунктов меню — текст практически исчезал. Задаём светлые.
   Контраст после правки: бренд 12,4:1, пункт в покое 7,4:1, активный 8,3:1. ── */
:root[data-theme="light"]{
  --side-tx:#26211A;
  --side-tx-mut:#564D40;
  --side-tx-dim:#645B4F;
  --side-line:rgba(58,42,24,.13);
  --side-line-s:rgba(58,42,24,.26);
  --side-well:rgba(58,42,24,.055);
  --side-well-sh:inset 0 1px 2px rgba(58,42,24,.07);
  --side-card:#FDFAF4;
  --side-card2:rgba(217,60,19,.12);
  --side-acc:#B8300E;
}

/* ── Пункты меню в светлой теме: задаём цвет напрямую и с запасом по
   специфичности. Через токен не проходило — где-то по пути цвет
   перехватывался, а поиск виновника обходился дороже, чем явное правило.
   Контраст: покой 7,4:1, наведение 13,6:1, активный 8,3:1 на кремовом. ── */
:root[data-theme="light"] .side .navitem,
:root[data-theme="light"] .side .navitem .t{color:#564D40}
:root[data-theme="light"] .side .navitem:hover,
:root[data-theme="light"] .side .navitem:hover .t{color:#26211A}
:root[data-theme="light"] .side .navitem.on,
:root[data-theme="light"] .side .navitem.on .t{color:#8F2408}
:root[data-theme="light"] .side .navitem .cnt{color:#645B4F; background:rgba(58,42,24,.08)}
:root[data-theme="light"] .side .navitem.on .cnt{color:#8F2408; background:rgba(217,60,19,.14)}
:root[data-theme="light"] .side .navitem>svg,
:root[data-theme="light"] .side .navitem .ni-ic{color:#645B4F}
:root[data-theme="light"] .side .navitem.on>svg,
:root[data-theme="light"] .side .navitem.on .ni-ic{color:#B8300E}

/* ═══ СМЕТА ПО ПОЖЕЛАНИЮ ═══════════════════════════════════════════════
   Клиент видит предложение и отвечает одной кнопкой. Блок намеренно
   заметный: это единственное место в кабинете, где от клиента ждут
   решения о деньгах, и оно не должно потеряться среди чипов и полей.
   Контраст: заголовок 15.9:1 тёмная / 13.6:1 светлая; сумма — то же;
   подпись «ждём вашего решения» на охряной плашке 7.4:1 / 7.1:1. ═══ */
.quote{
  border:1px solid var(--line2); border-radius:14px; padding:16px 18px;
  margin:0 0 18px; background:var(--card2); box-shadow:var(--dp-e1), var(--dp-rim);
}
.quote-sent{
  border-color:color-mix(in srgb, var(--warn) 42%, var(--line2));
  background:linear-gradient(180deg, color-mix(in srgb, var(--warn) 9%, var(--card2)), var(--card2));
}
.quote-ok{border-color:color-mix(in srgb, var(--ok) 40%, var(--line2))}
.quote-no{border-color:var(--line2); opacity:.9}
.quote .q-h{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px}
.quote .q-h b{font-size:16px;font-weight:700;letter-spacing:-.01em;color:var(--tx)}
.quote .q-tag{
  font-size:11.5px;font-weight:600;letter-spacing:.02em;padding:3px 9px;border-radius:99px;
  color:var(--warn); background:color-mix(in srgb, var(--warn) 15%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--warn) 34%, transparent);
}
.quote-ok .q-tag{color:var(--ok); background:color-mix(in srgb, var(--ok) 15%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--ok) 34%, transparent)}
.quote-no .q-tag{color:var(--tx-dim); background:var(--card); box-shadow:inset 0 0 0 1px var(--line)}

/* Числа — главный герой блока: крупно, моноширинным, в столбик по правому краю */
.quote .q-nums{display:flex;gap:26px;flex-wrap:wrap;margin-bottom:12px}
.quote .q-nums u{display:block;text-decoration:none;font-size:10.5px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--tx-dim);font-weight:600;margin-bottom:4px}
.quote .q-nums b{display:block;font-family:var(--mono);font-size:24px;line-height:1;
  font-weight:700;letter-spacing:-.02em;color:var(--tx);font-variant-numeric:tabular-nums}
.quote .q-note{
  font-size:13.5px;line-height:1.55;color:var(--tx-mut);
  padding:11px 13px;border-radius:10px;background:var(--card);
  border-left:3px solid color-mix(in srgb, var(--warn) 45%, transparent);margin-bottom:14px;
}
.quote .q-act{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:8px}
.quote .hint{font-size:12px;color:var(--tx-dim)}

/* Блок для команды — сворачиваемый, чтобы не мешал в обычной работе */
details.quote-adm{margin:0 0 16px}
details.quote-adm>summary .ps-t{color:var(--warn)}

@media(max-width:560px){
  .quote{padding:14px}
  .quote .q-nums{gap:18px}
  .quote .q-nums b{font-size:21px}
  .quote .q-act .btn{width:100%;justify-content:center}
}

/* ▼▼▼ ЭКРАН ВХОДА — УСИЛЕНИЕ ▼▼▼ */
/* ═══════════════════════════════════════════════════════════════════════════
   ЭКРАН ВХОДА · усиление отделки · roboweb.team / клиентский кабинет
   Подключать ПОСЛЕДНИМ — после app.css и theme.css. Там, где специфичность
   совпадает с уже существующим правилом, выигрывает порядок, и это осознанно.

   Разметку не трогаю: работаю только с классами, которые реально печатает
   app.js (authShell / renderLogin / renderRegister / pwField):
     .login-wrap.auth · .auth-side · .auth-side-in · .brand · .dot ·
     .auth-hero (h2,p) · .auth-pts > li > .ap-ic + div > b + span ·
     .auth-side-foot · .auth-main · form.login · h1 · .auth-sub ·
     .field > label + input · .pw-wrap · .pw-eye(.on) · .err(.on) ·
     .btn.btn-primary.auth-go(.loading) · .auth-alt a · .auth-back a

   ЧТО ЗДЕСЬ ПОЧИНЕНО ПОПУТНО (найдено чтением app.css/theme.css/app.js):
   ▸ .auth-hero h2 был зашит color:#FFFFFF (theme.css:4005) — в светлой теме
     витрина кремовая (#FDFAF4), и заголовок пропадал: 1.03:1. Классическая
     ловушка проекта: значение тёмной темы осталось без парного светлого.
   ▸ .ap-ic и .pw-eye нигде не задают размер вложенному <svg>, а ICON.* в
     app.js рисуется через svg() без width/height. Иконка раздувалась до
     размера по умолчанию и вываливалась из коробки 36×36.
   ▸ Крутилка отправки НЕ показывалась вообще: .btn:disabled::after{content:none}
     (theme.css:4111) стоит ПОЗЖЕ .auth-go.loading::after (theme.css:4063) при
     равной специфичности (0,2,0). А .btn:disabled{color:inherit;opacity:.45}
     тем же способом перебивал .auth-go.loading{color:transparent} — человек
     видел полупрозрачную кнопку с подписью и без признака работы.
   ▸ Крутилка была белой (border-top-color:#FFFFFF) поверх оранжевой заливки,
     на которой текст ТЁМНЫЙ (--ct-on #1A0B05): белое кольцо давало ~2.6:1.
   ▸ В светлой теме подпись поля в фокусе красится в --acc-tx (#B8300E,
     app.css:1771). Подпись — 11px капсом, ей нужно ≥7:1, а было 5.21:1.

   КОНТРАСТ. Считан по WCAG к реальной подложке элемента (составные подложки
   сведены с учётом альфы). Порог: основной текст ≥7:1, второстепенный ≥4.5:1,
   всё 11px и мельче ≥7:1. Числа — в комментариях по месту.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   1 · ТОКЕНЫ ОБЛАСТИ
   Поля и первичная кнопка кабинета до сих пор питаются семействами --fi-* и
   --ct-*, которые объявлены ВЫШЕ перехода на палитру лендинга и остались
   холодными (--fi-bg #2D2D2D). На витрине входа это видно сразу: тёплый уголь
   вокруг и серая щель поля внутри. Переопределяю их ТОЛЬКО внутри экрана
   входа — кабинет остаётся как есть.
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth{
  /* поле: тёплая ниша на полтона выше фона страницы (#0C0B09 темнее уже некуда) */
  --fi-bg:#171410;
  --fi-bg-hover:#1C1913;
  --fi-bg-focus:#201C15;
  --fi-line:rgba(255,246,232,.13);
  --fi-line-hover:rgba(255,246,232,.26);
  --fi-ph:#9B927F;                 /* 5.95:1 на поле (плейсхолдеров в разметке нет — задел) */
  --fi-label:#C6BDAE;              /* 11px капс: 10.58:1 на --bg, 9.90:1 на карточке */
  --fi-well:inset 0 1px 0 rgba(255,246,232,.05), inset 0 2px 7px -3px rgba(0,0,0,.85);
  /* кольцо фокуса из двух шагов: плотная кромка + мягкий ореол вокруг неё */
  --fi-ring:0 0 0 1px rgba(255,130,86,.55), 0 0 0 4px rgba(255,90,50,.18);

  /* кнопка: заливка глубже стандартной, чтобы тёмная подпись держала норму */
  --ct-fill-a:#FF7448;             /* --ct-on #1A0B05 → 7.17:1 */
  --ct-fill-b:#E04A18;             /* --ct-on #1A0B05 → 4.72:1 */
  --ct-fill-h-a:#FF8A63;           /* 8.29:1 */
  --ct-fill-h-b:#EE5620;           /* 5.47:1 */
  --ct-halo:0 12px 34px -14px rgba(255,90,50,.72);

  /* акцент как ТЕКСТ на этом экране (подпись поля в фокусе, ссылки) */
  --acc-tx:#FF8256;                /* 8.04:1 на --bg, 7.52:1 на карточке */

  /* собственные величины экрана, чтобы не плодить магические числа */
  --au-grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)' opacity='.07'/%3E%3C/svg%3E");
  --au-ray:rgba(255,168,128,.075);
  --au-ray2:rgba(255,168,128,.05);
  --au-grid:rgba(255,246,232,.035);
  --au-grid-fine:rgba(255,246,232,.016);
  --au-foot:#A39A8C;               /* 12.5px: 7.03:1 на низе витрины */
  --au-err-tx:#FF8A93;             /* 7.44:1 на собственной подложке */
  --au-err-bg:rgba(255,110,122,.13);
  --au-err-line:rgba(255,110,122,.34);
  --au-eye:#A8A092;                /* 7.09:1 на поле — «глаз» читаем и в покое */
  --au-seam:rgba(255,246,232,.10);
  --au-card:#16140F;
}

/* Светлая тема. Селектор :root[data-theme="light"] (0,3,0) специально сильнее
   базового .login-wrap.auth (0,2,0) — иначе тёмные значения текут в светлую.
   Каждому литералу выше здесь есть ПАРА, ни одно значение не унаследовано. */
:root[data-theme="light"] .login-wrap.auth{
  --fi-bg:#FFFDF9;                 /* поле светлее кремовой страницы: «чистый лист» */
  --fi-bg-hover:#FFFFFF;
  --fi-bg-focus:#FFFFFF;
  --fi-line:rgba(58,42,24,.20);
  --fi-line-hover:rgba(58,42,24,.34);
  --fi-ph:#6B6153;                 /* 5.97:1 на поле */
  --fi-label:#4A4136;              /* 11px капс: 8.59:1 на --bg, 9.60:1 на карточке */
  --fi-well:inset 0 1px 2px rgba(90,60,25,.10);
  --fi-ring:0 0 0 1px rgba(217,60,19,.55), 0 0 0 4px rgba(217,60,19,.16);

  /* на кремовом оранжевый под БЕЛОЙ подписью нужен глубже: #E4491C давал 3.99:1 */
  --ct-fill-a:#D2410F;             /* белый → 4.66:1 */
  --ct-fill-b:#B0300C;             /* белый → 6.41:1 */
  --ct-fill-h-a:#D2410F;           /* наведение НЕ осветляет верх: выше 4.5:1 не удержать */
  --ct-fill-h-b:#BC360D;           /* белый → 5.72:1 — светлеет только низ */
  --ct-halo:0 12px 30px -14px rgba(217,60,19,.5);

  --acc-tx:#96250A;                /* 11px капс в фокусе: 7.03:1 на --bg, 7.86:1 на карточке */

  --au-grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)' opacity='.05'/%3E%3C/svg%3E");
  --au-ray:rgba(217,60,19,.055);
  --au-ray2:rgba(217,60,19,.035);
  --au-grid:rgba(58,42,24,.06);
  --au-grid-fine:rgba(58,42,24,.028);
  --au-foot:#5A5145;               /* 12.5px: 6.41:1 на низе витрины */
  --au-err-tx:#A81430;             /* 5.50:1 на подложке (#C81E3A давал 4.17:1) */
  --au-err-bg:rgba(200,30,58,.10);
  --au-err-line:rgba(200,30,58,.28);
  --au-eye:#6B6153;                /* 5.97:1 на поле */
  --au-seam:rgba(58,42,24,.16);
  --au-card:#FDFAF4;
}


/* ───────────────────────────────────────────────────────────────────────────
   2 · КАРКАС И «ФАЛЬЦ» МЕЖДУ ВИТРИНОЙ И ФОРМОЙ
   Стык двух колонок был встык, без шва. Одна волосяная линия и подсветка,
   вытекающая из витрины на сторону формы, превращают стык в разворот.
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth{
  min-height:100dvh;               /* адресная строка мобильного не режет форму */
}

/* .auth-main — грид с place-items:center. Псевдоэлемент здесь стал бы третьим
   элементом грида и уехал во вторую строку, поэтому он абсолютный, а самому
   контейнеру нужен position:relative. */
.login-wrap.auth .auth-main{
  position:relative;
  isolation:isolate;               /* тени формы не проваливаются под соседние слои */
}
.login-wrap.auth .auth-main::before{
  content:''; position:absolute; inset:0; pointer-events:none; z-index:0;
  background:
    radial-gradient(72% 46% at 6% 8%, var(--au-ray), transparent 60%),
    radial-gradient(60% 44% at 96% 100%, var(--au-ray2), transparent 62%);
}
/* Шов: слева от формы — тонкая грань, как фальц у печатного разворота */
.login-wrap.auth .auth-main::after{
  content:''; position:absolute; left:0; top:0; bottom:0; width:1px; z-index:0;
  pointer-events:none;
  background:linear-gradient(180deg, transparent, var(--au-seam) 22%, var(--au-seam) 78%, transparent);
}
/* форма поднимается над обоими декоративными слоями */
.login-wrap.auth .login{
  position:relative; z-index:1;
}


/* ───────────────────────────────────────────────────────────────────────────
   3 · ВИТРИНА .auth-side — свет, зерно, сетка, лучи
   Три слоя вместо одного: материал на самом элементе (градиент + зерно +
   угловые подсветки), лучи на ::before, инженерная сетка на ::after.
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .auth-side{
  /* .auth-side попала в общий список скруглений 14px вместе с карточками
     (theme.css:4201). Но это не карточка, а колонка во всю высоту кадра:
     скруглённые углы упираются в край экрана и читаются тёмными сколами. */
  border-radius:0;
  background-color:#0E0C09;
  background-image:
    var(--au-grain),
    radial-gradient(76% 52% at 6% -6%, rgba(255,110,64,.22), transparent 64%),
    radial-gradient(62% 55% at 104% 106%, rgba(79,227,198,.09), transparent 62%),
    linear-gradient(163deg,#1B1811 0%,#16140F 46%,#0D0B08 100%);
  background-size:160px 160px, auto, auto, auto;
  background-repeat:repeat, no-repeat, no-repeat, no-repeat;
  /* внутренняя грань справа: витрина читается как отдельная плоскость */
  box-shadow:inset -1px 0 0 var(--au-seam);
}
:root[data-theme="light"] .login-wrap.auth .auth-side{
  background-color:#F1E8D9;
  background-image:
    var(--au-grain),
    radial-gradient(76% 52% at 6% -6%, rgba(217,60,19,.13), transparent 64%),
    radial-gradient(62% 55% at 104% 106%, rgba(14,158,134,.08), transparent 62%),
    linear-gradient(163deg,#FFFDF7 0%,#FDFAF4 46%,#EFE5D4 100%);
  background-size:160px 160px, auto, auto, auto;
  background-repeat:repeat, no-repeat, no-repeat, no-repeat;
}

/* Лучи. Не картинка и не блюр (дорого) — три очень пологих полосы света,
   гаснущие к низу маской: взгляд ведёт сверху вниз, к форме. */
.login-wrap.auth .auth-side::before{
  content:''; position:absolute; inset:-12% -6%; pointer-events:none;
  background:
    linear-gradient(102deg, transparent 30%, var(--au-ray) 37%, transparent 44%),
    linear-gradient(98deg,  transparent 52%, var(--au-ray2) 57%, transparent 63%),
    linear-gradient(106deg, transparent 70%, var(--au-ray2) 74%, transparent 79%);
  -webkit-mask-image:linear-gradient(178deg,#000 0%,rgba(0,0,0,.55) 46%,transparent 86%);
          mask-image:linear-gradient(178deg,#000 0%,rgba(0,0,0,.55) 46%,transparent 86%);
}

/* Сетка в двух масштабах: крупный шаг задаёт ритм, мелкий даёт «ткань».
   Альфа вписана прямо в цвета, поэтому opacity возвращаю к 1 —
   иначе базовое .5 из theme.css гасило бы расчётные значения ещё раз. */
.login-wrap.auth .auth-side::after{
  content:''; position:absolute; inset:0; pointer-events:none; opacity:1;
  background-image:
    linear-gradient(var(--au-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--au-grid) 1px, transparent 1px),
    linear-gradient(var(--au-grid-fine) 1px, transparent 1px),
    linear-gradient(90deg, var(--au-grid-fine) 1px, transparent 1px);
  background-size:64px 64px, 64px 64px, 16px 16px, 16px 16px;
  -webkit-mask-image:radial-gradient(118% 88% at 8% -4%, #000 16%, rgba(0,0,0,.34) 52%, transparent 82%);
          mask-image:radial-gradient(118% 88% at 8% -4%, #000 16%, rgba(0,0,0,.34) 52%, transparent 82%);
}


/* ───────────────────────────────────────────────────────────────────────────
   4 · БРЕНД
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .auth-side .brand{
  letter-spacing:-.015em;
  gap:12px;
}
/* Знак: не плоский квадрат, а «камень» — фаска сверху, тень снизу, ореол.
   Подпись R на оранжевом ТЁМНАЯ (#1A0B05) — на этой заливке 5.9:1 против
   3.2:1 у белого; в светлой теме заливка глубже, там белый даёт 5.5:1. */
.login-wrap.auth .auth-side .brand .dot{
  width:30px; height:30px; border-radius:9px; font-size:15px;
  background-image:linear-gradient(145deg,#FF9670 0%,#FF6A3F 46%,#D8420F 100%);
  color:#1A0B05;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -1px 0 rgba(90,20,0,.35),
    0 8px 22px -8px rgba(255,90,50,.75),
    0 0 0 1px rgba(255,130,86,.28);
}
:root[data-theme="light"] .login-wrap.auth .auth-side .brand .dot{
  background-image:linear-gradient(145deg,#F0592B 0%,#D2410F 48%,#A82A08 100%);
  color:#FFFFFF;                   /* 5.5:1 к средней точке заливки */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.42),
    0 8px 20px -9px rgba(217,60,19,.55),
    0 0 0 1px rgba(217,60,19,.24);
}


/* ───────────────────────────────────────────────────────────────────────────
   5 · ЗАГОЛОВОК ВИТРИНЫ
   Масштаб крупнее, трекинг плотнее. Акцент на части фразы разметкой не задан,
   поэтому «подсветка» делается градиентом по самому заголовку: верхняя строка
   светлая, нижняя уходит в тёплый. Приём включается только там, где он точно
   поддержан, иначе остаётся сплошной цвет.
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .auth-hero{margin:48px 0 36px}
.login-wrap.auth .auth-hero .auth-hero-t{
  font-size:clamp(29px,3.1vw,42px);
  line-height:1.13;
  letter-spacing:-.028em;
  font-weight:800;
  /* было зашито #FFFFFF — в светлой теме это белое по кремовому, 1.03:1.
     Токен --side-tx даёт 15.61:1 в тёмной и 15.33:1 в светлой. */
  color:var(--side-tx);
  margin:0 0 16px;
  text-wrap:balance;
}
@supports ((-webkit-background-clip:text) or (background-clip:text)){
  .login-wrap.auth .auth-hero .auth-hero-t{
    background-image:linear-gradient(168deg, var(--side-tx) 0%, var(--side-tx) 38%, var(--acc-tx) 128%);
    -webkit-background-clip:text;
            background-clip:text;
    -webkit-text-fill-color:transparent;
    color:transparent;
  }
}
.login-wrap.auth .auth-hero p{
  font-size:15.5px; line-height:1.62;
  color:var(--side-tx-mut);        /* 6.14:1 тёмная / 7.96:1 светлая */
  max-width:38ch;
}


/* ───────────────────────────────────────────────────────────────────────────
   6 · ПУНКТЫ ЦЕННОСТИ И ИХ ИКОНКИ
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .auth-pts{gap:20px}
.login-wrap.auth .auth-pts li{gap:15px; align-items:center}

/* ГЛАВНОЕ: <svg> из ICON.* печатается без width/height, а размера ему нигде
   не задавали — иконка раздувалась до размера по умолчанию и вылезала из
   коробки 36×36. Тут это чинится и заодно даётся материал. */
.login-wrap.auth .ap-ic svg{width:19px; height:19px; display:block}

.login-wrap.auth .ap-ic{
  width:38px; height:38px; border-radius:11px;
  background-color:transparent;
  background-image:linear-gradient(158deg, rgba(255,130,86,.22) 0%, rgba(255,90,50,.09) 100%);
  border:1px solid rgba(255,130,86,.30);
  color:var(--acc-d);              /* штрих 5.16:1 на светлой точке плитки, 6.81:1 на тёмной */
  box-shadow:
    inset 0 1px 0 rgba(255,246,232,.14),
    0 8px 18px -12px rgba(255,90,50,.65);
  transition:box-shadow var(--mo-1x) var(--mo-out), border-color var(--mo-1x) var(--mo-out);
}
:root[data-theme="light"] .login-wrap.auth .ap-ic{
  background-color:#FDFAF4;
  background-image:linear-gradient(158deg, rgba(255,255,255,.90) 0%, rgba(217,60,19,.16) 100%);
  border:1px solid rgba(217,60,19,.26);
  color:#A32A0C;                   /* 7.26:1 на светлой точке плитки, 5.56:1 на тёмной */
  box-shadow:
    inset 0 1px 0 #FFFFFF,
    0 6px 14px -10px rgba(217,60,19,.5);
}
/* Пункты некликабельны, поэтому при наведении НИЧЕГО не двигается и курсор не
   меняется — только плитка чуть ярче светится. Ложной кнопки не возникает. */
.login-wrap.auth .auth-pts li:hover .ap-ic{
  border-color:rgba(255,130,86,.48);
  box-shadow:inset 0 1px 0 rgba(255,246,232,.2), 0 10px 22px -12px rgba(255,90,50,.85);
}
:root[data-theme="light"] .login-wrap.auth .auth-pts li:hover .ap-ic{
  border-color:rgba(217,60,19,.42);
  box-shadow:inset 0 1px 0 #FFFFFF, 0 8px 18px -10px rgba(217,60,19,.62);
}

.login-wrap.auth .auth-pts b{
  font-size:15px; font-weight:700; letter-spacing:-.005em; margin-bottom:4px;
  color:var(--side-tx);            /* 15.61:1 / 15.33:1 */
}
.login-wrap.auth .auth-pts span{
  font-size:13.5px; line-height:1.52;
  color:var(--side-tx-mut);        /* 6.14:1 / 7.96:1 */
}

/* Подвал витрины: 12.5px — берём собственный, чуть более контрастный тон,
   чем --side-tx-dim (тот давал 5.11:1 на затемнённом низу). */
.login-wrap.auth .auth-side-foot{
  margin-top:48px; padding-top:18px;
  border-top:1px solid var(--au-seam);
  font-size:12.5px; letter-spacing:.002em;
  color:var(--au-foot);            /* 7.03:1 / 6.41:1 */
}


/* ───────────────────────────────────────────────────────────────────────────
   7 · ЗАГОЛОВОК ФОРМЫ
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .login h1{
  font-size:clamp(28px,2.5vw,34px);
  line-height:1.14;
  letter-spacing:-.028em;
  color:var(--tx);                 /* 16.69:1 тёмная / 13.73:1 светлая */
  margin:0 0 8px;
}
.login-wrap.auth .login .auth-sub{
  font-size:15px; line-height:1.55;
  color:var(--tx-mut);             /* 6.56:1 / 7.13:1 */
  margin-bottom:30px; max-width:34ch;
}


/* ───────────────────────────────────────────────────────────────────────────
   8 · ПОЛЯ ВВОДА
   Значения цвета приходят из токенов раздела 1 — здесь только геометрия,
   материал и состояния.
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .field{margin-bottom:18px}
.login-wrap.auth .field label{
  font-size:var(--fs-cap); letter-spacing:var(--tr-cap);
  /* цвет — --fi-label из раздела 1: 10.58:1 тёмная / 8.59:1 светлая (11px ≥7:1) */
}
.login-wrap.auth .login input{
  padding:14px 15px; font-size:15px; border-radius:11px;
  /* поле держит собственную высоту, чтобы строка не «прыгала» между темами */
  min-height:50px;
  letter-spacing:.002em;
  /* Заливку задаю ЯВНО, а не только токеном: в светлой теме поле перехватывает
     правило [data-theme="light"] .field input{background:#F3F3F3} (theme.css) —
     холодный серый из Ant-эпохи. Оно (0,2,1) сильнее .field input{var(--fi-bg)}
     (0,1,1), и тёплый токен туда не доезжал. Мой селектор (0,3,1) — доезжает. */
  background-color:var(--fi-bg);
  background-image:none;
  /* Грань тоже задаю явно — и вот почему. theme.css:1202 красит «заполненное»
     поле через .field input:not(:placeholder-shown). У полей входа атрибута
     placeholder нет вовсе, поэтому :placeholder-shown НЕ срабатывает никогда,
     а :not(...) срабатывает ВСЕГДА — даже на пустом и даже в фокусе. Правило
     (0,2,1) стоит ПОЗЖЕ .field input:focus{border-color:var(--acc)} (тоже
     (0,2,1)) и съедало акцентную грань фокуса: замерено в браузере — грань
     покоя и грань фокуса совпадали до последнего значения. Мои (0,3,1)/(0,4,1)
     возвращают трёхступенчатое «покой → наведение → фокус». */
  border-color:var(--fi-line);
}
/* Наведение: грань светлеет, ниша чуть раскрывается — сигнал «сюда можно» */
.login-wrap.auth .login input:hover{
  background-color:var(--fi-bg-hover);
  border-color:var(--fi-line-hover);
  box-shadow:var(--fi-well);
}
/* Фокус: двухшаговое кольцо (--fi-ring) плюс тёплая грань акцента */
.login-wrap.auth .login input:focus{
  background-color:var(--fi-bg-focus);
  border-color:var(--acc);
  box-shadow:var(--fi-well), var(--fi-ring);
}

/* Автозаполнение Chrome закрашивает поле своим цветом. Базовое правило
   theme.css подставляет туда var(--fi-bg) — а он у нас уже тёплый; здесь
   только возвращаю на место собственную нишу и кольцо фокуса. */
.login-wrap.auth .field input:-webkit-autofill,
.login-wrap.auth .field input:-webkit-autofill:hover{
  -webkit-box-shadow:inset 0 0 0 100px var(--fi-bg), var(--fi-well);
          box-shadow:inset 0 0 0 100px var(--fi-bg), var(--fi-well);
  -webkit-text-fill-color:var(--tx);
}
.login-wrap.auth .field input:-webkit-autofill:focus{
  -webkit-box-shadow:inset 0 0 0 100px var(--fi-bg-focus), var(--fi-well), var(--fi-ring);
          box-shadow:inset 0 0 0 100px var(--fi-bg-focus), var(--fi-well), var(--fi-ring);
}


/* ───────────────────────────────────────────────────────────────────────────
   9 · ПОКАЗАТЬ ПАРОЛЬ
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .pw-eye svg{width:18px; height:18px; display:block}
.login-wrap.auth .pw-eye{
  right:7px; width:34px; height:34px; border-radius:8px;
  color:var(--au-eye);             /* 7.09:1 / 5.97:1 — «глаз» виден и до наведения */
}
.login-wrap.auth .pw-eye:hover{
  color:var(--tx);
  background:var(--ct-wash);
}
.login-wrap.auth .pw-eye.on{color:var(--acc-tx)}
/* перечёркивание чуть тоньше и с мягкой обводкой — не «зачёркнутая ошибка» */
.login-wrap.auth .pw-eye.on::after{width:19px; height:1.6px}

/* Safari рисует внутри полей собственные кнопки «пароли»/«контакты» и
   индикатор Caps Lock — они садятся ровно на «глаз». Каждый вебкитовый
   псевдоэлемент выносится ОТДЕЛЬНЫМ правилом: в общем списке неизвестный
   псевдоэлемент отменил бы весь список за пределами WebKit. */
.login-wrap.auth .pw-wrap input::-webkit-credentials-auto-fill-button{
  margin-right:38px;
}
.login-wrap.auth .pw-wrap input::-webkit-caps-lock-indicator{
  margin-right:38px;
}


/* ───────────────────────────────────────────────────────────────────────────
   10 · ОШИБКА ВХОДА
   Плашка с иконкой-восклицанием (inline-SVG в data:URI, свой цвет на тему).
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .err.on{
  padding:11px 13px 11px 38px;
  border-radius:11px;
  font-size:13.5px; line-height:1.45; font-weight:600;
  color:var(--au-err-tx);          /* 7.44:1 тёмная / 5.50:1 светлая */
  background-color:var(--au-err-bg);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FF8A93' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.5v5.5M12 16.4h.01'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:13px 12px;
  background-size:16px 16px;
  border:1px solid var(--au-err-line);
  box-shadow:0 8px 20px -14px rgba(255,110,122,.8);
}
:root[data-theme="light"] .login-wrap.auth .err.on{
  /* тот же знак, но обведён глубоким красным светлой темы: на кремовой
     подложке розовый штрих тёмной темы почти не виден */
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23A81430' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7.5v5.5M12 16.4h.01'/%3E%3C/svg%3E");
  box-shadow:0 8px 18px -14px rgba(200,30,58,.55);
}


/* ───────────────────────────────────────────────────────────────────────────
   11 · КНОПКА ВХОДА
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .auth-go{
  padding:15px 18px!important;
  font-size:15.5px; font-weight:700; letter-spacing:-.005em;
  min-height:52px; margin-top:8px; border-radius:12px;
  /* верхняя фаска + ореол + дальняя тень: заливка читается как отлитая деталь */
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.38),
    inset 0 -1px 0 rgba(90,20,0,.28),
    var(--ct-halo),
    var(--dp-e2);
}
.login-wrap.auth .auth-go:hover{
  transform:translateY(-1px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.46),
    inset 0 -1px 0 rgba(90,20,0,.24),
    0 18px 40px -16px var(--glow),
    var(--dp-e3);
}
/* .btn:active:not(:disabled) в theme.css — (0,3,0), а мой :hover выше (0,4,0)
   и перекрыл бы нажатие. Возвращаю отклик явно и сильнее. */
.login-wrap.auth .auth-go:active:not(:disabled){
  transform:translateY(1px);
  box-shadow:
    inset 0 2px 8px -2px rgba(90,20,0,.55),
    inset 0 1px 0 rgba(255,255,255,.2);
}

/* СОСТОЯНИЕ ОТПРАВКИ. В theme.css .btn:disabled (0,2,0, строка 4110) стоит
   позже .auth-go.loading (0,2,0, строка 4062) — и перебивал его: подпись
   оставалась видимой, кнопка гасла до 45%, а .btn:disabled::after{content:none}
   (строка 4111) убивал крутилку совсем. Человек нажимал «Войти» и не получал
   ни одного признака работы. Возвращаю честное «идёт вход». */
.login-wrap.auth .auth-go.loading,
.login-wrap.auth .auth-go.loading:disabled,
.login-wrap.auth .auth-go.loading:disabled:hover{
  color:transparent;
  opacity:1;
  cursor:progress;
  transform:none;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28), var(--dp-e1);
}
.login-wrap.auth .auth-go.loading::after{
  content:'';
  position:absolute; left:50%; top:50%;
  width:18px; height:18px; margin:-9px 0 0 -9px;
  border-radius:50%;
  /* кольцо было белым поверх оранжевой заливки (~2.6:1). На этой заливке
     «свой» цвет — тёмный --ct-on: 4.72:1 в тёмной теме, белый 4.66:1 в светлой. */
  border:2px solid color-mix(in srgb, var(--ct-on) 28%, transparent);
  border-top-color:var(--ct-on);
  animation:authSpin .7s linear infinite;
}


/* ───────────────────────────────────────────────────────────────────────────
   12 · ССЫЛКИ ПОД ФОРМОЙ
   ─────────────────────────────────────────────────────────────────────────── */
.login-wrap.auth .auth-alt{margin-top:22px}
.login-wrap.auth .auth-alt a{
  display:inline-flex; align-items:center; gap:6px;
  padding:8px 12px; border-radius:10px;
  font-size:13.5px; font-weight:600;
  color:var(--acc-tx);             /* 8.04:1 тёмная / 7.03:1 светлая */
  transition:background var(--mo-1x) var(--mo-out), color var(--mo-1x) var(--mo-out);
}
.login-wrap.auth .auth-alt a:hover{
  background:var(--ct-wash);
  text-decoration:none;            /* подчёркивание заменено подложкой: спокойнее */
}
.login-wrap.auth .auth-back{margin-top:6px}
.login-wrap.auth .auth-back a{
  display:inline-flex; align-items:center;
  padding:8px 12px; border-radius:10px;
  font-size:13px;
  color:var(--tx-mut);             /* 6.56:1 / 7.13:1 */
  transition:color var(--mo-1x) var(--mo-out), background var(--mo-1x) var(--mo-out);
}
.login-wrap.auth .auth-back a:hover{
  color:var(--tx);
  background:color-mix(in srgb, var(--tx) 7%, transparent);
  text-decoration:none;
}


/* ───────────────────────────────────────────────────────────────────────────
   13 · ПОЯВЛЕНИЕ ПРИ ЗАГРУЗКЕ
   Деликатно: 8–12px подъёма и прозрачность, шаг 50–60 мс. Заливка режима —
   backwards, а НЕ both: both оставил бы на элементе transform:none навсегда
   и убил бы нажатие кнопки (анимация в каскаде сильнее обычных объявлений).
   ─────────────────────────────────────────────────────────────────────────── */
@keyframes authRise{
  from{opacity:0; transform:translateY(12px)}
  to{opacity:1; transform:none}
}
@keyframes authFadeIn{
  from{opacity:0}
  to{opacity:1}
}
@keyframes authErrIn{
  from{opacity:0; transform:translateY(-5px)}
  to{opacity:1; transform:none}
}

.login-wrap.auth .auth-side .brand{animation:authRise .5s var(--mn-ease) backwards}
.login-wrap.auth .auth-hero{animation:authRise .58s var(--mn-ease) 80ms backwards}
.login-wrap.auth .auth-pts li:nth-child(1){animation:authRise .5s var(--mn-ease) 150ms backwards}
.login-wrap.auth .auth-pts li:nth-child(2){animation:authRise .5s var(--mn-ease) 210ms backwards}
.login-wrap.auth .auth-pts li:nth-child(3){animation:authRise .5s var(--mn-ease) 270ms backwards}
.login-wrap.auth .auth-side-foot{animation:authFadeIn .6s var(--mn-ease) 340ms backwards}
/* декор витрины проявляется отдельно и медленнее — он фон, а не содержание */
.login-wrap.auth .auth-side::before,
.login-wrap.auth .auth-side::after{animation:authFadeIn 1.1s var(--mn-ease) backwards}

/* Форма. У обеих форм ровно 8 прямых потомков (вход: h1, .auth-sub, 2 поля,
   .err, кнопка, .auth-alt, .auth-back; регистрация: h1, .auth-sub, 3 поля,
   .err, кнопка, .auth-alt) — считаю по позиции, классов не добавляю. */
.login-wrap.auth .login>*:nth-child(1){animation:authRise .5s var(--mn-ease) 40ms backwards}
.login-wrap.auth .login>*:nth-child(2){animation:authRise .5s var(--mn-ease) 90ms backwards}
.login-wrap.auth .login>*:nth-child(3){animation:authRise .5s var(--mn-ease) 140ms backwards}
.login-wrap.auth .login>*:nth-child(4){animation:authRise .5s var(--mn-ease) 190ms backwards}
.login-wrap.auth .login>*:nth-child(5){animation:authRise .5s var(--mn-ease) 240ms backwards}
.login-wrap.auth .login>*:nth-child(6){animation:authRise .5s var(--mn-ease) 290ms backwards}
.login-wrap.auth .login>*:nth-child(7){animation:authRise .5s var(--mn-ease) 330ms backwards}
.login-wrap.auth .login>*:nth-child(8){animation:authRise .5s var(--mn-ease) 370ms backwards}

/* .err стоит 5-м или 6-м потомком, поэтому его правило появления должно идти
   ПОСЛЕ списка выше: специфичность равная (0,4,0), решает порядок. Иначе
   плашка ошибки въезжала бы «снизу вверх» вместе со стартовой раскладкой. */
.login-wrap.auth .err.on{
  animation:authErrIn .26s var(--mn-ease);
}


/* ───────────────────────────────────────────────────────────────────────────
   14 · УЗКИЙ ЭКРАН
   Витрина сворачивается в шапку (это уже задано в theme.css), а форма должна
   остаться самодостаточной — поэтому здесь она получает собственную карточку:
   тёплая поверхность, фаска, дальняя тень. Тяжёлые эффекты снимаются.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:900px){
  /* зерно и лучи на полоске шапки не читаются, а стоят кадров */
  .login-wrap.auth .auth-side{
    background-image:
      radial-gradient(120% 190% at 4% -60%, rgba(255,110,64,.20), transparent 66%),
      linear-gradient(180deg,#1B1811 0%,#100E0A 100%);
    background-size:auto, auto;
    /* слоёв стало два вместо четырёх — repeat переобъявляю целиком,
       иначе от настольного правила остаётся «repeat» на первом слое */
    background-repeat:no-repeat, no-repeat;
    box-shadow:inset 0 -1px 0 var(--au-seam), 0 14px 30px -26px rgba(0,0,0,.9);
    padding:20px 20px;
  }
  :root[data-theme="light"] .login-wrap.auth .auth-side{
    background-image:
      radial-gradient(120% 190% at 4% -60%, rgba(217,60,19,.12), transparent 66%),
      linear-gradient(180deg,#FFFDF7 0%,#F1E8D9 100%);
    background-size:auto, auto;
    background-repeat:no-repeat, no-repeat;
    box-shadow:inset 0 -1px 0 var(--au-seam), 0 12px 26px -26px rgba(90,60,25,.5);
  }
  .login-wrap.auth .auth-side::before{background:none}
  .login-wrap.auth .auth-side::after{
    background-size:64px 64px, 64px 64px, 0 0, 0 0;   /* мелкая сетка выключена */
  }
  .login-wrap.auth .auth-main{padding:26px 16px 40px}
  .login-wrap.auth .auth-main::after{display:none}    /* фальца между колонками больше нет */

  /* Карточка формы. Базовое .login-wrap.auth .login (0,3,0) обнуляет фон и
     рамку; здесь ровно та же специфичность, но правило идёт позже. */
  .login-wrap.auth .login{
    max-width:440px; width:100%;
    background:var(--au-card);
    border:1px solid var(--line);
    border-radius:16px;
    padding:26px 22px 24px;
    box-shadow:var(--dp-e4), var(--dp-rim-s);
  }
  /* На карточке поле должно оставаться нишей, иначе сливается с ней */
  .login-wrap.auth{
    --fi-bg:#100E0A; --fi-bg-hover:#13110C; --fi-bg-focus:#171410;
  }
  :root[data-theme="light"] .login-wrap.auth{
    --fi-bg:#F6EFE3; --fi-bg-hover:#FBF6EC; --fi-bg-focus:#FFFFFF;
  }

  .login-wrap.auth .login h1{font-size:26px}
  .login-wrap.auth .login .auth-sub{font-size:14.5px; margin-bottom:24px}

  /* Зоны нажатия ≥44px: «глаз», обе ссылки и сама кнопка */
  .login-wrap.auth .pw-eye{width:44px; height:44px; right:4px; border-radius:10px}
  .login-wrap.auth .pw-wrap input{padding-right:54px!important}
  .login-wrap.auth .pw-wrap input::-webkit-credentials-auto-fill-button{margin-right:46px}
  .login-wrap.auth .pw-wrap input::-webkit-caps-lock-indicator{margin-right:46px}
  .login-wrap.auth .auth-alt a,
  .login-wrap.auth .auth-back a{min-height:44px; padding:11px 14px}
  .login-wrap.auth .login input{min-height:48px}
  .login-wrap.auth .auth-go{min-height:52px}
}

/* Совсем узкие корпуса (iPhone SE/13 mini — 375/390 CSS-px): убираем всё,
   что может вытолкнуть строку за край, и подрезаем поля карточки. */
@media(max-width:430px){
  .login-wrap.auth .login{padding:22px 16px 20px; border-radius:14px}
  .login-wrap.auth .auth-main{padding:22px 12px 36px}
  .login-wrap.auth .login h1{font-size:24px; letter-spacing:-.022em}
  .login-wrap.auth .login .auth-sub{max-width:none}
  .login-wrap.auth .auth-side{padding:16px 16px}
  .login-wrap.auth .auth-side .brand{font-size:17px}
  /* длинная почта не должна распирать грид и рождать горизонтальный скролл */
  .login-wrap.auth .login input{min-width:0}
  .login-wrap.auth .auth-alt a{white-space:normal; text-align:center}
}

/* Низкий и широкий кадр (ноутбук 13″, развёрнутая панель закладок):
   витрина не должна выдавливать форму — уменьшаем вертикальные отступы. */
@media(min-width:901px) and (max-height:720px){
  .login-wrap.auth .auth-hero{margin:30px 0 24px}
  .login-wrap.auth .auth-pts{gap:15px}
  .login-wrap.auth .auth-side-foot{margin-top:30px; padding-top:14px}
  .login-wrap.auth .auth-main{padding:32px 24px}
}


/* ───────────────────────────────────────────────────────────────────────────
   15 · ПОКОЙ ДВИЖЕНИЯ
   Появление гасим полностью, крутилку — только замедляем: она единственная
   несёт смысл «идёт вход», без неё состояние становится немым.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .login-wrap.auth .auth-side .brand,
  .login-wrap.auth .auth-hero,
  .login-wrap.auth .auth-pts li:nth-child(1),
  .login-wrap.auth .auth-pts li:nth-child(2),
  .login-wrap.auth .auth-pts li:nth-child(3),
  .login-wrap.auth .auth-side-foot,
  .login-wrap.auth .login>*:nth-child(1),
  .login-wrap.auth .login>*:nth-child(2),
  .login-wrap.auth .login>*:nth-child(3),
  .login-wrap.auth .login>*:nth-child(4),
  .login-wrap.auth .login>*:nth-child(5),
  .login-wrap.auth .login>*:nth-child(6),
  .login-wrap.auth .login>*:nth-child(7),
  .login-wrap.auth .login>*:nth-child(8),
  .login-wrap.auth .err.on{
    animation:none;
  }
  /* псевдоэлементы витрины — отдельным правилом, чтобы опечатка в одном
     селекторе не унесла весь список выше */
  .login-wrap.auth .auth-side::before,
  .login-wrap.auth .auth-side::after{animation:none}

  .login-wrap.auth .auth-go,
  .login-wrap.auth .ap-ic,
  .login-wrap.auth .auth-alt a,
  .login-wrap.auth .auth-back a{transition:none}
  .login-wrap.auth .auth-go:hover{transform:none}
  .login-wrap.auth .auth-go.loading::after{animation-duration:1.6s}
}


/* ───────────────────────────────────────────────────────────────────────────
   16 · РЕЖИМ ВЫСОКОЙ КОНТРАСТНОСТИ
   Системная палитра подменяет цвета: декор мешает, границы обязаны остаться.
   ─────────────────────────────────────────────────────────────────────────── */
@media(forced-colors:active){
  .login-wrap.auth .auth-side::before,
  .login-wrap.auth .auth-side::after,
  .login-wrap.auth .auth-main::before,
  .login-wrap.auth .auth-main::after{display:none}
  .login-wrap.auth .ap-ic{border:1px solid CanvasText}
  .login-wrap.auth .auth-go{border:1px solid ButtonText}
  .login-wrap.auth .login input{border:1px solid CanvasText}
  .login-wrap.auth .err.on{border:1px solid CanvasText}
}

/* ▲▲▲ конец: ЭКРАН ВХОДА — УСИЛЕНИЕ ▲▲▲ */

/* ▼▼▼ ВНУТРЕННИЕ ЭКРАНЫ — УСИЛЕНИЕ ▼▼▼ */
@charset "UTF-8";
/* ═══════════════════════════════════════════════════════════════════════════
   ВНУТРЕННИЕ ЭКРАНЫ КАБИНЕТА · СЛОЙ ОТДЕЛКИ
   Подключать ПОСЛЕДНИМ: после app.css и theme.css. Слой рассчитан на то, что
   при равной специфичности выигрывает порядком, а не весом селектора.

   База принята — здесь не перекраска, а следующий уровень: материал, свет
   и внимание к деталям на экранах, которые клиент видит после входа.
   Разметку не трогаем: каждый селектор сверен по app.js (renderHome,
   projectCard, homeSummary/homeBar, renderStats, projectDash, renderInvoices,
   renderHours, renderDocs, openTask · roBody, subtasksHTML). Выдуманных
   классов нет.

   Что решает файл:
     1. Иерархия. Клиент за секунду должен понимать «что от меня ждут»:
        просрочка, приёмка и «ждём вас» получают собственный вес, всё
        остальное отступает на шаг.
     2. Материал. Сводка входа, карточка проекта, часы и клиентский вид
        задачи оставались плоскими заливками --panel там, где соседние
        панели уже собраны из света и тени.
     3. Клиентский вид задачи. Именно им заказчик принимает работу, и он
        был доведён меньше всех: чипы стояли на сером литерале, шкала
        готовности — без подписи, приёмка не отличалась от отмены.
     4. Контраст. Найденные и посчитанные провалы перечислены по месту.

   Контраст (посчитан, тёмная / светлая; худшая поверхность каждой темы):
     --tx        15,6 / 15,3   --d-cap  8,6 / 9,4    --d-sec (=--tx-mut) 5,4 / 6,9
     --d-ok      11,1 / 6,7    --d-danger 7,1 / 6,2  --in-warn-tx 10,3 / 6,3
     --acc-tx     7,1 / 5,0
   Ниже 4,5:1 в файле нет ничего; всё, что 11px и мельче, — не ниже 7:1.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ───────────────────────────────────────────────────────────────────────────
   0 · ТОКЕНЫ СЛОЯ · префикс --in-*
   Грепом по app.css, theme.css и app.js совпадений 0 — ничего не занимаем
   и ничего не перебиваем. Всё, что можно, считаем ОТ токенов палитры: такое
   выражение само переворачивается в светлой теме и не требует парного блока.
   Парные литералы (заливки под текст) вынесены ниже отдельно — это ровно те
   значения, которые нельзя вывести расчётом.
   ─────────────────────────────────────────────────────────────────────────── */
:root{
  /* Материал «поднятой» панели: свет сверху, к низу гаснет. Тот же приём, что
     у .dcard. Панели сводки, счёта и часов стояли плоским --panel и рядом с
     дашбордом читались как непрокрашенные. */
  --in-lift:linear-gradient(168deg,
    color-mix(in srgb, var(--card) 60%, var(--panel)) 0%, var(--panel) 100%);

  /* Ниша: дно шкалы, клетка значка, штамп номера, поле ввода. Считается от
     --bg, поэтому углубляет и на угле, и на кремовой бумаге — второй блок
     для светлой темы не нужен. */
  --in-well:color-mix(in srgb, var(--bg) 74%, var(--card));
  --in-well-sh:inset 0 1px 3px color-mix(in srgb, var(--bg) 78%, transparent),
               inset 0 0 0 1px color-mix(in srgb, var(--tx) 5%, transparent);

  /* Блик по заливке шкалы: сверху свет, снизу собственная тень. Кладётся
     ПЕРВЫМ слоем background-image, цвет заливки идёт вторым. */
  --in-gloss:linear-gradient(180deg,
    rgba(255,255,255,.26) 0%, rgba(255,255,255,0) 46%, rgba(0,0,0,.14) 100%);

  /* Охра как ТЕКСТ. Чистый --warn на кремовой теме даёт 3,9:1 — для «Высокий»
     и «сегодня» мало. Подмешивание --tx в тёмной осветляет, в светлой темнит:
     10,3:1 и 6,3:1 без смены оттенка. */
  --in-warn-tx:color-mix(in srgb, var(--warn) 62%, var(--tx));
  /* Акцент как ТЕКСТ мелким кеглем. --acc-tx (7,1 / 5,0) хватает от 12px, но
     11px требуют 7:1: на светлой теме --acc-tx даёт 5,0. Тот же приём. */
  --in-acc-tx:color-mix(in srgb, var(--acc) 55%, var(--tx));

  /* Отклик. Один шаг на весь слой: наведение, подъём, появление стрелки. */
  --in-t:.18s cubic-bezier(.22,.72,.28,1);
}

/* Парные литералы. Заливки, на которых лежит текст, расчётом не выводятся:
   в тёмной теме текст на них ТЁМНЫЙ, в светлой — белый, и сама заливка в
   светлой должна быть глубже, иначе белый не набирает норму.
   Селектор светлой темы (0,2,0) намеренно сильнее (0,1,0) — это главная
   ловушка проекта: значения тёмной темы копировали в блок светлой. */
:root, :root[data-theme="dark"]{
  /* Выбранная сортировка. Белый на #FF5A32 — 3,1:1, поэтому текст тёмный. */
  --in-sel-a:#FF6A3F; --in-sel-b:#E24E1B; --in-sel-tx:#1A0B05;   /* 6,8:1 / 4,9:1 */
  /* «Принять работу» — успех, значит бирюза. */
  --in-ok-a:#5FE7CD;  --in-ok-b:#2BC2A6;  --in-on-ok:#04211B;    /* 11,1:1 / 7,6:1 */
  --in-ok-ha:#74EDD6; --in-ok-hb:#35D0B4;
  --in-ok-halo:0 10px 26px -12px rgba(79,227,198,.55);
}
:root[data-theme="light"]{
  --in-sel-a:#C3350F; --in-sel-b:#A82B09; --in-sel-tx:#FFFFFF;   /* 5,5:1 / 7,0:1 */
  --in-ok-a:#0B7A66;  --in-ok-b:#065446;  --in-on-ok:#FFFFFF;    /* 5,3:1 / 8,9:1 */
  --in-ok-ha:#0A6E5C; --in-ok-hb:#054C3F;
  --in-ok-halo:0 10px 24px -12px rgba(11,122,102,.42);
  /* В кремовой теме --card и --panel — одно и то же значение (#FDFAF4), и
     расчётный градиент вырождается в плоскую заливку: панель теряет объём.
     Подмешиваем фон страницы — тем же приёмом, каким в theme.css выправлен
     светлый .dcard. */
  --in-lift:linear-gradient(168deg, var(--card) 0%,
    color-mix(in srgb, var(--bg) 45%, var(--card)) 100%);
}


/* ═══════════════════════════════════════════════════════════════════════════
   1 · ГЛАВНАЯ · СВОДКА ВХОДА · .hsum (homeSummary)
   Первое, что видит клиент после входа. Панель осталась от прежнего каркаса:
   радиус 10px против 14px у всех соседей, плоская заливка --panel, подписи на
   --tx-dim (4,3:1 на карточке — ниже нормы даже для 12px).
   ═══════════════════════════════════════════════════════════════════════════ */
.hsum{
  position:relative; overflow:hidden;
  border-radius:var(--bd-r);
  padding:20px 22px;
  background:var(--in-lift);
  border-color:var(--line2);
  box-shadow:var(--dp-e2), var(--dp-rim);
}
/* Световая нить по верхней кромке — как у .dcard. Псевдоэлемент обязан быть
   АБСОЛЮТНЫМ: .hsum — грид с именованными областями, обычный ::before стал бы
   грид-элементом и уехал в новую неявную строку, развалив раскладку. */
.hsum::before{
  content:''; position:absolute; left:0; right:0; top:0; height:1px;
  pointer-events:none;
  background:linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--edge) 62%, transparent) 50%, transparent);
}
/* Тёплое зарево из-за кольца — единственный декор панели: он показывает,
   где у экрана смысловой центр. Та же причина, что у подсветки .main. */
.hsum::after{
  content:''; position:absolute; pointer-events:none;
  left:-46px; top:-78px; width:270px; height:210px; border-radius:50%;
  background:radial-gradient(closest-side, var(--mn-glow-soft), transparent 72%);
}
/* Кольцо общего прогресса — то, ради чего панель существует. */
.hsum-ring .miniring circle:last-of-type{
  filter:drop-shadow(0 0 8px color-mix(in srgb, var(--acc) 50%, transparent));
}
/* «общий прогресс» — 11px, значит нужно 7:1. --tx-dim давал 4,3:1. */
.hsum-cap{
  color:var(--d-cap);
  font-family:var(--mono); font-size:10px; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase;
}
.hsum-note{ color:var(--d-sec); }

/* Плитки сводки — это КНОПКИ (data-sortto пересортировывает сетку ниже), но
   выглядели как таблички. Даём им материал кнопки и корешок отклика. */
.hsum-c{
  position:relative; overflow:hidden;
  min-height:58px;
  border-radius:10px;
  background:linear-gradient(160deg, var(--card2) 0%, var(--card) 100%);
  border-color:var(--line);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:border-color var(--in-t), transform var(--in-t), box-shadow var(--in-t);
}
.hsum-c::before{
  content:''; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:var(--acc); opacity:0;
  transition:opacity var(--in-t);
}
.hsum-c:hover, .hsum-c:focus-visible{
  border-color:color-mix(in srgb, var(--acc) 45%, var(--line2));
  box-shadow:var(--dp-e2), var(--dp-rim-s), 0 16px 32px -22px var(--glow);
}
.hsum-c:hover::before, .hsum-c:focus-visible::before{ opacity:1; }
.hsum-c:active{ transform:translateY(0); box-shadow:var(--dp-e1), var(--dp-rim); }
/* Клетка значка — утопленная, как у KPI дашборда: значок «вставлен», а не «лежит». */
.hsum-ic{
  background:var(--in-well);
  border-color:var(--line);
  box-shadow:var(--in-well-sh);
}
/* Число ведёт, подпись поддерживает: моно и табличные разряды у числа,
   спокойный тон у подписи (11,5px → норма 4,5:1, --d-sec даёт 5,4/6,9). */
.hsum-c b{ font-family:var(--mono); letter-spacing:-.02em; color:var(--tx); font-variant-numeric:tabular-nums; }
.hsum-l{ color:var(--d-sec); }

/* Просрочки — единственная плитка, которая обязана останавливать взгляд.
   (0,2,0) на ступень выше .hsum-c, поэтому корешок и рамка не гаснут в покое. */
.hsum-c.bad{ border-color:color-mix(in srgb, var(--danger) 38%, var(--line2)); }
.hsum-c.bad::before{ background:var(--danger); opacity:1; }
.hsum-c.bad b{ color:var(--d-danger); }
.hsum-c.bad .hsum-ic{
  color:var(--d-danger);
  background:linear-gradient(160deg,
    color-mix(in srgb, var(--danger) 22%, transparent),
    color-mix(in srgb, var(--danger) 6%, transparent));
  border-color:color-mix(in srgb, var(--danger) 30%, transparent);
}
/* «закрыто за неделю» — хорошая новость, и это единственное значение бирюзы. */
.hsum-c.good .hsum-ic{
  color:var(--d-ok);
  background:linear-gradient(160deg,
    color-mix(in srgb, var(--ok) 18%, transparent),
    color-mix(in srgb, var(--ok) 5%, transparent));
  border-color:color-mix(in srgb, var(--ok) 26%, transparent);
}


/* ───────────────────────────────────────────────────────────────────────────
   2 · ГЛАВНАЯ · ПОИСК И СОРТИРОВКА · .hbar (homeBar)
   ─────────────────────────────────────────────────────────────────────────── */
/* Поле поиска — ниша: ввод «утоплен», кнопки сортировки рядом «подняты».
   Разная глубина сразу отделяет поле от кнопок. */
.hbar-search{
  border-radius:10px; height:40px;
  background:var(--in-well);
  border-color:var(--line2);
  color:var(--d-sec);
  box-shadow:var(--in-well-sh);
}
.hbar-search:focus-within{
  border-color:var(--dp-focus);
  box-shadow:var(--in-well-sh), 0 0 0 3px color-mix(in srgb, var(--acc) 26%, transparent);
}
.hbar-search:focus-within svg{ color:var(--acc-tx); }
.hs{
  border-radius:10px; height:40px;
  background:var(--in-lift);
  border-color:var(--line2);
  color:var(--d-sec);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:color var(--in-t), border-color var(--in-t), box-shadow var(--in-t);
}
.hs:hover{ color:var(--tx); border-color:var(--edge); }
/* Активная сортировка. Здесь был реальный провал: правило писалось под
   прежнюю синюю палитру, а после перехода на оранжевую белый текст на
   var(--acc) даёт 3,1:1 в тёмной теме и 4,6:1 в светлой. По дисциплине
   палитры текст НА оранжевом тёмный; в светлой заливку углубляем, чтобы
   белый набрал норму. Итог: 6,8/4,9 в тёмной и 5,5/7,0 в светлой. */
.hs.on{
  background:linear-gradient(180deg, var(--in-sel-a), var(--in-sel-b));
  border-color:var(--in-sel-b);
  color:var(--in-sel-tx);
  font-weight:700;
  box-shadow:var(--ct-halo), inset 0 1px 0 rgba(255,255,255,.24);
}


/* ═══════════════════════════════════════════════════════════════════════════
   3 · ГЛАВНАЯ · КАРТОЧКА ПРОЕКТА · .pcard (projectCard)
   Карточка обязана быть витриной состояния: с двух метров видно, живой
   проект, завершённый или с просрочками, — до того как прочитана подпись.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Состояние берём из СОДЕРЖИМОГО (.pc-st уже в разметке), а не из выдуманного
   класса. Если :has не поддержан, остаётся нейтральная кромка — не поломка. */
.pcard{ --in-pc:var(--tx-dim); }
.pcard:has(.pc-st.live){ --in-pc:var(--acc); }
.pcard:has(.pc-st.done){ --in-pc:var(--ok); }
.pcard:has(.pc-st.risk){ --in-pc:var(--danger); }

.pcard{
  padding:18px 20px 16px;
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:transform var(--in-t), border-color var(--in-t), box-shadow var(--in-t);
}
/* Кромка состояния по верху. ::after у .pcard погашен в theme.css (content:none),
   поэтому берём свободный ::before; абсолютный — иначе стал бы флекс-элементом. */
.pcard::before{
  content:''; position:absolute; left:0; right:0; top:0; height:2px;
  pointer-events:none;
  background:linear-gradient(90deg,
    color-mix(in srgb, var(--in-pc) 88%, transparent), transparent 76%);
}
/* Подъём тенью, а не только рамкой: прежняя тень была холодным литералом
   rgba(36,36,36,.6) — на тёплой палитре она отдавала в синь. */
.pcard:hover{
  transform:translateY(-3px);
  border-color:color-mix(in srgb, var(--in-pc) 34%, var(--line2));
  box-shadow:var(--dp-e3), var(--dp-rim-s), 0 26px 50px -34px var(--glow);
}
.pcard:active{ transform:translateY(-1px); }
.pcard h3{ font-size:16.5px; letter-spacing:-.01em; }
/* Клиент и число задач — 12px: --tx-dim давал 4,6:1, ровно на границе. */
.pc-meta{ color:var(--d-sec); }
.pcard p{ color:var(--d-sec); line-height:1.55; }
/* Статус проекта — маленькая, но плотная плашка: она и есть заголовок состояния. */
.pc-st{ font-weight:700; letter-spacing:.01em; box-shadow:var(--dp-rim); }
.pc-chip{ color:var(--d-sec); box-shadow:var(--dp-rim); }
.pc-chip.bad{ color:var(--d-danger); }
.pc-chip .d{ box-shadow:var(--dot-bevel); }
/* Полоса готовности: дорожка уже «корыто» (theme.css), заливке добавляем
   объём и тёплое свечение — прогресс должен выглядеть как налитое, а не
   как закрашенное. */
.pcard .prog{ height:8px; border-radius:8px; }
.pcard .prog i{
  border-radius:8px;
  background-image:var(--in-gloss), linear-gradient(90deg, var(--acc-d), var(--acc));
  box-shadow:0 0 14px -5px var(--glow);
}
/* «Открыть →» проявляется на наведении (app.css), но стрелка стояла мёртво.
   Микродвижение читается как приглашение, а не как украшение. */
.pc-go{ color:var(--acc-tx); font-weight:700; }
.pc-go svg{ transition:transform var(--in-t); }
.pcard:hover .pc-go svg, .pcard:focus-visible .pc-go svg{ transform:translateX(3px); }


/* ═══════════════════════════════════════════════════════════════════════════
   4 · АНАЛИТИКА ПРОЕКТА · .hero-an / .kpic (projectDash)
   ═══════════════════════════════════════════════════════════════════════════ */
/* Кольцо готовности читают с двух метров — при диаметре 104px процент внутри
   оставался 15px, как в 46-пиксельном кольце карточки. */
.hero-an .an-ringbox.big .miniring .mrt{ font-size:19px; }
.hero-an .an-ringbox.big .miniring circle:last-of-type{
  filter:drop-shadow(0 0 10px color-mix(in srgb, var(--acc) 52%, transparent));
}
.hero-an .an-head>span:first-child{ font-size:16px; letter-spacing:-.01em; }
.hero-an .an-sum{ color:var(--d-sec); }

/* KPI-плитки. Смысл плитки («сделано» / «просрочено») должен считываться
   раньше, чем прочитана подпись, — нить по нижней кромке в смысловом цвете. */
.kpic{ --in-kpi:transparent; position:relative; overflow:hidden;
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:transform var(--in-t), box-shadow var(--in-t), border-color var(--in-t);
}
.kpic.good{ --in-kpi:var(--ok); }
.kpic.bad{ --in-kpi:var(--danger); }
.kpic::before{
  content:''; position:absolute; left:0; right:0; bottom:0; height:2px;
  pointer-events:none;
  background:linear-gradient(90deg, var(--in-kpi), transparent 82%);
}
.kpic:hover{ transform:translateY(-2px); box-shadow:var(--dp-e2), var(--dp-rim-s); }
.kpi-ic{ box-shadow:var(--in-well-sh); }
.kpi-l{ color:var(--d-sec); }


/* ───────────────────────────────────────────────────────────────────────────
   5 · СПИСКИ ДАШБОРДА · .dlist / .drow («Ближайшие сроки», «Требует внимания»)
   Каждая строка — кнопка, открывающая задачу. Отвечала она только сменой
   фона: на телефоне такой отклик не виден вовсе (палец закрывает строку).
   ─────────────────────────────────────────────────────────────────────────── */
.drow{
  position:relative;
  padding:11px 12px;
  min-height:44px;
  transition:background var(--in-t), box-shadow var(--in-t), transform var(--in-t);
}
.drow:hover{ background:var(--d-hov); box-shadow:inset 2px 0 0 var(--acc); }
.drow:active{ transform:translateX(1px); }
/* «Требует вашего внимания» — карточка обращена к клиенту лично, и её строки
   отвечают тревогой, а не акцентом: (0,3,0) выше базового .drow:hover (0,1,1). */
.dcard.attention .drow:hover{
  background:color-mix(in srgb, var(--danger) 10%, transparent);
  box-shadow:inset 2px 0 0 var(--danger);
}


/* ───────────────────────────────────────────────────────────────────────────
   6 · ЛЕНТА ИЗМЕНЕНИЙ · .feed .frow (projectDash · recent_changes)
   Это единственное место, где клиент видит ход работы как рассказ. Строки
   были разделены волосками, то есть выглядели таблицей. Нанизываем события
   на нить времени: значок — узел, волосок между узлами — ход времени.
   Селектор начинается с .feed, потому что .frow живёт только здесь, а класс
   .feed переиспользован на экране «Команда» (там строки .fe — их не трогаем).
   ─────────────────────────────────────────────────────────────────────────── */
.feed .frow{
  position:relative;
  border-bottom:none;
  padding:10px 2px;
  gap:12px;
  align-items:flex-start;
}
/* Нить идёт ОТ низа значка ДО значка следующей строки: 10px верхнего отступа
   + 20px значка = 31px сверху, −10px снизу как раз перекрывают отступ соседа.
   Высота строки минимум 40px, поэтому отрезок всегда положительный. */
.feed .frow::before{
  content:''; position:absolute; left:11px; top:31px; bottom:-10px; width:1px;
  background:var(--d-hair);
}
.feed .frow:last-child::before{ content:none; }
.feed .fic{ border-radius:7px; box-shadow:var(--dp-rim); }
/* Самое свежее событие сверху — тонкий тёплый ореол вокруг узла говорит
   «это только что», не крича цветом. */
.feed .frow:first-child .fic{
  box-shadow:var(--dp-rim), 0 0 0 3px color-mix(in srgb, var(--acc) 13%, transparent);
}
.feed .ftx{ color:var(--tx); }
.feed .fdt{ color:var(--d-sec); }


/* ───────────────────────────────────────────────────────────────────────────
   7 · ПУСТЫЕ СОСТОЯНИЯ
   Пусто — это задумка, а не сбой загрузки. Рамка пунктиром говорит «место
   отведено», тёплое зарево — «мы про него помним».
   ─────────────────────────────────────────────────────────────────────────── */
.dash-empty{
  background:
    radial-gradient(120% 150% at 50% 0,
      color-mix(in srgb, var(--acc) 6%, transparent), transparent 72%),
    color-mix(in srgb, var(--bg) 35%, transparent);
  color:var(--d-sec);
  text-wrap:balance;
}
.emptybox h3{ letter-spacing:-.01em; }
.emptybox p{ color:var(--d-sec); text-wrap:balance; }

/* Ошибка ≠ пусто. Значок уходит в тревожный, чтобы «не загрузилось» не
   читалось как «здесь пока ничего нет». Текст ошибки — моно, длинные строки
   без пробелов переносятся, но обычные слова не рвутся посреди. */
.emptybox.err .ei{
  background:color-mix(in srgb, var(--danger) 12%, var(--panel));
  border-color:color-mix(in srgb, var(--danger) 34%, var(--line2));
  color:var(--danger);
}
.emptybox.err h3{color:var(--tx)}
.emptybox.err p{font-family:var(--mono); font-size:13px; color:var(--tx-mut); overflow-wrap:break-word}

/* Двадцать пикселей под последним абзацем оставались от кнопки, которой в
   пустом состоянии нет: коробка выглядела съехавшей вверх. */
.emptybox p:last-child{margin-bottom:0}

/* «Движений пока нет» (часы) и текст ошибки счетов выводятся голым .empty
   прямо в #view — на весь экран висела строка серого текста без опоры. */
#view>.empty{
  margin:6px 24px 24px;
  padding:34px 18px;
  border:1px dashed var(--line2);
  border-radius:var(--bd-r);
  background:color-mix(in srgb, var(--bg) 35%, transparent);
  color:var(--d-sec);
  text-wrap:balance;
}


/* ───────────────────────────────────────────────────────────────────────────
   8 · СЧЕТА · .inv (renderInvoices)
   Строка счёта — платёжный документ; ей положен вес документа, а не строки
   списка. Плюс дисциплина действий: «Оплатить» громче «Скачать».
   ─────────────────────────────────────────────────────────────────────────── */
.inv{
  background:var(--in-lift);
  box-shadow:var(--dp-e1), var(--dp-rim);
  transition:transform var(--in-t), border-color var(--in-t), box-shadow var(--in-t);
}
.inv:hover{
  transform:translateY(-2px);
  border-color:var(--line2);
  box-shadow:var(--dp-e2), var(--dp-rim-s);
}
.inv-ttl{ letter-spacing:-.01em; }
.inv-meta{ color:var(--d-sec); }
.inv-sum{ color:var(--tx); }
/* Единственное действие клиента на экране — оплата. Ореол кнопки уводит на
   неё взгляд, «Скачать» остаётся тихой. */
.inv-acts .inv-pay{ box-shadow:var(--ct-halo); }
.inv-acts .btn-ghost{ color:var(--d-sec); }
/* «К оплате» — деньги в работе, первая плитка сводки ведёт. */
.inv-kpis .inv-kpi:first-child b{ color:var(--acc-tx); }


/* ───────────────────────────────────────────────────────────────────────────
   9 · ЧАСЫ ПОДДЕРЖКИ · .hbal / .hrow (renderHours)
   Материал шкалы и корешки строк уже разобраны в theme.css — здесь только
   то, что осталось плоским: сама панель баланса и подписи.
   ─────────────────────────────────────────────────────────────────────────── */
.hbal{
  position:relative; overflow:hidden;
  background:var(--in-lift);
  box-shadow:var(--dp-e2), var(--dp-rim);
}
.hbal::before{
  content:''; position:absolute; left:0; right:0; top:0; height:1px;
  pointer-events:none;
  background:linear-gradient(90deg, transparent,
    color-mix(in srgb, var(--edge) 62%, transparent) 50%, transparent);
}
/* «ОСТАТОК ЧАСОВ» — 11px капслоком, норма 7:1; --tx-dim давал 4,9:1. */
.hb-lbl{ color:var(--d-cap); }
.hb-sub{ color:var(--d-sec); }
.hb-sub b{ color:var(--tx); font-variant-numeric:tabular-nums; }
.hrow{ transition:border-color var(--in-t), box-shadow var(--in-t); }
.hrow:hover{ box-shadow:var(--dp-e2), var(--dp-rim-s); }
.hr-t{ color:var(--d-sec); }
.hr-d{ color:var(--d-sec); }


/* ───────────────────────────────────────────────────────────────────────────
   10 · ДОКУМЕНТЫ · .lib (renderDocs)
   ─────────────────────────────────────────────────────────────────────────── */
.lib{
  background:var(--in-lift);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.lib:hover{
  box-shadow:var(--dp-e2), var(--dp-rim-s), 0 18px 34px -26px var(--glow);
}
.lib-s{ color:var(--d-sec); }
/* Стрелка «Скачать» уезжает вниз — жест совпадает со смыслом действия. */
.lib-dl svg{ transition:transform var(--in-t); }
.lib:hover .lib-dl svg, .lib:focus-visible .lib-dl svg{ transform:translateY(2px); }
.lib-note{ color:var(--d-sec); }


/* ═══════════════════════════════════════════════════════════════════════════
   11 · КЛИЕНТСКИЙ ВИД ЗАДАЧИ · roBody в openTask
   Самый недоведённый экран кабинета — и при этом тот, которым заказчик
   принимает работу. Разбор по порядку разметки: ro-block → rochips → roprog →
   tk-move → ro-edit → подзадачи → обсуждение.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Название задачи — редактируемое поле (textarea.tt-area), но выглядит как
   обычный заголовок: клиент не догадывается, что его можно поправить.
   Пунктир при наведении — «здесь можно писать»; сплошная линия при фокусе. */
.mhead .tasktitle.tt-area{
  border-bottom:1px dashed transparent;
  padding-bottom:2px;
  transition:border-color var(--in-t);
}
.mhead .tasktitle.tt-area:hover{ border-bottom-color:var(--line2); }
.mhead .tasktitle.tt-area:focus{ border-bottom:1px solid var(--acc); }

/* «Задача ждёт вашего ответа» — единственная строка кабинета, которая прямо
   просит клиента о действии. Была плашкой в ряд с чипами; поднимаем до
   баннера: корешок тревоги, тёплая подложка, мягкое свечение.
   Контраст --d-danger на этой подложке: 6,7:1 тёмная, 5,8:1 светлая. */
.ro-block{
  position:relative; overflow:hidden;
  padding:12px 14px 12px 17px;
  border-radius:12px;
  color:var(--d-danger);
  background:linear-gradient(120deg,
    color-mix(in srgb, var(--danger) 15%, transparent),
    color-mix(in srgb, var(--danger) 7%, transparent));
  border-color:color-mix(in srgb, var(--danger) 34%, transparent);
  box-shadow:var(--dp-rim),
             0 12px 28px -22px color-mix(in srgb, var(--danger) 70%, transparent);
}
.ro-block::before{
  content:''; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:var(--danger);
}

/* ── Сводка чипами · .rochips ──
   Материал чипа оставался серым литералом rgba(159,159,159,.11) (theme.css:653) —
   холодное пятно на тёплой панели модалки. Берём тёплый белый на просвет:
   тон подхватывает подложку, на какой бы ступени чип ни стоял.
   --d-cap вместо --tx-mut: на этой подложке --tx-mut даёт 5,2:1, --d-cap — 8,3:1. */
.rochips{ gap:8px; margin-bottom:14px; }
.rochips .chip{
  padding:5px 11px;
  border-radius:8px;
  line-height:1.35;
  background:var(--bd-chip);
  box-shadow:inset 0 0 0 1px var(--bd-chip-line);
  color:var(--d-cap);
}
.rochips .typechip{ color:var(--tx); padding-left:22px; font-weight:650; }
.rochips .typechip::before{ box-shadow:var(--dot-bevel); }
/* Номер задачи — штамп: утопленная клетка, как у номера счёта. На него
   ссылаются в переписке, поэтому он обязан выделяться из ряда чипов. */
.rochips .tno{
  padding:0 9px; line-height:27px; border-radius:8px;
  background:var(--in-well);
  box-shadow:var(--in-well-sh);
  color:var(--d-cap);
  font-family:var(--mono); letter-spacing:.02em;
}
/* Смысловые состояния обязаны остаться сильнее общего материала.
   У .rochips .chip специфичность (0,2,0) — ровно как у .chip.hi и .chip.blk,
   и этот файл идёт позже: без повтора «Высокий» и «Ждём клиента» потеряли бы
   цвет. Просрочка и «сегодня» объявлены в theme.css как (0,3,0) — их не
   перебивает, но повторяем ради читаемости охры в светлой теме (3,9 → 6,3). */
.rochips .chip.hi{
  color:var(--in-warn-tx);
  background:color-mix(in srgb, var(--warn) 14%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--warn) 34%, transparent);
  font-weight:700;
}
.rochips .chip.due.today{
  color:var(--in-warn-tx);
  background:color-mix(in srgb, var(--warn) 14%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--warn) 32%, transparent);
}
.rochips .chip.due.over{
  color:var(--d-danger);
  background:color-mix(in srgb, var(--danger) 15%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--danger) 34%, transparent);
  font-weight:700;
}
.rochips .chip.blk{
  color:var(--d-danger);
  background:color-mix(in srgb, var(--danger) 13%, transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--danger) 30%, transparent);
}

/* ── Готовность · .roprog ──
   Было: голая полоса и «45%» без подписи. Человек без технического опыта не
   обязан догадываться, что это за число. Ставим шкалу в нишу и подписываем;
   подпись через ::before, потому что разметку менять нельзя. Блок сам по себе
   скрыт инлайновым display:none, когда прогресса нет, — псевдоэлемент тоже.
   Контраст подписи на нише: 10,2:1 тёмная, 10,0:1 светлая. */
.roprog{
  display:grid;
  grid-template-columns:1fr auto;
  grid-template-areas:'cap cap' 'bar val';
  align-items:center;
  gap:7px 12px;
  margin:0 0 14px;
  padding:12px 14px;
  border-radius:12px;
  background:var(--in-well);
  box-shadow:var(--in-well-sh);
}
.roprog::before{
  content:'Готовность';
  grid-area:cap;
  font-family:var(--mono); font-size:10px; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase;
  color:var(--d-cap);
}
.roprog .prog{
  grid-area:bar; min-width:0;
  height:10px; border-radius:10px;
  background:color-mix(in srgb, var(--bg) 62%, var(--card2));
}
/* Заливка уходила в бирюзу (общее .prog i в theme.css: акцент → --ok), то есть
   полоса на 15% всё равно заканчивалась цветом «готово». Бирюза остаётся за
   успехом — ход работы идёт тёплым. Тот же разбор, что у .pcard .prog i. */
.roprog .prog i{
  border-radius:10px;
  background:linear-gradient(90deg, var(--acc-d), var(--acc));
  background-image:var(--in-gloss), linear-gradient(90deg, var(--acc-d), var(--acc));
  box-shadow:0 0 14px -5px var(--glow);
}
.roprog>span{
  grid-area:val;
  font-size:15px; color:var(--tx);
  font-variant-numeric:tabular-nums; letter-spacing:-.02em;
}

/* ── Приёмка · .tk-move ──
   Три кнопки подряд весили одинаково, хотя последствия у них разные.
   Ставим лестницу: принять ≫ вернуть ≫ удалить.
   display:flex делает кнопки блочными: при inline-flex с width:100% между
   ними оставался пробел из разметки, и ритм плыл. */
.tk-move{
  display:flex; justify-content:center;
  min-height:48px;
  margin:12px 0 0;
  border-radius:12px;
  font-size:15px; font-weight:700;
}
.tk-move + .tk-move{ margin-top:8px; }

/* «Принять работу» — успех, а не «здесь ты». Бирюза, как у быстрой приёмки на
   карточке доски. Текст на заливке: тёмный в тёмной теме (11,1:1 и 7,6:1),
   белый в светлой (5,3:1 и 8,9:1). Специфичность (0,4,0) — выше .btn-primary
   и его вариантов в theme.css. */
.btn.btn-primary.tk-move[data-tkaccept]{
  background:linear-gradient(180deg, var(--in-ok-a), var(--in-ok-b));
  border-color:var(--in-ok-b);
  color:var(--in-on-ok);
  box-shadow:var(--in-ok-halo), inset 0 1px 0 rgba(255,255,255,.28);
}
.btn.btn-primary.tk-move[data-tkaccept]:hover{
  background:linear-gradient(180deg, var(--in-ok-ha), var(--in-ok-hb));
  border-color:var(--in-ok-hb);
  color:var(--in-on-ok);
}
.btn.btn-primary.tk-move[data-tkaccept]:active{ transform:translateY(1px); }

/* «Вернуть на проверку» — отмена приёмки: заметна, но не спорит с главной. */
.btn.btn-ghost.tk-move[data-tkundo]{
  min-height:44px; font-weight:650;
  background:var(--in-lift);
  border-color:var(--line2);
  color:var(--d-sec);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.btn.btn-ghost.tk-move[data-tkundo]:hover{
  color:var(--tx); border-color:var(--edge);
  background:var(--in-lift);
}
/* «Удалить задачу» — необратимо, поэтому только контур и отдельный отступ:
   промахнуться по нему пальцем не должно быть легко. */
.btn.btn-danger.tk-move[data-tkdel]{
  min-height:44px; font-weight:650;
  margin-top:16px;
  background:none;
  border-color:color-mix(in srgb, var(--danger) 34%, transparent);
  color:var(--d-danger);
  box-shadow:none;
}
.btn.btn-danger.tk-move[data-tkdel]:hover{
  border-color:var(--danger);
  color:var(--d-danger);
  background:color-mix(in srgb, var(--danger) 10%, transparent);
}

/* ── Правка описания · .ro-edit ──
   Клиенту доступны только название и описание. Блок должен читаться как
   отдельный лист, а не как хвост карточки. */
.ro-edit{
  margin:16px 0 4px;
  padding:14px 16px;
  border:1px solid var(--line);
  border-radius:12px;
  background:var(--in-lift);
  box-shadow:var(--dp-e1), var(--dp-rim);
}
.ro-edit label{
  font-family:var(--mono); font-size:10px; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase;
  color:var(--d-cap);
  margin-bottom:8px;
}
.ro-edit textarea{
  border-radius:10px;
  background:var(--in-well);
  box-shadow:var(--in-well-sh);
}
.ro-edit textarea:focus{
  border-color:var(--dp-focus);
  box-shadow:var(--in-well-sh), 0 0 0 3px color-mix(in srgb, var(--acc) 18%, transparent);
}
.ro-edit-act{ margin-top:12px; }
.ro-edit-act .hint{ color:var(--d-sec); font-family:var(--sans); }
.ro-edit-act .btn-primary{ min-height:40px; }

/* ── Подзадачи в клиентском виде ──
   У клиента КАЖДЫЙ чекбокс приходит с disabled (app.js), и правило
   .sub-ck:disabled{opacity:.6} гасило весь список: он выглядел выключенным,
   хотя это просто индикатор состояния, а не выключенный элемент управления.
   Возвращаем полную плотность и снимаем «выключенность» рамкой. */
.subs .sub-ck:disabled{ opacity:1; border-color:var(--line2); }
.subs .sub.done .sub-ck:disabled{
  border-color:color-mix(in srgb, var(--ok) 55%, transparent);
  color:var(--d-ok);
}
/* Статус подзадачи — 11px, норма 7:1; --tx-dim давал 4,3:1 на var(--card2). */
.subs .sub-st{ color:var(--d-cap); }
.subs-empty{ color:var(--d-sec); }
.subs-n{ color:var(--d-sec); font-variant-numeric:tabular-nums; }

/* ── Обсуждение ──
   Граница между приёмкой и перепиской: до сих пор заголовок просто висел
   между блоками, и глаз не понимал, где кончается «работа с задачей». */
.cmts-head{
  margin:22px 0 12px;
  padding-top:16px;
  border-top:1px solid var(--d-hair);
  font-size:14px; letter-spacing:-.01em;
  color:var(--tx);
}
/* Полоса прокрутки переписки. Каждый WebKit-псевдоэлемент — ОТДЕЛЬНЫМ
   правилом: в общем списке неизвестный псевдоэлемент отменяет весь список,
   и вне WebKit отвалились бы соседние селекторы. */
.cmts{ scrollbar-width:thin; scrollbar-color:var(--bd-bar) transparent; }
.cmts::-webkit-scrollbar{ width:8px; }
.cmts::-webkit-scrollbar-track{ background:transparent; }
.cmts::-webkit-scrollbar-thumb{
  background:var(--bd-bar);
  border-radius:8px;
  border:2px solid transparent;
  background-clip:padding-box;
}


/* ═══════════════════════════════════════════════════════════════════════════
   12 · ЧИТАЕМОСТЬ СМЫСЛОВЫХ ПЛАШЕК
   Найдено измерением В БРАУЗЕРЕ (вычисленный цвет текста против фактической
   подложки, обе темы, худшая остановка градиента). Общая причина одна: цвета
   --acc / --ok / --warn / --danger рассчитаны на ЗАЛИВКИ и точки, а как ТЕКСТ
   мелким кеглем они не добирают — особенно на кремовой теме, где акцент
   уходит в терракоту. Лечение везде одинаковое: подмешать --tx. В тёмной
   теме это осветляет, в светлой затемняет, оттенок и смысл остаются.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Статус проекта — 11px капслоком, норма 7:1. Было: «В работе» 6,5 в тёмной
   и 2,8 в светлой (чистый --acc-d), «Завершён» 4,4, «Есть просрочки» 4,7.
   Единая доля 55% даёт 7,6/7,0 · 11,1/7,5 · 8,4/8,1. */
.pc-st.live{ color:var(--in-acc-tx); }
.pc-st.done{ color:color-mix(in srgb, var(--ok) 55%, var(--tx)); }
.pc-st.risk{ color:color-mix(in srgb, var(--danger) 55%, var(--tx)); }
/* «Завершён» в светлой теме держится отдельным правилом: в theme.css он
   выставлен селектором :root[data-theme="light"] .pc-st.done (0,3,0), то есть
   сильнее (0,2,0) выше. Повторяем на той же ступени — иначе в кремовой теме
   остался бы чистый --ok и 4,4:1. */
:root[data-theme="light"] .pc-st.done{
  color:color-mix(in srgb, var(--ok) 55%, var(--tx));
}

/* «Скачать» в библиотеке документов стояло на чистом --acc: 3,1:1 на кремовой
   бумаге. --acc-tx — это тот же оранжевый, но пригодный для текста (7,3/5,5). */
.lib-dl{ color:var(--acc-tx); }

/* «Пакет заканчивается» — предупреждение, а не авария, поэтому охра (так
   решено в theme.css). Но чистая охра в светлой теме давала 4,3:1 — фраза,
   ради которой панель и краснеет, читалась хуже соседних. Теперь 11,2/6,9. */
.hb-warn{ color:var(--in-warn-tx); }

/* Сроки и блокировки В СПИСКАХ ДАШБОРДА. Селектор начинается с .dlist
   намеренно: те же классы .due/.pill-blk живут на карточке доски, а это
   чужая область — там их читаемость разобрана отдельно и своими подложками. */
.dlist .due.over,
.dlist .pill-blk{ color:var(--d-danger); }        /* 6,2 / 5,4 */
.dlist .due.today{ color:var(--in-warn-tx); }     /* 8,5 / 5,9 */
/* Счётчик тревоги в шапке «Требует вашего внимания»: 4,0:1 в светлой. */
.dcard.attention .badge-n{ color:var(--d-danger); }

/* Значок события в ленте. Глиф «✓» и «•» — единственное, что несёт статус
   до прочтения строки, а в светлой теме он проваливался до 2,5:1.
   Ключи статусов сверены по STATUSES в app.js. */
.feed .frow.done .fic{ color:color-mix(in srgb, var(--ok) 64%, var(--tx)); }
.feed .frow.review .fic{ color:var(--in-acc-tx); }
.feed .frow.in_progress .fic{ color:var(--in-warn-tx); }
.feed .frow.wish .fic{ color:color-mix(in srgb, var(--t-design) 70%, var(--tx)); }
.feed .frow.rejected .fic{ color:var(--d-danger); }

/* Закрытая подзадача. Зачёркнутый текст на --tx-dim давал 4,39:1 — ниже
   нормы. «Сделано» не значит «нечитаемо»: зачёркивание уже сообщает статус. */
.subs .sub.done .sub-t{ color:var(--d-sec); }


/* ═══════════════════════════════════════════════════════════════════════════
   13 · СВЕТЛАЯ ТЕМА · возврат материала
   Проверено в браузере: в кремовой теме счёт, строка часов, документ и поле
   описания возвращались к ХОЛОДНОМУ СЕРОМУ, хотя панель под ними тёплая.
   Причина не в цвете, а в специфичности: в theme.css остался блок правил вида
   [data-theme="light"] .inv{background:linear-gradient(170deg,#F9F9F9,#F3F3F3)}
   — это (0,2,0), то есть на ступень выше одноклассовых правил этого файла, и
   поздний порядок подключения не спасает. Часть семейств (.dcard, .kpic,
   .pcard, .ptile, .inv-kpi) уже выправлена в theme.css селектором
   :root[data-theme="light"] (0,3,0); дочиниваем оставшиеся тем же способом.

   Это ровно та ловушка, про которую предупреждает проект, только с другой
   стороны: не «тёмное значение просочилось в светлую тему», а «светлая тема
   держит своё старое значение сильнее». Проверка одна и та же — смотреть
   вычисленный стиль, а не исходный текст правила.
   ═══════════════════════════════════════════════════════════════════════════ */
:root[data-theme="light"] .inv,
:root[data-theme="light"] .hbal,
:root[data-theme="light"] .lib{
  background:var(--in-lift);
}
/* Строка движения по часам. theme.css:5891 даёт ей тёплый --dx-row, но
   правило одноклассовое и в светлой теме проигрывало серому градиенту:
   на кремовой странице список часов был единственным холодным пятном. */
:root[data-theme="light"] .hrow{
  background:var(--in-lift);
}
/* Поле описания — единственное место клиентского вида задачи, где пишет сам
   клиент. Заливалось #F3F3F3: холодная плита внутри тёплой карточки. */
:root[data-theme="light"] .ro-edit textarea{
  background:var(--in-well);
}


/* ───────────────────────────────────────────────────────────────────────────
   14 · ТЕЛЕФОН · проверено на 390px и 360px
   Кабинетом пользуются каждый день, часто с телефона и одной рукой. Здесь
   три задачи: зоны нажатия от 44px, отсутствие горизонтальной прокрутки и
   отказ от дорогих эффектов, которые оплачиваются кадрами при скролле.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:640px){
  .hsum{ margin:16px 16px 0; padding:16px 16px 18px; }
  .hbar{ padding:14px 16px 0; }
  .grid{ padding:16px; gap:12px; }
  #view>.empty{ margin:6px 16px 20px; padding:28px 14px; }

  /* Зоны нажатия. 38px у поля и кнопок сортировки — ниже нормы для пальца. */
  .hbar-search, .hs{ height:44px; }
  .hsum-c{ min-height:62px; }
  .drow{ min-height:46px; padding:12px; }
  .hb-acts .btn{ min-height:44px; }
  .tk-move{ min-height:50px; }
  .btn.btn-ghost.tk-move[data-tkundo],
  .btn.btn-danger.tk-move[data-tkdel]{ min-height:46px; }

  /* Ховера нет — подъём и сдвиг только мешают: карточка «прыгает» от
     случайного касания при прокрутке. */
  .pcard:hover, .kpic:hover, .inv:hover{ transform:none; }
  .pcard:hover{ box-shadow:var(--dp-e1), var(--dp-rim); }
  .pcard:hover .pc-go svg{ transform:none; }
  /* «Открыть →» на телефоне показываем всегда: наводить нечем. */
  .pc-go{ opacity:1; transform:none; }

  /* Самые дорогие эффекты слоя — размытия и зарево. На мобильном GPU они
     оплачиваются кадрами при прокрутке, а смысла не несут. */
  .hsum::after{ content:none; }
  .hsum-ring .miniring circle:last-of-type,
  .hero-an .an-ringbox.big .miniring circle:last-of-type{ filter:none; }
  .pcard .prog i, .roprog .prog i{ box-shadow:none; }
}
@media(max-width:400px){
  .hsum{ margin:12px 12px 0; padding:14px; }
  .grid{ padding:12px; }
  /* Панель приёмки на 360px: 14px по бокам съедали ширину шкалы. */
  .roprog{ padding:11px 12px; gap:6px 10px; }
  .ro-edit{ padding:12px 13px; }
  .rochips{ gap:6px; }
  /* Сжимаем ТОЛЬКО горизонтальные поля: сокращение padding обнулило бы
     padding-left:22px у чипа типа, и цветная точка легла бы на первую букву
     (проверено на 390px — «●оработка»). */
  .rochips .chip{ padding-inline:9px; }
  .rochips .typechip{ padding-left:20px; }
}


/* ───────────────────────────────────────────────────────────────────────────
   15 · «МЕНЬШЕ ДВИЖЕНИЯ»
   Медиазапрос не добавляет специфичности, поэтому правила слоя пришлось бы
   гасить вручную: блоки reduced-motion в app.css и theme.css стоят ВЫШЕ
   этого файла и уже не перекрывают того, что объявлено здесь.
   Гасим только движение: цвет, тень и кромка состояния остаются — состояние
   обязано читаться и без анимации.
   ─────────────────────────────────────────────────────────────────────────── */
@media(prefers-reduced-motion:reduce){
  .hsum-c, .hsum-c::before,
  .pcard, .pc-go svg, .kpic, .drow,
  .inv, .hrow, .lib, .lib-dl svg,
  .hs, .hbar-search,
  .tk-move, .ro-edit textarea,
  .mhead .tasktitle.tt-area{
    transition:none;
  }
  .pcard:hover, .kpic:hover, .inv:hover{ transform:none; }
  .pcard:active{ transform:none; }
  .drow:active{ transform:none; }
  .pcard:hover .pc-go svg, .pcard:focus-visible .pc-go svg,
  .lib:hover .lib-dl svg, .lib:focus-visible .lib-dl svg{ transform:none; }
  .btn.btn-primary.tk-move[data-tkaccept]:active{ transform:none; }
  /* WebKit-псевдоэлемент — ОТДЕЛЬНЫМ правилом (см. пояснение у .cmts выше). */
  .cmts::-webkit-scrollbar-thumb{ transition:none; }
}

/* ▲▲▲ конец: ВНУТРЕННИЕ ЭКРАНЫ — УСИЛЕНИЕ ▲▲▲ */

/* ═══ ДОРОЖНАЯ КАРТА ПРОЕКТА ═══════════════════════════════════════════
   Клиент заходит с вопросом «когда будет готово». Полоса этапов отвечает
   на него до того, как он откроет доску. Свёрнутое состояние помнить не
   нужно: этапов немного, и в развёрнутом виде они занимают одну строку.
   Контраст: название этапа 15.9:1 / 13.6:1, срок 7.0:1 / 7.4:1. ═══ */
.roadmap{
  border:1px solid var(--line); border-radius:14px; background:var(--panel);
  margin:0 0 14px; box-shadow:var(--dp-e1), var(--dp-rim);
}
.roadmap>summary{
  list-style:none; cursor:pointer; display:flex; align-items:baseline; gap:12px;
  padding:12px 16px; user-select:none;
}
.roadmap>summary::-webkit-details-marker{display:none}
.roadmap>summary::before{
  content:'▸'; font-size:11px; color:var(--tx-dim); transition:transform .16s; display:inline-block;
}
.roadmap[open]>summary::before{transform:rotate(90deg)}
.rm-t{font-size:14px; font-weight:650; letter-spacing:-.01em; color:var(--tx)}
.rm-c{font-size:12px; color:var(--tx-dim); font-family:var(--mono)}
.rm-body{padding:2px 16px 16px; border-top:1px solid var(--line)}

/* Этапы в строку с горизонтальной прокруткой: на длинном проекте их
   бывает десять, и переносить их в столбик — потерять ощущение пути. */
.rm-line{display:flex; gap:10px; overflow-x:auto; padding:14px 0 6px; scrollbar-width:thin}
.ms{
  flex:0 0 auto; min-width:172px; max-width:230px; position:relative;
  padding:12px 14px 12px 30px; border-radius:12px;
  background:var(--card); border:1px solid var(--line);
}
.ms-dot{
  position:absolute; left:12px; top:15px; width:9px; height:9px; border-radius:50%;
  background:var(--tx-dim); box-shadow:0 0 0 3px color-mix(in srgb, var(--tx-dim) 18%, transparent);
}
.ms-b b{display:block; font-size:13.5px; font-weight:650; color:var(--tx); line-height:1.3; margin-bottom:4px}
.ms-d{display:block; font-size:11.5px; font-family:var(--mono); color:var(--tx-dim)}
.ms-n{display:block; font-size:12px; color:var(--tx-mut); margin-top:6px; line-height:1.45}

/* Состояния. Бирюза — готово, оранжевый — идёт сейчас, красный — просрочен.
   «Запланирован» намеренно без цвета: будущее не должно кричать. */
.ms-done{border-color:color-mix(in srgb, var(--ok) 34%, var(--line))}
.ms-done .ms-dot{background:var(--ok); box-shadow:0 0 0 3px color-mix(in srgb, var(--ok) 20%, transparent)}
.ms-active{
  border-color:color-mix(in srgb, var(--acc) 42%, var(--line));
  background:linear-gradient(180deg, color-mix(in srgb, var(--acc) 8%, var(--card)), var(--card));
}
.ms-active .ms-dot{background:var(--acc); box-shadow:0 0 0 3px color-mix(in srgb, var(--acc) 22%, transparent)}
.ms-late{border-color:color-mix(in srgb, var(--danger) 45%, var(--line))}
.ms-late .ms-d{color:var(--danger); font-weight:600}
.ms-late .ms-dot{background:var(--danger); box-shadow:0 0 0 3px color-mix(in srgb, var(--danger) 22%, transparent)}

/* Команде этапы кликабельны, клиенту — нет: ложная кнопка хуже её отсутствия */
.ms[data-ms]{cursor:pointer; transition:border-color .15s, transform .15s}
.ms[data-ms]:hover{border-color:var(--edge); transform:translateY(-1px)}
.rm-add{margin-top:6px}
.rm-empty{font-size:13px; color:var(--tx-dim); padding:6px 0}

@media(max-width:760px){
  .rm-body{padding:2px 12px 12px}
  .ms{min-width:158px; padding:11px 12px 11px 28px}
}
@media(prefers-reduced-motion:reduce){
  .roadmap>summary::before, .ms[data-ms]{transition:none}
  .ms[data-ms]:hover{transform:none}
}

/* ═══ ОТМЕТКИ НА МАКЕТЕ ════════════════════════════════════════════════
   Точка на картинке + замечание. Раньше клиент писал «сдвиньте кнопку,
   которая справа сверху» текстом, и согласование дизайна шло кругами.
   Координаты в процентах, поэтому слой обязан лежать ровно по картинке —
   отсюда обёртка с position:relative и размером «по содержимому». ═══ */
.vw-wrap{position:relative; display:inline-block; max-width:100%; max-height:100%; line-height:0}
.vw-pins{position:absolute; inset:0; pointer-events:none}
.mkpin{
  position:absolute; transform:translate(-50%,-50%); pointer-events:auto;
  width:26px; height:26px; border-radius:50%; border:2px solid #fff;
  background:var(--acc); color:var(--on-acc); cursor:pointer; padding:0;
  display:grid; place-items:center; line-height:1;
  box-shadow:0 3px 12px -3px rgba(0,0,0,.6), 0 0 0 3px color-mix(in srgb, var(--acc) 30%, transparent);
  transition:transform .14s, box-shadow .14s;
}
.mkpin:hover{transform:translate(-50%,-50%) scale(1.12); z-index:3}
.mkpin-n{font-size:12px; font-weight:800; font-family:var(--mono)}
.mkpin-done{background:var(--ok); box-shadow:0 3px 12px -3px rgba(0,0,0,.6), 0 0 0 3px color-mix(in srgb, var(--ok) 30%, transparent)}

/* Всплывающее замечание: показываем по наведению, чтобы не заставлять
   кликать по каждой точке ради текста. */
.mkpin-b{
  position:absolute; left:50%; bottom:calc(100% + 10px); transform:translateX(-50%);
  min-width:180px; max-width:260px; padding:9px 11px; border-radius:10px;
  background:var(--panel); color:var(--tx); border:1px solid var(--line2);
  box-shadow:var(--dp-e3); font-size:12.5px; line-height:1.45; text-align:left;
  opacity:0; visibility:hidden; transition:opacity .14s; white-space:normal; font-weight:400;
}
.mkpin-b b{display:block; font-size:11px; color:var(--tx-dim); margin-bottom:3px; font-weight:600}
.mkpin:hover .mkpin-b{opacity:1; visibility:visible}
/* у нижних отметок подсказка вылезала бы за верх экрана — переносим её вниз */
.mkpin[style*="top:8"] .mkpin-b, .mkpin[style*="top:9"] .mkpin-b{bottom:auto; top:calc(100% + 10px)}

@media(max-width:760px){
  .mkpin{width:30px; height:30px}          /* палец, а не курсор */
  .mkpin-b{min-width:150px; max-width:200px; font-size:12px}
}
@media(prefers-reduced-motion:reduce){
  .mkpin{transition:none}
  .mkpin:hover{transform:translate(-50%,-50%)}
}

/* ═══ ПОДСКАЗКА ПРО АВТОТИП ════════════════════════════════════════════
   Клиент не обязан знать, чем «доработка» отличается от «фичи». Он пишет
   своими словами, а тип выводится из текста — подсказка объясняет, зачем
   заполнять описание, и показывает результат ещё до отправки. ═══ */
.tdet{
  display:flex; gap:9px; align-items:flex-start; margin-top:9px;
  padding:10px 12px; border-radius:10px; font-size:12.5px; line-height:1.5;
  color:var(--tx-dim); background:var(--card2); border:1px solid var(--line);
  transition:border-color .18s, background .18s, color .18s;
}
.tdet-i{flex:none; width:16px; height:16px; opacity:.7; margin-top:1px}
.tdet-i svg{width:16px; height:16px}
.tdet-x b{color:var(--tx); font-weight:650}
/* определился — подсказка становится утверждением и подсвечивается акцентом */
.tdet-on{
  color:var(--tx-mut);
  background:color-mix(in srgb, var(--acc) 8%, var(--card2));
  border-color:color-mix(in srgb, var(--acc) 30%, var(--line));
}
.tdet-on .tdet-i{opacity:1; color:var(--acc)}
@media(prefers-reduced-motion:reduce){ .tdet{transition:none} }

/* Выпадающий список внутри модалки: позиционируется от экрана, поэтому
   растягивание на всю ширину родителя ему больше не нужно — ширину
   задаёт JS по кнопке. Без сброса right:0 список уезжал бы вправо. */
.csel-list.csel-fixed{right:auto}

/* ▼▼▼ ПРОХОД: ЕДИНЫЙ РИТМ ▼▼▼ */
/* ============================================================================
   RHYTHM.CSS · клиентский кабинет roboweb.team
   Область прохода: ЕДИНЫЙ РИТМ — отступы, радиусы, кегль, линии, подача чисел.
   Направление не меняется: ни один цвет палитры, ни одна метафора оформления
   здесь не переизобретаются. Задача одна — свести разнобой величин, который
   накопился, пока блоки дописывались слоями.

   Подключать ПОСЛЕДНИМ: после app.css и theme.css. Там, где специфичность
   совпадает с уже существующим правилом, выигрывает порядок — это осознанно.

   Откуда берутся «канонические» значения (ничего не выдумано):
     • шкала кегля/веса/трекинга/интерлиньяжа — app.css:1530–1620 (--fs-*,
       --w-*, --tr-*, --lh-*), там же явно перечислены выброшенные ступени
       8/9/9.5/10/10.5/11.5/12.5/13.5/14.5/16.5/18;
     • шаг отступов --sp-1..--sp-6 (4/8/12/16/20/24) — app.css:1539;
     • радиусы 14 / 10 / 6 — theme.css:4200–4203 плюс токен --bd-r (4459);
     • дисциплина чисел (моно + tabular-nums + трекинг −.02em) — theme.css:2740–2750;
     • единый надзаголовок (11px, 600, капс, .07em, --d-cap) — app.css:1616–1620.

   Новые блоки (.quote, .roadmap/.ms, .rp-*, .mkpin, .tdet, details.props,
   .tno/.tid) писались уже ПОСЛЕ того, как эти списки были составлены, и в
   списки не попали — поэтому они и разъехались. Ниже они в них возвращаются.

   Контраст (посчитан для каждого литерала отдельно, тёмная / светлая):
     --tx      на --card  14.7:1 / 15.3:1   — заголовки блоков
     --d-cap   на --card2  8.6:1 /  9.4:1   — надзаголовки и штампы 11px
     --d-cap   на --bd-chip 7.7:1 /  9.6:1  — номер задачи в клетке чипа
     --d-sec   на --card2  5.4:1 /  6.9:1   — подсказка .tdet 12px
     --in-acc-tx на --card 8.3:1 /  8.1:1   — рубрика отчёта 11px акцентом
     --tx-dim  на --panel  4.9:1 /  6.4:1   — мета 12px, остаётся как было
   ============================================================================ */


/* ═══════════════════════════════════════════════════════════════════════════
   1 · РАДИУСЫ. Три ступени и ни одной больше.
   14px — панель и карточка (--bd-r) · 10px — кнопка, поле, чип · 6px — штамп.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Плитка этапа и плитка отчёта — карточки того же уровня, что .kpic и .ptile,
   а стояли на 12px: в одной сетке с 14px это читается как брак печати. */
.ms,

/* Строка часов выпала из списка theme.css:4200–4201 и осталась на 12px,
   хотя её соседи по экрану (.hbal 14, .lib 14, .inv 14) давно переведены. */
.hrow{border-radius:var(--bd-r)}

/* Клетка значка документа — 11px против 10px у такой же клетки KPI (.kpi-ic).
   Обе — «подставка под пиктограмму», ступень одна. */
.lib-ic{border-radius:10px}

/* Штампы: номер задачи и номер счёта. Было четыре значения на один смысл —
   .card .tid 5px, .tno 6px, .inv-num 7px, .rochips .tno 8px. Ступень «мелкий
   чип» в системе одна — 6px. Специфичность повторяет исходную (0,2,0/0,1,0),
   иначе правило не доедет. */
.card .tid,
.rochips .tno,
.tno,
.inv-num{border-radius:6px}

/* Мелкие плашки внутри карточки доски (app.css:1656 держал их на 5px, чтобы
   совпасть с .tid) — переезжают вместе со штампом на общую ступень. */
.card .meta .pchip,
.card .meta .due{border-radius:6px}

/* Сводка задачи чипами показывается клиенту (.rochips) и команде (.tmeta).
   Это один ряд одного смысла, а радиус у них был 8px и 10px соответственно. */
.tmeta .chip,
.rochips .chip{border-radius:10px}


/* ═══════════════════════════════════════════════════════════════════════════
   2 · ВНУТРЕННИЕ ОТСТУПЫ. Четыре уровня вложенности, у каждого своя пара.
   Панель раздела 20/24 · карточка-плитка 14/16 · строка списка 12/16 ·
   сворачиваемая панель 12/16 в шапке и 16 в теле.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Панель раздела. Эталон — .dcard (app.css:506) 20/24. ── */
/* Баланс часов стоял на 22px сверху: на 2px выше соседней панели дашборда,
   и в столбик они не выравнивались по внутренней сетке. */
.hbal{padding:var(--sp-5) var(--sp-6)}

/* ── KPI-плитка. Эталон — .kpic (theme.css:3022) 14/16/15: нижняя строка на
      1px больше верхней, потому что под числом сидит подпись. ── */
.kpic{padding:14px var(--sp-4) 15px}
.inv-kpi{padding:14px var(--sp-4) 15px}   /* было 14/18/15 — на 2px шире соседей */
      /* было 14/13 — единственная плитка,
                                             у которой отступ по вертикали
                                             БОЛЬШЕ, чем по горизонтали */

/* Плитка проекта: 14px по кругу против 14/16 у KPI, стоят в одной сетке. */
.ptile{padding:14px var(--sp-4)}

/* ── Строка списка. Эталон — .hrow (theme.css:2865) 12/16. ── */
.lib{padding:var(--sp-3) var(--sp-4)}     /* было 13/15 */

/* ── Плитка этапа. Слева зарезервировано место под бусину состояния:
      её левый край совпадает с левым отступом остальных плиток. ── */
.ms{padding:14px var(--sp-4) 14px 32px}
.ms-dot{left:var(--sp-4); top:18px}

/* ── Сворачиваемая панель. Их в кабинете две — «План проекта» и «Свойства
      задачи» — и метрики у них были разные: 12/16 против 11/14.
      12px по вертикали выбраны не на глаз: 12 + 20 (--lh-md) + 12 = 44px,
      ровно минимальная зона нажатия, а шапка панели и есть кнопка. ── */
details.props>summary{padding:var(--sp-3) var(--sp-4); line-height:var(--lh-md)}
.roadmap>summary{padding:var(--sp-3) var(--sp-4); line-height:var(--lh-md)}
.props-body{padding:2px var(--sp-4) var(--sp-4)}
.rm-body{padding:2px var(--sp-4) var(--sp-4)}

/* ── Блок сметы стоит в том же столбце модалки, что и обе панели выше,
      а внутренний отступ имел 18px по горизонтали против их 16px:
      левые края текста не совпадали на соседних блоках. ── */
.quote{padding:var(--sp-4)}

/* ── Врезки-примечания. Было три значения на один смысл: .tdet 10/12,
      .q-note 11/13. Обе — «полоска пояснения внутри панели», ступень
      совпадает со строкой списка. ── */
.tdet{padding:var(--sp-3) var(--sp-4)}
.quote .q-note{padding:var(--sp-3) var(--sp-4)}

/* Штампы номеров: клетка одной высоты и одной ширины в обоих рядах.
   .rochips .tno жил на line-height:27px и padding 0 9px, голый .tno —
   на 18px и 0 7px: один и тот же номер задачи выглядел по-разному
   у клиента и у команды. */
.card .tid,
.tno{padding:0 6px}


/* ═══════════════════════════════════════════════════════════════════════════
   3 · КЕГЛЬ, ВЕС, ТРЕКИНГ, ИНТЕРЛИНЬЯЖ.
   Возврат новых блоков на шкалу app.css:1530–1620. Ушедшие полуступени:
   10 / 10.5 / 11.5 / 12.5 / 13.5 / 16 / 24 / 26 и веса 500 / 650 / 800.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Заголовок блока = 17px/24, 700, −.01em. Ступень .dc-t / .pcard h3. ── */
.quote .q-h b{                       /* было 16px — полуступень между 15 и 17 */
  font-size:var(--fs-h3); line-height:var(--lh-h3);
  font-weight:var(--w-bd); letter-spacing:var(--tr-h);
}

/* ── Название сворачиваемой панели = 14px/20, 600. Было 14px+650 у «Плана»
      и 13px+600 у «Свойств»: два заголовка одного вида, два кегля. ── */
.rm-t,
details.props>summary .ps-t{
  font-size:var(--fs-md); line-height:var(--lh-md);
  font-weight:var(--w-sb); letter-spacing:var(--tr-h);
}
/* Подпись в свёрнутой шапке = 12px/16. Было 12px у «Плана» и 11.5px
   у «Свойств» — рядом лежащие строки не совпадали по базовой линии. */
.rm-c,
details.props .ps-h{font-size:var(--fs-xs); line-height:var(--lh-cap)}

/* ── Единый надзаголовок: 11px, 600, капслок, трекинг .07em, цвет --d-cap.
      Правило app.css:1616 собрало под него .inv-kpi .l, .hb-lbl, .field label
      и т.д.; подписи над числами в смете и отчёте в список не попали и жили
      на 10.5px/.11em и 10px/.1em со слишком тихим --tx-dim (4.3:1 при норме
      7:1 для такого кегля). --d-cap даёт 8.6:1 / 9.4:1. ── */
.quote .q-nums u,
/* Рубрика раздела отчёта — тот же надзаголовок, но намеренно акцентная:
   она делит длинный список на части. Вес 700 → 600 (ступень надзаголовка),
   трекинг .1em → .07em. Чистый --acc на 11px даёт 5.6:1 / 4.4:1 — мало;
   --in-acc-tx (объявлен ровно под этот случай) даёт 8.3:1 / 8.1:1. */

/* ── Тело карточки/строки = 14px/20. ── */
.ms-b b{                             /* было 13.5px + вес 650 */
  font-size:var(--fs-md); line-height:var(--lh-md); font-weight:var(--w-sb);
}
  /* было 500 — веса такого в шкале нет */

/* ── Мета и подписи = 12px. ── */
.ms-d{font-size:var(--fs-xs); line-height:var(--lh-cap)}   /* было 11.5px */
/* было 12.5px */
.quote .q-tag{font-size:var(--fs-xs)}                       /* было 11.5px */
.mkpin-b{font-size:var(--fs-xs); line-height:var(--lh-lg)}  /* было 12.5px */

/* ── Проза внутри блоков = 13px/24 (ступень .emptybox p, .pcard p). ── */
.quote .q-note{font-size:var(--fs-sm); line-height:var(--lh-lg)}  /* было 13.5px/1.55 */
.ms-n{line-height:var(--lh-lg)}
/* Подсказка про автотип — ступень .hint: 12px/24. --tx-dim давал на ней
   4.3:1 при норме 4.5:1; --d-sec — 5.4:1 / 6.9:1. Ровно тот же обмен, что
   theme.css:2899 уже сделал для .lib-note («было --tx-dim: ~4:1 на 12px»). */
.tdet{font-size:var(--fs-xs); line-height:var(--lh-lg); color:var(--d-sec)}
.tdet-x b{font-weight:var(--w-sb)}   /* было 650 */

/* ── Итоговая строка отчёта — ступень .ivtotal (15px/24), а не 13.5px:
      сумма обязана быть тяжелее строк, из которых она сложена. ── */

/* ── Штамп номера задачи. Было 10px в карточке и 11px в модалке — один
      объект, два кегля, причём 10px из шкалы выброшен. Ставим 11px, а вместе
      с кеглем ≤11px приходит и его норма контраста 7:1: --tx-dim давал 5.8:1,
      --d-cap даёт 7.7:1 в тёмной и 9.6:1 в светлой на подложке --bd-chip. ── */
.card .tid,
.tno{
  font-size:var(--fs-cap); line-height:var(--lh-cap);
  letter-spacing:.02em;              /* было .05em / .02em — берём меньшее:
                                        моноширинному хватает собственного шага */
  color:var(--d-cap);
}
/* В ряду чипов штамп обязан совпадать с ними по высоте: у .rochips .chip
   5px + 12px×1.35 + 5px = 27px, поэтому клетка штампа набирает ту же высоту
   вертикальными отступами, а не магическим line-height:27px. */
.rochips .tno{
  font-size:var(--fs-cap); line-height:var(--lh-cap);
  padding:5px 6px; letter-spacing:.02em; color:var(--d-cap);
}
.tmeta .chip,
.rochips .chip{font-size:var(--fs-xs); line-height:1.35; padding:5px 11px}

/* ── Номер отметки на макете: 800 — вес витрины (.brand .dot), для цифры
      в кружке 26px это перебор. 700 — ступень всех чисел кабинета. ── */
.mkpin-n{font-weight:var(--w-bd)}
.mkpin-b b{font-size:var(--fs-cap); line-height:var(--lh-cap); color:var(--d-cap)}


/* ═══════════════════════════════════════════════════════════════════════════
   4 · ПОДАЧА ЧИСЕЛ. Одна дисциплина на весь кабинет (theme.css:2740–2750):
   витринное число — моноширинный + tabular-nums + трекинг −.02em;
   любое другое число, даже внутри прозы, — как минимум tabular-nums.
   Без tabular-nums разряды не встают в столбик, и колонка сумм читается
   как случайный набор.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Витринные числа: 28px (--fs-num) и общий интерлиньяж 32px. Было четыре
   значения на четыре одинаковые плитки: 24px/1 у сметы, 26px/1 у отчёта,
   28px/1.1 у .kpic, 28px/1.15 у .inv-kpi. */
.kpic b,
.inv-kpi b,
.quote .q-nums b,

/* Числа и даты, которые ходят в строке текста. Все они уже моноширинные,
   но tabular-nums не получили — а именно он выравнивает столбик дат
   в полосе этапов и столбик сумм в отчёте. */
.rm-c,
.ms-d,
.rp-h span,
.rp-list span,
.mkpin-n{font-variant-numeric:tabular-nums}

/* Числа в основном шрифте: «45 000 ₽ · 5 раб. дн.» в плашке согласованной
   сметы и «Выставлено … · оплачено …» в итоге отчёта. */
.quote .q-tag,
.rp-tot,


/* ═══════════════════════════════════════════════════════════════════════════
   5 · ЛИНИИ. Толщина везде 1px, различается только тон:
   --d-hair — волосок между строками одного списка,
   --line   — граница блока и шов внутри него,
   --line2  — линия, ЗАКРЫВАЮЩАЯ раздел (шапка таблицы, итог).
   ═══════════════════════════════════════════════════════════════════════════ */

/* Строки отчёта — плотный список внутри панели, ровно как .tbl td, который
   theme.css уже перевёл на --d-hair. Стоял --line: на печатной странице
   и в светлой теме он читался как полноценная граница ячейки. */

/* Корешок врезки — в кабинете уже есть токен толщины (--dx-rail-w:3px,
   им нарисованы .hrow::before и .ro-block::before). Врезка сметы держала
   свои 3px литералом: сойдутся значения — не разъедутся при правке токена. */
.quote .q-note{border-left-width:var(--dx-rail-w)}


/* ═══════════════════════════════════════════════════════════════════════════
   6 · ВЕРТИКАЛЬНЫЕ ИНТЕРВАЛЫ. Шаг --sp-1..--sp-6 (4/8/12/16/20/24).
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Промежуток между блоками в столбце задачи. Было пять значений подряд:
      .roadmap 14, .tmeta 15, .rochips 14, .quote-adm 16, .quote 18,
      details.props 18. Глаз читает это как сбитую вёрстку. ── */
.roadmap,
.quote,
details.props,
details.quote-adm,
.tmeta,
.rochips{margin-bottom:var(--sp-4)}

/* ── Внутренний ритм блока сметы. ── */
.quote .q-h{margin-bottom:var(--sp-3)}
.quote .q-nums{margin-bottom:var(--sp-3); gap:var(--sp-6)}   /* было gap 26px */
.quote .q-nums u{margin-bottom:var(--sp-1)}
.quote .q-note{margin-bottom:var(--sp-3)}                    /* было 14px */
.quote .q-act{margin-bottom:var(--sp-2); gap:var(--sp-2)}    /* было gap 10px */

/* ── Внутренний ритм полосы этапов. ── */
.rm-line{padding:var(--sp-3) 0 var(--sp-2); gap:var(--sp-3)} /* было 14/0/6, gap 10 */
.rm-add{margin-top:var(--sp-2)}                              /* было 6px */
.rm-empty{padding:var(--sp-2) 0}                             /* было 6px */
.ms-b b{margin-bottom:var(--sp-1)}
.ms-n{margin-top:var(--sp-2)}                                /* было 6px */

/* ── Внутренний ритм отчёта. ── */
                              /* было 18px */
         /* было gap 10px */
                    /* было 20/0/10 */
                           /* было 9px */

/* ── Зазор «подпись → число» в плитках KPI. Было три значения на один жест:
      .kpic gap 3px, .inv-kpi margin-top 6px, .rp-k margin-bottom 6px. ── */
.kpic{gap:var(--sp-1)}
.inv-kpi b{margin-top:var(--sp-1)}
.inv-kpi em{margin-top:var(--sp-1)}

/* ── Подсказка про автотип отделяется от поля тем же шагом, что и всё
      остальное в форме. ── */
.tdet{margin-top:var(--sp-2)}                                /* было 9px */

/* ── Шаг между однотипными элементами в списках и сетках.
      Сетка плиток — 12px, список строк — 8px. Было: .kpis 16, .inv-kpis 12,
      .ptiles 12, .rp-kpis 10 · .hlist 8, .lib-list 9, .invlist 11. ── */
.kpis,
.inv-kpis,
.ptiles,
.hlist,
.lib-list,
.invlist{gap:var(--sp-2)}
.tmeta,
.rochips{gap:var(--sp-2)}                                    /* было 7px / 8px */


/* ═══════════════════════════════════════════════════════════════════════════
   7 · ПОЛОСА ПРОКРУТКИ ПОЛОСЫ ЭТАПОВ.
   У .rm-line стоял только scrollbar-width:thin — в WebKit это ничего не даёт,
   и над доской появлялась системная серая полоса вместо тёплой, какая уже
   нарисована у .board-wrap и .col-body. Стандартное свойство — здесь,
   вендорные псевдоэлементы — ОТДЕЛЬНЫМИ правилами ниже: неизвестный
   псевдоэлемент в общем списке отменил бы весь список вне WebKit.
   ═══════════════════════════════════════════════════════════════════════════ */
.rm-line{scrollbar-color:var(--bd-bar) transparent}

.rm-line::-webkit-scrollbar{height:11px; background:transparent}
.rm-line::-webkit-scrollbar-track{background:transparent}
.rm-line::-webkit-scrollbar-thumb{
  background:var(--bd-bar);
  border:3px solid transparent; background-clip:padding-box;
  border-radius:99px; min-width:36px;
  transition:background-color var(--mo-1x) var(--mo-out);
}
.rm-line::-webkit-scrollbar-thumb:hover{background:var(--bd-bar-h)}


/* ═══════════════════════════════════════════════════════════════════════════
   8 · ТЕЛЕФОН. Проверено на 390px: горизонтальной прокрутки страницы нет,
   зоны нажатия ≥44px.
   ═══════════════════════════════════════════════════════════════════════════ */
@media(max-width:760px){
  /* Мобильная ступень витринного числа: app.css:1699 уже опускает .kpic b и
     .inv-kpi b с 28 на 20px. Смета и отчёт в тот список не попали и остались
     на 21px (смета) и 26px (отчёт) — на 390px «45 000 ₽» в две колонки
     не помещалось и ломало сетку модалки. */
  .quote .q-nums b,

  /* Панель раздела на телефоне: 24px по бокам съедали ширину содержимого —
     тот же приём, что theme.css:5248 применил к .dcard (16px). Баланс часов
     стоял на 18px и был единственной панелью не на шаге сетки.
     .analytics намеренно не трогаем: у неё уже есть своя ступень на ≤420px
     (app.css:1018), и правило отсюда её бы перебило. */
  .hbal{padding:var(--sp-4)}

  /* Тело сворачиваемых панелей поджимается тем же шагом, что и шапка,
     иначе слева от текста остаётся 16px, а справа 12px. */
  .rm-body,
  .props-body{padding:2px var(--sp-3) var(--sp-3)}
  .roadmap>summary,
  details.props>summary{padding:var(--sp-3)}
  .ms{padding:var(--sp-3) var(--sp-3) var(--sp-3) 28px}
  .ms-dot{left:var(--sp-3); top:17px}

  /* Отметка на макете — 30px: пальцем не попасть. Растим только зону нажатия
     невидимым полем, чтобы точка не закрыла собой сам макет. */
  .mkpin::after{content:''; position:absolute; inset:-7px; border-radius:50%}
}

@media(max-width:560px){
  .quote{padding:var(--sp-3)}
  .quote .q-nums{gap:var(--sp-4)}                /* было 18px */
  .quote .q-act .btn{width:100%; justify-content:center}
}

@media(max-width:640px){
  /* Две колонки плиток отчёта: при 4 колонках на 390px в ячейку не влезала
     даже подпись. Шаг сетки тот же, что у остальных плиток. */
}


/* ═══════════════════════════════════════════════════════════════════════════
   9 · ДВИЖЕНИЕ. Единственный переход, добавленный этим файлом, — подсветка
   ползунка полосы этапов. Гасим его так же, как гасятся остальные.
   Вендорный псевдоэлемент — снова ОТДЕЛЬНЫМ правилом.
   ═══════════════════════════════════════════════════════════════════════════ */
@media(prefers-reduced-motion:reduce){
  .rm-line{scroll-behavior:auto}
}
@media(prefers-reduced-motion:reduce){
  .rm-line::-webkit-scrollbar-thumb{transition:none}
}


/* ═══════════════════════════════════════════════════════════════════════════
   10 · ПЕЧАТЬ. Отчёт уходит на бумагу через window.print(), и theme.css
   держит для него отдельный блок @media print. Этот файл подключается ПОЗЖЕ,
   поэтому правила раздела 3 и 5 (цвет рубрики, цвет надзаголовка, тон
   волоска) перебили бы бумажные значения и отчёт печатался бы экранными
   цветами по белому. Повторяем бумажные значения здесь.
   ═══════════════════════════════════════════════════════════════════════════ */
@media print{
  .rp-k u,
  .rp-list span,
  .rp-k b,
  .rp-list b,
}

/* ▲▲▲ конец: ЕДИНЫЙ РИТМ ▲▲▲ */

/* ═══════════════════════════════════════════════════════════════════════
   ВХОД · ЖИВОЕ ДВИЖЕНИЕ
   Поверх существующего появления (authRise/authFadeIn/authErrIn) добавляем
   постоянную жизнь: медленный свет в витрине, дыхание индикатора, отклик
   на действие. Всё — на transform и opacity, чтобы не заставлять браузер
   пересчитывать раскладку: экран входа часто открывают на слабом телефоне.
   Имена анимаций с префиксом lv- (проверено: в файле таких нет).
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. Витрина дышит: два световых пятна ходят по разным орбитам с разным
      периодом, поэтому картинка не повторяется заметно для глаза ── */
@keyframes lvAurora1{
  0%,100%{transform:translate3d(0,0,0) scale(1)}
  33%    {transform:translate3d(6%,4%,0) scale(1.14)}
  66%    {transform:translate3d(-4%,7%,0) scale(1.06)}
}
@keyframes lvAurora2{
  0%,100%{transform:translate3d(0,0,0) scale(1.05)}
  50%    {transform:translate3d(-7%,-5%,0) scale(1.18)}
}
/* Витрина уже проявляется через authFadeIn (0,3,1) — дописываем движение
   ВТОРЫМ в тот же список, а не вместо: authFadeIn ведёт только opacity,
   lvAurora1 только transform, они не спорят. Селектор повторяет исходный,
   иначе более специфичное старое правило перебьёт это. */
.login-wrap.auth .auth-side::before{
  animation:authFadeIn 1.1s var(--mn-ease) backwards,
            lvAurora1 26s ease-in-out infinite;
  will-change:transform;
}
/* второй источник света — отдельным слоем, чтобы двигался независимо */
.auth-side-in::before{
  content:''; position:absolute; inset:-20% -10% auto -10%; height:70%;
  pointer-events:none; z-index:-1; border-radius:50%;
  background:radial-gradient(closest-side, rgba(255,90,50,.16), transparent 70%);
  filter:blur(28px);
  animation:lvAurora2 34s ease-in-out infinite;
}
:root[data-theme="light"] .auth-side-in::before{
  background:radial-gradient(closest-side, rgba(217,60,19,.13), transparent 70%);
}

/* ── 2. Блик по знаку студии снят. Он крутился бесконечно и остановить его
      было нечем — WCAG 2.2.2 требует управления для движения дольше пяти
      секунд. Знак остаётся, движение уходит ── */
.auth-side .brand .dot{position:relative}

/* ── 3. Пункты витрины: плитка иконки чуть подаётся вперёд при наведении
      на строку. Пункты некликабельны, поэтому движение деликатное —
      это отклик на внимание, а не обещание действия ── */
.auth-pts li{transition:transform .32s cubic-bezier(.2,.8,.3,1)}
.auth-pts li:hover{transform:translateX(3px)}
.ap-ic{transition:transform .32s cubic-bezier(.2,.8,.3,1), box-shadow .32s}
.auth-pts li:hover .ap-ic{
  transform:scale(1.06);
  box-shadow:0 6px 18px -8px color-mix(in srgb, var(--acc) 60%, transparent);
}

/* ── 4. Поле: подпись приподнимается и подкрашивается в фокусе.
      Так видно, где ты находишься, даже боковым зрением ── */
.login .field label{
  transition:color .2s, transform .2s cubic-bezier(.2,.8,.3,1);
  transform-origin:left center;
}
.login .field:focus-within label{color:var(--acc-d); transform:translateY(-1px)}

/* ── 5. Свет по кромке кнопки снят по той же причине, что и блик знака:
      бесконечное движение рядом с полем ввода пароля мешает, а выключателя
      у него не было. position:relative оставляем — на нём держится крутилка
      отправки .auth-go.loading::after ── */
.auth-go{position:relative}

/* Появление формы НЕ трогаем: оно уже разложено по authRise на
   .login>*:nth-child(2..8) с шагом 40–50 мс. Второй слой поверх него
   только сбил бы тайминг. */

/* ── 6. Телефон: витрина скрыта, значит и её движение ни к чему —
      это батарея, потраченная на невидимое ── */
@media(max-width:820px){
  .login-wrap.auth .auth-side::before,
  .auth-side-in::before{animation:none}
}

/* ── 7. «Меньше движения» — гасим всё постоянное. Появление остаётся:
      его уже гасит собственный блок системы выше ── */
@media(prefers-reduced-motion:reduce){
  .login-wrap.auth .auth-side::before{animation:none}
  .auth-side-in::before{animation:none}
  .auth-pts li, .ap-ic, .login .field label{transition:none}
  .auth-pts li:hover, .auth-pts li:hover .ap-ic{transform:none}
}

/* ═══════════════════════════════════════════════════════════════════════
   MONTSERRAT · КАЛИБРОВКА
   Кабинет переведён с Inter на Montserrat. Это не подмена одного имени:
   Montserrat геометричнее, шире по набору и крупнее оптически при том же
   кегле. Ниже — поправки, без которых плотные места кабинета (колонки
   доски 280px, шапки таблиц, подписи на графиках) теряют читаемость.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. Цифры в столбик. Раньше выравнивание держал моноширинный --mono;
      теперь семейство одно, поэтому нужны табличные цифры. Montserrat
      их поддерживает. Наследуется вниз; поля формы наследование
      font-variant-numeric не подхватывают — им отдельно ── */
body{font-variant-numeric:tabular-nums}
input,textarea,select,button,table{font-variant-numeric:tabular-nums}

/* ── 2. Трекинг. Montserrat набирается свободнее Inter — на 15px это
      около полутора процентов лишней ширины строки. Малый минус
      возвращает плотность, не превращая текст в слипшийся ── */
body{letter-spacing:-.01em}
/* прописные подписи уже имеют собственный разряд — их не трогаем */
.side-lbl, .tbl th, .card .cstage, .q-nums u, .rp-k u,
.dc-cap, .an-ringtxt span{letter-spacing:initial}

/* ── 3. Мелкие подписи. У Inter 9–10px ещё читались за счёт крупного очка
      и узких форм; у Montserrat на этих кеглях прописные сливаются.
      Поднимаем на ступень — ниже 10px в кабинете не остаётся ── */
.card .cstage{font-size:10px}
.side-lbl, .cmt-meta span, .an-ringtxt span{font-size:11px}
.dc-cap, .barsvg .bx, .axl{font-size:10px}

/* ── 4. Насыщенность. Montserrat 800 плотнее Inter 800: крупные числа
      дашборда превращались в чёрные плашки. Витрину ведём на 700,
      восьмёрку оставляем только знаку студии ── */
.kpic b, .inv-kpi b, .q-nums b, .dc-total, .miniring .mrt{font-weight:700}

/* ── 5. Пока шрифт качается, показываем системный: display=swap уже стоит
      в ссылке, здесь страхуем поля формы, которые наследуют не всегда ── */
input,textarea,select{font-family:var(--sans)}
/* ═══════════════════════════════════════════════════════════════════════
   ДОСКА · ПЛОТНОСТЬ РАБОЧЕЙ ОБЛАСТИ
   Замер на окне 900px до правки: над доской 585px хрома (шапка 85, вкладки 54,
   план проекта 207, статистика 117, поиск 43, метки 46, отступы ~33) — доске
   оставалось 300px, то есть полторы карточки. Ниже ужимается всё, что стоит
   НАД доской, и сама карточка. Правила действуют только на экране доски:
   отбор через :has(.board-wrap), на остальных экранах прежние отступы.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. Шапка на доске: название и клиент в одну строку вместо двух ── */
.main:has(.board-wrap) .topbar{padding:var(--sp-2) var(--sp-4)}
.main:has(.board-wrap) #crumb{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;min-width:0}
.main:has(.board-wrap) #crumb .desc{margin:0}
/* разделитель между названием проекта и клиентом — иначе строка читается как одна фраза */
.main:has(.board-wrap) #crumb .desc::before{content:'·';margin-right:9px;color:var(--tx-dim)}

/* ── 2. Вкладки и полосы над доской ── */
.main:has(.board-wrap) .ptabs{padding-top:var(--sp-2)}
.main:has(.board-wrap) .analytics{margin-top:var(--sp-2);padding:var(--sp-3) var(--sp-4)}
.main:has(.board-wrap) .an-head{margin-bottom:var(--sp-2)}
.main:has(.board-wrap) .an-cells{margin-top:var(--sp-2)}

/* ── 3. Поиск и метки теперь в одном ряду (.bfilters) ── */
.bfilters{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  /* 24px — общий отступ экрана: столько же у .ptabs, .analytics и .board-wrap.
     Прежний ряд поиска (.tsearch) стоял ровно на нём, 16px ломали вертикаль. */
  margin:var(--sp-2) var(--sp-6) 0}
.bfilters .tsearch{flex:1 1 260px;min-width:200px;margin:0;padding:var(--sp-2) 12px}
.bfilters .tagfilter{flex:1 1 auto;padding:0;min-width:0}

/* ── 4. Поле доски ── */
.main:has(.board-wrap) .board-wrap{padding-top:var(--sp-3);padding-bottom:var(--sp-2)}
/* Подвал на доске не показываем: он всё равно уходил под нижний край и давал
   странице лишние 60px прокрутки при полностью видимой доске. */
.main:has(.board-wrap) .app-foot{display:none}

/* ── 5. Карточка. Основной выигрыш: заголовок обрезается на трёх строках
      вместо четырёх — полный текст остаётся в подсказке и в самой задаче ── */
.board .card{padding:10px 12px}
.board .card .ttl{-webkit-line-clamp:3;line-clamp:3}
.board .card .chead{margin-bottom:1px}
.board .card .ctags{margin-bottom:var(--sp-1)}
.board .card .cprog{margin:var(--sp-1) -12px -10px}
.board .col-body{gap:6px;padding:6px}
.board .col-h{padding:var(--sp-2) 12px}

/* ── 6. Узкий экран: :has уже неактуален, ряд фильтров разваливается сам ── */
@media(max-width:640px){
  .bfilters{margin:var(--sp-2) var(--sp-3) 0;gap:8px}
  .bfilters .tsearch{flex:1 1 100%}
}

/* ── План проекта: выравнивание с остальной страницей ────────────────────
   Панель была единственным блоком экрана без горизонтальных полей
   (.roadmap{margin:0 0 14px}) — растягивалась от края до края, тогда как
   соседние .analytics и .bfilters отбиты на 16px. Плюс внутри отступ
   разъехался: базовое правило задавало 12px/16px, а более позднее
   «.roadmap>summary, details.props>summary{padding:var(--sp-3)}» переписало
   его на 12px по кругу — шапка встала на 12px, тело осталось на 16px.  */
.roadmap{margin:var(--sp-2) var(--sp-6) 0}
.roadmap>summary{padding:var(--sp-3) var(--sp-4)}

/* Треугольник — в слот постоянной ширины: иначе левый край заголовка
   зависит от того, каким шрифтом отрисовался знак «▸». Тело выравниваем
   по заголовку, а не по краю панели: содержимое принадлежит своей подписи. */
.roadmap>summary{gap:10px}
.roadmap>summary::before{width:12px;flex:none;text-align:center}
.rm-body{padding-left:calc(var(--sp-4) + 22px)}

/* Пустое состояние занимало ~126px под две строчки текста и кнопку. */
.roadmap:not(:has(.ms)) .rm-line{padding:0}
.roadmap:not(:has(.ms)) .rm-empty{padding:var(--sp-2) 0 0}
.roadmap:not(:has(.ms)) .rm-add{margin-top:var(--sp-2)}

/* ═══════════════════════════════════════════════════════════════════════
   КАРТОЧКА ЗАДАЧИ · ЕДИНАЯ ШКАЛА ЭЛЕМЕНТОВ
   Замер на десктопе показал четыре разные высоты у элементов одного ряда
   при одинаковом padding: чип 33, кнопка 35, поле метки 39, поле «свой
   этап» и число 41, поле даты 43. Каждый считал высоту сам от своих
   отступов, а нативный input[type=date] добавлял сверху ещё пару пикселей.
   Правила min-height:44px в файле есть, но они в мобильной ветке — на
   десктопе не работали.
   Ниже одна шкала: поля и кнопки 40px, чипы 34px. Высота задаётся явно,
   а не выводится из padding, — тогда её не сдвинет ни шрифт, ни нативный
   контрол.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── 1. Поля ввода: одна высота на все типы ── */
/* Дата и «свой этап» исключены намеренно: у них свои правила ниже. Без этого
   общее правило оказывалось специфичнее частного — дата возвращала высоту 42px,
   а полю этапа не давала места под стрелку, и та ложилась поверх текста. */
.modal .field input:not([type=range]):not([type=checkbox]):not([type=date]):not(.stginput),
.modal .field select,
.modal .stginput,
.modal .tagin{
  min-height:40px; height:auto;
  padding:0 12px;
  border-radius:10px;
  font-size:14px;
  line-height:38px;      /* 40 минус две рамки — текст встаёт по центру без flex */
}
/* Многострочные поля высоту не фиксируем — им нужен рост. */
.modal .field textarea{padding:11px 12px;border-radius:10px;font-size:14px;line-height:1.5}
/* Нативный календарь считает высоту сам и не слушает line-height: при 40px
   он всё равно вырастал до 42. Поэтому высота задаётся жёстко, а не min-height. */
.modal .field input[type=date]{
  height:40px;min-height:0;line-height:normal;padding:0 12px;
  -webkit-appearance:none;appearance:none}

/* Поле меток — контейнер с чипами, у него своя механика. Внутренний ввод
   НЕ должен получать общую высоту поля: с ней контейнер раздувался до 50px.
   Специфичность выше общего правила намеренно — иначе оно перебивает. */
.modal .field .tagin{display:flex;align-items:center;flex-wrap:wrap;gap:6px;
  min-height:40px;padding:0 8px;line-height:normal}
.modal .field .tagin input.tgi{
  min-height:0;height:30px;line-height:30px;padding:0;font-size:14px;flex:1 1 110px}

/* ── 2. Кнопки в модалке — та же высота, что у полей ── */
/* :not(.iconbtn) обязателен. У кнопки закрытия текстовый «✕» намеренно скрыт
   через font-size:0, а сам крестик рисуется вектором в ::before. Правило без
   исключения оказывалось специфичнее и возвращало кегль — текстовый крестик
   проявлялся ПОВЕРХ векторного, и в углу окна их становилось два. */
.modal .mact .btn:not(.iconbtn),
.modal .props-body .btn:not(.iconbtn),
.modal>div>.btn:not(.iconbtn),
.modal .btn[data-save],.modal .btn[data-del]{
  min-height:40px;padding:0 16px;border-radius:10px;font-size:14px;font-weight:600
}

/* ── 3. Чипы: одна высота и один радиус на тип, статус, приоритет и этап ── */
.modal .seg button,
.modal .schip{
  min-height:34px;height:34px;padding:0 12px;
  border-radius:9px;font-size:13px;font-weight:600;
  display:inline-flex;align-items:center;justify-content:center;white-space:nowrap
}
.modal .seg{display:flex;flex-wrap:wrap;gap:6px}
/* Чипы больше не тянутся во всю ширину: flex:1 растягивал «Баг» до размера
   «Автоматизация маркетплейсов» и ряды выглядели случайными. */
.modal .seg button{flex:0 0 auto}
.modal .stagerow{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.modal .stginput{flex:0 0 148px;line-height:38px}

/* ── 4. Вертикальный ритм: одинаковый шаг между полями ── */
.modal .props-body>.field,
.modal .props-body>.row{margin-bottom:var(--sp-4)}
.modal .props-body>.field:last-child,
.modal .props-body>.row:last-child{margin-bottom:0}
/* Только подпись поля. label.switch — это сам переключатель, ему нужен
   inline-flex: с display:block ползунок наезжал на текст «Заблокировано». */
.modal .field>label:not(.switch){margin-bottom:var(--sp-2);display:block}
.modal .row{display:flex;gap:var(--sp-4)}
.modal .row>.field{flex:1 1 0;min-width:0;margin-bottom:0}

/* ── 5. Кнопки сохранения: отделены от поля описания, а не приклеены ── */
.modal .field+div[style*="display:flex"]{margin-top:var(--sp-4)!important;
  margin-bottom:var(--sp-5)!important;gap:var(--sp-2)!important}

/* ── 6. Ползунок готовности выравнивается по той же высоте ── */
.modal .rngrow{min-height:40px;gap:var(--sp-3)}
.modal .rngv{min-width:46px;text-align:right}

/* ── 7. Переключатель «Заблокировано» — та же высота, что у полей ── */
.modal .blkfield .switch{min-height:40px}

@media(max-width:640px){
  /* На телефоне палец требует 44px — там своя шкала, она уже была. */
  .modal .seg button,.modal .schip{height:auto;min-height:44px}
  .modal .row{flex-direction:column;gap:var(--sp-4)}
}

/* ── 8. Размер карточки задачи ──────────────────────────────────────────
   Базовая модалка рассчитана на короткие диалоги: 560px, у «широкой» 640px.
   Карточке задачи этого мало — в ней описание, смета, девять чипов статуса,
   шесть этапов, обсуждение и вложения. При 640px чипы жались в четыре ряда,
   а описание превращалось в узкую колонку.
   920px — ширина, при которой девять чипов статуса встают в две ровные
   строки, а строка описания держит комфортные 90–100 знаков. Шире делать
   нельзя: текст перестанет читаться, глазу тяжело возвращаться к началу.  */
.modal.task-modal{
  max-width:1200px;
  padding:30px 36px;
  border-radius:16px;
}
/* Ширина выросла ради свойств: девять чипов статуса теперь встают в одну
   строку, а ряды «Приоритет + Готовность» и «Срок + Оценка» перестали
   сжиматься. Но текст за ней не тянем: строка длиннее ~100 знаков читается
   тяжело — глазу трудно возвращаться к началу. Поэтому описание,
   комментарии и обсуждение держим в комфортной мере, а всю ширину
   отдаём управляющим элементам. */
/* Ограничения ширины были РАЗНЫЕ: описание 960, обсуждение 880, поля рядом —
   на всю колонку. В итоге правый край гулял тремя ступеньками, и окно
   выглядело неаккуратно. Все поверхности выравниваем по одной колонке;
   за читаемость длинной строки отвечает ширина самого окна, а не отдельные
   ограничения. Пузыри комментариев и так растут по содержимому. */
/* Липкая полоса действий внизу повторяет новые поля модалки, иначе
   она обрезается по краям. */
.modal.task-modal>.mact:last-child{margin-left:-36px;margin-right:-36px;
  padding-left:36px;padding-right:36px}

/* Заголовок задачи крупнее: это главный объект окна. */
.modal.task-modal .tasktitle{font-size:22px;line-height:1.3}
.modal.task-modal .mhead{gap:12px;margin-bottom:var(--sp-5)}

/* Описание — основное поле ввода, ему нужна высота, а не одна строка. */
.modal.task-modal .field textarea#rd,
.modal.task-modal .field textarea#td{min-height:120px}

/* Поле меток считало рамку сверх заданной высоты и выбивалось на 2px
   из общего ряда. Фиксируем высоту явно, как у поля даты. */
.modal .field .tagin{height:40px;box-sizing:border-box}

@media(max-width:1260px){
  .modal.task-modal{max-width:none;padding:20px 18px}
  .modal.task-modal .field textarea,
  .modal.task-modal .cmts,.modal.task-modal .cmt-form{max-width:none}
  .modal.task-modal>.mact:last-child{margin-left:-18px;margin-right:-18px;
    padding-left:18px;padding-right:18px}
  .modal.task-modal .tasktitle{font-size:19px}
}

/* ── 9. Карточка задачи: остальные несоответствия ────────────────────────
   Разбор по скриншотам владельца. Каждое — отдельная причина.               */

/* 9.1 Нативный <select> ничем не скрывался. В app.js есть комментарий
   «прячем сам select», но правила к нему не было: под кастомной кнопкой
   .csel-btn просвечивала родная стрелка — в поле «этап» их выходило две.
   Прячем визуально, но оставляем в разметке: весь код читает .value у него. */
.csel>select{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  opacity:0;pointer-events:none;overflow:hidden;clip-path:inset(50%);
}
/* И общая шкала полей его больше не касается — он невидим, размер не нужен. */
.modal .field .csel>select{min-height:0;height:auto;line-height:normal}
/* Кастомная кнопка селекта встаёт в ту же шкалу, что поля. */
.modal .csel-btn{min-height:40px;height:40px;padding:0 12px;border-radius:10px;font-size:14px}

/* 9.2 «Добавить» в подзадачах — призрачная кнопка без фона и рамки читалась
   как обычный текст рядом с полем. В этом ряду она единственное действие,
   поэтому получает видимые границы и высоту поля. */
.sub-add{gap:var(--sp-2);align-items:stretch}
.sub-add input{min-height:40px;height:40px;padding:0 12px;border-radius:10px;font-size:14px}
.sub-add .btn{min-height:40px;height:40px;padding:0 18px;border-radius:10px;
  border-color:var(--line2);background:var(--card);color:var(--tx);flex:none}
.sub-add .btn:hover{border-color:var(--acc);color:var(--acc-d)}

/* 9.3 Ряд «Файл / ссылка»: кнопка и поле стояли на разной высоте и
   прижимались друг к другу. Одна шкала и общий зазор. */
.cmt-tools{gap:var(--sp-2);align-items:stretch}
.cmt-tools .cmt-attach{min-height:40px;height:40px;padding:0 14px;border-radius:10px;flex:none}
.cmt-tools .cmt-url{min-height:40px;height:40px;padding:0 12px;border-radius:10px;font-size:14px}

/* 9.4 Поле комментария и кнопка отправки — та же шкала, кнопка квадратная. */
.modal .cmt-form{gap:var(--sp-2);align-items:flex-end}
.modal .cmt-form textarea{min-height:40px;padding:9px 12px;border-radius:10px;font-size:14px}
.modal .cmt-form [data-cmt]{width:40px;height:40px;min-height:40px;border-radius:10px;flex:none}

/* 9.5 Равномерные отступы между разделами окна. Было вразнобой:
   обсуждение 18px сверху, документы 2px, подзадачи 18px с отбивкой 16px.
   Один шаг 24px и один волосок-разделитель. */
.modal.task-modal .cmts-head,
.modal.task-modal .docs-sec,
.modal.task-modal .subs-sec{
  margin:var(--sp-6) 0 0;padding-top:var(--sp-5);
  border-top:1px solid var(--d-hair);
}
.modal.task-modal .cmts-head{padding-bottom:var(--sp-2);border-bottom:none}
.modal.task-modal .docs-head,
.modal.task-modal .subs-head{margin-bottom:var(--sp-3)}
.modal.task-modal .cmts{margin-top:0}
.modal.task-modal .cmt-form{margin-top:var(--sp-4)}
/* Первый раздел после свойств не удваивает линию: она уже есть у блока. */
.modal.task-modal details.props+.cmts-head{margin-top:var(--sp-5)}

@media(max-width:640px){
  .sub-add{flex-wrap:wrap}
  .sub-add .btn,.cmt-tools .cmt-attach,.cmt-tools .cmt-url,
  .sub-add input,.modal .cmt-form [data-cmt]{min-height:44px;height:44px}
}

/* ── 10. Исполнитель задачи ───────────────────────────────────────────────
   Имя выбирается из состава раздела «Команда». На карточке показываем
   сокращённо: «Roboweb AI · Бэкенд» занял бы всю мета-строку, а полное имя
   остаётся в подсказке при наведении. */
.card .meta .asg{
  display:inline-flex;align-items:center;gap:5px;
  padding:0 7px;line-height:16px;border-radius:5px;
  background:var(--bd-chip);color:var(--tx-mut);
  font-variant-numeric:normal;max-width:120px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.card .meta .asg::before{
  content:'';width:5px;height:5px;border-radius:50%;flex:none;
  background:currentColor;opacity:.65;
}

/* Поле «свой этап» в общей шкале модалки; справа — место под стрелку. */
.modal .stginput{height:40px;min-height:40px;border-radius:10px;padding:0 32px 0 12px}

/* ── 12. Форма создания задачи ───────────────────────────────────────────
   Она открывалась классом wide (640px) и повторяла ошибку карточки:
   «Тип» делил ряд с приоритетом и рвался на три неровные строки.
   Теперь у неё тот же класс task-modal — та же ширина и та же шкала.
   Кнопки «Добавить/Отмена» лежат в липкой полосе .mact внизу. */
.modal.task-modal .mact{gap:var(--sp-2)}
.modal.task-modal .mact .btn{min-height:40px;padding:0 20px;border-radius:10px}

/* ── 13. Единый вертикальный ритм в модалках ─────────────────────────────
   Шаг между полями был двух видов: 16px внутри «Свойств задачи»
   (.props-body) и 14px во всех остальных окнах, включая создание задачи.
   Рядом это читалось как «поля стоят по-разному». Ведём всё к --sp-4. */
.modal .field{margin-bottom:var(--sp-4)}
/* поля внутри ряда шага не имеют — его задаёт сам ряд */
.modal .row>.field{margin-bottom:0}

/* Тянуть текстовое поле вбок нельзя: мышью его растягивали шире окна,
   и появлялась горизонтальная прокрутка. Вертикально — сколько угодно. */
.modal .field textarea{resize:vertical}

/* Подпись переключателя набирается как обычный текст. Правило подписи поля
   (11px, uppercase) распространялось и на label.switch, а кегль у него свой —
   14px. Получалась строка КАПСОМ в полтора раза крупнее всех подписей рядом,
   и она читалась как заголовок, а не как подпись к тумблеру. */
.modal .field>label.switch,
.modal label.switch .swl{text-transform:none;letter-spacing:normal}

/* Скрытый чекбокс тумблера растягивался на всю ширину поля: в app.css
   правило `.field input{width:100%}` идёт ПОСЛЕ `.switch input{width:0}`
   при равной специфичности и побеждает. Абсолютный блок 349×44 вылезал
   за правый край окна — на телефоне карточка задачи получала лишнюю
   горизонтальную прокрутку. Держим его крошечным, но фокусируемым:
   на `input:focus-visible + .sw` завязано кольцо фокуса тумблера. */
.switch input{width:1px!important;max-width:1px;height:1px;min-height:0;padding:0;margin:0}

/* На узком экране тумблер переносился ПОД свою подпись: пилюля отдельной
   строкой, текст под ней. Виновато `.field label{flex-wrap:wrap;
   align-items:baseline}` — оно нужно подписям с уточнением, но по
   специфичности (0,1,1) перебивало `.switch` (0,1,0). Переносить должен
   сам текст, а тумблер остаётся слева и по центру строки. */
.field label.switch{flex-wrap:nowrap;align-items:center}
.field label.switch .sw{flex:0 0 auto}
.field label.switch .swl{flex:1 1 auto;min-width:0}

/* ── 14. Ряд полей не давал отступа следующему блоку ─────────────────────
   `.field` имеет margin-bottom, а поля ВНУТРИ ряда его сбрасывают — шаг
   должен задавать сам ряд. У `.row` его не было ни в одном файле, поэтому
   «Описание» вплотную прилипало к ряду «Оценка + Метки». */
.modal .row{margin-bottom:var(--sp-4)}
.modal .row:last-child,
.modal .props-body>.row:last-child{margin-bottom:0}

/* ── 15. Поле «свой этап»: свой список вместо родного ────────────────────
   Стрелку раньше рисовал ::-webkit-calendar-picker-indicator — псевдоэлемент
   поля с datalist. Списка больше нет, значит и стрелку рисуем сами.
   ⚠️ Фоном поля её ставить нельзя: общая «шкура» `.field input` задаёт фон
   с большей специфичностью, position и repeat терялись — шеврон замащивался
   по всей строке поверх подписи. Поэтому отдельным элементом, как .csel-chev
   у стилизованного select. */
.stgwrap{position:relative;display:inline-flex;align-items:center}
.stgchev{
  position:absolute;right:10px;top:50%;margin-top:-7.5px;
  width:15px;height:15px;pointer-events:none;
  background:var(--fi-ic-chev) no-repeat center/15px 15px;
  transition:transform .15s ease;
}
.stgwrap:hover .stgchev,
.stgwrap:focus-within .stgchev{background-image:var(--fi-ic-chev-on)}
.stginput[aria-expanded="true"] ~ .stgchev{transform:rotate(180deg)}
/* Панель подсказок повторяет список стилизованного select; ширину и
   положение ей выдаёт placeDropdown, здесь только вид. */
.csel-list.stglist{min-width:148px}
.csel-none{
  padding:9px 11px;font-size:13px;color:var(--tx-mut);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;
}

/* ── 16. Корзина проекта (вкладка «Удалено») ─────────────────────────────
   Список строкой, а не карточками: тут не работают, а решают «вернуть или
   стереть», и поле выбора должно читаться одним взглядом сверху вниз. */
.ptab-n{
  margin-left:6px;padding:0 6px;min-width:18px;height:18px;
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:9px;font-size:11px;font-weight:700;line-height:1;
  background:var(--bd-chip);color:var(--tx-mut);font-variant-numeric:tabular-nums;
}
.ptab.on .ptab-n{background:color-mix(in srgb,var(--acc) 22%,transparent);color:var(--acc-tx)}
.dellist{display:flex;flex-direction:column;gap:var(--sp-2)}
.delrow{
  display:flex;align-items:center;gap:var(--sp-4);
  padding:var(--sp-3) var(--sp-4);border:1px solid var(--line);border-radius:12px;
  background:var(--card2);
}
.delmain{flex:1 1 auto;min-width:0}
.delttl{font-weight:600;color:var(--tx);margin-bottom:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.delmeta{font-size:12.5px;color:var(--tx-dim);font-variant-numeric:tabular-nums}
.delact{flex:0 0 auto;display:flex;gap:var(--sp-2)}
.delnote{margin-top:var(--sp-4);font-size:12.5px;color:var(--tx-dim);line-height:1.55}
@media(max-width:640px){
  .delrow{flex-direction:column;align-items:stretch;gap:var(--sp-3)}
  .delttl{white-space:normal}
  .delact .btn{flex:1 1 auto;justify-content:center}
}

/* Рядом стоят «Восстановить» и «Удалить навсегда», и в базе .btn-danger
   в покое нейтральна — краснеет только на наведении. Для карточки задачи это
   уместно (кнопка там одна), а в списке две одинаковые кнопки, из которых одна
   возвращает, а другая стирает, — так ошибаются. Отличаем сразу. */
.delact .btn-danger{
  color:var(--d-danger);
  border-color:color-mix(in srgb, var(--danger) 42%, var(--line));
}
.delact .btn-danger:hover{
  color:var(--d-danger);
  border-color:var(--danger);
  background:color-mix(in srgb, var(--danger) 12%, transparent);
}

/* ── 17. Список выбранных документов ─────────────────────────────────────
   Файлов теперь можно выбрать несколько, поэтому имя выбранного переехало
   из строки с кнопкой в отдельный список под ней: рядом с кнопкой два-три
   имени сминали её в узкий столбик. */
.docpick-list{display:flex;flex-wrap:wrap;gap:var(--sp-2);margin-top:var(--sp-2)}
.docpick-list:empty{margin-top:0}
.docpick-list .docpick-name{
  max-width:100%;padding:5px 9px;border-radius:8px;
  background:var(--bd-chip);border:1px solid var(--line);
}
.docpick-list .cf-x{
  flex:none;margin-left:2px;width:18px;height:18px;line-height:1;
  display:inline-flex;align-items:center;justify-content:center;
  border:0;border-radius:5px;background:none;color:var(--tx-dim);cursor:pointer;
}
.docpick-list .cf-x:hover{background:var(--ct-wash);color:var(--tx)}
/* ── 18. Кто поставил задачу ─────────────────────────────────────────────
   На карточке два человека: автор и исполнитель. Различаем их не подписью
   (места нет), а знаком перед именем: у автора «+» — задачу завели,
   у исполнителя точка. Полные имена — в подсказке. */
.card .meta .aut{
  display:inline-flex;align-items:center;gap:4px;padding:0 7px;
  line-height:16px;border-radius:5px;background:var(--bd-chip);color:var(--tx-mut);
  max-width:124px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.card .meta .aut::before{
  content:'+';flex:none;font-weight:700;font-size:11px;line-height:1;
  color:var(--tx-dim);
}

/* ── 19. Аналитика: легенда полосы и «нет данных» в плитке ───────────────
   Полоса готовности стояла четырьмя цветами без подписей — на доске под
   такой же полосой легенда есть, здесь её не было. */
.an-leg{
  display:flex;flex-wrap:wrap;gap:var(--sp-2) var(--sp-4);
  margin-top:var(--sp-3);font-size:12.5px;color:var(--tx-dim);
}
.an-lg{display:inline-flex;align-items:center;gap:6px;white-space:nowrap}
.an-lg i{width:8px;height:8px;border-radius:3px;flex:none}
.an-lg b{color:var(--tx-mut);font-weight:650;font-variant-numeric:tabular-nums}
/* Пустая плитка показывала прочерк тем же кеглем 28px и весом 800, что и
   число, — это читалось как сбой отрисовки, а не как «данных нет». */
.kpic b .kpi-none, .kpi-none{
  font-size:15px;font-weight:600;color:var(--tx-dim);letter-spacing:normal;
  -webkit-text-fill-color:var(--tx-dim);background:none;
}

/* ── 20. «Ждёт вас» — экран проектов клиента ─────────────────────────────
   Сводка ниже отвечает на «как идут дела», а этот блок — на «мне надо
   что-то сделать?». Поэтому он первый и читается строками, а не плитками:
   строка = число + что именно + в каком проекте. */
.todo{
  margin-bottom:var(--sp-5);padding:var(--sp-4) var(--sp-5);
  border:1px solid color-mix(in srgb, var(--acc) 34%, var(--line));
  border-radius:14px;background:var(--panel);
  box-shadow:var(--dp-e1);
}
.todo-h{display:flex;align-items:center;gap:var(--sp-2);margin-bottom:var(--sp-3)}
.todo-h b{font-size:15px;font-weight:700;color:var(--tx)}
.todo-ic{display:inline-flex;width:22px;height:22px;align-items:center;justify-content:center;color:var(--acc-tx)}
.todo-ic svg{width:17px;height:17px}
.todo-n{
  margin-left:auto;min-width:24px;height:22px;padding:0 8px;
  display:inline-flex;align-items:center;justify-content:center;
  border-radius:11px;background:var(--acc);color:var(--on-acc);
  font-size:12px;font-weight:700;font-variant-numeric:tabular-nums;
}
.todo-list{display:flex;flex-direction:column;gap:var(--sp-1)}
.todo-row{
  display:flex;align-items:center;gap:var(--sp-3);width:100%;
  padding:var(--sp-2) var(--sp-3);border:0;border-radius:10px;
  background:none;color:var(--tx);cursor:pointer;text-align:left;
  transition:background var(--mo-1x, .15s) ease;
}
.todo-row:hover{background:var(--card2)}
.todo-cnt{
  flex:none;min-width:26px;height:24px;padding:0 7px;
  display:inline-flex;align-items:center;justify-content:center;border-radius:8px;
  background:color-mix(in srgb, var(--acc) 20%, transparent);color:var(--acc-tx);
  font-size:13px;font-weight:700;font-variant-numeric:tabular-nums;
}
.todo-t{flex:0 1 auto;font-size:14px}
.todo-p{
  flex:1 1 auto;min-width:0;text-align:right;font-size:12.5px;color:var(--tx-dim);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.todo-go{flex:none;display:inline-flex;color:var(--tx-dim)}
.todo-go svg{width:15px;height:15px}
.todo-row:hover .todo-go{color:var(--acc-tx)}
/* Пусто — это тоже ответ, и его надо дать словами, а не пустым местом. */
.todo-clear{display:flex;align-items:center;gap:var(--sp-3);border-color:var(--line)}
.todo-clear .todo-ic.ok{color:var(--ok)}
.todo-clear b{display:block;font-size:14px;color:var(--tx);margin-bottom:2px}
.todo-clear span{font-size:13px;color:var(--tx-dim)}
@media(max-width:640px){
  .todo{padding:var(--sp-3) var(--sp-4)}
  .todo-row{flex-wrap:wrap;gap:var(--sp-2)}
  .todo-p{flex:1 0 100%;text-align:left;padding-left:33px}
}

/* ── 21. Окно приёмки ────────────────────────────────────────────────────
   Возврат теперь спрашивает причину: без неё команда видит только «круг
   повторился». Быстрые причины — чипы, они дописывают текст в поле,
   а не заменяют его: обычно к готовой формулировке добавляют деталь. */
.acc-reasons{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:var(--sp-2)}
.acc-reasons button{
  min-height:32px;padding:0 12px;border-radius:9px;
  font-size:13px;font-weight:600;white-space:nowrap;
}
.modal .acc-reasons+textarea{min-height:96px}


/* Плашка типа задачи: слева кружок-цвет, поэтому нужен отступ под него.
   Отступ уже задавался выше, но ниже по файлу идёт `.rochips .chip{padding:5px 11px}`
   — та же специфичность, значит побеждает последнее правило, и сокращённый
   `padding` обнуляет padding-left. Кружок наезжал на первую букву: «●адача».
   Держим отступ после всех правил на .rochips .chip. */
.rochips .typechip{ padding-left:20px; }


/* ───────────────────────────────────────────────────────────────────────────
   «ЧТО НОВОГО» · лента событий, точки непрочитанного
   Точка — единственная «горячая» метка на карточке, поэтому она акцентная,
   а не тревожная: красный на доске уже занят просрочкой и блокировкой.
   ─────────────────────────────────────────────────────────────────────────── */
.nhead{display:flex;align-items:center;gap:9px}
.nsub{color:var(--tx-mut);font-size:13px;margin:2px 0 14px}
.nlist{max-height:min(58vh,520px);overflow:auto;margin:0 -4px;padding:0 4px}
.ngrp+.ngrp{margin-top:14px}
.ngrp-h{display:flex;align-items:center;gap:8px;font-size:12px;font-weight:700;letter-spacing:.02em;
  text-transform:uppercase;color:var(--tx-mut);padding:0 2px 7px}
.ngrp-n{font-family:var(--mono);font-size:11px;font-weight:700;color:var(--tx-mut);
  background:var(--ct-wash);border-radius:999px;padding:1px 7px}
.nrow{display:grid;grid-template-columns:30px 1fr auto;align-items:center;gap:11px;width:100%;
  text-align:left;padding:10px 11px;border:1px solid transparent;border-radius:11px;
  background:none;color:inherit;cursor:pointer;transition:background .14s ease,border-color .14s ease}
.nrow+.nrow{margin-top:2px}
.nrow:hover{background:var(--ct-wash);border-color:color-mix(in srgb,var(--acc) 24%,transparent)}
.nr-ic{display:grid;place-items:center;width:30px;height:30px;border-radius:9px;
  background:color-mix(in srgb,var(--acc) 12%,transparent);color:var(--acc)}
.nr-ic svg{width:16px;height:16px}
.nr-ic.k-review{background:color-mix(in srgb,var(--warn,#E0A33E) 16%,transparent);color:var(--warn,#E0A33E)}
.nr-ic.k-done{background:color-mix(in srgb,var(--ok,#3E9E6A) 15%,transparent);color:var(--ok,#3E9E6A)}
.nr-b{min-width:0;display:flex;flex-direction:column;gap:2px}
.nr-t{font-weight:650;font-size:14px;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nr-s{font-size:12px;color:var(--tx-mut);line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nr-d{font-family:var(--mono);font-size:11px;color:var(--tx-dim);white-space:nowrap}
.nfoot{display:flex;gap:8px;justify-content:flex-end;margin-top:16px}

/* точка на проекте в боковом меню и на карточке задачи */
.pdot.new{width:6px;height:6px;border-radius:50%;background:var(--acc);display:inline-block;
  box-shadow:0 0 7px -1px var(--acc)}
.card .newdot{position:absolute;top:9px;left:9px;width:7px;height:7px;border-radius:50%;
  background:var(--acc);box-shadow:0 0 8px -1px var(--acc)}
.card.isnew{border-color:color-mix(in srgb,var(--acc) 34%,var(--line))}
.card.isnew .chead{padding-left:12px}
@media(max-width:760px){
  .nrow{grid-template-columns:28px 1fr;row-gap:2px}
  .nr-d{grid-column:2;justify-self:start}
}


/* ───────────────────────────────────────────────────────────────────────────
   ПОИСК ПО КАБИНЕТУ · ⌘K
   Палитра, а не модалка: прижата к верху, чтобы список не прыгал под курсором,
   и держит фокус на поле — печатать можно сразу.
   ─────────────────────────────────────────────────────────────────────────── */
.gsov{align-items:flex-start;padding-top:min(12vh,110px)}
.gsbox{width:min(680px,calc(100vw - 32px));background:var(--card);border:1px solid var(--line);
  border-radius:14px;box-shadow:0 24px 60px -20px rgba(0,0,0,.55);overflow:hidden}
.gsin{display:flex;align-items:center;gap:10px;padding:13px 15px;border-bottom:1px solid var(--line)}
.gsin svg{width:18px;height:18px;color:var(--tx-dim);flex:none}
.gsin input{flex:1;min-width:0;background:none;border:none;outline:none;color:var(--tx);
  font-size:16px;font-family:inherit}
.gsin input::placeholder{color:var(--tx-dim)}
.gskbd{font-family:var(--mono);font-size:11px;color:var(--tx-dim);border:1px solid var(--line);
  border-radius:6px;padding:2px 6px;flex:none}
.gsres{max-height:min(56vh,460px);overflow:auto;padding:8px}
.gshint{color:var(--tx-mut);font-size:13px;padding:22px 12px;text-align:center}
.gshint.sm{padding:10px 12px 4px;font-size:12px}
.gsgrp+.gsgrp{margin-top:10px}
.gsgrp-h{font-size:11px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--tx-dim);padding:4px 8px 6px}
.gsrow{display:grid;grid-template-columns:26px 1fr;align-items:center;gap:10px;width:100%;
  text-align:left;padding:8px 9px;border:1px solid transparent;border-radius:10px;
  background:none;color:inherit;cursor:pointer}
.gsrow.on{background:var(--ct-wash);border-color:color-mix(in srgb,var(--acc) 30%,transparent)}
.gsr-ic{display:grid;place-items:center;width:26px;height:26px;border-radius:8px;
  background:color-mix(in srgb,var(--acc) 10%,transparent);color:var(--acc)}
.gsr-ic svg{width:15px;height:15px}
.gsr-b{min-width:0;display:flex;flex-direction:column;gap:1px}
.gsr-t{font-weight:650;font-size:14px;line-height:1.25;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gsr-s{font-size:12px;color:var(--tx-mut);line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.gsm{color:var(--acc);font-weight:800}
.onlyphone{display:none}
.gsfoot{border-top:1px solid var(--line);padding:8px 14px;font-size:11.5px;color:var(--tx-dim);font-family:var(--mono)}
@media(max-width:760px){
  .gsov{padding-top:8vh}
  .gsin input{font-size:16px}      /* мельче — iOS зумит страницу при фокусе */
  .gsres{max-height:64vh}
}


/* ───────────────────────────────────────────────────────────────────────────
   ПРИЁМКА ПАКЕТОМ · кнопка над колонкой «На проверке» и список работ в окне
   ─────────────────────────────────────────────────────────────────────────── */
.col-bulk{display:block;width:100%;margin:0 0 8px;padding:9px 12px;border-radius:10px;
  border:1px solid color-mix(in srgb,var(--ok) 40%,transparent);
  background:color-mix(in srgb,var(--ok) 12%,transparent);color:var(--ok);
  font:inherit;font-weight:700;font-size:13px;cursor:pointer;
  transition:background .14s ease,border-color .14s ease}
.col-bulk:hover{background:color-mix(in srgb,var(--ok) 20%,transparent);
  border-color:color-mix(in srgb,var(--ok) 60%,transparent)}
.col-bulk:active{transform:translateY(1px)}
.acl{max-height:min(46vh,360px);overflow:auto;border:1px solid var(--line);border-radius:11px;padding:5px}
.acl-i{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:10px;
  padding:9px 10px;border-radius:9px;cursor:pointer}
.acl-i:hover{background:var(--ct-wash)}
.acl-i input{width:17px;height:17px;accent-color:var(--ok);cursor:pointer}
.acl-t{font-size:14px;line-height:1.3;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acl-n{font-family:var(--mono);font-size:11px;color:var(--tx-dim)}


/* ───────────────────────────────────────────────────────────────────────────
   ОТЧЁТ ЗА ПЕРИОД · экран и печать
   Пришёл на смену окну с тем же названием: окно умело один проект и жило на
   доске. Лист живёт двумя жизнями — на экране в теме пользователя, на бумаге
   всегда чёрным по белому, поэтому правила печати тут же.
   ─────────────────────────────────────────────────────────────────────────── */
.rep-bar{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 16px}
.rep-f{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--tx-mut)}
.rep-f input,.rep-f select{background:var(--card2,var(--card));color:var(--tx);border:1px solid var(--line);
  border-radius:9px;padding:6px 9px;font:inherit;font-size:13px}
.rep-bar .sp{flex:1}
.rep{background:var(--card);border:1px solid var(--line);border-radius:14px;padding:26px 28px}
.rep-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;
  border-bottom:2px solid var(--line);padding-bottom:14px;margin-bottom:18px}
.rep-t{margin:0;font-size:21px;font-weight:800}
.rep-sub{color:var(--tx-mut);font-size:13px;margin-top:3px}
.rep-org{text-align:right;font-weight:800;font-size:14px}
.rep-org span{display:block;font-weight:500;font-size:12px;color:var(--tx-mut)}
.rep-kpis{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:10px;margin-bottom:22px}  /* auto-fill, а не auto-fit: одинокая пятая плитка не растягивается на всю ширину */
.rep-kpi{border:1px solid var(--line);border-radius:11px;padding:12px 14px}
.rep-kv{display:block;font-size:22px;font-weight:800;line-height:1.1}
.rep-kl{display:block;font-size:12px;color:var(--tx-mut);margin-top:2px}
.rep-kn{display:block;font-size:11px;color:var(--tx-dim);margin-top:2px}
.rep-h{font-size:13px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;
  color:var(--tx-mut);margin:22px 0 8px}
.rep-grp+.rep-grp{margin-top:14px}
.rep-grp-h{font-size:13px;font-weight:700;margin:10px 0 4px}
.rep-tbl{width:100%;border-collapse:collapse;font-size:13.5px}
.rep-tbl td{padding:7px 8px;border-bottom:1px solid var(--line);vertical-align:top}
.rep-tbl tr:last-child td{border-bottom:none}
.rep-d{width:96px;color:var(--tx-mut);font-family:var(--mono);font-size:12px;white-space:nowrap}
.rep-ty{width:190px;color:var(--tx-mut);text-align:right;white-space:nowrap}
.rep-empty{color:var(--tx-mut);font-size:13px;padding:10px 2px}
.rep-note{margin:14px 0 0;padding:10px 12px;border:1px dashed var(--line);border-radius:10px;font-size:13px;color:var(--tx-mut)}
.rep-foot{margin-top:24px;padding-top:12px;border-top:1px solid var(--line);
  font-size:11.5px;color:var(--tx-dim)}
@media(max-width:760px){
  .rep{padding:18px 15px}
  .rep-ty{display:none}
  .rep-head{flex-direction:column;gap:8px}
  .rep-org{text-align:left}
}
/* печать: на листе только сам отчёт, чёрным по белому */
@media print{
  body{background:#fff}
  /* ширина листа A4 за вычетом полей меньше 760px, поэтому сюда попадали
     мобильные правила: третья колонка (суммы счетов, проекты) исчезала
     с бумаги, а шапка расползалась в столбик. Возвращаем как на экране. */
  .rep-ty{display:table-cell;width:190px}
  .rep-head{flex-direction:row}
  .rep-org{text-align:right}
  .rep{padding:0}
  .side,.topbar,.scrim,.app-foot,.noprint,.ov{display:none !important}
  .shell,.main{display:block;height:auto;overflow:visible}
  .rep{border:none;border-radius:0;padding:0;background:#fff;color:#111}
  .rep-t,.rep-org,.rep-kv{color:#111}
  .rep-sub,.rep-kl,.rep-kn,.rep-h,.rep-d,.rep-ty,.rep-foot{color:#555}
  .rep-head{border-bottom-color:#111}
  .rep-kpi,.rep-tbl td{border-color:#ccc}
  .rep-grp,.rep-tbl tr{break-inside:avoid}
  @page{margin:14mm}
}


/* ───────────────────────────────────────────────────────────────────────────
   ТЕЛЕФОН · доска лентой секций
   Канбан на 390px не работает: шесть колонок по 320px — это три экрана вбок
   до «На проверке». Здесь колонка становится секцией во всю ширину, свёрнутая —
   строкой-заголовком со счётчиком. Порядок колонок и вся логика те же.
   ─────────────────────────────────────────────────────────────────────────── */
@media(max-width:760px){
  /* overflow-x:visible при overflow-y:hidden браузер сам приводит к auto —
     поэтому снимаем прокрутку по обеим осям. Ширину держало правило
     min-width: 4 × 86vw и width:max-content, их тоже гасим. */
  .board-wrap{overflow-x:visible;overflow-y:visible;scroll-snap-type:none;padding:12px 12px 8px}
  .board{display:block;width:auto;min-width:0;grid-template-columns:none}
  .col{width:auto;max-width:none;min-width:0;flex:none;margin:0 0 10px;max-height:none;scroll-snap-align:none}
  .col-body{max-height:none;overflow:visible}
  .col-h{border-radius:13px 13px 0 0}

  /* свёрнутая колонка: обычная строка, а не вертикальная надпись */
  .col-collapsed{flex:none;width:auto;min-height:0;max-height:none;border-radius:13px}
  .col-exp{flex-direction:row;align-items:center;justify-content:flex-start;gap:10px;
    height:auto;min-height:52px;padding:0 14px;width:100%}
  .col-exp .col-vt{writing-mode:horizontal-tb;transform:none;flex:1;text-align:left;
    font-size:15px;color:var(--tx);display:block;line-height:52px}
  .col-exp .n{margin-left:auto}
  .col-exp::after{content:'';width:9px;height:9px;border-right:2px solid var(--tx-dim);
    border-bottom:2px solid var(--tx-dim);transform:rotate(45deg);margin-left:4px;flex:none}

  /* колонка «добавить» и стрелки перестановки на телефоне не нужны */
  .col-addcol{width:100%;margin:0}
  .col-mv{display:none}

  /* первый экран: до задач было ~1000px мебели — сжимаем всё лишнее */
  .board-wrap{margin-top:6px}
  .tagfilter{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;
    scrollbar-width:none;padding-bottom:2px}
  .tagfilter::-webkit-scrollbar{display:none}
  .tagfilter .tf{flex:none}
  .bfilters{gap:8px}

  /* Первый экран: до первой карточки было 664px — почти весь экран занимала
     «мебель». Кольцо прогресса уводим в строку, легенду — в один ряд с
     прокруткой, поиск делаем ниже. Ни один блок не прячем: на телефоне
     прогресс и метки нужны так же, просто занимать пол-экрана они не должны. */
  .analytics{flex-direction:row;align-items:center;gap:12px;padding:11px 12px;margin:10px 12px 0}
  .an-ringbox{width:56px;height:56px;flex:none}
  .an-ring{width:56px;height:56px}
  .an-ringtxt b{font-size:15px}
  .an-ringtxt span{font-size:9px}
  .an-head{flex-wrap:wrap;gap:2px 8px}
  .an-head>span:first-child{font-size:14px}
  .an-sum{font-size:11.5px}
  .an-cells{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;gap:10px}
  .an-cells::-webkit-scrollbar{display:none}
  .an-cell{flex:none;white-space:nowrap}
  .tsearch{min-height:42px}
  .tsearch input{font-size:16px}      /* мельче — iOS зумит страницу при фокусе */

  /* «Фото» показываем только на телефоне: на десктопе камеры обычно нет,
     а лишняя кнопка рядом с «Файл» только путает */
  .onlyphone{display:inline-flex}

  /* приёмка — главное действие клиента на телефоне, её кнопки крупнее */
  .card .qadv.qc{width:44px;height:44px}
  .col-bulk{padding:13px 12px;font-size:14px}
}


/* чек-лист приёмки: две неброские ссылки под полем добавления подзадачи */
.sub-tpl{display:flex;align-items:center;gap:14px;margin-top:8px;flex-wrap:wrap}
.sub-tpl .lnk{display:inline-flex;align-items:center;gap:6px;background:none;border:none;
  color:var(--acc);font:inherit;font-size:12.5px;font-weight:600;cursor:pointer;padding:4px 0}
.sub-tpl .lnk:hover{text-decoration:underline}
.sub-tpl .lnk.dim{color:var(--tx-mut);font-weight:500}
.sub-tpl .lnk svg{width:14px;height:14px}
.tpl-a{min-height:70px;font-size:13px;line-height:1.45}

/* запись голосового: во время записи кнопка «горит» и считает секунды */
.cmt-attach.rec{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 45%,transparent);
  background:color-mix(in srgb,var(--danger) 12%,transparent)}
.cmt-attach.rec svg{animation:vcpulse 1.1s ease-in-out infinite}
@keyframes vcpulse{0%,100%{opacity:1}50%{opacity:.35}}
@media(prefers-reduced-motion:reduce){ .cmt-attach.rec svg{animation:none} }

/* ссылки на приёмку без входа */
.shl{display:grid;grid-template-columns:1fr auto auto;gap:8px;align-items:center;margin-bottom:10px}
.shl-u{grid-column:1;background:var(--card2,var(--card));color:var(--tx-mut);border:1px solid var(--line);
  border-radius:9px;padding:8px 10px;font:inherit;font-size:12.5px}
.shl-m{grid-column:1/-1;font-size:11.5px;color:var(--tx-dim)}
@media(max-width:760px){ .shl{grid-template-columns:1fr auto} .shl-u{grid-column:1/-1} }

/* выбор дня недели для дайджеста и предпросмотр письма */
.wdp{border:1px solid var(--line);background:none;color:var(--tx-mut);font:inherit;font-size:12px;
  padding:3px 7px;border-radius:8px;cursor:pointer;margin-left:3px}
.wdp:hover{color:var(--tx);background:var(--ct-wash)}
.wdp.on{background:color-mix(in srgb,var(--acc) 18%,transparent);border-color:var(--acc);color:var(--tx)}
.cdprev+.cdprev{margin-top:12px}
.cdprev-h{display:flex;align-items:baseline;gap:10px;font-weight:700;font-size:13px;margin-bottom:5px}
.cdprev-h .ok{color:var(--ok);font-weight:500;font-size:11.5px}
.cdprev-h .dim{color:var(--tx-dim);font-weight:500;font-size:11.5px}
.cdprev-b{margin:0;padding:11px 13px;background:var(--card2,var(--card));border:1px solid var(--line);
  border-radius:10px;font-family:inherit;font-size:12.5px;line-height:1.5;white-space:pre-wrap;
  max-height:260px;overflow:auto}

/* порог напоминаний прямо в строке настройки */
.remd{width:52px;background:var(--card2,var(--card));color:var(--tx);border:1px solid var(--line);
  border-radius:8px;padding:3px 6px;font:inherit;font-size:13px;text-align:center;margin:0 2px}


/* ───────────────────────────────────────────────────────────────────────────
   СПРАВОЧНИК ПО КАБИНЕТУ · только команда
   Разделы свёрнуты: справочник читают точечно. Метка «кому» стоит в строке
   заголовка, а не в тексте, — так колонка «сам» читается одним взглядом.
   ─────────────────────────────────────────────────────────────────────────── */
.mn-s{padding:0;overflow:hidden}
.mn-s>summary{display:flex;align-items:center;gap:10px;cursor:pointer;list-style:none;
  padding:15px 18px;font-weight:700}
.mn-s>summary::-webkit-details-marker{display:none}
.mn-s>summary:hover{background:var(--ct-wash)}
.mn-t{font-size:15px;flex:1}
.mn-n{font-family:var(--mono);font-size:11px;font-weight:700;color:var(--tx-mut);
  background:var(--ct-wash);border-radius:999px;padding:2px 8px}
.mn-s>summary .qhelp-x{transition:transform .16s ease;color:var(--tx-dim)}
.mn-s[open]>summary .qhelp-x{transform:rotate(180deg)}
.mn-s[open]>summary{border-bottom:1px solid var(--line)}
.mn-b{padding:6px 18px 16px}
.mn-r{padding:13px 0;border-bottom:1px solid var(--line)}
.mn-r:last-child{border-bottom:none;padding-bottom:2px}
.mn-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}
.mn-h b{font-size:14.5px;font-weight:650}
.mn-r p{margin:5px 0 0;font-size:13.5px;line-height:1.55;color:var(--tx-mut)}
.mn-w{font-family:var(--mono);font-size:10.5px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;padding:2px 8px;border-radius:999px;white-space:nowrap;flex:none}
.mn-you{color:var(--acc);background:color-mix(in srgb,var(--acc) 13%,transparent)}
.mn-cli{color:var(--tx-mut);background:var(--ct-wash)}
.mn-all{color:var(--tx-mut);background:var(--ct-wash)}
.mn-bot{color:var(--ok);background:color-mix(in srgb,var(--ok) 15%,transparent)}
@media(max-width:760px){
  .mn-s>summary{padding:14px}
  .mn-b{padding:4px 14px 14px}
}


/* путь до кнопки в справочнике: справочник без него отвечает «что умеет»,
   но не отвечает «как до этого добраться» */
.mn-where{display:flex;align-items:baseline;gap:8px;margin-top:8px;padding:7px 10px;
  background:var(--ct-wash);border:1px solid var(--line);border-radius:9px;
  font-size:12.5px;color:var(--tx)}
.mn-where span{font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--tx-dim);flex:none}


/* ───────────────────────────────────────────────────────────────────────────
   ОБНОВЛЕНИЯ КАБИНЕТА
   Клиент узнавал о доработках случайно — однажды видел новую кнопку. Здесь
   лента по датам; непрочитанное помечено, но не кричит.
   ─────────────────────────────────────────────────────────────────────────── */
.chg{padding:16px 18px}
.chg+.chg{margin-top:10px}
.chg-h{display:flex;align-items:center;gap:9px;margin-bottom:7px}
.chg-d{font-family:var(--mono);font-size:11.5px;color:var(--tx-dim);letter-spacing:.02em}
.chg-badge{font-family:var(--mono);font-size:9.5px;font-weight:700;letter-spacing:.08em;
  text-transform:uppercase;color:var(--acc);background:color-mix(in srgb,var(--acc) 14%,transparent);
  border-radius:999px;padding:2px 8px}
.chg-t{font-size:15.5px;font-weight:700;line-height:1.3;margin-bottom:9px}
.chg-l{margin:0;padding-left:18px;display:flex;flex-direction:column;gap:6px}
.chg-l li{font-size:13.5px;line-height:1.55;color:var(--tx-mut)}
.chg-new{border-color:color-mix(in srgb,var(--acc) 32%,var(--line))}
/* точка непрочитанного у пункта меню */
.navitem .ni-dot{width:6px;height:6px;border-radius:50%;background:var(--acc);
  margin-left:auto;flex:none;box-shadow:0 0 7px -1px var(--acc)}
@media(max-width:760px){.chg{padding:14px}}


/* ───────────────────────────────────────────────────────────────────────────
   БАЗА ЗНАНИЙ ПРОЕКТА
   Список ссылок и договорённостей. Предупреждение про пароли стоит рядом с
   кнопкой добавления, а не в подвале: иначе его прочтут уже после.
   ─────────────────────────────────────────────────────────────────────────── */
.kb-add{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:12px}
.kb-warn{font-size:12.5px;color:var(--tx-mut)}
.kb-list{padding:6px 8px}
.kb-i{display:grid;grid-template-columns:34px 1fr auto auto auto;align-items:center;gap:10px;
  padding:12px 10px;border-bottom:1px solid var(--line)}
.kb-i:last-child{border-bottom:none}
.kb-i:hover{background:var(--ct-wash);border-radius:10px}
.kb-ic{display:grid;place-items:center;width:34px;height:34px;border-radius:10px;
  background:color-mix(in srgb,var(--acc) 11%,transparent);color:var(--acc)}
.kb-ic svg{width:17px;height:17px}
.kb-b{min-width:0}
.kb-t{font-size:14.5px;font-weight:650;line-height:1.3}
.kb-t a{color:inherit;text-decoration:none;border-bottom:1px solid color-mix(in srgb,var(--acc) 45%,transparent)}
.kb-t a:hover{color:var(--acc)}
.kb-u{font-family:var(--mono);font-size:11.5px;color:var(--tx-dim);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kb-n{font-size:13px;color:var(--tx-mut);margin-top:4px;line-height:1.5}
.kb-k{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--tx-dim);background:var(--ct-wash);
  border-radius:999px;padding:3px 9px;white-space:nowrap}
/* Свой класс, а не .col-tool: у того иконку рисует маска в ::before, и для
   чужих кнопок вместо значка остаётся залитый квадрат. */
.kb-act{display:grid;place-items:center;width:32px;height:32px;padding:0;border-radius:9px;
  border:1px solid transparent;background:none;color:var(--tx-dim);cursor:pointer;
  transition:color .14s ease,background .14s ease,border-color .14s ease}
.kb-act svg{width:16px;height:16px;display:block}
.kb-act:hover{color:var(--tx);background:var(--ct-wash);
  border-color:color-mix(in srgb,var(--acc) 26%,transparent)}
.kb-act:active{transform:translateY(1px)}
@media(max-width:760px){
  .kb-i{grid-template-columns:30px 1fr auto;row-gap:6px}
  .kb-k{grid-column:2/4;justify-self:start}
  .kb-act{width:40px;height:40px}
}


/* Ряд вкладок проекта растёт: «Знания» и «Архив» перестали помещаться на
   узких экранах и выталкивали страницу вбок. Ряд теперь прокручивается сам,
   как метки над доской, — вместо горизонтальной прокрутки всей страницы. */
.ptabs{overflow-x:auto;flex-wrap:nowrap;scrollbar-width:none;-webkit-overflow-scrolling:touch}
/* ⚠️ overflow-x:auto делает вторую ось тоже прокручиваемой — выпадающее меню
   «Ещё» обрезалось полосой вкладок по высоте, и «Бюджет», «Решения», «Релизы»
   и «Добавить этап» открыть было нельзя ни на телефоне, ни в узком окне.
   Даём полосе хвост снизу и выносим само меню из потока прокрутки. */
.ptabs{padding-bottom:2px}
.ptabs .pmore{position:static}
.pmore-d{position:fixed; top:auto; right:auto; overflow-y:auto; overscroll-behavior:contain}
.ptabs::-webkit-scrollbar{display:none}
.ptabs>*{flex:none}


/* ───────────────────────────────────────────────────────────────────────────
   ЖИВОЙ КАБИНЕТ
   Доска обновляется сама. Подсветка нужна не для красоты: без неё переезд
   карточки читается как «экран моргнул», и человек не понимает, что изменилось.
   ─────────────────────────────────────────────────────────────────────────── */
@keyframes justMoved{
  0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--acc) 55%,transparent)}
  35%{box-shadow:0 0 0 4px color-mix(in srgb,var(--acc) 30%,transparent)}
  100%{box-shadow:0 0 0 0 transparent}
}
.card.just-moved{animation:justMoved 2.1s ease-out;border-color:color-mix(in srgb,var(--acc) 45%,var(--line))}

/* кто сейчас смотрит проект */
.watchers{display:flex;align-items:center;gap:-6px;margin-right:2px}
.watchers.hidden{display:none}
.wa{display:grid;place-items:center;width:26px;height:26px;border-radius:50%;
  font-family:var(--mono);font-size:11px;font-weight:700;color:var(--tx);
  background:var(--ct-wash);border:2px solid var(--bg);margin-left:-6px}
.wa:first-child{margin-left:0}
.wa-team{background:color-mix(in srgb,var(--acc) 22%,transparent);color:var(--acc)}
.wa-more{color:var(--tx-dim);font-size:10px}
@media(prefers-reduced-motion:reduce){.card.just-moved{animation:none}}
@media(max-width:760px){.watchers{display:none}}


/* Запись экрана из браузера на телефоне недоступна — кнопку там прячем.
   Во время записи она горит, как кнопка голосового. */
.nophone{display:inline-flex}
@media(max-width:760px){.nophone{display:none}}


/* ───────────────────────────────────────────────────────────────────────────
   ПОМОЩНИК ПО ПРОЕКТУ
   Подсказки-вопросы стоят ДО поля: без них человек не знает, о чём спрашивать,
   и закрывает окно, ничего не написав.
   ─────────────────────────────────────────────────────────────────────────── */
.ask-h{display:flex;align-items:center;gap:9px}
.ask-h svg{width:19px;height:19px;color:var(--acc)}
.ask-hints{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:12px}
.ask-hint{font:inherit;font-size:12.5px;padding:6px 11px;border-radius:999px;cursor:pointer;
  border:1px solid var(--line);background:var(--ct-wash);color:var(--tx-mut);transition:.14s}
.ask-hint:hover{color:var(--tx);border-color:color-mix(in srgb,var(--acc) 34%,transparent)}
.ask-q{font-size:13px;color:var(--tx-dim);margin:4px 0 6px}
.ask-a{background:var(--card2,var(--card));border:1px solid var(--line);
  border-left:3px solid var(--acc);border-radius:0 12px 12px 0;padding:13px 15px;
  font-size:14.5px;line-height:1.6;white-space:normal}
.ask-wait{display:flex;align-items:center;gap:10px;color:var(--tx-mut)}
.ask-note{font-size:11.5px;color:var(--tx-dim);margin-top:8px}
.ptab.ask{color:var(--acc)}


/* Роль участника — выпадающим списком прямо на чипе. */
.pmrole{font:inherit;font-size:11.5px;margin:0 4px;padding:2px 6px;border-radius:7px;
  background:var(--ct-wash);color:var(--tx-mut);border:1px solid var(--line);cursor:pointer}
.pmrole:hover{color:var(--tx)}




/* Список актов проекта. Статус — словами, а не цветом: «ждёт подтверждения»
   должно читаться и в чёрно-белой печати экрана. */
.acts{border:1px solid var(--line);border-radius:11px;overflow:hidden}
.act-r{display:grid;grid-template-columns:1fr auto auto auto;align-items:center;gap:10px;
  padding:10px 12px;border-bottom:1px solid var(--line)}
.act-r:last-child{border-bottom:none}
.act-b b{font-size:14px}
.act-b span{display:block;font-size:12px;color:var(--tx-mut);font-family:var(--mono)}
.act-s{font-size:12px;color:var(--tx-mut)}
.act-s.ok{color:var(--ok)}
@media(max-width:760px){.act-r{grid-template-columns:1fr auto auto}.act-s{grid-column:1/4;order:3}}


/* ───────────────────────────────────────────────────────────────────────────
   СТАРТ ПРОЕКТА · «что нужно от вас»
   Прогресс сверху не для красоты: он показывает клиенту, что работа стоит не
   из-за нас, и делает это без единого напоминания.
   ─────────────────────────────────────────────────────────────────────────── */
.ink-head{padding:16px 18px;margin-bottom:12px}
.ink-h{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;margin-bottom:10px}
.ink-h b{font-size:15px}
.ink-h span{display:block;font-size:13px;color:var(--tx-mut);margin-top:2px}
.ink-pct{font-family:var(--mono);font-size:20px;font-weight:800;color:var(--acc)}
.ink-bar{height:8px;border-radius:999px;background:var(--ct-wash);overflow:hidden}
.ink-bar i{display:block;height:100%;background:var(--acc);transition:width .3s ease}
.ink-list{padding:4px 8px}
.ink-i{display:grid;grid-template-columns:34px 1fr auto;align-items:start;gap:12px;
  padding:13px 10px;border-bottom:1px solid var(--line)}
.ink-i:last-child{border-bottom:none}
.ink-ic{display:grid;place-items:center;width:34px;height:34px;border-radius:10px;
  background:color-mix(in srgb,var(--acc) 11%,transparent);color:var(--acc)}
.ink-i.ok .ink-ic{background:color-mix(in srgb,var(--ok) 15%,transparent);color:var(--ok)}
.ink-ic svg{width:17px;height:17px}
.ink-t{font-size:14.5px;font-weight:650;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.ink-k{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--tx-dim);background:var(--ct-wash);border-radius:999px;padding:2px 7px}
.ink-n{font-size:13px;color:var(--tx-mut);margin-top:3px;line-height:1.5}
.ink-v{font-size:13.5px;margin-top:6px;padding:8px 10px;border-radius:9px;background:var(--ct-wash);
  white-space:pre-wrap;word-break:break-word}
.ink-f{display:inline-flex;align-items:center;gap:6px;margin-top:6px;font-size:13px;color:var(--acc);text-decoration:none}
.ink-f svg{width:14px;height:14px}
.ink-d{font-size:11.5px;color:var(--tx-dim);margin-top:5px}
.ink-a{display:flex;align-items:center;gap:6px}
.ink-add{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
@media(max-width:760px){
  .ink-i{grid-template-columns:30px 1fr;row-gap:8px}
  .ink-a{grid-column:2;justify-content:flex-start}
}


/* ───────────────────────────────────────────────────────────────────────────
   ИСТОРИЯ ПРОЕКТА
   Лента с начала работы, сгруппированная по дням: без группировки это сплошная
   простыня, в которой невозможно найти нужную неделю.
   ─────────────────────────────────────────────────────────────────────────── */
.hs-day+.hs-day{margin-top:16px}
.hs-dh{font-size:11.5px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;
  color:var(--tx-dim);padding:0 4px 7px}
.hs-list{padding:4px 8px}
.hs-r{display:grid;grid-template-columns:44px 28px 1fr;align-items:start;gap:10px;
  padding:9px 8px;border-radius:10px;border-bottom:1px solid var(--line)}
.hs-r:last-child{border-bottom:none}
.hs-r.go{cursor:pointer}
.hs-r.go:hover{background:var(--ct-wash)}
.hs-time{font-family:var(--mono);font-size:11.5px;color:var(--tx-dim);padding-top:5px}
.hs-ic{display:grid;place-items:center;width:28px;height:28px;border-radius:9px;
  background:var(--ct-wash);color:var(--tx-mut)}
.hs-ic svg{width:15px;height:15px}
.hs-ic.k-accepted,.hs-ic.k-milestone,.hs-ic.k-act{color:var(--ok);background:color-mix(in srgb,var(--ok) 14%,transparent)}
.hs-ic.k-review{color:var(--warn);background:color-mix(in srgb,var(--warn) 14%,transparent)}
.hs-ic.k-comment{color:var(--acc);background:color-mix(in srgb,var(--acc) 12%,transparent)}
.hs-t{font-size:13.5px;font-weight:600;line-height:1.35}
.hs-x{font-size:13px;color:var(--tx-mut);margin-top:3px;line-height:1.5;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.hs-more{display:flex;justify-content:center;margin-top:14px}
@media(max-width:760px){
  .hs-r{grid-template-columns:38px 26px 1fr;gap:8px}
  .hs-time{font-size:11px}
}


/* ───────────────────────────────────────────────────────────────────────────
   КАЛЕНДАРЬ СРОКОВ
   Месяц целиком: пустые недели и завалы видно сразу, а списком — нет.
   Дни вне месяца приглушены, но не спрятаны: срок 1-го числа не должен
   пропадать из виду в последнюю неделю предыдущего месяца.
   ─────────────────────────────────────────────────────────────────────────── */
.cal-bar{display:flex;align-items:center;gap:8px;margin-bottom:12px;flex-wrap:wrap}
.cal-bar .sp{flex:1}
.cal-t{font-size:15px;min-width:150px;text-align:center}
.cal-n{font-size:12.5px;color:var(--tx-mut)}
.cal{padding:12px}
.cal-h{display:grid;grid-template-columns:repeat(7,1fr);gap:6px;margin-bottom:6px}
.cal-h span{font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--tx-dim);text-align:center}
.cal-g{display:grid;grid-template-columns:repeat(7,1fr);gap:6px}
.cal-d{min-height:88px;border:1px solid var(--line);border-radius:10px;padding:6px;
  display:flex;flex-direction:column;gap:3px;background:var(--card2,transparent)}
.cal-d.out{opacity:.4}
.cal-d.we{background:var(--ct-wash)}
.cal-d.now{border-color:var(--acc);box-shadow:0 0 0 1px color-mix(in srgb,var(--acc) 40%,transparent)}
.cal-num{font-family:var(--mono);font-size:11.5px;color:var(--tx-dim)}
.cal-d.now .cal-num{color:var(--acc);font-weight:700}
.cal-e{font-size:11px;line-height:1.3;padding:3px 6px;border-radius:6px;cursor:pointer;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  background:color-mix(in srgb,var(--acc) 14%,transparent);color:var(--acc)}
.cal-e.k-done{background:color-mix(in srgb,var(--ok) 14%,transparent);color:var(--ok)}
.cal-e.k-ms{background:color-mix(in srgb,var(--warn) 16%,transparent);color:var(--warn);font-weight:700}
.cal-e.k-msdone{background:color-mix(in srgb,var(--ok) 18%,transparent);color:var(--ok);font-weight:700}
.cal-more{font-size:10.5px;color:var(--tx-dim);padding-left:6px}
.cal-leg{display:flex;flex-wrap:wrap;gap:14px;margin-top:12px;font-size:12px;color:var(--tx-mut)}
.cal-leg span{display:inline-flex;align-items:center;gap:6px}
.cal-leg i{width:10px;height:10px;border-radius:3px;display:inline-block;
  background:color-mix(in srgb,var(--acc) 40%,transparent)}
.cal-leg i.k-done,.cal-leg i.k-msdone{background:color-mix(in srgb,var(--ok) 45%,transparent)}
.cal-leg i.k-ms{background:color-mix(in srgb,var(--warn) 45%,transparent)}
@media(max-width:760px){
  .cal{padding:8px}
  .cal-g{gap:4px}
  .cal-d{min-height:64px;padding:4px}
  .cal-e{font-size:10px;padding:2px 4px}
  .cal-h span{font-size:10px}
}


/* ───────────────────────────────────────────────────────────────────────────
   МЕНЮ «ЕЩЁ» НА ВКЛАДКАХ ПРОЕКТА
   Разовые действия (отчёт, акт, выгрузки) убраны с глаз: ряд из четырнадцати
   вкладок не помещался на экран, и до «Календаря» приходилось мотать.
   ─────────────────────────────────────────────────────────────────────────── */
.pmore{position:relative;flex:none}
.pmore-c{font-style:normal;font-size:10px;margin-left:2px;color:var(--tx-dim)}
.pmore-d{position:absolute;top:calc(100% + 6px);right:0;z-index:40;min-width:280px;
  background:var(--card);border:1px solid var(--line);border-radius:12px;padding:6px;
  box-shadow:0 18px 40px -16px rgba(0,0,0,.55)}
.pmore-d.hidden{display:none}
.pmore-i{display:block;width:100%;text-align:left;padding:9px 11px;border:none;border-radius:9px;
  background:none;color:inherit;cursor:pointer;font:inherit}
.pmore-i:hover{background:var(--ct-wash)}
.pmore-i b{display:block;font-size:13.5px;font-weight:650}
.pmore-i span{display:block;font-size:12px;color:var(--tx-mut);margin-top:1px}
@media(max-width:760px){.pmore-d{right:auto;left:0;min-width:240px}}


/* ═══════════════════════════════════════════════════════════════════════════
   СВОДКА ОФОРМЛЕНИЯ · приведение новых экранов к одной мере
   За день кабинет прирос десятком экранов, и каждый принёс свои значения:
   «надзаголовок» существовал в пяти вариантах (11–13px, вес 700/800,
   трекинг .02–.08em), отступ строки списка — в шести, заголовок строки — в трёх.
   По отдельности незаметно, вместе экраны перестают выглядеть одним продуктом.
   Здесь одна мера на каждую роль. Слой идёт последним и потому побеждает.
   ═══════════════════════════════════════════════════════════════════════════ */

/* 1 · Надзаголовок группы: «СЕГОДНЯ», «ЗАДАЧИ», «ПРИНЯТЫЕ РАБОТЫ» */
.hs-dh, .rep-h, .ngrp-h, .gsgrp-h, .docs-head > span, .cmts-head{
  font-size:11.5px; font-weight:800; letter-spacing:.07em; text-transform:uppercase;
  color:var(--tx-dim);
}
.hs-dh, .ngrp-h{padding:0 4px 8px}
.gsgrp-h{padding:4px 8px 7px}
.rep-h{margin:22px 0 9px}

/* 2 · Карточка-контейнер списка: своё содержимое уже с отступами */
.kb-list, .hs-list, .ink-list, .acts, .mn-b{padding:6px 10px}
.mn-b{padding:6px 14px 14px}

/* 3 · Строка списка: одна высота ритма на все экраны */
.kb-i, .hs-r, .ink-i, .act-r, .nrow{padding:12px 12px; gap:11px}
.mn-r{padding:12px 2px}

/* 4 · Заголовок строки */
.kb-t, .ink-t, .hs-t, .act-b b, .nr-t{font-size:14px; font-weight:650; line-height:1.35}
/* пояснение под заголовком — одним кеглем и цветом */
.kb-n, .ink-n, .hs-x, .nr-s, .pmore-i span{font-size:12.5px; color:var(--tx-mut); line-height:1.5}

/* 5 · Значок-квадрат слева в строке: один размер и радиус */
.kb-ic, .ink-ic, .hs-ic, .nr-ic, .gsr-ic{border-radius:9px}
.kb-ic, .ink-ic{width:32px; height:32px}
.kb-ic svg, .ink-ic svg, .hs-ic svg{width:16px; height:16px}

/* 6 · Служебная подпись под строкой (дата, статус) */
.ink-d, .hs-time, .act-b span, .kb-u{font-family:var(--mono); font-size:11.5px; color:var(--tx-dim)}


/* ═══ КАРТОЧКА · плотность и доступность ══════════════════════════════════
   Резерв под кнопки в шапке был всегда (30px, на телефоне 48px), а сами
   кнопки есть не у всех: клиент в «Бэклоге» их не видит вовсе, зато номер
   задачи всё равно жался. Даём резерв ровно тем карточкам, где кнопки есть:
   .qadv занимает правые 34px, .qpick — 64px.                              */
.card .chead{padding-right:0}
.card:has(.qadv) .chead{padding-right:38px}
.card:has(.qpick) .chead{padding-right:72px}
/* Плашка блокировки резервировала 38px на всех карточках — включая клиентский
   «Бэклог», где кнопок нет. Сбрасываем симметрично шапке. */
.card .blk{padding-right:12px}
.card:has(.qadv) .blk{padding-right:38px}
.card:has(.qpick) .blk{padding-right:72px}

/* Значки в мете пришли на смену эмодзи: те игнорировали цвет темы и были
   разной ширины на macOS и Windows. Высоту ряда держим ровно, иначе ритм
   карточки съезжает на пиксель. */
.card .meta .mi{display:inline-flex; align-items:center; gap:4px}
.card .meta .mi svg{width:12px; height:12px; flex:none; opacity:.9}
.card .meta .pchip{display:inline-flex; align-items:center; gap:4px}
.card .meta .pchip svg{width:11px; height:11px; flex:none}
.card .meta .mi.etx{color:var(--tx-mut)}

/* Карточку теперь можно открыть с клавиатуры — показываем это фокусом. */
.card:focus-visible{outline:2px solid var(--dp-focus, var(--acc)); outline-offset:2px}

@media(max-width:760px){
  /* Ниже 760px .qadv вырастает до 44px, а .qpick оставался 26px на right:38 —
     кнопки налезали друг на друга на 10px. Разводим: 4..48 и 52..90. */
  .card .qpick{width:38px; height:38px; right:52px; opacity:1; transform:none}
  .card .qpick svg{width:16px; height:16px}
  .card .chead{padding-right:0}
  .card:has(.qadv) .chead{padding-right:52px}
  .card:has(.qpick) .chead{padding-right:94px}
  .card .blk{padding-right:12px}
  .card:has(.qadv) .blk{padding-right:52px}
  .card:has(.qpick) .blk{padding-right:94px}
}

/* Планшет в портрете (768px) под ≤760 не попадает, а ховера на нём нет:
   кнопки с opacity:0 были недостижимы вообще. */
@media(hover:none){
  .card .qadv, .card .qpick{opacity:1; transform:none}
}

/* Браузер без :has (Firefox до 121) — возвращаем прежний безусловный резерв,
   чтобы номер задачи не заезжал под кнопку. */
@supports not selector(:has(*)){
  .card .chead{padding-right:30px}
  .card .blk{padding-right:38px}
  @media(max-width:760px){ .card .chead{padding-right:48px} .card .blk{padding-right:52px} }
}


/* Счётчик находок ⌘K существует только для диктора: на экране число видно
   по самому списку, произносить его глазами не нужно. Прячем без display:none
   — скрытое так не читается вовсе. */
.gscount{position:absolute; width:1px; height:1px; margin:-1px; padding:0;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%); white-space:nowrap; border:0}


/* ═══ НОВЫЕ РАЗДЕЛЫ: БЮДЖЕТ · РИСКИ · РЕШЕНИЯ · РЕЛИЗЫ ════════════════════
   Оформление подчинено правилу кабинета: числа моноширинные и с одинаковой
   шириной цифр, подписи мелкие и приглушённые, цветом отмечаем только то,
   что требует действия. Палитра не меняется. */

/* ── Бюджет ── */
.bg-head{padding:18px 20px}
.bg-bar{position:relative; height:12px; border-radius:999px;
  background:color-mix(in srgb, var(--tx) 8%, transparent); overflow:hidden}
.bg-bar i{position:absolute; inset:0 auto 0 0; width:var(--w); border-radius:999px;
  transition:width .6s cubic-bezier(.2,.8,.3,1)}
.bg-bar .bg-issued{background:color-mix(in srgb, var(--acc) 38%, transparent); z-index:1}
.bg-bar .bg-paid{background:linear-gradient(90deg, var(--ok), color-mix(in srgb, var(--ok) 70%, var(--acc))); z-index:2}
.bg-lg{display:flex; flex-wrap:wrap; gap:14px; margin-top:11px; font-size:12.5px; color:var(--tx-mut)}
.bg-lg span{display:inline-flex; align-items:center; gap:6px}
.bg-d{width:8px; height:8px; border-radius:50%; flex:none}
.bg-d.paid{background:var(--ok)}
.bg-d.issued{background:color-mix(in srgb, var(--acc) 60%, transparent)}
.bg-d.plan{background:color-mix(in srgb, var(--tx) 30%, transparent)}

.bg-grid{display:grid; grid-template-columns:repeat(auto-fit, minmax(210px, 1fr)); gap:12px; margin-top:12px}
.bg-t{background:var(--panel); border:1px solid var(--line); border-radius:var(--bd-r, 14px);
  padding:15px 17px; display:flex; flex-direction:column; gap:4px; text-align:left}
.bg-l{font-size:11px; letter-spacing:.07em; text-transform:uppercase; color:var(--tx-dim)}
.bg-v{font-family:var(--mono); font-size:21px; font-variant-numeric:tabular-nums; letter-spacing:-.01em}
.bg-s{font-size:12px; color:var(--tx-mut)}
.bg-t.warn .bg-v{color:var(--warn)}
.bg-t.ok .bg-s{color:var(--ok)}
.bg-plan.can{cursor:pointer; transition:border-color .16s, transform .16s}
.bg-plan.can:hover{border-color:color-mix(in srgb, var(--acc) 45%, var(--line)); transform:translateY(-1px)}
.bg-plan.can:focus-visible{outline:2px solid var(--acc); outline-offset:2px}

.bg-hours{margin-top:12px; padding:15px 18px}
.bg-hours h3{font-size:12px; letter-spacing:.07em; text-transform:uppercase; color:var(--tx-dim); margin:0 0 10px}
.bg-hrow{display:flex; align-items:baseline; gap:8px 16px; flex-wrap:wrap; font-size:13px; color:var(--tx-mut)}
.bg-hrow b{font-family:var(--mono); font-size:16px; color:var(--tx); font-variant-numeric:tabular-nums}
.bg-hrow b.bad{color:var(--danger)} .bg-hrow b.ok{color:var(--ok)}

.bg-list{display:flex; flex-direction:column}
.bg-row{display:grid; grid-template-columns:1fr auto auto; gap:12px; align-items:center;
  padding:11px 4px; background:none; border:0; border-top:1px solid var(--line); width:100%;
  text-align:left; color:inherit; font:inherit; cursor:pointer; transition:background .14s}
.bg-row:first-child{border-top:0}
.bg-row:hover{background:color-mix(in srgb, var(--tx) 4%, transparent)}
.bg-rt{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:13.5px}
.bg-rs{font-size:11px; padding:2px 8px; border-radius:999px; white-space:nowrap;
  background:color-mix(in srgb, var(--tx) 8%, transparent); color:var(--tx-mut)}
.bg-rs.q-approved{background:color-mix(in srgb, var(--ok) 16%, transparent); color:var(--ok)}
.bg-rs.q-declined{background:color-mix(in srgb, var(--danger) 14%, transparent); color:var(--danger)}
.bg-ra{font-family:var(--mono); font-size:13.5px; font-variant-numeric:tabular-nums; white-space:nowrap}

/* ── Риски ── */
.rk-sum{display:flex; align-items:center; gap:14px; padding:16px 20px}
.rk-n1{font-family:var(--mono); font-size:30px; line-height:1; color:var(--warn); font-variant-numeric:tabular-nums}
.rk-sum span{color:var(--tx-mut); font-size:13.5px}
.rk-list{margin-top:12px; display:flex; flex-direction:column}
/* minmax(0,1fr): без него минимум дорожки равен длине неразрывного заголовка */
.rk-b{min-width:0}
.rk-i{display:grid; grid-template-columns:auto minmax(0,1fr) auto auto; gap:12px; align-items:center;
  padding:12px 6px; border-top:1px solid var(--line); width:100%; text-align:left;
  background:none; border-left:0; border-right:0; border-bottom:0; color:inherit; font:inherit}
.rk-i:first-child{border-top:0}
button.rk-i{cursor:pointer; transition:background .14s}
button.rk-i:hover{background:color-mix(in srgb, var(--tx) 4%, transparent)}
.rk-ic{display:grid; place-items:center; width:30px; height:30px; border-radius:9px; flex:none;
  background:color-mix(in srgb, var(--warn) 12%, var(--panel)); color:var(--warn)}
.rk-ic svg{width:15px; height:15px}
.rk-bad .rk-ic{background:color-mix(in srgb, var(--danger) 12%, var(--panel)); color:var(--danger)}
.rk-t{font-size:14px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.rk-n{font-size:12px; color:var(--tx-mut); margin-top:2px}
.rk-k{font-size:11px; padding:2px 9px; border-radius:999px; white-space:nowrap;
  background:color-mix(in srgb, var(--tx) 8%, transparent); color:var(--tx-mut)}
.rk-w{font-family:var(--mono); font-size:12px; color:var(--tx-dim); white-space:nowrap;
  font-variant-numeric:tabular-nums}
.rk-bad .rk-w{color:var(--danger)}

/* ── Решения ── */
.dc-list{display:flex; flex-direction:column}
.dc-i{display:grid; grid-template-columns:52px 1fr auto; gap:14px; padding:14px 6px;
  border-top:1px solid var(--line)}
.dc-i:first-child{border-top:0}
.dc-d{text-align:center; font-family:var(--mono); line-height:1.15; padding-top:2px}
.dc-d b{display:block; font-size:13px; color:var(--tx)}
.dc-d span{font-size:11px; color:var(--tx-dim)}
.dc-t{font-size:14.5px; font-weight:700; letter-spacing:-.005em}
.dc-w{font-size:13px; color:var(--tx-mut); margin-top:4px; line-height:1.5; text-wrap:pretty}
.dc-m{display:flex; flex-wrap:wrap; gap:6px 14px; margin-top:7px; font-size:11.5px; color:var(--tx-dim)}
.dc-lnk{display:inline-flex; align-items:center; gap:5px; background:none; border:0; padding:0;
  color:var(--acc); font:inherit; font-size:11.5px; cursor:pointer}
.dc-lnk svg{width:12px; height:12px}
.dc-lnk:hover{text-decoration:underline}
.dc-act{display:flex; gap:4px; align-self:start}

/* ── Релизы ── */
.rl-list{display:flex; flex-direction:column}
.rl-i{display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:14px; padding:16px 6px;
  border-top:1px solid var(--line); position:relative}
/* minmax(0,1fr) и min-width:0 — иначе минимум дорожки равен длине неразрывной
   ссылки, и строка распирает страницу, унося кнопки за край */
.rl-b{min-width:0}
.rl-u{max-width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.rl-i:first-child{border-top:0}
.rl-dot{position:relative; width:14px; display:flex; justify-content:center}
.rl-dot i{width:10px; height:10px; border-radius:50%; margin-top:5px; flex:none;
  background:var(--acc); box-shadow:0 0 0 4px color-mix(in srgb, var(--acc) 16%, transparent)}
/* линия ленты между выкладками — она и делает список историей, а не перечнем */
.rl-i:not(:last-child) .rl-dot::after{content:''; position:absolute; left:50%; top:20px; bottom:-16px;
  width:1px; background:var(--line); transform:translateX(-50%)}
.rl-h{display:flex; align-items:baseline; gap:9px; flex-wrap:wrap}
.rl-v{font-family:var(--mono); font-size:11px; padding:1px 7px; border-radius:6px;
  background:color-mix(in srgb, var(--acc) 14%, transparent); color:var(--acc)}
.rl-t{font-size:15px; letter-spacing:-.01em}
.rl-d{font-size:11.5px; color:var(--tx-dim); margin-left:auto; white-space:nowrap}
.rl-n{font-size:13px; color:var(--tx-mut); margin-top:5px; line-height:1.5; text-wrap:pretty}
.rl-u{display:inline-flex; align-items:center; gap:5px; margin-top:7px; font-size:12px; color:var(--acc)}
.rl-u svg{width:12px; height:12px}
.rl-tasks{display:flex; flex-wrap:wrap; gap:6px; margin-top:9px}
.rl-tk{display:inline-flex; align-items:center; gap:6px; padding:4px 10px; border-radius:999px;
  background:color-mix(in srgb, var(--tx) 6%, transparent); border:1px solid var(--line);
  color:var(--tx-mut); font:inherit; font-size:12px; cursor:pointer; max-width:100%;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; transition:border-color .14s, color .14s}
.rl-tk:hover{border-color:color-mix(in srgb, var(--acc) 40%, var(--line)); color:var(--tx)}
.rl-pick{display:flex; flex-direction:column; gap:2px; max-height:230px; overflow:auto;
  border:1px solid var(--line); border-radius:11px; padding:8px}
.rl-p{display:flex; align-items:center; gap:9px; padding:6px 8px; border-radius:8px;
  font-size:13px; cursor:pointer}
.rl-p:hover{background:color-mix(in srgb, var(--tx) 5%, transparent)}
.rl-p span:last-child{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}

@media(max-width:760px){
  .bg-grid{grid-template-columns:1fr}
  .dc-i{grid-template-columns:44px 1fr auto; gap:10px}
  .rk-i{grid-template-columns:auto 1fr auto; row-gap:6px}
  .rk-w{grid-column:3}
  .rk-k{display:none}
  .rl-d{margin-left:0; width:100%}
}


/* ═══ ДВИЖЕНИЕ ═══════════════════════════════════════════════════════════
   Правило одно: движение отвечает на действие человека и заканчивается.
   Ничего бесконечного — два таких блика отсюда уже удалялись по WCAG 2.2.2.
   Всё ниже глушится системной настройкой «меньше движения» в конце блока. */

/* Колонки проявляются лесенкой при открытии доски. Ограничено восемью:
   дальше эффект не читается, а работа начинает ждать анимацию. */
@keyframes colRise{ from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:none} }
#view.intro .board .col{animation:colRise .34s cubic-bezier(.2,.8,.3,1) both}
#view.intro .board .col:nth-child(1){animation-delay:0ms}
#view.intro .board .col:nth-child(2){animation-delay:45ms}
#view.intro .board .col:nth-child(3){animation-delay:90ms}
#view.intro .board .col:nth-child(4){animation-delay:135ms}
#view.intro .board .col:nth-child(5){animation-delay:180ms}
#view.intro .board .col:nth-child(6){animation-delay:215ms}
#view.intro .board .col:nth-child(n+7){animation-delay:245ms}

/* Карточки — только первые двенадцать в колонке: на доске с 214 карточками
   анимировать все значит заставить человека ждать пустоты. */
@keyframes cardRise{ from{opacity:0; transform:translateY(6px)} to{opacity:1; transform:none} }
#view.intro .board .col .card:nth-child(-n+12){animation:cardRise .3s ease-out both}
#view.intro .board .col .card:nth-child(2){animation-delay:25ms}
#view.intro .board .col .card:nth-child(3){animation-delay:50ms}
#view.intro .board .col .card:nth-child(4){animation-delay:70ms}
#view.intro .board .col .card:nth-child(5){animation-delay:88ms}
#view.intro .board .col .card:nth-child(6){animation-delay:104ms}
#view.intro .board .col .card:nth-child(n+7):nth-child(-n+12){animation-delay:118ms}

/* Карточка чуть подаётся к курсору — знак, что её можно открыть. */
.board .card{transition:transform .16s cubic-bezier(.2,.8,.3,1), border-color .16s, box-shadow .16s}
.board .card:hover{transform:translateY(-2px)}
.board .card:active{transform:translateY(0) scale(.995)}

/* Смена раздела: содержимое въезжает, а не подменяется рывком. */
@keyframes viewIn{ from{opacity:0; transform:translateY(6px)} to{opacity:1; transform:none} }
/* .analytics — это блок готовности НАД доской: он пересоздаётся вместе с ней
   на каждый ввод в поиск, и проявление проигрывалось заново. Экран аналитики
   использует класс .dash, его это не касается. */
#view > .section, #view > .emptybox{animation:viewIn .26s cubic-bezier(.2,.8,.3,1) both}

/* Счётчик колонки меняется — короткий отклик, чтобы изменение заметили. */
@keyframes numBump{ 0%{transform:scale(1)} 40%{transform:scale(1.22)} 100%{transform:scale(1)} }
.col-h .n.bump{animation:numBump .34s cubic-bezier(.2,.8,.3,1)}

/* Плитки новых разделов появляются лесенкой — тот же приём, что и у колонок. */
.bg-grid .bg-t{animation:cardRise .3s ease-out both}
.bg-grid .bg-t:nth-child(2){animation-delay:40ms}
.bg-grid .bg-t:nth-child(3){animation-delay:80ms}
.bg-grid .bg-t:nth-child(4){animation-delay:120ms}

/* Строки списков в «Рисках», «Решениях» и «Релизах» — первые восемь. */
.rk-list .rk-i:nth-child(-n+8), .dc-list .dc-i:nth-child(-n+8), .rl-list .rl-i:nth-child(-n+8){
  animation:cardRise .28s ease-out both}
.rk-list .rk-i:nth-child(2), .dc-list .dc-i:nth-child(2), .rl-list .rl-i:nth-child(2){animation-delay:30ms}
.rk-list .rk-i:nth-child(3), .dc-list .dc-i:nth-child(3), .rl-list .rl-i:nth-child(3){animation-delay:60ms}
.rk-list .rk-i:nth-child(4), .dc-list .dc-i:nth-child(4), .rl-list .rl-i:nth-child(4){animation-delay:85ms}
.rk-list .rk-i:nth-child(n+5), .dc-list .dc-i:nth-child(n+5), .rl-list .rl-i:nth-child(n+5){animation-delay:105ms}

/* Вкладки разделов: подчёркивание переезжает вместе с выбором. */
.ptab{transition:color .16s, background .16s}

@media(prefers-reduced-motion:reduce){
  #view.intro .board .col, #view.intro .board .col .card, #view > .section, #view > .analytics, #view > .emptybox,
  .bg-grid .bg-t, .rk-list .rk-i, .dc-list .dc-i, .rl-list .rl-i, .col-h .n.bump{
    animation:none !important}
  .board .card:hover, .board .card:active{transform:none}
  .board .card{transition:none}
}


/* ═══ ПРОКРУТКА ДОСКИ ══════════════════════════════════════════════════════
   На телефоне прокрутка «прилипает» к колонкам с самого начала, а на десктопе
   нет — доска останавливалась посередине колонки, и первая оказывалась
   обрезанной краем. Добавляем то же прилипание: proximity, а не mandatory —
   оно срабатывает только когда отпустили рядом с границей и не мешает
   перетаскиванию карточек. */
@media(min-width:761px){
  .board-wrap{scroll-snap-type:x proximity; scroll-padding-left:24px}
  .board .col{scroll-snap-align:start}
}

/* Признак того, что за краем ещё есть колонки. Без него единственный намёк —
   полоса прокрутки внизу, а её замечают не сразу. Тень рисуем на обёртке,
   поэтому она не уезжает вместе с содержимым. */
.board-outer{position:relative}
.board-outer::before, .board-outer::after{
  content:''; position:absolute; top:0; bottom:0; width:34px; pointer-events:none;
  opacity:0; transition:opacity .2s; z-index:3}
.board-outer::before{left:0; background:linear-gradient(90deg, var(--bg), transparent)}
.board-outer::after{right:0; background:linear-gradient(270deg, var(--bg), transparent)}
.board-outer.has-left::before{opacity:1}
.board-outer.has-right::after{opacity:1}

/* Шапка колонки держится на месте, пока листаешь её карточки: в колонке
   «Готово» их 214, и без этого непонятно, что вообще листаешь.
   ⚠️ Фон здесь НЕ задаём: этот селектор (0,2,0) стоит последним в файле и
   перебивал и градиент «крышки» колонки, и тонированную шапку «Пожеланий» —
   шапка сливалась с телом колонки. Прилипающему элементу нужен непрозрачный
   фон, но его даёт собственный градиент .col-h, он непрозрачен. */
/* Прилипание имеет смысл только там, где шапка и карточки в ОДНОМ
   прокручиваемом блоке. На десктопе прокручивается .col-body — сосед шапки,
   значит прилипать ей не к чему. На телефоне прокручивается страница целиком,
   и шапка прилипала ПОД верхнюю панель, накрывая собой кнопку «свернуть».
   Оставляем только там, где это работает: внутри колонки с прокруткой. */
.board .col{position:relative}

@media(prefers-reduced-motion:reduce){
  .board-outer::before, .board-outer::after{transition:none}
}


/* ═══ ВХОД · НАБРОСОК ДОСКИ ════════════════════════════════════════════════
   На витрине было три строки текста и много пустоты снизу: на высоком экране
   форма и обещания висели в верхней трети. Набросок доски занимает эту пустоту
   и отвечает на вопрос «что внутри» быстрее любого абзаца.
   Это НЕ скриншот и не данные клиента — только форма экрана, собранная из
   прямоугольников. Картинок не грузит, для диктора скрыт. */
.auth-peek{
  display:grid; grid-template-columns:repeat(3, 1fr); gap:10px;
  margin-top:34px; padding:14px; border-radius:14px;
  background:linear-gradient(168deg, rgba(255,246,232,.045), rgba(255,246,232,.015));
  border:1px solid var(--au-seam);
  /* нижний край растворяется — набросок не спорит с подвалом витрины */
  -webkit-mask-image:linear-gradient(180deg,#000 62%,transparent 100%);
          mask-image:linear-gradient(180deg,#000 62%,transparent 100%);
}
.pk-col{display:flex; flex-direction:column; gap:7px}
.pk-h{height:7px; border-radius:999px; background:rgba(255,246,232,.30)}
.pk-h.a{background:color-mix(in srgb, var(--acc) 70%, transparent)}
.pk-h.b{background:color-mix(in srgb, var(--ok) 62%, transparent)}
.pk-c{height:26px; border-radius:8px; background:rgba(255,246,232,.075);
  border:1px solid rgba(255,246,232,.05)}
.pk-c.s2{height:34px}
.pk-c.s3{height:20px}
:root[data-theme="light"] .auth-peek{
  background:linear-gradient(168deg, rgba(20,16,10,.05), rgba(20,16,10,.02));
}
:root[data-theme="light"] .pk-h{background:rgba(20,16,10,.24)}
:root[data-theme="light"] .pk-c{background:rgba(20,16,10,.06); border-color:rgba(20,16,10,.05)}

/* Карточки набрасываются лесенкой один раз при открытии — движение отвечает
   на появление экрана и заканчивается. Ничего бесконечного. */
@keyframes pkRise{ from{opacity:0; transform:translateY(7px)} to{opacity:1; transform:none} }
.auth-peek .pk-h, .auth-peek .pk-c{animation:pkRise .42s cubic-bezier(.2,.8,.3,1) both}
.pk-col:nth-child(1) .pk-c:nth-child(2){animation-delay:.10s}
.pk-col:nth-child(1) .pk-c:nth-child(3){animation-delay:.16s}
.pk-col:nth-child(1) .pk-c:nth-child(4){animation-delay:.22s}
.pk-col:nth-child(2) .pk-h{animation-delay:.06s}
.pk-col:nth-child(2) .pk-c:nth-child(2){animation-delay:.16s}
.pk-col:nth-child(2) .pk-c:nth-child(3){animation-delay:.22s}
.pk-col:nth-child(3) .pk-h{animation-delay:.12s}
.pk-col:nth-child(3) .pk-c:nth-child(2){animation-delay:.22s}
.pk-col:nth-child(3) .pk-c:nth-child(3){animation-delay:.28s}
.pk-col:nth-child(3) .pk-c:nth-child(4){animation-delay:.34s}

/* На узком экране витрина и так скрыта (≤900px), но если её вернут —
   набросок уходит первым: он украшение, а не содержание. */
@media(max-width:1180px){ .auth-peek{display:none} }
@media(prefers-reduced-motion:reduce){
  .auth-peek .pk-h, .auth-peek .pk-c{animation:none}
}

/* ═══ ВХОД · ФОРМА ══════════════════════════════════════════════════════════
   Звёздочку у обязательного поля кабинет ставит сам по атрибуту required. На
   входе обязательны ВСЕ поля, поэтому она не сообщает ничего — только шумит
   рядом с подписью. Внутри кабинета, где поля смешанные, она остаётся. */
.login-wrap.auth .field:has(input:required) label::after{content:none}

/* Кнопка входа: тёплая подложка под ней делает её опорой формы, а не просто
   прямоугольником. Тень уходит при нажатии — отклик на действие. */
.login-wrap.auth .auth-go{
  box-shadow:0 14px 30px -14px color-mix(in srgb, var(--acc) 78%, transparent);
  transition:transform .14s cubic-bezier(.2,.8,.3,1), box-shadow .18s;
}
.login-wrap.auth .auth-go:hover{
  transform:translateY(-1px);
  box-shadow:0 18px 38px -14px color-mix(in srgb, var(--acc) 85%, transparent);
}
.login-wrap.auth .auth-go:active{transform:translateY(0);
  box-shadow:0 8px 18px -12px color-mix(in srgb, var(--acc) 70%, transparent)}
@media(prefers-reduced-motion:reduce){
  .login-wrap.auth .auth-go{transition:none}
  .login-wrap.auth .auth-go:hover, .login-wrap.auth .auth-go:active{transform:none}
}


/* ═══ СПРАВОЧНИК · ПОИСК И ФИЛЬТР ═════════════════════════════════════════
   Семьдесят шесть строк в четырнадцати свёрнутых разделах листанием не
   находятся, а Ctrl+F не видит того, что внутри закрытого <details>. */
.mn-tools{display:flex; align-items:center; gap:14px; flex-wrap:wrap; padding:14px 16px; margin-bottom:12px}
.mn-find{display:flex; align-items:center; gap:9px; flex:1 1 300px; min-width:0;
  padding:9px 13px; border-radius:11px; background:var(--fi-bg); border:1px solid var(--fi-line);
  transition:border-color .16s, background .16s}
.mn-find:focus-within{border-color:var(--acc); background:var(--fi-bg-focus)}
.mn-find svg{width:16px; height:16px; color:var(--tx-dim); flex:none}
.mn-find input{flex:1; min-width:0; background:none; border:0; outline:none; color:var(--tx);
  font:inherit; font-size:14px; padding:0}
/* 16px — iOS иначе увеличивает страницу при касании поля */
@media(max-width:760px){ .mn-find input{font-size:16px} }
.mn-find input::-webkit-search-cancel-button{filter:grayscale(1) opacity(.6)}

.mn-flt{display:flex; gap:4px; flex-wrap:wrap}
.mn-f{padding:7px 13px; border-radius:999px; border:1px solid var(--line);
  background:none; color:var(--tx-mut); font:inherit; font-size:12.5px; cursor:pointer;
  transition:border-color .14s, color .14s, background .14s}
.mn-f:hover{color:var(--tx); border-color:var(--line2)}
.mn-f.on{background:color-mix(in srgb, var(--acc) 14%, transparent);
  border-color:color-mix(in srgb, var(--acc) 45%, transparent); color:var(--acc)}
.mn-f:focus-visible{outline:2px solid var(--acc); outline-offset:2px}

.mn-act{display:flex; align-items:center; gap:12px; margin-left:auto}
.mn-cnt{font-family:var(--mono); font-size:12px; color:var(--tx-dim); white-space:nowrap;
  font-variant-numeric:tabular-nums}
.mn-none{margin-top:12px}

@media(max-width:760px){
  .mn-tools{gap:10px}
  .mn-act{margin-left:0; width:100%; justify-content:space-between}
  .mn-find{flex-basis:100%}
}


/* ═══ АНАЛИТИКА · НОВЫЕ ДАШБОРДЫ ═══════════════════════════════════════════
   Числа моноширинные и с равной шириной цифр, подписи мелкие и приглушённые,
   цветом отмечаем только то, что требует действия. Палитра прежняя. */

/* ── Путь задачи: три отрезка со стрелками между ними ── */
.cy-row{display:flex; align-items:stretch; gap:8px; flex-wrap:wrap; padding:4px 2px}
.cy-p{flex:1 1 150px; min-width:0; display:flex; flex-direction:column; gap:2px;
  padding:13px 15px; border-radius:12px; background:var(--card2, color-mix(in srgb, var(--tx) 4%, transparent));
  border:1px solid var(--line)}
.cy-p.empty{opacity:.62}
.cy-l{font-size:11px; letter-spacing:.06em; text-transform:uppercase; color:var(--tx-dim)}
.cy-p b{font-family:var(--mono); font-size:23px; line-height:1.1; font-variant-numeric:tabular-nums}
.cy-u{font-size:12px; color:var(--tx-mut); margin-top:-2px}
.cy-n{font-size:11px; color:var(--tx-dim); margin-top:3px}
.cy-ar{align-self:center; color:var(--tx-dim); font-size:15px; flex:none}
.cy-ar.cy-eq{color:var(--acc)}

/* ── Сводная строка над списком: «в среднем N дней» ── */
.wt-sum{font-size:13px; color:var(--tx-mut); margin:2px 0 10px}
.wt-sum b{font-family:var(--mono); color:var(--tx); font-variant-numeric:tabular-nums}

/* ── Столбики по месяцам: выставлено — заливка, оплачено — внутри неё ── */
.mm-row{display:flex; align-items:flex-end; gap:10px; height:132px; padding:8px 2px 0}
.mm-c{flex:1; min-width:0; display:flex; flex-direction:column; align-items:center; gap:7px; height:100%}
.mm-bar{position:relative; width:100%; max-width:44px; flex:1; border-radius:8px 8px 4px 4px;
  background:color-mix(in srgb, var(--tx) 5%, transparent); overflow:hidden}
.mm-i{position:absolute; left:0; right:0; bottom:0; border-radius:8px 8px 0 0;
  background:color-mix(in srgb, var(--acc) 42%, transparent);
  transition:height .5s cubic-bezier(.2,.8,.3,1)}
.mm-p{position:absolute; left:0; right:0; bottom:0; border-radius:8px 8px 0 0;
  background:linear-gradient(180deg, var(--ok), color-mix(in srgb, var(--ok) 72%, var(--acc)));
  transition:height .5s cubic-bezier(.2,.8,.3,1) .08s}
.mm-i.rel{background:linear-gradient(180deg, var(--acc), #FF8256)}
.mm-l{font-size:11px; color:var(--tx-dim); white-space:nowrap; font-family:var(--mono)}

@media(max-width:760px){
  /* flex-basis 150px задан по ГЛАВНОЙ оси: развернув ряд в колонку, мы
     превратили ширину в высоту, и три числа занимали пол-экрана */
  /* на телефоне плитка становится строкой: подпись слева, число справа —
     четыре отрезка занимают 4 строки вместо половины экрана */
  .cy-row{flex-direction:column}
  .cy-p{flex:0 0 auto; display:grid; grid-template-columns:1fr auto auto; align-items:baseline;
    gap:4px 8px; padding:11px 14px}
  .cy-p .cy-l{grid-column:1; align-self:center}
  .cy-p b{grid-column:2; font-size:19px}
  .cy-u{grid-column:3; margin-top:0}
  .cy-n{grid-column:1 / -1; margin-top:1px}
  .cy-ar{transform:rotate(90deg); align-self:center}
  .mm-row{height:112px; gap:7px}
}
@media(prefers-reduced-motion:reduce){
  .mm-i, .mm-p{transition:none}
}


/* ═══ ХОД ЗАГРУЗКИ ════════════════════════════════════════════════════════
   Файл до гигабаита грузится минутами. Без признака жизни человек решает, что
   зависло, и жмёт ещё раз — получаются два одинаковых вложения. Полоска
   показывает процент и сколько уже ушло. */
.uptoast{
  position:fixed; left:50%; bottom:26px; transform:translate(-50%, 14px);
  z-index:120; min-width:260px; max-width:min(420px, calc(100vw - 32px));
  padding:12px 16px 13px; border-radius:14px;
  background:var(--panel); border:1px solid var(--line2);
  box-shadow:0 18px 44px -18px rgba(0,0,0,.6);
  opacity:0; transition:opacity .22s, transform .22s cubic-bezier(.2,.8,.3,1);
}
.uptoast.on{opacity:1; transform:translate(-50%, 0)}
.up-n{font-size:13px; color:var(--tx); margin-bottom:8px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.up-b{height:6px; border-radius:999px; overflow:hidden;
  background:color-mix(in srgb, var(--tx) 10%, transparent)}
.up-b i{display:block; height:100%; width:0; border-radius:999px;
  background:linear-gradient(90deg, var(--acc), #FF8256); transition:width .18s linear}
.up-s{margin-top:7px; font-family:var(--mono); font-size:11.5px; color:var(--tx-dim);
  font-variant-numeric:tabular-nums}
@media(max-width:560px){ .uptoast{left:12px; right:12px; transform:none; max-width:none}
  .uptoast.on{transform:none} }
@media(prefers-reduced-motion:reduce){
  .uptoast{transition:opacity .01s} .up-b i{transition:none}
}


/* Работа, удалённая после выкладки: состав релиза — это факт, поэтому строка
   остаётся, но вести по ней некуда. То же у решения со ссылкой на задачу. */
.rl-tk.gone, .dc-lnk.gone{opacity:.55; cursor:default; text-decoration:line-through}
.rl-tk.gone .typedot{background:var(--tx-dim)}
.dc-lnk.gone{color:var(--tx-dim)}

/* ── Расход вычислительных мощностей ИИ ──────────────────────────────────
   Раздел читают, а не листают: сначала итог, потом задачи по убыванию цены,
   потом объяснение, почему объём и деньги — разные величины. Цветом отмечена
   только денежная плитка; полосы — приглушённый акцент, они шкала, а не акцент. */
.ai-grid{display:grid; grid-template-columns:repeat(auto-fit, minmax(190px, 1fr)); gap:12px; margin-bottom:12px}
.ai-t{background:var(--panel); border:1px solid var(--line); border-radius:var(--bd-r, 14px);
  padding:15px 17px; display:flex; flex-direction:column; gap:4px}
.ai-l{font-size:11px; letter-spacing:.07em; text-transform:uppercase; color:var(--tx-dim)}
.ai-v{font-family:var(--mono); font-size:21px; font-variant-numeric:tabular-nums; letter-spacing:-.01em;
  display:flex; align-items:baseline; gap:7px}
.ai-v i{font-style:normal; font-size:11.5px; color:var(--tx-mut); font-family:inherit; letter-spacing:.05em}
.ai-v.ai-sm{font-size:15px}
.ai-money .ai-v{color:var(--acc)}

.ai-rows{display:flex; flex-direction:column; margin-top:4px}
.ai-row{display:grid; grid-template-columns:minmax(0,1fr) auto 92px auto auto; gap:12px; align-items:center;
  padding:11px 4px; background:none; border:0; border-top:1px solid var(--line); width:100%;
  text-align:left; color:inherit; font:inherit; cursor:pointer; transition:background .14s}
.ai-row:first-child{border-top:0}
.ai-row:hover{background:color-mix(in srgb, var(--tx) 4%, transparent)}
.ai-row:focus-visible{outline:2px solid var(--acc); outline-offset:-2px}
.ai-rt{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:13.5px}
.ai-rd{font-size:11.5px; color:var(--tx-mut); white-space:nowrap; font-variant-numeric:tabular-nums}
.ai-rb{height:8px; border-radius:999px; background:color-mix(in srgb, var(--tx) 8%, transparent); overflow:hidden}
.ai-rb i{display:block; height:100%; width:var(--w); border-radius:999px;
  background:color-mix(in srgb, var(--acc) 55%, transparent)}
.ai-rk{font-family:var(--mono); font-size:12.5px; color:var(--tx-mut); font-variant-numeric:tabular-nums; white-space:nowrap}
.ai-ra{font-family:var(--mono); font-size:13.5px; font-variant-numeric:tabular-nums; white-space:nowrap}
.ai-sum{display:flex; justify-content:space-between; align-items:baseline; gap:12px;
  border-top:2px solid color-mix(in srgb, var(--tx) 22%, transparent); margin-top:6px; padding-top:10px;
  font-size:13px; color:var(--tx-mut)}
.ai-sum b{font-family:var(--mono); font-size:15px; color:var(--tx); font-variant-numeric:tabular-nums}

.ai-cats{display:flex; flex-direction:column; gap:10px; margin-top:6px}
.ai-cat{display:grid; grid-template-columns:minmax(0,1fr) 96px auto; gap:12px; align-items:center}
.ai-ct{font-size:13px; display:flex; flex-direction:column; gap:2px; min-width:0}
.ai-ct i{font-style:normal; font-size:11.5px; color:var(--tx-mut)}
.ai-cb{height:8px; border-radius:999px; background:color-mix(in srgb, var(--tx) 8%, transparent); overflow:hidden}
.ai-cb i{display:block; height:100%; width:var(--w); min-width:2px; border-radius:999px;
  background:color-mix(in srgb, var(--acc) 45%, transparent)}
.ai-cv{font-family:var(--mono); font-size:13px; font-variant-numeric:tabular-nums; white-space:nowrap;
  display:flex; align-items:baseline; gap:8px}
.ai-cv i{font-style:normal; font-size:11.5px; color:var(--tx-mut)}
.ai-note{margin:12px 0 0; font-size:12.5px; color:var(--tx-mut); max-width:78ch}

.ai-days{display:flex; align-items:flex-end; gap:6px; height:110px; margin-top:8px; overflow-x:auto; padding-bottom:2px}
.ai-day{display:flex; flex-direction:column; align-items:center; justify-content:flex-end; gap:6px;
  height:100%; flex:1 0 26px; min-width:26px}
.ai-day i{display:block; width:100%; height:var(--h); border-radius:4px 4px 0 0;
  background:color-mix(in srgb, var(--acc) 42%, transparent); transition:background .14s}
.ai-day:hover i{background:color-mix(in srgb, var(--acc) 70%, transparent)}
.ai-day b{font-family:var(--mono); font-size:10px; font-weight:400; color:var(--tx-dim); white-space:nowrap}

.ai-plist{display:flex; flex-direction:column; margin-top:4px}
.ai-p{display:grid; grid-template-columns:minmax(0,1fr) auto auto; gap:12px; align-items:baseline;
  padding:9px 4px; border-top:1px solid var(--line); font-size:13.5px}
.ai-p:first-child{border-top:0}
.ai-p.on .ai-pn{font-weight:600}
.ai-pn{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ai-pk{font-family:var(--mono); font-size:12.5px; color:var(--tx-mut); font-variant-numeric:tabular-nums}
.ai-pa{font-family:var(--mono); font-size:13.5px; font-variant-numeric:tabular-nums}

.ai-meth ul{margin:6px 0 0; padding-left:18px; display:flex; flex-direction:column; gap:6px;
  font-size:13px; color:var(--tx-mut); max-width:82ch}
.ai-empty{padding:22px 20px}
.ai-empty p{margin:8px 0 0; color:var(--tx-mut); font-size:13.5px; max-width:70ch}

@media(max-width:640px){
  .ai-row{grid-template-columns:minmax(0,1fr) auto; row-gap:6px}
  .ai-rd{grid-column:1; font-size:11px}
  .ai-rb{grid-column:1 / -1; order:5}
  .ai-rk{order:4}
  .ai-cat{grid-template-columns:minmax(0,1fr) auto; row-gap:6px}
  .ai-cb{grid-column:1 / -1; order:3}
}
.ai-share p{margin:6px 0 12px; font-size:13px; color:var(--tx-mut); max-width:70ch}
.rl-list{display:flex; flex-direction:column; gap:2px; margin-bottom:14px}
.rl-p{display:grid; grid-template-columns:auto minmax(0,1fr) auto; gap:10px; align-items:center;
  padding:8px 10px; border:1px solid var(--line); border-radius:10px; cursor:pointer; font-size:13.5px}
.rl-p:hover{border-color:color-mix(in srgb, var(--acc) 45%, var(--line))}
.rl-p i{font-style:normal; font-size:12px; color:var(--tx-mut); font-family:var(--mono); white-space:nowrap}
.rl-p span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.ai-acts{display:flex; flex-wrap:wrap; gap:10px; margin-bottom:16px}   /* кнопки прилипали к плиткам */

/* ── Шапка «Отчёта за период» ────────────────────────────────────────────
   Поля жили отдельно от системы полей кабинета: select рисовался нативным
   (в тёмной теме — белый, с системной стрелкой), даты были на 36px, кнопки
   на 32 — строка выглядела разъехавшейся. Подключаем к тем же токенам и
   выравниваем всё по одной высоте. */
/* Страница отчёта — прямые дети #view без обёртки, поэтому у неё не было ни
   верхнего воздуха, ни боковых полей: полоса фильтров начиналась вплотную к
   топбару и левее содержимого карточки. Даём те же 24px, что и у прочих экранов. */
.rep-bar{gap:10px 12px; margin:20px 24px 14px}
.rep{margin:0 24px 24px}
@media(max-width:760px){ .rep-bar{margin:14px 16px 12px} .rep{margin:0 16px 16px} }
@media print{ .rep-bar{margin:0} .rep{margin:0} }
.rep-f input,.rep-f select{
  height:34px; padding:0 10px; font:inherit; font-size:13px;
  background-color:var(--fi-bg); color:var(--tx);
  border:1px solid var(--fi-line); border-radius:var(--fi-r);
  box-shadow:var(--fi-well); color-scheme:var(--fi-scheme);
  transition:border-color .15s ease, background-color .15s ease;
}
.rep-f select{
  -webkit-appearance:none; -moz-appearance:none; appearance:none;
  background-image:var(--fi-ic-chev); background-repeat:no-repeat;
  background-position:right 10px center; background-size:16px 16px;
  padding-right:34px; cursor:pointer; max-width:min(300px, 42vw); text-overflow:ellipsis;
}
.rep-f select option{background:var(--panel); color:var(--tx)}   /* выпадашку рисует ОС */
.rep-f input:hover,.rep-f select:hover{border-color:var(--fi-line-hover); background-color:var(--fi-bg-hover)}
.rep-f input:focus,.rep-f select:focus{border-color:var(--acc); background-image:var(--fi-ic-chev-on)}
.rep-f input[type=date]{min-width:132px}
.rep-bar .btn{height:34px; display:inline-flex; align-items:center}
@media(max-width:900px){
  .rep-bar .sp{display:none}                 /* распорка на узком экране рвала строку пополам */
  .rep-f{flex:1 1 auto}
  .rep-f select{max-width:none; width:100%}
}

/* ── Ведомость ИИ: страница всех проектов договора ── */
.ai-lps{display:flex; flex-direction:column; gap:18px; margin-top:6px}
.ai-lp{display:flex; flex-direction:column; gap:8px}
.ai-lph{display:flex; align-items:baseline; justify-content:space-between; gap:12px}
.ai-lpn{font-size:14.5px; font-weight:600}
.ai-lpm{font-family:var(--mono); font-size:12.5px; color:var(--tx-mut);
  font-variant-numeric:tabular-nums; white-space:nowrap}
.ai-lp .ai-rows{border-top:1px solid var(--line); padding-top:2px}

/* ── Ведомость ИИ: страница-документ в кабинете ──────────────────────────
   Клиент приходит сюда с одним вопросом — за что заплачено. Порядок ответа:
   шапка с условиями, итоги, разбор операций по цене, проекты, задачи, дни. */
.ai-doc{display:flex; flex-direction:column; gap:16px}
.ai-doc .ai-grid{margin:0}
.ai-hero{display:flex; flex-wrap:wrap; align-items:flex-start; justify-content:space-between; gap:20px}
.ai-hero-t{min-width:min(320px, 100%); flex:1 1 340px}
.ai-hero h2{margin:0 0 6px; font-size:19px; font-weight:800; letter-spacing:-.01em}
.ai-hero p{margin:0; font-size:13.5px; color:var(--tx-mut); max-width:62ch}
.ai-req{display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:2px 18px;
  margin:0; flex:0 1 auto}
.ai-req > div{display:flex; flex-direction:column; gap:3px; padding:6px 0}
.ai-req dt{font-size:11px; letter-spacing:.06em; text-transform:uppercase; color:var(--tx-dim)}
.ai-req dd{margin:0; font-family:var(--mono); font-size:14px; font-variant-numeric:tabular-nums; white-space:nowrap}

/* полоса стоимости по видам операций: цвет здесь — шкала, а не смысл,
   поэтому берём один акцент четырьмя ступенями и подписываем каждую */
.ai-seg{display:flex; gap:2px; height:24px; margin:12px 0 14px}
.ai-seg i{display:block; height:100%; border-radius:2px}
.ai-seg i:first-child{border-radius:6px 2px 2px 6px}
.ai-seg i:last-child{border-radius:2px 6px 6px 2px}
/* одна шкала, четыре ступени прозрачности: смесь с тёмным токеном давала
   в светлой теме тёмно-коричневый третий сегмент и рвала последовательность */
.ai-s1{background:var(--acc)}
.ai-s2{background:color-mix(in srgb, var(--acc) 62%, transparent)}
.ai-s3{background:color-mix(in srgb, var(--acc) 38%, transparent)}
.ai-s4{background:color-mix(in srgb, var(--acc) 20%, transparent)}
.ai-dot{width:9px; height:9px; border-radius:3px; flex:none; display:inline-block; margin-right:8px}
.ai-cat{grid-template-columns:minmax(0,1fr) 96px auto auto}
.ai-ct{flex-direction:row; flex-wrap:wrap; align-items:baseline}
.ai-ct i{flex:1 1 100%; margin-left:17px}
.ai-cr{font-family:var(--mono); font-size:13.5px; font-variant-numeric:tabular-nums; white-space:nowrap;
  min-width:104px; text-align:right; display:flex; flex-direction:column; gap:1px}
.ai-cr i{font-style:normal; font-size:11.5px; color:var(--tx-mut)}

/* таблица проектов: строки на сетке, чтобы числа стояли колонкой */
.ai-ptbl{display:flex; flex-direction:column; margin-top:4px}
.ai-ptr{display:grid; grid-template-columns:minmax(0,1fr) 72px 108px 84px 116px; gap:10px;
  align-items:baseline; padding:9px 4px; border-top:1px solid var(--line); font-size:13.5px}
.ai-ptr .num{text-align:right; font-family:var(--mono); font-size:13px;
  font-variant-numeric:tabular-nums; white-space:nowrap}
.ai-pth{border-top:0; font-size:11px; letter-spacing:.06em; text-transform:uppercase; color:var(--tx-dim)}
.ai-pth .num{font-family:inherit; font-size:11px; letter-spacing:.06em}
.ai-ptf{border-top:2px solid color-mix(in srgb, var(--tx) 22%, transparent); font-weight:700}
.ai-ptr span:first-child{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}

@media(max-width:720px){
  .ai-cat{grid-template-columns:minmax(0,1fr) auto; row-gap:6px}
  .ai-cat .ai-cb{grid-column:1 / -1; order:3}
  .ai-cr{min-width:0; flex-direction:row; gap:8px; align-items:baseline}
  .ai-ptr{grid-template-columns:minmax(0,1fr) 64px 92px; row-gap:4px}
  .ai-ptr span:nth-child(4){display:none}          /* доля — вычислимая, на телефоне лишняя */
  .ai-hero{gap:14px}
}

/* ── Ведомость ИИ: усиление типографики и ритма ──────────────────────────
   Первая версия была собрана «по-табличному»: подписи слева, цифры у правого
   края, а между ними полоса в 96px и пустота на пол-экрана. Строки читаются
   по горизонтали, поэтому колонки получают долю ширины, а не фиксированные
   пиксели; кегль поднят — это документ, который читают, а не панель приборов. */
.ai-doc{font-size:15px; gap:18px}
.ai-doc .dcard{padding:22px 24px}
.ai-doc .dcard h3{font-size:17px; font-weight:800; letter-spacing:-.01em; margin:0 0 14px}
.ai-doc .ai-note{font-size:14px; line-height:1.55; max-width:88ch; margin:0 0 16px}

/* шапка: текст и условия — две колонки с общей линией, без провала посередине */
.ai-hero{padding:24px 26px; gap:26px}
.ai-hero h2{font-size:22px; margin-bottom:8px}
.ai-hero p{font-size:14.5px; line-height:1.55}
.ai-req{grid-template-columns:repeat(auto-fit, minmax(132px, 1fr)); gap:14px 22px;
  border-left:1px solid var(--line); padding-left:24px}
.ai-req dt{font-size:11.5px}
.ai-req dd{font-size:15px}

/* плитки итогов */
.ai-doc .ai-t{padding:17px 19px}
.ai-doc .ai-l{font-size:11.5px}
.ai-doc .ai-v{font-size:24px}
.ai-doc .ai-money .ai-v{font-size:27px}

/* «За что вы платите»: полоса тянется, цифры стоят колонками */
.ai-doc .ai-cats{gap:14px}
.ai-doc .ai-cat{grid-template-columns:minmax(180px, 1.3fr) minmax(120px, 1fr) 132px 116px;
  gap:18px; align-items:center; padding:4px 0}
.ai-doc .ai-ct{font-size:15px; font-weight:600}
.ai-doc .ai-ct i{font-size:13px; font-weight:400; margin-top:2px}
.ai-doc .ai-cb{height:10px}
.ai-doc .ai-cv{font-size:14.5px; flex-direction:column; align-items:flex-end; gap:2px; text-align:right}
.ai-doc .ai-cv i{font-size:12px}
.ai-doc .ai-cr{font-size:16px; font-weight:600; min-width:0}
.ai-doc .ai-cr i{font-size:12px}
.ai-seg{height:28px; margin:6px 0 20px}

/* таблица проектов */
.ai-doc .ai-ptr{grid-template-columns:minmax(0,1fr) 84px 132px 96px 140px; gap:14px;
  padding:12px 4px; font-size:15px}
.ai-doc .ai-ptr .num{font-size:14.5px}
.ai-doc .ai-pth{font-size:11.5px}
.ai-doc .ai-pth .num{font-size:11.5px}

/* задачи: название и полоса делят ширину, цифры — колонкой у правого края */
.ai-doc .ai-lps{gap:26px}
.ai-doc .ai-lpn{font-size:16px}
.ai-doc .ai-lpm{font-size:13.5px}
.ai-doc .ai-row{grid-template-columns:minmax(160px, 1.6fr) auto minmax(90px, .9fr) 108px 108px;
  gap:16px; padding:13px 4px}
.ai-doc .ai-rt{font-size:15px}
.ai-doc .ai-rd{font-size:12.5px}
.ai-doc .ai-rb{height:9px}
.ai-doc .ai-rk{font-size:13.5px; text-align:right}
.ai-doc .ai-ra{font-size:15px; font-weight:600; text-align:right}

/* дни */
.ai-doc .ai-days{height:132px; gap:8px}
.ai-doc .ai-day b{font-size:11px}

/* «Как считаем»: было прижато к краю карточки маркерами списка — теперь
   это пронумерованные строки с воздухом и нормальным кеглем */
.ai-meth ul{list-style:none; padding:0; margin:0; gap:0; max-width:96ch; counter-reset:m}
.ai-meth li{position:relative; counter-increment:m; padding:14px 0 14px 46px;
  border-top:1px solid var(--line); font-size:15px; line-height:1.55; color:var(--tx)}
.ai-meth li:first-child{border-top:0; padding-top:2px}
.ai-meth li::before{content:counter(m); position:absolute; left:0; top:12px;
  width:28px; height:28px; border-radius:9px; display:grid; place-items:center;
  background:color-mix(in srgb, var(--acc) 16%, transparent); color:var(--acc);
  font-family:var(--mono); font-size:12.5px; font-weight:600}
.ai-meth li:first-child::before{top:0}

@media(max-width:900px){
  .ai-hero{padding:20px}
  .ai-req{border-left:0; padding-left:0; border-top:1px solid var(--line); padding-top:16px; width:100%}
  .ai-doc .ai-cat{grid-template-columns:minmax(0,1fr) auto; row-gap:8px}
  .ai-doc .ai-cat .ai-cb{grid-column:1 / -1; order:3}
  .ai-doc .ai-cv{flex-direction:row; gap:10px; align-items:baseline}
  .ai-doc .ai-cr{flex-direction:row; gap:10px}
  .ai-doc .ai-row{grid-template-columns:minmax(0,1fr) auto; row-gap:6px}
}

/* Ритм колонок: при коротких названиях доля 1.3fr оставляла полосе край экрана,
   и строка распадалась на «подпись слева — цифры справа». Ширину забирает полоса. */
.ai-doc .ai-hero{display:grid; grid-template-columns:minmax(300px, 1.15fr) minmax(260px, .85fr);
  align-items:start; gap:0 30px}
.ai-doc .ai-req{grid-template-columns:repeat(2, minmax(120px, 1fr)); gap:16px 24px}
.ai-doc .ai-cat{grid-template-columns:minmax(190px, .85fr) minmax(150px, 1.6fr) 128px 112px}
.ai-doc .ai-row{grid-template-columns:minmax(150px, 1.05fr) auto minmax(110px, 1.35fr) 104px 104px}
@media(max-width:900px){
  .ai-doc .ai-hero{grid-template-columns:1fr; gap:18px}
  .ai-doc .ai-req{grid-template-columns:repeat(auto-fit, minmax(130px, 1fr))}
}
/* описание операции не должно ломаться пополам на широком экране */
.ai-doc .ai-cat{grid-template-columns:minmax(230px, 1fr) minmax(150px, 1.5fr) 128px 112px}
.ai-doc .ai-lp + .ai-lp{padding-top:6px}

/* ── Ведомость ИИ: цена операции, выводы и формула ───────────────────────── */
.ai-doc .ai-s{font-size:12px; color:var(--tx-mut); margin-top:4px; line-height:1.35}
.ai-doc .ai-s.up{color:var(--warn)}
.ai-doc .ai-s.down{color:var(--ok)}

/* таблица операций: шесть колонок, числа моноширинные, подписи — под названием */
.ai-opt{display:flex; flex-direction:column; margin-top:4px}
.ai-opr{display:grid; grid-template-columns:minmax(220px, 1.5fr) 104px 104px 108px 124px 104px;
  gap:14px; align-items:baseline; padding:13px 4px; border-top:1px solid var(--line); font-size:15px}
.ai-opr .num{text-align:right; font-family:var(--mono); font-size:14.5px;
  font-variant-numeric:tabular-nums; white-space:nowrap}
.ai-opr .num.dim{color:var(--tx-mut); font-size:13px}
.ai-opr .num.strong{font-weight:700}
.ai-oph{border-top:0; font-size:11.5px; letter-spacing:.06em; text-transform:uppercase; color:var(--tx-dim)}
.ai-oph .num{font-family:inherit; font-size:11.5px; letter-spacing:.06em}
.ai-opf{border-top:2px solid color-mix(in srgb, var(--tx) 22%, transparent); font-weight:700}
.ai-opn{display:flex; flex-wrap:wrap; align-items:baseline; font-weight:600; min-width:0}
.ai-opn i{flex:1 1 100%; margin-left:17px; font-style:normal; font-size:13px;
  font-weight:400; color:var(--tx-mut); margin-top:2px}

/* выводы: три коротких утверждения с крупной цифрой */
.ai-facts{display:grid; grid-template-columns:repeat(auto-fit, minmax(240px, 1fr)); gap:14px; margin-top:4px}
.ai-fact{border:1px solid var(--line); border-radius:14px; padding:16px 18px;
  display:flex; flex-direction:column; gap:4px; background:color-mix(in srgb, var(--tx) 3%, transparent)}
.ai-fact b{font-family:var(--mono); font-size:23px; font-weight:700; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums; color:var(--acc)}
.ai-fact span{font-size:13px; letter-spacing:.05em; text-transform:uppercase; color:var(--tx-dim)}
.ai-fact i{font-style:normal; font-size:13.5px; line-height:1.5; color:var(--tx-mut); margin-top:4px}

/* формула: из чего складывается строка ведомости */
.ai-formula{display:flex; flex-wrap:wrap; align-items:center; gap:8px 10px; margin:0 0 20px;
  padding:16px 18px; border:1px dashed var(--line); border-radius:14px;
  background:color-mix(in srgb, var(--acc) 4%, transparent)}
.ai-fx{padding:7px 12px; border-radius:10px; background:var(--panel); border:1px solid var(--line);
  font-size:13.5px; white-space:nowrap}
.ai-fx.res{background:color-mix(in srgb, var(--acc) 16%, transparent);
  border-color:color-mix(in srgb, var(--acc) 40%, var(--line)); font-weight:600}
.ai-formula i{font-style:normal; font-family:var(--mono); color:var(--tx-dim); font-size:15px}
.ai-meth li b{font-weight:700; color:var(--tx)}

@media(max-width:1100px){
  .ai-opr{grid-template-columns:minmax(180px, 1.3fr) 92px 92px 100px 112px 92px; gap:10px; font-size:14px}
}
@media(max-width:820px){
  .ai-opr{grid-template-columns:minmax(0,1fr) auto auto; row-gap:6px; padding:12px 4px}
  .ai-oph{display:none}                       /* на телефоне шапка колонок мешает больше, чем помогает */
  .ai-opr .num:nth-child(3),
  .ai-opr .num:nth-child(6){display:none}      /* доли считаются глазом по полосе выше */
  .ai-opn{flex:1 1 100%}
}

/* ── Переключатель проектов в шапке ──────────────────────────────────────
   Проекты переехали сюда из бокового меню: два десятка строк вытесняли
   разделы вниз, а переход между проектами всё равно начинался с прокрутки. */
.pswrap{position:relative; flex:none}
.psbtn{display:inline-flex; align-items:center; gap:9px; max-width:min(320px, 32vw);
  padding:8px 12px; border-radius:12px; border:1px solid var(--line);
  background:var(--panel); color:var(--tx); font:inherit; font-size:14px; cursor:pointer;
  transition:border-color .15s, background .15s}
.psbtn:hover{border-color:color-mix(in srgb, var(--acc) 45%, var(--line))}
.psbtn.on{border-color:color-mix(in srgb, var(--acc) 38%, var(--line))}
.psbtn:focus-visible{outline:2px solid var(--acc); outline-offset:2px}
.psbtn svg{width:16px; height:16px; flex:none; opacity:.75}
.psname{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-weight:600}
.pschev{font-style:normal; color:var(--tx-dim); font-size:11px; flex:none}

.psdrop{position:absolute; top:calc(100% + 8px); left:0; z-index:60; width:min(380px, 92vw);
  background:var(--panel); border:1px solid var(--line); border-radius:16px;
  box-shadow:0 18px 48px rgba(0,0,0,.34); overflow:hidden;
  display:flex; flex-direction:column; max-height:min(70vh, 560px)}
.psdrop.hidden{display:none}
.psq{padding:12px 12px 8px}
.psq input{width:100%; height:38px; padding:0 12px; font:inherit; font-size:14px;
  background:var(--fi-bg); color:var(--tx); border:1px solid var(--fi-line);
  border-radius:11px; color-scheme:var(--fi-scheme)}
.psq input:focus{outline:none; border-color:var(--acc)}
.pslist{overflow:auto; padding:0 8px 8px; display:flex; flex-direction:column; gap:2px}
.psg{font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--tx-dim);
  padding:10px 8px 6px}
.psitem{display:grid; grid-template-columns:minmax(0,1fr) auto auto; gap:10px; align-items:center;
  width:100%; padding:9px 10px; border:0; border-radius:11px; background:none; color:inherit;
  font:inherit; font-size:14px; text-align:left; cursor:pointer}
.psitem:hover{background:color-mix(in srgb, var(--tx) 6%, transparent)}
.psitem.on{background:color-mix(in srgb, var(--acc) 14%, transparent)}
.psitem:focus-visible{outline:2px solid var(--acc); outline-offset:-2px}
.psi-n{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.psi-m{display:inline-flex; align-items:center; gap:7px; color:var(--tx-mut); font-size:12px;
  font-family:var(--mono); font-variant-numeric:tabular-nums}
.psitem .pin{opacity:.35; font-size:13px; line-height:1; transition:opacity .15s, color .15s}
.psitem:hover .pin{opacity:.7}
.psitem .pin.on{opacity:1; color:var(--acc)}
.psempty{padding:18px 10px; color:var(--tx-mut); font-size:13.5px; text-align:center}
.psfoot{border-top:1px solid var(--line); padding:8px; display:flex; flex-direction:column; gap:2px}
.psall{display:flex; align-items:center; gap:10px; width:100%; padding:10px;
  border:0; border-radius:11px; background:none; color:var(--tx); font:inherit; font-size:13.5px;
  cursor:pointer; text-align:left}
.psall:hover{background:color-mix(in srgb, var(--tx) 6%, transparent)}
.psall svg{width:16px; height:16px; opacity:.7; flex:none}

@media(max-width:760px){
  .psbtn{max-width:44vw; padding:7px 10px}
  .psbtn svg{display:none}
  /* панель кладём по краям экрана: у кнопки левый край далеко от нуля, и
     выпадашка фиксированной ширины уезжала за правую кромку телефона */
  .psdrop{position:fixed; left:8px; right:8px; top:calc(var(--topbar-h, 62px) + 6px);
    width:auto; max-height:70vh}
}
.hbar-new{margin-left:auto; flex:none; display:inline-flex; align-items:center; gap:7px}
.hbar-new svg{width:15px; height:15px}
@media(max-width:640px){ .hbar-new{margin-left:0; width:100%; justify-content:center} }
