/* =========================================================================
   Wortly 2.0 — токены дизайн-системы
   =========================================================================

   Два уровня переменных:

     1. Примитивы  --blue-500, --gray-900  — сырая палитра, в компонентах
        напрямую НЕ используются.
     2. Семантика  --surface, --text, --accent — то, чем пользуется вёрстка.

   Смысл разделения: тема переопределяет только семантику. Компоненту
   всё равно, какой конкретно серый стоит за --surface, — поэтому тёмная
   тема не требует ни одной правки в components.css.

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

:root {
  /* ===== Примитивы: палитра ============================================= */

  --blue-50:  #eef3ff;
  --blue-100: #dbe5ff;
  --blue-200: #bccfff;
  --blue-300: #96b3fe;
  --blue-400: #739efe;   /* фирменный цвет Wortly */
  --blue-500: #5b7fe0;
  --blue-600: #4361c9;
  --blue-700: #33499b;
  --blue-800: #24336d;
  --blue-900: #161f42;

  --violet-300: #b3a7fa;
  --violet-400: #8b7cf6;
  --violet-500: #7c5cf6;
  --violet-600: #6437e0;

  --green-300: #7fe0b4;
  --green-400: #3ec98a;
  --green-500: #2ba872;
  --green-600: #1f855a;

  --amber-300: #ffe08a;
  --amber-400: #ffc94c;
  --amber-500: #f0ad20;
  --amber-600: #c98a0e;

  --orange-400: #ff8a4c;
  --orange-500: #ff6a26;

  --red-300: #ffa0a0;
  --red-400: #ff5a5a;
  --red-500: #e83b3b;
  --red-600: #c02626;

  --pink-400: #ff6b9d;

  /* Нейтрали. Холодный оттенок — чтобы серый не спорил с синим брендом. */
  --gray-0:   #ffffff;
  --gray-25:  #fafbfd;
  --gray-50:  #f5f7fa;
  --gray-100: #eef1f6;
  --gray-150: #e6e9f0;
  --gray-200: #d8dce6;
  --gray-300: #b9bfcd;
  --gray-400: #8a8d98;
  --gray-500: #6b6f7d;
  --gray-600: #4c505d;
  --gray-700: #333743;
  --gray-800: #232631;
  --gray-850: #1c1f28;
  --gray-900: #15171e;
  --gray-950: #0b0d14;

  /* ===== Типографика ==================================================== */

  /* «Twemoji Country Flags» стоит первым намеренно: в @font-face он сужен
     до U+1F1E6–1F1FF, поэтому претендует только на символы-индикаторы
     флага и ни одной буквы у основного шрифта не отбирает. Стоял бы позже
     — системный шрифт успел бы отдать вместо флага буквы «DE». */
  --font-display: "Twemoji Country Flags", "Plus Jakarta Sans", "Segoe UI", system-ui, sans-serif;
  --font-body: "Twemoji Country Flags", "Manrope", "Segoe UI", system-ui, sans-serif;
  --font-mono: ui-monospace, "JetBrains Mono", Consolas, monospace;

  /* Размеры плавают между мобильным и десктопным значением: на телефоне
     заголовок не съедает экран, на большом мониторе не выглядит мелким. */
  --text-2xs: 0.6875rem;                          /* 11px */
  --text-xs:  0.75rem;                            /* 12px */
  --text-sm:  0.8125rem;                          /* 13px */
  --text-base: 0.9375rem;                         /* 15px */
  --text-md:  1rem;                               /* 16px */
  --text-lg:  clamp(1.0625rem, 1rem + 0.3vw, 1.1875rem);
  --text-xl:  clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
  --text-2xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);
  --text-3xl: clamp(1.875rem, 1.5rem + 1.8vw, 2.75rem);
  --text-4xl: clamp(2.25rem, 1.7rem + 2.6vw, 3.5rem);

  --leading-tight: 1.15;
  --leading-snug: 1.35;
  --leading-normal: 1.55;
  --leading-relaxed: 1.7;

  --tracking-tight: -0.02em;
  --tracking-normal: 0;
  --tracking-wide: 0.04em;
  --tracking-caps: 0.08em;   /* для КАПСА в подписях */

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800;

  /* ===== Ритм: шаг 4px ================================================== */

  --space-0: 0;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;

  /* ===== Скругления ===================================================== */

  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius-md: 14px;
  --radius-lg: 18px;
  --radius-xl: 24px;
  --radius-2xl: 32px;
  --radius-full: 999px;

  /* ===== Слои =========================================================== */

  --z-base: 0;
  --z-sticky: 100;
  --z-nav: 200;
  --z-overlay: 300;
  --z-modal: 400;
  --z-toast: 500;

  /* ===== Движение ======================================================= */

  --duration-instant: 80ms;
  --duration-fast: 150ms;
  --duration-normal: 240ms;
  --duration-slow: 400ms;
  --duration-slower: 700ms;

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  /* Лёгкий перелёт для карточек и модалок — движение читается как «живое» */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* ===== Размеры каркаса ================================================ */

  --container-sm: 480px;
  --container-md: 640px;
  --container-lg: 960px;
  --container-xl: 1200px;

  /* Колонка контента внутри приложения. Одна на все вкладки: разная ширина
     по страницам заставляла вёрстку прыгать при каждом переходе по
     навигации — на телефоне это незаметно, на широком экране бросается
     в глаза. Меняется здесь и сразу на всех экранах. */
  --container-app: 880px;

  --nav-height: 64px;
  --header-height: 56px;
  /* Отступ под системные панели iOS/Android в установленной PWA */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);

  /* Шторка на телефоне: высота при открытии и предел, до которого её
     растягивают жестом вверх. До самого верха раскрытая не доходит —
     полоска подложки над ней оставляет её шторкой, а не новой страницей.
     Разницу между этими высотами проходит жест, он в ui.js. */
  --sheet-peek: min(72dvh, 620px);
  --sheet-full: calc(100dvh - var(--safe-top) - var(--space-8));
}

/* =========================================================================
   СВЕТЛАЯ ТЕМА (по умолчанию)
   ========================================================================= */

:root,
:root[data-theme="light"] {
  color-scheme: light;

  /* Поверхности: от «утопленной» к «поднятой» */
  --surface-sunken: var(--gray-50);
  --surface: var(--gray-0);
  --surface-raised: var(--gray-0);
  --surface-overlay: var(--gray-0);
  --surface-inverse: var(--gray-950);

  /* Заливки интерактивных элементов */
  --fill: var(--gray-100);
  --fill-hover: var(--gray-150);
  --fill-active: var(--gray-200);
  --fill-subtle: var(--gray-50);

  /* Текст */
  --text: var(--gray-950);
  --text-secondary: var(--gray-600);
  --text-muted: var(--gray-400);
  --text-inverse: var(--gray-0);
  --text-on-accent: #ffffff;

  /* Границы */
  --border: var(--gray-150);
  --border-strong: var(--gray-200);
  --border-subtle: var(--gray-100);

  /* Акцент */
  --accent: var(--blue-400);
  --accent-hover: var(--blue-500);
  --accent-active: var(--blue-600);
  --accent-subtle: var(--blue-50);
  --accent-border: var(--blue-200);
  --accent-text: var(--blue-600);

  /* Статусы */
  --success: var(--green-400);
  --success-subtle: #e6f9f0;
  --success-text: var(--green-600);

  --warning: var(--amber-400);
  --warning-subtle: #fff6e0;
  --warning-text: var(--amber-600);

  --danger: var(--red-400);
  --danger-subtle: #ffecec;
  --danger-text: var(--red-600);

  --info: var(--violet-400);
  --info-subtle: #f0edff;
  --info-text: var(--violet-600);

  --streak: var(--orange-400);

  /* Тени. В светлой теме глубина создаётся тенью. */
  --shadow-xs: 0 1px 2px rgba(11, 13, 20, 0.05);
  --shadow-sm: 0 2px 8px rgba(11, 13, 20, 0.06);
  --shadow-md: 0 8px 24px rgba(11, 13, 20, 0.08);
  --shadow-lg: 0 16px 48px rgba(11, 13, 20, 0.12);
  --shadow-accent: 0 8px 24px rgba(115, 158, 254, 0.35);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.6);

  --backdrop: rgba(11, 13, 20, 0.4);
  /* Растворяется в фоне страницы, а не в белом: --surface здесь оставлял
     под липкой панелью светлый прямоугольник поверх серой подложки. */
  --scrim-top: linear-gradient(to bottom, var(--surface-sunken) 70%, transparent);
  --scrim-bottom: linear-gradient(to top, var(--surface-sunken) 70%, transparent);
}

/* =========================================================================
   ТЁМНАЯ ТЕМА
   ========================================================================= */

:root[data-theme="dark"] {
  color-scheme: dark;

  /* В тёмной теме глубина создаётся не тенью (её не видно), а тем,
     что «поднятая» поверхность светлее фона. */
  --surface-sunken: var(--gray-950);
  --surface: var(--gray-900);
  --surface-raised: var(--gray-850);
  --surface-overlay: var(--gray-800);
  --surface-inverse: var(--gray-0);

  --fill: var(--gray-850);
  --fill-hover: var(--gray-800);
  --fill-active: var(--gray-700);
  --fill-subtle: rgba(255, 255, 255, 0.04);

  --text: #ffffff;
  --text-secondary: var(--gray-300);
  --text-muted: var(--gray-400);
  --text-inverse: var(--gray-950);
  /* Тёмный текст на светло-синей кнопке — контраст выше, чем белым по синему */
  --text-on-accent: var(--gray-950);

  --border: var(--gray-800);
  --border-strong: var(--gray-700);
  --border-subtle: rgba(255, 255, 255, 0.06);

  --accent: var(--blue-400);
  --accent-hover: var(--blue-300);
  --accent-active: var(--blue-200);
  --accent-subtle: rgba(115, 158, 254, 0.12);
  --accent-border: rgba(115, 158, 254, 0.3);
  --accent-text: var(--blue-300);

  --success: var(--green-400);
  --success-subtle: rgba(62, 201, 138, 0.14);
  --success-text: var(--green-300);

  --warning: var(--amber-400);
  --warning-subtle: rgba(255, 201, 76, 0.14);
  --warning-text: var(--amber-300);

  --danger: var(--red-400);
  --danger-subtle: rgba(255, 90, 90, 0.14);
  --danger-text: var(--red-300);

  --info: var(--violet-400);
  --info-subtle: rgba(139, 124, 246, 0.14);
  --info-text: var(--violet-300);

  --streak: var(--orange-400);

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.65);
  --shadow-accent: 0 8px 24px rgba(115, 158, 254, 0.2);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.04);

  --backdrop: rgba(0, 0, 0, 0.6);
  --scrim-top: linear-gradient(to bottom, var(--surface-sunken) 70%, transparent);
  --scrim-bottom: linear-gradient(to top, var(--surface-sunken) 70%, transparent);
}

/* Системная тема, пока пользователь не выбрал вручную.
   Дублируем блок, а не @import: каскад должен сработать до первой отрисовки,
   иначе будет вспышка светлой темы. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --surface-sunken: var(--gray-950);
    --surface: var(--gray-900);
    --surface-raised: var(--gray-850);
    --surface-overlay: var(--gray-800);
    --surface-inverse: var(--gray-0);

    --fill: var(--gray-850);
    --fill-hover: var(--gray-800);
    --fill-active: var(--gray-700);
    --fill-subtle: rgba(255, 255, 255, 0.04);

    --text: #ffffff;
    --text-secondary: var(--gray-300);
    --text-muted: var(--gray-400);
    --text-inverse: var(--gray-950);
    --text-on-accent: var(--gray-950);

    --border: var(--gray-800);
    --border-strong: var(--gray-700);
    --border-subtle: rgba(255, 255, 255, 0.06);

    --accent-hover: var(--blue-300);
    --accent-active: var(--blue-200);
    --accent-subtle: rgba(115, 158, 254, 0.12);
    --accent-border: rgba(115, 158, 254, 0.3);
    --accent-text: var(--blue-300);

    --success-subtle: rgba(62, 201, 138, 0.14);
    --success-text: var(--green-300);
    --warning-subtle: rgba(255, 201, 76, 0.14);
    --warning-text: var(--amber-300);
    --danger-subtle: rgba(255, 90, 90, 0.14);
    --danger-text: var(--red-300);
    --info-subtle: rgba(139, 124, 246, 0.14);
    --info-text: var(--violet-300);

    --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.5);
    --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.55);
    --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.65);
    --shadow-accent: 0 8px 24px rgba(115, 158, 254, 0.2);
    --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.04);

    --backdrop: rgba(0, 0, 0, 0.6);
  }
}

/* =========================================================================
   ПРЕДМЕТНЫЕ ТОКЕНЫ
   ========================================================================= */

:root {
  /* Грамматический род. Индексы, а не имена: der/die/das, le/la, el/la —
     компонент подставляет --gender-1..3 по позиции значения из
     languages.gender_values и работает с любым языком. */
  --gender-1: var(--blue-400);      /* мужской   */
  --gender-2: var(--pink-400);      /* женский   */
  --gender-3: var(--green-400);     /* средний   */
  --gender-4: var(--violet-400);    /* запас: языки с 4+ классами */

  /* Методики тренировки — цвет для иконки и бейджа */
  --method-recognition: var(--blue-400);
  --method-production: var(--violet-400);
  --method-choice: var(--green-400);
  --method-typing: var(--amber-400);
  --method-listening: var(--pink-400);
  --method-speaking: var(--orange-400);
  --method-cloze: var(--violet-500);
  --method-matching: var(--green-500);
  --method-form: var(--blue-600);

  /* Тон карточки дня.
     Смысла у конкретного цвета здесь нет — и в этом весь смысл: карточку
     открывают каждый день, и меняющийся вместе со словом цвет не даёт ей
     примелькаться. Индексы, а не имена, потому что выбирает их то же зерно
     из даты, что выбирает и само слово: цвет и слово меняются одновременно. */
  --daily-1: var(--blue-400);
  --daily-2: var(--violet-400);
  --daily-3: var(--green-400);
  --daily-4: var(--amber-400);
  --daily-5: var(--pink-400);
  --daily-6: var(--orange-400);

  /* Разделы приложения — тон медальона в шапке.
     Смысла у конкретного цвета здесь нет, как и у --daily-*: он нужен,
     чтобы смена экрана читалась раньше заголовка. Нижняя навигация цвет
     раздела не повторяет намеренно — активная вкладка везде акцентная,
     иначе на экране оказывалось бы два разных «главных» цвета. */
  --section-dictionary: var(--violet-400);
  --section-practice: var(--blue-400);
  --section-stats: var(--green-400);

  /* Оценки FSRS */
  --rating-again: var(--red-400);
  --rating-hard: var(--orange-400);
  --rating-good: var(--green-400);
  --rating-easy: var(--blue-400);

  /* Зрелость словаря — цвета сегментов стек-графика.
     Значения прогнаны через валидатор палитры и проходят все проверки
     В ОБЕИХ темах: полоса светлоты, порог насыщенности, разделимость
     при протанопии и дейтеранопии, контраст к подложке.
     Брать сюда обычные --amber-400 / --blue-400 нельзя: они подобраны
     для акцентов интерфейса и выпадают из полосы светлоты для заливок.

     Разделимость при тританопии = 5.1, ниже порога 6, поэтому цвет не
     может быть единственным носителем смысла: у графика обязательны
     легенда, подписи значений на сегментах и разрывы между ними. */
  --maturity-learning: #bc7f0b;
  --maturity-young: #4361c9;
  --maturity-mature: #1f855a;

  /* «Новые» — это отсутствие прогресса, а не ещё одна категория.
     Поэтому им достаётся подложка шкалы, а не собственный цвет:
     нейтральный серый в палитре данных провалил порог насыщенности
     и честно читался как пустота. */
  --maturity-new: var(--fill-active);

  /* Тепловая карта активности: 5 ступеней интенсивности */
  --heat-0: var(--fill);
  --heat-1: rgba(115, 158, 254, 0.25);
  --heat-2: rgba(115, 158, 254, 0.45);
  --heat-3: rgba(115, 158, 254, 0.7);
  --heat-4: var(--blue-400);
}

/* =========================================================================
   ДОСТУПНОСТЬ
   ========================================================================= */

/* Пользователь просил меньше движения — оставляем только мгновенные
   переходы состояния, убираем всю декоративную анимацию. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-instant: 1ms;
    --duration-fast: 1ms;
    --duration-normal: 1ms;
    --duration-slow: 1ms;
    --duration-slower: 1ms;
  }

  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}

/* То же, но по тумблеру в профиле (user_preferences.reduce_motion).
   Блок дублируется, а не объединяется с медиазапросом выше: селектор по
   атрибуту и @media в одно правило не сводятся, а прятать это за
   вычисляемым множителем времени — сложнее, чем восемь строк повтора.
   Атрибут ставится инлайновым скриптом в <head> из localStorage, иначе
   анимация успела бы проиграться до ответа сервера. */
:root[data-motion="reduced"] {
  --duration-instant: 1ms;
  --duration-fast: 1ms;
  --duration-normal: 1ms;
  --duration-slow: 1ms;
  --duration-slower: 1ms;
}

:root[data-motion="reduced"] *,
:root[data-motion="reduced"] *::before,
:root[data-motion="reduced"] *::after {
  animation-duration: 1ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 1ms !important;
  scroll-behavior: auto !important;
}

/* Режим повышенного контраста системы */
@media (prefers-contrast: more) {
  :root {
    --border: var(--gray-400);
    --border-strong: var(--gray-600);
    --text-muted: var(--gray-600);
  }

  :root[data-theme="dark"] {
    --border: var(--gray-500);
    --border-strong: var(--gray-300);
    --text-muted: var(--gray-300);
  }
}
