:root{
  --paper:#DFE4E8;
  --card:#FFFFFF;
  --ink:#10171E;
  --muted:#61707E;
  --rule:#C6CED5;
  --signal:#B3312A;
  --signal-2:#8E2721;
  --signal-3:#6B1D18;
  --steel:#33485C;
  --ok:#2E6B4F;
  --alt:#8A6212;
  --fm:#33485C;
  --safe-b:env(safe-area-inset-bottom,0px);
  --header-h:112px; /* запасное значение до первого измерения в JS, см. syncHeaderHeightVar() в app.js */
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent;}
html{-webkit-text-size-adjust:100%;}
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:"IBM Plex Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  font-size:16px;line-height:1.5;
  padding-bottom:calc(16px + var(--safe-b));
  /* Место под шапку, которая теперь position:fixed (см. .header-sticky
     ниже) и больше не занимает место в потоке сама. Меняется вместе с
     --header-h (см. syncHeaderHeightVar() в app.js) — просядет/подрастёт
     автоматически, без лишнего JS, это же CSS-переменная. */
  padding-top:var(--header-h);
  overscroll-behavior-y:none;
}
button{font:inherit;color:inherit;cursor:pointer;}

h2{font-family:"JetBrains Mono",ui-monospace,Menlo,monospace;font-size:11.5px;font-weight:700;
   letter-spacing:.2em;text-transform:uppercase;color:var(--steel);margin:0 0 12px;}
.mono{font-family:"JetBrains Mono",ui-monospace,Menlo,monospace;}

/* ---------- шапка ---------- */
/* Шапка + верхняя навигация закреплены наверху ВМЕСТЕ, одним
   контейнером. Раньше — position:sticky, но на iOS фокус на поле
   ввода чата запускает системное "докрутить инпут в видимую область"
   НЕЗАВИСИМО от overflow:hidden на body — это панорамирование уводило
   sticky-шапку за экран вместе с остальным документом (sticky всё
   равно часть обычного потока/скролла). position:fixed этого лишён в
   принципе: элемент больше не "часть скролла" ни для какого предка,
   системе просто нечего утаскивать. Что раньше давал sticky сам
   (резервирование места под себя в потоке) — теперь делает
   `body{padding-top:var(--header-h)}` выше. */
.header-sticky{position:fixed;top:0;left:0;right:0;z-index:30;}
.appbar{
  background:var(--ink);color:#fff;
  padding:calc(10px + env(safe-area-inset-top,0px)) 16px 10px;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
}
.appbar .brand{font-family:"Unbounded","IBM Plex Sans",sans-serif;font-weight:800;
  font-size:15px;letter-spacing:.02em;text-transform:uppercase;}
.appbar .ver{font-family:"JetBrains Mono",monospace;font-weight:400;font-size:9px;letter-spacing:0;
  text-transform:none;color:#5A6B7A;margin-left:6px;white-space:nowrap;}
.appbar .clock{font-family:"JetBrains Mono",monospace;font-size:12px;color:#9FB0BE;text-align:right;line-height:1.25;}
.appbar .clock b{display:block;color:#fff;font-size:15px;font-weight:700;}
.appbar .clock.late b{color:#FF8A80;}
.who-btn{background:#1E2A36;border:1px solid #33485C;color:#9FB0BE;padding:4px 9px;
  font-family:"JetBrains Mono",monospace;font-size:10.5px;font-weight:600;letter-spacing:.02em;
  border-radius:11px;white-space:nowrap;}
.who-btn.unset{background:var(--signal);border-color:var(--signal);color:#fff;}
.sync-dot{width:7px;height:7px;border-radius:50%;background:#5A6B7A;flex-shrink:0;margin-right:-2px;}
.sync-dot.ok{background:#3FA574;}
.sync-dot.pending{background:#E0A93A;animation:pulse 1s ease-in-out infinite;}
.sync-dot.err{background:var(--signal);}
@keyframes pulse{0%,100%{opacity:1;}50%{opacity:.35;}}

.wrap{max-width:640px;margin:0 auto;padding:16px 12px 8px;}
.view{display:none;}
.view:not(.on){display:none !important;}
.view.on{display:block;}

/* ---------- карточка участника ---------- */
.card{background:var(--card);border:1px solid var(--rule);margin-bottom:10px;}
/* Карточка участника + его видео-блок — визуально одна группа: внешний
   отступ до следующего участника висит на группе целиком, а между самой
   карточкой и её видео зазора нет вообще. */
.p-group{margin-bottom:10px;}
.p-group .card{margin-bottom:0;}
.p-group .vid-row{margin-bottom:0;margin-top:-1px;}
.card .head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:12px 14px;}
.card .name{font-family:"Unbounded",sans-serif;font-weight:600;font-size:15px;text-transform:uppercase;flex-shrink:0;}
/* Бейдж статуса (Норма/Форс/...) — в одну строку с именем и числом
   повторений, не отдельной строкой под ними (по прямому запросу). */
.card .stat{display:flex;align-items:baseline;gap:8px;min-width:0;justify-content:flex-end;flex-wrap:wrap;}
.card .badges-inline{line-height:1;display:flex;gap:4px;flex-wrap:wrap;}
.card .reps-line{font-family:"JetBrains Mono",monospace;font-size:19px;font-weight:700;letter-spacing:-.01em;
  line-height:1;white-space:nowrap;}
.card .reps-line .ex{font-family:"IBM Plex Sans",sans-serif;font-size:12px;font-weight:400;color:var(--muted);
  text-transform:none;letter-spacing:normal;margin-left:2px;}
.card.gone{opacity:.5;}

.badge{font-family:"JetBrains Mono",monospace;font-size:10px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase;padding:3px 7px;border:1px solid var(--rule);color:var(--steel);white-space:nowrap;}
.badge.mult{background:var(--signal);border-color:var(--signal);color:#fff;}
.badge.mult.m3{background:var(--signal-2);border-color:var(--signal-2);}
.badge.mult.m4{background:var(--signal-3);border-color:var(--signal-3);}
.badge.done{background:var(--ok);border-color:var(--ok);color:#fff;}
.badge.alt{background:var(--alt);border-color:var(--alt);color:#fff;}
.badge.forgiven{background:var(--fm);border-color:var(--fm);color:#fff;}
.badge.missed{background:var(--ink);border-color:var(--ink);color:#fff;}

.status-row{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--rule);border-top:1px solid var(--rule);}
.status-row button{background:var(--card);border:0;padding:9px 4px;font-size:11.5px;font-weight:600;color:var(--muted);
  display:flex;flex-direction:column;align-items:center;gap:3px;line-height:1.15;}
.status-row button .g{font-size:15px;line-height:1;}
.status-row button.sel{background:var(--ink);color:#fff;}
.status-row button.sel.s-done{background:var(--ok);}
.status-row button.sel.s-alt{background:var(--alt);}
.status-row button.sel.s-forgiven{background:var(--fm);}
.status-row button.sel.s-missed{background:var(--signal);}

.hint{font-size:13px;color:var(--muted);padding:9px 14px;border-top:1px solid var(--rule);}
.hint b{color:var(--ink);}
.hint.warn{color:var(--signal);}

/* ---------- журнал ---------- */
.grid{background:var(--card);border:1px solid var(--rule);overflow-x:auto;}
table.log{border-collapse:collapse;width:100%;font-family:"JetBrains Mono",monospace;font-size:12px;}
table.log th,table.log td{border-bottom:1px solid var(--rule);padding:0;text-align:center;}
table.log thead th{font-size:10px;letter-spacing:.05em;color:var(--steel);text-transform:uppercase;
  border-bottom:2px solid var(--ink);padding:8px 4px;}
table.log td.d{text-align:left;padding:0 8px;white-space:nowrap;color:var(--muted);font-size:11px;}
table.log tr.we td.d{color:var(--signal);}
table.log td span{display:block;width:100%;padding:11px 2px;font-size:14px;line-height:1;}
.cell-done{color:var(--ok);} .cell-alt{color:var(--alt);} .cell-forgiven{color:var(--fm);}
.cell-missed{color:var(--signal);} .cell-none{color:#C6CED5;}

/* ---------- счёт ---------- */
.ledger{background:var(--card);border:1px solid var(--rule);}
.lrow{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px;border-bottom:1px solid var(--rule);}
.lrow:last-child{border-bottom:0;}
.lrow .who{font-family:"Unbounded",sans-serif;font-weight:600;font-size:14px;text-transform:uppercase;}
.lrow .sub{font-size:12.5px;color:var(--muted);margin-top:2px;}
.lrow .sum{font-family:"JetBrains Mono",monospace;font-weight:700;font-size:17px;white-space:nowrap;}
.sum.plus{color:var(--ok);} .sum.minus{color:var(--signal);} .sum.zero{color:var(--muted);}
.total{background:var(--ink);color:#fff;padding:14px;display:flex;justify-content:space-between;align-items:center;}
.total span{font-family:"JetBrains Mono",monospace;font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:#9FB0BE;}
.total b{font-family:"JetBrains Mono",monospace;font-size:19px;}

/* ---------- правила ---------- */
.doc{background:var(--card);border:1px solid var(--rule);padding:18px 16px;}
.doc h3{font-family:"Unbounded",sans-serif;font-size:14px;text-transform:uppercase;margin:22px 0 8px;letter-spacing:.01em;}
.doc h3:first-child{margin-top:0;}
.doc p{margin:0 0 10px;font-size:14.5px;}
.doc ul{margin:0 0 10px;padding-left:19px;font-size:14.5px;}
.doc li{margin-bottom:6px;}
.doc .note{border-left:3px solid var(--steel);padding:2px 0 2px 12px;color:var(--steel);font-size:14px;margin:12px 0;}
.ladder{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin:12px 0;}
.ladder div{padding:10px 8px;color:#fff;background:var(--signal);}
.ladder div:nth-child(2){background:var(--signal-2);}
.ladder div:nth-child(3){background:var(--signal-3);}
.ladder .x{font-family:"JetBrains Mono",monospace;font-size:22px;font-weight:700;line-height:1;}
.ladder .l{font-size:11px;margin-top:5px;opacity:.85;line-height:1.3;}

/* ---------- настройки ---------- */
/* Крупные разделы (Профиль/Подключения/Челлендж/...) — по прямому
   запросу вместо одного длинного списка без иерархии. Заголовок раздела
   визуально тяжелее, чем h2 у подпунктов внутри него (тот остаётся
   прежним — просто теперь "вложен" визуально отступом слева). */
.cfg-group{margin-bottom:28px;}
.cfg-group-title{display:flex;align-items:center;gap:8px;font-family:"Unbounded",sans-serif;
  font-weight:700;font-size:13px;letter-spacing:.01em;text-transform:uppercase;color:var(--ink);
  padding-bottom:8px;margin-bottom:14px;border-bottom:2px solid var(--ink);}
.cfg-group-title .g{font-size:16px;line-height:1;}
.cfg-group h2{margin-left:2px;}

/* Профиль — фото + ник, редактирует только сам участник за себя. */
.profile-row{display:flex;align-items:center;gap:14px;}
.profile-avatar-btn{position:relative;flex-shrink:0;width:64px;height:64px;border-radius:50%;
  padding:0;border:1px solid var(--rule);background:var(--steel);color:#fff;overflow:hidden;}
.profile-avatar-btn #profile-avatar-preview{width:100%;height:100%;display:flex;align-items:center;
  justify-content:center;font-family:"Unbounded",sans-serif;font-weight:700;font-size:22px;}
.profile-avatar-btn img{width:100%;height:100%;object-fit:cover;display:block;}
.profile-avatar-edit{position:absolute;right:-2px;bottom:-2px;width:22px;height:22px;border-radius:50%;
  background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;font-size:11px;
  border:2px solid var(--card);}
.profile-fields{flex:1;min-width:0;}
.profile-fields label{margin-top:0 !important;}
.panel{background:var(--card);border:1px solid var(--rule);padding:16px;margin-bottom:12px;}
.panel label{display:block;font-family:"JetBrains Mono",monospace;font-size:10.5px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--steel);margin:14px 0 5px;}
.panel label:first-of-type{margin-top:0;}
.panel input,.panel select{width:100%;padding:10px 11px;border:1px solid var(--rule);background:#F7F9FA;
  font-family:"JetBrains Mono",monospace;font-size:16px;color:var(--ink);border-radius:0;}
.panel .row{display:flex;gap:8px;}
.panel p.h{font-size:13px;color:var(--muted);margin:8px 0 0;}
.btn{display:inline-block;border:1px solid var(--ink);background:var(--ink);color:#fff;padding:11px 16px;
  font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;}
.btn.ghost{background:transparent;color:var(--ink);}
.btn.danger{background:var(--signal);border-color:var(--signal);}
.btn[disabled]{opacity:.45;}
.status-line{font-size:13px;margin-top:12px;color:var(--muted);}
.status-line.err{color:var(--signal);}
.status-line.ok{color:var(--ok);}

/* ---------- верхняя навигация (заменила нижнюю панель вкладок) ----------
   Одна страница, снизу совершенно пусто — по прямому запросу. Дом —
   «Сегодня», без явной кнопки (сама шапка/лого = "домой"). На "Сегодня"
   видна группа [Журнал | Чат (+бейдж) | Настройки], на всех остальных
   экранах — ровно одна кнопка "← Назад", тот же элемент везде. */
.topnav{background:var(--ink);display:flex;align-items:center;gap:8px;padding:0 16px 10px;}
/* Раньше был просто текст без фона — на тёмной шапке терялся почти до
   невидимости. Теперь такая же по весу "пилюля", как у остальных
   кнопок топнава, чтобы её невозможно было не заметить. */
.topnav-back{background:#1E2A36;border:1px solid #33485C;color:#fff;font-family:"JetBrains Mono",monospace;
  font-size:12.5px;font-weight:700;letter-spacing:.02em;padding:7px 14px;border-radius:11px;
  display:flex;align-items:center;gap:4px;}
/* "Денис печатает…" справа от "← Назад" — тот же голубой акцент и
   тот же некрупный шрифт, что в референсе Telegram (заголовок чата).
   Показывается только на вкладке "Чат" (body.chat-open) — на "Журнал"/
   "Настройки" тот же #topnav-back используется без этого текста. */
.topnav-typing{display:none;align-items:center;gap:5px;font-family:"IBM Plex Sans",sans-serif;font-size:13px;
  font-weight:600;color:#9FB0BE;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.topnav-typing b{color:#4EA1F5;font-weight:600;}
body.chat-open .topnav-typing:not([hidden]){display:flex;}

/* Три точки прыгают по очереди, как в большинстве мессенджеров —
   каждая поднимается и снова опускается со сдвигом по времени
   (animation-delay), а не мигают все разом. currentColor — тот же
   приглушённый серый, что и раньше был у статичных "•••". */
.topnav-typing-dots{display:inline-flex;align-items:flex-end;gap:2px;height:8px;}
.topnav-typing-dots i{display:block;width:3.5px;height:3.5px;border-radius:50%;
  background:currentColor;animation:typingDotBounce 1.1s infinite ease-in-out;}
.topnav-typing-dots i:nth-child(2){animation-delay:.15s;}
.topnav-typing-dots i:nth-child(3){animation-delay:.3s;}
@keyframes typingDotBounce{
  0%,60%,100%{transform:translateY(0);opacity:.5;}
  30%{transform:translateY(-4px);opacity:1;}
}
@media (prefers-reduced-motion:reduce){
  .topnav-typing-dots i{animation:none;opacity:.85;}
}

.topnav-home-actions{display:flex;align-items:center;gap:8px;width:100%;}
.topnav-journal{background:#1E2A36;border:1px solid #33485C;color:#9FB0BE;padding:6px 12px;
  font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:600;letter-spacing:.02em;
  border-radius:11px;display:flex;align-items:center;gap:5px;}
.topnav-chat{flex:1;position:relative;background:var(--signal);border:0;color:#fff;padding:8px 14px;
  font-family:"JetBrains Mono",monospace;font-size:12px;font-weight:700;letter-spacing:.03em;
  border-radius:11px;display:flex;align-items:center;justify-content:center;gap:6px;}
.topnav-settings{background:#1E2A36;border:1px solid #33485C;color:#9FB0BE;width:32px;height:32px;
  border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:15px;flex-shrink:0;}
.topnav-bell{background:#1E2A36;border:1px solid #33485C;color:#9FB0BE;width:32px;height:32px;
  border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;flex-shrink:0;}
.topnav-bell.off{opacity:.5;}

/* ---------- таймер тренировки (шапка, любая вкладка) ----------
   Простой секундомер: старт/стоп на этом телефоне, без синхронизации
   с остальными участниками. Пока идёт — видна полоса под шапкой на
   ЛЮБОМ экране приложения (Чат, Журнал, Настройки), не только на
   «Сегодня», по прямому запросу. */
.workout-timer-bar{display:flex;align-items:center;gap:8px;padding:8px 16px;
  background:var(--signal);color:#fff;}
.wt-dot{width:8px;height:8px;border-radius:50%;background:#fff;flex-shrink:0;
  animation:wt-pulse 1.2s ease-in-out infinite;}
@keyframes wt-pulse{0%,100%{opacity:1;}50%{opacity:.35;}}
.wt-label{font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:600;
  letter-spacing:.02em;text-transform:uppercase;opacity:.9;}
.wt-time{font-family:"JetBrains Mono",monospace;font-size:15px;font-weight:700;
  letter-spacing:.03em;margin-left:auto;}
.wt-stop{background:rgba(255,255,255,.18);border:1px solid rgba(255,255,255,.4);
  color:#fff;padding:5px 12px;border-radius:10px;font-family:"JetBrains Mono",monospace;
  font-size:11px;font-weight:700;}
.wt-stop:active{background:rgba(255,255,255,.3);}

/* Кнопка старта — на "Сегодня", под мини-кнопками. Видна только пока
   таймер НЕ идёт — во время тренировки статус и "Стоп" уже показывает
   верхняя красная полоса (#workout-timer-bar), эта кнопка в этот
   момент прячется (см. renderWorkoutQuicklink() в app.js), чтобы не
   дублировать и не мешать. */
.wt-toggle{width:100%;display:flex;align-items:center;justify-content:center;gap:8px;
  background:var(--card);border:1px solid var(--rule);color:var(--ink);
  padding:11px 10px;border-radius:12px;margin-bottom:16px;
  font-family:"JetBrains Mono",monospace;font-size:12.5px;font-weight:700;letter-spacing:.02em;}
.wt-toggle .g{font-size:15px;line-height:1;}

/* Всплывающее сообщение — для действий с главной, где нет своей
   строки статуса (колокольчик уведомлений). */
.toast{position:fixed;left:50%;transform:translateX(-50%) translateY(20px);
  bottom:calc(24px + var(--safe-b));z-index:200;max-width:88%;
  background:var(--ink);color:#fff;padding:10px 16px;border-radius:20px;
  font-size:13px;line-height:1.35;text-align:center;
  opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;}
.toast.on{opacity:1;transform:translateX(-50%) translateY(0);}
.toast.err{background:var(--signal);}

/* ---------- мини-кнопки сверху на «Сегодня» ---------- */
.quicklinks{display:flex;gap:8px;margin-bottom:16px;}
.quicklinks button{position:relative;flex:1;background:var(--card);border:1px solid var(--rule);
  padding:10px 6px;display:flex;flex-direction:column;align-items:center;gap:3px;
  font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:600;color:var(--ink);letter-spacing:.02em;}
.quicklinks button .g{font-size:15px;line-height:1;}
.quicklinks button[disabled]{opacity:.6;}
.quicklinks button.spinning .g{display:inline-block;animation:spin .8s linear infinite;}
@keyframes spin{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}
#ql-money-sum.zero{color:var(--ok);}
#ql-money-sum.owe{color:var(--signal);}

/* ---------- статус мгновенной записи отметки в SQL ---------- */
.save-status{display:flex;align-items:center;gap:8px;padding:8px 12px;margin-bottom:14px;
  font-family:"JetBrains Mono",monospace;font-size:12px;font-weight:600;border:1px solid var(--rule);}
.save-status.pending{background:#FFF6E0;border-color:#E0A93A;color:#8A6212;}
.save-status.ok{background:#E7F3ED;border-color:var(--ok);color:var(--ok);}
.save-status.err{background:#FBEAE9;border-color:var(--signal);color:var(--signal);}
.save-status .dot{width:7px;height:7px;border-radius:50%;flex-shrink:0;background:currentColor;}
.save-status.pending .dot{animation:pulse 1s ease-in-out infinite;}

.datebar{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:14px;}
.datebar .d{font-family:"JetBrains Mono",monospace;font-size:13px;font-weight:600;}
.datebar button{background:var(--card);border:1px solid var(--rule);padding:8px 13px;font-size:15px;line-height:1;}
.datebar button[disabled]{opacity:.35;}

.empty{padding:28px 14px;text-align:center;color:var(--muted);font-size:14px;
  background:var(--card);border:1px solid var(--rule);}

@media (prefers-reduced-motion:no-preference){
  .view.on{animation:fade .18s ease-out;}
  @keyframes fade{from{opacity:0;transform:translateY(4px);}to{opacity:1;transform:none;}}
}
:focus-visible{outline:2px solid var(--signal);outline-offset:2px;}
[hidden]{display:none !important;}

/* ---------- видео дня ---------- */
.vid-row{background:var(--card);border:1px solid var(--rule);display:flex;align-items:center;gap:12px;padding:12px 14px;margin-bottom:8px;}
.vid-row .who{font-family:"Unbounded",sans-serif;font-weight:600;font-size:13px;text-transform:uppercase;min-width:70px;}
.vid-row .clips{display:flex;gap:10px;flex:1;flex-wrap:wrap;}
.vid-clip{position:relative;flex-shrink:0;}
.vid-thumb{width:44px;height:44px;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;
  font-size:16px;border:0;flex-shrink:0;position:relative;overflow:hidden;padding:0;}
.vid-thumb img{width:100%;height:100%;object-fit:cover;display:block;}
.vid-reps{position:absolute;bottom:1px;right:1px;background:rgba(16,23,30,.82);color:#fff;font-size:8px;
  font-family:"JetBrains Mono",monospace;font-weight:700;padding:1px 3px;line-height:1.3;}
/* «?» — число повторений не указано, но это своё видео: можно дописать.
   Заметно ярче обычной плашки, чтобы читалось как действие, а не как
   отсутствие данных. */
.vid-reps.ask{background:var(--signal);cursor:pointer;font-size:9px;padding:1px 5px;}
.vid-expiry{position:absolute;bottom:1px;left:1px;background:rgba(179,49,42,.88);color:#fff;font-size:7px;
  font-family:"JetBrains Mono",monospace;font-weight:700;padding:1px 3px;line-height:1.3;text-transform:uppercase;}
.vid-del{position:absolute;top:-7px;right:-7px;width:20px;height:20px;background:var(--signal);color:#fff;
  border:2px solid var(--card);border-radius:50%;font-size:11px;line-height:16px;text-align:center;padding:0;}
.vid-add{background:transparent;border:1px dashed var(--rule);color:var(--steel);width:44px;height:44px;font-size:19px;flex-shrink:0;}
.vid-add[disabled]{opacity:.35;}
.vid-empty-hint{font-size:12.5px;color:var(--muted);padding:2px 14px 12px;}

/* ---------- модалки записи/просмотра ---------- */
.rec-overlay{position:fixed;inset:0;background:rgba(16,23,30,.92);z-index:80;display:none;align-items:flex-end;justify-content:center;}
.rec-overlay.on{display:flex;}
/* Подтверждение и ввод повторений всегда вызываются ПОВЕРХ другого
   экрана (например, поверх модалки записи — «норма выполнена, закрыть
   день?» спрашивается в момент отправки видео). При одинаковом z-index
   побеждал тот, кто ниже в разметке, — то есть модалка записи, и диалог
   оказывался под ней: человек его не видел, отправка молча вставала
   намертво, а повторные нажатия плодили дубли видео. */
#confirmOverlay, #repsOverlay{z-index:120;}
.rec-box{background:var(--ink);color:#fff;width:100%;max-width:520px;padding-bottom:calc(16px + var(--safe-b));}
.rec-head{display:flex;justify-content:space-between;align-items:center;padding:calc(12px + env(safe-area-inset-top,0px)) 16px 10px;
  font-family:"Unbounded",sans-serif;font-weight:600;font-size:14px;text-transform:uppercase;}
.rec-head button{background:transparent;border:0;color:#fff;font-size:18px;padding:4px 8px;}
.rec-head .close-safe{font-family:"JetBrains Mono",monospace;font-size:12px;font-weight:600;
  letter-spacing:.02em;color:#9FB0BE;padding:6px 10px;}
.rec-limit-warn{margin:0 16px 10px;padding:7px 11px;background:#3A2E10;color:#E0A93A;
  font-family:"JetBrains Mono",monospace;font-size:11.5px;font-weight:700;letter-spacing:.02em;
  border:1px solid #5A4718;text-align:center;}

/* ---------- "Кто прочитал" ---------- */
.readby-list{padding:6px 16px 18px;}
.readby-row{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid rgba(255,255,255,.08);}
.readby-row:last-child{border-bottom:0;}
.readby-avatar{width:30px;height:30px;border-radius:50%;flex-shrink:0;display:flex;
  align-items:center;justify-content:center;color:#fff;font-weight:700;font-size:12px;}
/* Фото профиля вместо цветного кружка с буквой — общее правило для
   msg-avatar/readby-avatar/mention-avatar, см. renderAvatarCircle(). */
.msg-avatar.has-photo,.readby-avatar.has-photo,.mention-avatar.has-photo{background:transparent;padding:0;overflow:hidden;}
.msg-avatar.has-photo img,.readby-avatar.has-photo img,.mention-avatar.has-photo img{
  width:100%;height:100%;object-fit:cover;display:block;border-radius:50%;}
.readby-name{flex:1;font-size:14px;}
.readby-status{font-size:12px;color:#9FB0BE;}
.readby-row:not(.unread) .readby-status{color:#3FA574;}
.rec-stage{position:relative;width:100%;aspect-ratio:3/4;background:#000;overflow:hidden;}
.rec-stage video{width:100%;height:100%;object-fit:cover;display:block;}
.rec-stage video.mirror{transform:scaleX(-1);}
.rec-timer{position:absolute;top:10px;left:10px;background:var(--signal);color:#fff;font-family:"JetBrains Mono",monospace;
  font-weight:700;font-size:13px;padding:4px 9px;letter-spacing:.04em;}
/* Обратный отсчёт перед стартом записи (10…1), см. #rec-countdown в
   index.html и startRecordingCountdown() в app.js. Крупные цифры по
   центру картинки, полупрозрачная плашка под ними — картинка с камеры
   остаётся видна, не перекрывается полностью. z-index не нужен — это
   единственный абсолютно спозиционированный элемент поверх .rec-stage
   после .rec-timer, идёт следом в разметке. */
.rec-countdown{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:rgba(0,0,0,.28);pointer-events:none;
  font-family:"JetBrains Mono",monospace;font-weight:700;font-size:96px;color:#fff;
  text-shadow:0 2px 12px rgba(0,0,0,.6);}
.rec-reps-row{padding:12px 16px 0;}
.rec-reps-row label{display:block;font-family:"JetBrains Mono",monospace;font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;color:#9FB0BE;margin-bottom:6px;}
.rec-reps-row input{width:100%;padding:10px 12px;border:1px solid #33485C;background:#1E2A36;color:#fff;
  font-family:"JetBrains Mono",monospace;font-size:16px;}

.rec-settings-row{display:flex;gap:8px;padding:0 16px 12px;align-items:stretch;}
.rec-mic-btn{flex-shrink:0;background:#2A3744;border:1px solid #2A3744;color:#fff;padding:0 12px;
  font-family:"JetBrains Mono",monospace;font-size:11px;font-weight:600;white-space:nowrap;}
.rec-mic-btn.off{background:transparent;border-color:#4A5B6B;color:#9FB0BE;}
.rec-quality-pick{display:flex;flex:1;gap:1px;background:#33485C;}
.rec-quality-pick button{flex:1;background:#1E2A36;border:0;color:#9FB0BE;font-family:"JetBrains Mono",monospace;
  font-size:10.5px;font-weight:600;padding:0 4px;}
.rec-quality-pick button.on{background:#4A5B6B;color:#fff;}

.speed-pick{display:flex;gap:1px;background:#33485C;margin:0 16px;}
.speed-pick button{flex:1;background:#1E2A36;border:0;color:#9FB0BE;font-family:"JetBrains Mono",monospace;
  font-size:12px;font-weight:600;padding:9px 4px;}
.speed-pick button.on{background:var(--signal);color:#fff;}

.rec-msg{padding:10px 16px 0;font-size:13px;color:#9FB0BE;min-height:18px;}
.rec-controls{display:flex;gap:8px;padding:14px 16px 0;}
.rec-controls .btn{flex:1;text-align:center;padding-left:8px;padding-right:8px;font-size:11px;white-space:nowrap;}
.btn.cam{background:#2A3744;border-color:#2A3744;color:#fff;}
.btn.cam[disabled]{opacity:.4;}
#rec-toggle.active{background:#4A5B6B;border-color:#4A5B6B;}

/* ---------- выбор «кто я» ---------- */
.who-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;}
.who-grid button{background:var(--card);border:1px solid var(--rule);padding:12px 10px;
  font-family:"Unbounded",sans-serif;font-weight:600;font-size:14px;text-transform:uppercase;color:var(--ink);}
.who-grid button.on{background:var(--ink);border-color:var(--ink);color:#fff;}
/* Компактный вариант — только для настроек (#cfg-who-pick), где эта
   сетка появляется лишь в редком краевом случае (идентичность почему-то
   не выбрана), в остальное время там просто закреплённое имя+кнопка
   сброса. В обязательном гейте при первом запуске и в чате оставлен
   обычный размер — там это единственное и главное действие на экране,
   должно быть удобно тапать. */
.who-grid.compact{gap:6px;}
.who-grid.compact button{padding:8px 6px;font-size:12px;}
.who-locked-name{font-family:"Unbounded",sans-serif;font-weight:600;font-size:15px;text-transform:uppercase;color:var(--ink);}

/* ---------- компактные карточки участников в настройках ---------- */
.ppl-card{padding:10px 0;border-bottom:1px solid var(--rule);}
.ppl-card:last-child{border-bottom:0;}
.ppl-name{font-family:"Unbounded",sans-serif;font-weight:600;font-size:12px;text-transform:uppercase;
  margin-bottom:6px;color:var(--muted);}
.ppl-row{display:flex;gap:6px;}
.ppl-field{flex:1;min-width:0;}
.ppl-field span{display:block;font-family:"JetBrains Mono",monospace;font-size:9px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);margin-bottom:3px;}
.ppl-field input{width:100%;padding:6px 7px;border:1px solid var(--rule);background:#F7F9FA;
  font-family:"JetBrains Mono",monospace;font-size:13px;color:var(--ink);}

/* ---------- что нового ---------- */
.cl-version{padding-bottom:12px;margin-bottom:12px;border-bottom:1px solid var(--rule);}
.cl-version:last-child{border-bottom:0;margin-bottom:0;padding-bottom:0;}
.cl-version b{font-family:"JetBrains Mono",monospace;font-size:12px;letter-spacing:.04em;color:var(--steel);}
.cl-version ul{margin:6px 0 0;padding-left:18px;}
.cl-version li{font-size:13px;line-height:1.5;margin-bottom:3px;}

/* ============================================================
   Чат — оформление один в один с Herald Chat (по прямому запросу):
   тёмная тема, скруглённые пузыри без хвостика, группировка подряд
   идущих сообщений одного автора, время утоплено в правый нижний угол
   пузыря через float, реакции внахлёст снизу пузыря, аватар только у
   последнего сообщения группы. Тёмный фон — только у вкладки чата,
   не у всего приложения, по тому же принципу, что и тёмная модалка
   записи видео (см. .rec-box) — самостоятельный "режим" внутри в целом
   светлого приложения, не глобальная смена темы.
   ============================================================ */
:root{
  --chat-bg:#121316; --chat-surface:#1b1d22; --chat-surface2:#22252b; --chat-border:#2c2f36;
  --chat-primary:#8774E1; --chat-mine:#6C5DD3; --chat-text:#e8eaed; --chat-muted:#9aa0a8;
}
/* Геометрия чата. Три правила, которые тут нельзя нарушать:

   1. Никакого position:fixed и никакого transform на контейнерах чата.
      Любой transform (и fixed-предок) становится containing block'ом
      для СВОИХ position:fixed потомков. Именно на этом чат ломался:
      контейнер центрировался через translateX(-50%), и поле ввода
      вместе с меню переставало отсчитываться от экрана — уезжало на
      дно прокручиваемого контента, с экрана пропадало совсем.

   2. Скроллится ровно ОДИН элемент — .chat-log. Ни страница целиком,
      ни #v-chat. Тогда "прокрутить в самый низ" — это буквально
      log.scrollTop = log.scrollHeight, без вычислений высоты документа,
      которые вечно расходились с реальностью.

   3. Поле ввода — не наложенный сверху fixed-слой, а нижняя строка
      flex-колонки (.chat-bottom). Поэтому под него не нужно резервировать
      padding "на глаз": он физически занимает своё место, и последнее
      сообщение не может под него заехать в принципе. */
.view.on#v-chat{display:flex;flex-direction:column;
  margin:-16px -12px 0;
  height:calc(100vh - var(--header-h));
  height:calc(100dvh - var(--header-h));
  overflow:hidden;
  background:var(--chat-bg);
  padding:0;color:var(--chat-text);}
/* Пока открыт чат, страница целиком не скроллится — иначе под чатом
   оставалась "губа" из фона body, которую можно было оттянуть. */
body.chat-open{overflow:hidden;}
#chat-wrap{flex:1;display:flex;flex-direction:column;min-height:0;}
/* Единственный скроллер чата. min-height:0 обязателен: без него
   flex-элемент не даёт себя сжать меньше контента и overflow не
   включается. */
.chat-log{flex:1;min-height:0;overflow-y:auto;-webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;display:flex;flex-direction:column;padding:10px 12px;}
/* Когда сообщений мало, они должны стоять внизу, у поля ввода, а не
   висеть вверху. justify-content:flex-end для этого не годится — при
   переполнении он обрезает верх ленты и до старых сообщений не
   долистать. Псевдоэлемент с margin-top:auto делает то же самое
   безопасно: при коротком списке он забирает свободное место, при
   длинном схлопывается в ноль. */
.chat-log::before{content:'';margin-top:auto;}

.chat-day{align-self:center;font-size:11.5px;font-weight:600;color:var(--chat-muted);
  background:rgba(127,127,127,.22);padding:4px 12px;margin:10px 0 6px;border-radius:12px;}

.msg-row{position:relative;display:flex;gap:8px;margin-bottom:1px;align-items:flex-end;}
.msg-row.group-start{margin-top:6px;}
.msg-row.mine{flex-direction:row-reverse;}
.msg-col{display:flex;flex-direction:column;max-width:75%;min-width:0;}
.msg-row.mine .msg-col{align-items:flex-end;}
.avatar-spacer{width:28px;flex-shrink:0;}
.msg-avatar{width:28px;height:28px;border-radius:50%;display:flex;align-items:center;justify-content:center;
  color:#fff;font-weight:700;font-size:12px;flex-shrink:0;}

.msg-sender-inline{font-size:12.5px;font-weight:700;margin-bottom:2px;}

.bubble{padding:7px 8px 8px 10px;border-radius:14px;font-size:13.5px;line-height:1.35;
  min-width:0;position:relative;background:var(--chat-surface2);}
.bubble.out{background:var(--chat-mine);}
.bubble-text{white-space:pre-wrap;word-break:break-word;padding-right:2px;}

/* Медиа без подписи — как в Telegram: никакого цветного "пузыря" вокруг
   фото/видео, сама картинка и есть пузырь (со своими скруглёнными
   углами). Применяется только когда у сообщения нет текста-подписи
   (см. isMediaOnly() в app.js) — с подписью пузырь остаётся обычным,
   т.к. под текст всё равно нужен фон. */
.bubble.media-only{padding:0;background:transparent;}
/* Реакции обычно "заезжают" под пузырь на -9px (см. .msg-reactions
   ниже) — это рассчитано на цветной фон пузыря под ними. У голого медиа
   фона нет, тот же отрицательный отступ обрезал бы кусок фото/видео. */
.bubble.media-only + .msg-reactions{margin-top:6px;}
/* Имя отправителя (в группе) и цитата-ответ рендерятся ДО медиа внутри
   того же пузыря — у них своего отступа от краёв не было, его давал
   padding пузыря, которого у media-only больше нет. */
.bubble.media-only .msg-sender-inline{margin:6px 8px 4px;}
.bubble.media-only .reply-quote{margin:6px 8px 5px;}

/* Время — последним элементом текста, float:right заставляет текст
   обтекать его, как в телеге, вместо отдельной строки под сообщением. */
.msg-time-inline{float:right;margin:4px 0 -3px 8px;font-size:10.5px;line-height:1;
  color:rgba(255,255,255,.55);white-space:nowrap;}

/* Счётчик прочитавших ("N/4" / "+") — раньше тут были CSS-галочки
   (::after content), теперь настоящий текст из readCountText() в
   app.js, тем же цветом/размером — просто наследует .msg-time-inline,
   отдельно стилизовать нечего. */
.read-count{font-weight:600;}

.reply-quote{border-left:3px solid var(--chat-primary);padding:2px 8px;margin-bottom:5px;
  background:rgba(255,255,255,.08);border-radius:4px;overflow:hidden;cursor:pointer;}
.reply-quote b{display:block;font-size:11px;font-weight:600;color:var(--chat-primary);}
.reply-quote span{font-size:12px;color:var(--chat-muted);display:block;overflow:hidden;
  white-space:nowrap;text-overflow:ellipsis;}
.msg-row.flash .bubble{animation:msgflash .9s ease;}
@keyframes msgflash{0%,100%{box-shadow:none;}30%{box-shadow:0 0 0 2px var(--chat-primary);}}

/* Реакции "прижаты" к нижнему краю пузыря — отрицательный margin-top
   заводит их под бабл внахлёст, как чипсы в телеграме. */
.msg-reactions{display:flex;flex-wrap:wrap;gap:4px;margin-top:-9px;padding:0 2px;position:relative;z-index:2;}
.react-pill{display:flex;align-items:center;gap:3px;padding:2px 7px;border-radius:11px;font-size:11.5px;
  border:2px solid var(--chat-bg);background:var(--chat-surface2);color:var(--chat-text);}
.react-pill.mine{background:rgba(135,116,225,.4);}

/* Чип появляется с лёгким «пружинным» подскоком — как в Telegram, где
   реакция не возникает резко, а слегка выпрыгивает. */
.react-pill{animation:reactPop .22s cubic-bezier(.3,1.4,.5,1);}
@keyframes reactPop{
  from{transform:scale(.4);opacity:0;}
  to{transform:scale(1);opacity:1;}
}

/* Мини-салют вокруг только что поставленной реакции. Отдельный слой
   поверх всего (position:fixed, pointer-events:none) — намеренно НЕ
   внутри сообщения: любая вставка внутрь пузыря снова меняла бы его
   высоту, а её только что зафиксировал якорь прокрутки. */
.react-burst{position:fixed;z-index:300;pointer-events:none;width:0;height:0;}
.react-burst span{position:absolute;left:0;top:0;font-size:13px;line-height:1;
  animation:reactBurst .75s ease-out forwards;}
@keyframes reactBurst{
  0%{transform:translate(-50%,-50%) scale(.5);opacity:0;}
  25%{opacity:1;}
  100%{transform:translate(calc(-50% + var(--dx)),calc(-50% + var(--dy))) scale(1.15);opacity:0;}
}
@media (prefers-reduced-motion:reduce){
  .react-pill{animation:none;}
  .react-burst{display:none;}
}

.bubble.pending{opacity:.55;}

/* Подсветка выбранной строки в режиме множественного выбора — как
   лёгкая заливка на всю ширину ленты позади содержимого. */
.msg-row.selected{background:rgba(135,116,225,.12);border-radius:8px;}

/* Чекбокс слева от строки — пустой круг / залитый с галочкой, ровно
   как в референсе Telegram Web. Рендерится в HTML только пока реально
   включён режим выбора (см. renderChat в app.js) — так его отсутствие
   не сдвигает обычную ленту лишним flex-gap. */
.msg-select-check{width:22px;height:22px;border-radius:50%;border:2px solid var(--chat-muted);
  flex-shrink:0;align-self:center;box-sizing:border-box;background:transparent;}
.msg-select-check.checked{background:var(--chat-primary);border-color:var(--chat-primary);
  position:relative;}
/* .msg-row.mine идёт flex-direction:row-reverse (аватар/пузырь справа) —
   без этого чекбокс, будучи первым в DOM, оказался бы справа тоже.
   order:99 в реверснутом контейнере — это "к концу главной оси", а
   конец главной оси при row-reverse визуально слева. */
.msg-row.mine .msg-select-check{order:99;}
.msg-select-check.checked::after{content:'✓';position:absolute;inset:0;display:flex;
  align-items:center;justify-content:center;color:#fff;font-size:13px;font-weight:700;}
.chat-log.selecting .msg-row{cursor:pointer;}

/* ---------- видео-карточка в чате ---------- */
/* Превью фото/видео в чате — по прямому запросу уменьшены в 1.5 раза
   (было 168px/200px/220px, аспект и пропорции сохранены). */
.chat-vid-card{position:relative;display:block;width:112px;aspect-ratio:3/4;background:var(--chat-bg);
  border:0;padding:0;overflow:hidden;border-radius:10px;}
.chat-vid-card img{width:100%;height:100%;object-fit:cover;display:block;}
.chat-vid-noimg{width:100%;height:100%;display:flex;align-items:center;justify-content:center;
  color:#4A5B6B;font-size:19px;}
.chat-vid-play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:24px;height:24px;border-radius:50%;background:rgba(16,23,30,.55);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:10px;pointer-events:none;}
.chat-vid-reps{position:absolute;bottom:5px;right:5px;background:rgba(16,23,30,.82);color:#fff;
  font-size:10px;font-weight:700;padding:2px 5px;border-radius:4px;}
/* Счётчик повторов и время вместе не влезают в один угол — время уходит
   в левый нижний. */
.chat-vid-reps ~ .chat-media-time{left:5px;right:auto;}

/* Время поверх фото/видео без подписи — полупрозрачный чип в правом
   нижнем углу самого медиа, как в Telegram, вместо отдельной строки
   под пузырём (той больше нет — см. .bubble.media-only выше). */
.chat-media-time{position:absolute;bottom:5px;right:6px;background:rgba(16,23,30,.55);
  color:#fff;font-size:10.5px;line-height:1;padding:3px 6px;border-radius:9px;
  pointer-events:none;white-space:nowrap;}

/* ---------- делитель непрочитанных ---------- */
.chat-unread-divider{align-self:center;font-size:11px;font-weight:700;color:#fff;
  background:var(--signal);padding:4px 14px;margin:10px 0 8px;border-radius:12px;
  text-transform:uppercase;letter-spacing:.04em;}

/* ---------- панель ответа над полем ввода ---------- */
/* В потоке, прямо над полем ввода — не наложением поверх экрана. */
.reply-bar{display:flex;align-items:center;gap:8px;background:var(--chat-surface2);
  border-top:1px solid var(--chat-border);padding:7px 12px;font-size:12.5px;
  color:var(--chat-text);}
.reply-bar-txt{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.reply-bar-txt b{display:block;font-size:11px;font-weight:600;color:var(--chat-primary);}
.reply-bar button{background:transparent;border:0;color:var(--chat-muted);font-size:15px;padding:2px 4px;}

/* Нижняя строка flex-колонки чата. Никакого fixed: место под себя
   занимает физически, поэтому сообщения под него заехать не могут.
   .chat-bottom — общий контейнер низа, он же точка отсчёта (relative)
   для всплывающих меню, которые садятся на bottom:100% (прямо над ним). */
.chat-bottom{position:relative;flex-shrink:0;background:var(--chat-bg);
  padding-bottom:var(--safe-b);}
.chat-input{display:flex;align-items:center;gap:8px;
  background:var(--chat-bg);padding:8px 12px 10px;}

/* ---------- кнопка "вниз" (как в Telegram) — когда пролистал вверх ---------- */
.scroll-bottom-btn{position:absolute;right:12px;bottom:100%;margin-bottom:10px;
  z-index:54;width:40px;height:40px;border-radius:50%;
  background:var(--chat-surface);border:1px solid var(--chat-border);color:var(--chat-text);
  font-size:17px;display:flex;align-items:center;justify-content:center;
  box-shadow:0 4px 14px rgba(0,0,0,.35);}
.scroll-bottom-btn:active{background:var(--chat-surface2);}

/* Скрепка + поле + эмодзи — один общий "пузырь", как в референсе
   Telegram Web, а не три отдельных элемента с полем посередине. Кнопка
   отправки намеренно снаружи, отдельным цветным кругом — так же, как
   и там. */
.chat-input-pill{flex:1;min-width:0;display:flex;align-items:center;gap:2px;
  border:1px solid var(--chat-border);background:var(--chat-surface2);border-radius:22px;
  padding:0 4px 0 6px;}
.chat-input-pill input{flex:1;min-width:0;padding:11px 4px;border:0;background:transparent;
  color:var(--chat-text);font-size:16px;font-family:"IBM Plex Sans",sans-serif;}
/* > — только кнопка отправки, прямой потомок формы; скрепка/эмодзи
   вложены в .chat-input-pill и это правило их не должно задевать (без
   ">" общий селектор по специфичности перебивал .chat-icon-btn ниже). */
.chat-input > button{width:42px;height:42px;flex-shrink:0;padding:0;font-size:16px;
  border-radius:50%;background:var(--chat-primary);color:#fff;}
/* Скрепка/эмодзи — тонкие монохромные иконки (SVG, currentColor), не
   цветные emoji-глифы: тон = var(--chat-muted), как приглушённые
   контурные иконки в Telegram, не сплошная заливка. */
.chat-icon-btn{width:32px;height:38px;flex-shrink:0;padding:0;background:transparent;border:0;
  color:var(--chat-muted);border-radius:50%;display:flex;align-items:center;justify-content:center;
  -webkit-appearance:none;appearance:none;}
.chat-icon-btn:active{background:rgba(255,255,255,.08);}

/* ---------- панель эмодзи над полем ввода ---------- */
.emoji-picker{position:absolute;left:8px;right:8px;bottom:100%;margin-bottom:6px;
  box-sizing:border-box;z-index:56;background:var(--chat-surface);
  border:1px solid var(--chat-border);border-radius:12px;padding:8px;
  box-shadow:0 -4px 20px rgba(0,0,0,.35);max-height:240px;overflow-y:auto;
  display:grid;grid-template-columns:repeat(8,1fr);gap:2px;}
.emoji-picker button{background:transparent;border:0;font-size:22px;line-height:1;padding:6px 0;
  border-radius:8px;}
.emoji-picker button:active{background:var(--chat-surface2);}

/* ---------- панель множественного выбора (заменяет композер) ---------- */
.select-bar{display:flex;align-items:center;
  gap:10px;background:var(--chat-bg);padding:8px 14px 10px;color:var(--chat-text);}
.select-bar button{background:transparent;border:0;color:var(--chat-text);font-size:18px;padding:4px 6px;}
.select-bar button:disabled{opacity:.35;}
.select-bar #chat-select-count{flex:1;font-size:13.5px;color:var(--chat-muted);}
.select-bar .danger{color:#FF6B6B;}
.chat-input.hidden-by-select{display:none;}

/* ---------- подсветка @упоминаний в тексте сообщения ---------- */
.mention{color:#8FB3FF;font-weight:600;}
.bubble.out .mention{color:#fff;text-decoration:underline;text-decoration-color:rgba(255,255,255,.5);}

/* ---------- автодополнение @упоминаний над полем ввода ---------- */
.mention-menu{position:absolute;left:8px;right:8px;bottom:100%;margin-bottom:6px;
  box-sizing:border-box;z-index:56;background:var(--chat-surface);
  border:1px solid var(--chat-border);border-radius:12px;padding:6px;
  box-shadow:0 -4px 20px rgba(0,0,0,.35);max-height:200px;overflow-y:auto;}
.mention-menu button{display:flex;align-items:center;gap:10px;width:100%;background:transparent;
  border:0;color:var(--chat-text);font-size:14px;padding:8px 8px;border-radius:8px;text-align:left;}
.mention-menu button:active{background:var(--chat-surface2);}
.mention-avatar{width:26px;height:26px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;color:#fff;font-weight:700;font-size:11px;flex-shrink:0;}

/* ---------- скрепка: маленькое меню "Фото или видео / Файл" ---------- */
.attach-menu{position:absolute;left:12px;bottom:100%;margin-bottom:6px;z-index:56;
  background:var(--chat-surface);border:1px solid var(--chat-border);border-radius:12px;
  padding:6px;display:flex;flex-direction:column;box-shadow:0 8px 24px rgba(0,0,0,.4);min-width:190px;}
.attach-menu button{display:flex;align-items:center;gap:10px;background:transparent;border:0;
  color:var(--chat-text);font-size:14px;padding:9px 10px;border-radius:8px;text-align:left;width:100%;}
.attach-menu button:active{background:var(--chat-surface2);}

/* ---------- меню действий сообщения (тап по пузырю) ----------
   Всплывает над всем интерфейсом (аппендится в body, не в ленту) —
   полоса быстрых реакций сверху + список действий снизу, тот же
   визуальный порядок, что и в референсе Telegram Web. */
.msg-menu-backdrop{position:fixed;inset:0;z-index:60;background:rgba(0,0,0,.35);}
.msg-menu-panel{position:fixed;z-index:61;display:flex;flex-direction:column;gap:6px;}
.msg-quick-reactions{display:flex;flex-wrap:wrap;gap:2px;max-width:92vw;justify-content:center;
  background:var(--chat-surface);border:1px solid var(--chat-border);
  border-radius:22px;padding:5px 6px;box-shadow:0 8px 24px rgba(0,0,0,.4);align-self:flex-start;}
.quick-react{width:34px;height:34px;font-size:19px;border-radius:50%;background:transparent;
  padding:0;display:flex;align-items:center;justify-content:center;}
.quick-react:active{background:var(--chat-surface2);}
.msg-context-menu{display:flex;flex-direction:column;background:var(--chat-surface);
  border:1px solid var(--chat-border);border-radius:12px;padding:6px;min-width:190px;
  box-shadow:0 8px 24px rgba(0,0,0,.4);}
.msg-context-menu button{display:block;background:transparent;border:0;color:var(--chat-text);
  font-size:14px;padding:9px 10px;border-radius:8px;text-align:left;width:100%;}
.msg-context-menu button:active{background:var(--chat-surface2);}
.msg-context-menu button.danger{color:#FF6B6B;}

/* ---------- фото/файл в чате ---------- */
/* Превью — по прямому запросу уменьшены в 1.5 раза (было 200/280px,
   max-width 60vw). */
.chat-img-card{position:relative;display:block;width:133px;max-width:40vw;min-height:80px;
  border-radius:10px;overflow:hidden;background:var(--chat-surface2);cursor:pointer;}
.chat-img-card img{width:100%;display:block;max-height:187px;object-fit:cover;}
.chat-img-spinner{display:flex;align-items:center;justify-content:center;min-height:80px;font-size:14px;}
.chat-img-card.loading{opacity:.6;}
/* Клип из скрепки ("Фото или видео") — тот же контейнер, что у фото,
   но video сам управляет своим соотношением сторон (не object-fit,
   иначе элементы управления браузера обрежутся по контейнеру). */
.chat-clip-card{cursor:default;width:147px;}
.chat-clip-card video{width:100%;display:block;max-height:187px;background:#000;}

.chat-file-card{display:flex;align-items:center;gap:9px;background:rgba(255,255,255,.06);
  border-radius:10px;padding:8px 10px;width:220px;max-width:100%;text-align:left;}
.bubble.out .chat-file-card{background:rgba(0,0,0,.15);}
.chat-file-card.loading{opacity:.6;}
.chat-file-icon{font-size:22px;flex-shrink:0;}
.chat-file-info{min-width:0;display:flex;flex-direction:column;gap:1px;}
.chat-file-name{font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.chat-file-size{font-size:11px;color:var(--chat-muted);}

/* ---------- бейдж непрочитанных на кнопке чата ---------- */
.chat-dot{position:absolute;top:4px;right:6px;min-width:15px;height:15px;padding:0 3px;
  background:var(--signal);color:#fff;border-radius:8px;font-family:"JetBrains Mono",monospace;
  font-size:9.5px;font-weight:700;line-height:15px;text-align:center;}

/* ---------- логи ---------- */
.log-box{background:var(--ink);color:#B7C4CE;font-family:"JetBrains Mono",monospace;font-size:11px;
  line-height:1.5;padding:10px;max-height:220px;overflow-y:auto;white-space:pre-wrap;word-break:break-word;}
.log-box .lvl-error{color:#FF8A80;}
.log-box .lvl-warn{color:#E0A93A;}


