@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/inter-cyrillic.woff2?v=aebf2ab4') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/inter-latin.woff2?v=c9407645') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'PT Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/pt-serif-400-cyrillic.woff2?v=a60d74d7') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'PT Serif';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/pt-serif-400-latin.woff2?v=202b8aa6') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Кириллического начертания 700 здесь нет намеренно: жирными засечками набран
   только логотип «chatlogs», а он латиницей. Появится жирный русский
   заголовок — подмножество вернём. */
@font-face {
  font-family: 'PT Serif';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/pt-serif-700-latin.woff2?v=57d3ae6c') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ─────────────────────────────────────────────────────────────
   Оформление перенесено из макета (Feed.dc.html / Post.dc.html).
   Цвета там заданы в oklch — держим их как есть, но каждому даём hex-дубль
   строкой выше: oklch понимают Chrome 111+, Safari 15.4+, Firefox 113+, а в
   браузере постарше правило с ним невалидно ЦЕЛИКОМ. Без запасного значения
   аватары остались бы бесцветными, а фон — белым.
   ───────────────────────────────────────────────────────────── */

:root {
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-read: 'PT Serif', Georgia, 'Times New Roman', serif;
  --maxw: 640px;

  --bg: #faf8f5;
  --bg: oklch(98% 0.004 75);
  --ink: #13110f;
  --ink: oklch(18% 0.006 75);
  /* Текст реплики чуть светлее основного — так задумано в макете: заголовки и
     подписи остаются самыми тёмными, а длинный текст читается мягче. */
  --ink-read: #1c1a18;
  --ink-read: oklch(22% 0.006 75);

  /* Величины реплики — здесь, а не по месту: их подбирают глазами, и лазить за
     этим в три разных правила значит однажды поправить не все.
     --lh-read — интервал ВНУТРИ абзаца. Было 1.6 на странице и 1.5 в ленте;
     1.45 плотнее, но строки ещё не слипаются.
     --msg-gap против --para-gap — вся иерархия чтения: разные реплики обязаны
     стоять дальше друг от друга, чем абзацы одной. Запас всего в полтора раза,
     поэтому менять их порознь нельзя. */
  --lh-read: 1.45;
  --msg-gap: 12px;
  --para-gap: 8px;
  --ink-dim: #605d5a;
  --ink-dim: oklch(48% 0.006 75);
  --ink-faint: #74716e;
  --ink-faint: oklch(55% 0.006 75);
  --line: #dfdedb;
  --line: oklch(90% 0.004 75);
  --link: #116bb5;
  --link: oklch(52% 0.14 250);
  --link-hover: #00569f;
  --link-hover: oklch(45% 0.14 250);
  --select: #c1e2ff;
  --select: oklch(90% 0.06 250);
}

/* ─── БАЗА ─── */
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  font-size: 15px;
  line-height: 1.5;
}

a { color: var(--link); }
a:hover { color: var(--link-hover); }
::selection { background: var(--select); }

/* Нижний отступ на самом контейнере, а не на последнем блоке: раньше его
   давал подвал ленты, и с его удалением содержимое упёрлось в край окна.
   В макете этот отступ есть на обеих страницах. */
.shell { max-width: var(--maxw); margin: 0 auto; padding: 0 20px 64px; }

/* ─── РЕПЛИКА ─── ЕДИНСТВЕННОЕ место, где описано оформление реплики. И на
   странице публикации, и в карточке ленты действуют ровно эти правила: слева
   круглый аватар с инициалом, справа имя и текст засечками.
   Блок .item ниже ПЕРЕОПРЕДЕЛЯТЬ их не имеет права — единственное дозволенное
   отличие ленты это обрезка. Дважды поверхности расходились именно потому, что
   одни и те же значения были объявлены в двух местах и правились по одному. */
.msg { display: flex; gap: 10px; align-items: flex-start; }
.msg + .msg { margin-top: var(--msg-gap); }

.ava {
  width: 24px; height: 24px; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 600;
}
/* min-width: 0 позволяет длинному слову переноситься, а не распирать колонку:
   у flex-элемента ширина по умолчанию считается от содержимого. */
.msg .body { flex: 1; min-width: 0; }

.msg .who { font-size: 13px; font-weight: 600; margin-bottom: 2px; }
/* .text — контейнер сообщения, абзацы внутри него. Типографика объявлена на
   контейнере и наследуется абзацами: так обрезка в ленте вешается на него же и
   считает строки всего сообщения, а не каждого абзаца по отдельности. */
.msg .text {
  font-family: var(--font-read);
  font-size: 18px; line-height: var(--lh-read); color: var(--ink-read);
  word-wrap: break-word; overflow-wrap: anywhere;
}
/* Расстояние между абзацами задаёт отступ, а не интервал: line-height растянул
   бы и строки внутри абзаца, то есть ровно то, что здесь убавляли. */
.msg .text p + p { margin-top: var(--para-gap); }
/* Два максимума вместо width: 100% — каждый работает по своей оси: вертикальный
   снимок упрётся в высоту, горизонтальный в ширину колонки. Пропорции держит
   сам браузер при auto по обеим сторонам, поэтому object-fit не нужен: он
   понадобился бы только при жёстко заданных обеих сторонах.
   Снимок уже колонки больше не растягивается — апскейл делал его мыльным. */
.msg .photo img {
  max-width: 100%; max-height: 300px; width: auto; height: auto;
  border-radius: 8px; display: block; margin: 8px 0;
}
/* Под последним блоком реплики нижний отступ лишний: расстояние до соседней
   реплики задаёт .msg + .msg, иначе у реплики с одним фото оно удваивается. */
.msg .photo:last-child img { margin-bottom: 0; }

/* Пять цветов аватара по порядку появления автора — палитра из макета.
   Шестой участник получит цвет первого: цветов пять, и это осознанный предел. */
.c0 { color: #00569f; color: oklch(45% 0.14 250); background: #dee5eb; background: oklch(52% 0.1 250 / 0.15); }
.c1 { color: #932b2a; color: oklch(45% 0.14 25);  background: #ece0de; background: oklch(52% 0.1 25 / 0.15); }
.c2 { color: #006925; color: oklch(45% 0.14 150); background: #dee7de; background: oklch(52% 0.1 150 / 0.15); }
.c3 { color: #763584; color: oklch(45% 0.14 320); background: #e9e1e8; background: oklch(52% 0.1 320 / 0.15); }
.c4 { color: #006b66; color: oklch(45% 0.14 190); background: #d5e7e5; background: oklch(52% 0.1 190 / 0.15); }
/* Шестой класс вне палитры: цвет вставки в анонимной публикации. Один на все
   источники и не выводится из названия — иначе один и тот же скрытый чат давал
   бы один цвет во всех публикациях и связывал бы их между собой. */
.cn { color: #605d5a; color: oklch(48% 0.006 75); background: #e7e5e2; background: oklch(52% 0.004 75 / 0.15); }

/* ─── ВСТАВКА ИЗ КАНАЛА ─── чужой пост, который кто-то принёс в переписку.
   Ни рамки, ни подложки: и коробка, и заливка спорили бы с телеграф-вёрсткой,
   где всё держится на типографике. Вставку называет подпись сверху — этого
   достаточно, чтобы её не приняли за реплику участника. */
/* Подпись источника: мелко и приглушённо — она поясняет блок, а не спорит с
   текстом внутри него за внимание. */
/* align-items: flex-start, а не center: на узком экране длинное название
   переносится на вторую строку, и при центрировании значок повисал ровно
   между строками, ни к одной не относясь. Со start он остаётся при первой —
   там, где начинается фраза, которую он поясняет. */
.fwd .fwd-from {
  display: flex; align-items: flex-start; gap: 7px;
  font-size: 13px; line-height: 1.5; color: var(--ink-faint); margin-bottom: 8px;
}
/* Значок пересылки. Размер задан атрибутами самого SVG, а цвет наследуется
   через currentColor — своих значений у правила нет намеренно: разъехаться по
   цвету с текстом подписи значку тогда просто нечем.
   margin-top доводит значок до середины ПЕРВОЙ строки: строка 19.5px (13px ×
   1.5), значок 14px, разница пополам — три пикселя. Отсюда же явный
   line-height у подписи: без него расчёт зависел бы от настроек браузера.
   flex: 0 0 auto — иначе длинная подпись сожмёт значок по ширине. */
.fwd-icon { flex: 0 0 auto; margin-top: 3px; }
/* Кружок слева от вставки пустой, но цветной: цвет берётся от имени
   источника, как у аватаров участников, и один канал всегда узнаётся по нему.
   Буквы внутри нет — она выдала бы источник за собеседника. */
/* Внутри вставки первый элемент уже отбит подписью, поэтому верхний отступ
   у фото лишний. */
.fwd .photo img { margin-top: 0; }

/* ─── СТРАНИЦА ПЕРЕПИСКИ ─── */
.page-post .top { padding: 32px 0 20px; }
.brand { font-size: 14px; color: var(--ink-dim); text-decoration: none; }
.brand:hover { color: var(--ink); }

.chat-head {
  display: flex; align-items: center; gap: 8px;
  padding-bottom: 20px; border-bottom: 1px solid var(--line); margin-bottom: 24px;
}
.date { font-size: 14px; color: var(--ink-faint); }

.chat { padding-bottom: 24px; }

/* ─── ЛЕНТА ─── */
.brandbar { padding: 48px 0 28px; border-bottom: 1px solid var(--line); }
/* Логотип и ссылка на бота в одной строке, подпись ниже.
   flex-wrap обязателен: около 380px они в строку не помещаются, и ссылка
   должна переехать под логотип, а не выдавить его за край.
   align-items: flex-start — ссылка держится верхнего края, а не centered
   относительно крупного логотипа. */
.brandbar-top {
  display: flex; align-items: flex-start; justify-content: space-between;
  flex-wrap: wrap; gap: 4px 16px;
}
.brandbar .logo {
  font-family: var(--font-read);
  font-weight: 700; font-size: 28px; letter-spacing: -0.01em;
  /* Знак и слово — одна строка по центру. inline-flex, а не flex: блок во всю
     ширину растянул бы кликабельную область до края, хотя знак со словом
     занимают левый угол. */
  display: inline-flex; align-items: center; gap: 10px;
}
/* Размер задан и в разметке (width/height), и здесь: атрибуты держат место до
   загрузки файла и не дают странице дёрнуться, CSS оставляет знак ровно
   такого размера, даже если сам svg придёт с другими размерами внутри. */
.brandbar .logo img { width: 24px; height: 24px; flex: 0 0 auto; display: block; }
.brandbar .tagline { font-size: 14px; color: var(--ink-dim); margin-top: 6px; }

.feed { display: flex; flex-direction: column; }
.item {
  display: block; text-decoration: none; color: inherit;
  padding: 28px 0; border-bottom: 1px solid var(--line);
}
/* Обрезка — ЕДИНСТВЕННОЕ, чем лента отличается от страницы. Всё остальное
   (кегль, интервал, цвет, аватар, отступы) объявлено один раз в блоке .msg
   выше и сюда не дублируется.
   Превью — приглашение открыть переписку: сообщение обрезается двумя строками,
   иначе одна длинная реплика вытеснит соседние публикации за экран.
   Обрезка висит на КОНТЕЙНЕРЕ сообщения, а не на абзаце: иначе сообщение из
   трёх абзацев дало бы шесть строк вместо двух. Проверено — на контейнере с
   блочными <p> внутри высота получается ровно та же, что на одиночном абзаце,
   потому что в проекте есть сброс отступов в самом верху файла. */
.item .text {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Миниатюра снимка в превью: вписывается целиком, без кадрирования.
   Раньше здесь стоял фиксированный размер с object-fit: cover, и вертикальные
   снимки резались по краям — от портрета оставалась полоса поперёк лица.
   Теперь ограничение только по высоте, ширину и пропорции держит браузер.

   Высоту резервирует контейнер, а не атрибуты картинки: настоящих пропорций
   файла мы не знаем, поэтому width/height в разметке задавали бы неверное
   соотношение и лента прыгала бы при загрузке сильнее, чем без них. Так по
   вертикали место стабильно, меняется только ширина.

   Лежит внутри .body, поэтому выравнивается по левому краю текста, а не под
   аватаром. */
.item .thumb { height: 100px; margin-bottom: 6px; }
.item .thumb img {
  max-height: 100px; max-width: 100%; width: auto; height: auto;
  border-radius: 6px; display: block;
}

/* Вставка из канала в ленте своих правил не имеет: подпись и значок берут
   размеры со страницы публикации. Уменьшающие переопределения здесь были и
   сняты намеренно — карточка и публикация должны показывать вставку
   одинаково, иначе переход из ленты выглядит переходом на другой сайт. */

/* Отступ слева равен ширине аватара с зазором — строка встаёт под текст
   реплик, а не под кружки. */
.item .rest { font-size: 13px; color: var(--ink-faint); margin: 4px 0 12px 34px; }
.item .date { margin-top: 8px; display: block; font-size: 13px; }

/* ── Догрузка ── */
.more-btn {
  display: block; margin: 24px auto 0; cursor: pointer;
  background: none; border: 1px solid var(--line); border-radius: 100px;
  padding: 10px 24px; font: inherit; font-size: 14px; color: var(--ink-dim);
}
.more-btn:hover { color: var(--ink); }
.more-btn:disabled { opacity: .6; cursor: default; }

/* ── Пустая лента и 404 ── */
.welcome { text-align: center; padding: 44px 20px 30px; color: var(--ink-dim); }
.welcome p { margin-bottom: 18px; font-size: 15px; }
.quiet-link { color: var(--ink-dim); text-decoration: underline; text-underline-offset: 2px; }
.quiet-link:hover { color: var(--ink); }

.empty { text-align: center; padding: 60px 20px; color: var(--ink-dim); }
.empty .dim { color: var(--ink-faint); font-size: 14px; margin-top: 6px; }
.empty .quiet-link { margin-top: 20px; display: inline-block; }

/* ── Подвал страницы публикации ── */
/* Подвал в строку: копирование слева, ссылка на бота справа.
   flex-wrap на случай, если подписи не поместятся при крупном шрифте. */
.foot-copy {
  margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: 4px 16px;
}
/* Подчёркивания нет намеренно. Осознанная плата: у этой кнопки нет и значка,
   а hover на телефоне не существует — там она читается как обычный серый
   текст. Решение принято ради единого вида строки подвала; вернуть
   различимость — это либо значок, либо подчёркивание обратно. */
.linky {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; font-size: 14px; color: var(--ink-dim);
  text-decoration: none;
}
.linky:hover { color: var(--ink); }
.linky:disabled { opacity: .55; cursor: default; text-decoration: none; }

/* Подсказка о превышении лимита и прочих отказах API. */
.notice {
  margin: 14px 0 0; padding: 11px 15px; border-radius: 12px;
  background: #ece9e5; background: oklch(94% 0.004 75);
  color: var(--ink-dim); font-size: 14px; line-height: 1.4;
}

/* ─── ССЫЛКА НА БОТА ─── единственный вход в сервис для того, кто пришёл по
   чужой ссылке. Один набор правил на обе поверхности: и шапку ленты, и подвал
   публикации. Копий под .brandbar или .foot-copy заводить нельзя — лента и
   страница расходились дважды именно из-за дублирования одинаковых значений.

   Цвет — та же переменная, что у .linky рядом: подбирать похожий оттенок
   отдельно значит однажды получить две почти одинаковые серости.

   Шрифт служебный: наследуется от body, var(--font-read) здесь не место.

   Вертикальный отступ доводит область нажатия до 44px, а отрицательное поле
   возвращает строку на место — иначе ссылка растянула бы шапку и подвал.
   Пальцем по мелкой ссылке иначе не попасть. */
/* white-space: nowrap — не косметика. При переносе на две строки значок,
   центрированный по всей ссылке, повис бы между ними, не относясь ни к одной:
   ровно этот дефект чинили у значка пересылки. Строка короткая и помещается
   даже на 320px, но короткая она по случайности, а не по устройству — запрет
   переноса снимает вопрос навсегда. */
.bot-link {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 12px 0; margin: -12px 0;
  font-size: 14px; color: var(--ink-dim);
  text-decoration: none; cursor: pointer;
}
.bot-link:hover { color: var(--ink); }
/* В шапке ссылка опускается на 4px, чтобы её буквы начинались на одной высоте
   с «chatlogs».
   Причина в разнице кеглей: строка логотипа 28px, ссылки — 14px, а при
   line-height 1.5 полулидинг у них 7px и 3.5px. Выровненные по верху рамок,
   буквы расходятся ровно на эту разницу — измерено, 3.8px.
   Смещение задано отрицательным полем поверх компенсации отступа (-12 + 4),
   поэтому область нажатия остаётся прежней.
   Только в шапке: в подвале ссылка стоит рядом с текстом того же кегля, и там
   выравнивать нечего. */
.brandbar-top .bot-link { margin-top: -8px; }
/* Обводка, а не рамка: рамка добавила бы ширину и сдвинула соседей. */
.bot-link:focus-visible { outline: 2px solid var(--link); outline-offset: 3px; }
/* Значок цветом не распоряжается — наследует через currentColor. Своего
   значения нет намеренно: иначе он разъедется с текстом при правке палитры. */
.bot-icon { flex: 0 0 auto; }

/* На узком экране подвал становится столбцом, и ссылка на бота оказывается
   СВЕРХУ. Разворот, а не обычная колонка: в разметке она идёт второй, потому
   что порядок чтения «сначала про эту публикацию, потом про свою» верен, а
   визуальный приоритет на телефоне обратный. */
@media (max-width: 480px) {
  .foot-copy { flex-direction: column-reverse; align-items: center; gap: 10px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}
