349 lines
12 KiB
CSS
349 lines
12 KiB
CSS
/*
|
||
* VidConf — design tokens
|
||
* Источник истины для design/DESIGN_SYSTEM.md. Значения синхронизированы 1:1.
|
||
*
|
||
* Три темы, независимые механизмы переключения:
|
||
* - Оболочка, светлая (дефолт) — :root.
|
||
* - Оболочка, тёмная — :root[data-theme="dark"] (переключатель
|
||
* пользователя) ИЛИ автоматически по @media (prefers-color-scheme: dark),
|
||
* если data-theme не проставлен явно (см. блок ниже). Утверждено
|
||
* 2026-07-18 (фаза 6a, design/mockups/dark/README.md) — палитра 1:1 из
|
||
* утверждённых тёмных макетов оболочки.
|
||
* - Комната конференции — [data-theme="room"] (скоуп на контейнер
|
||
* экрана конференции; отдельный неймспейс --color-room-*, НЕ переключается
|
||
* системной темой и НЕ смешивается с dark-оболочкой — комната всегда
|
||
* тёмная независимо от выбора пользователя).
|
||
*
|
||
* Шрифты. Семейства и веса ниже — контракт дизайн-системы (Unbounded —
|
||
* display, Inter — body, JetBrains Mono — mono) и синхронизированы 1:1 с
|
||
* DESIGN_SYSTEM.md. Реализация подключения различается по среде, БЕЗ внешних
|
||
* CDN (инвариант приватности):
|
||
* - Собранный фронт (frontend/) — шрифты самохостятся через npm-пакеты
|
||
* @fontsource с кириллическим subset (импорты в frontend/src/main.tsx);
|
||
* там ручных @font-face нет.
|
||
* - Статические HTML-макеты (design/mockups/) — сборки npm нет, поэтому
|
||
* подключаются @font-face ниже. При отсутствии локальных woff2 браузер
|
||
* молча уходит в fallback-стек без сетевых запросов (макеты остаются
|
||
* рабочими; кастомная типографика появляется, если положить woff2 рядом).
|
||
*/
|
||
|
||
@font-face {
|
||
font-family: 'Unbounded';
|
||
src: url('../fonts/Unbounded/Unbounded-Regular.woff2') format('woff2');
|
||
font-weight: 400;
|
||
font-display: swap;
|
||
}
|
||
@font-face {
|
||
font-family: 'Unbounded';
|
||
src: url('../fonts/Unbounded/Unbounded-SemiBold.woff2') format('woff2');
|
||
font-weight: 600;
|
||
font-display: swap;
|
||
}
|
||
@font-face {
|
||
font-family: 'Unbounded';
|
||
src: url('../fonts/Unbounded/Unbounded-Bold.woff2') format('woff2');
|
||
font-weight: 700;
|
||
font-display: swap;
|
||
}
|
||
@font-face {
|
||
font-family: 'Inter';
|
||
src: url('../fonts/Inter/Inter-Variable.woff2') format('woff2-variations');
|
||
font-weight: 400 800;
|
||
font-display: swap;
|
||
}
|
||
@font-face {
|
||
font-family: 'JetBrains Mono';
|
||
src: url('../fonts/JetBrainsMono/JetBrainsMono-Medium.woff2') format('woff2');
|
||
font-weight: 500;
|
||
font-display: swap;
|
||
}
|
||
|
||
:root {
|
||
color-scheme: light;
|
||
|
||
/* ---------- Типографика ---------- */
|
||
--font-display: 'Unbounded', 'Arial Rounded MT Bold', -apple-system, 'Segoe UI', sans-serif;
|
||
--font-body: 'Inter', -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
||
--font-mono: 'JetBrains Mono', 'SFMono-Regular', Menlo, Consolas, monospace;
|
||
|
||
--text-display-2xl: 700 64px/1.05 var(--font-display);
|
||
--text-display-xl: 700 48px/1.1 var(--font-display);
|
||
--text-display-lg: 600 34px/1.2 var(--font-display);
|
||
--text-h1: 700 28px/1.25 var(--font-body);
|
||
--text-h2: 600 22px/1.3 var(--font-body);
|
||
--text-h3: 600 18px/1.35 var(--font-body);
|
||
--text-body-lg: 400 16px/1.5 var(--font-body);
|
||
--text-body: 400 14px/1.5 var(--font-body);
|
||
--text-caption: 600 12px/1.4 var(--font-body);
|
||
--text-mono-sm: 500 13px/1.4 var(--font-mono);
|
||
|
||
/* ---------- Spacing (8pt grid, база 4px) ---------- */
|
||
--space-1: 4px;
|
||
--space-2: 8px;
|
||
--space-3: 12px;
|
||
--space-4: 16px;
|
||
--space-5: 20px;
|
||
--space-6: 24px;
|
||
--space-8: 32px;
|
||
--space-10: 40px;
|
||
--space-12: 48px;
|
||
--space-16: 64px;
|
||
--space-20: 80px;
|
||
--space-24: 96px;
|
||
|
||
/* ---------- Радиусы ---------- */
|
||
--radius-sm: 8px;
|
||
--radius-md: 12px;
|
||
--radius-lg: 16px;
|
||
--radius-xl: 20px;
|
||
--radius-2xl: 24px;
|
||
--radius-3xl: 32px;
|
||
--radius-full: 999px;
|
||
|
||
/* ---------- Границы ---------- */
|
||
--border-thin: 1px;
|
||
--border-md: 1.5px;
|
||
--border-thick: 2px;
|
||
--border-speaker: 3px;
|
||
|
||
/* ---------- Breakpoints (справочно, desktop-first) ---------- */
|
||
--bp-desktop: 1440px;
|
||
--bp-min: 1280px;
|
||
|
||
/* ---------- Motion ---------- */
|
||
--transition-fast: 120ms ease;
|
||
--transition-base: 200ms ease;
|
||
|
||
/* ---------- Цвета: светлая тема (оболочка) ---------- */
|
||
--color-bg: #F1F1F1;
|
||
--color-bg-alt: #F7F7F8;
|
||
--color-surface: #FFFFFF;
|
||
--color-surface-glass: rgba(255, 255, 255, 0.55);
|
||
|
||
--color-border: #E1E3E9;
|
||
--color-border-strong: #C7CCDC;
|
||
--color-border-pill: #4A5A9E;
|
||
|
||
--color-ink-900: #2E3454;
|
||
--color-ink-700: #3B4D95;
|
||
--color-ink-500: #535F94;
|
||
--color-ink-400: #6976AC;
|
||
--color-ink-300: #A6AECB;
|
||
|
||
/* Пастельная мята — фаза R1 (пивот, 2026-07-16): переименовано из
|
||
--color-accent-green*, акцент больше не обязан быть зелёным.
|
||
Осветлено на 50% (смешение 50/50 с белым) по фидбеку гейта утверждения
|
||
R1-итерации (2026-07-16): #A9E4C6→#D4F2E3, #8FD6B2→#C7EBD9,
|
||
#74C89D→#BAE4CE. Mapping см. design/DESIGN_SYSTEM.md §1.1/§1.3. */
|
||
--color-accent: #D4F2E3;
|
||
--color-accent-hover: #C7EBD9;
|
||
--color-accent-active: #BAE4CE;
|
||
--color-accent-text: #2E3454;
|
||
|
||
--color-success: #0A7A4C;
|
||
--color-success-bg: #E4F7ED;
|
||
--color-success-dot: #46916B;
|
||
|
||
--color-danger: #C7364F;
|
||
--color-danger-bg: #FCE7EB;
|
||
--color-danger-dot: #C65366;
|
||
|
||
--color-warning: #7F560D;
|
||
--color-warning-bg: #FBF0DC;
|
||
--color-warning-dot: #B58A26;
|
||
|
||
--color-focus-ring: #3B4D95;
|
||
|
||
/* ---------- Тени (светлая тема) ---------- */
|
||
--shadow-sm: 0 1px 2px rgba(46, 52, 84, 0.06);
|
||
--shadow-md: 0 4px 16px rgba(46, 52, 84, 0.08);
|
||
--shadow-lg: 0 12px 32px rgba(46, 52, 84, 0.12);
|
||
--shadow-glass: 0 8px 24px rgba(59, 77, 149, 0.15);
|
||
}
|
||
|
||
/* =====================================================================
|
||
* Тёмная тема: оболочка (auth/лобби/календарь/join/«мои конференции»/админка)
|
||
* Утверждено 2026-07-18 (фаза 6a). Палитра — 1:1 копия блока :root из
|
||
* design/mockups/dark/*.html (все 6 файлов идентичны), происхождение каждого
|
||
* значения задокументировано в design/mockups/dark/README.md и продублировано
|
||
* в design/DESIGN_SYSTEM.md §1.2b. Принцип: тёмная оболочка не изобретает
|
||
* новых цветов, а переиспользует уже утверждённые --color-room-* в новых
|
||
* ролях (см. таблицу происхождения), поэтому тёмное лобби и тёмная комната
|
||
* читаются как одна система.
|
||
*
|
||
* Механизм активации (два независимых триггера, одни и те же переопределения
|
||
* --color-* / --shadow-* — те же имена, что в :root светлой темы выше):
|
||
* 1) явный выбор пользователя — атрибут data-theme="dark" на <html>/:root;
|
||
* 2) дефолт по системной теме — @media (prefers-color-scheme: dark),
|
||
* только пока data-theme НЕ проставлен явно (:root:not([data-theme])).
|
||
* Явный data-theme="light" отключает автодетект и форсирует светлую
|
||
* тему (базовый :root выше) даже при тёмной ОС.
|
||
* Оба блока продублированы намеренно (plain CSS, без препроцессора) — при
|
||
* правке палитры менять оба синхронно.
|
||
* ===================================================================== */
|
||
@media (prefers-color-scheme: dark) {
|
||
:root:not([data-theme]) {
|
||
color-scheme: dark;
|
||
|
||
--color-bg: #1E1E1E;
|
||
--color-bg-alt: #242424;
|
||
--color-surface: #2A2A2A;
|
||
--color-surface-glass: rgba(51, 51, 51, 0.55);
|
||
|
||
--color-border: #3F3F3F;
|
||
--color-border-strong: #585858;
|
||
--color-border-pill: #7FDDA8;
|
||
|
||
--color-ink-900: #E8E8E8;
|
||
--color-ink-700: #7FDDA8;
|
||
--color-ink-500: #B0B0B0;
|
||
--color-ink-400: #5D9A78;
|
||
--color-ink-300: #7A7A7A;
|
||
|
||
--color-accent: #7FDDA8;
|
||
--color-accent-hover: #75CA9A;
|
||
--color-accent-active: #6CB78C;
|
||
--color-accent-text: #10331F;
|
||
|
||
--color-success: #7FDDA8;
|
||
--color-success-bg: rgba(127, 221, 168, 0.14);
|
||
--color-success-dot: #7FDDA8;
|
||
|
||
--color-danger: #EB93A1;
|
||
--color-danger-bg: rgba(235, 147, 161, 0.14);
|
||
--color-danger-dot: #EB93A1;
|
||
--color-danger-solid: #B85468;
|
||
--color-danger-solid-hover: #B9495F;
|
||
|
||
--color-warning: #D6A83D;
|
||
--color-warning-bg: rgba(214, 168, 61, 0.16);
|
||
--color-warning-dot: #D6A83D;
|
||
|
||
--color-focus-ring: #D6A83D;
|
||
|
||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
|
||
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
|
||
--shadow-glass: 0 8px 24px rgba(0, 0, 0, 0.45);
|
||
}
|
||
}
|
||
|
||
:root[data-theme='dark'] {
|
||
color-scheme: dark;
|
||
|
||
--color-bg: #1E1E1E;
|
||
--color-bg-alt: #242424;
|
||
--color-surface: #2A2A2A;
|
||
--color-surface-glass: rgba(51, 51, 51, 0.55);
|
||
|
||
--color-border: #3F3F3F;
|
||
--color-border-strong: #585858;
|
||
--color-border-pill: #7FDDA8;
|
||
|
||
--color-ink-900: #E8E8E8;
|
||
--color-ink-700: #7FDDA8;
|
||
--color-ink-500: #B0B0B0;
|
||
--color-ink-400: #5D9A78;
|
||
--color-ink-300: #7A7A7A;
|
||
|
||
--color-accent: #7FDDA8;
|
||
--color-accent-hover: #75CA9A;
|
||
--color-accent-active: #6CB78C;
|
||
--color-accent-text: #10331F;
|
||
|
||
--color-success: #7FDDA8;
|
||
--color-success-bg: rgba(127, 221, 168, 0.14);
|
||
--color-success-dot: #7FDDA8;
|
||
|
||
--color-danger: #EB93A1;
|
||
--color-danger-bg: rgba(235, 147, 161, 0.14);
|
||
--color-danger-dot: #EB93A1;
|
||
--color-danger-solid: #B85468;
|
||
--color-danger-solid-hover: #B9495F;
|
||
|
||
--color-warning: #D6A83D;
|
||
--color-warning-bg: rgba(214, 168, 61, 0.16);
|
||
--color-warning-dot: #D6A83D;
|
||
|
||
--color-focus-ring: #D6A83D;
|
||
|
||
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.35);
|
||
--shadow-md: 0 4px 16px rgba(0, 0, 0, 0.4);
|
||
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
|
||
--shadow-glass: 0 8px 24px rgba(0, 0, 0, 0.45);
|
||
}
|
||
|
||
/* ---------- Тёмная тема: комната конференции ---------- */
|
||
[data-theme='room'] {
|
||
color-scheme: dark;
|
||
|
||
--color-room-bg: #1E1E1E;
|
||
--color-room-surface: #2A2A2A;
|
||
--color-room-surface-raised: #333333;
|
||
|
||
--color-room-tile: #363636;
|
||
--color-room-tile-border: #3F3F3F;
|
||
--color-room-tile-hover: #3D3D3D;
|
||
|
||
--color-room-text-primary: #E8E8E8;
|
||
--color-room-text-secondary: #B0B0B0;
|
||
--color-room-text-tertiary: #7A7A7A;
|
||
|
||
--color-room-mic-on: #7FDDA8;
|
||
--color-room-mic-off: #EB93A1;
|
||
--color-room-speaker-ring: #D6A83D;
|
||
|
||
--color-room-danger: #EB93A1;
|
||
--color-room-danger-bg: #B85468;
|
||
--color-room-danger-bg-hover: #B9495F;
|
||
|
||
--color-room-focus-ring: #D6A83D;
|
||
|
||
--shadow-speaker-glow: 0 0 0 3px var(--color-room-speaker-ring), 0 0 24px rgba(214, 168, 61, 0.35);
|
||
--shadow-room-panel: 0 8px 24px rgba(0, 0, 0, 0.4);
|
||
}
|
||
|
||
/* ---------- Базовые сбросы, общие для макетов ---------- */
|
||
*, *::before, *::after { box-sizing: border-box; }
|
||
|
||
body {
|
||
margin: 0;
|
||
font: var(--text-body-lg);
|
||
color: var(--color-ink-900);
|
||
background: var(--color-bg);
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
[data-theme='room'] body,
|
||
[data-theme='room'] {
|
||
background: var(--color-room-bg);
|
||
color: var(--color-room-text-primary);
|
||
}
|
||
|
||
a { color: inherit; }
|
||
|
||
button {
|
||
font: inherit;
|
||
cursor: pointer;
|
||
}
|
||
|
||
:focus-visible {
|
||
outline: 2px solid var(--color-focus-ring);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
[data-theme='room'] :focus-visible {
|
||
outline-color: var(--color-room-focus-ring);
|
||
}
|
||
|
||
svg.icon {
|
||
width: 20px;
|
||
height: 20px;
|
||
stroke: currentColor;
|
||
stroke-width: 2;
|
||
fill: none;
|
||
stroke-linecap: round;
|
||
stroke-linejoin: round;
|
||
flex-shrink: 0;
|
||
}
|