/* comp-media.css — медиа в ленте, полноэкранный просмотр, мини-меню вложений, вставка из буфера.

   Часть css/components.css: файл был 107 КБ, и патч, несущий его целиком, вёз всё ради одного
   правила. Подключается из $cssParts в index.php — сразу за самим components.css и ДО
   надстроек-стилей (addons.css, rxmenu.css, convprev.css, scrollcalm.css), которые базу
   перекрывают.

   Рез только ХВОСТОВОЙ, и это не вкусовщина: части грузятся ПОСЛЕ components.css, поэтому
   вырезать секцию из середины значило бы опустить её ниже по каскаду — при равной силе
   селектора она начала бы выигрывать у того, что раньше выигрывало у неё. Здесь части идут
   строго теми же строками и в том же порядке, что в исходнике, поэтому итоговый каскад
   совпадает побайтово. Строки 426-541.
*/
/* ================= МЕДИА (фото/видео/кружки/голосовые/файлы) ================= */

/* Кадр фото/видео/кружка */
.media-frame{position:relative;width:min(280px,100%);max-width:280px;min-width:140px;border-radius:16px;overflow:hidden;background:#0c0d10;line-height:0}
/* Потолок высоты кадра. Раньше его не было вовсе: кадр брал ширину (280 в ленте, 323 на десктопе)
   и считал высоту из пропорций сообщения. Для фотографии с телефона это ещё сходило (3:4 при 280
   даёт 373), а вертикальное ВИДЕО — обычно снятый экран, 9:20 и уже — вырастало до 620px и
   занимало ленту целиком: пролистать один пузырь стоило двух движений.
   Считаем не «сколько отрезать», а «какой ширины кадр вписывается в потолок»: --media-ar (ширина
   делить на высоту, ставит js рядом с aspect-ratio) умноженная на потолок и даёт предельную
   ширину. Кадр остаётся ЦЕЛЫМ — ни обрезки, ни чёрных полей: он просто уже. Для 9:20 это 198×440
   вместо 280×622.
   Ограничение через max-width, а не height, нарочно: базовую ширину задаёт каждый свой файл
   (280 здесь, 323 в tgsize.css для десктопа), и width:min(...) сам возьмёт меньшее из двух —
   потолок вмешивается только там, где кадр реально высокий, и не спорит с раскладкой.
   Потолок 440px выбран так, чтобы НЕ переделывать то, что и раньше выглядело нормально: обычный
   портрет 3:4 в него укладывается целиком на обеих раскладках (280×373 и 323×431), и потолок
   вмешивается только начиная с 2:3 и уже — там, где кадр и правда съедал пол-ленты.
   99 в var() — «пропорции неизвестны» (кадр без размеров, пока грузится превью): 440×99 больше
   любого экрана, то есть потолок молчит, пока не станет что ограничивать.
   Только ОДИНОЧНЫЙ кадр (.mcontent > .media-frame): у клеток коллажа своя геометрия (квадрат,
   width:100%), и потолок сломал бы сетку. Кружок исключён по той же причине — у него свой размер
   и aspect-ratio 1/1. */
#messages .mcontent > .media-frame:not(.round){max-width:calc(var(--media-maxh, 440px) * var(--media-ar, 99))}
/* На телефоне «огромный кадр» — это не столько пиксели, сколько ДОЛЯ экрана: 440px на телефоне с
   800px полотна — больше половины ленты, и пузырь всё равно читается как экран, хотя на десктопе
   те же 440 выглядят нормально. Поэтому там потолок меряется экраном: 42% его высоты. Кадр
   занимает предсказуемую часть ленты на любом телефоне, а не на том, по которому подбирали число.
   Единицы парой, как у полноэкранного листа настроек в layout.css: сначала vh для движков без
   svh, затем svh — он считается по полотну с РАЗВЁРНУТЫМИ панелями браузера и, в отличие от dvh,
   не меняется, когда панели прячутся при листании; кадру, у которого от этого числа зависит
   ширина, менять размеры на ходу нельзя.
   Порог по pointer:coarse, а не по ширине окна: правило проекта — телефон в режиме «версия для
   ПК» о ширине врёт, а про палец отвечает честно. */
@media (pointer:coarse){
  #messages .mcontent > .media-frame:not(.round){--media-maxh:min(440px, 42vh)}
  #messages .mcontent > .media-frame:not(.round){--media-maxh:min(440px, 42svh)}
}
.media-frame:not([style*="aspect-ratio"]){min-height:150px}
.mmine .media-frame{border-bottom-right-radius:6px}
.mthem .media-frame{border-bottom-left-radius:6px}
/* Рамка кадра в цвет пузыря отправителя (задумка #195): свои — цветом исходящего пузыря, чужие —
   цветом входящего. Кадр в ленте лежит без пузыря вовсе, и на пёстрых обоях у него не было
   границы — фотография просто начиналась. Рамка её и рисует, и заодно связывает кадр с подписью:
   у подписи (#151) фон ровно этот же цвет, поэтому шов между ними не читается — блок выглядит
   одним куском.
   Своим рамку красит --accent, а НЕ --bubble-out, и это не небрежность: --bubble-out — это
   linear-gradient (tokens.css), а градиент цветом границы быть не может. `border:2px solid
   var(--bubble-out)` — объявление недопустимое целиком, браузер молча выбрасывает его, и рамки
   нет вовсе. Проверено на живом клиенте. Градиент пузыря и так идёт ОТ подмешанного белым
   акцента К самому акценту, то есть --accent — его же цвет, только без перехода; у тёмной темы
   ниже своя строка, потому что там пузырь темнее акцента.
   Коллажу это не мешает: там цвет уезжает в background (comp-bots.css), а фон градиент принимает.
   Только у ОДИНОЧНОГО кадра — `.mcontent > .media-frame`: у клеток коллажа своя рамка была бы
   двойной (у коллажа она общая, см. .album-grid в comp-bots.css), а они лежат внутри .album-cell
   и под этот селектор не попадают.
   Кружок (.round) намеренно не трогаем: он не «картинка в рамке», а свой силуэт, и цветное
   кольцо превратило бы его в аватарку.
   Про геометрию. box-sizing:border-box стоит на всём (tokens.css), поэтому рамка съедает 2px
   внутрь, а не раздувает кадр: ширина 280px, соотношение сторон и место в ряду остаются прежними.
   clip-path из addons.css (#150) считается по border-box — рамка попадает под ту же скруглённую
   обрезку, что и сам кадр, ничего дорисовывать там не нужно. */
.mmine .mcontent > .media-frame:not(.round){border:2px solid var(--accent)}
.mthem .mcontent > .media-frame:not(.round){border:2px solid var(--bubble-in)}
body.dark .mmine .mcontent > .media-frame:not(.round){border-color:color-mix(in oklch, var(--accent), black 19%)}
.media-frame.round{width:200px;max-width:60vw;height:200px;min-width:0;min-height:0;border-radius:50%!important;aspect-ratio:1/1!important}
.media-blur{position:absolute;inset:0;background-size:cover;background-position:center;filter:blur(14px);transform:scale(1.15);transition:opacity .25s;z-index:1}
.media-blur.dark{background:linear-gradient(135deg,#22262c,#14171b)}
.media-img,.media-vid{position:relative;z-index:2;width:100%;height:100%;object-fit:cover;display:block;transition:opacity .25s}
.media-frame.round .media-img,.media-frame.round .media-vid{border-radius:50%}
.media-frame.clickable{cursor:pointer}
.media-overlay{position:absolute;inset:0;z-index:3;display:flex;align-items:center;justify-content:center;pointer-events:none}
.media-overlay>*{pointer-events:auto}
/* Три подписи поверх кадра: длительность, размер и время отправки. Геометрия у них ОБЩАЯ и живёт
   одним правилом — порознь они разъезжаются, что и случилось: .media-frame задаёт line-height:0
   (он нужен, чтобы под <video> не было зазора), время отправки перекрывало его своим значением,
   а длительность и размер наследовали ноль. Плашка выходила 4px высотой, текст торчал из неё,
   и три подписи смотрелись по-разному.
   line-height:1 = ровно кегль, без полуинтерлиньяжа: тогда вертикальный отступ текста равен padding.
   Смещения подобраны так, чтобы равноудалён от краёв был ТЕКСТ, а не плашка:
   по горизонтали 4+8 = 12px, по вертикали 9+3 = 12px. */
.media-dur,.media-size,.media-time{position:absolute;z-index:4;padding:3px 8px;border-radius:11px;background:rgba(0,0,0,.42);color:#fff;font-size:11px;line-height:1;backdrop-filter:blur(6px)}
.media-dur{left:4px;top:9px}
.media-size{left:4px;bottom:9px}
.media-time{right:4px;bottom:9px;display:flex;align-items:center;gap:4px}
.media-time .ck{display:flex;align-items:center}
.media-caption{margin-top:5px;font-size:14.5px;line-height:1.4;white-space:pre-wrap;word-break:break-word;color:var(--text)}
.mmine .media-caption{color:var(--text)}

/* Кнопка-кольцо (заливка/скачивание/отмена/повтор) */
.ring-btn{position:relative;width:54px;height:54px;border:none;border-radius:50%;background:rgba(0,0,0,.5);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}
.ring-btn.small{width:44px;height:44px}
.ring-btn:hover{background:rgba(0,0,0,.62)}
.ring-svg{position:absolute;inset:0;margin:auto;transform:rotate(-90deg)}
.ring-track{fill:none;stroke:rgba(255,255,255,.28);stroke-width:3}
.ring-prog{fill:none;stroke:#fff;stroke-width:3;stroke-linecap:round;transition:stroke-dashoffset .18s linear}
.ring-ic{position:relative;z-index:1;display:flex;align-items:center;justify-content:center;color:#fff}
.ring-svg.ring-spin{animation:spin 1s linear infinite}
/* Процент — под кольцом, по центру кадра. Раньше он стоял внизу по центру и на узком экране
   наезжал на время отправки (оно в правом нижнем углу) и на размер (в левом нижнем).
   Под кольцом угловые плашки ему не помеха при любой ширине. */
.media-prog-label{position:absolute;z-index:4;left:50%;top:50%;transform:translate(-50%,32px);font-size:11px;line-height:1;color:#fff;background:rgba(0,0,0,.4);padding:3px 8px;border-radius:9px;white-space:nowrap}

.play-btn{width:56px;height:56px;border:none;border-radius:50%;background:rgba(0,0,0,.5);color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center}
.play-btn:hover{background:rgba(0,0,0,.62)}
.play-btn svg{margin-left:2px}

/* Голосовое сообщение */
.voicebubble{display:inline-block;min-width:200px}
.voicebubble.out{background:var(--bubble-out);color:#fff}
.voicebubble.in{background:var(--bubble-in);color:var(--text)}
.voice-player{display:flex;align-items:center;gap:10px}
.voice-ctrl{width:40px;height:40px;flex-shrink:0;border:none;border-radius:50%;cursor:pointer;display:flex;align-items:center;justify-content:center;background:rgba(255,255,255,.22);color:#fff;position:relative}
.voicebubble.in .voice-ctrl{background:var(--accent);color:#fff}
.voice-ctrl.loading .ring-track{stroke:rgba(255,255,255,.35)}
.voice-ctrl .ring-svg{width:40px;height:40px}
/* #104: floor ужат 120→72, иначе кнопка скорости (flex-shrink:0) вылезала за пузырь на узком экране; на десктопе meta всё равно flex:1 и растёт */
.voice-meta{flex:1;min-width:72px}
.voice-bar{height:4px;border-radius:2px;background:rgba(255,255,255,.3);overflow:hidden}
.voicebubble.in .voice-bar{background:var(--hover)}
.voice-bar i{display:block;height:100%;width:0;background:#fff;border-radius:2px}
.voicebubble.in .voice-bar i{background:var(--accent)}
.voice-time{font-size:11.5px;margin-top:5px;opacity:.85}
/* кольцо заливки в пузыре голосового/файла */
.voice-ring,.file-ring,.fc-ring{position:relative;width:44px;height:44px;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.voice-ring .ring-btn,.file-ring .ring-btn,.fc-ring .ring-btn{background:var(--accent)}

/* Карточка файла: кольцо/иконка слева */
.filecard.clickable{cursor:pointer}
.fc-ring .ring-btn.small{width:44px;height:44px}
.mthem .fc-ring .ring-btn{background:var(--accent)}

/* ============ Полноэкранный просмотр ============ */
#lightbox{position:fixed;inset:0;z-index:80;display:none;align-items:center;justify-content:center;background:rgba(0,0,0,.94)}
#lightbox.open{display:flex;animation:popIn .16s ease}
#lightbox .lb-body{display:flex;align-items:center;justify-content:center;width:100%;height:100%;padding:24px}
.lb-img{max-width:96vw;max-height:92vh;object-fit:contain;border-radius:8px}
.lb-vid{max-width:96vw;max-height:92vh;border-radius:8px;background:#000}
.lb-close{position:fixed;top:14px;right:16px;z-index:81;width:44px;height:44px;border:none;border-radius:50%;background:rgba(255,255,255,.14);color:#fff;font-size:20px;cursor:pointer}
.lb-close:hover{background:rgba(255,255,255,.24)}
body.lb-lock{overflow:hidden}
.lb-nav{position:fixed;top:50%;transform:translateY(-50%);z-index:81;width:46px;height:46px;border:none;border-radius:50%;background:rgba(255,255,255,.10);color:#fff;font-size:30px;line-height:1;cursor:pointer;display:none;align-items:center;justify-content:center;user-select:none;-webkit-user-select:none;transition:background .12s}
.lb-nav:hover{background:rgba(255,255,255,.22)}
.lb-prev{left:12px}
.lb-next{right:12px}
.lb-counter{position:fixed;top:18px;left:50%;transform:translateX(-50%);z-index:81;color:rgba(255,255,255,.72);font-size:13px;font-weight:600;letter-spacing:.04em;display:none;pointer-events:none}
@media (max-width:600px){.lb-nav{width:40px;height:40px;font-size:26px;background:rgba(255,255,255,.08)}}

/* ============ Мини-меню вложений ============ */
#attach-menu{display:none;position:absolute;right:12px;bottom:74px;z-index:22;background:var(--panel2);backdrop-filter:blur(var(--blur)) saturate(1.4);-webkit-backdrop-filter:blur(var(--blur)) saturate(1.4);border:1px solid var(--border);border-radius:16px;box-shadow:0 16px 40px rgba(0,0,0,.24);padding:6px;min-width:200px}
#attach-menu.open{display:block;animation:popIn .16s ease}
.attach-item{display:flex;align-items:center;gap:12px;width:100%;padding:11px 12px;border:none;background:transparent;border-radius:11px;cursor:pointer;font-size:14.5px;color:var(--text);text-align:left}
.attach-item:hover{background:var(--accent-soft)}
.attach-item .ai-ic{width:22px;height:22px;display:flex;align-items:center;justify-content:center;color:var(--accent);flex-shrink:0}
@media(max-width:760px){#attach-menu{right:9px;bottom:80px}}

/* ---- Вставка из буфера (Ctrl+V, задумки #34/#38) ----
   Лист «Отправить изображение»: превью того, что легло в буфер, поле подписи, Отправить/Отмена.
   Одна картинка — во всю ширину листа (как в Telegram), несколько — плитками; не-картинки
   (файл, скопированный в проводнике) — строкой с именем и размером. ✕ на каждом элементе —
   повторный Ctrl+V докладывает в тот же лист, и лишнее должно убираться без полного «Отмена». */
/* Лист «Отправить изображение». Три правки по живой проверке владельца.

   (1) ВЫСОТА ПРЕВЬЮ ИЗВЕСТНА ЗАРАНЕЕ. Было max-height:38vh при height:auto — то есть высота
   картинки выяснялась только после её декодирования, и лист на глазах подпрыгивал: сначала он
   собран по пустому месту, потом в него встаёт кадр. Теперь высота задана (26vh), а вписывается
   кадр по object-fit:contain — лист собран правильно с первого кадра, до всякой картинки.
   (2) НИЖЕ РОСТОМ. 46vh под галерею плюс подпись и кнопки занимали почти весь экран; 26vh хватает,
   чтобы узнать кадр, и оставляет лист листом, а не вторым экраном.
   (3) ПОЯВЛЕНИЕ ЧАСТЯМИ. Лист приезжает своим popIn, а его части — заголовок, превью, подпись,
   кнопки — коротко проступают друг за другом. Задержки чистым css, через nth-child: анимация
   одноразовая и класс снимать не нужно, поэтому и перезапускать нечего (то самое правило про
   класс, подменяющий animation, тут просто не возникает).
   Про «many» (три и больше кадров) высота не меняется: там своя сетка с квадратными плитками. */
#paste-previews{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;max-height:30vh;overflow-y:auto}
/* И здесь полоса мелькает: превью вставляются пачкой, высота галереи в этот момент меняется, и
   браузер показывает указатель прокрутки на долю секунды — при одном-двух кадрах, где крутить
   нечего вовсе. Прокрутка остаётся (три и больше вложений в неё упираются), скрыт только указатель. */
#paste-previews{scrollbar-width:none;-ms-overflow-style:none}
#paste-previews::-webkit-scrollbar{width:0;height:0;display:none}
.paste-img{position:relative;border-radius:14px;overflow:hidden;background:#0c0d10;line-height:0;max-width:100%}
.paste-img img{display:block;max-width:100%;width:auto;height:26vh;object-fit:contain}
#paste-previews.many .paste-img{width:calc(33.33% - 6px)}
#paste-previews.many .paste-img img{width:100%;height:96px;object-fit:cover}
.paste-file{position:relative;display:flex;align-items:center;width:100%;padding:10px 40px 10px 12px;border:1px solid var(--border);border-radius:12px;background:var(--panel)}
.paste-file .pf-meta{min-width:0}
.paste-file .pf-name{font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.paste-file .pf-size{font-size:12px;color:var(--text2);margin-top:2px}
.paste-x{position:absolute;top:6px;right:6px;width:24px;height:24px;border:none;border-radius:50%;background:rgba(0,0,0,.55);color:#fff;font-size:12px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}
.paste-x:hover{background:rgba(0,0,0,.75)}
.paste-file .paste-x{top:50%;transform:translateY(-50%)}

/* Появление частей листа. Короткое и одинаковое для всех — здесь не место разнообразию: человек
   пришёл посмотреть на кадр и нажать «Отправить», а не любоваться движением. Полкадра сдвига и
   проявление, очередь сверху вниз с шагом 45мс; сами кадры внутри галереи идут своей очередью,
   поэтому два-три вложения проступают один за другим, а не пачкой.
   prefers-reduced-motion гасит всё — лист просто появляется. */
@keyframes pasteIn{ from{ opacity:0; transform:translateY(9px) } to{ opacity:1; transform:none } }
#paste-modal .modal-sheet > *{ animation:pasteIn .24s cubic-bezier(.22,.9,.28,1) both }
#paste-modal .modal-sheet > *:nth-child(1){ animation-delay:.03s }
#paste-modal .modal-sheet > *:nth-child(2){ animation-delay:.08s }
#paste-modal .modal-sheet > *:nth-child(3){ animation-delay:.13s }
#paste-modal .modal-sheet > *:nth-child(4){ animation-delay:.18s }
#paste-previews > *{ animation:pasteIn .22s cubic-bezier(.22,.9,.28,1) both }
#paste-previews > *:nth-child(1){ animation-delay:.10s }
#paste-previews > *:nth-child(2){ animation-delay:.15s }
#paste-previews > *:nth-child(3){ animation-delay:.20s }
#paste-previews > *:nth-child(n+4){ animation-delay:.24s }
@media (prefers-reduced-motion: reduce){
  #paste-modal .modal-sheet > *,
  #paste-previews > *{ animation:none }
}
