/* * VidConf — общие стили светлой оболочки (auth/lobby/calendar/admin). * 1:1 воспроизводит классы из design/mockups/{auth,lobby}.html, чтобы * JSX-разметка страниц могла использовать те же имена классов, что и * утверждённые макеты. Токены — из tokens.css. */ /* ---------- Топбар (лобби/календарь/админка) ---------- */ .topbar { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; justify-content: space-between; padding: var(--space-4) var(--space-8); background: var(--color-surface); border-bottom: 1px solid var(--color-border); } .brand-mark { display: inline-flex; align-items: center; gap: 8px; font: var(--text-h3); color: var(--color-ink-700); text-decoration: none; } .brand-mark .logo-mark { width: 22px; height: 22px; flex-shrink: 0; } .topbar-right { display: flex; align-items: center; gap: var(--space-4); } /* ---------- Переключатель темы «солнце/луна» (см. design/mockups/dark/*.html) ---------- */ .theme-toggle { display: inline-flex; gap: 2px; background: var(--color-bg-alt); padding: 4px; border-radius: var(--radius-full); border: 1px solid var(--color-border); } .theme-toggle-btn { width: 32px; height: 32px; border-radius: 50%; border: none; background: transparent; color: var(--color-ink-500); display: flex; align-items: center; justify-content: center; } .theme-toggle-btn .icon { width: 16px; height: 16px; } .theme-toggle-btn:hover { color: var(--color-ink-900); } .theme-toggle-btn.is-active { background: var(--color-surface); color: var(--color-ink-700); box-shadow: var(--shadow-sm); } /* ---------- Пилюля пользователя (декоративная, см. lobby.html) ---------- */ .user-pill { display: inline-flex; align-items: center; gap: 10px; padding: 6px 16px 6px 6px; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-full); font: var(--text-body); font-weight: 600; color: var(--color-ink-900); transition: border-color var(--transition-fast), box-shadow var(--transition-fast); } .user-pill:hover { border-color: var(--color-border-strong); box-shadow: var(--shadow-sm); } .avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--color-ink-700); color: #fff; display: flex; align-items: center; justify-content: center; font: var(--text-caption); text-transform: none; letter-spacing: 0; flex-shrink: 0; overflow: hidden; } /* Фото аватара (Avatar.tsx) — покрывает заглушку с инициалами целиком. */ .avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; } .user-pill .avatar { width: 30px; height: 30px; } /* ---------- Бургер и скрывающаяся панель навигации (см. lobby.html) ---------- */ .menu-wrap { position: relative; } .burger { width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); color: var(--color-ink-700); transition: border-color var(--transition-fast), box-shadow var(--transition-fast); } .burger:hover { border-color: var(--color-border-strong); box-shadow: var(--shadow-sm); } .burger[aria-expanded='true'] { border-color: var(--color-ink-700); } .menu { position: absolute; top: calc(100% + 10px); right: 0; min-width: 236px; padding: var(--space-2); background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); display: none; z-index: 30; } .menu.is-open { display: block; } .menu a, .menu button { display: flex; align-items: center; gap: 10px; width: 100%; padding: 10px 14px; border: none; background: transparent; border-radius: var(--radius-sm); font: var(--text-body-lg); font-weight: 600; color: var(--color-ink-900); text-decoration: none; text-align: left; cursor: pointer; } .menu a:hover, .menu button:hover { background: var(--color-bg-alt); color: var(--color-ink-700); } .menu a.is-active { background: var(--color-bg-alt); color: var(--color-ink-700); } .menu a .icon, .menu button .icon { color: var(--color-ink-400); } .menu-divider { height: 1px; background: var(--color-border); margin: var(--space-2) 6px; } .menu a.danger, .menu button.danger { color: var(--color-danger); } .menu a.danger .icon, .menu button.danger .icon { color: var(--color-danger); } /* ---------- Топбар на узких экранах ---------- */ @media (max-width: 640px) { .topbar { padding: var(--space-3) var(--space-4); } .topbar-right { gap: var(--space-2); } .user-pill { padding: 6px; gap: 0; } .user-pill-name { display: none; } } /* ---------- Кнопки (общие для оболочки) ---------- */ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; border: none; cursor: pointer; font-family: var(--font-body); white-space: nowrap; transition: background var(--transition-fast), box-shadow var(--transition-fast); } .btn-primary { background: var(--color-accent); color: var(--color-accent-text); font: var(--text-body); font-weight: 700; padding: 11px 22px; border-radius: var(--radius-full); } .btn-primary:hover:not(:disabled) { background: var(--color-accent-hover); box-shadow: var(--shadow-md); } .btn-primary:active:not(:disabled) { background: var(--color-accent-active); } .btn-primary:disabled { background: rgba(166, 174, 203, 0.35); color: var(--color-surface); cursor: not-allowed; } .btn-secondary { background: transparent; color: var(--color-ink-700); border: 1.5px solid var(--color-border-pill); font: var(--text-body); font-weight: 600; padding: 9px 18px; border-radius: var(--radius-full); } .btn-secondary:hover:not(:disabled) { background: var(--color-bg-alt); } .btn-secondary:disabled { border-color: var(--color-border); color: var(--color-ink-300); cursor: not-allowed; } .btn-danger { background: transparent; color: var(--color-danger); border: 1.5px solid var(--color-danger); font: var(--text-body); font-weight: 600; padding: 9px 18px; border-radius: var(--radius-full); } .btn-danger:hover:not(:disabled) { background: var(--color-danger-bg); } .btn-danger:disabled { opacity: 0.5; cursor: not-allowed; } /* ---------- Бейджи статуса ---------- */ .badge { display: inline-flex; align-items: center; gap: 6px; padding: 4px 12px; border-radius: var(--radius-full); font: var(--text-caption); white-space: nowrap; } .badge-free { background: var(--color-success-bg); color: var(--color-success); } .badge-busy { background: var(--color-danger-bg); color: var(--color-danger); } .badge-booked { background: var(--color-warning-bg); color: var(--color-warning); } .badge-locked { background: var(--color-bg-alt); color: var(--color-ink-700); } /* ---------- Индикатор загрузки (bootstrap-сессия, join и т.п.) ---------- */ .app-loader { display: flex; align-items: center; justify-content: center; min-height: 100vh; color: var(--color-ink-500); font: var(--text-body-lg); background: var(--color-bg); } .spin { animation: vidconf-spin 0.9s linear infinite; } @keyframes vidconf-spin { to { transform: rotate(360deg); } } /* ---------- Тосты ---------- */ .toast-stack { position: fixed; right: var(--space-6); bottom: var(--space-6); display: flex; flex-direction: column; gap: var(--space-2); z-index: 100; } .toast { display: flex; align-items: center; gap: 8px; padding: 12px 18px; border-radius: var(--radius-md); font: var(--text-body); font-weight: 600; box-shadow: var(--shadow-lg); max-width: 360px; } .toast-error { background: var(--color-danger-bg); color: var(--color-danger); } .toast-success { background: var(--color-success-bg); color: var(--color-success); } .toast-info { background: var(--color-surface); color: var(--color-ink-900); border: 1px solid var(--color-border); } /* ---------- Ховер-карточка конференции (ConferenceHoverCard) ---------- * Новый элемент без готового макета в design/mockups/ — собран из уже * утверждённых паттернов (карточка-поповер `--shadow-lg`, бейдж закреплённости * с `Repeat` из §4.6). Рендерится порталом в document.body с `position: fixed` * (см. ConferenceHoverCard.tsx) — `pointer-events: none`, чтобы не перекрывать * клики по элементу под ней. */ .conf-hover-card { pointer-events: none; z-index: 250; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: var(--space-4); font: var(--text-body); color: var(--color-ink-900); } .conf-hover-card-hint { margin: 0; color: var(--color-ink-500); } .conf-hover-card-title { margin: 0 0 var(--space-2); font: var(--text-h3); color: var(--color-ink-900); } .conf-hover-card-row { display: flex; align-items: center; gap: 6px; margin: 0 0 6px; color: var(--color-ink-700); } .conf-hover-card-row:last-of-type { margin-bottom: 0; } .conf-hover-card-label { display: flex; align-items: center; gap: 5px; font: var(--text-caption); color: var(--color-ink-400); margin-right: 4px; } .conf-hover-card-participants { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--color-border); } .conf-hover-card-participants ul { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; max-height: 140px; overflow-y: auto; } .conf-hover-card-participants li { display: flex; align-items: center; gap: 8px; font: var(--text-body); color: var(--color-ink-900); } .conf-hover-card-tag { font: var(--text-caption); color: var(--color-ink-500); } /* ---------- Модальные диалоги (светлая оболочка) ---------- */ /* Общая обёртка модалок оболочки (диалог быстрого просмотра вхождения конференции, редактирование в «Моих конференциях» и т.п.) — центрированная модалка (--shadow-lg) поверх затемнённого фона. */ .modal-overlay { position: fixed; inset: 0; background: rgba(46, 52, 84, 0.4); display: flex; align-items: center; justify-content: center; padding: var(--space-6); z-index: 200; } .modal-panel { background: var(--color-surface); border-radius: var(--radius-2xl); box-shadow: var(--shadow-lg); padding: var(--space-6); width: 100%; max-width: 420px; max-height: calc(100vh - var(--space-12)); overflow-y: auto; } .modal-panel.is-wide { max-width: 480px; } .modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); margin-bottom: var(--space-5); } .modal-head h2 { font: var(--text-h2); color: var(--color-ink-900); margin: 0; } .modal-close { width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--color-border); background: var(--color-surface); color: var(--color-ink-500); display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .modal-close:hover { border-color: var(--color-border-strong); color: var(--color-ink-900); } .modal-actions { display: flex; gap: var(--space-3); margin-top: var(--space-5); } .modal-actions .btn { flex: 1; justify-content: center; } /* Опасное действие (удаление) — отдельно слева, Отмена/Сохранить — группой справа, без растягивания на всю ширину (см. EditConferenceModal). */ .modal-actions.modal-actions--split { justify-content: space-between; } .modal-actions--split > .btn-danger { flex: none; } .modal-actions--split .modal-actions-group { display: flex; gap: var(--space-3); } .modal-actions--split .row-actions { display: flex; align-items: center; gap: var(--space-3); } /* Модалка вокруг ConferenceFormCard (`.create-card`, «Мои конференции» и календарь) — сама карточка остаётся визуальной панелью (фон/обводка/радиус/паддинг из calendar.css), здесь только гасим её sticky-позиционирование из десктопного сайдбара и ограничиваем высоту внутри модалки, чтобы скроллилась она сама, а не вся страница. */ .modal-form-wrap { width: 100%; max-width: 480px; } .modal-form-wrap .create-card { position: static; max-height: calc(100vh - var(--space-12)); overflow-y: auto; } /* Узкий экран: «Удалить» + «Отмена» + «Сохранить» в один ряд не помещаются (в сумме шире содержимого модалки на телефоне) — переносим «Удалить» на свою строку сверху. */ @media (max-width: 480px) { .modal-actions--split { flex-wrap: wrap; } .modal-actions--split > .btn-danger { flex: 1 1 100%; } .modal-actions--split .modal-actions-group { flex: 1 1 100%; } .modal-actions--split .row-actions { flex-wrap: wrap; } } /* ---------- Поля форм в модалках (общие для всех диалогов оболочки) ---------- */ .field { margin-bottom: var(--space-5); } .field:last-child { margin-bottom: 0; } .field label { display: flex; align-items: center; gap: 6px; font: var(--text-body); font-weight: 600; color: var(--color-ink-900); margin-bottom: var(--space-2); } .field input, .field textarea, .field select { width: 100%; font: var(--text-body-lg); color: var(--color-ink-900); padding: 10px 14px; border-radius: var(--radius-md); border: 1px solid var(--color-border); background: var(--color-surface); font-family: var(--font-body); } .field input:focus, .field textarea:focus, .field select:focus { outline: none; border-color: var(--color-focus-ring); box-shadow: 0 0 0 3px rgba(59, 77, 149, 0.12); } .field-hint { font: var(--text-body); color: var(--color-ink-500); margin: 4px 0 0; } .error-banner { display: flex; gap: 10px; align-items: flex-start; background: var(--color-danger-bg); border: 1px solid rgba(199, 54, 79, 0.3); color: var(--color-danger); border-radius: var(--radius-md); padding: var(--space-4); font: var(--text-body); margin-bottom: var(--space-5); } .error-banner strong { display: block; margin-bottom: 2px; } .error-banner svg { flex-shrink: 0; margin-top: 1px; } /* ===================================================================== * Тёмная тема: точечные патчи (design/mockups/dark/README.md, «Точечные * правки поверх скопированного CSS»). Все переменные --color-* / --shadow-* * уже перекрашиваются сами через каскад tokens.css — здесь только правила, * где использован литеральный hex/rgba (не var()) и поэтому не могли * перекраситься автоматически. Оба блока (авто по ОС + явный выбор) * продублированы намеренно, как в самом tokens.css. * ===================================================================== */ @media (prefers-color-scheme: dark) { :root:not([data-theme]) .avatar { color: var(--color-accent-text); } :root:not([data-theme]) .btn-primary:disabled { background: rgba(122, 122, 122, 0.3); color: var(--color-ink-300); } :root:not([data-theme]) .modal-overlay { background: rgba(0, 0, 0, 0.6); } :root:not([data-theme]) .field input:focus, :root:not([data-theme]) .field textarea:focus, :root:not([data-theme]) .field select:focus { box-shadow: 0 0 0 3px rgba(214, 168, 61, 0.18); } :root:not([data-theme]) .error-banner { border-color: rgba(235, 147, 161, 0.3); } } :root[data-theme='dark'] .avatar { color: var(--color-accent-text); } :root[data-theme='dark'] .btn-primary:disabled { background: rgba(122, 122, 122, 0.3); color: var(--color-ink-300); } :root[data-theme='dark'] .modal-overlay { background: rgba(0, 0, 0, 0.6); } :root[data-theme='dark'] .field input:focus, :root[data-theme='dark'] .field textarea:focus, :root[data-theme='dark'] .field select:focus { box-shadow: 0 0 0 3px rgba(214, 168, 61, 0.18); } :root[data-theme='dark'] .error-banner { border-color: rgba(235, 147, 161, 0.3); }