/* * 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" на /: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; }