/* ==========================================================================
   Уведомления и прогресс
   ==========================================================================
   Раньше статус был серой строчкой справа от кнопки «Запустить»: и «файл не
   загружен», и «связь потеряна», и ход прогона выглядели одинаково и мимо
   взгляда. Здесь у каждого состояния свой цвет из общей статусной гаммы,
   значок и место - под кнопками во всю ширину, где его не пропустить.
   Оранжевый по-прежнему занят брендом под управляющие элементы, поэтому
   в статусах он появляется только у «идёт работа»: это и есть действие. */
.notice {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 3px 9px;
  align-items: start;
  margin-top: 12px;
  padding: 10px 12px;
  border: 1px solid var(--free-line);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  background: var(--free-bg);
  color: var(--free-text);
  font-size: 12.5px;
  line-height: 1.5;
}
.notice::before {
  content: "i";
  grid-row: 1;
  display: flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-top: 1px;
  border-radius: 50%;
  background: currentColor; color: var(--surface);
  font-size: 11px; font-weight: 700; font-style: italic;
}
.notice-text { grid-column: 2; word-break: break-word; }
/* Место в коде, где всё сломалось, - второй строкой и мельче: оно нужно
   при разборе, но читать сообщение не должно мешать. */
.notice-where { grid-column: 2; font-size: 11px; opacity: .75; }

/* Техническая подробность отказа - под раскрытием (этап 1 плана seo_report,
   тема 8: «технические детали - под раскрытием», попап не канал ошибок).
   Статус, адрес ручки и сырой ответ сервера - для баг-репорта, не для
   первого взгляда: свёрнуто по умолчанию, человека текстом не кричит. */
.notice-details { grid-column: 2; margin-top: 4px; }
.notice-details > summary { cursor: pointer; font-size: 11px; opacity: .75; }
.notice-details pre {
  margin: 4px 0 0; padding: 6px 8px;
  background: color-mix(in srgb, currentColor 8%, transparent);
  border-radius: var(--radius-sm);
  font-size: 11px; line-height: 1.4;
  white-space: pre-wrap; word-break: break-word;
  max-height: 160px; overflow: auto;
}

.notice.error { background: var(--no-bg);   border-color: var(--no-line);   color: var(--no-text); }
.notice.warn  { background: var(--att-bg);  border-color: var(--att-line);  color: var(--att-text); }
.notice.ok    { background: var(--live-bg); border-color: var(--live-line); color: var(--live-text); }
.notice.info  { background: var(--wl);      border-color: var(--wl-line);   color: var(--wl-text); }
.notice.busy  { background: var(--accent-soft); border-color: var(--accent); color: var(--warn); }

.notice.error::before { content: "!"; font-style: normal; }
.notice.warn::before  { content: "!"; font-style: normal; }
.notice.ok::before    { content: "✓"; font-style: normal; font-size: 10px; }
/* У «идёт работа» вместо значка - крутящееся кольцо: неподвижная точка
   на длинном прогоне читается как «всё зависло». */
.notice.busy::before {
  content: "";
  background: none;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: notice-spin .7s linear infinite;
}
@keyframes notice-spin { to { transform: rotate(360deg); } }

/* Полоса прогресса. Проценты сервер и так присылает - показывать их числом
   в тексте и не показывать полосой значит терять единственную картинку,
   по которой видно, что прогон движется. */
.notice-bar {
  grid-column: 2;
  height: 4px; margin-top: 5px;
  border-radius: 2px;
  background: color-mix(in srgb, currentColor 18%, transparent);
  overflow: hidden;
}
.notice-bar i {
  display: block; height: 100%;
  border-radius: 2px;
  background: var(--accent);
  transition: width .25s ease;
}

/* Компактный вариант - под полем, где полноразмерная плашка распирала бы форму */
.notice.compact {
  margin-top: 6px; padding: 6px 9px; font-size: 11.5px;
  grid-template-columns: 13px 1fr; gap: 2px 7px;
}
.notice.compact::before { width: 13px; height: 13px; font-size: 9px; }

/* Список конкурентов из выдачи. Колонка узкая, поэтому четыре колонки -
   предел: домен и три числа. Остальное (примеры запросов, лучшая позиция)
   уходит в книгу Excel, где ширины хватает. */
.rival-head, .rival {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 46px 78px 40px;
  gap: 8px;
  align-items: center;
  padding: 5px 2px;
  font-size: 12px;
}
.rival-head {
  border-bottom: 1px solid var(--line);
  color: var(--text-3);
  font-size: 11px;
}
.rival-head .num, .rival .num { text-align: right; font-variant-numeric: tabular-nums; }
.rival { border-bottom: 1px solid var(--line); }
.rival b { font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Свой сайт и бренды подкрашены: в общем списке их надо узнавать мгновенно,
   иначе «почему мы у себя в конкурентах» - первый вопрос к отчёту. */
.rival.own b { color: var(--live-text); }
.rival.brand b { color: var(--att-text); }
.rival.aggregator b { color: var(--text-3); }


/* ==========================================================================
   Индикатор прогона
   ========================================================================== */
/* Один на все инструменты. Прогон идёт на сервере десятки секунд (отчёт
   Директа собирается асинхронно, выдача выкупается поштучно), и до этого
   единственным признаком жизни была плашка под кнопкой: экран выглядел
   застывшим, и его перезагружали на середине. */
/* Шире и слева, не center, как было при одной строке стадии и спиннере:
   .run-steps - сетка из 6-11 пунктов (TOOL_STAGES в core.js), в 460px
   по центру она сжалась бы в одну узкую колонку текста. .loading-tool/
   .loading-note остались по центру своим правилом ниже - короткая
   строка-эйбрау сверху и приписка снизу читаются как подпись, а не
   как часть списка. */
.loading-box {
  min-width: 320px; max-width: min(640px, 92vw);
  padding: 30px 34px 26px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  text-align: left;
}
.loading-tool {
  margin: 0 0 14px; font-size: 11.5px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-3); text-align: center;
}
.loading-note { margin: 14px 0 0; font-size: 11.5px; color: var(--text-3); text-align: center; }
/* Журнал прогона (DESIGN.md §3, окно 2) и кнопка «Остановить» - под
   индикатором, не рядом: это не главное на экране ожидания, читают их
   по желанию, а не обязаны видеть сразу. */
.run-log-box { margin: 14px 0 0; text-align: left; }
.run-log-box > summary {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--text-3);
}
.run-log-box[open] > summary { margin-bottom: 8px; }
.run-log-box .log { list-style: none; margin: 0; text-align: left; }
.run-log-box .log li + li { margin-top: 2px; }
#run-stop { margin: 14px auto 0; display: block; }


/* Сохранение в конфиг - это действие, и выглядеть оно должно кнопкой.
   Ссылкой в ряду подсказок его просто не замечали: «Сохранить списки в конфиг
   проекта» читалось как подпись к полю. Вариант тише основной кнопки: она
   заглавными и жирная, а это действие редкое и не главное на экране. */
button.secondary.compact {
  padding: 6px 12px;
  font-size: 11.5px; font-weight: 600;
  text-transform: none; letter-spacing: 0;
}


/* Строка кеша под кнопкой запуска: слева сколько накоплено, справа кнопка.
   Кеш экономит время и деньги, поэтому его чистят редко и осознанно - место
   для этого не главное на экране, но и не спрятанное. */
.cache-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding-top: 10px; margin-top: 2px; border-top: 1px solid var(--line);
}
.cache-row:not([hidden]) { display: flex; }
.cache-row .hint { min-width: 0; }

/* Список готовых отчётов - под кнопками запуска, отдельно от выбранного
   в форме проекта: ссылку открывают, не запуская прогон и не переключая
   проект. Список свой на каждый инструмент, но появляется только там,
   где у проектов вообще есть сохранённая ссылка (сейчас - report). */
.project-links {
  padding-top: 10px; margin-top: 2px; border-top: 1px solid var(--line);
}
.project-links > .label { display: block; margin-bottom: 6px; }
.project-links-list {
  display: flex; flex-direction: column; gap: 6px;
  max-height: 220px; overflow-y: auto;
}
.project-link-row {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.project-link-row > span { min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; }


/* Статусы площадок. «Кандидат» - акцентный, но не тревожный: это предложение
   инструмента, а не поломка. «Рабочая» намеренно бледная: строк с ней
   большинство, и кричать о них нечего - важно лишь, что ячейка не пустая. */
.tag-cand { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); font-weight: 600; }
/* tag-plain, не tag-none: имя "none" занято семьёй статусов url_checker
   (good/warn/bad/crit/none, style.css:1338-1342) - тот же класс здесь
   молча перебивал их цвет своим, и "ни в чём не замечена" ссылка выглядела
   бы серой площадкой площадок вместо своей палитры. Найдено при аудите
   структуры проекта 2026-10-09, тем же классом бага, что был у .row. */
.tag-plain { background: transparent; border-color: var(--line); color: var(--text-3); }


/* Шапка нижнего блока: название слева, крестик справа. Блок занимает
   до половины панели, и закрывать его приходится чаще, чем открывать. */
.detail-head {
  display: flex; align-items: baseline; gap: 8px;
  position: sticky; top: 0; background: var(--surface); padding-bottom: 4px;
}
.detail-head h3 { margin: 0; flex: 1; min-width: 0; }
.detail-head .detail-close { padding: 0 4px; font-size: 13px; line-height: 1; }

/* Имя площадки - ссылка на неё саму. Подчёркивание точками, чтобы строка
   таблицы не пестрила, но было видно, что это ссылка. */
#p-rows .c-name a { color: inherit; text-decoration: underline dotted var(--text-3); }
#p-rows .c-name a:hover { color: var(--accent); text-decoration-color: var(--accent); }


/* Уровень минус-фразы рядом с плашкой статуса: кампания, группа, библиотека.
   Отдельным элементом, а не текстом внутри плашки, - иначе «исключено
   (библиотека)» не помещается в колонку и обрезается ровно на уровне. */
.c-flag .lvl { font-size: 10px; color: var(--text-3); margin-left: 5px; }


/* ==========================================================================
   Подсказка-кружок у подписи поля
   ==========================================================================
   Параметров у SEO-анализа больше двадцати, и по названию не понять, что
   параметр делает. Подсказка под полем вмещает три-четыре слова, а объяснить
   модель атрибуции нужно двумя строками - поэтому кружок с вопросом.

   Тултип рисуется сам, а не через системный title, по двум причинам:
   системный появляется через секунду (за это время человек успевает
   отвернуться) и не умеет переносить длинный текст - он выходит одной
   строкой во весь экран.

   Имя класса своё, не `.q`: короткое имя уже занято строками запросов
   у n-грамм, а стили здесь общие на все инструменты. */
/* Кружок без текста подсказки не рисуется вовсе: пустой значок «?» обещает
   пояснение, а по наведению показывает пустое чёрное окно. Пустым он
   оказывается, когда инструмент подключает панель и не передаёт hint. */
.hint-dot:not([data-tip]), .hint-dot[data-tip=""] { display: none; }
.hint-dot {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  /* Размер прибит со всех сторон, а не одним width. Кружок стоит и в гибких
     строках (переключатели, заголовок панели), и в сетках, и в обычном
     тексте: в гибком контейнере width - это лишь база, и элемент растягивался
     на всю свободную ширину, превращаясь в пустой овал во весь блок.
     flex: none + min/max ширины держат его 14×14 в любом окружении. */
  flex: none;
  width: 16px; min-width: 16px; max-width: 16px;
  height: 16px; min-height: 16px;
  box-sizing: border-box;
  align-self: center;
  margin-left: 5px;
  border: 1px solid var(--line-strong); border-radius: 50%;
  background: var(--surface);
  /* Было 14×14 и 9.5px. На экране с масштабом знак вопроса внутри кружка
     не читался - оставался серый ободок, по которому непонятно, значок это
     или артефакт вёрстки. 16×16 и 11px с цветом основного текста читаются. */
  font-size: 11px; font-weight: 700; line-height: 1; color: var(--text-2);
  cursor: help; vertical-align: middle;
}
.hint-dot:hover, .hint-dot:focus-visible {
  border-color: var(--accent); color: var(--accent); outline: none;
}
.hint-dot::after {
  content: attr(data-tip);
  position: absolute; left: 50%; top: calc(100% + 8px);
  transform: translateX(-50%);
  z-index: 60;
  width: max-content; max-width: 300px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--text); color: var(--surface);
  font-size: 11.5px; font-weight: 400; line-height: 1.45;
  text-align: left; white-space: normal;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .18);
  opacity: 0; visibility: hidden; transition: opacity .12s ease;
  pointer-events: none;
}
/* Уголок к кружку: без него подсказка висит в воздухе и непонятно, к чему
   она относится, когда полей в строке несколько. */
.hint-dot::before {
  content: ""; position: absolute; left: 50%; top: calc(100% + 3px);
  transform: translateX(-50%);
  border: 5px solid transparent; border-bottom-color: var(--text);
  z-index: 61;
  opacity: 0; visibility: hidden; transition: opacity .12s ease;
  pointer-events: none;
}
.hint-dot:hover::after, .hint-dot:focus-visible::after,
.hint-dot:hover::before, .hint-dot:focus-visible::before {
  opacity: 1; visibility: visible;
}
/* У полей в правой части строки подсказка уехала бы за край окна.
   Правило-помощник: поставить у кружка класс, и она прижмётся правым краем. */
.hint-dot.left::after { left: auto; right: -4px; transform: none; }
.hint-dot.left::before { left: auto; right: 2px; transform: none; }

/* Изменение к базовому периоду: зелёное - в лучшую сторону, красное - в худшую.
   Направление «лучше» у каждого показателя своё и задано в tool-seo.js:
   у визитов и выручки больше - лучше, у отказов и позиций - наоборот.
   Цвет здесь не оценка работы, а направление показателя: без него колонка
   из −31,20 и −0,70 читается одинаково, хотя разница между ними в сорок раз. */
/* Базовый и текущий периоды: подложка и подпись в шапке. Две колонки
   из шестизначных чисел без них различаются только порядком, и «база» с
   «текущим» путаются на второй минуте чтения. */
.dtable th.col-base, .dtable td.col-base { background: var(--free-bg); }
.dtable th.col-cur, .dtable td.col-cur { background: var(--accent-soft); }
.dtable tr.row-base td:first-child { box-shadow: inset 3px 0 0 var(--free-line); }
.dtable tr.row-cur td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.dtable tbody tr:hover td.col-base, .dtable tbody tr:hover td.col-cur { filter: brightness(.98); }

/* Слово с расшифровкой: пунктир под ним обещает подсказку при наведении.
   Без пунктира подсказку не ищут - про неё просто не знают. */
.term { text-decoration: underline dotted var(--line-strong); text-underline-offset: 3px; cursor: help; }
.dtable th.term { text-decoration-color: var(--line); }
/* Код, которого нет в справочнике. Показан как есть - и видно, что как есть. */
.term.unknown { color: var(--text-3); font-style: italic; }
/* «Проверено и не найдено»: строка нужна как свидетельство проверки,
   но читать её наравне с находкой не нужно. */
.dtable tr.quiet td { color: var(--text-3); }
.dtable tr.quiet td .term { text-decoration-color: var(--line); }

.dtable td.better { color: var(--live-text); font-weight: 600; }
.dtable td.worse { color: var(--no-text); font-weight: 600; }
.dtable tr.total td.better { background: var(--live-bg); }
.dtable tr.total td.worse { background: var(--no-bg); }

/* Панель прогона: подпись слева, значение справа, длинное переносится. */
.impact table td:first-child { color: var(--text-2); padding-right: 10px; }
.impact table td:last-child { text-align: right; word-break: break-word; }


/* ==========================================================================
   Графики над таблицей
   ==========================================================================
   Рисует Plotly с CDN, общий слой - static/charts.js. Здесь только место
   под график: рамка, отступы и сворачивание.

   Раньше в этом комментарии было «рисуются своим SVG, без библиотеки» -
   правда для той версии и ложь для этой. Переход на Plotly описан
   в шапке charts.js, там же и причина. */
/* Графики сворачиваются: на широком экране они помогают, на ноутбуке
   съедают половину высоты, а таблица - главное на экране. Состояние
   запоминается, чтобы не сворачивать заново на каждой вкладке. */
.charts-box { flex: none; margin-bottom: 10px; }
.charts-box > summary {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; cursor: pointer; list-style: none;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 12px; font-weight: 600; color: var(--text-2);
}
.charts-box > summary:hover { color: var(--accent); border-color: var(--accent-soft); }
.charts-box[open] > summary {
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
  border-bottom-color: transparent; margin-bottom: -1px;
}
/* Высота графика растёт с числом строк (`Math.max(180, 46 * n + 60)` и
   похожие формулы в charts.js) - без потолка длинный список при раскрытии
   выдавливал таблицу результатов почти целиком за пределы видимой области:
   `.scroller` ниже - честный flex: 1, он просто сжимался до нескольких
   пикселей, читалось это как «таблица пропала и не прокручивается» (живой
   баг, пойман по скриншоту). У открытого блока свой потолок высоты и своя
   прокрутка - графики растут внутри себя, а не за счёт соседей по колонке. */
/* flex: 1 1 140px (не none) - проверено вживую через getBoundingClientRect():
   с KPI-карточками сравнения периодов (.kpis.card, ~160px) НАД тулбаром
   .charts-box своим весом ВСЕГДА выдавливал .scroller ниже нижнего края
   .left, даже с потолком в 320px - на окне короче ~950px сумма
   kpis+toolbar+hint+320+160(пол .scroller) превышала высоту .left, и
   .scroller целиком уезжал за overflow:hidden, невидимый и недоступный
   никаким скроллом (не «едва видно» - вообще не в DOM-боксе .left).
   Теперь .charts-box тоже ужимается первым, раньше .scroller - у графика
   есть СВОЙ скролл внутри, у таблицы снаружи его нет.

   overflow-y здесь, на самом .charts-box, а не на .charts-pair внутри -
   тоже проверено вживую и тоже неочевидно. .charts-pair - CSS-грид
   (grid-template-columns, tool-audit.css), и будучи одновременно
   flex-элементом .charts-box, он игнорировал flex-shrink/flex-basis: 0
   (проверено getComputedStyle - свойства применены верно, высота всё
   равно считалась по контенту, 335px, а не по доступному месту, 97px) -
   грид как flex-item в Chrome не ужимается ниже content-based авто-
   минимума только через min-height: 0 на себе самом, нужен был бы ещё
   один оборачивающий блок. Проще перенести overflow на .charts-box
   (обычный блок, не грид) - он сам уже надёжно ужат родителем (.left),
   и .charts-pair внутри него просто обрезается/скроллится как контент.
   Шапка `summary` - position: sticky, чтобы при скролле графика кнопка
   свернуть/переключатели динамика-доля не уезжали вместе с ним. */
.charts-box[open] { flex: 1 1 140px; min-height: 140px; max-height: min(32vh, 320px); overflow-y: auto; }
.charts-box[open] > summary { position: sticky; top: 0; z-index: 1; background: var(--surface-2); }
.charts-box[open] > .charts-pair { padding-right: 4px; }
.charts-legend { font-weight: 400; color: var(--text-3); font-size: 11.5px; }

/* Карточки показателей со своим SVG жили здесь до перехода на Plotly.
   Разметки под них не осталось ни в одном инструменте, и правила удалены:
   мёртвый CSS переживает любую переделку и однажды красит что-нибудь чужое. */


/* ==========================================================================
   Разбор моделью
   ==========================================================================
   Панель под кнопками в правой колонке. Разбор идёт минуты, поэтому у неё
   три состояния - готова, идёт, готово - и все три должны быть видны без
   догадок: «кнопка нажалась или нет» на минутном ожидании становится
   отдельным вопросом. */
/* Оговорки прогона. Свёрнуты: их бывает восемь по три строки, и развёрнутый
   список занимал правую колонку до самого низа - экран читался как страница
   предупреждений. В заголовке видно, сколько их и с чего начинается первая. */
.caveats > summary { cursor: pointer; list-style: none; }
.caveats > summary::-webkit-details-marker { display: none; }
.caveats > summary b { font-size: 12px; }
.caveats > summary::after {
  content: '▾'; float: right; color: var(--text-3); font-size: 11px;
  transition: transform .12s;
}
.caveats[open] > summary::after { content: '▴'; }
.caveats-note { display: block; font-size: 11px; color: var(--text-3); margin-top: 2px; }
.caveats-teaser {
  display: block; font-size: 11.5px; color: var(--text-2);
  margin-top: 6px; line-height: 1.45;
}
.caveats[open] .caveats-teaser { display: none; }
.caveats-lead {
  margin: 10px 0 6px; font-size: 11.5px; color: var(--text-3); line-height: 1.5;
}
.caveats ul { margin: 0; padding-left: 18px; }
.caveats li { margin-bottom: 6px; line-height: 1.45; }

/* Панель разбора - .fld/.selwrap/.sel (components-v3.css, дословно по
   эталону): своих .agent-field/.agent-label/.agent-skill больше нет. */
.agent-skill-hint {
  font-size: 11.5px; color: var(--text-3); margin-top: 5px; line-height: 1.5;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
}
/* Чужой скил помечается словом, а не только текстом подсказки: он написан
   не под эти данные, и это решение, а не мелочь оформления. */
.agent-foreign {
  font-size: 10px; text-transform: uppercase; letter-spacing: .04em;
  padding: 1px 6px; border-radius: 999px;
  background: var(--att-bg); color: var(--att-text); border: 1px solid var(--att-line);
}
.agent-skill-hint.pending { color: var(--warn, #9a6b00); }
/* Имя скила внутри подсказки - моноширинным: это имя файла в .claude/skills,
   а не слово из фразы, и найти его глазами надо сразу. */
.agent-skill-hint code {
  font-family: var(--font-mono);
  font-size: 10.5px; padding: 1px 4px; border-radius: 4px;
  background: var(--surface-2); border: 1px solid var(--line); color: var(--text-2);
}
.agent-meta {
  display: flex; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 8px; font-size: 11.5px; color: var(--text-3);
}
/* Разбор - это текст на несколько экранов. Держим его в своей прокрутке,
   иначе он выталкивает вниз всё остальное, включая кнопки. */
.agent-result {
  margin-top: 10px; padding: 11px 13px;
  max-height: 460px; overflow-y: auto;
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm); background: var(--surface);
  font-size: 12.5px; line-height: 1.6; white-space: pre-wrap; word-break: break-word;
}
.agent-result:empty { display: none; }


/* Узел графика Plotly. Своя рамка, чтобы график не висел на фоне страницы.

   Ширина задана явно, хотя блочный элемент и так тянется: Plotly меряет
   место в момент отрисовки, и любое «почти во всю ширину» он запоминает
   навсегда. Ширину поддерживает chartFit из charts.js - CSS тут только
   отдаёт место, а не растягивает уже нарисованное. */
.chart-node {
  width: 100%; min-width: 0;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface);
  /* Поля не для красоты: Plotly резервирует под подписи оси ровно их ширину
     и ни пикселя сверх, поэтому без внутреннего отступа самая длинная
     подпись упирается в рамку и читается как обрезанная. */
  padding: 10px 14px 6px;
}
.chart-node:empty { display: none; }
/* Панель кнопок Plotly (сохранить, увеличить, сбросить) появляется по
   наведению. Она рисуется поверх поля графика и по умолчанию липнет
   к самому его краю - там она задевает и рамку панели, и правую колонку.
   Отодвигаем внутрь и даём подложку: так она читается как набор кнопок,
   а не как артефакты поверх графика. */
.chart-node .modebar {
  top: 4px !important; right: 8px !important;
  background: var(--surface) !important;
  border-radius: var(--radius-sm);
  padding: 1px 2px;
  box-shadow: 0 0 0 1px var(--line);
}

/* ==========================================================================
   Разбор моделью: окно во весь экран
   ==========================================================================
   Разбор - это текст на две страницы с заголовками, списками и таблицами.
   В узкой правой колонке он не читается, а согласовывать его там тем более
   нельзя: человек должен видеть весь ответ целиком, прежде чем сказать
   «да, делаем документ». */
/* Визуально подтянуто к новому дизайну (тот же язык, что у .cmdk/.dlg):
   скруглённый угол r-2xl вместо старого radius-sm, контурная рамка поверх
   тени (в тёмной теме тень не видна, контур держит границу один),
   overflow: hidden, чтобы прямые углы .modal-head/.modal-foot не торчали
   за скруглением контейнера. Сам .modal/.modal-box не трогаю - это общие
   классы help-modal и upload-modal, у них другой, более простой экран. */
.agent-modal .modal-box {
  width: min(920px, 94vw); max-height: 92vh;
  border-radius: var(--r-2xl); border: 1px solid var(--line); overflow: hidden;
}
.agent-body {
  overflow-y: auto; padding: 18px 24px;
  font-size: 13.5px; line-height: 1.65; color: var(--text);
}
.agent-body h2 { font-size: 16px; margin: 22px 0 8px; font-weight: 600; }
.agent-body h3 { font-size: 14px; margin: 18px 0 6px; font-weight: 600; }
.agent-body h4 { font-size: 13px; margin: 14px 0 5px; font-weight: 600; color: var(--text-2); }
.agent-body h2:first-child, .agent-body h3:first-child { margin-top: 0; }
.agent-body p { margin: 0 0 10px; }
.agent-body ul, .agent-body ol { margin: 0 0 12px; padding-left: 22px; }
.agent-body li { margin-bottom: 5px; }
.agent-body code {
  padding: 1px 5px; border-radius: 3px;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: 12px;
}
.agent-body hr { border: 0; border-top: 1px solid var(--line); margin: 16px 0; }
.md-table { width: 100%; border-collapse: collapse; margin: 0 0 14px; font-size: 12.5px; }
.md-table th, .md-table td { padding: 6px 10px; border-bottom: 1px solid var(--line); text-align: left; }
.md-table th { background: var(--surface-2); font-weight: 600; color: var(--text-2); white-space: nowrap; }

/* Якорь в тексте разбора (DESIGN.md §8): ссылается на строку результата
   под окном, не на внешний адрес - курсор и подчёркивание те же, что
   у обычной ссылки, но это <button>, не <a>: некуда переходить. */
.agent-body .anchor {
  background: none; border: 0; padding: 0; margin: 0; font: inherit;
  color: var(--accent); text-decoration: underline; text-underline-offset: 2px;
  cursor: pointer;
}
.agent-body .anchor:hover { text-decoration-thickness: 2px; }

/* Строка результата, на которую сослался клик по якорю. Общий класс, а не
   отдельный у каждого инструмента: якорь в #agent-body не знает заранее,
   в таблицу он целится или в карточку аудита, и outline (не border) не
   меняет размеров ни у той, ни у другой - в отличие от границы, он не
   сдвигает соседей. */
.is-flagged { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--accent-soft); }

/* Подвал окна: что делать с разбором. Согласование - отдельная кнопка
   и отдельный шаг: документ клиенту не должен появляться сам собой. */
.agent-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.agent-foot .meta { margin-right: auto; font-size: 11.5px; color: var(--text-3); }
.agent-refine { display: grid; gap: 6px; padding: 0 24px 14px; }
.agent-refine textarea { width: 100%; }
.agent-stage {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 2px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 600;
}
.agent-stage.draft { background: var(--att-bg); color: var(--att-text); border: 1px solid var(--att-line); }
.agent-stage.final { background: var(--live-bg); color: var(--live-text); border: 1px solid var(--live-line); }
.agent-stage.busy { background: var(--surface-2); color: var(--text-2); border: 1px solid var(--line); }

/* Ожидание разбора: то же окно, но по центру и с движением.

   Почему по центру, а не строкой в правой колонке, как было. Разбор идёт
   минуту и больше, и всё это время на экране не менялось ничего, кроме
   серой кнопки «Разбирает…» шириной в треть панели. Ожидание без признаков
   жизни читается как поломка, и кнопку жмут второй раз. Здесь работа
   занимает середину экрана, значок крутится, счётчик идёт - вопрос
   «нажалось или нет» не возникает вовсе. */
.agent-wait {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 10px; padding: 54px 24px 58px; text-align: center;
}
.agent-spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--line);
  border-top-color: var(--accent);
  animation: notice-spin .8s linear infinite;
}
.agent-wait-stage { margin: 0; font-size: 14px; font-weight: 600; color: var(--text); }
/* Моноширинные цифры: без них счётчик дёргается на каждой секунде, потому
   что «1» уже «8», и движение читается как мигание, а не как ход времени. */
.agent-wait-time {
  margin: 0; font-size: 22px; font-weight: 600; color: var(--text-2);
  font-variant-numeric: tabular-nums;
}
/* Строка про кофе - не шутка ради шутки. Она отвечает на вопрос, который
   человек задаёт себе на сороковой секунде: «мне тут сидеть или можно
   заняться делом?». Ответ «можно» экономит эти полторы минуты. */
.agent-wait-coffee {
  margin: 2px 0 0; max-width: 430px;
  font-size: 12.5px; line-height: 1.6; color: var(--text-2);
}
.agent-wait-note {
  margin: 4px 0 0; max-width: 430px;
  font-size: 12px; line-height: 1.6; color: var(--text-3);
}
/* Кнопка, у которой отняли значок анимации, не должна прыгать: значок
   в разметке один и тот же, меняется только текст под ним. */
@media (prefers-reduced-motion: reduce) {
  .agent-spinner { animation-duration: 2.4s; }
}

