Files
SHiNE-server/shine-UI/styles/features/messages.css
T
qandClaude Opus 5.5 2e62616b46 UI v4: новый стиль по макету V3/V4 и доводка экранов
Палитра «Сияние» по умолчанию, новые роли цветов. Лента канала: плоские записи, ряд действий
с равным шагом иконок, дата у записи. Обсуждение со строкой ввода, личный чат, шторки.
Вход и регистрация: стартовый экран (надпись «СИЯНИЕ», сияние мандалы), настройки входа
со статусами серверов, статус логина в одну строку, вход с другого устройства (код, таймер, шаги),
сохранение ключей с переключателями. Корневые разделы – заголовок по центру; фильтр чатов –
переключатель; уведомления – список как в чатах; фото – просмотр на весь экран.
Общее: один зазор под шапкой (--page-top-gap), переключатели высотой с поле ввода,
второстепенные кнопки по одной роли (в том числе на экранах устройств и серверов),
иконки только из ui-icon.js, полоса прокрутки скрыта, среднее тире в текстах интерфейса.

Что нужно от сервера и разработчика – docs/UI-Design/UI-v4-for-dev.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-29 01:36:52 +03:00

770 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: 0 0 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-row-last-message.is-encrypted { font-style: italic; }