first commit
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled

This commit is contained in:
2026-07-23 02:38:05 +03:00
commit 8757bec8ac
335 changed files with 61527 additions and 0 deletions

348
design/tokens.css Normal file
View File

@@ -0,0 +1,348 @@
/*
* 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;
}