Files
SHiNE-server/shine-UI/styles/features/messages.css
T
qandClaude Opus 5.5 f8900e531a UI: новый общий стиль, тёмная/светлая тема, настраиваемая палитра
- styles/main.css: роли цветов (по умолчанию «Индиго»), шкала отступов/скруглений/шрифтов,
  цвета отношений для обеих тем; жёсткие цвета в стилях заменены на роли.
- Палитра: пресеты и личные правки, «Оформление» Авто/День/Ночь, долгое нажатие —
  редактор цветов с экспортом/импортом.
- Каналы: пузыри постов автора, плашки дней, строка «Написать в канал…», «О канале»,
  создание канала с адресом из названия; лента открывается на свежих постах.
- Чаты: плоский список, чипы-фильтры, пузыри, плашки дней; нижняя панель скрыта в переписке.
- Корневые разделы — единая шапка; профиль и чужой профиль — общая карточка;
  настройки, кошелёк, сеансы — меню-списки.
- Нижняя панель: иконки без подписей, бейджи на иконках.
- confirmDialog вместо window.confirm/alert; на телефоне диалоги — шторки снизу.
- docs/UI-Design/ISSUES-for-dev.md — найденные ошибки сервера/UI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:05:26 +03:00

772 lines
21 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Поиск контактов относится к feature «Личные/Контакты». */
.contact-search-actions {
display: grid;
grid-template-columns: 1fr;
gap: 8px;
}
.contact-search-form-card,
.contact-search-results-card {
margin: 0 6px;
padding: 14px;
border-radius: 24px;
background: var(--surface);
border: 1px solid var(--border-subtle);
box-shadow: var(--shadow-sm);
}
.contact-search-input {
border-radius: 16px;
}
.contact-search-results-title {
font-size: 14px;
font-weight: 700;
color: var(--text-secondary);
text-align: center;
}
.contact-search-result-main {
min-width: 0;
display: flex;
align-items: center;
}
/* Personal messages list and DM-list styles. */
/* ===== Direct Messages Glass Theme (DM-only) ===== */
.dm-screen {
position: relative;
isolation: isolate;
color: var(--text-primary);
min-height: 100%;
align-content: start;
}
.screen-content .dm-screen {
min-height: 100%;
}
@keyframes dm-orbs-drift {
from { transform: translate3d(0, 0, 0) scale(1); }
to { transform: translate3d(0, -8px, 0) scale(1.02); }
}
.dm-dialog-card {
position: relative;
display: grid;
grid-template-columns: 60px minmax(0, 1fr) auto;
gap: 12px;
align-items: center;
min-height: 74px;
padding: 10px 12px 10px 10px;
border-radius: 26px;
background: var(--surface);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid color-mix(in srgb, var(--rel-contact) 32%, transparent); /* оконтовка = цвет линии связи; default = violet (контакт) */
box-shadow: none;
cursor: pointer;
}
.dm-dialog-card:focus-visible { outline: 2px solid var(--rel-link); outline-offset: 2px; }
.dm-card--family { border-color: transparent; }
/* линия связи: gold (семья) */
.dm-card--shining { border-color: color-mix(in srgb, var(--rel-shining) 45%, transparent); }
/* линия связи: cyan (сияющий) */
.dm-screen .list-item .avatar {
width: 40px;
height: 40px;
min-width: 40px;
min-height: 40px;
}
.dm-screen .list-item {
align-items: stretch;
}
.dm-screen .meta-muted {
color: var(--text-secondary);
}
/* ===== «Личные сообщения» v2 — списочная форма «Связей» ===== */
/* Токены-мост: НЕ придумываем цвета, наследуем канонический язык «Связей» (network-graph.css :root). */
.dm-screen {
--dm-tone-default: var(--rel-contact);
--dm-tone-family: var(--rel-family);
--dm-tone-shining: var(--rel-shining);
}
/* DM-шапка через grid 1fr auto 1fr: бренд слева, title строго по центру, «+» справа. */
.dm-head-brand { display: flex; align-items: center; gap: 8px; min-width: 0; }
.dm-head-logo-wrap { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; flex: 0 0 auto; }
.dm-head-logo {
width: 36px;
height: 36px;
object-fit: contain;
display: block;
filter: drop-shadow(0 0 7px color-mix(in srgb, var(--rel-shining) 38%, transparent));
}
/* Центр шапки — светящийся бренд «Shine» */
@keyframes dm-shine-pulse {
0%, 100% { text-shadow: 0 0 5px color-mix(in srgb, var(--rel-family) 42%, transparent), 0 0 12px color-mix(in srgb, var(--rel-family) 26%, transparent); }
50% { text-shadow: 0 0 9px color-mix(in srgb, var(--rel-family) 68%, transparent), 0 0 20px color-mix(in srgb, var(--rel-family) 46%, transparent); }
}
.dm-divider { position: relative; height: 18px; margin: 6px 14px 8px; }
.dm-divider::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--rel-family) 50%, transparent), transparent); }
.dm-divider::after { content: ""; position: absolute; left: 50%; top: 50%; width: 6px; height: 6px; transform: translate(-50%, -50%) rotate(45deg); background: var(--rel-family); box-shadow: 0 0 8px var(--rel-family-glow); }
/* список: скролл внутри контента, карточки не ужимаем, отступ снизу под bottom nav (86px) + 16px */
.dm-list { display: flex; flex-direction: column; gap: 8px; padding: 0 6px; padding-bottom: calc(86px + 16px); }
/* текст карточки */
.dm-row-main { min-width: 0; }
.dm-row-titleline { display: flex; align-items: center; gap: 6px; min-width: 0; }
.dm-row-titlewrap { flex-wrap: wrap; row-gap: 6px; }
.dm-dialog-card .dm-row-title { font-size: 16px; font-weight: 600; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dm-dialog-card .dm-row-last-message { font-size: 14px; color: var(--text-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dm-contact-note {
display: inline-flex;
align-items: center;
min-height: 22px;
padding: 0 8px;
border-radius: 999px;
border: 1px solid var(--border-subtle);
background: var(--surface-selected);
color: var(--text-secondary);
font-size: 11px;
font-weight: 600;
white-space: nowrap;
}
/* галочка-подтверждён у имени (золотая, без слова «Подтверждён») */
.dm-name-check { display: inline-flex; flex: 0 0 auto; color: var(--rel-family); }
.dm-name-check svg { width: 16px; height: 16px; }
/* AvatarRing — обод/свечение по тону (адаптация орбов «Связей», без тяжёлой магии) */
.dm-av { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; position: relative; }
.dm-av .avatar { width: 40px; height: 40px; min-width: 40px; min-height: 40px; border: none; box-shadow: none; }
/* Цветные обводки вокруг аватаров (violet/gold) убраны по просьбе. Свечение оставляем только у сияющих (ниже). */
.dm-av--default { box-shadow: none; }
.dm-av--family { box-shadow: none; }
/* Сияющий аватар = АДАПТАЦИЯ сияющего узла экрана «Связи»: та же небесная палитра, тот же небесный rim,
тот же двойной «дышащий» пульс. Переиспользуем ОБЩИЕ keyframes графа (fg-shine-glow — пульс box-shadow,
fg-shine-halo — дыхание радиального ореола; объявлены в network-graph.css, грузится глобально), а не рисуем
второй похожий эффект. Радиальный ореол повторяет стопы узла графа; SVG-фильтр #fg-shine-glow есть только на
стр. «Связи», поэтому здесь мягкий CSS-blur. Мини-сфера компактная — не размывает текст/соседей. */
.dm-av--shining {
border: 1px solid color-mix(in srgb, var(--rel-shining) 62%, transparent);
animation: fg-shine-glow 3.6s ease-in-out infinite;
}
.dm-av--shining::before {
content: ""; position: absolute; inset: -12px; border-radius: 50%; z-index: -1; pointer-events: none;
background: radial-gradient(circle, color-mix(in srgb, var(--rel-shining) 50%, transparent) 0%, color-mix(in srgb, var(--rel-shining) 18%, transparent) 46%, transparent 72%);
filter: blur(3.4px); /* = stdDeviation 3.4 SVG-фильтра #fg-shine-glow графа; геометрия inset −12px тоже как у узла (58px↔56px, scale≈1) */
animation: fg-shine-halo 3.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
.dm-av--shining { animation: none; }
.dm-av--shining::before { animation: none; }
}
.dm-row-meta-col {
display: inline-flex;
min-width: 0;
align-self: stretch;
flex-direction: column;
align-items: flex-end;
justify-content: space-between;
gap: 4px;
}
.dm-row-meta-line {
display: inline-flex;
align-items: center;
gap: 6px;
min-height: 24px;
}
.dm-row-meta-spacer {
width: 24px;
height: 24px;
}
.dm-row-time {
font-size: 12px;
font-weight: 600;
color: var(--text-secondary);
}
.dm-row-time--empty {
width: 0;
min-width: 0;
overflow: hidden;
}
/* непрочитанные — отдельная violet-сфера (НЕ изумруд) */
.dm-unread-badge {
min-width: 24px; height: 24px; padding: 0 7px; border-radius: 12px;
display: inline-flex; align-items: center; justify-content: center;
font-size: 12px; font-weight: 700; color: var(--text);
color: var(--on-accent); background: var(--accent); border: 0;
}
.dm-chevron { display: inline-flex; color: var(--text-secondary); }
.dm-chevron svg { width: 16px; height: 16px; }
@media (max-width: 380px) {
.dm-dialog-card {
grid-template-columns: 60px minmax(0, 1fr);
row-gap: 10px;
}
.dm-row-meta-col {
grid-column: 2;
justify-self: end;
}
}
/* Значок «связь через кого» — ТОЛЬКО иконка (кликабельная); детали пути в попапе ниже */
.dm-via {
display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
width: 24px; height: 24px; padding: 0; border-radius: 8px; cursor: pointer;
color: var(--rel-link); border: 1px solid color-mix(in srgb, var(--rel-link) 50%, transparent); background: color-mix(in srgb, var(--rel-link) 8%, transparent);
}
.dm-via-icon { display: inline-flex; }
.dm-via-icon svg { width: 14px; height: 14px; }
/* попап пути связи: Ты → …посредники… → он; узлы = аватар+имя, кликабельные → профиль */
.dm-via-path {
display: none; position: absolute; left: 14px; right: 14px; top: 46px; z-index: 6;
flex-wrap: wrap; align-items: center; gap: 6px; padding: 9px 11px; border-radius: 12px;
background: var(--surface); border: 1px solid color-mix(in srgb, var(--rel-link) 35%, transparent);
box-shadow: var(--shadow);
}
.dm-via-path.is-open { display: flex; }
.dm-via-node {
display: inline-flex; align-items: center; gap: 5px; padding: 3px 7px 3px 4px; border-radius: 11px;
background: var(--surface); border: 1px solid var(--border-subtle);
color: var(--text); font-size: 12px; cursor: default;
}
button.dm-via-node { cursor: pointer; }
button.dm-via-node:hover { border-color: color-mix(in srgb, var(--rel-link) 50%, transparent); }
.dm-via-node-ava { width: 20px; height: 20px; border-radius: 50%; overflow: hidden; flex: 0 0 auto; }
.dm-via-node-ava .avatar { width: 20px; height: 20px; min-width: 20px; min-height: 20px; border: none; box-shadow: none; }
.dm-via-node-ava .avatar-fallback { font-size: 9px; font-weight: 700; }
.dm-via-me { display: grid; place-items: center; width: 20px; height: 20px; border-radius: 50%; background: var(--rel-family); color: var(--background); font-size: 10px; font-weight: 700; }
.dm-via-node-name { white-space: nowrap; }
.dm-via-arrow { font-size: 12px; color: var(--rel-link); }
.screen-content:has(> .dm-screen) {
scrollbar-width: none;
-ms-overflow-style: none;
}
.screen-content:has(> .dm-screen)::-webkit-scrollbar {
width: 0;
height: 0;
display: none;
}
.dm-history-loader {
position: sticky;
top: 0;
z-index: 3;
display: flex;
justify-content: center;
pointer-events: none;
margin-bottom: -4px;
opacity: 0;
transform: translateY(-8px);
transition: opacity 160ms ease, transform 160ms ease;
}
.dm-history-loader[hidden] {
display: none;
}
.dm-history-loader.is-visible {
opacity: 1;
transform: translateY(0);
}
.dm-history-loader__pill {
display: inline-flex;
align-items: center;
gap: 10px;
min-height: 34px;
padding: 7px 14px;
border-radius: 999px;
border: 1px solid transparent;
background: var(--surface);
color: var(--text-primary);
box-shadow: var(--shadow-sm);
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
}
.dm-history-loader__label {
font-size: 12px;
font-weight: 600;
letter-spacing: 0.02em;
}
.dm-history-loader__spinner {
width: 16px;
height: 16px;
border-radius: 50%;
border: 2px solid transparent;
border-top-color: transparent;
box-shadow: none;
animation: dm-history-loader-spin 0.85s linear infinite;
}
@keyframes dm-history-loader-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.dm-actions-col {
position: relative;
display: grid;
grid-template-columns: repeat(2, 46px);
grid-template-rows: 46px;
grid-template-areas: "emoji send";
gap: 6px;
align-self: end;
}
.dm-screen .input {
background: var(--surface);
border: 1px solid transparent;
border-radius: 14px;
color: var(--text-primary);
}
.dm-floating-menu-layer {
position: fixed;
inset: 0;
z-index: 120;
pointer-events: none;
}
.dm-confirm-check {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 10px 12px;
border-radius: 14px;
background: var(--surface);
border: 1px solid var(--border-subtle);
color: var(--text-primary);
font-size: 14px;
}
.dm-confirm-check input {
margin-top: 2px;
}
/* ===== Empty states alignment + transparent wrappers cleanup ===== */
.dm-screen::before {
position: absolute;
inset: -12px -12px 0;
z-index: -1;
pointer-events: none;
background: none;
animation: dm-orbs-drift 16s ease-in-out infinite alternate;
content: none;
}
.dm-screen .dm-list > .card.meta-muted {
margin: 0 20px;
padding: 14px 16px;
border-radius: 14px;
background: var(--surface);
backdrop-filter: blur(25px);
-webkit-backdrop-filter: blur(25px);
border: 1px solid transparent;
color: var(--text-secondary);
box-shadow: none;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
width: calc(100% - 40px);
}
/* «Личные»: вместо жёлтого шестиугольника — текущий аватар пользователя. */
/* Список личных чатов: без цветной границы карточки, компактная ава как в шапке
* самого чата, а дата/время стоит на строке превью. */
.dm-list-screen .dm-card--family,
.dm-list-screen .dm-card--shining {
border: 0;
}
.dm-list-screen .dm-av {
width: 60px;
height: 60px;
min-width: 60px;
min-height: 60px;
}
.dm-list-screen .dm-av .avatar,
.dm-list-screen .list-item .avatar {
width: 56px;
height: 56px;
min-width: 56px;
min-height: 56px;
font-size: 18px;
border: 0;
box-shadow: none;
}
.dm-list-screen .dm-row-main {
display: grid;
grid-template-rows: 22px 20px;
align-items: center;
gap: 0;
min-height: 42px;
}
.dm-list-screen .dm-row-titlewrap {
flex-wrap: nowrap;
min-height: 22px;
overflow: hidden;
}
.dm-list-screen .dm-row-last-message {
align-self: center;
line-height: 20px;
}
.dm-list-screen .dm-unread-badge,
.dm-list-screen .dm-row-meta-spacer {
grid-row: 1;
align-self: center;
}
.dm-list-screen .dm-row-time {
grid-row: 2;
align-self: center;
line-height: 20px;
white-space: nowrap;
}
.dm-list-screen .dm-row-meta-line {
display: contents;
}
.dm-list-screen .dm-chevron {
display: none;
}
@media (max-width: 380px) {
.dm-list-screen .dm-dialog-card {
grid-template-columns: 60px minmax(0, 1fr) auto;
}
.dm-list-screen .dm-row-meta-col {
grid-column: 3;
justify-self: end;
}
}
/* ===== DM + Channels polish (2026-08-22 13:22) ===== */
/* «Личные»: аватар основной вкладки стоит ровно на той же горизонтальной позиции,
* что и аватар собеседника в открытом чате: после 40px back-slot + 8px gap. */
/* ===== DM avatar + channel row visual alignment fix (2026-08-22 13:29) ===== */
/* Шапка «Личных» переносится в topbar-slot отдельно от .dm-list-screen,
* поэтому позиционируем аватар по реальной DOM-структуре. 48px = back 40px + gap 8px
* в открытом чате, что даёт одинаковую абсолютную X-позицию. */
/* «Контакты»: верхняя аватарка убрана полностью. Пустая левая колонка сохраняет
* строгий центр заголовка относительно правого overflow-меню. */
.topbar-slot .dm-head-brand {
margin-left: 0;
min-width: 40px;
width: 40px;
height: 40px;
}
.dm-menu-icon,
.dm-menu-image-icon {
width: 18px;
height: 18px;
min-width: 18px;
flex: 0 0 18px;
object-fit: contain;
color: var(--accent);
}
.dm-user-identity-menu {
width: 196px;
}
.dm-user-menu-layer {
pointer-events: auto;
}
.dm-actions-col {
grid-template-columns: repeat(2, 43px);
grid-template-rows: 46px;
gap: 2px;
}
/* Loader не имеет права участвовать в растяжении пустого flex-контейнера. */
.dm-history-loader {
flex: 0 0 34px;
align-self: center;
width: max-content;
max-width: calc(100% - 24px);
height: 34px;
min-height: 34px;
max-height: 34px;
top: calc(var(--topbar-height, 64px) + 8px);
margin: 0 auto -4px;
overflow: visible;
}
.dm-history-loader__pill {
flex: 0 0 auto;
width: max-content;
max-width: 100%;
height: 34px;
}
/* «Личные»: широкие, низкие и более плотные плитки. */
.dm-list-screen .dm-list {
width: 100%;
margin-inline: 0;
gap: 4px;
}
.dm-list-screen .dm-dialog-card {
border: 0;
box-shadow: none;
background: var(--surface);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
grid-template-columns: 50px minmax(0, 1fr) auto;
min-height: 54px;
margin: 0;
padding: 5px 6px 5px 4px;
gap: 8px;
border-radius: 15px;
}
.dm-list-screen .dm-av,
.dm-list-screen .dm-av .avatar,
.dm-list-screen .list-item .avatar {
width: 48px;
height: 48px;
min-width: 48px;
min-height: 48px;
}
.dm-list-screen .dm-row-main {
min-height: 40px;
}
.dm-list-screen .dm-row-meta-col {
display: grid;
grid-template-rows: 22px 20px;
align-items: center;
gap: 0;
align-self: center;
justify-items: end;
justify-content: initial;
min-height: 40px;
}
@media (max-width: 380px) {
.dm-list-screen .dm-dialog-card {
grid-template-columns: 50px minmax(0, 1fr) auto;
}
}
.dm-head-filter-title {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
cursor: pointer;
}
.dm-head-filter-title::after {
content: "⌄";
font-size: 13px;
line-height: 1;
opacity: 0.72;
transform: translateY(-1px);
}
/* ===== Personal chat row layout: time top-right, unread bottom-right ===== */
.dm-list-screen .dm-row-time {
grid-row: 1;
align-self: center;
}
.dm-list-screen .dm-unread-badge,
.dm-list-screen .dm-row-meta-spacer {
grid-row: 2;
align-self: center;
}
.dm-list { gap: 0; margin-inline: 0; padding: 0; padding-bottom: calc(86px + 16px); }
.dm-list-screen .dm-dialog-card,
.dm-dialog-card {
min-height: 68px;
margin: 0;
padding: 10px 0;
gap: 12px;
grid-template-columns: 48px minmax(0, 1fr) auto;
border: 0;
border-radius: 0;
background: linear-gradient(var(--border-subtle), var(--border-subtle)) right bottom / calc(100% - 60px) 1px no-repeat;
backdrop-filter: none;
-webkit-backdrop-filter: none;
transition: background-color var(--duration-fast) ease;
}
.dm-dialog-card:hover { background-color: color-mix(in srgb, var(--surface) 66%, transparent); }
.dm-dialog-card:active { background-color: var(--surface-selected); }
.dm-dialog-card:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: -2px; }
.dm-card--family .dm-av .avatar { box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--rel-family); }
.dm-card--shining .dm-av .avatar { box-shadow: 0 0 0 2px var(--background), 0 0 0 4px var(--rel-shining); }
.dm-dialog-card .dm-row-title { font-size: var(--text-md); font-weight: var(--weight-bold); }
.dm-dialog-card .dm-row-last-message { font-size: var(--text-sm); }
.dm-row-time { font-size: var(--text-xs); font-weight: 400; color: var(--text-secondary); }
.dm-contact-note { flex-shrink: 0; padding: 0; border: 0; border-radius: 0; background: none; color: var(--rel-contact); font-size: var(--text-xs); font-weight: var(--weight-medium); }
.dm-contact-note--close_friend { color: var(--rel-family); }
.dm-filter-row { margin-bottom: var(--space-1); }
.dm-row-meta-col { align-self: stretch; display: flex; flex-direction: column; align-items: flex-end; justify-content: center; gap: 6px; }
.dm-row-meta-line { display: flex; align-items: center; gap: 0; }
.dm-unread-badge { min-width: 20px; height: 20px; padding: 0 6px; display: grid; place-items: center; border-radius: var(--radius-pill); color: var(--on-accent); background: var(--accent); border: 0; font-size: var(--text-xs); font-weight: var(--weight-bold); }
.dm-list-screen > .card.meta-muted, .dm-list > .card.meta-muted { margin: var(--space-6) 0; padding: 0; border: 0; background: none; box-shadow: none; text-align: center; color: var(--text-secondary); }
.dm-divider { height: auto; margin: 0; padding: var(--space-4) 0 var(--space-1); color: var(--text-secondary); font-size: var(--text-xs); line-height: var(--leading-xs); font-weight: var(--weight-bold); }
.dm-divider::before, .dm-divider::after { content: none; }
.contact-search-results { gap: 0; margin-top: var(--space-3); }
.contact-search-results .contact-search-results-title { margin: 0 0 var(--space-1); color: var(--text-secondary); font-size: var(--text-xs); }
.dm-filter-row { gap: 6px; }
.dm-filter-row .chip { padding: 0 12px; }
.dm-row-last-message.is-encrypted { font-style: italic; }