@layer ui {
/* Мысли на «Дне» (ritm#28) и тост с «Отменить».

   Список — очередь на разбор, а не архив. Строка: точка статуса слева, текст в
   одну строку, справа меню. Слово рядом с точкой только там, где идёт процесс:
   объяснять состояние словами под каждым элементом не нужно, статус читается по
   точке и по полосе. Значения — только из tokens.css. */

.thoughts {
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}

/* Ничего не ждёт — блока нет (ritm#380): ни рамки, ни подложки, остаётся тихая
   строка «Архив мыслей». Секция на месте — в неё встанет новая мысль. */
.thoughts-empty {
  padding-top: 0;
  padding-bottom: 0;
  background: none;
  border-color: transparent;
}

.thoughts-empty .thoughts-archive {
  margin-top: 0;
  border-top: 0;
}

.thoughts-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  padding-bottom: var(--space-2);
}

.thoughts-title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

/* --- строка ---------------------------------------------------------------- */

/* Строка мысли: точка статуса и тело. Кнопка «⋯» лежит поверх правого края, а
   не отдельной колонкой сетки (владелец 12.09: «справа большой пустой отступ»).
   Колонка держала 44 px плюс зазор у каждой строки — и у пузырей переписки, и у
   поля ответа; место под «⋯» нужно только первой строке, где стоит заголовок.

   Первая строка — своя дорожка сетки высотой в строку заголовка (ritm#295):
   точка статуса и «⋯» стоят по её середине. Раньше их опускали числами,
   подобранными под одну высоту строки, — точку `margin-top: 7px`, «⋯» верхом
   меню. Строка на телефоне 21,75 px, на десктопе 23,2, и точка съезжала на
   1,4–2,1 px, «⋯» на 2,4–3,1; а в шторке мысли, где строки нет, те же 7 px
   ставили точку на 4 px ниже слова статуса. */
.thought {
  --thought-line: calc(var(--text-md) * var(--leading-normal));
  position: relative;
  display: grid;
  grid-template-columns: 14px minmax(0, 1fr);
  grid-template-rows: var(--thought-line) auto;
  column-gap: var(--space-3);
  align-items: start;
  padding: var(--space-2) 0;
  border-top: 1px solid var(--line);
  animation: ritm-rise var(--dur-2) var(--ease);
}

.thought > .thought-dot {
  grid-row: 1;
  align-self: center;
}

.thought > .thought-body {
  grid-row: 1 / span 2;
}

/* «⋯» — в первой строке сетки, а не от краёв строки: поверх, из потока, но
   рамкой ему служит дорожка первой строки (grid-row у абсолютного). Так «⋯»
   ходит вместе с заголовком, когда строка складывается при уходе и её поля
   тают до нуля: от верха строки «⋯» оставалась на месте и отставала от
   заголовка на все 8 px (ritm#295, замер на стенде с живым разбором).
   Середина кнопки — на середине дорожки: кнопка в 44 px выступает над меню
   на 8 px (поле −8px у .rowmenu-more), значит, верх меню — на 22 − 8 = 14 px
   выше середины. Обе линии — явно: у абсолютного `auto` вместо второй линии
   значит край строки, а не «одна дорожка». */
.thought > .rowmenu {
  position: absolute;
  grid-column: 2 / 3;
  grid-row: 1 / 2;
  top: calc(50% - 14px);
  right: 0;
}

.thought:first-of-type {
  border-top: 0;
}

/* Складывание при удалении и при уходе в задачу: строка уезжает вверх и
   схлопывается по высоте. Высоту ставит скрипт из фактической. */
.thought.is-leaving {
  overflow: hidden;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease),
    height var(--dur-2) var(--ease), padding var(--dur-2) var(--ease);
  padding-top: 0;
  padding-bottom: 0;
}

/* Точка статуса: ждёт руки — контур; в работе — заливка акцентом и дыхание;
   в очереди — приглушённая; спотыкается — охра. */
.thought-dot {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  border: 1.5px solid var(--line-strong);
  background: transparent;
  justify-self: center;
}

.thought[data-status="processing"] .thought-dot,
.tsheet[data-status="processing"] .thought-dot {
  border-color: var(--accent);
  background: var(--accent);
  animation: ritm-rec-dot 1.2s infinite;
}

.thought[data-status="queued"] .thought-dot,
.tsheet[data-status="queued"] .thought-dot {
  border-color: var(--line-strong);
  background: var(--surface-sunken);
}

.thought[data-status="stuck"] .thought-dot,
.tsheet[data-status="stuck"] .thought-dot {
  border-color: var(--status-warn);
  background: var(--status-warn-soft);
}

/* Разобранные мысли остаются в списке (владелец 06.09): сделано — зелёная
   отметка в стилистике макета, задачи агент не увидел — охра, разбор сорвался —
   красноватая. Текст сделанной приглушён: она уже не просит внимания. */
.thought[data-status="done"] .thought-dot,
.tsheet[data-status="done"] .thought-dot {
  border-color: var(--status-good);
  background: var(--status-good);
}

.thought[data-status="none"] .thought-dot,
.tsheet[data-status="none"] .thought-dot {
  border-color: var(--status-warn);
  background: var(--status-warn-soft);
}

.thought[data-status="failed"] .thought-dot,
.tsheet[data-status="failed"] .thought-dot {
  border-color: var(--status-bad);
  background: var(--status-bad-soft);
}

.thought[data-status="done"] .thought-text {
  color: var(--text-secondary);
}

.thought[data-status="ask"] .thought-dot,
.tsheet[data-status="ask"] .thought-dot {
  border-color: var(--status-warn);
  background: var(--status-warn);
}

.thoughts-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}

/* display: flex сильнее браузерного [hidden] { display: none }: без этой пары
   пустой список показывал шапку «Мысли · 0». */
.thoughts-head[hidden] {
  display: none;
}

/* Дорога в архив — в конце списка (ritm#91): отдельной строкой под мыслями, а
   не подписью в шапке, где она перебивала сами мысли. */
.thoughts-archive {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  margin-top: var(--space-2);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
  color: var(--text-muted);
  font-size: var(--text-sm);
  text-decoration: none;
}

/* Стрелка «chevron-right» и так смотрит вправо (ritm#264): поворот, оставшийся
   от прежней стрелки вниз, ставил её вверх. */
.thoughts-archive .ic {
  width: 16px;
  height: 16px;
}

.thought-result-ask {
  margin: 2px 0 0;
  color: var(--status-warn);
}

.thought-result-ask span {
  color: var(--text-secondary);
}

/* Диалог с агентом (ritm#54): виден в раскрытой мысли, как и действия. Вид —
   окно переписки (ritm#241): сообщение агента слева, своё справа, время под
   пузырём. Подписи «ТЫ» и «АГЕНТ» убраны: сторона говорит то же самое. */
.thought-dialog {
  display: none;
  margin-top: var(--space-2);
  padding-top: var(--space-2);
  border-top: 1px solid var(--line);
}

.thought.is-open .thought-dialog {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* Раскрытая мысль показывает итог перепиской, а не строкой над ней: один и тот
   же текст стоял дважды (владелец 12.09). Свёрнутая строка итог оставляет —
   там его больше негде взять. */
.thought.is-open .thought-result,
.thought.is-open .thought-result-ask {
  display: none;
}

/* Заметка разбора — то же самое третьим экземпляром («Не увидел задачи» над
   пузырём «Не увидел здесь задачи»). Гасим только когда в переписке есть что
   читать: у сорвавшегося разбора причина стоит именно в заметке, и она нужна. */
.thought.is-open:has(.thought-msg) .thought-note {
  display: none;
}

.thought-msg {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: 86%;
}

.thought-msg-agent {
  align-self: flex-start;
  align-items: flex-start;
}

.thought-msg-human {
  align-self: flex-end;
  align-items: flex-end;
}

.thought-bubble {
  margin: 0;
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--text);
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  border-bottom-left-radius: var(--space-1);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.thought-msg-human .thought-bubble {
  background: var(--accent-soft);
  border-color: var(--line-accent);
  border-bottom-left-radius: var(--radius-md);
  border-bottom-right-radius: var(--space-1);
}

.thought-msg-at {
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.thought-msg-link {
  color: var(--text-muted);
}

.thought-result {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--status-good);
  text-decoration: none;
}

.thought-result .ic {
  width: 14px;
  height: 14px;
}

.thought-result span {
  color: var(--text-secondary);
}

/* Строка мысли раскрывается нажатием, а удерживание открывает её меню, поэтому
   выделять текст пальцем некуда: браузер подсвечивал выделение синим прямо во
   время раскрытия. Заодно выключено меню браузера по удержанию (владелец 12.09,
   как у карточек доски). Переписка остаётся выделяемой — оттуда текст копируют. */
.thought-body {
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.thought-dialog,
.thought-note,
.thought-error {
  -webkit-user-select: text;
  user-select: text;
}

.thought-body {
  min-width: 0;
  cursor: pointer;
}

.thought-line {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  min-width: 0;
  /* Место под «⋯» — только здесь: остальное тело строки идёт во всю ширину. */
  padding-right: 44px;
}

.thought-text {
  flex: 1;
  min-width: 0;
  font-size: var(--text-md);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Раскрытая мысль показывает переносы: мысль набирают в несколько строк
   (ritm#275), и склеивать их в абзац значит потерять список, ради которого
   строки и ставили. Закрытая строка по-прежнему одна — там переносы ни к чему. */
.thought.is-open .thought-text {
  white-space: pre-line;
  overflow: visible;
}

.thought-when {
  flex: none;
  font-size: var(--text-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

/* Вторая строка — только у тех, у кого есть процесс или длительность. */
/* Строка статуса ровняется по своей первой строке, а не по середине (ritm#295).
   Пометка агента в ней переносится (C14), и при `align-items: center` всё
   остальное — этап («ждёт разбора», «1-я в очереди»), «голосовое», скрепка,
   полоса — уезжало к середине её абзаца: на 8,7 px при двух строках, на 17,4
   при трёх. Так выглядела мысль, вернувшаяся в очередь со старой пометкой
   (ответ агенту, «Повторить»), — на телефоне, где пометка переносится.
   Теперь всё прижато к верху и высотой в строку `--thought-meta-line`: первые
   строки совпадают сами, а полосу, у которой строки нет, ставит по середине
   строки формула.
   Строка статуса переносится между частями, а не внутри них (ritm#451): рядом
   с длинной пометкой «голосовое · 0:12» рвалась посередине, а пометка сжималась
   в колонку в 146 px на пять строк. Теперь пометка, которой не хватает места
   целиком, уходит строкой ниже во всю ширину (ниже — у `.thought-note`). */
.thought-meta {
  --thought-meta-line: calc(var(--text-xs) * var(--leading-normal));
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 2px var(--space-2);
  margin-top: 2px;
  font-size: var(--text-xs);
  line-height: var(--thought-meta-line);
  color: var(--text-secondary);
}

.thought-stage,
.thought-voice {
  white-space: nowrap;
}

/* Полоса расшифровки — настоящая: whisper на этой ВМ идёт примерно в реальном
   времени, длительность записи известна, ширину ставит скрипт по времени. */
.thought-bar {
  position: relative;
  flex: 1;
  max-width: 9rem;
  height: 3px;
  /* По середине первой строки статуса: строки текста у полосы нет. */
  margin-block: calc((var(--thought-meta-line) - 3px) / 2);
  border-radius: 2px;
  background: var(--surface-sunken);
  overflow: hidden;
}

.thought-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--accent);
  border-radius: 2px;
  transition: width 1s linear;
}

/* Раскрытие: действия появляются под текстом за --dur-2. */
.thought-actions {
  display: none;
  gap: var(--space-2);
  margin-top: var(--space-3);
  animation: ritm-fade-in var(--dur-2) var(--ease);
}

.thought.is-open .thought-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

/* Удаление — иконкой у правого края ряда действий (владелец 12.09). Тот же рост,
   что у кнопок рядом, чтобы ряд не плавал; красным вспыхивает только под
   пальцем: мысль удаляется с «Отменить», а не безвозвратно. */
.thought-actions .thought-delete {
  margin-left: auto;
}

.thought-drop {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--control-h);
  height: var(--control-h);
  padding: 0;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  cursor: pointer;
}

.thought-drop:active {
  color: var(--status-bad);
  border-color: var(--status-bad);
}

.thought-drop .ic {
  width: 18px;
  height: 18px;
}

.thought-error {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--status-warn);
}

/* Пометка агента («не увидел здесь задачи») — не ошибка, а факт: приглушённо.
   В строке статуса (аудит 23.09, C14) — следом за этапом, если помещается там
   целиком; нет — строкой ниже во всю ширину (ritm#451, выбор владельца «Б»).
   Длинная переносится внутри себя, а не обрезается: у сорвавшегося разбора
   причина именно здесь. В архиве мыслей она по-прежнему абзацем. */
.thought-note {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

/* Основа — длина самой пометки одной строкой (`auto`), а не число: поместилась
   целиком — стоит в строке статуса, нет — перенос строки статуса уводит её вниз,
   где она растягивается во всю ширину. С основой 10rem длинная пометка у мысли
   без голосового («разбор не удался», телефон) оставалась в строке колонкой
   в 191 px на четыре строки — та же узкая колонка. Пометка всегда последняя
   (`order`): этап и полосу разбора живая строка дописывает в конец (today.js,
   stageOf и barOf), и без этого полоса вставала под пометкой. */
.thought-meta .thought-note {
  flex: 1 1 auto;
  order: 1;
  min-width: 0;
  margin-top: 0;
}

/* Строка очереди без связи (pwa.js) — дорога на «Офлайн». */
.thoughts-proposals {
  display: block;
  padding: var(--space-2) 0;
  font-size: var(--text-sm);
  color: var(--accent);
  text-decoration: none;
}

/* Меню справа: кнопка 44×44, само меню — небольшой список, открывается рядом. */
.rowmenu {
  position: relative;
  justify-self: end;
}

.rowmenu-more {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin: -8px -8px 0 0;
  color: var(--text-muted);
  background: none;
  border: 0;
  cursor: pointer;
}

/* «⋯» — значком, как в макете (17 px, три точки по середине): символа U+22EF
   в Fira Sans нет, его рисовал запасной шрифт, и точки стояли ниже середины
   кнопки на 0–1,5 px — на iPhone, Android и Windows по-разному (ritm#295). */
.rowmenu-more .ic {
  width: 17px;
  height: 17px;
}

.rowmenu-list {
  position: absolute;
  right: 0;
  top: 36px;
  z-index: 5;
  display: none;
  flex-direction: column;
  min-width: 11rem;
  padding: var(--space-1);
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
  animation: ritm-rise var(--dur-1) var(--ease);
}

.rowmenu.is-open .rowmenu-list {
  display: flex;
}

.rowmenu-list form {
  margin: 0;
}

.rowmenu-item {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 0 var(--space-3);
  text-align: left;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
  line-height: 44px;
}

.rowmenu-item:hover {
  background: var(--surface-sunken);
}

.rowmenu-item-bad {
  color: var(--status-bad);
}

/* --- тост ------------------------------------------------------------------ */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(132px + env(safe-area-inset-bottom, 0px)); /* над панелью захвата */
  transform: translateX(-50%);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--space-4);
  /* По содержимому, а не по «сжать до влезания»: от `left: 50%` до края —
     полэкрана, и итог разбора (ritm#379) ломался в три строки по 195 px. */
  width: max-content;
  box-sizing: border-box; /* поля входят в ширину: у краёв экрана остаётся по 20 px */
  max-width: min(24rem, calc(100% - 2 * var(--space-5)));
  padding: var(--space-3) var(--space-4);
  background: var(--text);
  color: var(--bg-page);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-2);
  font-size: var(--text-sm);
  animation: ritm-toast-in var(--dur-2) var(--ease);
}

/* Появление тоста — своё, а не общий `ritm-rise` (ritm#451): тот поднимает
   через `transform` и на время подъёма перебивал центровку `translateX(-50%)`:
   первые 260 мс тост стоял на полширины правее и прыгал на место (левый край
   на 1440 px — 836 → 769, на 390 px — 195 → 131). Подъём здесь — нижним полем:
   центровку он не трогает, работает и без свойства `translate` (его может не
   знать старый WebView Telegram на Android) и не спорит с местом тоста в окне
   карточки — там today.js ставит ему свои `left` и `bottom` и `transform: none`
   (ritm#401). */
@keyframes ritm-toast-in {
  from { opacity: 0; margin-bottom: -6px; }
  to { opacity: 1; margin-bottom: 0; }
}

.toast-undo {
  font: inherit;
  font-weight: var(--weight-semibold);
  color: var(--accent-soft);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  white-space: nowrap;
}

.toast.is-leaving {
  opacity: 0;
  transition: opacity var(--dur-2) var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  .thought,
  .thought-dot,
  .thought-actions,
  .rowmenu-list,
  .toast,
  .thought-bar-fill {
    animation: none !important;
    transition: none !important;
  }
}

/* --- шторка мысли (ritm#260) ---------------------------------------------------
   Раскрытая мысль по макету `Мысль.dc.html` — шторка поверх экрана на 85%
   высоты: сверху видна лента, снизу поле ответа агенту. Внутри переписка:
   реплики агента слева, свои справа. */
.thought-sheet {
  position: relative;
  /* Потолок из макета — 85% высоты; короткая переписка не тянется до него, иначе
     под двумя строками остаётся пустое поле в пол-экрана. */
  height: auto;
  min-height: 40%;
  max-height: 85%;
  display: flex;
  flex-direction: column;
  padding: 0;
}

.thought-sheet-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.tsheet {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

/* Хват — полоска поверх шапки, как в макете: своей высоты не занимает, иначе
   шторка начиналась на 56px ниже, а полоска висела над её краем (замечание
   владельца 17.09). Тянут за всю ширину шапки, зона 20px. */
.thought-handle {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1;
  height: 20px;
  min-height: 0;
  margin: 0;
  padding: var(--space-2) 0 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  background: none;
  touch-action: none;
  cursor: grab;
}

.thought-handle .sheet-grip {
  width: 36px;
  height: 4px;
  margin: 0;
  border-radius: 999px;
  background: var(--line-strong);
}

/* Шапка по макету: высота 73, поля 8/12/12, всё по центру одной линии —
   заголовок со статусом слева, корзина и крестик справа. */
.tsheet-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3) var(--space-3);
  border-bottom: 1px solid var(--line);
}

/* Обе иконки шапки стоят на одной линии: у общей `.head-icon` отрицательные
   поля по вертикали, и корзина с крестиком разъезжались на 10px. */
.tsheet-head .head-icon {
  flex: none;
  width: 44px;
  height: 44px;
  margin: var(--space-2) 0 0;
}

.tsheet-title {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  padding: var(--space-3) 0 0 var(--space-2);
}

.tsheet-name {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  line-height: 1.15;
}

/* Состояние — точкой и словом: точка красится теми же правилами, что в ленте
   (по data-status на строке), слово приходит с сервера. */
.tsheet-state {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-xs);
  color: var(--text-secondary);
}

.tsheet-menu {
  flex: none;
  position: relative;
}

.tsheet-close {
  flex: none;
  margin: 0;
}

.tsheet-thread {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-4) var(--space-6);
}

/* Застрявшая мысль: что случилось и что можно сделать — одной строкой. */
.tsheet-stall {
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-md);
}

.tsheet-stall-text {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.tsheet-stall form {
  margin: 0;
}

.tsheet-day {
  align-self: center;
  padding: 2px var(--space-3);
  border-radius: 999px;
  background: var(--surface-sunken);
  font-size: var(--text-xs);
  color: var(--text-muted);
}

.tmsg {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-width: 100%;
}

.tmsg-agent {
  align-items: flex-start;
}

.tmsg-human {
  align-items: flex-end;
}

.tmsg-bubble {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 78%;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  text-wrap: pretty;
}

/* Своя реплика — сплошным акцентом: кто сказал, видно по стороне и по цвету,
   без подписи (владелец 12.09). */
.tmsg-human .tmsg-bubble {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.tmsg-text {
  font-size: var(--text-md);
  line-height: var(--leading-normal);
}

.tmsg-at {
  padding: 0 var(--space-2);
  font-size: var(--text-xs);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.tmsg-voice {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.tmsg-voice-mark .ic {
  width: 16px;
  height: 16px;
}

.tmsg-voice-text {
  font-size: var(--text-sm);
}

/* Вложенная карточка задачи: то, что агент сделал, лежит в реплике, а не
   ссылкой в тексте. Полоска слева — категория, как в строке дня. */
.tmsg-card {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-left: 3px solid var(--cat, var(--line-strong));
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  color: inherit;
  text-decoration: none;
}

.tmsg-human .tmsg-card {
  background: var(--surface);
  color: var(--text);
}

.tmsg-card-title {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.tmsg-card-meta {
  font-size: var(--text-xs);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

/* Дифф не разворачивается в ленту: строка открывает его на месте. */
.tmsg-diff {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.tmsg-diff-toggle {
  align-self: flex-start;
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  margin: -6px 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  cursor: pointer;
}

.tmsg-diff-toggle .ic {
  width: 14px;
  height: 14px;
  transition: transform var(--dur-1) var(--ease);
}

.tmsg-diff-toggle[aria-expanded="true"] .ic {
  transform: rotate(-90deg);
}

.tmsg-diff-rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

.tmsg-diff-row {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.tmsg-diff-field {
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.tmsg-diff-from {
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-decoration: line-through;
  text-decoration-color: var(--line-strong);
}

.tmsg-diff-to {
  font-size: var(--text-sm);
  color: var(--text);
}

/* Удаление задачи и мысли — внизу шторки. Красная, когда есть карточка: без неё
   удаляется одна мысль, и пугать красным нечем (владелец 15.09). */
.tsheet-drop {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4) calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line);
}

/* Когда под удалением стоит ещё и строка ответа, черта и нижняя отбивка у него
   лишние: подвал один, и чертит его нижний блок. */
.tsheet-drop-mid {
  padding-bottom: 0;
  border-top: 0;
}

.tsheet-drop-btn {
  justify-content: center;
  gap: var(--space-2);
  background: none;
  border: 1px solid var(--line-strong);
  color: var(--text-secondary);
}

.tsheet-drop.is-hot .tsheet-drop-btn {
  border-color: var(--status-bad);
  color: var(--status-bad);
}

.tsheet-drop-yes {
  background: var(--status-bad);
  color: var(--on-accent);
}

.tsheet-drop-ask {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  align-items: center;
  text-align: center;
}

.tsheet-drop-text {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.tsheet-drop-row {
  display: flex;
  gap: var(--space-2);
}

.tsheet-drop-row form {
  margin: 0;
}

/* Со скриптом сначала спрашиваем, без него форма стоит сразу: удалить должно
   быть можно и без скрипта. */
.has-js .tsheet-drop-ask {
  display: none;
}

.has-js .tsheet-drop.is-asking .tsheet-drop-ask {
  display: flex;
}

.has-js .tsheet-drop.is-asking .tsheet-drop-btn {
  display: none;
}


/* Строка ответа агенту — над клавиатурой, микрофона здесь нет: голос заводит
   новую мысль, а не реплику в этой. */
.tsheet-reply {
  flex: none;
  display: flex;
  align-items: flex-end;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-3) var(--space-4) calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--line);
}

.tsheet-reply-input {
  flex: 1;
  min-width: 0;
  min-height: 48px;
  padding: 0 var(--space-4);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--text-md);
}

.tsheet-send {
  flex: none;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  cursor: pointer;
}

.tsheet-send:disabled {
  background: var(--surface-sunken);
  color: var(--text-muted);
  cursor: default;
}

/* Страница мысли без скрипта: та же переписка, только в потоке экрана. */
.tsheet-page .tsheet {
  min-height: 60vh;
}
}
