/* ==========================================================================
   Edit.OS — компоненты
   Требует tokens.css. Сырых цветов и размеров здесь нет ни одного: всё через
   переменные, иначе тёмная тема не переключится.

   Порядок: основа → каркас → навигация → шапка → кнопки → расход → метки →
   карточки → пустые состояния → формы → ход работы → сообщения → окно →
   план в трёх уровнях → история → печать → телефон.

   ── ПОКАЗ СОСТОЯНИЙ ───────────────────────────────────────────────────────
   У каждого интерактивного правила рядом с псевдоклассом стоит класс-двойник:
   :hover / .is-hover, :active / .is-active, :focus-visible / .is-focus.
   Он нужен витрине: снимок статичен, а состояния показать надо все.
   В продукте классы-двойники не используются.
   ========================================================================== */

/* ==========================================================================
   1. ОСНОВА
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }

/* 🔴 ПЕРВОЕ ПРАВИЛО ФАЙЛА, И ОНО ВЫСТРАДАНО.
   Атрибут hidden рисуется правилом браузера [hidden]{display:none} — у него
   вес нулевого класса. Любое правило компонента вида .nav{display:flex} или
   .empty{display:flex} его перебивает, и спрятанный блок остаётся на экране.
   Поймано снимками кабинета: на экране первого входа висело боковое меню,
   а на пустом кабинете разом стояли и пустое состояние, и заполненные блоки.
   Чтение кода бесполезно — hidden там проставлен правильно.
   Место общее для всего продукта, поэтому правило живёт здесь, а не
   переписывается заново в каждом файле. */
[hidden] { display: none !important; }

html { font-size: 16px; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fz-md);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--font-head);
  line-height: var(--lh-tight);
  letter-spacing: -.01em;
  font-weight: var(--fw-semi);
  margin: 0;
  text-wrap: balance;
}

p { margin: 0; text-wrap: pretty; }

a { color: var(--accent-text); text-underline-offset: .18em; }
a:hover { text-decoration-thickness: 2px; }

/* Кольцо фокуса — одно на всю систему.
   Рисуется с просветом: просвет показывает подложку, поэтому кольцо мерится
   против неё, а не против самой кнопки. Кольцо вплотную к янтарной заливке
   в тёмной теме давало 1,60:1 — отброшено по замеру, а не по вкусу. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible,
.is-focus {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: var(--focus-offset);
  border-radius: var(--r-xs);
}
:where(a, button, input, select, textarea, summary, [tabindex]):focus:not(:focus-visible) {
  outline: none;
}
/* Окно прокрутки — тоже остановка на пути таба: внутри него скроллят стрелками.
   Браузер делает его фокусируемым сам и рисует своё кольцо толщиной в пиксель.
   Заменяем на наше. Поймано обходом страницы табом, а не чтением кода. */
.plan-scroll:focus-visible, .tbl-wrap:focus-visible {
  outline: var(--focus-w) solid var(--focus);
  outline-offset: var(--focus-offset);
}

/* 🔴 Куда попадает ЧУЖОЙ текст — там слово обязано ломаться.
   Поймано стресс-прогоном: слово без пробелов длиной в колонку
   («Самопрезентациякотораяневлезает…») уводило страницу вбок на 761 px
   при ширине 390. Пользователь такое пишет регулярно: хештег, ссылка,
   немецкое слово, склеенный заголовок. `anywhere`, а не `break-word`:
   только он влияет на минимальную ширину блока в сетке и во флексе. */
.card__title, .card__gist, .card__meta, .card__angles,
.plan-table .c-idea, .plan-table .c-hook,
.nav__item, .week__theme, .lane__theme, .lane__mon,
.empty__title, .empty__text, .empty__note,
.notice__title, .notice__text, .history__what,
.level__name, .page-head__title, .crumbs li,
.field__label, .field__why, .field__err, .spend__v, .sheet__title, .sheet__sub {
  overflow-wrap: anywhere;
  min-inline-size: 0;
}

.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.num  { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.dim  { color: var(--text-3); }
.hint { color: var(--text-3); font-size: var(--fz-xs); line-height: var(--lh-snug); }

/* Надзаголовок капителью: единственное место, где кегль опускается до 11 px.
   Разрядка обязательна — без неё капитель в 11 px слипается. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--fz-2xs);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-3);
  font-weight: var(--fw-bold);
}

.icon { inline-size: var(--icon); block-size: var(--icon); flex: 0 0 auto; }
.icon--sm { inline-size: var(--icon-sm); block-size: var(--icon-sm); }
.icon--lg { inline-size: var(--icon-lg); block-size: var(--icon-lg); }

.sr-only {
  position: absolute; inline-size: 1px; block-size: 1px;
  margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* 🔴 ГНЕЗДО, В КОТОРОЕ СОДЕРЖИМОЕ КЛАДЁТ КОД. Само оно ничего не рисует
   и в раскладке не участвует — участвует то, что в него положили.
   Без этого пустой <span> внутри флекс-строки становится флекс-элементом
   и сжимается ВМЕСТО метки: сама .chip честно объявлена несжимаемой
   (flex: 0 0 auto), а обёртка вокруг неё — нет. «Утверждено» рвалось
   на четыре строки и превращалось в зелёный кружок. Ловушка на любую
   динамическую вставку, а не на один экран; чтением кода не ловится —
   и разметка, и компонент по отдельности правильные.
   ⚠️ Гнездо, у которого есть СВОЯ оформленная коробка (заголовок экрана,
   полоса меток .card__marks), этим классом не помечается: оно рисует само. */
.slot { display: contents; }

/* ==========================================================================
   2. КАРКАС
   ========================================================================== */
.eos-shell {
  display: grid;
  grid-template-columns: var(--w-nav) minmax(0, 1fr);
  min-block-size: 520px;
  background: var(--bg);
  border: var(--bw) solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
}

/* 🔴 ВАРИАНТ «НА ВСЮ СТРАНИЦУ» — настоящий кабинет.
   Оболочка выше собрана под ВИТРИНУ: она стои́т врезкой внутри документа,
   поэтому у неё рамка, скругление и overflow:hidden. В кабинете это не
   работает: предок с overflow:hidden сам становится окном прокрутки, и
   приклеить боковое меню нечем — sticky цепляется за неподвижную коробку.
   Здесь оболочка распахнута на страницу, а меню липнет к верхней кромке.
   Отступ сверху задаётся переменной --shell-top: если над кабинетом стои́т
   своя полоса, её высоту меряют и кладут сюда. Зашитое число будет враньём —
   полоса на телефоне переносится в две-три строки. */
.eos-shell--page {
  overflow: visible;
  border: none;
  border-radius: 0;
  min-block-size: calc(100dvh - var(--shell-top, 0px));
}
@media (min-width: 861px) {
  .eos-shell--page > .nav {
    position: sticky;
    align-self: start;
    inset-block-start: var(--shell-top, 0px);
    /* Высота задаётся жёстко, а не потолком: у липкого меню высотой в своё
       содержимое правая граница обрывается посреди экрана и читается
       поломкой вёрстки. */
    block-size: calc(100dvh - var(--shell-top, 0px));
  }
}

/* 🔴 Меню спрятано (экран первого входа) или его нет в разметке вовсе —
   рабочая зона обязана занять всю ширину. Иначе она остаётся ВТОРЫМ
   элементом сетки, а достаётся ей ПЕРВАЯ колонка: те самые 232 px под меню.
   Экран «Кто вы» выходил узкой полосой посреди пустого холста в 1440.
   Поймано снимком; чтением кода не ловится — и разметка, и компонент
   по отдельности правильные, ломает сетка, из которой убрали участника. */
.eos-shell:not(:has(> .nav:not([hidden]))) { grid-template-columns: minmax(0, 1fr); }

.eos-main {
  min-inline-size: 0;
  padding: var(--s-7);
  display: flex;
  flex-direction: column;
  gap: var(--s-7);
}

/* ==========================================================================
   3. БОКОВОЕ МЕНЮ
   Без иконок разделов — намеренно. Шесть значков пришлось бы рисовать под
   единый стиль, а половина смыслов («Идеи», «Контент», «План») в 14 px
   различается только подписью. Ведёт глаз янтарная насечка активного пункта.
   ========================================================================== */
.nav {
  background: var(--surface-nav);
  border-inline-end: var(--bw) solid var(--line);
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
}

.nav__brand {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-6) var(--s-6) var(--s-5);
  font-family: var(--font-head);
  font-size: var(--fz-lg);
  font-weight: var(--fw-bold);
  letter-spacing: -.02em;
}
.nav__brand .dot {
  inline-size: 8px; block-size: 8px; border-radius: var(--r-pill);
  background: var(--accent); border: var(--bw) solid var(--accent-edge);
}

/* «Добавить мысль» живёт над списком разделов и остаётся на месте при
   прокрутке меню: она сквозная на всех экранах (UX-СПЕЦ §2, С-3). */
.nav__add { padding: 0 var(--s-6) var(--s-6); }
.nav__add .btn { inline-size: 100%; }

.nav__scroll { flex: 1 1 auto; overflow: auto; padding-block-end: var(--s-6); }

/* 🔴 СКЛАДНОЕ МЕНЮ. Необязательная обёртка <details class="nav__fold"> вокруг
   списка разделов и подвала. На большом экране её не видно вовсе — меню
   выглядит и работает как раньше. На телефоне список сворачивается в одну
   строку «Меню», и это не украшение: 21 пункт занимает 944 px, а плита меню
   стоит НАД содержимым на каждом экране. Без сворачивания человек проматывает
   навигацию перед каждым разделом, а шестнадцать пунктов из двадцати одного
   прячутся во вложенную прокрутку внутри страницы, которая и сама
   прокручивается: видно ровно пять. Замерено, а не прикинуто.

   Почему <details>, а не своя кнопка: состояние «раскрыто» держит браузер,
   клавиатура и чтение с экрана работают без единой строки скрипта.

   Два правила раскладки вместо одного — намеренно. В новых движках содержимое
   <details> живёт в псевдоэлементе ::details-content, в старых остаётся прямыми
   детьми. Здесь описаны оба случая: движок берёт то, что понимает, и меню
   тянется на всю высоту в любом. */
.nav__fold { flex: 1 1 auto; min-block-size: 0; display: flex; flex-direction: column; }
.nav__fold::details-content { display: flex; flex-direction: column; flex: 1 1 auto; min-block-size: 0; }
.nav__fold[open]::details-content { content-visibility: visible; }
/* Строка «Меню» нужна только на телефоне: на большом экране список и так виден. */
.nav__toggle { display: none; }

.nav__group { padding-inline: var(--s-4); }
.nav__group + .nav__group { margin-block-start: var(--s-1); }

.nav__item {
  display: flex; align-items: center; gap: var(--s-4);
  min-block-size: var(--h-nav-item);
  padding: 0 var(--s-4);
  border: none; background: none;
  inline-size: 100%;
  font: inherit; font-size: var(--fz-md); color: var(--text-2);
  text-align: start; text-decoration: none;
  border-radius: var(--r-sm);
  cursor: pointer;
  position: relative;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.nav__item:hover, .nav__item.is-hover { background: var(--surface-hover); color: var(--text); }
.nav__item:active, .nav__item.is-active { background: var(--surface-press); }
/* Счётчик под курсором поднимается на ступень: приглушённый серый на подсветке
   даёт 4,06:1 и выпадает из порога текста, второстепенный — 6,51:1. */
.nav__item:hover .nav__count, .nav__item.is-hover .nav__count,
.nav__item:active .nav__count, .nav__item.is-active .nav__count { color: var(--text-2); }

/* Текущий раздел: насечка + начертание + цвет. Три признака, а не один цвет. */
.nav__item[aria-current="page"],
.nav__item.is-current {
  color: var(--text);
  font-weight: var(--fw-semi);
  background: var(--accent-tint);
}
.nav__item[aria-current="page"]::before,
.nav__item.is-current::before {
  content: ""; position: absolute; inset-block: 4px; inset-inline-start: -4px;
  inline-size: 3px; border-radius: var(--r-pill); background: var(--accent);
}

.nav__count {
  margin-inline-start: auto;
  font-family: var(--font-mono); font-size: var(--fz-2xs);
  color: var(--text-3); font-variant-numeric: tabular-nums;
}

.nav__sub { display: flex; flex-direction: column; padding-inline-start: var(--s-5); }
.nav__sub .nav__item { min-block-size: var(--h-nav-sub); font-size: var(--fz-sm); color: var(--text-3); }
.nav__sub .nav__item:hover, .nav__sub .nav__item.is-hover { color: var(--text); }
.nav__sub .nav__item[aria-current="page"],
.nav__sub .nav__item.is-current { color: var(--text); background: var(--accent-tint); }

.nav__foot {
  border-block-start: var(--bw) solid var(--line);
  padding: var(--s-4);
  display: flex; flex-direction: column; gap: var(--s-1);
}
.nav__wallet { display: flex; align-items: baseline; gap: var(--s-3); }
.nav__wallet b { font-family: var(--font-mono); font-weight: var(--fw-bold); color: var(--text); }

/* ==========================================================================
   4. ШАПКА ЭКРАНА: крошки + заголовок + правая сторона
   Крошки показывают путь, но НЕ заменяют заголовок — он стоит и там, и там
   (UX-СПЕЦ §2.2, «где я»).
   ========================================================================== */
.page-head { display: flex; flex-direction: column; gap: var(--s-3); }

.crumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3);
  font-size: var(--fz-xs); color: var(--text-3);
  margin: 0; padding: 0; list-style: none;
}
.crumbs li { display: flex; align-items: center; gap: var(--s-3); }
.crumbs li + li::before { content: "→"; color: var(--text-3); }
.crumbs a { color: var(--text-3); text-decoration: none; }
.crumbs a:hover { color: var(--text); text-decoration: underline; }
.crumbs [aria-current] { color: var(--text-2); }

.page-head__bar {
  display: flex; align-items: center; gap: var(--s-6); flex-wrap: wrap;
}
.page-head__title { font-size: var(--fz-2xl); letter-spacing: -.02em; }
.page-head__aside { margin-inline-start: auto; display: flex; align-items: center; gap: var(--s-5); }

.section-head {
  display: flex; align-items: baseline; gap: var(--s-5); flex-wrap: wrap;
  margin-block-end: var(--s-5);
}
.section-head h2 { font-size: var(--fz-xl); }

/* ==========================================================================
   5. КНОПКИ
   Четыре вида плюс пятый особый — с ценой.
   Опасная сделана обводкой, а не красной заливкой: в рабочем инструменте
   сплошной красный занят сообщением об ошибке, и заливка спорила бы с ним.

   🔴 НАЖАТИЕ ОБЯЗАНО ОТЛИЧАТЬСЯ ОТ НАВЕДЕНИЯ, и не на глаз, а числом.
   В инструменте, за которым сидят часами, нажатие — единственное подтверждение,
   что клик дошёл: отклик страницы придёт позже, а палец уже отпущен. Первая
   версия давала между наведением и нажатием 1,10–1,22:1 у всех четырёх видов,
   а у опасной фон вообще не менялся — двигалась только рамка. Теперь ступени
   считает kontrast.py, раздел «соседние состояния»: 1,2:1 покой → наведение,
   1,3:1 наведение → нажатие.
   ========================================================================== */
.btn {
  --btn-h: var(--h-control);
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--s-3);
  block-size: var(--btn-h);
  padding: var(--pad-control);
  border: var(--bw) solid transparent;
  border-radius: var(--r-sm);
  background: none;
  font-family: var(--font-body);
  font-size: var(--fz-md);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}
.btn--lg { --btn-h: var(--h-control-lg); font-size: var(--fz-md); padding: 0 var(--s-7); }
.btn--sm { --btn-h: var(--h-control-sm); font-size: var(--fz-sm); padding: 0 var(--s-5); }
.btn--wide { inline-size: 100%; }

/* основная */
.btn--primary {
  background: var(--accent); border-color: var(--accent-edge); color: var(--accent-ink);
  font-weight: var(--fw-semi);
}
.btn--primary:hover,  .btn--primary.is-hover  { background: var(--accent-hover); }
.btn--primary:active, .btn--primary.is-active { background: var(--accent-press); }

/* вторичная */
.btn--secondary {
  background: var(--surface); border-color: var(--line-strong); color: var(--text);
}
.btn--secondary:hover,  .btn--secondary.is-hover  { background: var(--surface-hover); }
.btn--secondary:active, .btn--secondary.is-active { background: var(--surface-press); }

/* тихая */
.btn--quiet { background: none; border-color: transparent; color: var(--text-2); }
.btn--quiet:hover,  .btn--quiet.is-hover  { background: var(--surface-hover); color: var(--text); }
.btn--quiet:active, .btn--quiet.is-active { background: var(--surface-press); color: var(--text); }

/* опасная: меняется и заливка, и кромка — одной рамки для подтверждения мало */
.btn--danger { background: var(--surface); border-color: var(--err-edge); color: var(--err); }
.btn--danger:hover,  .btn--danger.is-hover  { background: var(--danger-hover); border-color: var(--err); }
.btn--danger:active, .btn--danger.is-active { background: var(--danger-press); border-color: var(--err); }

/* выключенная: одинаково для всех видов, чтобы не гадать, что нажимается */
.btn[disabled], .btn.is-disabled, .btn[aria-disabled="true"] {
  background: var(--surface-2); border-color: var(--line); color: var(--text-off);
  cursor: not-allowed; box-shadow: none;
}

/* загрузка: подпись остаётся в разметке, но гаснет, а кольцо встаёт по центру.
   Ширина кнопки не меняется — иначе соседние контролы прыгают под курсором. */
.btn[data-loading="true"] { pointer-events: none; }
.btn[data-loading="true"] > * { opacity: 0; }
.btn[data-loading="true"]::after {
  content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  inline-size: 14px; block-size: 14px; margin: -7px 0 0 -7px;
  border: 2px solid currentColor; border-block-start-color: transparent;
  border-radius: var(--r-pill);
  animation: eos-spin 700ms linear infinite;
}
@keyframes eos-spin { to { transform: rotate(360deg); } }
/* Кольцо не убираем — оно единственный признак работы; замедляем втрое. */
@media (prefers-reduced-motion: reduce) {
  .btn[data-loading="true"]::after { animation-duration: 2100ms; }
}

/* --- Кнопка с ценой (UX-Р-3) ---------------------------------------------
   Цена — часть подписи, а не подсказка при наведении: с телефона подсказку
   не увидеть вовсе. Число моноширинное, отбито волосяной чертой.
   🔴 Цена висит на кнопке, которая ЗАПУСКАЕТ работу. Кнопка, открывающая
   мастер или редактор, цены не несёт — иначе человек читает цену за то, что
   бесплатно, и не открывает мастер (UI-COPY §5.1).                          */
.btn__price {
  display: inline-flex; align-items: center; gap: .3em;
  padding-inline-start: var(--s-4);
  margin-inline-start: var(--s-2);
  border-inline-start: var(--bw) solid currentColor;
  font-family: var(--font-mono); font-size: .92em; font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  opacity: .82;
}
.btn--primary .btn__price { opacity: 1; }
.btn__free {
  padding-inline-start: var(--s-4); margin-inline-start: var(--s-2);
  border-inline-start: var(--bw) solid currentColor;
  font-size: .92em; opacity: .8;
}

.btn-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4); }

/* ==========================================================================
   6. ПАНЕЛЬ ПОДТВЕРЖДЕНИЯ РАСХОДА (UX-Р-3, С-16)
   Четыре строки в жёстком порядке: что получите · цена · баланс · остаток.
   Остаток отдельной строкой, потому что именно его человек ищет глазами.
   ========================================================================== */
.spend {
  background: var(--surface);
  border: var(--bw) solid var(--line);
  border-radius: var(--r-md);
  padding: var(--pad-panel);
  display: flex; flex-direction: column; gap: var(--s-5);
  max-inline-size: 560px;
  box-shadow: var(--shadow-sm);
}
.spend__title { font-size: var(--fz-lg); }
.spend__rows { display: grid; grid-template-columns: auto 1fr; gap: var(--s-3) var(--s-6); }
.spend__k { color: var(--text-3); font-size: var(--fz-sm); }
.spend__v { font-size: var(--fz-sm); color: var(--text); }
.spend__v .num { font-size: var(--fz-md); font-weight: var(--fw-bold); }
.spend__after {
  display: flex; align-items: baseline; gap: var(--s-4);
  padding-block-start: var(--s-5);
  border-block-start: var(--bw) solid var(--line);
}
.spend__after .num { font-size: var(--fz-xl); font-family: var(--font-mono); font-weight: var(--fw-bold); }
.spend__foot { display: flex; gap: var(--s-4); flex-wrap: wrap; }

/* Не хватает токенов — состояние ДО запуска, а не ошибка после него
   (UX-СПЕЦ §6, Запрет 15: настройки не теряются). */
.spend--short { border-color: var(--warn-edge); }
.spend--short .spend__title { color: var(--warn); }

/* ==========================================================================
   7. МЕТКИ: статусы, закрепление, сохранение, источник
   🔴 Цвет нигде не единственный носитель смысла (UX-Р-5, UX-СПЕЦ §9.2):
   у каждой метки есть нарисованный знак и слово. Метка переживает ксерокс,
   чёрно-белую печать и дальтонизм.
   ========================================================================== */
.chip {
  display: inline-flex; align-items: center; gap: var(--s-3);
  min-block-size: var(--h-chip);
  padding: 0 var(--s-4);
  border: var(--bw) solid var(--line-strong);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--text-2);
  font-size: var(--fz-xs);
  line-height: var(--lh-snug);
  /* Не nowrap: подписи статусов короткие и сами не переносятся, а вот
     отметка по площадке приходит из данных. Длинная метка станет выше,
     но не утащит страницу вбок. */
  overflow-wrap: anywhere;
  max-inline-size: 100%;
  padding-block: 2px;
  /* Не сжимается соседями: без этого «Утверждено» в шапке карточки рвётся
     на «Утвержде / но» просто потому, что рядом длинный заголовок.
     Ломаться метка имеет право только тогда, когда сама шире контейнера. */
  flex: 0 0 auto;
}
.chip .icon { inline-size: var(--icon-sm); block-size: var(--icon-sm); }

/* Пять состояний материала. Пятое — «на согласовании» — придёт вместе с
   командными ролями; в MVP статусов четыре (UI-COPY §21.1). */
.chip--idea      { border-color: var(--line-strong); color: var(--text-2);  background: var(--surface); }
.chip--draft     { border-color: var(--accent-edge); color: var(--text);    background: var(--accent-tint); }
.chip--review    { border-color: var(--warn-edge);   color: var(--warn);    background: var(--warn-tint); }
.chip--approved  { border-color: var(--ok-edge);     color: var(--ok);      background: var(--ok-tint); }
/* Контурная, а не чёрная плашка. Заливка делала «Опубликовано» самым громким
   пятном таблицы, хотя это состояние ничего не требует: работа закончена.
   Громкость достаётся тому, что просит внимания, — конфликту и черновику. */
.chip--published { border-color: var(--text);        color: var(--text);    background: var(--surface); }

/* --- Отметка по площадке (UI-COPY §10.2) ---------------------------------
   Это НЕ статус материала, поэтому форма другая: прямоугольник вместо
   таблетки. Знак публикации один и тот же в обоих положениях — стрелка над
   чертой; меняются заливка и штрих рамки, а не рисунок. Иначе на одном экране
   публикация обозначена двумя разными знаками и читается как два разных
   события.                                                                  */
.chip--platform { border-radius: var(--r-xs); }
.chip--platform.is-off { border-style: dashed; color: var(--text-3); background: var(--surface); }

/* Служебные метки */
.chip--ok   { border-color: var(--ok-edge);   color: var(--ok);   background: var(--ok-tint); }
.chip--warn { border-color: var(--warn-edge); color: var(--warn); background: var(--warn-tint); }
.chip--err  { border-color: var(--err-edge);  color: var(--err);  background: var(--err-tint); }
/* Без uppercase: строка в UI-COPY написана «Beta-язык», и регистр — часть текста,
   а не оформления. Капитель молча превратила бы её в «BETA-ЯЗЫК». */
.chip--beta { border-color: var(--line-strong); color: var(--text-2); font-family: var(--font-mono);
              font-size: var(--fz-2xs); letter-spacing: .04em; }

/* --- Метка закрепления (UX-Р-5) ------------------------------------------
   Значок канцелярской кнопки ПЛЮС текст. Отдельно от статуса: закрепление —
   не стадия работы, а свойство карточки.                                    */
.pin {
  display: inline-flex; align-items: center; gap: var(--s-3);
  padding: 2px var(--s-4);
  border: var(--bw) solid var(--accent-edge);
  border-radius: var(--r-sm);
  background: var(--accent-tint);
  color: var(--text);
  font-size: var(--fz-xs);
  line-height: var(--lh-snug);
  flex: 0 0 auto;
  max-inline-size: 100%;
}
.pin__why { color: var(--text-2); }
/* Автоматическая защита — правка человека и утверждение. Форма другая:
   рамка без заливки, чтобы не спорить с ручным закреплением. */
.pin--auto { background: none; border-color: var(--line-strong); }

/* --- Индикатор сохранения (UX-Р-6) ---------------------------------------
   Три состояния. Ошибка сама не исчезает и несёт кнопку повтора.            */
.save {
  display: inline-flex; align-items: center; gap: var(--s-3);
  font-size: var(--fz-xs); color: var(--text-3);
}
.save--saving .icon { animation: eos-spin 900ms linear infinite; }
@media (prefers-reduced-motion: reduce) { .save--saving .icon { animation-duration: 2700ms; } }
.save--saved  { color: var(--ok); }
.save--error  { color: var(--err); }
.save--error .btn { margin-inline-start: var(--s-2); }

/* --- Метка источника (UX-Р-8) --------------------------------------------
   Раскрывается на месте, рядом с утверждением. Список ссылок в другом
   разделе не годится: человек не пойдёт его искать.                         */
/* 🔴 В строке живёт только метка, тело раскрывается НАД текстом.
   Раньше раскрытая метка тащила в строку блок шириной 460 px: предложение
   разрывалось, а точка после него уезжала на отдельную строку. Замеры
   в браузере (три варианта, оба положения) дали один рабочий: метка остаётся
   атомарной строчной коробкой, тело выносится из потока абсолютом. Вариант
   `display:inline` отпадает — у закрытой свёртки всё равно остаётся блочная
   коробка ::details-content, и она рвёт строку даже тогда, когда показывать
   нечего.

   ⚠️ Вторая половина этой поломки была не в стилях, а в разметке: <details>
   входит в список тегов, которые ЗАКРЫВАЮТ открытый <p>. Метка источника
   внутри абзаца выносилась парсером наружу, и никакой CSS этого не лечит.
   Абзац с меткой источника собирается на <div>, а не на <p>. */
.src { display: inline-block; }
/* Хозяин раскрытой панели — блок с самим утверждением, а не метка. Он задаёт
   и ширину, и левый край: панель, привязанная к метке, вылезала за экран на
   ширинах 700–900 и уводила страницу вбок на 45–205 px (метка стоит в конце
   строки, а панели нужно 460). Блок с меткой обязан нести .src-line либо быть
   .card__meta — иначе панель уедет к чужому предку. */
.src-line, .card__meta { position: relative; }
.src > summary {
  display: inline-flex; align-items: center; gap: var(--s-2);
  min-block-size: var(--h-inline-tap);   /* исключение для цели внутри строки */
  padding: 1px var(--s-3);
  border: var(--bw) solid var(--line-strong);
  border-radius: var(--r-xs);
  background: var(--surface);
  color: var(--text-2);
  font-size: var(--fz-2xs);
  cursor: pointer;
  list-style: none;
  vertical-align: baseline;
}
.src > summary::-webkit-details-marker { display: none; }
.src > summary:hover, .src > summary.is-hover { background: var(--surface-hover); color: var(--text); }
.src[open] > summary { border-color: var(--accent-edge); background: var(--accent-tint); color: var(--text); }
.src__body {
  position: absolute;                    /* вынесено из строчного потока */
  inset-inline: 0;                       /* ширина строки утверждения */
  inset-block-start: calc(100% + var(--s-3));
  z-index: 5;
  max-inline-size: 460px;
  padding: var(--s-4) var(--s-5);
  border: var(--bw) solid var(--line);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--r-sm);
  background: var(--surface);
  box-shadow: var(--shadow-md);          /* панель поверх текста, а не врезка */
  font-size: var(--fz-xs);
  color: var(--text-2);
}
.src__body b { color: var(--text); font-weight: var(--fw-semi); }
/* Утверждение без подтверждения. Метка другая по форме — пунктир. */
.src--none > summary { border-style: dashed; border-color: var(--err-edge); color: var(--err); }

/* --- Полнота профиля (UX-Р-1) --------------------------------------------
   Показываем и подсказываем, но не запираем: рядом всегда «Напомнить позже».
   Число дублирует полосу словами — полоса одна смысла не несёт.             */
.meter { display: flex; flex-direction: column; gap: var(--s-3); max-inline-size: 520px; }
/* 🔴 Полоса на всю ширину колонки — для отдельного блока «Полнота профиля».
   Своя мерка в 520 px нужна полосе внутри сообщения и рядом с кнопкой; когда
   же блок стоит на экране сам по себе, он обязан быть той же ширины, что
   соседние поля. Иначе строка рядом с числом переносится раньше остального
   текста экрана и роняет вниз сироту в два слова — при том что справа от неё
   полстраницы пустого места. */
.meter--wide { max-inline-size: none; }
.meter__top { display: flex; align-items: baseline; gap: var(--s-4); }
.meter__val { font-family: var(--font-mono); font-weight: var(--fw-bold); font-size: var(--fz-md); }
.meter__track {
  block-size: 6px; border-radius: var(--r-pill);
  background: var(--surface-2);
  border: var(--bw) solid var(--line);
  overflow: hidden;
}
.meter__fill { block-size: 100%; background: var(--accent); border-inline-end: var(--bw) solid var(--accent-edge); }
.meter--done .meter__fill { background: var(--ok); border-inline-end-color: var(--ok); }
.meter__foot { display: flex; gap: var(--s-4); flex-wrap: wrap; align-items: center; }

/* Полоса из восьми блоков профиля: видно не только «сколько», но и «чего».
   Восемь — решение владельца 02.09.2026; было шесть. */
.meter__blocks { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.meter__block {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 1px var(--s-3);
  border: var(--bw) solid var(--line-strong); border-radius: var(--r-xs);
  font-size: var(--fz-2xs); color: var(--text-2); background: var(--surface);
}
.meter__block[data-state="done"]    { border-color: var(--ok-edge);     color: var(--ok);   background: var(--ok-tint); }
.meter__block[data-state="partial"] { border-color: var(--accent-edge); color: var(--text); background: var(--accent-tint); }
.meter__block[data-state="none"]    { border-style: dashed; color: var(--text-3); }

/* ==========================================================================
   8. КАРТОЧКИ
   Одна оболочка, четыре начинки. Отличаются не цветом, а составом строк:
   у идеи — углы, у события — дата и обратный отсчёт, у кампании — касания,
   у единицы контента — носитель и площадки.
   ========================================================================== */
.card {
  display: flex; flex-direction: column; gap: var(--s-4);
  padding: var(--pad-card);
  background: var(--surface);
  border: var(--bw) solid var(--line);
  border-radius: var(--r-md);
  min-inline-size: 0;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.card:hover, .card.is-hover { border-color: var(--line-strong); box-shadow: var(--shadow-sm); }

.card__top { display: flex; align-items: flex-start; gap: var(--s-4); }
.card__title { font-size: var(--fz-lg); font-weight: var(--fw-semi); min-inline-size: 0; }
.card__title a { color: inherit; text-decoration: none; }
.card__title a:hover { text-decoration: underline; }
.card__gist { color: var(--text-2); font-size: var(--fz-sm); }
.card__meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3) var(--s-5);
  font-size: var(--fz-xs); color: var(--text-3);
}
.card__meta b { color: var(--text-2); font-weight: var(--fw-medium); }
.card__marks { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; }
/* Пустая полоса меток места не занимает. У карточки общий просвет между
   блоками, и пустое гнездо даёт лишний зазор — он читается не как воздух,
   а как «тут чего-то не хватает». Полоса приходит из данных и пустой бывает
   у половины карточек. */
.card__marks:empty { display: none; }
.card__foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4);
  padding-block-start: var(--s-4);
  border-block-start: var(--bw) solid var(--line);
}
.card__foot .btn:last-child { margin-inline-start: auto; }

/* углы раскрытия у карточки идеи */
.card__angles { display: flex; flex-direction: column; gap: var(--s-2); font-size: var(--fz-sm); }
.card__angles li { color: var(--text-2); }
.card__angles { margin: 0; padding-inline-start: var(--s-7); }

/* событие: дата слева крупно, обратный отсчёт под ней */
.card--event .card__when {
  flex: 0 0 auto; text-align: center; min-inline-size: 56px;
  padding: var(--s-3) var(--s-4);
  border: var(--bw) solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--surface-2);
}
.card--event .card__day { font-family: var(--font-mono); font-size: var(--fz-xl); font-weight: var(--fw-bold); line-height: 1; }
.card--event .card__mon { font-size: var(--fz-2xs); color: var(--text-3); text-transform: uppercase; letter-spacing: .08em; }

/* кампания: полоса касаний
   🔴 Четыре положения различаются ФОРМОЙ, а не одним цветом (UX-Р-5):
   будущее — пунктир без заливки, собранное — сплошная рамка с заливкой,
   пройденное — то же плюс утолщённая нижняя кромка, день события — двойная
   рамка. Полоса переживает чёрно-белую печать и дальтонизм: раньше все
   четыре отличались только краской, а «0» на бумаге исчезал вовсе. */
.touchline { display: flex; align-items: stretch; gap: 2px; }
.touchline__t {
  flex: 1 1 0; min-inline-size: 0; block-size: 22px;
  border: var(--bw) dashed var(--line-strong); border-radius: var(--r-xs);
  background: none;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: var(--fz-2xs); color: var(--text-3);
}
.touchline__t[data-state="done"]    { background: var(--ok-tint);     border: var(--bw) solid var(--ok-edge);
                                      border-block-end-width: 3px;    color: var(--ok); }
.touchline__t[data-state="draft"]   { background: var(--accent-tint); border: var(--bw) solid var(--accent-edge); color: var(--text); }
.touchline__t[data-state="anchor"]  { background: var(--surface);     border: 3px double var(--text);
                                      color: var(--text);             font-weight: var(--fw-bold); }

/* align-items: start — карточки не растягиваются до самой высокой в ряду.
   Растянутая карточка события с пустым низом читается как «тут чего-то нет». */
.cards-grid {
  display: grid; gap: var(--gap-grid); align-items: start;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

/* ==========================================================================
   9. ПУСТЫЕ СОСТОЯНИЯ (UX-СПЕЦ §6)
   Заголовок зовёт к действию, вторая строка объясняет, что получится.
   «Здесь пока пусто» и «нет данных» в системе запрещены (UI-COPY §3, §20).
   ========================================================================== */
.empty {
  display: flex; flex-direction: column; gap: var(--s-4);
  padding: var(--s-9) var(--s-7);
  border: var(--bw) dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface);
  text-align: start;
  max-inline-size: 560px;
}
.empty--inline { padding: var(--s-7) var(--s-6); }
.empty__title { font-size: var(--fz-lg); }
.empty__text { color: var(--text-2); font-size: var(--fz-sm); }
.empty__acts { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-block-start: var(--s-2); }
.empty__note { font-size: var(--fz-xs); color: var(--text-3); }

/* ==========================================================================
   10. ФОРМЫ
   ========================================================================== */
.field { display: flex; flex-direction: column; gap: var(--s-3); max-inline-size: 420px; }
.field__label { font-size: var(--fz-sm); font-weight: var(--fw-medium); color: var(--text); }
.field__why { font-size: var(--fz-xs); color: var(--text-3); }
/* 🔴 Значение, которое человек читает, но не меняет, — строка, а не
   выключенное поле. Выключенный контрол браузер вдобавок гасит собственной
   прозрачностью 0.7 поверх нашего приглушённого цвета: #7D8189 на #EDEBE5
   превращается в 2,3:1 — ниже даже графического порога. Замеры этого
   не видели, потому что считали объявленный цвет, а не тот, что доходит
   до глаза. Правило: выключенным бывает ДЕЙСТВИЕ, а не сообщение. */
.field__value { font-size: var(--fz-md); color: var(--text); }
.field__err { font-size: var(--fz-xs); color: var(--err); display: flex; align-items: flex-start; gap: var(--s-3); }
.field__err .icon { margin-block-start: 1px; }

.input, .select, .textarea {
  inline-size: 100%;
  min-block-size: var(--h-control);
  padding: var(--pad-control);
  border: var(--bw) solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fz-md);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.textarea { min-block-size: 84px; padding: var(--s-4) var(--s-6); line-height: var(--lh-base); resize: vertical; }
.input::placeholder, .textarea::placeholder { color: var(--text-3); }
/* Класс-двойник нужен КАЖДОМУ псевдоклассу, иначе витрина показывает
   состояние, которого нет: у образца «список под курсором» рамка была та же,
   что у обычного. */
.input:hover, .input.is-hover,
.select:hover, .select.is-hover,
.textarea:hover, .textarea.is-hover { border-color: var(--text-3); }
.input:focus, .select:focus, .textarea:focus { border-color: var(--text); }
/* 🔴 opacity: 1 — не украшение, а снятие чужого гашения. Свой выключенный
   цвет мы посчитали: #7D8189 на #EDEBE5 даёт 3,28:1 и держит порог метки.
   Но браузер поверх него накладывает собственную прозрачность 0.7 на
   выключенный <select> (на input и textarea — нет, на кнопку — нет), и
   до глаза доходит 2,17:1 — ниже даже графического порога. Замеры этого
   не видели: они считали цвет, который мы объявили, а не тот, что рисуется.
   Считать эффективный цвет kontrast.py научили тем же заходом. */
.input[disabled], .select[disabled], .textarea[disabled] {
  opacity: 1;
  background: var(--surface-2); color: var(--text-off); border-color: var(--line); cursor: not-allowed;
}
.input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--err); border-width: var(--bw-strong); }

/* Выпадающий список: своя стрелка, потому что системная в тёмной теме
   остаётся светлой на части машин. */
.select {
  appearance: none;
  padding-inline-end: var(--s-9);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 15px) center, calc(100% - 10px) center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* Переключатель: положение видно по ручке и по подписи, а не только по цвету */
/* Цель касания — вся подпись целиком, а не ручка: по ней и попадают пальцем.
   Ручка 36×20 остаётся рисунком нужного размера. */
.switch {
  display: inline-flex; align-items: center; gap: var(--s-4); cursor: pointer;
  min-block-size: var(--h-control);
  align-self: flex-start;   /* иначе в колонке формы кольцо фокуса растянется во всю ширину */
}
.switch input { position: absolute; opacity: 0; inline-size: 1px; block-size: 1px; }
.switch__track {
  position: relative; flex: 0 0 auto;
  inline-size: 36px; block-size: 20px;
  border: var(--bw) solid var(--line-strong); border-radius: var(--r-pill);
  background: var(--surface-2);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.switch__track::after {
  content: ""; position: absolute; inset-block-start: 2px; inset-inline-start: 2px;
  inline-size: 14px; block-size: 14px; border-radius: var(--r-pill);
  background: var(--text-3);
  transition: transform var(--t-base) var(--ease), background var(--t-fast) var(--ease);
}
.switch input:checked + .switch__track { background: var(--accent); border-color: var(--accent-edge); }
.switch input:checked + .switch__track::after { transform: translateX(16px); background: var(--accent-ink); }
.switch input:focus-visible + .switch__track,
.switch.is-focus .switch__track { outline: var(--focus-w) solid var(--focus); outline-offset: var(--focus-offset); }
.switch input:disabled + .switch__track { background: var(--surface-2); border-color: var(--line); }
.switch input:disabled + .switch__track::after { background: var(--text-off); }
.switch__label { font-size: var(--fz-sm); }
.switch__state { font-family: var(--font-mono); font-size: var(--fz-2xs); color: var(--text-3); }

/* Список флажков: несколько значений из одного перечня — умения в профиле,
   форматы выгрузки, площадки публикации.
   Это НЕ переключатель: переключатель отвечает «да/нет» на один вопрос,
   флажки отмечают сколько угодно пунктов сразу.
   Цель касания — строка целиком, а не квадратик в 16 пикселей: высота
   строки равна h-control, те же 44 px под пальцем, что у поля и кнопки.
   Кольцо фокуса приходит общим правилом основы (:focus-visible у input),
   своего здесь не нужно.
   🔴 До 05.09.2026 компонента в системе не было, и один и тот же набор
   флажков был собран дважды местными классами прототипа — .opt на профиле
   и .exp__i на выгрузке. Разъезжались они уже на третьем месте: у одного
   был свой цвет текста, у другого — приписка справа и своя сетка. */
.checks { display: flex; flex-direction: column; }
.check {
  display: flex; align-items: center; gap: var(--s-4);
  min-block-size: var(--h-control);
  font-size: var(--fz-sm); color: var(--text); cursor: pointer;
}
/* margin: 0 обязателен. Браузер даёт флажку собственный отступ (в Chrome
   3px сверху и снизу, 3 и 4 по бокам), и столбик флажков вставал на 4 px
   правее всего остального в колонке — заголовка, подписи, кнопки. Поймано
   слепым просмотром снимков, замером по пикселям, а не чтением кода. */
.check input { accent-color: var(--accent); inline-size: 16px; block-size: 16px; flex: 0 0 auto; margin: 0; }
/* Приписка в конце строки: расширение файла, число файлов. Прижата к краю,
   чтобы приписки стояли колонкой, а не плавали за подписями разной длины. */
.check__tag { margin-inline-start: auto; font-family: var(--font-mono); font-size: var(--fz-2xs); color: var(--text-3); }

/* Колонками — когда пунктов много и они разбиты на группы по назначению
   (выгрузка, UI-COPY §16). 240 — ширина, ниже которой подписи форматов
   рвутся на две строки.
   🔴 Просвет между колонками шире, чем между строками, и это не вкус.
   Приписка прижата к концу строки, и при общем просвете 16 px от неё
   до чужого флажка соседней колонки оставался 21 px, а до своего
   названия — 118. Глаз группирует по близости, и приписки читались
   подписями к соседней колонке. Замерено по снимку. */
.checks--cols { display: grid; gap: var(--s-7) var(--s-11); grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); align-items: start; }
.checks__g { display: flex; flex-direction: column; gap: var(--s-2); }

/* Вкладки */
/* Переносятся, а не сжимаются: сжатая вкладка рвёт подпись на слоги
   и вылезает за рамку. Проверено на пяти вкладках в колонке 420 px. */
.tabs { display: flex; flex-wrap: wrap; gap: var(--s-1); border-block-end: var(--bw) solid var(--line); }
.tab {
  appearance: none; border: none; background: none;
  min-block-size: var(--h-control);
  padding: var(--s-4) var(--s-6);
  font: inherit; font-size: var(--fz-sm); color: var(--text-2);
  cursor: pointer; white-space: nowrap;
  border-block-end: 2px solid transparent;
  margin-block-end: -1px;
  display: inline-flex; align-items: center; gap: var(--s-3);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.tab:hover, .tab.is-hover { color: var(--text); background: var(--surface-hover); }
.tab:active, .tab.is-active { background: var(--surface-press); }
/* 🔴 Выбранная вкладка обязана быть громче наведённой. Была наоборот:
   у выбранной — только подчёркивание в 2 px, у наведённой — заливка во всю
   плашку, и глаз читал «выбрано» на той, где стоит курсор. Теперь у выбранной
   три признака: янтарная подложка, янтарное подчёркивание и начертание;
   у наведённой — один серый. */
.tab[aria-selected="true"], .tab.is-current {
  color: var(--text); font-weight: var(--fw-semi);
  background: var(--accent-tint); border-block-end-color: var(--accent);
}
.tab[disabled] { color: var(--text-off); cursor: not-allowed; }

/* ==========================================================================
   11. ХОД РАБОТЫ (UX-СПЕЦ §6, состояние «Идёт»)
   Стадии человеческими словами. Поставщиков и внутренние службы не называем.
   ========================================================================== */
.stages { display: flex; flex-direction: column; gap: var(--s-5); max-inline-size: 560px; }
.stages__list { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); margin: 0; padding: 0; list-style: none; }
.stages__s {
  display: inline-flex; align-items: center; gap: var(--s-3);
  padding: 2px var(--s-4);
  border: var(--bw) solid var(--line); border-radius: var(--r-sm);
  font-size: var(--fz-xs); color: var(--text-3);
}
.stages__s[data-state="done"] { border-color: var(--ok-edge); color: var(--ok); background: var(--ok-tint); }
.stages__s[data-state="now"]  { border-color: var(--accent-edge); color: var(--text); background: var(--accent-tint); font-weight: var(--fw-semi); }
.stages__s .icon { inline-size: var(--icon-sm); block-size: var(--icon-sm); }
.stages__s[data-state="now"] .icon { animation: eos-spin 900ms linear infinite; }
@media (prefers-reduced-motion: reduce) { .stages__s[data-state="now"] .icon { animation-duration: 2700ms; } }
.stages__note { font-size: var(--fz-xs); color: var(--text-3); }

/* ==========================================================================
   12. СООБЩЕНИЯ
   Каждое отвечает на три вопроса: что сейчас, что сохранилось, что делать.
   ========================================================================== */
.notice {
  display: flex; gap: var(--s-5);
  padding: var(--s-5) var(--s-6);
  border: var(--bw) solid var(--line);
  border-inline-start: 3px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  max-inline-size: 640px;
}
.notice__body { display: flex; flex-direction: column; gap: var(--s-3); min-inline-size: 0; }
.notice__title { font-size: var(--fz-sm); font-weight: var(--fw-semi); }
.notice__text { font-size: var(--fz-sm); color: var(--text-2); }
.notice__acts { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-block-start: var(--s-2); }
.notice--info  { border-inline-start-color: var(--text-3); }
.notice--ok    { border-inline-start-color: var(--ok);   background: var(--ok-tint); }
.notice--ok    .notice__title { color: var(--ok); }
.notice--warn  { border-inline-start-color: var(--warn); background: var(--warn-tint); }
.notice--warn  .notice__title { color: var(--warn); }
.notice--err   { border-inline-start-color: var(--err);  background: var(--err-tint); }
.notice--err   .notice__title { color: var(--err); }
/* 🔴 Акцентное сообщение живёт БЕЗ заливки, на белом листе. Янтарная подложка
   и охряная подложка предупреждения дают между собой 1,02:1 — одна и та же
   кремовая полоса то говорит «файл больше 200 МБ», то предлагает правило
   голосу, и предупреждение перестаёт читаться предупреждением. Разводим не
   краской (её там взять негде), а носителем: у акцента остаётся только
   янтарная насечка слева. */
.notice--accent{ border-inline-start-color: var(--accent); border-inline-start-width: 4px; }

/* ==========================================================================
   13. ОКНО «ДОБАВИТЬ МЫСЛЬ» (С-3, UX-П-3)
   Четыре входа одной поверхностью. Раздел выбирать не нужно — по этому
   правилу кнопка и сделана сквозной.
   ========================================================================== */
.sheet {
  inline-size: 100%; max-inline-size: 560px;
  background: var(--surface);
  border: var(--bw) solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.sheet__head { padding: var(--s-7) var(--s-7) var(--s-5); display: flex; flex-direction: column; gap: var(--s-2); }
.sheet__title { font-size: var(--fz-xl); }
.sheet__sub { font-size: var(--fz-sm); color: var(--text-2); }
.sheet__tabs { padding-inline: var(--s-7); }
.sheet__body { padding: var(--s-6) var(--s-7) var(--s-7); display: flex; flex-direction: column; gap: var(--s-6); }
.sheet__foot {
  padding: var(--s-6) var(--s-7);
  border-block-start: var(--bw) solid var(--line);
  background: var(--surface-2);
  display: flex; flex-direction: column; gap: var(--s-4);
}
.sheet__foot .btn-row { justify-content: flex-end; }

.drop {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s-3);
  min-block-size: 96px;
  border: var(--bw) dashed var(--line-strong);
  border-radius: var(--r-md);
  background: var(--bg);
  color: var(--text-2);
  font-size: var(--fz-sm);
  text-align: center;
  padding: var(--s-6);
}
.drop.is-over { border-color: var(--accent-edge); background: var(--accent-tint); color: var(--text); }

.rec { display: flex; align-items: center; gap: var(--s-5); }
.rec__time { font-family: var(--font-mono); font-size: var(--fz-xl); font-variant-numeric: tabular-nums; }
.rec__wave { flex: 1 1 auto; display: flex; align-items: center; gap: 3px; block-size: 24px; }
/* Полоски узкие и с потолком ширины: без него на широком экране они
   расплываются в кирпичи и перестают читаться звуковой дорожкой. */
.rec__wave i { flex: 0 1 3px; max-inline-size: 3px; background: var(--line-strong); border-radius: 1px; }

/* ==========================================================================
   14. ПЛАН В ТРЁХ УРОВНЯХ (UX-Р-4)
   Ближайший месяц — по датам. Месяцы 2–3 — недельными блоками.
   Месяцы 4–12 — кампаниями и линиями. Уровень подписан на самом плане,
   а не в справке: человек должен отличать точную дату от направления,
   не читая инструкции (UX-П-5).
   ========================================================================== */
.level {
  display: flex; align-items: baseline; gap: var(--s-4); flex-wrap: wrap;
  margin-block-end: var(--s-4);
}
.level__name { font-family: var(--font-head); font-size: var(--fz-lg); font-weight: var(--fw-semi); }
.level__kind {
  font-family: var(--font-mono); font-size: var(--fz-2xs); letter-spacing: .08em; text-transform: uppercase;
  padding: 1px var(--s-3); border-radius: var(--r-xs);
  border: var(--bw) solid var(--line-strong); color: var(--text-2);
}
.level__kind[data-level="dates"]     { border-color: var(--accent-edge); background: var(--accent-tint); color: var(--text); }
.level__kind[data-level="weeks"]     { border-style: dashed; }
.level__kind[data-level="campaigns"] { border-style: dotted; }
.level__note { font-size: var(--fz-xs); color: var(--text-3); }

/* --- Уровень 1: таблица по датам ------------------------------------------
   🔴 Потолок высоты у окна прокрутки обязателен: без него окно не становится
   собственным скроллпортом, и липкая шапка уезжает вместе с таблицей при
   прокрутке страницы. На сороковой строке человек смотрит на безымянные
   столбцы. Проверяется только живой прокруткой.                             */
.plan-scroll {
  max-block-size: 340px;
  overflow: auto;
  border: var(--bw) solid var(--line);
  border-radius: var(--r-sm);
  background: var(--surface);
}
/* 🔴 А таблице ИЗВЕСТНОЙ длины потолок не нужен, и он там вреден.
   Список касаний кампании всегда короткий и весь описан подписью рядом
   («семь касаний»). С потолком 340 px семь строк занимали 448 — седьмая
   уезжала под кромку, и подпись начинала врать: полоса показывает семь,
   окно расхода обещает семь, в таблице видно шесть. Причём обрезалось
   именно то касание, которое подпись выделяет отдельно, — единственное
   после события. Потолок ставят там, где список растёт от данных; там,
   где длина задана шаблоном, он только прячет содержание.
   Липкая шапка здесь не нужна по той же причине — заголовки видны всегда. */
.plan-scroll--full { max-block-size: none; overflow: visible; }
.plan-table { inline-size: 100%; border-collapse: collapse; font-size: var(--fz-sm); }
.plan-table thead th {
  position: sticky; inset-block-start: 0; z-index: 2;
  background: var(--surface-2);
  color: var(--text-3);
  font-weight: var(--fw-medium);
  font-size: var(--fz-xs);
  text-align: start;
  padding: var(--pad-cell);
  border-block-end: var(--bw) solid var(--line-strong);
  white-space: nowrap;
}
.plan-table td {
  padding: var(--pad-cell);
  border-block-end: var(--bw) solid var(--line);
  vertical-align: middle;
  block-size: var(--h-row);
}
.plan-table tbody tr:last-child td { border-block-end: none; }
/* Зебры нет (см. ниже), значит строку под курсором ведёт только подсветка —
   и она обязана быть видимой. Прежние 1,05:1 к белому не видел никто. */
.plan-table tbody tr:hover td, .plan-table tbody tr.is-hover td { background: var(--surface-hover); }
/* Первая фраза набрана приглушённым: на подсветке он даёт 4,06:1 и выпадает
   из порога текста. Поднимаем на ступень — 6,51:1. */
.plan-table tbody tr:hover .c-hook, .plan-table tbody tr.is-hover .c-hook { color: var(--text-2); }

/* 🔴 Зебры нет — и это решение, а не забывчивость. Полосатость и подсветка
   состояния строки живут в одном канале: правило на чётную строку весит
   больше правила на класс строки и выигрывает независимо от порядка.
   В соседней системе так пропала красная строка «нет цены» на чётных
   позициях. Строку ведёт волосяная линия снизу, состояние — насечка слева.
   Подложку объявляет ЯЧЕЙКА (td), а не строка, иначе она не рисуется. */
.plan-table tr[data-state] td { background: var(--surface); }
.plan-table tr[data-state="pinned"]   td { background: var(--accent-tint); }
.plan-table tr[data-state="conflict"] td { background: var(--err-tint); }
.plan-table tr[data-state="approved"] td { background: var(--ok-tint); }
.plan-table tr[data-state] td:first-child { position: relative; }
.plan-table tr[data-state] td:first-child::before {
  content: ""; position: absolute; inset-block: 0; inset-inline-start: 0; inline-size: 3px;
}
.plan-table tr[data-state="pinned"]   td:first-child::before { background: var(--accent); }
.plan-table tr[data-state="conflict"] td:first-child::before { background: var(--err); }
.plan-table tr[data-state="approved"] td:first-child::before { background: var(--ok); }

.plan-table .c-date { font-family: var(--font-mono); white-space: nowrap; color: var(--text-2); }
.plan-table .c-idea { min-inline-size: 200px; }
.plan-table .c-idea b { font-weight: var(--fw-medium); }
.plan-table .c-hook { color: var(--text-3); font-size: var(--fz-xs); }
.plan-table .c-num  { font-family: var(--font-mono); text-align: end; }

/* --- Уровень 2: недельные блоки ------------------------------------------
   Дат внутри нет намеренно: ложная точность хуже отсутствия точности.       */
.plan-weeks { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.week {
  border: var(--bw) dashed var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  padding: var(--s-5);
  display: flex; flex-direction: column; gap: var(--s-3);
}
.week__no { font-family: var(--font-mono); font-size: var(--fz-2xs); color: var(--text-3); letter-spacing: .08em; text-transform: uppercase; }
.week__theme { font-size: var(--fz-sm); font-weight: var(--fw-semi); }
.week__mix { display: flex; flex-wrap: wrap; gap: var(--s-3); font-size: var(--fz-xs); color: var(--text-2); }
.week__count { font-family: var(--font-mono); font-size: var(--fz-xs); color: var(--text-3); }

/* --- Уровень 3: кампании и линии ----------------------------------------- */
.plan-lanes { display: flex; flex-direction: column; gap: var(--s-3); }
.lane {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) auto;
  gap: var(--s-5);
  align-items: center;
  padding: var(--s-4) var(--s-5);
  border: var(--bw) dotted var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
}
.lane__mon { font-family: var(--font-mono); font-size: var(--fz-sm); color: var(--text-2); }
.lane__theme { font-size: var(--fz-sm); }
.lane__theme b { font-weight: var(--fw-semi); }
.lane__budget { font-family: var(--font-mono); font-size: var(--fz-xs); color: var(--text-3); white-space: nowrap; }
.lane__camps { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-block-start: var(--s-2); }

/* ==========================================================================
   15. ИСТОРИЯ ВЕРСИЙ (UX-Р-7)
   Откат создаёт новую вершину, а не стирает прошлое.
   ========================================================================== */
.history { display: flex; flex-direction: column; max-inline-size: 560px; }
.history__row {
  display: grid; grid-template-columns: 1fr auto auto; gap: var(--s-5);
  align-items: center;
  padding: var(--s-4) var(--s-5);
  border-block-end: var(--bw) solid var(--line);
  font-size: var(--fz-sm);
}
.history__row:last-child { border-block-end: none; }
.history__row.is-current { background: var(--accent-tint); }
.history__what b { font-weight: var(--fw-medium); }
.history__who { font-size: var(--fz-xs); color: var(--text-3); }
.history__when { font-family: var(--font-mono); font-size: var(--fz-xs); color: var(--text-3); white-space: nowrap; }

/* ==========================================================================
   15b. ЦЕЛИ КАСАНИЯ ВНУТРИ СТРОКИ ТЕКСТА

   🔴 Токен --h-inline-tap не работает сам по себе — его надо кому-то отдать.
   Он был объявлен и применён ровно в одном месте (метка источника), а живые
   замеры при сенсорном указателе показали 15–18 px у ссылки «Открыть»
   в источнике, у ссылок в подписях и у хлебных крошек. Крошки на телефоне —
   это кнопка «назад»: промах по ней стоит дороже всех.

   Растянуть такие ссылки до 44 px нельзя — строка разъедется. Стандарт
   допускает исключение для целей внутри строки текста; берём 24 и говорим
   об этом вслух.
   ========================================================================== */
@media (pointer: coarse) {
  .crumbs a,
  .src__body a,
  .card__meta a,
  .notice__text a,
  .field__why a,
  .meter__foot a,
  .stages__note a,
  .hint a,
  .link {
    display: inline-flex; align-items: center;
    min-block-size: var(--h-inline-tap);
  }
}

/* ==========================================================================
   16. ПЕЧАТЬ
   🔴 В настройках печати Chrome фоновая графика ВЫКЛЮЧЕНА по умолчанию.
   Значит метка «цветная заливка плюс текст» на бумаге станет пустой рамкой.
   Здесь заливки снимаются, рамки остаются, знак и слово никуда не деваются —
   лист читается чёрно-белым. Проверять печать только с выключенным фоном:
   печать из командной строки фон рисует и показывает ложное «всё хорошо».
   ========================================================================== */
@media print {
  /* 🔴 Список полный. Он собирается по признаку «тёмная заливка плюс светлый
     текст», а не по памяти: один такой элемент — плашка «0» на линии
     касаний — в него когда-то не попал, и день события на бумаге исчезал
     (1,05:1). Добавили новый элемент с заливкой — впиши его сюда. */
  .chip, .pin, .notice, .plan-table tr[data-state] td, .stages__s, .meter__block,
  .touchline__t {
    background: none !important;
    color: #000 !important;
    border-color: #000 !important;
  }
  /* Форма положения на бумаге остаётся: пунктир, двойная рамка, толстая
     нижняя кромка. Краски нет — различает рисунок рамки. */
  .plan-scroll { max-block-size: none; overflow: visible; border-color: #000; }

  /* 🔴 Таблица обязана уместиться в ширину листа целиком.
     Поймано выгрузкой в PDF: последняя колонка «Слайдов» уезжала за кромку
     и обрезалась вместе с числами. По такому листу считают не то.
     Ширина печатного окна — около 717 px против 1180 на экране, поэтому
     набор и поля ужимаются, а минимальная ширина колонки идеи снимается. */
  .plan-table { font-size: 10px; table-layout: auto; inline-size: 100%; }
  .plan-table .c-idea { min-inline-size: 0; }
  .plan-table .c-hook { font-size: 9px; }
  .plan-table td, .plan-table th { padding: 3px 4px; }
  .chip, .pin { font-size: 9px; padding: 0 4px; }
  /* 🔴 И метка не рвётся посреди слова. У .chip стои́т overflow-wrap: anywhere —
     он нужен отметкам по площадкам, которые приходят из данных. Но он же делает
     минимальной шириной метки ОДИН ЗНАК, и автоматическая раскладка печатной
     таблицы сжимает колонку до предела: на печатных 9 px «Черновик»
     превращался в «Чернови / к». Видно только в выгрузке PDF — на экране
     колонка шире и переносить нечего. В таблице плана метка всегда из нашего
     словаря и всегда короткая, переносить её незачем вовсе; раскладка сама
     даст колонке нужную ширину. */
  .plan-table .chip, .plan-table .pin { white-space: nowrap; }

  /* И второе оттуда же: строка не должна разрываться между листами.
     Разорванная строка теряет дату и статус — опознать её на второй
     странице нечем. Шапка при этом повторяется сама (thead). */
  .plan-table tr { break-inside: avoid; }
  .plan-table thead { display: table-header-group; }
  .plan-table thead th { position: static; background: none; color: #000; border-color: #000; }
  .plan-table td { border-color: #999; }
  .card, .week, .lane, .notice, .empty, .spend { break-inside: avoid; }

  .btn, .nav { display: none; }
}

/* ==========================================================================
   17. ТЕЛЕФОН
   Проверено на 390 точках. Главное правило: строка таблицы разворачивается
   в блок с ПОДПИСЯМИ. Столбик голых чисел без подписей — это потеря смысла,
   а не компактность (UX-П-17: горизонтальной прокрутки быть не должно).
   ========================================================================== */
@media (max-width: 860px) {
  .eos-shell { grid-template-columns: minmax(0, 1fr); block-size: auto; }
  /* 🔴 Свободная высота уходит рабочей зоне, а не меню. У оболочки на всю
     страницу есть min-block-size в высоту окна; без явных строк сетка делит
     остаток поровну между меню и содержимым, и под свёрнутым «Меню» вырастает
     пустота, тем больше, чем короче страница. Замерено 07.09.2026 на 390:
     меню 98 px на длинной странице и 173 px на короткой при том же составе. */
  .eos-shell--page { grid-template-rows: auto minmax(0, 1fr); }
  .nav { border-inline-end: none; border-block-end: var(--bw) solid var(--line); }
  /* Меню без сворачивания прокручивается внутри себя, а последний пункт
     растворяется книзу: ровно обрезанный список читается как поломка,
     растворённый — как «есть ещё». Это запасной вид для навигаций, где
     обёртки .nav__fold нет. */
  .nav__scroll {
    max-block-size: 240px;
    mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
  }

  /* 🔴 А со свёрнутым меню вложенной прокрутки не остаётся вовсе, и это
     главное: прокрутка внутри страницы, которая сама прокручивается, — способ
     спрятать содержимое, а не показать его. Список раскрывается целиком,
     потолка высоты у него нет. */
  .nav__fold .nav__scroll { max-block-size: none; mask-image: none; overflow: visible; }
  .nav__fold:not([open]) { flex: 0 0 auto; }
  .nav__toggle {
    display: flex; align-items: center; gap: var(--s-4);
    min-block-size: var(--h-nav-item);
    margin-inline: var(--s-4); margin-block-end: var(--s-4);
    padding: 0 var(--s-4);
    border: var(--bw) solid var(--line-strong); border-radius: var(--r-sm);
    background: var(--surface); color: var(--text);
    font-size: var(--fz-md); font-weight: var(--fw-medium);
    cursor: pointer;
    list-style: none;               /* треугольник браузера убираем: свой знак */
  }
  .nav__toggle::-webkit-details-marker { display: none; }
  .nav__toggle:hover { background: var(--surface-hover); }
  .nav__toggle .icon { margin-inline-start: auto; transition: transform var(--t-fast) var(--ease); }
  .nav__fold[open] > .nav__toggle .icon { transform: rotate(180deg); }
  .eos-main { padding: var(--s-6); }
}

@media (max-width: 640px) {
  /* На телефоне панели некуда всплывать: метка может стоять у правого края
     строки, и плавающее тело утащило бы страницу вбок. Возвращаем его в поток
     под строку — места по вертикали хватает всегда. */
  .plan-scroll { max-block-size: none; border: none; background: none; }
  .plan-table, .plan-table tbody, .plan-table tr, .plan-table td { display: block; inline-size: 100%; }
  .plan-table thead { display: none; }
  .plan-table tr {
    border: var(--bw) solid var(--line);
    border-radius: var(--r-sm);
    background: var(--surface);
    margin-block-end: var(--s-4);
    padding: var(--s-4) var(--s-5);
    position: relative;
  }
  .plan-table td {
    border: none;
    padding: var(--s-2) 0;
    display: grid;
    grid-template-columns: 92px minmax(0, 1fr);
    gap: var(--s-4);
    align-items: baseline;
    block-size: auto;
  }
  /* Подпись берётся из data-label — та же, что в шапке таблицы.
     Без неё столбик значений превратился бы в набор чисел без имён. */
  .plan-table td::before {
    content: attr(data-label);
    font-size: var(--fz-2xs);
    color: var(--text-3);
    text-transform: uppercase;
    letter-spacing: .06em;
  }
  /* Всё содержимое ячейки — во вторую колонку, под своей подписью.
     Иначе вторая строка ячейки (первая фраза материала) уезжает под подпись
     и читается как ещё одна безымянная колонка. */
  .plan-table td > * { grid-column: 2; justify-self: start; }
  .plan-table td:empty { display: none; }
  /* Насечку состояния переносим на всю карточку. Заливку подписи снимаем:
     иначе полоса, нарисованная для строки таблицы, красит слово «Дата». */
  .plan-table tr[data-state] td { background: none; }
  .plan-table tr[data-state] td:first-child::before {
    content: attr(data-label); position: static;
    inline-size: auto; block-size: auto; background: none;
  }
  .plan-table tr[data-state="pinned"]   { border-inline-start: 3px solid var(--accent); }
  .plan-table tr[data-state="conflict"] { border-inline-start: 3px solid var(--err); }
  .plan-table tr[data-state="approved"] { border-inline-start: 3px solid var(--ok); }
  .plan-table .c-num { text-align: start; }

  .lane { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }
  .history__row { grid-template-columns: minmax(0, 1fr); gap: var(--s-2); }
  .spend__rows { grid-template-columns: minmax(0, 1fr); gap: var(--s-2); }
  .spend__k { font-size: var(--fz-2xs); text-transform: uppercase; letter-spacing: .06em; }
  /* Подпись кнопки переносится, а не уезжает за экран: «Собрать кадры из
     готового текста · бесплатно» в 390 точках в одну строку не влезает. */
  .btn { white-space: normal; block-size: auto; min-block-size: var(--h-control);
         padding-block: var(--s-3); text-align: center; }
  .btn-row .btn { flex: 1 1 auto; }
}
