/* ==========================================================================
   Puponki Monitor — единая тема интерфейса
   --------------------------------------------------------------------------
   1. Токены и базовые стили          8. Таблицы
   2. Каркас страницы                 9. Списки (WiFi, отправители, статы)
   3. Заголовки страниц и секции     10. Мониторы
   4. Карточки и подсказки           11. История и карточки сообщений
   5. Кнопки и панели действий       12. Модальные окна
   6. Формы                          13. Адаптивность
   7. Бейджи, код, счётчик символов
   14. Мобильная оптимизация (телефоны)
   15. Мессенджер (/messages)

   ========================================================================== */

/* ========== 1. Токены и базовые стили ========== */

:root {
    --bg: #f2f5fa;
    --bg-soft: #f8fafc;

    --surface: #ffffff;
    --surface-2: #f7f9fc;
    --surface-3: #eef2f8;

    --border: #e3e8f0;
    --border-strong: #cfd7e3;

    --text: #1b2333;
    --text-2: #5a6577;
    --text-3: #8d97a8;

    --accent: #2f6fed;
    --accent-600: #245fd6;
    --accent-soft: #eaf1ff;

    --ok: #12794a;
    --ok-soft: #e6f6ec;

    --warn: #a95d05;
    --warn-soft: #fff3e0;

    --danger: #c62f43;
    --danger-soft: #fdecef;

    --info: #0c7397;
    --info-soft: #e6f4fa;

    --violet: #6d4ac9;
    --violet-soft: #f1ecfd;

    --radius-lg: 16px;
    --radius: 13px;
    --radius-sm: 10px;
    --radius-xs: 8px;

    --shadow-xs: 0 1px 2px rgba(16, 24, 40, 0.05);
    --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06), 0 2px 6px rgba(16, 24, 40, 0.05);
    --shadow-md: 0 6px 20px rgba(16, 24, 40, 0.09);
    --shadow-lg: 0 30px 70px rgba(15, 23, 42, 0.3);

    --ring: 0 0 0 3px rgba(47, 111, 237, 0.18);

    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

    --header-h: 64px;
    --gap: 20px;
}

* {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    font-family: var(--font);
    font-size: 15px;
    line-height: 1.55;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
}

a {
    color: var(--accent);
    text-decoration: none;
}

a:hover {
    color: var(--accent-600);
    text-decoration: underline;
}

img {
    max-width: 100%;
}

h1, h2, h3, h4 {
    margin: 0 0 12px;
    line-height: 1.25;
    font-weight: 650;
    letter-spacing: -0.01em;
}

h1 { font-size: 1.65rem; }
h2 { font-size: 1.2rem; margin-top: 28px; }
h3 { font-size: 1.02rem; margin-top: 22px; }

p { margin: 0 0 12px; }

h1 + p, h2 + p, h3 + p {
    color: var(--text-2);
}

/* Атрибут hidden прячет элемент только до тех пор, пока у него нет своего
   display: как только авторское правило задаёт display (например,
   display: flex у .messenger-chats), правило браузера «[hidden]{display:none}»
   перестаёт действовать и блок остаётся видимым. Поэтому дублируем его сами —
   так hidden скрывает всегда, у любого блока. */
[hidden] {
    display: none !important;
}

/* ========== 2. Каркас страницы ========== */

.container {
    width: 100%;
    max-width: 1440px;
    margin: 0 auto;
    padding: 0 28px;
}

.container-wide {
    max-width: 1560px;
}

header {
    position: sticky;
    top: 0;
    z-index: 60;
    background: rgba(255, 255, 255, 0.94);
    backdrop-filter: saturate(180%) blur(10px);
    border-bottom: 1px solid var(--border);
}

header .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    min-height: var(--header-h);
}

header .logo {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-size: 1.06rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
    text-decoration: none;
    white-space: nowrap;
}

header .logo:hover {
    color: var(--text);
    text-decoration: none;
}

header .logo-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 10px;
    background: linear-gradient(160deg, var(--accent), #5b8cf7);
    color: #fff;
    font-size: 17px;
    box-shadow: var(--shadow-xs);
}

header .logo-text small {
    display: block;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-3);
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

header nav {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-wrap: wrap;
}

header nav a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    border-radius: var(--radius-xs);
    color: var(--text-2);
    font-size: 0.92rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s, color 0.15s;
}

header nav a:hover {
    background: var(--surface-3);
    color: var(--text);
    text-decoration: none;
}

header nav a.nav-cta {
    background: var(--accent);
    color: #fff;
    padding: 8px 14px;
}

header nav a.nav-cta:hover {
    background: var(--accent-600);
    color: #fff;
}

header nav a.is-active {
    background: var(--accent-soft);
    color: var(--accent-600);
}

header nav a.nav-admin {
    color: var(--warn);
}

header nav a.nav-admin.is-active {
    background: var(--warn-soft);
    color: var(--warn);
}

/* Сервисные ссылки прижимаются вправо (справа от них — блок пользователя) */
header nav.main-nav {
    margin-left: auto;
}

/* Иконки и короткие подписи нужны только нижней таб-панели на телефоне */
header nav.main-nav .nav-icon {
    display: inline;
}

header nav.main-nav .nav-short {
    display: none;
}

/* Профиль и выход вынесены из nav в отдельный блок шапки */
.header-user {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.header-user .nav-logout {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    border-radius: var(--radius-xs);
    color: var(--text-3);
    font-size: 0.92rem;
    font-weight: 500;
    transition: background 0.15s, color 0.15s;
}

.header-user .nav-logout:hover {
    background: var(--surface-3);
    color: var(--danger);
    text-decoration: none;
}

.header-user .nav-logout .nav-icon {
    display: none;
}

.nav-user {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 4px 12px 4px 4px;
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.88rem;
    color: var(--text-2);
    background: var(--surface);
}

.nav-user .avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent-600);
    font-weight: 700;
    font-size: 0.8rem;
    text-transform: uppercase;
}

main {
    padding: 28px 0 8px;
    min-height: 62vh;
}

footer {
    margin-top: 48px;
    padding: 22px 0;
    border-top: 1px solid var(--border);
    color: var(--text-3);
    font-size: 0.86rem;
    background: var(--surface);
}

footer .container {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

footer p {
    margin: 0;
}

/* ========== 3. Заголовки страниц и секции ========== */

.page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    padding-bottom: 18px;
    margin-bottom: 22px;
    border-bottom: 1px solid var(--border);
}

.page-head h1 {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.page-head .page-sub {
    margin: 6px 0 0;
    color: var(--text-2);
    max-width: 80ch;
}

.page-head .page-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.breadcrumbs {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
    font-size: 0.85rem;
    color: var(--text-3);
}

.breadcrumbs a {
    color: var(--text-2);
}

.section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin: 34px 0 14px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border);
}

.section-head h2 {
    margin: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.section-head .section-sub {
    margin: 0;
    color: var(--text-3);
    font-size: 0.88rem;
}

.section-head.is-own h2 { color: var(--ok); }
.section-head.is-foreign h2 { color: var(--info); }

.count-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 26px;
    padding: 1px 9px;
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-2);
    font-size: 0.78rem;
    font-weight: 600;
}

/* ========== Сворачиваемая группа «Мои мониторы» (личный кабинет) ==========
   <details> без атрибута open — при загрузке страницы группа всегда свёрнута
   (templates/dashboard/index.php). Заголовок — сам <summary>, поэтому системный
   маркер убираем (list-style + webkit), а стрелку рисуем псевдоэлементом. */
.cabinet-fold {
    margin: 34px 0 0;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: var(--shadow-xs);
}

.cabinet-fold-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 10px;
    padding: 14px 18px;
    cursor: pointer;
    list-style: none;
    user-select: none;
    border-radius: var(--radius);
}

.cabinet-fold-head::-webkit-details-marker { display: none; }
.cabinet-fold-head:hover { background: var(--surface-2); }
.cabinet-fold-head:focus-visible { outline: none; box-shadow: var(--ring); }

.cabinet-fold-arrow {
    align-self: center;
    color: var(--text-3);
    line-height: 1;
}

.cabinet-fold-arrow::before {
    content: '▸';
    display: inline-block;
    transition: transform 0.15s;
}

.cabinet-fold[open] .cabinet-fold-arrow::before { transform: rotate(90deg); }

.cabinet-fold-title {
    font-size: 1.05rem;
    font-weight: 650;
    color: var(--text);
}

.cabinet-fold-body {
    padding: 0 18px 18px;
}

/* Первый заголовок внутри группы — без большого отступа сверху */
.cabinet-fold-body > .section-head:first-child { margin-top: 6px; }

.muted { color: var(--text-3); }
.nowrap { white-space: nowrap; }
.text-center { text-align: center; }
.stack-sm > * + * { margin-top: 10px; }

/* ========== 4. Карточки, панели, подсказки ========== */

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 22px 24px;
    box-shadow: var(--shadow-xs);
}

.card + .card {
    margin-top: 18px;
}

.card.is-danger {
    border-color: #f2c3cb;
}

.card.is-warn {
    border-color: #f0d9b5;
}

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.card-head h2,
.card-head h3 {
    margin: 0;
}

.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
    gap: var(--gap);
    align-items: stretch;
}

/* В сетке карточки стоят в одной строке: вертикальный отступ
   «.card + .card» здесь не нужен (он сдвигал вторую карточку вниз),
   роль разделителя выполняет grid-gap */
.card-grid > .card + .card {
    margin-top: 0;
}

/* Равная высота карточек: содержимое выстраивается в колонку,
   а завершающая подсказка прижимается к нижнему краю карточки */
.card-grid > .card {
    display: flex;
    flex-direction: column;
}

.card-grid > .card > .hint:last-child,
.card-grid > .card > p:last-child {
    margin-bottom: 0;
}

.card-grid > .card > .hint:last-child {
    margin-top: auto;
}

/* Форма, растянутая до низа карточки: строка с кнопкой прижимается
   к нижнему краю, поэтому кнопки в соседних карточках выстраиваются
   на одном уровне (используется на странице «Добавить монитор») */
.card-form-stretch {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

.card-form-stretch > .form-actions {
    margin-top: auto;
}

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 18px 22px;
}

.form-grid .span-2 {
    grid-column: 1 / -1;
}

.info-box {
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius-sm);
    padding: 18px 20px;
    margin-bottom: 18px;
    box-shadow: var(--shadow-xs);
}

.info-box > *:last-child {
    margin-bottom: 0;
}

.info-box h2,
.info-box h3 {
    margin-top: 0;
}

.info-box.is-ok { border-left-color: var(--ok); background: var(--ok-soft); }
.info-box.is-info { border-left-color: var(--info); background: var(--info-soft); }
.info-box.is-warn { border-left-color: var(--warn); background: var(--warn-soft); }
.info-box.is-danger { border-left-color: var(--danger); background: var(--danger-soft); }

.info-box dl,
.def-list {
    margin: 0;
    display: grid;
    grid-template-columns: minmax(140px, auto) 1fr;
    gap: 8px 18px;
}

.info-box dt,
.def-list dt {
    color: var(--text-3);
    font-size: 0.85rem;
    padding-top: 2px;
}

.info-box dd,
.def-list dd {
    margin: 0;
    font-weight: 500;
    word-break: break-word;
}

.hint {
    color: var(--text-3);
    font-size: 0.85rem;
}

.empty-state {
    background: var(--surface);
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    padding: 40px 26px;
    text-align: center;
    color: var(--text-2);
}

.empty-state .empty-icon {
    display: block;
    font-size: 30px;
    margin-bottom: 10px;
    opacity: 0.75;
}

.empty-state > *:last-child {
    margin-bottom: 0;
}

.errors {
    background: var(--danger-soft);
    border: 1px solid #f5c8ce;
    border-left: 3px solid var(--danger);
    border-radius: var(--radius-sm);
    padding: 14px 18px;
    margin-bottom: 20px;
}

.errors p {
    margin: 4px 0;
    color: #8f1f2f;
    font-size: 0.92rem;
}

.errors p:first-child {
    margin-top: 0;
}

.errors p:last-child {
    margin-bottom: 0;
}

.flash {
    padding: 13px 18px;
    margin-bottom: 20px;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    border-left-width: 3px;
    font-size: 0.94rem;
    box-shadow: var(--shadow-xs);
}

.flash-success { background: var(--ok-soft); color: var(--ok); border-color: #c3e7d1; border-left-color: var(--ok); }
.flash-error { background: var(--danger-soft); color: #8f1f2f; border-color: #f5c8ce; border-left-color: var(--danger); }
.flash-info { background: var(--info-soft); color: var(--info); border-color: #c6e6f2; border-left-color: var(--info); }

code {
    font-family: var(--mono);
    font-size: 0.86em;
    background: var(--surface-3);
    border: 1px solid var(--border);
    color: #33415c;
    padding: 2px 7px;
    border-radius: 6px;
    word-break: break-word;
}

.copyable {
    display: inline-block;
    font-size: 0.95rem;
    padding: 6px 10px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    user-select: all;
}

/* ========== 5. Кнопки и панели действий ========== */

.btn,
button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    padding: 9px 16px;
    min-height: 38px;
    font-family: inherit;
    font-size: 0.93rem;
    font-weight: 550;
    line-height: 1.2;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xs);
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s;
}

.btn:hover,
button:hover {
    background: var(--surface-3);
    border-color: var(--border-strong);
    color: var(--text);
    text-decoration: none;
}

.btn:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: none;
    box-shadow: var(--ring);
}

.btn-primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    box-shadow: var(--shadow-xs);
}

.btn-primary:hover {
    background: var(--accent-600);
    border-color: var(--accent-600);
    color: #fff;
}

.btn:disabled,
button:disabled {
    opacity: 0.55;
    cursor: not-allowed;
    box-shadow: none;
}

.btn:disabled:hover,
button:disabled:hover {
    background: var(--surface);
    border-color: var(--border-strong);
    color: var(--text);
}

.btn-danger {
    background: var(--danger);
    border-color: var(--danger);
    color: #fff;
}

.btn-danger:hover {
    background: #ac2436;
    border-color: #ac2436;
    color: #fff;
}

.btn-warning {
    background: var(--warn);
    border-color: var(--warn);
    color: #fff;
}

.btn-warning:hover {
    background: #8e4d02;
    border-color: #8e4d02;
    color: #fff;
}

.btn-ghost {
    background: transparent;
    border-color: transparent;
    color: var(--text-2);
}

.btn-ghost:hover {
    background: var(--surface-3);
    border-color: transparent;
}

.btn-sm {
    padding: 5px 11px;
    min-height: 30px;
    font-size: 0.85rem;
    border-radius: 7px;
}

.btn-icon {
    padding: 0;
    width: 32px;
    min-height: 32px;
}

.btn-block {
    width: 100%;
}

.actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: 0 0 20px;
}

.actions form {
    margin: 0;
}

.actions .btn,
.actions button {
    margin: 0;
}

.toolbar {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: space-between;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 12px 16px;
    margin-bottom: 18px;
    box-shadow: var(--shadow-xs);
}

.toolbar .toolbar-meta {
    color: var(--text-2);
    font-size: 0.9rem;
}

.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin: 26px 0 8px;
    font-size: 0.9rem;
    color: var(--text-2);
}

.row-actions {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    white-space: nowrap;
}

.row-actions form {
    display: inline-flex;
    margin: 0;
}

/* ========== 6. Формы ========== */

form {
    margin: 0;
}

form label,
.field-label {
    display: block;
    margin-bottom: 16px;
    font-weight: 550;
    font-size: 0.93rem;
    color: var(--text);
}

form input[type="text"],
form input[type="email"],
form input[type="password"],
form input[type="number"],
form input[type="search"],
form textarea,
form select {
    display: block;
    width: 100%;
    margin-top: 6px;
    padding: 10px 12px;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 400;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xs);
    transition: border-color 0.15s, box-shadow 0.15s;
}

form textarea {
    min-height: 96px;
    line-height: 1.5;
    resize: vertical;
}

form input::placeholder,
form textarea::placeholder {
    color: var(--text-3);
    font-weight: 400;
}

form input[type="text"]:focus,
form input[type="email"]:focus,
form input[type="password"]:focus,
form input[type="number"]:focus,
form input[type="search"]:focus,
form textarea:focus,
form select:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: var(--ring);
}

form input:disabled,
form textarea:disabled,
form select:disabled {
    background: var(--surface-2);
    color: var(--text-3);
    cursor: not-allowed;
}

form label .hint,
form .hint {
    display: block;
    margin-top: 6px;
    font-weight: 400;
}

form fieldset {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 16px 18px 18px;
    margin: 0 0 18px;
    background: var(--surface-2);
}

form fieldset legend {
    padding: 0 8px;
    font-size: 0.85rem;
    font-weight: 650;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-2);
}

form fieldset label:last-child {
    margin-bottom: 0;
}

.form-grid > fieldset {
    margin-bottom: 0;
}

form fieldset .hint:last-child {
    margin-bottom: 0;
}

.form-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 18px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}

.checkbox-label {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 9px 12px;
    margin: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-xs);
    font-weight: 400;
    font-size: 0.93rem;
    line-height: 1.45;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}

.checkbox-label:hover {
    background: var(--surface);
    border-color: var(--border);
}

.checkbox-label input[type="checkbox"],
.checkbox-label input[type="radio"] {
    flex: 0 0 auto;
    width: 17px;
    height: 17px;
    margin: 2px 0 0;
    accent-color: var(--accent);
    cursor: pointer;
}

.checkbox-label code {
    margin-left: auto;
}

.checkbox-label.is-muted {
    opacity: 0.55;
    cursor: not-allowed;
}

/* Подпись под галочкой «📰 Отправить в Ленту» (templates/send.php):
   прижимаем её к галочке (у абзаца браузерные отступы) и сдвигаем под текст
   галочки — 12px padding .checkbox-label + 17px чекбокс + 10px gap. */
.send-feed-hint {
    margin: -4px 0 12px;
    padding: 0 12px 0 39px;
    line-height: 1.45;
}

.monitors-select {
    max-height: 340px;
    overflow-y: auto;
}

.monitors-select legend + .checkbox-label {
    margin-top: 4px;
}

.file-input-label {
    display: block;
    padding: 14px 16px;
    margin-bottom: 18px;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    cursor: pointer;
    font-weight: 400;
}

.file-input-label:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.file-input-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.file-input-button {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-weight: 550;
    color: var(--accent-600);
}

.file-input-filename {
    margin-left: 10px;
    color: var(--text-2);
    font-size: 0.88rem;
}

.char-counter {
    text-align: right;
    font-size: 0.85rem;
    font-weight: 550;
    color: var(--text-3);
    margin: -8px 0 16px;
    transition: color 0.15s;
}

.char-counter.warn { color: var(--warn); }
.char-counter.danger { color: var(--danger); font-weight: 700; }

/* ========== 7. Бейджи ========== */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-2);
    font-size: 0.76rem;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
    vertical-align: middle;
}

.badge-active { background: var(--ok-soft); color: var(--ok); }
.badge-inactive { background: var(--danger-soft); color: #a3213a; }
.badge-info { background: var(--info-soft); color: var(--info); }
.badge-warn { background: var(--warn-soft); color: var(--warn); }
.badge-danger { background: var(--danger-soft); color: #a3213a; }
.badge-foreign { background: var(--info-soft); color: var(--info); }
.badge-admin { background: var(--warn-soft); color: var(--warn); }
.badge-violet { background: var(--violet-soft); color: var(--violet); }

/* ========== 8. Таблицы ========== */

.table-wrap {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-xs);
    overflow: auto;
    margin-top: 18px;
}

.admin-table {
    width: 100%;
    min-width: 880px;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.89rem;
}

.admin-table thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--surface-2);
    color: var(--text-2);
    padding: 11px 14px;
    text-align: left;
    font-size: 0.74rem;
    font-weight: 650;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    white-space: nowrap;
    border-bottom: 1px solid var(--border);
}

.admin-table td {
    padding: 12px 14px;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
    color: var(--text);
}

.admin-table tbody tr:last-child td {
    border-bottom: none;
}

.admin-table tbody tr:hover td {
    background: var(--bg-soft);
}

.admin-table code {
    background: transparent;
    border: none;
    padding: 0;
    font-size: 0.86rem;
    color: #33415c;
}

.admin-table .badge {
    font-size: 0.72rem;
    padding: 2px 8px;
}

.admin-table .cell-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--text-2);
}

.admin-table .cell-muted {
    color: var(--text-3);
    font-size: 0.84rem;
}

.admin-table th:last-child,
.admin-table td:last-child {
    text-align: right;
}

/* ========== 9. Списки и статистика ========== */

.list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.wifi-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.wifi-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding: 13px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-xs);
}

.wifi-item.wifi-active {
    border-left: 3px solid var(--ok);
}

.wifi-item > form {
    margin: 0;
    display: inline-flex;
    gap: 8px;
    align-items: center;
    flex-wrap: wrap;
}

.wifi-info {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    min-width: 0;
    color: var(--text);
}

.wifi-error {
    flex-basis: 100%;
    color: var(--danger);
    font-size: 0.87rem;
}

.wifi-info strong {
    font-weight: 600;
}

/* Один общий «ящик» для списка сетей (класс is-boxed на .wifi-list):
   сами сети внутри разделяются линиями, а не отдельными рамками */
.wifi-list.is-boxed {
    gap: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-xs);
    overflow: hidden;
}

.wifi-list.is-boxed > .wifi-item {
    background: none;
    border: 0;
    border-bottom: 1px solid var(--border);
    border-radius: 0;
    box-shadow: none;
}

.wifi-list.is-boxed > .wifi-item:last-child {
    border-bottom: 0;
}

/* Активная сеть — зелёная полоса слева; тенью, чтобы текст не сдвигался */
.wifi-list.is-boxed > .wifi-item.wifi-active {
    box-shadow: inset 3px 0 0 var(--ok);
}

.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 16px;
    margin-top: 18px;
}

.stat-card {
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px;
    box-shadow: var(--shadow-xs);
}

.stat-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border-radius: 12px;
    background: var(--accent-soft);
    font-size: 20px;
    flex: 0 0 auto;
}

.stat-icon.is-ok { background: var(--ok-soft); }
.stat-icon.is-warn { background: var(--warn-soft); }
.stat-icon.is-violet { background: var(--violet-soft); }
.stat-icon.is-info { background: var(--info-soft); }

.stat-value {
    font-size: 1.55rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
}

.stat-label {
    color: var(--text-2);
    font-size: 0.85rem;
}

/* ========== 10. Мониторы ========== */

.monitors-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: var(--gap);
}

.monitor-card {
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 18px 20px;
    box-shadow: var(--shadow-xs);
    transition: box-shadow 0.18s, transform 0.18s, border-color 0.18s;
}

.monitor-card:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--border-strong);
    transform: translateY(-1px);
}

.monitor-card.is-foreign {
    border-left: 3px solid var(--info);
    background: linear-gradient(180deg, var(--info-soft) 0%, var(--surface) 42%);
}

.monitor-card.is-offline {
    opacity: 0.85;
}

.monitor-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.monitor-header h3 {
    margin: 0;
    font-size: 1.04rem;
    min-width: 0;
    overflow-wrap: anywhere;
}

.monitor-header h3 a {
    color: var(--text);
    text-decoration: none;
}

.monitor-header h3 a:hover {
    color: var(--accent);
    text-decoration: none;
}

.monitor-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 7px;
}

.monitor-body p {
    margin: 0;
    font-size: 0.89rem;
    color: var(--text-2);
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.monitor-body p strong {
    color: var(--text-3);
    font-weight: 500;
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.monitor-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--border);
}

.monitor-actions form {
    margin: 0;
}

/* Форма-кнопка «+ Добавить монитор» на странице «Доступные мониторы»
   (templates/monitors/available.php): стоит прямо в .monitor-header рядом
   с названием монитора, поэтому не должна сжиматься */
.monitor-header form {
    margin: 0;
    flex-shrink: 0;
}

.monitor-detail {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.monitor-detail h2 {
    margin-top: 30px;
}

.monitor-detail h2:first-child {
    margin-top: 0;
}

.monitor-detail ol {
    margin: 0 0 18px;
    padding-left: 22px;
    color: var(--text-2);
}

.monitor-detail ol li {
    margin-bottom: 6px;
}

/* ========== 11. История и карточки сообщений ========== */

.history {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.history-date-group {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.history-date-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--border);
}

.history-date-label {
    font-weight: 650;
    font-size: 0.92rem;
    color: var(--text);
}

.history-date-count {
    color: var(--text-3);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}

.history-grid {
    display: grid;
    /* Карточки уменьшены примерно вдвое: 300px -> 220px */
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

.msg-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 7px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--border-strong);
    border-radius: var(--radius-sm);
    padding: 9px 11px 11px;
    box-shadow: var(--shadow-xs);
    cursor: pointer;
    transition: box-shadow 0.18s, transform 0.18s, border-color 0.18s;
}

.msg-card:hover {
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}

.msg-card:focus {
    outline: none;
    box-shadow: var(--ring), var(--shadow-md);
}

.msg-card.msg-status-done { border-left-color: var(--ok); }
.msg-card.msg-status-partial { border-left-color: var(--warn); }
.msg-card.msg-status-delivered { border-left-color: var(--accent); }
.msg-card.msg-status-pending { border-left-color: var(--border-strong); }
.msg-card.msg-status-incoming { border-left-color: var(--info); }
.msg-card.msg-status-deleted-all { border-left-color: var(--text-3); }

/* Подсветка карточки «куда ушло сообщение» (templates/partials/feed_card.php,
   $cardTone; владелец, 02.10.2026):
     входящее (чужое)       — голубой фон, голубая полоска слева;
     своё на чужие мониторы — зелёный фон, зелёная полоска слева;
     своё только на свои    — белый фон, серая полоска слева.
   Специфичность у этих селекторов та же, что у .msg-card.msg-status-* (класс +
   класс), поэтому выигрывает последнее правило: полоску задаёт направление
   сообщения, а статус доставки остаётся словами в нижней строке и в модалке.
   Блок .msg-card.msg-card-deleted идёт НИЖЕ и потому сильнее — у «удалённого
   всеми» сообщения фон остаётся приглушённым, а полоска серой. */
.msg-card.msg-card-incoming {
    border-left-color: var(--info);
    background: linear-gradient(180deg, var(--info-soft) 0%, var(--surface) 30%);
}

.msg-card.msg-card-outgoing-foreign {
    border-left-color: var(--ok);
    background: linear-gradient(180deg, var(--ok-soft) 0%, var(--surface) 30%);
}

.msg-card.msg-card-outgoing-own {
    border-left-color: var(--border-strong);
    background: var(--surface);
}

.msg-card.msg-card-deleted {
    background: var(--surface-2);
    border-left-color: var(--text-3);
}

.msg-card-header {
    display: flex;
    align-items: center;
    gap: 6px;
    min-height: 16px;
}

.msg-time {
    font-size: 0.74rem;
    font-weight: 600;
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
}

.msg-status-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 auto;
    background: var(--border-strong);
}

.msg-status-dot-done { background: var(--ok); }
.msg-status-dot-incoming { background: var(--info); }
.msg-status-dot-deleted { background: var(--text-3); }
.msg-status-dot-none { background: var(--border-strong); }

/* Непрочитанные комментарии: яркая красная точка вместо статусной.
   Показывается, пока пользователь не открыл список комментариев
   (см. /api/message/{id}/comments/read), потом гаснет. */
.msg-status-dot-unread {
    background: #ef1b2c;
    box-shadow: 0 0 0 2px rgba(239, 27, 44, 0.20), 0 0 7px rgba(239, 27, 44, 0.85);
    animation: msg-unread-pulse 1.5s ease-in-out infinite;
}

@keyframes msg-unread-pulse {
    0%, 100% { box-shadow: 0 0 0 2px rgba(239, 27, 44, 0.20), 0 0 7px rgba(239, 27, 44, 0.85); }
    50%      { box-shadow: 0 0 0 3px rgba(239, 27, 44, 0.28), 0 0 11px rgba(239, 27, 44, 1); }
}

.msg-sender {
    font-size: 0.76rem;
    color: var(--text-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.msg-sender-incoming {
    color: var(--info);
    font-weight: 550;
}

.msg-badge {
    display: inline-flex;
    align-items: center;
    padding: 1px 7px;
    border-radius: 999px;
    font-size: 0.68rem;
    font-weight: 600;
    background: var(--surface-3);
    color: var(--text-2);
    white-space: nowrap;
}

.msg-status-done-badge { background: var(--ok-soft); color: var(--ok); }
.msg-status-partial-badge { background: var(--warn-soft); color: var(--warn); }
.msg-status-delivered-badge { background: var(--info-soft); color: var(--info); }
.msg-status-pending-badge { background: var(--surface-3); color: var(--text-2); }

.msg-image-preview {
    /* Потолок высоты превью: блок растягивается по пропорциям картинки,
       поэтому ничего не обрезается (раньше было cover + фикс. 4:3) */
    --preview-max: 170px;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 80px;
    max-height: var(--preview-max);
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--surface-2);
    border: 1px solid var(--border);
}

.msg-image-preview img {
    display: block;
    width: 100%;
    height: auto;
    max-height: calc(var(--preview-max) - 2px);
    object-fit: contain;
    margin: 0 auto;
}

.msg-text {
    font-size: 0.82rem;
    color: var(--text);
    overflow-wrap: anywhere;
    white-space: pre-wrap;
}

.msg-text-muted {
    color: var(--text-3);
}

/* У сообщения с картинкой текст уже нарисован на самой картинке,
   поэтому отдельным блоком он не показывается: блок лежит в разметке скрытым
   и раскрывается (inline display: block) только если картинка не отдалась */
.msg-text-fallback {
    display: none;
}

.msg-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: auto;
    padding-top: 7px;
    border-top: 1px solid var(--border);
    font-size: 0.72rem;
    color: var(--text-3);
}

.msg-recipients {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Имена получателей — отдельным элементом (многоточие при переполнении
   работает только у блока с текстом): стрелки рядом с ними больше нет, она
   переехала в верхнюю строку к имени отправителя (см. .msg-arrow). */
.msg-recipients-names {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Стрелка направления в верхней строке карточки — слева от имени отправителя
   (templates/partials/feed_card.php, $senderArrow; владелец, 03.10.2026: раньше
   стояла у получателей в нижней строке): серая вниз — сообщение пришло на мои
   мониторы (входящее), зелёная вверх — моё ушло на чужие мониторы. Значки ↑/↓
   (U+2191/U+2193) текстовые, поэтому их красит color; у эмодзи ⬆/⬇ цвет задаёт
   шрифт, и страница на него не влияет. */
.msg-arrow {
    flex: 0 0 auto;
    font-weight: 700;
    line-height: 1;
}

.msg-arrow-in { color: var(--text-3); }
.msg-arrow-out { color: var(--ok); }

.msg-details {
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* ========== Карточки в стиле ленты (templates/partials/feed_card.php) ==========
   Одна разметка на ленту, «Мои заставки» и личный кабинет:
     верхняя строка — имя отправителя (вместо часов и статусной точки);
     нижняя строка  — счётчик комментариев, слева от него красная точка
                      непрочитанного, а время прижато к правому краю.
   Статусных точек (зелёная / синяя / серая) здесь нет: статус сообщения видно
   по цвету левой кромки карточки, у своих сообщений — ещё и текстом
   в нижней строке кабинета («Показано 2/3», «Ожидает», …).
   Высота карточек в ряду выравнивается сеткой (.history-grid: align-items
   по умолчанию stretch), а нижнюю строку прижимает к низу margin-top: auto
   у .msg-meta — поэтому пустых строк внутри карточки не остаётся.

   Класс страницы нужен, чтобы прижать время к правому краю и разложить
   нижнюю строку в линию: лента (.history-feed), «Мои заставки»
   (.history-screensaver) и личный кабинет (.history-cabinet). */
.history-feed .msg-time,
.history-screensaver .msg-time,
.history-cabinet .msg-time {
    margin-left: auto;
}

.history-feed .msg-details,
.history-screensaver .msg-details,
.history-cabinet .msg-details {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* ========== Группа «Новые комментарии» ==========
   Сообщения с непрочитанными комментариями лента поднимает наверх в отдельную
   группу (Message::getFeedForUser, templates/feed/index.php), а «живое»
   обновление (msgLive* в msg_modal.php) переставляет карточки между этой
   группой и датами — без перезагрузки страницы. */

.history-date-group-unread .history-date-header {
    border-bottom-color: #f2c3cb;
}

.history-date-group-unread .history-date-label {
    color: var(--danger);
}

/* Пустые группы не занимают место: «Новые комментарии» пустеют, когда всё
   прочитано, а группы по датам — пока их карточки уехали наверх
   (класс ставит и снимает msgLiveSyncGroups) */
.history-date-group-empty {
    display: none;
}

/* Карточка, которую только что подняли в «Новые комментарии»: короткая
   подсветка, чтобы переезд был заметен (класс снимает msgLiveFlash) */
.msg-card-live-new {
    animation: msg-live-new 2.6s ease-out 1;
}

@keyframes msg-live-new {
    0%   { background: #fff5f6; box-shadow: 0 0 0 3px rgba(239, 27, 44, 0.28); }
    35%  { background: #fff5f6; box-shadow: 0 0 0 2px rgba(239, 27, 44, 0.18); }
    100% { background: var(--surface); box-shadow: none; }
}

.msg-card-toolbar {
    position: absolute;
    top: 7px;
    right: 7px;
    display: flex;
    align-items: center;
    gap: 3px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s;
    z-index: 2;
}

.msg-card:hover .msg-card-toolbar,
.msg-card:focus-within .msg-card-toolbar {
    opacity: 1;
    pointer-events: auto;
}

.msg-tool-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    min-height: 24px;
    padding: 0;
    font-size: 0.78rem;
    line-height: 1;
    color: var(--text-2);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: 6px;
    box-shadow: var(--shadow-xs);
    cursor: pointer;
}

.msg-tool-btn:hover {
    background: var(--surface-3);
    color: var(--text);
}

.msg-tool-screensaver:hover { background: #fff8d8; border-color: #efd489; color: #8a6100; }

/* Звезда включена — сообщение лежит в заставках, нажатие убирает его оттуда.
   На странице «Мои заставки» звезда стоит вместо прежней 🗑 и значит
   «Переместить в историю личного кабинета» (владелец, 03.10.2026): сообщение
   не удаляется, а возвращается в «Историю сообщений» кабинета.
   Отдельной кнопки ↩ «вернуть в историю» на карточках нет (см. feed_card.php). */
.msg-tool-screensaver.is-on {
    background: #fff8d8;
    border-color: #efd489;
    color: #8a6100;
}

.msg-tool-forward:hover { background: var(--accent-soft); border-color: #c3d6fb; color: var(--accent-600); }

/* 📰 — «сообщение в ленте»: кнопка есть только у СВОЕГО сообщения (в ленте и
   в истории кабинета). Нажатие убирает его из ленты, повторное — возвращает;
   «Истории сообщений» кабинета это не касается (feed_card.php,
   confirmToggleFeed в msg_modal.php). */
.msg-tool-feed:hover { background: var(--accent-soft); border-color: #c3d6fb; color: var(--accent-600); }

/* Ленты сообщение не видит: отправлено без галочки или убрано кнопкой 📰.
   Кнопка приглушена и обесцвечена — состояние читается, не открывая подсказку. */
.msg-tool-feed.is-off {
    opacity: 0.55;
    filter: grayscale(1);
}

.msg-tool-feed.is-off:hover {
    opacity: 1;
    filter: none;
}

.msg-tool-delete:hover { background: var(--danger-soft); border-color: #f2c3cb; color: var(--danger); }

.strikethrough {
    text-decoration: line-through;
}

/* Строки получателей (используются в модалке) */
.recipient-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 9px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
}

.recipient-row + .recipient-row {
    margin-top: 8px;
}

.recipient-name {
    font-weight: 600;
}

.recipient-uid {
    font-family: var(--mono);
    font-size: 0.8rem;
    color: var(--text-3);
}

.recipient-status {
    margin-left: auto;
}

.recipient-star {
    font-size: 0.9rem;
    flex: 0 0 auto;
}

.recipient-row.recipient-green .recipient-status { color: var(--ok); }
.recipient-row.recipient-deleted { opacity: 0.7; }
.recipient-row.recipient-deleted .recipient-status { color: var(--text-3); }
.recipient-row.recipient-gray .recipient-status { color: var(--text-3); }

.load-error {
    color: var(--danger);
    font-size: 0.9rem;
}

.forward-modal h3:first-child {
    margin-top: 0;
}

/* ========== 12. Модальные окна ========== */

.msg-modal-overlay,
.forward-modal-overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 200;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(15, 23, 42, 0.55);
    backdrop-filter: blur(3px);
}

.msg-modal-overlay.active,
.forward-modal-overlay.active {
    display: flex;
}

/* Появление окна — АНИМАЦИЯ ТОЛЬКО ОДИН РАЗ, при открытии.
   При перелистывании сообщений окно не двигается: его высота фиксируется
   в msgModalShowCurrent() из templates/partials/msg_modal.php */
@keyframes msg-overlay-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes msg-modal-in {
    from { opacity: 0; transform: translateY(18px) scale(0.985); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

.msg-modal-overlay.active {
    animation: msg-overlay-in 0.2s ease-out;
}

.msg-modal-overlay.active .msg-modal {
    animation: msg-modal-in 0.24s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Окно сообщения растёт ТОЛЬКО вниз: верхняя кромка стоит на месте.
   Окно выравнивается по верху оверлея и получает постоянный отступ сверху,
   поэтому его верхний край неизменен, а растущий список комментариев удлиняет
   окно только вниз. Позицию окна задаёт только CSS, JavaScript её не трогает:
   раньше кромку фиксировал JS (класс-маркер на оверлее), но при перерисовке
   списка комментариев окно успевало сместиться (оверлей оставался align-items:
   center и окно уезжало вверх и вниз одновременно).
   overflow-y — страховка, если содержимое окажется выше экрана.
   На телефоне окно — «шторка» снизу (@media max-width: 760px): она растёт вверх
   от нижнего края, фиксировать там нечего, поэтому правило только для широких
   экранов. */
@media (min-width: 761px) {
    .msg-modal-overlay.active {
        align-items: flex-start;
        padding-top: 6vh;
        overflow-y: auto;
    }
}

.msg-modal {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 1000px;
    max-height: 90vh;
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    overflow: hidden;
}

.msg-modal-body {
    display: flex;
    align-items: stretch;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

.msg-modal-image-wrap {
    flex: 1 1 55%;
    min-width: 0;
    /* Левая половина окна (фото) — чёрный фон; правая (текст и комментарии)
       остаётся белой, её задаёт background у .msg-modal */
    background: #000000;
    border-right: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
    min-height: 320px;
}

.msg-modal-image-wrap img {
    display: block;
    width: 100%;
    height: 100%;
    max-height: 86vh;
    object-fit: contain;
}

.msg-modal-content {
    flex: 1 1 45%;
    min-width: 0;
    /* Снизу оставлена полоса под кружки листания (.msg-modal-nav) */
    padding: 26px 28px 72px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.msg-modal-status {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-2);
    font-size: 0.8rem;
    font-weight: 650;
}

.msg-modal-status.msg-status-done { background: var(--ok-soft); color: var(--ok); }
.msg-modal-status.msg-status-partial { background: var(--warn-soft); color: var(--warn); }
.msg-modal-status.msg-status-delivered { background: var(--info-soft); color: var(--info); }
.msg-modal-status.msg-status-pending { background: var(--surface-3); color: var(--text-2); }
.msg-modal-status.msg-status-incoming { background: var(--info-soft); color: var(--info); }
.msg-modal-status.msg-status-deleted-all { background: var(--danger-soft); color: var(--danger); }

.msg-modal-text {
    font-size: 1.06rem;
    line-height: 1.6;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ========== Модалка в ленте (templates/feed/index.php) ==========
   Лента показывает сообщения всех пользователей, поэтому блок получателей
   в окне не выводится: класс .msg-modal-feed на оверлее + JS-флаг
   MSG_MODAL_FEED_MODE (он же отключает запрос /api/message/{id}/recipients). */
.msg-modal-overlay.msg-modal-feed #msgModalRecipientsBlock {
    display: none;
}

.msg-modal-recipients-title {
    font-weight: 650;
    font-size: 0.92rem;
    margin-bottom: 8px;
    /* Подпись приглушённая: заголовок списка, а не акцент */
    color: var(--text-2);
}

.msg-modal-recipients-list {
    max-height: 240px;
    overflow-y: auto;
}

.msg-modal-close,
.forward-modal-close {
    position: absolute;
    top: 12px;
    right: 12px;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    min-height: 34px;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-2);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    box-shadow: var(--shadow-xs);
}

.msg-modal-close:hover,
.forward-modal-close:hover {
    background: var(--surface-3);
    color: var(--text);
}

.msg-modal-counter {
    position: absolute;
    top: 16px;
    left: 18px;
    z-index: 3;
    padding: 3px 11px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.92);
    border: 1px solid var(--border);
    color: var(--text-2);
    font-size: 0.82rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Кружки листания — внизу окна (в десктопной/основной версии).
   В мобильной «шторке» (@media max-width: 600px) они остаются по бокам
   без кружочков, по вертикали по центру — см. правила ниже */
.msg-modal-nav {
    position: absolute;
    top: auto;
    bottom: 14px;
    transform: none;
    z-index: 3;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.95);
    border: 1px solid var(--border);
    color: var(--text-2);
    font-size: 26px;
    line-height: 1;
    cursor: pointer;
    user-select: none;
    box-shadow: var(--shadow-sm);
}

.msg-modal-nav:hover {
    background: #fff;
    color: var(--text);
}

.msg-modal-nav-prev { left: 12px; }
.msg-modal-nav-next { right: 12px; }

.msg-modal-nav.disabled {
    opacity: 0.35;
    pointer-events: none;
}

/* Пока грузится список получателей, показываем прежний приглушённым:
   блок не схлопывается и модалка не «прыгает» по высоте */
.msg-modal-recipients-list.is-loading {
    opacity: 0.45;
    pointer-events: none;
    transition: opacity 0.15s;
}

/* ========== Комментарии в модалке ==========
   Список комментариев — между списком получателей и полем ввода.
   Заголовка со счётчиком («💬 Комментарии: N») в окне нет: список
   говорит сам за себя, а поле ввода видно ниже. */

.msg-modal-comments-list {
    max-height: 220px;
    overflow-y: auto;
}

.msg-modal-comments-list.is-loading {
    opacity: 0.45;
    pointer-events: none;
    transition: opacity 0.15s;
}

.msg-comment {
    padding: 9px 12px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
}

.msg-comment + .msg-comment {
    margin-top: 8px;
}

.msg-comment-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 3px;
    font-size: 0.76rem;
    color: var(--text-3);
}

.msg-comment-author {
    font-weight: 650;
    color: var(--text-2);
}

.msg-comment-time {
    font-variant-numeric: tabular-nums;
}

/* Непрочитанный комментарий: красная точка в том же правом слоте строки,
   где у своих комментариев стоит крестик удаления (см. buildCommentsHtml).
   Точка не мигает: в списке их может быть много. */
.msg-comment-unread {
    margin-left: auto;
    align-self: center;
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #ef1b2c;
    box-shadow: 0 0 0 2px rgba(239, 27, 44, 0.20), 0 0 7px rgba(239, 27, 44, 0.85);
}

.msg-comment-del {
    margin-left: auto;
    width: 20px;
    height: 20px;
    min-height: 20px;
    padding: 0;
    font-size: 0.7rem;
    line-height: 1;
    color: var(--text-3);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 5px;
    cursor: pointer;
}

.msg-comment-del:hover {
    color: var(--danger);
    background: var(--danger-soft);
    border-color: #f2c3cb;
}

.msg-comment-text {
    font-size: 0.88rem;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.msg-comment-form {
    margin-top: 12px;
}

.msg-comment-form textarea {
    width: 100%;
    min-height: 62px;
    resize: vertical;
    font-family: inherit;
    font-size: 0.9rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xs);
    padding: 9px 12px;
}

.msg-comment-form textarea:focus {
    outline: none;
    box-shadow: var(--ring);
    border-color: var(--accent);
}

.msg-comment-form-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: 8px;
}

.msg-comment-counter {
    font-size: 0.78rem;
    color: var(--text-3);
    font-variant-numeric: tabular-nums;
}

.msg-comment-error {
    margin-top: 8px;
    padding: 8px 12px;
    border-radius: var(--radius-xs);
    background: var(--danger-soft);
    border: 1px solid #f5c8ce;
    color: #8f1f2f;
    font-size: 0.85rem;
}

.forward-modal {
    position: relative;
    width: 100%;
    max-width: 560px;
    max-height: 90vh;
    overflow-y: auto;
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 26px 28px;
}

.forward-modal .monitors-select {
    max-height: 280px;
}

.forward-modal .checkbox-label code {
    margin-left: 0;
}

/* ========== 13. Служебные блоки и адаптивность ========== */

.hero {
    max-width: 760px;
    padding: 48px 0 12px;
}

.hero h1 {
    font-size: 2.3rem;
    letter-spacing: -0.03em;
    margin-bottom: 14px;
}

.hero .lead {
    font-size: 1.08rem;
    color: var(--text-2);
    margin-bottom: 24px;
}

.hero-actions {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 34px;
}

.feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 18px;
}

.feature-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 20px;
    box-shadow: var(--shadow-xs);
}

.feature-card .feature-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 11px;
    background: var(--accent-soft);
    font-size: 19px;
    margin-bottom: 12px;
}

.feature-card h3 {
    margin: 0 0 6px;
    font-size: 1rem;
}

.feature-card p {
    margin: 0;
    color: var(--text-2);
    font-size: 0.9rem;
}

.auth-wrap {
    display: flex;
    justify-content: center;
    padding: 20px 0 40px;
}

.auth-card {
    width: 100%;
    max-width: 460px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 30px 32px;
    box-shadow: var(--shadow-sm);
}

.auth-card h1 {
    margin-bottom: 6px;
}

.auth-card .auth-sub {
    color: var(--text-2);
    font-size: 0.92rem;
    margin-bottom: 22px;
}

.auth-card .auth-alt {
    margin: 18px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    font-size: 0.9rem;
    color: var(--text-2);
}

.not-found {
    max-width: 560px;
    margin: 40px auto;
    text-align: center;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 46px 32px;
    box-shadow: var(--shadow-xs);
}

.not-found .not-found-code {
    font-size: 3.2rem;
    font-weight: 700;
    letter-spacing: -0.04em;
    color: var(--accent);
    line-height: 1;
    margin-bottom: 10px;
}

@media (max-width: 1100px) {
    .container,
    .container-wide {
        padding: 0 20px;
    }

    .msg-modal-body {
        flex-direction: column;
        overflow-y: auto;
    }

    /* Картинка — во всю ширину окна, высота по её пропорциям:
       поэтому по бокам не остаётся светлых полос */
    .msg-modal-image-wrap {
        flex: 0 0 auto;
        display: block;
        background: none;
        border-right: none;
        border-bottom: 1px solid var(--border);
        max-height: none;
        min-height: 0;
    }

    .msg-modal-image-wrap img {
        width: 100%;
        height: auto;
        max-height: none;
        object-fit: contain;
    }

    .msg-modal-content {
        flex: 0 0 auto;
        overflow: visible;
    }
}

@media (max-width: 820px) {
    header .container {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
        padding-top: 12px;
        padding-bottom: 12px;
    }

    header nav {
        width: 100%;
    }

    .nav-user {
        margin-left: 0;
    }

    .page-head {
        flex-direction: column;
        align-items: stretch;
    }

    .page-head .page-actions {
        width: 100%;
    }

    .hero {
        padding-top: 24px;
    }

    .hero h1 {
        font-size: 1.8rem;
    }

    .card-grid,
    .form-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .info-box dl,
    .def-list {
        grid-template-columns: minmax(0, 1fr);
        gap: 2px 0;
    }

    .info-box dd,
    .def-list dd {
        margin-bottom: 10px;
    }

    .monitors-grid,
    .history-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Заставки: две карточки в ряд, а не одна */
    .history-screensaver .history-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Карточки стали шире — разрешаем превью быть выше */
    .msg-image-preview {
        --preview-max: 260px;
    }
}

@media (max-width: 600px) {
    body {
        font-size: 14.5px;
    }

    .container,
    .container-wide {
        padding: 0 14px;
    }

    .card,
    .auth-card,
    .forward-modal {
        padding: 18px 16px;
    }

    .msg-modal-overlay,
    .forward-modal-overlay {
        padding: 0;
        align-items: flex-end;
    }

    .msg-modal,
    .forward-modal {
        max-width: none;
        max-height: 94vh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    }

    .msg-modal-nav {
        display: none;
    }

    .stats-grid {
        grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    }

    .stat-card {
        padding: 13px 14px;
    }

    .stat-icon {
        width: 36px;
        height: 36px;
        font-size: 17px;
    }

    .stat-value {
        font-size: 1.3rem;
    }
}

/* На тач-устройствах панель действий всегда видна */
@media (pointer: coarse) {
    .msg-card-toolbar {
        opacity: 1;
        pointer-events: auto;
    }

    /* Кнопки на карточке оставляем крупными — под палец */
    .msg-tool-btn {
        width: 34px;
        height: 34px;
        min-height: 34px;
        font-size: 0.9rem;
    }
}

/* ========== 14. Мобильная оптимизация (телефоны) ========== */
/*
   Цель: на экране телефона всё влезает без «нагромождения» и лишнего листания.
   - сервисные ссылки уезжают в фиксированную нижнюю таб-панель (как в приложении);
   - шапка сжимается до логотипа + аватара + иконки выхода;
   - таблицы админки превращаются в карточки (метка берётся из data-label);
   - кнопки/поля удобны для пальца (>= 42px), поля 16px — iOS не зумит страницу;
   - учитываются «безопасные зоны» (вырез, полоса жестов) через env(safe-area-inset-*).
*/

@media (max-width: 760px) {
    :root {
        --gap: 12px;
        --header-h: 52px;
    }

    body {
        font-size: 14.5px;
        line-height: 1.5;
        /* clip (а не hidden) — не ломает sticky-шапку */
        overflow-x: clip;
    }

    /* Место под нижнюю панель + полосу жестов — только когда панель есть */
    body.has-tabbar {
        padding-bottom: calc(62px + env(safe-area-inset-bottom, 0px));
    }

    /* Отступы контента с учётом выреза/скруглений по краям экрана */
    .container,
    .container-wide {
        padding-left: calc(14px + env(safe-area-inset-left, 0px));
        padding-right: calc(14px + env(safe-area-inset-right, 0px));
    }

    /* --- Шапка: минимум элементов --- */
    /*
       backdrop-filter у шапки создаёт containing block для position: fixed,
       поэтому нижняя панель «приклеилась» бы к шапке, а не к низу экрана.
       На телефоне блюр отключаем — фон делаем плотным.
    */
    header {
        backdrop-filter: none;
        background: #fff;
    }

    header .container {
        flex-direction: row;
        align-items: center;
        flex-wrap: wrap;
        gap: 8px;
        padding-top: 8px;
        padding-bottom: 8px;
        min-height: var(--header-h);
    }

    header .logo {
        gap: 8px;
        font-size: 1rem;
        min-width: 0;
    }

    header .logo-text {
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Подпись «сообщения на 3D-принтер» на телефоне только мешает */
    header .logo-text small {
        display: none;
    }

    header .logo-mark {
        width: 30px;
        height: 30px;
        font-size: 15px;
        border-radius: 9px;
    }

    /* Профиль — только аватар, выход — только иконка */
    .header-user {
        margin-left: auto;
        gap: 4px;
    }

    .nav-user {
        padding: 0;
        border: none;
        background: transparent;
    }

    .nav-user .avatar {
        width: 32px;
        height: 32px;
        font-size: 0.85rem;
    }

    .nav-user-name {
        display: none;
    }

    .header-user .nav-logout {
        padding: 6px 8px;
        font-size: 1.05rem;
        line-height: 1;
        color: var(--text-2);
    }

    .header-user .nav-logout .nav-icon {
        display: inline;
    }

    .header-user .nav-logout .nav-label {
        display: none;
    }

    /* --- Нижняя таб-панель (только для вошедших: класс main-nav-app) --- */
    .main-nav-app {
        position: fixed;
        top: auto;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 90;
        display: flex;
        flex-wrap: nowrap;
        align-items: stretch;
        gap: 2px;
        margin: 0;
        padding: 4px 6px;
        padding-right: calc(6px + env(safe-area-inset-right, 0px));
        padding-bottom: calc(4px + env(safe-area-inset-bottom, 0px));
        padding-left: calc(6px + env(safe-area-inset-left, 0px));
        background: rgba(255, 255, 255, 0.97);
        backdrop-filter: saturate(180%) blur(10px);
        border-top: 1px solid var(--border);
        box-shadow: 0 -2px 14px rgba(16, 24, 40, 0.07);
    }

    .main-nav-app a {
        flex: 1 1 0;
        min-width: 0;
        flex-direction: column;
        gap: 3px;
        padding: 6px 2px;
        font-size: 0.68rem;
        font-weight: 550;
        line-height: 1.1;
        text-align: center;
        color: var(--text-2);
        border-radius: var(--radius-xs);
        white-space: nowrap;
    }

    .main-nav-app a .nav-icon {
        font-size: 1.2rem;
        line-height: 1;
    }

    .main-nav-app a .nav-label {
        display: none;
    }

    .main-nav-app a .nav-short {
        display: block;
        max-width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .main-nav-app a.is-active {
        background: var(--accent-soft);
        color: var(--accent-600);
    }

    .main-nav-app a.nav-admin.is-active {
        background: var(--warn-soft);
        color: var(--warn);
    }

    /* Гость (вход/регистрация): ссылки остаются в шапке, но крупнее */
    .main-nav:not(.main-nav-app) {
        width: auto;
        margin-left: auto;
        flex-wrap: nowrap;
        gap: 6px;
    }

    .main-nav:not(.main-nav-app) a {
        min-height: 42px;
        padding: 8px 12px;
    }

    /* --- Контент: меньше «воздуха», больше пользы на экране --- */
    main {
        padding: 14px 0 4px;
        min-height: 0;
    }

    footer {
        margin-top: 20px;
        padding: 14px 0;
        font-size: 0.78rem;
    }

    footer .container {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
    }

    /* Второстепенный текст в подвале на телефоне не нужен */
    footer .hint {
        display: none;
    }

    h1 { font-size: 1.32rem; }
    h2 { font-size: 1.06rem; margin-top: 20px; }
    h3 { font-size: 0.98rem; margin-top: 16px; }

    .page-head {
        gap: 10px;
        margin-bottom: 14px;
    }

    .page-head h1 {
        font-size: 1.3rem;
    }

    .page-head .page-sub {
        font-size: 0.85rem;
    }

    .page-actions {
        gap: 8px;
    }

    .page-actions .btn,
    .page-actions button {
        flex: 1 1 auto;
        justify-content: center;
    }

    .section-head {
        flex-direction: column;
        align-items: flex-start;
        gap: 2px;
        margin: 20px 0 10px;
    }

    .section-head h2 {
        font-size: 1.02rem;
    }

    .section-head .section-sub {
        font-size: 0.82rem;
    }

    /* --- Первый экран (/) --- */
    .hero {
        padding: 18px 0 8px;
    }

    .hero h1 {
        font-size: 1.6rem;
        margin-bottom: 10px;
    }

    .hero .lead {
        font-size: 0.95rem;
        margin-bottom: 16px;
    }

    .hero-actions {
        gap: 8px;
        margin-bottom: 20px;
    }

    .hero-actions .btn,
    .hero-actions button {
        flex: 1 1 140px;
    }

    .feature-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px;
    }

    .feature-card {
        padding: 12px;
        border-radius: var(--radius-sm);
    }

    .feature-card .feature-icon {
        width: 30px;
        height: 30px;
        font-size: 15px;
        border-radius: 9px;
        margin-bottom: 8px;
    }

    .feature-card h3 {
        font-size: 0.9rem;
    }

    .feature-card p {
        font-size: 0.79rem;
    }

    /* --- Карточки и списки «ключ — значение» --- */
    .card,
    .auth-card {
        padding: 14px;
        border-radius: var(--radius);
    }

    .auth-card {
        padding: 20px 16px;
    }

    .card-grid,
    .form-grid,
    .monitors-grid,
    .history-grid {
        gap: 10px;
    }

    .card-grid,
    .form-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .info-box {
        padding: 12px 14px;
    }

    .info-box dl,
    .def-list {
        grid-template-columns: minmax(0, 1fr);
        gap: 0;
    }

    .info-box dt,
    .def-list dt {
        font-size: 0.74rem;
        padding-top: 4px;
    }

    .info-box dd,
    .def-list dd {
        margin-bottom: 8px;
        font-size: 0.9rem;
    }

    /* --- Статистика: по две плитки в ряд --- */
    .stats-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
        margin-top: 12px;
    }

    .stat-card {
        gap: 10px;
        padding: 10px 12px;
        border-radius: var(--radius-sm);
    }

    .stat-icon {
        width: 30px;
        height: 30px;
        font-size: 14px;
        border-radius: 9px;
    }

    .stat-value {
        font-size: 1.15rem;
    }

    .stat-label {
        font-size: 0.72rem;
    }

    /* --- Мониторы --- */
    .monitor-card {
        padding: 12px 14px;
    }

    .monitor-header {
        gap: 8px;
        margin-bottom: 8px;
    }

    .monitor-header h3 {
        font-size: 0.98rem;
    }

    .monitor-body {
        gap: 4px;
    }

    .monitor-body p {
        font-size: 0.86rem;
    }

    .monitor-actions {
        gap: 6px;
        margin-top: 10px;
        padding-top: 10px;
    }

    .monitor-actions .btn,
    .monitor-actions button {
        flex: 1 1 auto;
        justify-content: center;
        min-height: 40px;
    }

    /* --- Кнопки и панели: удобно нажимать пальцем --- */
    .btn,
    button {
        min-height: 42px;
    }

    .btn-sm {
        min-height: 34px;
        padding: 6px 12px;
    }

    .btn-icon {
        width: 42px;
    }

    .actions {
        gap: 8px;
        margin-bottom: 14px;
    }

    .actions .btn,
    .actions button {
        flex: 1 1 auto;
        justify-content: center;
    }

    .toolbar {
        gap: 8px;
        padding: 10px 12px;
        margin-bottom: 12px;
    }

    .toolbar .toolbar-meta {
        font-size: 0.82rem;
    }

    .row-actions {
        gap: 8px;
    }

    .row-actions .btn {
        min-width: 44px;
    }

    .pagination {
        gap: 8px;
        margin: 16px 0 4px;
        font-size: 0.82rem;
    }

    .pagination .btn {
        flex: 1 1 auto;
    }

    /* --- Формы: поля 16px, чтобы iOS не зумил страницу --- */
    form label,
    .field-label {
        margin-bottom: 12px;
        font-size: 0.88rem;
    }

    form input[type="text"],
    form input[type="email"],
    form input[type="password"],
    form input[type="number"],
    form input[type="search"],
    form textarea,
    form select {
        font-size: 16px;
        padding: 11px 12px;
    }

    form textarea {
        min-height: 84px;
    }

    form fieldset {
        padding: 12px 12px 14px;
        margin-bottom: 12px;
    }

    .checkbox-label {
        padding: 10px 10px;
        font-size: 0.88rem;
    }

    .form-actions {
        gap: 8px;
        margin-top: 14px;
        padding-top: 14px;
    }

    .form-actions .btn,
    .form-actions button {
        flex: 1 1 140px;
    }

    .monitors-select {
        max-height: 46vh;
    }

    /* --- Таблицы админки: карточки вместо горизонтального скролла --- */
    .table-wrap {
        overflow: visible;
        background: transparent;
        border: none;
        box-shadow: none;
        margin-top: 12px;
    }

    .admin-table {
        display: block;
        width: 100%;
        min-width: 0;
        font-size: 0.88rem;
    }

    .admin-table thead {
        display: none;
    }

    .admin-table tbody {
        display: block;
    }

    .admin-table tbody tr {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 2px 12px;
        padding: 10px 12px;
        margin-bottom: 8px;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: var(--radius-sm);
        box-shadow: var(--shadow-xs);
    }

    .admin-table tbody tr:hover td {
        background: transparent;
    }

    .admin-table td,
    .admin-table td:last-child {
        display: flex;
        flex-direction: column;
        gap: 1px;
        min-width: 0;
        padding: 4px 0;
        border: none;
        text-align: left;
        vertical-align: top;
        overflow-wrap: anywhere;
    }

    /* Подпись колонки берётся из атрибута data-label */
    .admin-table td::before {
        content: attr(data-label);
        font-size: 0.66rem;
        font-weight: 650;
        letter-spacing: 0.04em;
        text-transform: uppercase;
        color: var(--text-3);
    }

    .admin-table td:not([data-label])::before {
        content: none;
    }

    /* Пустые ячейки не занимают место */
    .admin-table td:empty {
        display: none;
    }

    .admin-table .cell-num {
        text-align: left;
    }

    .admin-table code {
        font-size: 0.8rem;
    }

    /* Действия — во всю ширину карточки */
    .admin-table td:last-child {
        grid-column: 1 / -1;
        margin-top: 2px;
    }

    .admin-table td:last-child .row-actions {
        width: 100%;
    }

    .admin-table td:last-child .row-actions .btn {
        flex: 1 1 auto;
        min-height: 40px;
    }

    /* --- Карточки сообщений: одна колонка во всю ширину --- */
    .history {
        gap: 12px;
    }

    .history-date-group {
        gap: 8px;
    }

    .history-date-header {
        font-size: 0.86rem;
    }

    .history-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /* --- Заставки: две карточки в ряд (не одна колонка) --- */
    .history-screensaver .history-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 8px;
        align-items: start;
    }

    .history-screensaver .msg-card {
        gap: 5px;
        padding: 8px 9px 9px;
    }

    .history-screensaver .msg-card-toolbar {
        top: 5px;
        right: 5px;
        gap: 3px;
    }

    .history-screensaver .msg-tool-btn {
        width: 28px;
        height: 28px;
        min-height: 28px;
        font-size: 0.78rem;
    }

    .history-screensaver .msg-image-preview {
        --preview-max: 104px;
        min-height: 60px;
    }

    .history-screensaver .msg-sender {
        font-size: 0.7rem;
    }

    /* Длинный текст в узкой карточке обрезаем — список не «расползается» */
    .history-screensaver .msg-text {
        display: -webkit-box;
        -webkit-line-clamp: 4;
        -webkit-box-orient: vertical;
        overflow: hidden;
        font-size: 0.76rem;
        line-height: 1.35;
    }

    .msg-image-preview {
        --preview-max: 240px;
        min-height: 0;
    }

    .msg-card-toolbar {
        top: 6px;
        right: 6px;
        gap: 4px;
    }

    /* --- Модальные окна: «шторка» снизу, без отступов по краям --- */
    .msg-modal-overlay,
    .forward-modal-overlay {
        padding: 0;
        align-items: flex-end;
    }

    .msg-modal,
    .forward-modal {
        max-width: none;
        max-height: 92dvh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        padding-bottom: env(safe-area-inset-bottom, 0px);
    }

    /* «Шторка» выезжает снизу — только при открытии окна,
       при перелистывании она стоит на месте */
    @keyframes msg-sheet-in {
        from { transform: translateY(100%); }
        to   { transform: translateY(0); }
    }

    .msg-modal-overlay.active .msg-modal {
        animation: msg-sheet-in 0.3s cubic-bezier(0.22, 0.61, 0.36, 1);
    }

    .forward-modal {
        padding: 18px 16px;
    }

    .msg-modal-body {
        flex-direction: column;
        overflow-y: auto;
    }

    /* Картинка — во всю ширину «шторки» (без полос по бокам из-за ограничения высоты) */
    .msg-modal-image-wrap {
        flex: 0 0 auto;
        display: block;
        min-height: 0;
        max-height: none;
        background: none;
        border-right: none;
        border-bottom: 1px solid var(--border);
    }

    .msg-modal-image-wrap img {
        width: 100%;
        height: auto;
        max-height: none;
    }

    .msg-modal-content {
        flex: 0 0 auto;
        gap: 10px;
        /* По бокам оставлено место под стрелки листания (они без «кружочков») */
        padding: 16px 26px;
        overflow: visible;
    }

    .msg-modal-text {
        font-size: 0.98rem;
    }

    .recipient-row {
        min-height: 40px;
    }

    .msg-modal-counter {
        top: 10px;
        left: 12px;
    }

    .msg-modal-close,
    .forward-modal-close {
        top: 8px;
        right: 8px;
    }

    /* Стрелки листания: по бокам модалки, без «кружочков».
       display уточняем явно — в блоке @media (max-width: 600px) они скрыты. */
    .msg-modal-nav {
        display: flex;
        top: 50%;
        bottom: auto;
        transform: translateY(-50%);
        width: 38px;
        height: 72px;
        font-size: 30px;
        font-weight: 300;
        color: var(--text-2);
        background: none;
        border: 0;
        border-radius: 0;
        box-shadow: none;
        /* Стрелка читается и поверх светлой картинки */
        filter: drop-shadow(0 1px 3px rgba(255, 255, 255, 0.95));
    }

    .msg-modal-nav:hover,
    .msg-modal-nav:active {
        background: none;
        color: var(--accent);
    }

    .msg-modal-nav-prev { left: 0; }
    .msg-modal-nav-next { right: 0; }

    .msg-modal-nav.disabled {
        opacity: 0.22;
    }
}

/* Очень узкие телефоны (<= 380px): ещё компактнее */
@media (max-width: 380px) {
    .feature-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .admin-table tbody tr {
        grid-template-columns: minmax(0, 1fr);
    }

    .main-nav-app a {
        font-size: 0.62rem;
    }

    .main-nav-app a .nav-icon {
        font-size: 1.05rem;
    }

    .hero h1 {
        font-size: 1.42rem;
    }

    .stats-grid {
        gap: 6px;
    }

    .stat-card {
        gap: 8px;
        padding: 9px 10px;
    }

    .stat-value {
        font-size: 1.05rem;
    }

    .card,
    .auth-card {
        padding: 12px;
    }

    /* Заставки в две колонки остаются, но совсем компактными */
    .history-screensaver .history-grid {
        gap: 6px;
    }

    .history-screensaver .msg-image-preview {
        --preview-max: 86px;
        min-height: 50px;
    }

    .history-screensaver .msg-text {
        -webkit-line-clamp: 3;
        font-size: 0.72rem;
    }
}

/* ========== Значки-картинки вместо эмодзи ==========
   Иконки меню и страниц нарисованы файлами из public/assets/img/ (исходники
   владельца лежат в puponki/pic/, но это не веб-корень — поэтому рядом с
   сайтом их копии):

     - mail.png   — пункт меню «Отправить» (templates/layout.php);
     - zast.png   — пункт меню «Заставки» и заголовок/заглушка страницы
                    «Мои заставки» (templates/screensaver/index.php);
     - zoidberg.svg — пункт меню «Лента» (там же живёт красная точка
                    непрочитанного — .nav-unread-dot ниже), заголовок ленты и
                    заглушка «Пока пусто» (templates/feed/index.php).

   Размер задан в em и потому берётся из шрифта места: в меню значок одного
   роста с подписью, в мобильной таб-панели крупнее (там .nav-icon = 1.2rem),
   в заголовке страницы и в заглушке — крупнее вместе с текстом. Отдельные
   правила для телефонов не нужны.
   vertical-align выравнивает картинку по тексту (у эмодзи это делал шрифт),
   inline-block — чтобы в заглушке «Пока пусто» картинка центрировалась
   через text-align: center родителя, flex: none — чтобы в заголовке (flex)
   картинку не сжало. */
.icon-img {
    width: 1.05em;
    height: 1.05em;
    display: inline-block;
    vertical-align: -0.14em;
    object-fit: contain;
    flex: none;
}

/* ========== Красная точка у пункта меню «Лента» ==========
   Точка та же, что на карточках ленты (.msg-status-dot-unread — красная и
   пульсирующая, см. её правило выше), только стоит слева от иконки.
   Пункт загорается, когда есть непрочитанные комментарии или новые входящие,
   которые пользователь ещё не открывал
   (Message::hasNavUnread — шаблон templates/layout.php, живое обновление —
   GET /api/messages/nav-unread: раз в 3 с, пока страница активна).

   .nav-icon-badge делает иконку точкой отсчёта: на телефоне .nav-icon —
   флекс-элемент таб-панели, на компьютере строчный, и абсолютная точка
   работает в обоих случаях. */
.nav-icon-badge {
    position: relative;
}

.nav-unread-dot {
    position: absolute;
    top: 50%;
    left: -7px;
    margin-top: -3.5px; /* половина высоты точки (7px в .msg-status-dot) */
}

/* ========== Пониженная анимация (системная настройка) ==========
   Блок намеренно в конце файла: перекрывает правила появления модалки
   из @media (max-width: 600px) */
@media (prefers-reduced-motion: reduce) {
    .msg-modal-overlay.active,
    .msg-modal-overlay.active .msg-modal {
        animation: none;
    }

    /* Красная точка непрочитанного не мигает, но остаётся заметной */
    .msg-status-dot-unread {
        animation: none;
    }

    /* Карточка, уехавшая в «Новые комментарии», не подсвечивается */
    .msg-card-live-new {
        animation: none;
    }
}

/* ========== Дополнения ==========
   Блок намеренно в конце файла (как «Пониженная анимация» выше): правки в
   середине сдвигали бы номера строк, на которые ссылается docs/INDEX.md. */

/* «Всего заставок: N» на странице «Мои заставки» — по правому краю.
   .section-head — flex с justify-content: space-between, но подпись в нём
   одна, поэтому по умолчанию она прижимается влево; модификатор is-end
   разворачивает строку вправо (шаблон templates/screensaver/index.php). */
.section-head.is-end {
    justify-content: flex-end;
}

/* «Живой» статус монитора — карточка кабинета и шапка страницы /monitors/{id}
   (Monitor::onlineStatus, templates/partials/monitor_live.php): бейдж
   Online/Offline и таймер «Активен:/Отключен:», которые меняются без
   перезагрузки страницы. Бейджи парные к badge-active/badge-inactive
   (секция 7, строка 1108), но с явными цветами «на связи»/«нет связи». */
.badge-online {
    background: var(--ok-soft);
    color: var(--ok);
}

.badge-offline {
    background: var(--danger-soft);
    color: #a3213a;
}

/* Таймер: цифры не «пляшут» при смене значения (tabular-nums), цвет — по
   состоянию. data-online на сам таймер ставит и сервер, и скрипт. */
[data-monitor-timer] {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}

[data-monitor-timer][data-online="1"] {
    color: var(--ok);
}

[data-monitor-timer][data-online="0"] {
    color: #a3213a;
}

/* Монитор без связи: карточка больше не бледнеет (прежнее правило
   .monitor-card.is-offline { opacity: 0.85 } — секция 10, строка 1363 —
   оставлено на месте, чтобы не сдвигать номера строк). Вместо бледности
   красная полоса слева: inset-тень не сдвигает содержимое карточки при
   живом переключении Online → Offline. */
.monitor-card.is-offline {
    opacity: 1;
    box-shadow: inset 3px 0 0 var(--danger), var(--shadow-xs);
}

/* Точка «на связи / не на связи» перед UID монитора на странице «Отправить
   сообщение» (templates/send.php, окно «Выберите мониторы»): зелёная — монитор
   отвечает серверу, красная — молчит (или отключён на сайте). Считает
   Monitor::onlineStatus при загрузке страницы, порог — 20 с.
   Обёртка .monitor-uid держит точку и UID рядом: в .checkbox-label (flex) у
   code стоит margin-left: auto (строка 1023) — без обёртки точка уехала бы к
   левому краю, а UID остался бы справа. */
.monitor-uid {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
}

.monitor-dot {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--border-strong);
}

.monitor-dot.is-online {
    background: var(--ok);
}

.monitor-dot.is-offline {
    background: var(--danger);
}


/* Предупреждение «превышен лимит отправки сообщений в час» на странице
   «Отправить сообщение» (templates/send.php): та же красная плашка .errors
   (строка 643), но с обратным отсчётом до конца лимита — сколько осталось до
   начала следующего часа. Когда отсчёт дошёл до нуля, блок зеленеет: лимит
   снят, можно отправлять снова (скрипт там же ставит класс .is-expired). */
.limit-notice {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 8px;
    border-top: 1px dashed #f5c8ce;
    padding-top: 9px;
    margin-top: 9px !important;   /* .errors p:last-child обнуляет отступ снизу */
}

.limit-countdown {
    display: inline-block;
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;   /* цифры не «прыгают» при отсчёте */
    font-size: 1.02em;
    font-weight: 700;
    color: #8f1f2f;
    background: rgba(255, 255, 255, 0.7);
    border: 1px solid #f5c8ce;
    border-radius: 6px;
    padding: 1px 8px;
}

.limit-notice.is-expired {
    color: var(--ok);
    border-top-color: #c3e7d1;
}

.limit-notice.is-expired .limit-countdown {
    color: var(--ok);
    background: var(--ok-soft);
    border-color: #c3e7d1;
}

/* Кнопка-иконка «Скачать приложение для Android» — сразу справа от блока
   логотипа в шапке (разметка: templates/layout.php). Высота картинки задана
   числом, а не var(--header-h): логотип ниже шапки, и кнопка равняется именно
   по нему (проверено в браузере: блок логотипа 43px на компьютере и 30px на
   телефоне). Файл приложения лежит в веб-корне —
   puponki/public/downloads/app-debug.apk; отдаёт его веб-сервер, а если запрос
   всё-таки доходит до роутера — public/index.php. */
.header-download {
    display: inline-flex;
    align-items: center;
    flex: none;
    padding: 4px;
    border-radius: var(--radius-xs);
    transition: background 0.15s, transform 0.15s;
}

.header-download img {
    display: block;
    height: 40px;
    width: auto;
}

.header-download:hover {
    background: var(--surface-3); /* фон — как у пунктов меню в шапке */
}

.header-download:active {
    transform: scale(0.95);
}

/* На телефоне (секция 14) логотип мельче — кнопка уменьшается вместе с ним */
@media (max-width: 760px) {
    .header-download {
        padding: 2px;
    }

    .header-download img {
        height: 30px;
    }
}

/* ========== Код активации монитора (templates/monitors/show.php) ==========
   Карточка «🔑 Доступ и данные для Wemos»: «плашка» из 5 цифр — единственное,
   что владелец переносит в AP-портал платы. Раньше там стояли API Key и
   Server URL: их вводили в AP-портале вручную. Теперь по коду плата получает
   Monitor UID, ключ и адрес сервера с сервера сама
   (POST /api/monitor/activate), а три значения уехали в свёрнутый блок
   «Данные для ручной настройки» (.monitor-manual).

   Секция дописана в конец файла (02.10.2026) намеренно: так она не сдвигает
   номера строк прежних правил, которые указаны в docs/INDEX.md. */
.activation-code {
    display: inline-block;
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0.25em;
    padding: 8px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    user-select: all;
}

.monitor-manual {
    margin-top: 14px;
    border-top: 1px solid var(--border);
    padding-top: 12px;
}

.monitor-manual > summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--text-2);
    list-style: none;
    user-select: none;
}

.monitor-manual > summary::-webkit-details-marker { display: none; }

.monitor-manual > summary::before {
    content: '▸';
    display: inline-block;
    margin-right: 6px;
    color: var(--text-3);
    transition: transform 0.15s;
}

.monitor-manual[open] > summary::before { transform: rotate(90deg); }

.monitor-manual > summary:hover { color: var(--text); }

.monitor-manual .def-list { margin-top: 10px; }

/* ========== Панель ленты «Показать / Сортировка» ==========
   Ссылки-переключатели под шапкой ленты (templates/feed/index.php, владелец,
   03.10.2026): «Все / Мои» и «По дате / По имени». Это обычные ссылки с
   GET-параметрами — роут /feed (public/index.php) читает их и отдаёт нужный
   набор (Message::getFeedForUser), страница перезагружается в нужном режиме.
   Секция дописана в конец файла намеренно: так она не сдвигает номера строк
   прежних правил, которые указаны в docs/INDEX.md. */
.feed-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 22px;
    margin: -4px 0 6px;
}

.feed-control-group {
    display: flex;
    align-items: center;
    gap: 6px;
}

.feed-control-label {
    color: var(--text-3);
    font-size: 0.85rem;
}

.feed-control {
    padding: 3px 12px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-2);
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.4;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.feed-control:hover {
    background: var(--surface-3);
    color: var(--text);
    text-decoration: none;
}

.feed-control.is-active {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
}

/* ========== Кнопки карточки: порядок и «включённая ⭐» ==========
   (владелец, 03.10.2026; templates/partials/feed_card.php)

   Порядок кнопок в верхнем углу карточки один на всех страницах: крайняя
   справа — всегда ⭐ «в заставки», левее 🗑 удалить, ещё левее 📰 «лента», а
   первым — ↗ «переслать». Задают его не номера строк в разметке (у ⭐ в
   кабинете, ленте и на «Моих заставках» разное место), а flex-порядок:
   .msg-card-toolbar 1805 — position: absolute + display: flex. */
.msg-card-toolbar .msg-tool-forward { order: 1; }
.msg-card-toolbar .msg-tool-feed { order: 2; }
.msg-card-toolbar .msg-tool-delete { order: 3; }
.msg-card-toolbar .msg-tool-screensaver { order: 4; }

/* Сообщение уже лежит в моих заставках (⭐ включена): панель кнопок такой
   карточки видна всегда, а не только под курсором — активная звезда читается
   без наведения (класс .is-pinned ставит feed_card.php, $pinToolbar). На
   странице «Мои заставки» класса нет: там активны все звёзды, и постоянно
   показанные панели загораживали бы карточки.

   Внутри такой панели видна ТОЛЬКО ⭐ (владелец, 02.10.2026): остальные
   кнопки (↗ / 📰 / 🗑) прячутся до наведения на карточку — ровно как у
   обычной карточки прячется вся панель. Прячем через visibility, а не
   opacity: невидимая кнопка не должна ловить клик. Место в панели кнопки
   сохраняют, поэтому ⭐ при наведении не сдвигается. */
.msg-card-toolbar.is-pinned {
    opacity: 1;
    pointer-events: auto;
}

.msg-card-toolbar.is-pinned .msg-tool-forward,
.msg-card-toolbar.is-pinned .msg-tool-feed,
.msg-card-toolbar.is-pinned .msg-tool-delete {
    visibility: hidden;
}

.msg-card:hover .msg-card-toolbar.is-pinned .msg-tool-forward,
.msg-card:hover .msg-card-toolbar.is-pinned .msg-tool-feed,
.msg-card:hover .msg-card-toolbar.is-pinned .msg-tool-delete,
.msg-card:focus-within .msg-card-toolbar.is-pinned .msg-tool-forward,
.msg-card:focus-within .msg-card-toolbar.is-pinned .msg-tool-feed,
.msg-card:focus-within .msg-card-toolbar.is-pinned .msg-tool-delete {
    visibility: visible;
}

/* На тач-устройствах наведения нет: панель показана всегда (правило
   @media (pointer: coarse) выше, style.css 2612), значит и все её кнопки
   должны быть видны — иначе ↗ / 📰 / 🗑 остались бы недоступны. */
@media (pointer: coarse) {
    .msg-card-toolbar.is-pinned .msg-tool-forward,
    .msg-card-toolbar.is-pinned .msg-tool-feed,
    .msg-card-toolbar.is-pinned .msg-tool-delete {
        visibility: visible;
    }
}

/* ========== 15. Мессенджер (/messages) ==========
   (владелец, 02.10.2026; этап «картинки и цвета» — 03.10.2026;
   templates/messenger/index.php)

   Личная переписка пользователей: слева список переписок, справа окно чата.
   Высота ограничена экраном — прокручиваются список и переписка, а не вся
   страница. На телефоне (<= 900px) экраны меняются, как в привычных чатах:
   сначала список переписок, при открытой (класс .is-chat-open) — только чат во
   всю высоту, кнопкой «←» в шапке (правила в конце секции). */

.messenger {
    display: grid;
    grid-template-columns: 320px minmax(0, 1fr);
    gap: 16px;
    align-items: start;
}

.messenger-side,
.messenger-main {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-xs);
}

.messenger-side {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 12px;
    max-height: calc(100vh - 220px);
}

.messenger-main {
    display: flex;
    flex-direction: column;
    min-height: 420px;
    max-height: calc(100vh - 220px);
    overflow: hidden;
}

/* --- Мой профиль: аватарка, имя и карандаш (владелец, 03.10.2026, пункт 3) ---
   В левой колонке над кнопкой «➕ Добавить пользователя»: круг с аватаркой
   (44px — привычный размер аватарки в мессенджерах), имя пользователя и
   карандаш справа. Карандаш виден только при наведении на строку профиля
   (и всегда на тач-устройствах — там наведения нет, см. @media ниже).
   Карандаш открывает окно профиля #chatProfile. */
/* Блок профиля — целиком активное поле (владелец, 04.10.2026: окно профиля
   открывается нажатием на аватарку, имя и «···»), поэтому и курсор, и лёгкая
   подсветка при наведении: видно, что нажать можно в любое место */
.messenger-me {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 8px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: border-color 0.15s;
}

.messenger-me:hover {
    border-color: var(--accent);
}

.messenger-avatar {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    overflow: hidden;
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--accent-600);
    text-transform: uppercase;
    background: var(--accent-soft);
    border-radius: 50%;
}

.messenger-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.messenger-me-name {
    flex: 1 1 auto;
    overflow: hidden;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Значок «···» — вместо карандаша (владелец, 04.10.2026). Владелец, 04.10.2026
   (уточнение к пунктам 2 и 3): «у трех точек не должно быть отдельного круглого
   фона. Они появляются как декор при наведении», а нажимать их не нужно —
   нажимается само поле (слева — профиль, в шапке чата — имя контакта). Поэтому у
   значка нет ни фона, ни круглой подложки, ни своего наведения: только появление
   и исчезновение (opacity) с серыми точками. В разметке это <span
   class="messenger-edit" aria-hidden="true">···</span> — без title и без
   обработчика (templates/messenger/index.php). */
.messenger-edit {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    padding: 0;
    /* Три средние точки (U+00B7): есть в любом шрифте и, в отличие от «…»,
       рисуются посередине строки — значок не «съезжает» вниз */
    font-size: 18px;
    line-height: 1;
    color: var(--text-3);
    cursor: inherit;   /* значок — украшение: курсор берётся у поля под ним */
    background: transparent;
    border: 0;
    opacity: 0;
    transition: opacity 0.15s;
}

/* Появляется при наведении на своё поле: слева — на весь блок профиля, в шапке
   чата — на имя контакта (владелец: «появляются только во время наведения на имя
   контакта»). Селектор .messenger-edit:hover держит значок видимым, пока курсор
   скользит по нему самому: без него точки мигали бы в зазоре между именем и
   значком. Фона и подсказки у значка нет ни в одном состоянии. */
.messenger-me:hover .messenger-edit,
.messenger-peer:hover ~ .messenger-edit,
.messenger-edit:hover {
    opacity: 1;
}

/* Телефон/планшет: наведения нет — значок «···» показываем всегда (как крестик
   удаления сообщения ниже, .chat-msg-del) */
@media (pointer: coarse) {
    .messenger-edit {
        opacity: 1;
    }
}

/* Логин рядом с отредактированным именем — серым (владелец, 03.10.2026,
   пункт 2: «Отредактированное имя (логин контакта, серым цветом)») */
.messenger-peer-login {
    flex: none;
    font-size: 0.9rem;
    color: var(--text-3);
}

/* Поле переименования контакта: по карандашу встаёт вместо имени */
.messenger-peer-form {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 6px;
    margin-left: auto;
}

.messenger-peer-form .messenger-add-input {
    flex: 1 1 auto;
    min-width: 0;
}

/* Пока идёт переименование, в шапке остаётся только поле с кнопками — ни группа
   с именем, ни «личная переписка», ни 🗑 (удалять контакт во время правки имени
   незачем) */
.messenger-head.is-editing .messenger-peer-box,
.messenger-head.is-editing .messenger-peer-kind,
.messenger-head.is-editing .messenger-peer-del {
    display: none;
}

/* --- Поиск собеседника: поиск по своим контактам и «+» (владелец, 04.10.2026) ---
   Вместо кнопки «➕ Добавить пользователя» над списком стоит поле поиска по уже
   добавленным контактам (оно фильтрует список на месте, без запросов — скрипт
   шаблона), а справа — крупный серый «+» БЕЗ рамки и фона (раньше на его месте
   был такой же крестик).
   По нажатию крестика НА МЕСТЕ поиска раскрывается поле ДРУГОГО цвета для поиска
   НОВЫХ пользователей сервера (GET /api/chat/users?only_new=1&limit=10): класс
   .is-new на .messenger-find гасит первое поле и показывает второе, поэтому
   раскрытое поле ровно совпадает по размерам с поиском по контактам — у обоих
   одни и те же классы (.messenger-add-input + .messenger-find-input), а
   .messenger-new-input только красит его в другой цвет. Клик вне поля (в любом
   другом месте) сворачивает его обратно в поиск по контактам. */
.messenger-find {
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Размеры поля поиска — общие для обоих полей (по своим контактам и новых):
   вид берётся у .messenger-add-input, здесь только «растягиваться по строке» */
.messenger-find-input {
    flex: 1 1 auto;
    min-width: 0;
}

/* Раскрыт поиск новых — поиск по своим контактам уступает ему место (display,
   а не ширина: раскрытое поле должно занимать строку ЦЕЛИКОМ). Стрелка «>» тут
   обязательна: класс .messenger-find-input есть у ОБОИХ полей, и без неё
   правило спрятало бы и раскрытое поле (оно лежит глубже, в .messenger-new). */
.messenger-find.is-new > .messenger-find-input {
    display: none;
}

.messenger-new {
    display: none;
    flex: 1 1 auto;
    min-width: 0;
}

.messenger-find.is-new > .messenger-new {
    display: flex;
    animation: messenger-find-in 0.18s ease;
}

/* Поле новых собеседников отличается ТОЛЬКО цветом: размеры те же, что у
   поиска по контактам (класс .messenger-find-input у обоих). Селектор из двух
   классов, потому что .messenger-add-input объявлен ниже в файле и иначе
   перекрасил бы поле обратно в обычный фон */
.messenger-new .messenger-new-input {
    background: var(--accent-soft);
    border-color: var(--accent);
}

@keyframes messenger-find-in {
    from {
        opacity: 0;
        transform: translateX(10px);   /* поле будто выезжает влево на место поиска */
    }
}

/* Значок «добавить контакт» — крупный серый «+» без рамки и фона (владелец,
   04.10.2026: он заменил такой же по виду крестик). Размер шрифта больше, чем был
   у «✕»: у «+» значок занимает меньше места в строке, и при 22px он выглядел бы
   заметно мельче прежнего крестика.
   Владелец, 04.10.2026 (пункт 4): «у иконки "плюс" не должно быть круглого фона,
   только смена цвета». Поэтому фон и рамку гасим явно и при наведении: у общего
   правила сайта («button:hover» в разделе 5) свой фон есть, и без этого знак
   всплывал бы светлым кружком. */
.messenger-cross {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    /* Общее правило кнопки задаёт min-height 38px — знаку он не нужен: иначе «+»
       стоял бы вытянутым прямоугольником 34×38 (владелец, пункт 4: «только смена
       цвета») */
    min-height: 0;
    padding: 0;
    font-size: 28px;
    line-height: 1;
    color: var(--text-3);
    cursor: pointer;
    background: transparent;
    border: 0;
    border-radius: var(--radius-xs);   /* нужен только рамке фокуса: фона нет */
    transition: color 0.15s;
}

.messenger-cross:hover,
.messenger-cross.is-open {
    color: var(--accent-600);
    background: transparent;
    border-color: transparent;
}

.messenger-cross:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Найденные новые собеседники — сразу под полем; их не больше
   UserChat::NEW_USERS_LIMIT (10), поэтому высоту ограничиваем и прокручиваем */
.messenger-new-results {
    max-height: 244px;
    overflow-y: auto;
}

/* Поле поиска вне формы (form input[…] его не покрывает) — вид тот же */
.messenger-add-input {
    display: block;
    width: 100%;
    padding: 10px 12px;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xs);
    transition: border-color 0.15s, box-shadow 0.15s;
}

.messenger-add-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: var(--ring);
}

.messenger-add-results {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.messenger-user {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    font-family: inherit;
    font-size: 0.9rem;
    color: var(--text);
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-xs);
    cursor: pointer;
}

/* Кружок найденного пользователя (и в окне «Переслать пользователю»):
   меньше, чем в списке переписок — список результатов компактнее */
.messenger-user-avatar {
    width: 28px;
    height: 28px;
    font-size: 0.8rem;
}

.messenger-user-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.messenger-user:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.messenger-user:disabled {
    opacity: 0.6;
    cursor: default;
}

/* --- Список переписок --- */
.messenger-chats {
    display: flex;
    flex-direction: column;
    gap: 6px;
    overflow-y: auto;
}

.messenger-none {
    margin: 0;
}

/* Строка списка: слева кружок собеседника, справа две строки текста
   (имя + время, последнее сообщение + счётчик) — владелец, 04.10.2026, пункт 2 */
.messenger-chat {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px;
    color: inherit;
    text-decoration: none;
    background: var(--surface-2);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
}

/* Наведение: подсвечиваем фон, текст НЕ подчёркиваем. Подчёркивание приходило
   от глобального «a:hover» (style.css 94): пункт списка — ссылка, поэтому
   подчёркивались имя, последнее сообщение и время (владелец, 03.10.2026).
   Правило с :hover перебивает «a:hover» по специфичности. */
.messenger-chat:hover {
    background: var(--surface-3);
    border-color: var(--border-strong);
    text-decoration: none;
}

.messenger-chat.is-active {
    background: var(--accent-soft);
    border-color: var(--accent);
}

/* Кружок собеседника в списке: аватарка или первая буква имени (владелец,
   04.10.2026, пункт 2). Чуть меньше, чем в блоке профиля */
.messenger-chat-avatar {
    width: 40px;
    height: 40px;
    font-size: 1rem;
}

/* Текстовая часть строки: имя со временем и последнее сообщение со счётчиком
   (min-width: 0 — иначе длинное имя не даёт себя обрезать) */
.messenger-chat-main {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.messenger-chat-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

.messenger-chat-name {
    font-weight: 600;
}

.messenger-chat-time {
    font-size: 12px;
    color: var(--text-3);
    white-space: nowrap;
}

.messenger-chat-bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.messenger-chat-last {
    overflow: hidden;
    font-size: 13px;
    color: var(--text-2);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.messenger-chat-unread {
    flex: none;
    min-width: 20px;
    padding: 1px 6px;
    font-size: 12px;
    font-weight: 600;
    text-align: center;
    color: #ffffff;
    background: var(--accent);
    border-radius: 999px;
}

/* --- Окно чата --- */
.messenger-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 16px;
    background: var(--surface-2);
    border-bottom: 1px solid var(--border);
}

/* Кнопка «←» к списку переписок: на широком экране не нужна (список рядом с
   чатом), показывается только на телефоне — см. @media (max-width: 900px) */
.messenger-back {
    display: none;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    font-size: 18px;
    line-height: 1;
    color: var(--text);
    text-decoration: none;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
}

.messenger-back:hover {
    color: var(--accent);
    text-decoration: none;   /* «a:hover» подчёркивал бы стрелку «←» */
    border-color: var(--accent);
}

/* Имя контакта — единственное, что нажимается в шапке (владелец, 04.10.2026,
   пункт 2: логин в скобках и «···» не должны «реагировать на нажатие»), поэтому
   курсор и подсветка синим — как у всего нажимаемого на сайте. Открывает поле
   переименования; с клавиатуры — tabindex + Enter (разметка и скрипт шаблона). */
.messenger-peer {
    font-size: 1rem;
    cursor: pointer;
    transition: color 0.15s;
}

.messenger-peer:hover,
.messenger-peer:focus-visible {
    color: var(--accent-600);
}

/* Имя, логин и «···» — одной группой СЛЕВА (владелец, 04.10.2026: раньше эти
   подписи растягивались по всей шапке большими отступами). Шапка — flex, поэтому
   группа стоит слева, а «личная переписка» и 🗑 уезжают вправо (margin-left: auto).
   Нажимается в группе только имя (.messenger-peer выше) — у самой группы ни
   курсора, ни обработчика: клик по логину и по «···» не делает ничего
   (владелец, 04.10.2026, пункт 2). */
.messenger-peer-box {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* Длинное имя обрезается, чтобы карандаш и «личная переписка» остались на месте */
.messenger-peer-box .messenger-peer {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* «Личная переписка» — к правому краю строки */
.messenger-peer-kind {
    flex: none;
    margin-left: auto;
}

/* 🗑 — удалить контакт (владелец, 04.10.2026, пункт 3): справа от «личная
   переписка». Виден всегда, как и «···»: наводить в шапке не на что. Наведение
   подкрашивает значок красным — тем же цветом, что у крестика удаления
   комментария (.msg-comment-del): «удаляющее» везде выглядит одинаково.
   По нажатию открывается окно с предупреждением (.chat-modal). */
.messenger-peer-del {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    /* Как у «✕» и «+»: у общего правила кнопки min-height 38px, от него значок
       вытягивался в 26×38 — круг при наведении получался овалом */
    min-height: 0;
    padding: 0;
    font-size: 14px;
    line-height: 1;
    color: var(--text-3);
    cursor: pointer;
    background: transparent;
    border: 0;
    border-radius: 50%;
    transition: color 0.15s, background 0.15s;
}

.messenger-peer-del:hover {
    color: var(--danger);
    background: var(--danger-soft);
}

.messenger-peer-del:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.messenger-body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 10px;
    padding: 16px;
    overflow-y: auto;
    background: var(--bg-soft);
}

/* Пузырь сообщения: чужое слева, своё справа (класс .is-mine ставит
   templates/partials/chat_messages.php по sender_id) */
.chat-msg {
    /* Крестик удаления (.chat-msg-del) позиционируется по сообщению, а не по
       переписке: он стоит у верхнего правого угла пузыря */
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    max-width: 78%;
    /* На сколько подпись (имя/время) сдвинута от края пузыря, чтобы встать по
       краю ЕГО ТЕКСТА: 12px отступ пузыря + 1px его рамка. Своё значение —
       у смайликов и картинок (см. ниже). */
    --msg-inset: 13px;
}

.chat-msg.is-mine {
    align-self: flex-end;
    align-items: flex-end;
}

/* Имя отправителя и время выравниваются по КРАЮ ТЕКСТА пузыря, а не по краю
   самого пузыря (владелец, 03.10.2026, пункт 1: «имя отправителя и дату
   сдвинуть правее и выровнять с началом входящего текста», а у своих — по
   концу своего текста). Сдвиг — переменная --msg-inset (см. .chat-msg выше):
   у текстового пузыря 13px, у смайликов 5px, у картинки 0. */
.chat-msg.is-emoji-msg {
    --msg-inset: 5px;    /* 4px отступ пузыря + 1px рамка */
}

.chat-msg.is-pic-msg {
    --msg-inset: 0;      /* у картинки ни рамки, ни отступов */
}

.chat-msg-author {
    padding-left: var(--msg-inset);
    font-size: 12px;
    color: var(--text-3);
}

/* Цвет пузыря = «получатель уже видел?» (владелец, 03.10.2026): синий —
   базовый (и свои, и чужие сообщения), СВОЁ светло-серое (.is-unread), пока
   собеседник его не открыл. Класс ставит chat_messages.php по границе
   прочтения собеседника (UserChat::othersLastReadMessageId); страница снимает
   его по peer_last_read_id из ответов /api/chat/*. */
.chat-msg-bubble {
    padding: 8px 12px;
    color: #ffffff;
    word-break: break-word;
    background: var(--accent);
    border: 1px solid var(--accent);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-xs);
}

.chat-msg.is-mine .chat-msg-bubble {
    color: #ffffff;
    background: var(--accent);
    border-color: var(--accent);
}

/* Своё сообщение, которого получатель ещё не видел: светло-серый фон. Правило
   идёт ПОСЛЕ «.chat-msg.is-mine .chat-msg-bubble» — иначе его синий фон победил
   бы по специфичности. «Синеет» пузырь сам: опрос каждые 3 секунды приносит
   границу прочтения собеседника, и скрипт снимает класс (applyPeerRead). */
.chat-msg-bubble.is-unread,
.chat-msg.is-mine .chat-msg-bubble.is-unread {
    color: var(--text);
    background: #dde3ec;
    border-color: #cfd7e3;
}

/* Сообщение из одних смайликов (до трёх) показываем крупно — как чаты на
   телефоне. Класс .is-emoji ставит templates/partials/chat_messages.php
   через UserChat::isEmojiOnly. Фона у смайликов нет (владелец, 03.10.2026:
   «фон должен быть только у сообщений»), поэтому правило идёт после
   «.chat-msg.is-mine .chat-msg-bubble» и снимает его синий фон тоже. */
.chat-msg-bubble.is-emoji,
.chat-msg.is-mine .chat-msg-bubble.is-emoji {
    padding: 0 4px;
    font-size: 32px;
    line-height: 1.2;
    color: inherit;
    background: transparent;
    border-color: transparent;
    box-shadow: none;
}

/* --- Картинка в переписке (этап «картинки», владелец 03.10.2026) ---
   Владелец, 03.10.2026: у картинки НЕ должно быть рамки и «выглядывающего» из
   под неё синего фона пузыря. Поэтому пузырь-картинка прозрачный, без рамки и
   без отступов, а мини-кнопки лежат ПОВЕРХ картинки (раньше под ней была
   зарезервированная полоса высотой 26px — из неё и «выглядывал» фон). Подпись
   (.chat-msg-caption) должна читаться на светлом фоне — поэтому цвет текста у
   пузыря-картинки обычный, а не белый из базового правила. Пропорции храним
   «как есть» (никаких чёрных полей формата монитора). */
.chat-msg-bubble.is-pic {
    padding: 0;
    color: var(--text);
    background: transparent;
    border: 0;
    box-shadow: none;
}

.chat-msg-pic {
    position: relative;   /* мини-кнопки позиционируются по картинке */
    max-width: 300px;
}

.chat-msg-pic img {
    display: block;
    width: auto;
    max-width: 100%;
    max-height: 260px;
    cursor: zoom-in;
    border: 0;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-xs);
}

/* Мини-кнопки на картинке: появляются при наведении в ЛЕВОМ НИЖНЕМ углу самой
   картинки (владелец, 03.10.2026), на тачскрине видны сразу. Выглядят строго:
   тёмная полупрозрачная плашка с белой пиктограммой — читается на любой
   картинке, в отличие от прежних светлых кнопок «в рамочке». */
.chat-msg-pic-tools {
    position: absolute;
    left: 8px;
    bottom: 8px;
    display: flex;
    gap: 6px;
    opacity: 0;
    transition: opacity 0.15s;
}

.chat-msg-pic:hover .chat-msg-pic-tools,
.chat-msg-pic:focus-within .chat-msg-pic-tools {
    opacity: 1;
}

@media (hover: none) {
    .chat-msg-pic-tools {
        opacity: 1;
    }
}

.chat-pic-tool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    font-size: 14px;
    line-height: 1;
    color: #ffffff;
    cursor: pointer;
    background: rgba(17, 24, 39, 0.62);
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: 9px;
    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.35);
    transition: background 0.15s, border-color 0.15s;
}

.chat-pic-tool:hover {
    background: var(--accent);
    border-color: var(--accent);
}

.chat-pic-tool:focus-visible {
    outline: 2px solid #ffffff;
    outline-offset: 1px;
}

.chat-pic-tool:disabled {
    opacity: 0.6;
    cursor: default;
}

/* Подпись под картинкой — текст самого сообщения */
.chat-msg-caption {
    margin-top: 6px;
    font-size: 0.95rem;
    color: inherit;
}

.chat-msg-time {
    padding: 0 var(--msg-inset);
    font-size: 11px;
    color: var(--text-3);
}

/* Свои сообщения: дата — по КОНЦУ своего текста (владелец, 03.10.2026,
   пункт 1), поэтому левый сдвиг снимаем, правый оставляем */
.chat-msg.is-mine .chat-msg-time {
    padding-left: 0;
}

/* --- Крестик «удалить сообщение» (владелец, 04.10.2026, пункт 4) ---
   Маленький серый крестик справа сверху НАД сообщением: появляется при наведении
   на сообщение и исчезает, когда курсор ушёл. Виден только у СВОИХ сообщений —
   разметку рисует templates/partials/chat_messages.php, а сервер чужое сообщение
   удалить не даёт (POST /api/chat/message-delete).
   Владелец, 04.10.2026 (пункт 5): «у крестика тоже не должно быть круглого фона,
   только смена цвета с серого на синий», и он «должен находиться немного выше
   правого верхнего угла сообщения, чтобы не перекрывать сообщение». Поэтому фон,
   рамка, тень и круглая подложка убраны — остался только сам знак «✕», при
   наведении он синеет (--accent), а смещение стало выше: top: -18px вместо -9px
   (было видно, что белый кружок лежит на тексте пузыря). -18px подобран так,
   чтобы знак оставался выше текста и в «мышином» размере (22px), и в телефонном
   (@media 900px: 26px) — там знак крупнее и от -16px краем заходил на строку.
   visibility (а не только прозрачность): невидимая кнопка не должна ловить клик. */
.chat-msg-del {
    position: absolute;
    top: -18px;
    right: -12px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    /* У общих правил кнопки (раздел 5) min-height 38px — знаку он не нужен: без
       этой строки «✕» вытягивался в 22×38 и налезал на текст пузыря (владелец,
       пункт 5: «чтобы не перекрывать сообщение») */
    min-height: 0;
    padding: 0;
    font-size: 12px;
    line-height: 1;
    color: var(--text-3);
    cursor: pointer;
    visibility: hidden;
    background: transparent;
    border: 0;
    border-radius: var(--radius-xs);   /* нужен только рамке фокуса: фона нет */
    opacity: 0;
    transition: color 0.15s, opacity 0.15s;
}

.chat-msg:hover .chat-msg-del,
.chat-msg:focus-within .chat-msg-del,
.chat-msg-del:focus-visible {
    visibility: visible;
    opacity: 1;
}

/* Наведение — только цвет, серый → синий (владелец, пункт 5). Фон гасим явно:
   у общего правила «button:hover» он есть, и без этого знак всплывал бы светлым
   квадратом. */
.chat-msg-del:hover {
    color: var(--accent);
    background: transparent;
}

.chat-msg-del:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

/* Телефон/планшет: наведения нет — крестик виден всегда, как мини-кнопки у
   картинки в переписке (.chat-msg-pic-tools) */
@media (hover: none) {
    .chat-msg-del {
        visibility: visible;
        opacity: 1;
    }
}

.messenger-start {
    margin: 0;
}

/* --- Поле ввода: во всю ширину, кнопки внутри (владелец, 03.10.2026) ---
   Раньше кнопки 😀/📎 и «Отправить» стояли рядом с textarea и отнимали у неё
   ширину, а сам ввод был узкой коробкой. Теперь это одна строка во всю ширину
   окна: слева внутри — смайлики и картинка, справа — «отправить», а рамку
   рисует сам .messenger-field (у textarea своей рамки и фона нет).
   Высота: одна строка; при фокусе поле приподнимается на строку вверх (там и
   начинается набор), дальше растёт по мере набора — считает скрипт шаблона
   (fitInput), после шести строк текст прокручивается внутри поля.
   Глобальные «form textarea» (style.css 909, 925) перебиваются по
   специфичности: у поля ввода здесь нет ни рамки, ни фона, ни resize. */
.messenger-composer {
    position: relative;   /* панель смайликов открывается поверх переписки */
    z-index: 20;
    display: block;
    padding: 10px 14px;
    background: var(--surface);
    border-top: 1px solid var(--border);
}

.messenger-field {
    position: relative;
    display: flex;
    align-items: flex-end;
    gap: 4px;
    padding: 4px 6px;
    background: var(--surface-2);
    border: 1px solid var(--border-strong);
    border-radius: 22px;
    transition: border-color 0.15s, box-shadow 0.15s;
}

.messenger-field:focus-within {
    border-color: var(--accent);
    box-shadow: var(--ring);
}

/* Кнопки внутри поля: круглые и без своей рамки — рамку рисует само поле */
.messenger-field .messenger-emoji-btn {
    width: 38px;
    height: 38px;
    font-size: 19px;
    background: transparent;
    border-color: transparent;
    border-radius: 50%;
}

.messenger-field .messenger-emoji-btn:hover,
.messenger-field .messenger-emoji-btn.is-open {
    background: var(--accent-soft);
    border-color: transparent;
}

.messenger-field textarea {
    flex: 1 1 auto;
    width: 100%;
    min-height: 38px;   /* одна строка: 24px текст + 7px сверху и снизу */
    max-height: none;
    margin: 0;
    padding: 7px 2px;
    font-family: inherit;
    font-size: 15px;
    line-height: 24px;  /* ровно строка: по ней скрипт считает высоту поля */
    color: var(--text);
    background: transparent;
    border: 0;
    border-radius: 0;
    resize: none;       /* росло само, без «уголка» для растягивания мышью */
    overflow-y: hidden;
}

.messenger-field textarea:focus {
    outline: none;
    border-color: transparent;
    box-shadow: none;
}

/* «Отправить» — круглая кнопка внутри поля. Текста в ней нет, поэтому в
   разметке есть title и aria-label (шаблон templates/messenger/index.php) */
.messenger-send {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    padding: 0;
    font-size: 17px;
    line-height: 1;
    color: #ffffff;
    cursor: pointer;
    background: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 50%;
    transition: background 0.15s, border-color 0.15s;
}

.messenger-send:hover {
    background: var(--accent-600);
    border-color: var(--accent-600);
}

.messenger-send:disabled {
    opacity: 0.55;
    cursor: default;
}

/* --- Смайлики: кнопка 😀 и панель групп (partials/chat_emoji_picker.php) ---
   Панель открывается ВВЕРХ от кнопки: окно чата стоит внизу экрана, вниз ей
   места нет. Высоту ограничиваем — .messenger-main обрезает всё лишнее по
   overflow: hidden, а длинные группы прокручиваются внутри панели. */
.messenger-emoji {
    position: relative;
    flex: none;
}

.messenger-emoji-btn {
    display: block;
    width: 44px;
    height: 44px;
    padding: 0;
    font-size: 22px;
    line-height: 1;
    color: var(--text);
    cursor: pointer;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xs);
    transition: border-color 0.15s, background 0.15s;
}

.messenger-emoji-btn:hover,
.messenger-emoji-btn.is-open {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.emoji-picker {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: 6px;
    width: 320px;
    max-width: calc(100vw - 48px);
    max-height: 232px;
    padding: 8px;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
}

.emoji-tabs {
    display: flex;
    flex: none;
    gap: 2px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border);
}

.emoji-tab {
    width: 30px;
    height: 30px;
    padding: 0;
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-xs);
}

.emoji-tab:hover {
    background: var(--surface-3);
}

.emoji-tab.is-active {
    background: var(--accent-soft);
    border-color: var(--accent);
}

.emoji-groups {
    flex: 1 1 auto;
    overflow-y: auto;
}

/* Открыта одна группа за раз (data-group ↔ data-tab) */
.emoji-group {
    display: none;
    flex-wrap: wrap;
    gap: 2px;
    align-content: flex-start;
}

.emoji-group.is-active {
    display: flex;
}

/* «Часто используемые» пока пусты — не видно ни вкладки, ни группы (скрипт
   снимает класс, когда смайлики появились). Правило идёт после .is-active,
   чтобы перевесить его, если на элементе окажутся оба класса. */
.emoji-tab.is-empty,
.emoji-group.is-empty {
    display: none;
}

.emoji-btn {
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-xs);
}

.emoji-btn:hover {
    background: var(--accent-soft);
    border-color: var(--accent);
}

/* Пустой экран справа, когда переписка не выбрана */
.messenger-empty {
    padding: 40px 20px;
    margin: auto;
    text-align: center;
}

.messenger-empty-icon {
    display: block;
    margin-bottom: 8px;
    font-size: 40px;
}

/* --- Просмотр картинки во весь экран ---
   Владелец: «картинка раскрывается во всплывающем окне в полный размер с
   небольшим увеличением, с чёрным прозрачным затенением фона». Закрывается
   кликом в любом месте и клавишей Esc (скрипт страницы). */
.chat-pic-viewer {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    background: rgba(0, 0, 0, 0.82);
    cursor: zoom-out;
}

/* Картинка показывается в полный размер (как хранится) с небольшим
   увеличением — владелец: «в полный размер с небольшим увеличением».
   Увеличение делаем transform: scale — тогда оно одинаково для любой
   картинки и не ломает пропорции (max-width/max-height только ограничивают
   размер по экрану). */
.chat-pic-viewer img {
    width: auto;
    max-width: min(84vw, 400px);
    max-height: 76vh;
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-lg);
    transform: scale(1.15);
}

/* --- Всплывающие окна мессенджера (пересылка на монитор / пользователю) ---
   Владелец, 03.10.2026: окна «должны стильно затенять фон чёрным прозрачным
   цветом» — поэтому затенение чёрное (раньше было синеватое), плюс лёгкое
   размытие фона. Разметку обоих окон рисует templates/messenger/index.php
   (#chatMonitor и #chatShare), содержимое списков строит скрипт страницы. */
.chat-modal {
    position: fixed;
    inset: 0;
    z-index: 210;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 20px;
    background: rgba(0, 0, 0, 0.68);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
}

.chat-modal-box {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 10px;
    width: 100%;
    max-width: 380px;
    max-height: 82vh;
    padding: 18px;
    overflow-y: auto;
    background: var(--surface);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
}

.chat-modal-box h3 {
    margin: 0;
}

.chat-modal-box .hint {
    margin: 0;
}

.chat-modal-close {
    position: absolute;
    top: 8px;
    right: 10px;
    padding: 0 4px;
    font-size: 22px;
    line-height: 1;
    color: var(--text-3);
    cursor: pointer;
    background: transparent;
    border: 0;
}

.chat-modal-close:hover {
    color: var(--text);
}

/* Список мониторов в окне «Переслать на монитор» */
.chat-modal-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.chat-monitor {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    cursor: pointer;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.chat-monitor:hover {
    border-color: var(--accent);
}

.chat-monitor input {
    flex: none;
    width: 18px;
    height: 18px;
    accent-color: var(--accent);
}

.chat-monitor-name {
    flex: 1 1 auto;
    font-weight: 600;
}

/* Имя владельца — у добавленного чужого монитора («у кого он стоит») */
.chat-monitor-owner {
    flex: none;
    font-size: 0.85rem;
    color: var(--text-3);
}

/* Галочка «📰 Отправить в ленту» в окне пересылки на монитор */
.chat-feed {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    cursor: pointer;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.chat-feed:hover {
    border-color: var(--accent);
}

.chat-feed input {
    flex: none;
    width: 18px;
    height: 18px;
    accent-color: var(--accent);
}

.chat-modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

/* --- Профиль: аватарка и дополнительная информация (окно #chatProfile) ---
   Владелец, 03.10.2026 (пункт 3): по карандашу в блоке профиля слева
   открывается окно с выбором изображения для аватарки и полем
   «дополнительная информация». Само окно — общий .chat-modal, здесь только
   его содержимое. */
.chat-profile-pic {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* Кружок в окне крупнее, чем в списке: по нему сразу видно, что загрузилось */
.messenger-avatar.is-big {
    width: 64px;
    height: 64px;
    font-size: 1.5rem;
}

.chat-profile-pic-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.chat-profile-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.chat-profile-label {
    font-size: 0.9rem;
    color: var(--text-2);
}

/* Поле вне формы (окно профиля — не <form>), поэтому вид задаём сами —
   как у .messenger-add-input */
.chat-profile-field textarea {
    width: 100%;
    padding: 8px 10px;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-xs);
    resize: vertical;
}

.chat-profile-field textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: var(--ring);
}

/* Кнопка 📎 у поля ввода (внешне — как кнопка смайликов) */
.messenger-attach {
    position: relative;
    flex: none;
}

/* Короткое уведомление внизу страницы («отправлено на 2 монитора») */
.messenger-toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    z-index: 210;
    max-width: min(90vw, 420px);
    padding: 10px 16px;
    font-size: 0.9rem;
    color: #ffffff;
    text-align: center;
    background: rgba(27, 35, 51, 0.94);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    transform: translateX(-50%);
}

.messenger-toast.is-error {
    background: var(--danger);
}

/* --- Телефон: два экрана, как в привычных мессенджерах ---
   Владелец, 03.10.2026 («сделай оптимизацию в мобильной версии, чтобы
   мессенджер выглядел и работал удобно и привычно»). Раньше на телефоне внизу
   страницы висели обе колонки сразу: слева список переписок горизонтальной
   полосой, справа окно чата — полоса прокручивалась боком и отнимала место.
   Теперь: переписка не выбрана — показываем только список (вертикальной лентой,
   во всю высоту), переписка открыта (класс .is-chat-open на .messenger) —
   только чат во всю высоту, а к списку возвращает «←» в шапке чата.
   Полезное для пальца: кнопки крупнее, поля 16px (iOS не зумит страницу при
   фокусе), у поля ввода учтена «полоса жестов» (env(safe-area-inset-bottom)). */
@media (max-width: 900px) {
    .messenger {
        grid-template-columns: minmax(0, 1fr);
        gap: 10px;
    }

    .messenger-side {
        max-height: calc(100vh - 210px);
        max-height: calc(100dvh - 210px);
        padding: 10px;
    }

    /* Список переписок — обычной вертикальной лентой, а не полосой боком */
    .messenger-chats {
        flex-direction: column;
        max-height: none;
        overflow-y: auto;
    }

    .messenger-chat {
        flex: none;
        padding: 12px;
    }

    /* Переписка открыта: список прячем — он целиком на экране «/messages» */
    .messenger.is-chat-open .messenger-side {
        display: none;
    }

    /* Переписка не выбрана: пустой экран справа не нужен */
    .messenger:not(.is-chat-open) .messenger-main {
        display: none;
    }

    /* Окно чата: во всю высоту экрана, от шапки до нижней панели. Значение
       считает скрипт шаблона (fitChatHeight) и кладёт в --messenger-chat-h;
       второй calc(...) — запасной вариант, если скрипт не отработал. */
    .messenger-main {
        min-height: 0;
        height: calc(100vh - 220px);
        height: var(--messenger-chat-h, calc(100dvh - 220px));
        max-height: none;
    }

    /* --- Переписка открыта: страница — это только чат (владелец, 03.10.2026) ---
       Заголовок «💬 Сообщения», подзаголовок, кнопка «Отправить на монитор»
       (весь блок .page-head) и подвал только отнимают экран, поэтому на
       телефоне прячем их совсем: окно чата встаёт по верхнему краю сразу под
       меню. Класс is-messenger-chat ставит на <body> public/index.php (шаблон
       layout.php умеет $body_class) — прятать успевает сервер, без мигания. */
    body.is-messenger-chat .page-head,
    body.is-messenger-chat footer {
        display: none;
    }

    /* ...и поле ввода идёт во всю ширину экрана: от края до края, боковые
       отступы страницы оставляем только под «вырез» (safe-area) */
    body.is-messenger-chat main .container {
        padding-left: env(safe-area-inset-left, 0px);
        padding-right: env(safe-area-inset-right, 0px);
    }

    body.is-messenger-chat .messenger-main {
        border-right: 0;
        border-left: 0;
        border-radius: 0;
    }

    /* Отступ страницы под нижнюю панель тут не нужен: окно чата само
       останавливается над панелью (её высоту учитывает fitChatHeight) */
    body.has-tabbar.is-messenger-chat {
        padding-bottom: 0;
    }

    /* Шапка чата: «←» слева, имя рядом, «личная переписка» — справа */
    .messenger-head {
        justify-content: flex-start;
        gap: 10px;
        padding: 8px 10px;
    }

    .messenger-back {
        display: inline-flex;
    }

    /* Имя с логином и карандашом — слева, «личная переписка» — справа
       (её margin-left: auto задан общим правилом .messenger-peer-kind) */
    .messenger-peer-box {
        margin-right: auto;
    }

    .messenger-body {
        padding: 12px 10px;
        overscroll-behavior: contain;
    }

    /* Поле ввода: во всю ширину экрана, кнопки внутри поля; 16px — iOS не
       зумит страницу при фокусе (владелец, 03.10.2026) */
    .messenger-composer {
        padding: 6px;
        padding-bottom: calc(6px + env(safe-area-inset-bottom));
    }

    .messenger-field {
        border-radius: 20px;
    }

    .messenger-field textarea {
        min-height: 40px;
        padding: 8px 2px;
        font-size: 16px;
    }

    /* Кнопки под палец: 40px прямо в поле (поле от них выше ровно на строку
       текста). Пока кнопки стояли рядом с полем, здесь было 42px. */
    .messenger-field .messenger-emoji-btn,
    .messenger-send {
        width: 40px;
        height: 40px;
    }

    /* Поиск собеседника под палец: «+» крупнее, поля 16px — iOS не зумит
       страницу при фокусе (владелец, 04.10.2026) */
    .messenger-cross {
        width: 40px;
        height: 40px;
        font-size: 32px;
    }

    /* Крестик удаления сообщения и 🗑 удаления переписки — под палец: на телефоне
       они видны всегда (крестик — @media (hover: none) выше), поэтому должны быть
       крупнее мышиных 22px и 26px */
    .chat-msg-del {
        width: 26px;
        height: 26px;
        font-size: 14px;
    }

    .messenger-peer-del {
        width: 34px;
        height: 34px;
        font-size: 18px;
    }

    .messenger-find-input {
        padding: 10px 12px;
        font-size: 16px;
    }

    /* Найденный пользователь — строка выше, кружок крупнее */
    .messenger-user {
        padding: 10px;
    }

    .messenger-user-avatar {
        width: 32px;
        height: 32px;
        font-size: 0.9rem;
    }

    .chat-msg {
        max-width: 88%;
    }

    /* Мини-кнопки на картинке — крупнее под палец (видны всегда, см.
       @media (hover: none) выше) */
    .chat-pic-tool {
        width: 36px;
        height: 36px;
        font-size: 16px;
    }

    /* Панель смайликов ниже: окно чата тут во весь экран, и высокая панель
       закрыла бы переписку целиком */
    .emoji-picker {
        max-height: 220px;
    }

    /* Просмотр картинки: с запасом на увеличение (transform: scale(1.15)) */
    .chat-pic-viewer img {
        max-width: 92vw;
        max-height: 74vh;
    }

    /* Окна пересылки на телефоне — почти во всю ширину, с учётом «полосы
       жестов» снизу */
    .chat-modal {
        align-items: flex-end;
        padding: 12px;
        padding-bottom: calc(12px + env(safe-area-inset-bottom));
    }

    .chat-modal-box {
        max-width: none;
        max-height: 78vh;
    }
}

