diff --git a/docs/backlog/ai-chat-collapse-on-page-focus.md b/docs/backlog/ai-chat-collapse-on-page-focus.md
new file mode 100644
index 00000000..fd134684
--- /dev/null
+++ b/docs/backlog/ai-chat-collapse-on-page-focus.md
@@ -0,0 +1,263 @@
+# Авто-сворачивание AI-чата в заголовок при фокусе на странице, разворот по клику
+
+## Контекст (запрос)
+
+Плавающее окно AI-чата (`AiChatWindow`) сейчас перекрывает контент страницы:
+если открыть чат и начать читать/листать вики-страницу под ним, окно остаётся
+во весь рост и закрывает таблицу/текст (см. скриншот: окно поверх «Аудио-тракт в
+умных колонках»). Свернуть можно только вручную — кнопкой «—» (Minimize) в шапке.
+
+Хотим, чтобы окно **само сворачивалось в свою шапку, как только пользователь
+переключается на страницу** (кликает мимо окна — в редактор/в контент), и
+**разворачивалось обратно по клику на шапку**. Тогда чат не мешает читать
+страницу, но остаётся под рукой одним кликом.
+
+Важно: сворачивание — это именно визуальный коллапс (как нынешний Minimize), а
+**не** закрытие. Поток ответа агента не должен прерываться.
+
+## Как сейчас устроено (цепочка)
+
+Всё во фронтенде, в одном компоненте окна:
+`apps/client/src/features/ai-chat/components/ai-chat-window.tsx`
+(+ его CSS `ai-chat-window.module.css`).
+
+- **Состояние «свёрнуто»** уже есть: `const [minimized, setMinimized] = useState(false)`
+ — строка ~108.
+- **Переключатель** `toggleMinimize` (строки ~319-321) просто инвертирует флаг;
+ привязан к кнопке «—» (`IconMinus`) в шапке (строки ~366-374).
+- **Визуальный коллапс уже реализован в CSS** (`ai-chat-window.module.css`):
+ - `.minimized { height: auto !important; min-height: 0 !important; resize: none; }`
+ (строки ~40-44) — окно схлопывается до высоты шапки;
+ - `.minimized .content { display: none; }` (строки ~56-58) — тело
+ (история + тред) скрывается, но **не размонтируется**: `ChatThread` остаётся
+ в DOM, поэтому идущий стрим/`AbortController` не обрывается (это явно описано в
+ комментариях у `.content` и в `toggleMinimize`).
+ - При `minimized` инлайновая `height` не задаётся (строка ~334), чтобы победила
+ auto-высота из CSS; резайз-ручка скрыта (строки ~454-458).
+- **Шапка = `.dragBar`** (JSX строки ~338-385) с `onMouseDown={startDrag}`.
+ - `startDrag` (строки ~262-314) игнорирует нажатия на кнопках
+ (`if ((e.target).closest("button")) return;`, строка ~264) — чтобы «—»/«×»/«+»
+ не таскали окно.
+ - В `mouseup` (`up`, строки ~290-308) сохраняется итоговая позиция в `geom`.
+ - **Клика-для-разворота сейчас нет**: одиночный клик по шапке только инициирует
+ перетаскивание, развернуть свёрнутое окно можно лишь повторным нажатием «—».
+- Окно смонтировано глобально и плавает над всем: `` в
+ `apps/client/src/components/layouts/global/global-app-shell.tsx` (строка ~159),
+ `position: fixed`, `z-index: 105` (ниже оверлеев Mantine: modal=200, menu=300,
+ notifications=400 — это нам важно, см. «Тонкие моменты»).
+- Композер автофокусится при монтировании треда (`autoFocus` в
+ `chat-input.tsx`) — это фокус **внутри** окна, не на странице.
+
+Итого: «свёрнутый» вид готов. Нужно добавить **два триггера**: (1) авто-сворот при
+взаимодействии со страницей и (2) разворот по клику на шапку.
+
+## Решение (точечное, только клиент)
+
+Файл: `apps/client/src/features/ai-chat/components/ai-chat-window.tsx`
+(+ пара строк CSS, опционально + i18n-ключ).
+
+### Часть 1 — авто-сворачивание при взаимодействии со страницей
+
+Слушаем `mousedown`/`pointerdown` на `document` (в capture-фазе), но **только**
+когда окно открыто и ещё не свёрнуто. Если нажатие пришло **вне окна** и **не
+внутри портала Mantine** — сворачиваем.
+
+```ts
+// Auto-collapse the window into its header as soon as the user interacts with
+// anything outside it (clicks the page/editor). Active only while open and
+// expanded. Capture phase so a child's stopPropagation can't hide the event.
+useEffect(() => {
+ if (!windowOpen || minimized) return;
+ const onPointerDown = (e: MouseEvent) => {
+ const target = e.target as HTMLElement | null;
+ const el = winRef.current;
+ if (!el || !target) return;
+ // Inside the window itself -> not an "away" interaction.
+ if (el.contains(target)) return;
+ // Inside a Mantine portal the chat owns (kebab Menu dropdown, delete-confirm
+ // modal, the context-size Tooltip, notifications). Mantine's Portal sets
+ // data-portal="true" on its node, so this reliably excludes ALL of them.
+ if (target.closest("[data-portal]")) return;
+ setMinimized(true);
+ };
+ document.addEventListener("mousedown", onPointerDown, true);
+ return () => document.removeEventListener("mousedown", onPointerDown, true);
+}, [windowOpen, minimized]);
+```
+
+Почему `mousedown` (а не `focusin`):
+- Клик по **не-фокусируемому** элементу страницы (ячейка таблицы, обычный текст —
+ ровно случай со скриншота) фокус-событие не порождает, но это и есть «ушёл на
+ страницу». `mousedown` ловит любой клик. `focusin` пропустил бы такие клики.
+- Минус: `mousedown` не ловит переход фокуса с клавиатуры (Tab в редактор). Если
+ это нужно — добавить параллельно `focusin`-слушатель с тем же гардом (см.
+ «Открытые вопросы»). По умолчанию — только указатель, как и просит запрос
+ («смена фокуса на страницу» = клик мимо окна).
+
+Почему гард `[data-portal]` обязателен:
+- Кебаб-меню списка чатов рендерит `Menu.Dropdown` в портал (вне DOM окна) —
+ `conversation-list.tsx` строки ~123-149; удаление — `modals.openConfirmModal`
+ (строка ~56), тоже портал. Без гарда клик по пункту «Rename»/«Delete» свернул
+ бы чат прямо в момент выбора. Mantine на узле портала ставит
+ `data-portal="true"` (подтверждено в `node_modules/@mantine/core` →
+ `Portal.cjs`), поэтому `target.closest("[data-portal]")` исключает их все
+ (а заодно Tooltip размера контекста и нотификации — они тоже порталы).
+
+Регистрация в `useEffect` с deps `[windowOpen, minimized]`: слушатель вешается
+только когда `windowOpen && !minimized`, и снимается при сворачивании/закрытии —
+не делаем лишней работы и не дёргаем `setMinimized(true)` повторно.
+
+### Часть 2 — разворот по клику на шапку
+
+Нужно отличить **клик** по шапке (развернуть) от **перетаскивания** свёрнутой
+плашки (она остаётся таскаемой). Нельзя просто навесить `onClick` на `.dragBar`:
+браузер шлёт `click` и в конце драга (mousedown+mouseup на том же элементе), и
+плашка разворачивалась бы после любого перетаскивания.
+
+Решение — доработать существующий `startDrag`: запомнить стартовые координаты,
+а в `mouseup` посчитать смещение; если оно ниже порога (≈4px) **и** окно сейчас
+свёрнуто — развернуть.
+
+```ts
+const startDrag = useCallback((e: React.MouseEvent): void => {
+ if ((e.target as HTMLElement).closest("button")) return;
+ const el = winRef.current;
+ if (!el) return;
+ const sx = e.clientX;
+ const sy = e.clientY;
+ // ... (ol/ot + move() unchanged)
+
+ const up = (ev: MouseEvent): void => {
+ document.removeEventListener("mousemove", move);
+ document.removeEventListener("mouseup", up);
+ document.body.style.userSelect = "";
+ // Treat a near-zero-movement press as a click. When minimized, a click on
+ // the header expands the window (drag still repositions the collapsed bar).
+ const moved =
+ Math.abs(ev.clientX - sx) > 4 || Math.abs(ev.clientY - sy) > 4;
+ if (!moved && minimizedRef.current) {
+ setMinimized(false);
+ return; // nothing to persist: position didn't change
+ }
+ // ... (persist geom as before)
+ };
+ // ...
+}, []);
+```
+
+Подводный камень — **stale closure**: `startDrag` обёрнут в `useCallback([])`,
+поэтому замыкает устаревший `minimized`. Два варианта:
+- держать `minimizedRef = useRef(minimized)` и синхронизировать его в эффекте
+ (`minimizedRef.current = minimized`) — тогда `useCallback([])` остаётся (как в
+ коде выше); **рекомендуется**, не пересоздаёт хендлер;
+- либо добавить `minimized` в deps `useCallback` — проще, но пересоздаёт `startDrag`
+ на каждом тоггле (дёшево, но дёргает `onMouseDown`-проп).
+
+Кнопка «—» остаётся как явный тоггл (`toggleMinimize` уже инвертирует флаг), так
+что развернуть можно и ей. Менять её не нужно.
+
+### Часть 3 (рекомендуется) — аффорданс и доступность шапки
+
+- **Курсор**: в свёрнутом виде шапка кликабельна — заменить `grab` на `pointer`:
+ ```css
+ /* ai-chat-window.module.css — hint that the collapsed header expands on click */
+ .minimized .dragBar { cursor: pointer; }
+ ```
+- **Клавиатура/скринридер**: `.dragBar` — это `div`. В свёрнутом состоянии дать
+ ему `role="button"`, `tabIndex={0}`, `aria-label={t("Expand")}` и обработчик
+ Enter/Space → `setMinimized(false)`. Иначе развернуть без мыши нельзя.
+
+## Тонкие моменты / edge cases
+
+- **Стрим не прерывается.** Авто-сворот выставляет `minimized=true` — `ChatThread`
+ остаётся смонтированным (только `.content` скрывается). Ответ агента
+ достреливается в фоне; развернув шапку, пользователь видит результат. Это
+ желаемое поведение (он специально ушёл читать страницу).
+- **Автофокус композера при открытии.** Открытие окна автофокусит textarea —
+ это `focus` **внутри** окна, а не внешний `mousedown`, поэтому ложного
+ немедленного сворота не будет.
+- **Перетаскивание окна** (mousedown по шапке) — это нажатие **внутри**
+ `winRef.current`, гард `el.contains(target)` его пропускает: drag не сворачивает.
+- **Резайз** нативной ручкой — mousedown тоже внутри окна, не сворачивает.
+- **Порталы дочерних компонентов** (кебаб-меню, confirm-модалка, tooltip,
+ нотификации) исключены гардом `[data-portal]` — клик по ним не сворачивает.
+ Это ключевая причина не использовать «голый» contains-only outside-click.
+- **Capture-фаза** слушателя: ловим `mousedown` даже если кто-то на странице
+ вызывает `stopPropagation` в bubble-фазе. На клики внутри окна/порталов не
+ влияет (их отсекают гарды).
+- **Повторный авто-сворот** не происходит: при `minimized` слушатель снят (deps
+ эффекта). Разворот по клику снова навешивает слушатель — цикл корректен.
+- **Состояние при закрытии/открытии.** Компонент при `!windowOpen` возвращает
+ `null`, но **не размонтируется**, поэтому `minimized` переживает закрытие.
+ Желательно при каждом открытии показывать окно **развёрнутым**: добавить
+ `setMinimized(false)` в эффект, срабатывающий на переход `windowOpen → true`
+ (можно в тот же `useLayoutEffect`, что вычисляет геометрию, строки ~238-241).
+ См. «Открытые вопросы».
+- **z-index/оверлеи.** Окно (105) ниже modal/menu/notifications — поэтому
+ confirm-модалка удаления и кебаб-меню рисуются **над** окном; даже если бы чат
+ свернулся за ними, они продолжали бы работать. Но гард `[data-portal]` всё равно
+ не даёт сворачиваться при работе с ними.
+- **Touch.** Драг сейчас на mouse-событиях (десктоп-фича). Для единообразия
+ внешний слушатель можно сделать `pointerdown` вместо `mousedown` (покроет тач),
+ но тогда и порог-клик в `up` стоит считать на pointer-событиях. По умолчанию —
+ `mousedown`, как у драга.
+
+## i18n
+
+- Новые пользовательские строки — **только через `t(...)`** и добавить ключ в
+ `apps/client/public/locales/en-US/translation.json` (каталог ключ==значение).
+ Достаточно `"Expand"` (для `aria-label`/`title` шапки в свёрнутом виде).
+ В шапке уже есть `t("Minimize")`, `t("Close")`, `t("New chat")`.
+- Комментарии в коде — на английском (правило проекта).
+
+## Тесты
+
+- Вынести чистые хелперы и покрыть Vitest:
+ - `shouldCollapseOnOutsidePointer(target, windowEl): boolean`
+ (`windowEl.contains(target)` + `target.closest("[data-portal]")`) —
+ `(внутри окна) → false`, `(в портале) → false`, `(на странице) → true`.
+ - `isHeaderClick(dx, dy, threshold=4): boolean` — порог клик-vs-драг.
+- Компонентный тест (`@testing-library/react`): открыть окно → диспатчить
+ `mousedown` по `document.body` → окно получает класс `.minimized`; клик по
+ `.dragBar` (без движения) в свёрнутом виде → класс снят. Проверить, что
+ `mousedown` по узлу с `data-portal` сворота не вызывает.
+- Прогнать `pnpm --filter client lint` и `pnpm --filter client test`.
+
+## Файлы к изменению
+
+- `apps/client/src/features/ai-chat/components/ai-chat-window.tsx`
+ — внешний `mousedown`-эффект (Часть 1); доработка `startDrag` + `minimizedRef`
+ (Часть 2); опц. `setMinimized(false)` при открытии; a11y-атрибуты на `.dragBar`.
+- `apps/client/src/features/ai-chat/components/ai-chat-window.module.css`
+ — опц. `.minimized .dragBar { cursor: pointer; }`.
+- `apps/client/public/locales/en-US/translation.json` — ключ `"Expand"` (если
+ добавляем aria/title).
+
+## Альтернативы / расширения (вне базового объёма)
+
+- **`useClickOutside` из `@mantine/hooks`** вместо ручного слушателя. Минус:
+ порталы дочерних меню/модалок нужно явно передавать как `nodes` для игнора, а
+ они создаются динамически — ручной гард `[data-portal]` проще и надёжнее.
+ Поэтому ручной слушатель предпочтительнее.
+- **Учитывать клавиатурный фокус** (`focusin`) дополнительно к `mousedown` — если
+ захотим сворачивать и при Tab в редактор.
+- **Не сворачивать во время стрима** — если решим, что во время генерации окно
+ должно оставаться раскрытым (противоречит идее «ушёл читать страницу», поэтому
+ по умолчанию сворачиваем всегда).
+- **Анимация коллапса/разворота** (height/opacity transition) — косметика, можно
+ добавить позже в `.window`/`.content`.
+
+## Принятые решения (базовый объём)
+
+- **Триггер авто-сворота — только клик** (`mousedown` в capture-фазе).
+ `focusin` не добавляем: запрос — про переключение на страницу кликом, а клик по
+ не-фокусируемому контенту (ячейка таблицы) фокус-событие не даёт.
+- **При каждом открытии окна показываем его развёрнутым** —
+ `setMinimized(false)` на переход `windowOpen → true`. Свёрнутое состояние не
+ «залипает» между сессиями открытия.
+- **Во время стрима сворачиваем как обычно.** Поток не прерывается (`ChatThread`
+ остаётся смонтированным), результат виден после разворота — это и есть смысл
+ «ушёл читать страницу».
+- **Клавиатурный разворот шапки входит в базовый объём** — в свёрнутом виде
+ `.dragBar` получает `role="button"`, `tabIndex={0}`, `aria-label={t("Expand")}`
+ и обработку Enter/Space. Доступность без мыши обязательна.
diff --git a/docs/backlog/comments-panel-density.md b/docs/backlog/comments-panel-density.md
new file mode 100644
index 00000000..c17e569a
--- /dev/null
+++ b/docs/backlog/comments-panel-density.md
@@ -0,0 +1,181 @@
+# Панель комментариев: сделать плотнее (меньше воздуха, меньше шрифт)
+
+Статус: **план, код не менялся.** Чисто UI-задача на клиенте (CSS + пропсы
+Mantine). Бэкенда, схемы данных и логики не касается.
+
+## Суть
+
+Сейчас панель комментариев (правый aside, вкладка «Comments») выглядит
+разреженной: крупные отступы между карточками и внутри них, большой межстрочный
+интервал, тело комментария набрано базовым размером редактора (16px). На узкой
+колонке это «съедает» вертикаль — на экран помещается мало комментариев, много
+пустого места.
+
+Хотим: **уплотнить раскладку** — уменьшить внутренние/внешние отступы карточек,
+зазор «аватар ↔ текст», вертикальный ритм редактора — **и уменьшить шрифт**
+тела комментария, имени автора и цитаты выделения. Цель — больше комментариев
+на экран без потери читабельности.
+
+## Где сейчас живёт «воздух» (точные места)
+
+Вся вёрстка панели — в фиче `apps/client/src/features/comment/`.
+
+### 1. Карточка комментария — [comment-list-with-tabs.tsx](apps/client/src/features/comment/components/comment-list-with-tabs.tsx)
+- `renderComments`, обёртка каждого треда (~строки 121-129):
+ `` — `p="sm"` (12px
+ внутренний отступ) и `mb="sm"` (12px зазор между комментариями).
+- Разделитель перед редактором ответа (~строка 148): ``.
+- Вкладки (`Tabs.Panel pt="xs"`, строки 226 и 245) и пустое состояние
+ (``, строки 228 и 247) — второстепенные источники воздуха.
+- Нижнее поле ввода `PageCommentInput` (строки ~361-405): `paddingTop` = `sm`,
+ `paddingBottom: 25`, аватар `marginTop: 10`, кнопка отправки спозиционирована
+ `bottom: 30`. Эти величины связаны (плавающая кнопка над полем) — трогать
+ осторожно.
+
+### 2. Элемент комментария — [comment-list-item.tsx](apps/client/src/features/comment/components/comment-list-item.tsx)
+- Внешняя обёртка (строка 119): `` — 10px снизу у каждого
+ элемента (включая вложенные ответы).
+- Шапка «аватар ↔ контент» (строка 120): `` **без** `gap` → дефолтный
+ `gap="md"` (16px) между аватаром и блоком с именем/телом. Это главный
+ горизонтальный «воздух».
+- Имя автора (строка 129): `` — 14px.
+- Время (строки 157-161): уже `` (12px) — оставить.
+- Цитата выделения (строка 180): `{comment?.selection}` —
+ 14px, внутри блока `.textSelection`.
+
+### 3. Стили — [comment.module.css](apps/client/src/features/comment/components/comment.module.css)
+- `.textSelection` (строки 9-21): `margin-top: 4px`, `padding: 8px`.
+- `.commentEditor .ProseMirror :global(.ProseMirror)` (строки 35-44):
+ `margin-top: 10px`, `margin-bottom: 2px`, паддинги 6px. **font-size не задан** —
+ тело комментария наследует глобальный
+ `.ProseMirror { font-size: var(--mantine-font-size-md) }` (16px) из
+ [core.css:10](apps/client/src/features/editor/styles/core.css#L10).
+- `.wrapper` (строки 1-3) — `padding: md`, **в коде не используется** (можно
+ игнорировать или удалить заодно).
+
+### 4. Внешняя рамка панели (ВНИМАНИЕ: общая) — [aside.tsx](apps/client/src/components/layouts/global/aside.tsx)
+- `` (строка 47) и шапка `` с
+ `` (строки 50-51) дают 16px отступа по краям панели
+ и под заголовком. **Этот контейнер общий для трёх вкладок** aside
+ (`comments` / `toc` / `details`). Менять его — значит уплотнить заодно
+ «Содержание» и «Детали». См. «Открытые вопросы».
+
+Шкалы Mantine в проекте без переопределений (`theme.ts` палитру/контраст меняет,
+но не размеры): шрифт `xs=12px / sm=14px / md=16px`; spacing `xs=10 / sm=12 /
+md=16`.
+
+## Решение (точечное, в границах фичи comment)
+
+Базовый объём — **только компоненты `features/comment/`**, чтобы вкладки
+«Содержание»/«Детали» (общий `aside.tsx`) не задеть. Уплотнение рамки панели —
+отдельный опциональный пункт (см. ниже).
+
+### Правки по файлам
+
+**`comment-list-with-tabs.tsx`**
+- `` в `renderComments`: `p="sm"` → `p="xs"`, `mb="sm"` → `mb="xs"`
+ (12 → 10px). `shadow="sm"`, `radius="md"`, `withBorder` — оставить.
+- `` → `my={2}`.
+
+**`comment-list-item.tsx`**
+- `` → `pb={6}`.
+- Шапка `` (аватар + контент, строка 120): добавить `gap="xs"`
+ (дефолтные 16px → 10px). НЕ трогать внутренние ``
+ и ``, у них зазор уже задан.
+- Имя: `` → `size="xs"`. `fw={500}` и `lineClamp={1}` —
+ оставить (см. «иерархия шрифта» ниже).
+- Цитата: `{comment?.selection}` → `size="xs"`.
+
+**`comment.module.css`**
+- В `.ProseMirror :global(.ProseMirror)` добавить
+ `font-size: var(--mantine-font-size-sm);` (16 → 14px) и `line-height: 1.4;`,
+ заменить `margin-top: 10px` → `margin-top: 4px`. Остальные декларации
+ (`border-radius`, `max-width`, `white-space`, `word-break`, паддинги,
+ `margin-bottom`) — без изменений.
+- `.textSelection`: `margin-top: 4px` → `2px`, `padding: 8px` → `6px`.
+
+### Эскиз (ключевой фрагмент CSS)
+
+```css
+.commentEditor {
+ /* ... */
+ .ProseMirror :global(.ProseMirror) {
+ border-radius: var(--mantine-radius-sm);
+ max-width: 100%;
+ white-space: pre-wrap;
+ word-break: break-word;
+ padding-left: 6px;
+ padding-right: 6px;
+ /* Denser comments: shrink body text from the global 16px ProseMirror size
+ to 14px and tighten the rhythm vs. the comment header. */
+ font-size: var(--mantine-font-size-sm);
+ line-height: 1.4;
+ margin-top: 4px; /* was 10px */
+ margin-bottom: 2px;
+ }
+}
+
+.textSelection {
+ margin-top: 2px; /* was 4px */
+ padding: 6px; /* was 8px */
+ /* ...остальное без изменений... */
+}
+```
+
+## Тонкие моменты / edge cases
+
+- **Не трогать `aside.tsx` в базовом объёме.** Его `p="md"` и шапка общие для
+ вкладок `toc`/`details` — правка уплотнит и их. Если это нежелательно, держать
+ изменения строго внутри `features/comment/`.
+- **Иерархия шрифта (принято).** После правок: имя — `xs` (12px, `fw=500`),
+ тело — `sm` (14px), время — `xs` (12px). Тело крупнее имени — это норма
+ (имя/мета как «капс-лейбл», тело как основной текст).
+- **`font-size` ставится на внутренний `:global(.ProseMirror)`,** т.к. размер
+ приходит из глобального правила `core.css`. Класс-модуль `.commentEditor`
+ скоупит переопределение только на редактор комментариев — основной редактор
+ страницы не затрагивается.
+- **Тёмная тема.** Меняем только размеры/отступы, цвета берутся из токенов
+ Mantine — отдельной проверки палитры не требуется, но визуально глянуть стоит.
+- **Вложенные ответы** рендерятся тем же `CommentListItem` → уплотнение `pb`,
+ `gap`, шрифтов применится и к ним автоматически (так и нужно).
+- **Markdown/код в теле.** `pre`/`code`/списки внутри комментария наследуют
+ `font-size` от `.ProseMirror` контейнера — после `font-size: sm` они тоже
+ станут компактнее; проверить, что код-блоки не разъезжаются.
+- **Цитата выделения кликабельна** (`role="button"`, переход к месту в тексте) —
+ уменьшение `padding`/`size` не должно сломать зону клика; визуально проверить.
+- **Нижнее поле ввода** (`PageCommentInput`) с плавающей кнопкой: величины
+ `paddingBottom: 25` / `bottom: 30` связаны. В базовом объёме не трогаем; если
+ захотим уплотнить и его — менять обе согласованно и проверить, что кнопка
+ отправки не наезжает на текст.
+
+## Тесты / проверка
+
+- Прогнать `pnpm --filter client lint` и `pnpm --filter client test`
+ (изменения косметические — падений быть не должно).
+- Ручная проверка во вкладке Comments: тред с длинным телом, тред с цитатой
+ выделения, вложенные ответы, режим редактирования, светлая/тёмная тема, узкая
+ ширина aside. Убедиться, что вкладки «Содержание»/«Детали» не изменились
+ (если `aside.tsx` не трогали).
+
+## Опционально / расширения (вне базового объёма)
+
+- **Уплотнить рамку панели** — `aside.tsx`: `p="md"` → `p="sm"`, шапка
+ `mb="md"` → `mb="sm"`. Даст ощутимо меньше воздуха по краям, **но затронет все
+ вкладки aside** (см. «Открытые вопросы»).
+- **Компактные вкладки Tabs** — `Tabs.Panel pt="xs"` → `pt={6}`, бейджи счётчиков
+ уже `size="sm"`.
+- **Удалить мёртвый `.wrapper`** из `comment.module.css` (не используется).
+- **Уменьшить аватары** с `size="sm"` до `size="xs"` в `CommentListItem` и
+ `PageCommentInput` для ещё большей плотности (проверить, что инициалы/картинка
+ не мельчат до нечитаемости).
+
+## Принятые решения
+
+Решения зафиксированы — реализовать можно сразу, без доп. согласований:
+
+- **Границы правки:** строго `features/comment/`. Общую рамку aside (`p="md"`,
+ шапка `mb="md"`) **не трогаем** — она общая с вкладками «Содержание»/«Детали»,
+ и правка задела бы их (см. «Опционально», если позже захотим уплотнить и их).
+- **Шрифт тела:** `sm` (14px) — не мельче.
+- **Иерархия:** имя `xs` (12px, `fw=500`), тело `sm` (14px), время `xs` (12px).
+- **Нижнее поле ввода и размер аватаров:** оставляем как есть.