/* Чат комнаты: окно справа снизу над канвой, лента облачков как в
   мессенджерах. Отдельным файлом — ни с чем не пересекается, подключается
   одной строкой.

   Вид держится за класс .chatbox, а не за id: тот же класс носят полосы-копии
   эффекта появления (client/render/geniefx.ts), у которых id нет. За id —
   только место на экране. */

.chatbox {
  /* Облачка непрозрачные: хвостик — отдельная фигура у края облачка, и с
     полупрозрачным цветом их стык проступал бы более тёмной полосой. */
  --bub-in: #262a30;
  --bub-out: #3d3526;
  --bub-ink: #ece7dc;
  --meta-in: rgba(236, 231, 220, 0.42);
  --meta-out: rgba(240, 220, 180, 0.55);
  --read: #5aaeff;
  --r: 15px;
  --r-in: 5px;
  /* Размер из chatframe — это размер рамки целиком: иначе каждое укладывание
     в экран прибавляло бы к окну толщину рамки. */
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  border-radius: 14px;
  background: rgba(18, 20, 24, 0.95);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 12px 34px rgba(0, 0, 0, 0.55);
  font: 400 13.5px/1.35 Rubik, system-ui, sans-serif;
}

#chat {
  position: fixed;
  right: calc(10px + var(--safe-r) + var(--chat-dx, 0px));
  bottom: calc(48px + var(--safe-b) + var(--chat-dy, 0px));
  z-index: 8;
  /* Размер — из client/hud/chatframe.ts: окно тянется за края и помнит
     размер. Пределы — там же, в коде: здесь только запасной вид до первого
     скрипта. */
  width: var(--chat-w, 320px);
  height: var(--chat-h, 360px);
}
#chat.hidden { display: none; }
/* Пока тянут край — выделение текста и курсор ленты не мешают. */
#chat.resizing { user-select: none; }
#chat.resizing .log { pointer-events: none; }

.chatbox .log {
  /* Точка отсчёта offsetTop строк: по нему копии эффекта оставляют только
     видимое. */
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 10px 10px 6px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Полоса прокрутки в тон, а не системная белая поверх тёмной панели. */
  scrollbar-width: thin;
  scrollbar-color: rgba(236, 231, 220, 0.22) transparent;
}

/* Реплик мало — они прижаты к низу, к полю ввода, как в мессенджерах, а не
   висят под потолком над пустым окном. Отступом первой строки, а не
   justify-content: flex-end — с ним переполненную ленту не прокрутить
   вверх. */
.chatbox .log > :first-child { margin-top: auto; }

.chatbox .empty {
  margin: auto;
  font-size: 12px;
  color: rgba(236, 231, 220, 0.38);
}

/* --- блоки и облачка ------------------------------------------------------ */

/* Блок — подряд идущие реплики одного автора: чужие слева с кружком, свои
   справа без него. */
/* Зазор с кружком — с запасом на хвостик: он торчит из облачка на 8 px. */
.chatbox .grp {
  display: flex;
  align-items: flex-end;
  gap: 11px;
}
.chatbox .grp.mine { justify-content: flex-end; }
.chatbox .stack {
  display: flex;
  flex-direction: column;
  /* Облачка блока прилипают друг к другу с волосяным зазором. */
  gap: 2px;
  min-width: 0;
  max-width: 82%;
}
.chatbox .grp.mine .stack { align-items: flex-end; }
.chatbox .grp.theirs .stack { align-items: flex-start; }

/* Кружок автора на липучке: пока блок на экране, он держится у нижнего края
   ленты, а уходя вверх, уезжает вместе со своим блоком. Слева от него — ни
   одной реплики, поэтому и место под него держит только чужой блок. */
.chatbox .grp > .ava {
  position: sticky;
  bottom: 0;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font: 600 10px/1 Rubik, system-ui, sans-serif;
  color: #16140f;
  background: hsl(var(--hue, 40) 42% 62%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}
/* Шар-аватарка — те же слои, что на табло (avatar.css). */
.chatbox .grp > .ava.ball {
  background:
    radial-gradient(circle at 50% 50%, #fff 0 34%, rgba(255, 255, 255, 0) 34%),
    var(--bc, #888);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.3);
}
.chatbox .grp > .ava.ball.stripe {
  background:
    radial-gradient(circle at 50% 50%, #fff 0 34%, rgba(255, 255, 255, 0) 34%),
    linear-gradient(var(--bc, #888) 0 0) 50% 50% / 100% 60% no-repeat,
    #f4f1e8;
}

.chatbox .bub {
  position: relative;
  max-width: 100%;
  padding: 6px 10px 7px;
  border-radius: var(--r);
  background: var(--bub-in);
  color: var(--bub-ink);
  /* Длинное слово без пробелов иначе растянет окно за край экрана. */
  overflow-wrap: anywhere;
}
.chatbox .grp.mine .bub { background: var(--bub-out); }

/* Углы со стороны блока скругляются меньше: облачки стоят стопкой и читаются
   одним сообщением, а внешние углы стопки остаются круглыми. У последнего
   нижний угол занят хвостиком. */
.chatbox .grp.theirs .bub.grouped { border-top-left-radius: var(--r-in); }
.chatbox .grp.theirs .bub:not(.last) { border-bottom-left-radius: var(--r-in); }
.chatbox .grp.theirs .bub.last { border-bottom-left-radius: 0; }
.chatbox .grp.mine .bub.grouped { border-top-right-radius: var(--r-in); }
.chatbox .grp.mine .bub:not(.last) { border-bottom-right-radius: var(--r-in); }
.chatbox .grp.mine .bub.last { border-bottom-right-radius: 0; }

/* Хвостик — у последнего облачка блока, со стороны автора. Фигура — маской,
   цвет — фоном: одна и та же кривая на оба цвета. */
.chatbox .bub.last::before {
  content: '';
  position: absolute;
  bottom: 0;
  left: -8px;
  width: 9px;
  height: 14px;
  background: inherit;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 14'%3E%3Cpath d='M9 0v14H1.2C.3 14-.2 13 .5 12.3 3.4 9.7 8.2 6.2 8.2 0z'/%3E%3C/svg%3E") no-repeat 0 0 / 100% 100%;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 14'%3E%3Cpath d='M9 0v14H1.2C.3 14-.2 13 .5 12.3 3.4 9.7 8.2 6.2 8.2 0z'/%3E%3C/svg%3E") no-repeat 0 0 / 100% 100%;
}
.chatbox .grp.mine .bub.last::before {
  left: auto;
  right: -8px;
  transform: scaleX(-1);
}

.chatbox .who {
  margin-bottom: 1px;
  font-size: 12px;
  font-weight: 500;
  color: hsl(var(--hue, 40) 60% 70%);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Разметка реплик (client/hud/chatmd.ts, рисует render/mdview.ts). Класс .md
   носит и текст облачка, и пример синтаксиса в правилах: пример выглядит
   ровно так, как выйдет в чате. */
.md b { font-weight: 600; }
.md s { text-decoration-color: rgba(236, 231, 220, 0.6); }
.md u { text-underline-offset: 2px; }
/* Заголовки — вся реплика крупнее. Время остаётся мелким в углу: распорка
   .pad той же ширины, строка просто выше. */
.md.h1 { font-size: 21px; line-height: 1.25; font-weight: 700; }
.md.h2 { font-size: 18px; line-height: 1.28; font-weight: 600; }
.md.h3 { font-size: 15.5px; line-height: 1.3; font-weight: 600; }
.md.h4 { font-size: 13.5px; font-weight: 600; letter-spacing: 0.02em; }
.md code {
  padding: 1px 4px;
  border-radius: 4px;
  background: rgba(0, 0, 0, 0.3);
  font: 12px/1.3 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
/* Спойлер — размытым текстом, как в мессенджерах: видно, что там что-то
   есть и какой длины, но не что. Раскрывается нажатием. */
.md .spoiler {
  border-radius: 4px;
  background: rgba(236, 231, 220, 0.07);
  color: transparent;
  text-shadow: 0 0 7px rgba(236, 231, 220, 0.8);
  cursor: pointer;
  transition: color 0.2s, text-shadow 0.2s, background 0.2s;
}
.md .spoiler.shown {
  background: none;
  color: inherit;
  text-shadow: none;
  cursor: auto;
}
.md .spoiler:not(.shown) code { background: none; }
.md .spoiler:not(.shown) .chip { filter: blur(3px); opacity: 0.7; }

/* Шары-смайлики — ячейка забитого шара с табло (board.css, .chip) размером
   со строчку текста: в заголовке они крупнее вместе с буквами. */
.md .chip {
  --chip: 1.3em;
  display: inline-block;
  margin: 0 0.05em;
  vertical-align: -0.28em;
  /* Падение в ячейку (anim.css) — для табло, где шар только что забит. В
     чате лента пересобирается на каждой реплике, и все шары в ней заново
     проявлялись по 0.3 с — будто грузятся. */
  animation: none;
}
/* Реплика из одних шаров — крупно, как сообщение из одних эмодзи. */
.chatbox .bub.jumbo .txt .chip { --chip: 2.3em; margin: 0.05em 0.06em; }
/* Цитата — полоской слева во всю высоту облачка. */
.chatbox .bub.quote { padding-left: 19px; }
.chatbox .qbar {
  position: absolute;
  left: 10px;
  top: 7px;
  bottom: 7px;
  width: 2px;
  border-radius: 1px;
  background: rgba(236, 231, 220, 0.35);
}
.chatbox .grp.mine .qbar { background: rgba(240, 220, 180, 0.5); }

/* Время — частью облачка, в правом нижнем углу. Распорка .pad той же ширины
   стоит в конце текста: влезает в последнюю строку — время встаёт на неё,
   не влезает — переносится вместе с распоркой, и время уходит под текст. */
.chatbox .pad {
  display: inline-block;
  width: 36px;
  height: 1px;
}
.chatbox .grp.mine .pad { width: 52px; }
.chatbox .meta {
  position: absolute;
  right: 9px;
  bottom: 5px;
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 10.5px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--meta-in);
  pointer-events: none;
}
.chatbox .grp.mine .meta { color: var(--meta-out); }

/* Галочки: одна — реплика на сервере, две и синим — её прочитал кто-то ещё. */
.chatbox .ticks {
  width: 15px;
  height: 10px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.chatbox .ticks path + path { display: none; }
.chatbox .bub.read .ticks { color: var(--read); }
.chatbox .bub.read .ticks path + path { display: inline; }

/* --- поле ввода ------------------------------------------------------------ */

/* Поле без рамки и подложки — продолжение окна, а не вставленный в него
   виджет; от ленты отделено одной волосяной линией. Кнопка — голая стрелка:
   бледная, пока отправлять нечего, и тёплая, когда есть текст. */
.chatbox form {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px 4px 2px 13px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
  transition: border-color 0.15s;
}
/* Фокус — чуть ярче линия, без обводки поля: пишущий и так видит курсор. */
.chatbox form:focus-within { border-top-color: rgba(255, 255, 255, 0.13); }
.chatbox input {
  flex: 1;
  min-width: 0;
  padding: 11px 0;
  border: 0;
  background: none;
  color: var(--chalk, #ece7dc);
  caret-color: #f0dcb4;
  font: inherit;
}
.chatbox input::placeholder { color: rgba(236, 231, 220, 0.3); }
.chatbox input:focus { outline: none; }
.chatbox button {
  flex: none;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: rgba(236, 231, 220, 0.22);
  cursor: default;
  transition: color 0.15s, transform 0.15s;
}
.chatbox button svg { width: 19px; height: 19px; }
.chatbox form.ready button { color: #f0dcb4; cursor: pointer; }
.chatbox form.ready button:hover { transform: translateX(2px); }
.chatbox button:focus-visible { outline: 1px solid rgba(240, 220, 180, 0.5); outline-offset: -3px; }

/* --- края для растягивания ------------------------------------------------- */

/* Невидимые полосы по краям и квадраты по углам, чуть наружу от рамки: так
   за край легче взяться, а текст у самой рамки остаётся выделяемым. */
.chatbox .grip {
  position: absolute;
  z-index: 2;
  touch-action: none;
}
.chatbox .grip.n { top: -4px; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }
.chatbox .grip.s { bottom: -4px; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }
.chatbox .grip.w { left: -4px; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }
.chatbox .grip.e { right: -4px; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }
.chatbox .grip.nw { top: -5px; left: -5px; width: 17px; height: 17px; cursor: nwse-resize; }
.chatbox .grip.se { bottom: -5px; right: -5px; width: 17px; height: 17px; cursor: nwse-resize; }
.chatbox .grip.ne { top: -5px; right: -5px; width: 17px; height: 17px; cursor: nesw-resize; }
.chatbox .grip.sw { bottom: -5px; left: -5px; width: 17px; height: 17px; cursor: nesw-resize; }
/* Верхний край — главный (окно прибито к низу, растёт вверх): на нём
   ручка-черта, как у выдвижных листов, чтобы было видно, что тянется. */
.chatbox .grip.n::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 6px;
  width: 30px;
  height: 3px;
  margin-left: -15px;
  border-radius: 2px;
  background: rgba(236, 231, 220, 0.16);
}
.chatbox .grip.n:hover::after { background: rgba(236, 231, 220, 0.32); }
/* Пальцу нужна полоса пошире. */
@media (pointer: coarse) {
  .chatbox .grip.n, .chatbox .grip.s { height: 16px; top: -8px; }
  .chatbox .grip.s { top: auto; bottom: -8px; }
  .chatbox .grip.w, .chatbox .grip.e { width: 16px; }
  .chatbox .grip.w { left: -8px; }
  .chatbox .grip.e { right: -8px; }
  .chatbox .grip.n::after { top: 10px; }
}

/* --- эффект появления ---------------------------------------------------- */

.genie-layer {
  position: fixed;
  inset: 0;
  z-index: 8;
  pointer-events: none;
}
.genie-slice {
  position: absolute;
  left: 0;
  top: 0;
  overflow: hidden;
  transform-origin: 0 0;
  will-change: transform;
  contain: layout paint;
}
/* Копии — без тени и рамки по бокам: на изгибе они лепились бы лесенкой. */
.genie-slice > .chatbox { box-shadow: none; }

/* --- точка непрочитанного на кнопке ------------------------------------ */

/* Позицию кнопке здесь не задаём: .dial уже делает её fixed, а правило по id
   перебило бы это (id сильнее класса, и файл грузится позже) — кнопка
   вывалилась бы из угла в поток. Для абсолютной точки fixed-родитель и так
   подходит. */
#chat-btn .badge {
  position: absolute;
  top: 2px;
  right: 1px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #3d9bff;
  /* Ободок цветом фона — точка не сливается с линией значка под ней. */
  box-shadow: 0 0 0 2px #121417;
}
#chat-btn .badge.hidden { display: none; }
#chat-btn.active { opacity: 0.85; }

/* Ряд кнопок на узком экране поднят над пультом — окно уходит выше вслед
   за своей кнопкой, иначе легло бы прямо на неё. */
@container screen (max-width: 560px) {
  #chat { bottom: calc(86px + var(--safe-b) + var(--chat-dy, 0px)); }
}
