/* =============================================================
   theme.css — слой токенов. Только объявления, ни одного правила.

   Два уровня, как в зрелых системах:
     1. ССЫЛОЧНЫЙ — сырая палитра. Имя говорит, какой это цвет.
     2. СЕМАНТИЧЕСКИЙ — роли. Имя говорит, где цвет применяется.
   Тёмная тема переопределяет ТОЛЬКО первый уровень: семантика
   написана один раз и работает в обеих темах.

   Третьим блоком идут алиасы под именами shadcn/ui — чтобы слой
   примитивов не переписывался при смене цветовой модели.

   Все числа контраста в комментариях посчитаны по WCAG 2.x
   (OKLCH → sRGB, полупрозрачные слои скомпозитены), не на глаз.

   Разделы: палитра · роли · тёмная тема · радиус ·
            отступы · кегль · ритм · размеры · раскладка ·
            тень · движение · слои · переломы
   ============================================================= */

:root{

  /* ===========================================================
     УРОВЕНЬ 1 — ССЫЛОЧНЫЙ
     Нейтрали подкрашены к фирменному синему (hue 265) на
     0.003—0.030 хромы: серый рядом с акцентом не выглядит грязным.
     =========================================================== */

  /* ---- нейтрали ---------------------------- hex ---- роль ---- */
  --gray-0:    oklch(1.000 0.000 0);      /* #FFFFFF  лист светлой    */
  --gray-25:   oklch(0.985 0.003 265);    /* #F9FAFC  текст тёмной    */
  --gray-50:   oklch(0.968 0.008 265);    /* #F2F4FA  резерв          */
  --gray-100:  oklch(0.932 0.012 265);    /* #E4E9F1  стол светлой    */
  --gray-200:  oklch(0.885 0.014 265);    /* #D5D9E3                  */
  --gray-300:  oklch(0.820 0.018 265);    /* #BEC4D0                  */
  --gray-400:  oklch(0.770 0.024 265);    /* #ADB4C4  приглуш. тёмной */
  --gray-500:  oklch(0.669 0.028 265);    /* #8D95A7                  */
  --gray-600:  oklch(0.585 0.030 265);    /* #737C8E                  */
  --gray-700:  oklch(0.455 0.030 265);    /* #4E5768  приглуш. светлой*/
  --gray-800:  oklch(0.340 0.024 265);    /* #323845                  */
  --gray-900:  oklch(0.245 0.016 265);    /* #1D2028  лист тёмной     */
  --gray-950:  oklch(0.205 0.014 265);    /* #14171E  текст светлой   */
  --gray-1000: oklch(0.145 0.012 265);    /* #080A0F  стол тёмной     */

  /* ---- фирменный синий ---------------------------------------- */
  --blue-300:  oklch(0.780 0.090 265);    /* #9BB7F2  нажатие тёмной  */
  --blue-400:  oklch(0.680 0.130 265);    /* #7195E8  бренд тёмной    */
  --blue-600:  oklch(0.405 0.161 265);    /* #1C3E9E  БРЕНД           */
  --blue-700:  oklch(0.345 0.140 265);    /* #143080  нажатие светлой */
  --blue-900:  oklch(0.180 0.045 265);    /* #081025  текст на бренде */

  /* Ссылочный уровень — палитра, а не список ролей: ступени без
     роли тут норма, они дают шкале форму и берутся, когда роль
     появляется. Мёртвыми считаются только семантические токены. */

  /* ---- второй тон: знак отделения 16-xx ------------------------
     Был #731345 — бордовый, чужой синей системе. Бирюза лежит
     на той же светлоте, что и бренд, и читается как его пара.
     В CSS не применяется: цвет запечён в assets/mark-scales.svg,
     эти две строки — источник, из которого он взят. */
  --teal-400:  oklch(0.700 0.095 195);    /* #49B1B1 */
  --teal-600:  oklch(0.455 0.105 195);    /* #006869 */

  /* ---- тревога ------------------------------------------------- */
  --red-400:   oklch(0.704 0.165  27);    /* #F57165 */
  --red-600:   oklch(0.505 0.196  27);    /* #BB141A */

  --shade:     oklch(0 0 0);              /* основа затемнения и теней */

  /* ---- краска состояний ---------------------------------------
     Состояние — не новая поверхность, а примесь краски к текущей.
     Одна примесь даёт одинаковую ступень и на белом листе, и на
     сером столе, и в тёмной теме. Хрома поднята (0.060 против
     0.014 у текста): иначе 8% примеси на белом дают нейтральный
     #ECECED рядом с синеватым столом #E4E9F1 — и это видно. */
  --wash:      oklch(0.300 0.060 265);    /* #1F2D4C */

  /* ---- шкала прозрачности -------------------------------------- */
  --a-sunk:   6%;    --a-hover:  8%;    --a-press: 12%;
  --a-line:  14%;    --a-edge:  54%;
  --a-shadow-xs: .05;

  /* ===========================================================
     УРОВЕНЬ 2 — СЕМАНТИЧЕСКИЙ
     Только ссылки на уровень 1. Ни одного литерала цвета.
     =========================================================== */

  /* ---- поверхности: три уровня, не восемь ---------------------
     Два несёт светлота, третий — примесь. Было: восемь токенов,
     пять значений, панель против страницы 1.07. */
  --surface-page:   var(--gray-0);      /* лист: документ                    */
  --surface-desk:   var(--gray-100);    /* стол: панель, полоса ...... 1.22  */
  --surface-sunk:   color-mix(in oklab, var(--wash) var(--a-sunk),  transparent);
                                        /* код, цитата, заглушка ..... 1.12  */
  --surface-hover:  color-mix(in oklab, var(--wash) var(--a-hover), transparent);
                                        /* наведение на столе ........ 1.15  */
  --surface-press:  color-mix(in oklab, var(--wash) var(--a-press), transparent);
                                        /* нажатие на столе .......... 1.26  */

  /* ---- текст ---------------------------------------------------- */
  --text:           var(--gray-950);    /* на листе ................. 17.93
                                           на столе ................. 14.71  */
  --text-muted:     var(--gray-700);    /* на листе .................. 7.27
                                           на столе .................. 5.97
                                           на нажатии (худший) ....... 4.75 AA */
  --text-on-brand:  var(--gray-25);     /* на бренде ................. 9.01
                                           на нажатом бренде ........ 11.40  */
  --text-on-danger: var(--gray-25);     /* на тревоге ................ 6.23  */

  /* ---- бренд ------------------------------------------------------
     Единственная сплошная заливка — плашка выбранной группы.
     До правки площадь фирменного цвета на странице была 0 px². */
  --brand:          var(--blue-600);    /* ссылка на листе ........... 9.41
                                           плашка на столе ........... 7.72  */
  --brand-press:    var(--blue-700);    /* плашка на столе ........... 9.76  */

  /* ---- тревога ----------------------------------------------------- */
  --danger:         var(--red-600);     /* текст на листе ............ 6.51  */
  --danger-solid:   var(--red-600);     /* заливка                          */
  --danger-soft:    color-mix(in oklab, var(--red-600) 8%, var(--surface-page));
                                        /* текст --danger на ней ..... 5.67  */

  /* ---- линии -------------------------------------------------------
     Два токена вместо одного: разделитель и несущий край — разные
     роли и разные пороги. Раньше оба лежали на 1.27 и не читались. */
  --line:  color-mix(in oklab, var(--wash) var(--a-line), transparent);
                                        /* декор, порога нет ......... 1.30  */
  --edge:  color-mix(in oklab, var(--wash) var(--a-edge), transparent);
                                        /* на листе .................. 3.32
                                           на столе .................. 3.12
                                           порог WCAG 1.4.11 ......... 3.00  */

  /* ---- фокус --------------------------------------------------------
     Одно значение outline целиком, а не формула, скопированная
     руками в трёх местах. Непрозрачное: прежний color-mix 50%
     давал 2.02 при заявленных в комментариях 4.92. */
  --ring-width: 2px;
  --focus-ring: var(--ring-width) solid var(--brand);
                                        /* на листе .................. 9.41
                                           на столе .................. 7.72  */
  --focus-offset: 1px;

  color-scheme: light;
}

/* =============================================================
   ТЁМНАЯ ТЕМА
   Переопределяет ТОЛЬКО ссылочный уровень и альфы — семантика
   выше не повторяется ни строкой. Направление возвышения то же,
   что в светлой: лист светлее стола. Раньше темы противоречили
   друг другу — в светлой карточка сливалась с фоном (Δ 0.000),
   в тёмной поднималась (Δ 0.060).
   ============================================================= */
:root[data-theme="dark"]{
  --surface-page: var(--gray-900);      /* лист  #1D2028                     */
  --surface-desk: var(--gray-1000);     /* стол  #080A0F ... лист/стол 1.22  */

  --wash:   oklch(0.900 0.040 265);     /* #D1DEF9 — светлая краска на тёмном */
  --a-sunk:  8%;  --a-hover: 10%;  --a-press: 15%;
  --a-line: 16%;  --a-edge:  42%;
  --a-shadow-xs: .30;

  --text:           var(--gray-25);     /* на листе ................. 15.59  */
  --text-muted:     var(--gray-400);    /* на листе .................. 7.83
                                           на нажатии (худший) ....... 5.32  */
  --text-on-brand:  var(--blue-900);    /* на бренде ................. 6.45  */
  --text-on-danger: var(--gray-1000);   /* на тревоге ................ 7.00  */

  --brand:          var(--blue-400);    /* ссылка на листе ........... 5.56
                                           плашка на столе ........... 6.76  */
  --brand-press:    var(--blue-300);    /* плашка на столе ........... 9.85  */

  --danger:         var(--red-400);     /* текст на листе ............ 5.76  */
  --danger-solid:   var(--red-400);
  --danger-soft:    color-mix(in oklab, var(--red-400) 16%, var(--surface-page));

  /* --line: лист 1.53 · стол 1.42
     --edge: лист 3.24 · стол 3.24 — порог 3.0 держится
     кромка панели против затемнённой страницы 4.12: в тёмной теме
     подложка даёт всего 1.03, а тень на почти чёрном невидима */

  color-scheme: dark;
}

/* =============================================================
   РАЗМЕРНЫЕ ШКАЛЫ
   ============================================================= */
:root{

  /* ---------- радиус ------------------------------------------
     Формула аддитивная, как у shadcn. Была множительная
     (×0.6/×0.8/×1.4): при --radius 0.625rem обе дают 6/8/10, но
     стоит сменить базу на 1rem — множительная даёт 9.6/12.8px,
     дробные пиксели на всех углах. */
  --radius: 0.625rem;                        /* 10px */
  --radius-sm: calc(var(--radius) - 4px);    /*  6px */
  --radius-md: calc(var(--radius) - 2px);    /*  8px */
  --radius-lg: var(--radius);                /* 10px */
  --radius-full: 9999px;

  /* ---------- отступы: шаг 0.25rem ----------------------------- */
  --space-1: 0.25rem;
  --space-1_5: 0.375rem;
  --space-2: 0.5rem;
  --space-2_5: 0.625rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;

  /* ---------- кегль: интерфейс (rem, не плывёт) ---------------- */
  --text-xs:   0.75rem;   --leading-xs: 1rem;     /* 12/16 — подписи, тип файла */
  --text-sm:   0.875rem;  --leading-sm: 1.25rem;  /* 14/20 — вся обвязка        */
  --text-base: 1rem;                              /* 16    — колонка текста     */
  --text-lg:   1.125rem;  --leading-lg: 1.75rem;  /* 18/28 — заголовок пустого  */
  --text-h1:   1.625rem;                          /* 26 → 30 на ≥47.5em         */

  /* ---------- линейка для текста (безразмерная) ----------------
     rem-линейка и em-модель .ui-prose несовместимы: в аккордеоне
     абзац шёл 14/20 = 1.43, а таблица .925em внутри него
     наследовала те же жёсткие 20px = 1.54. Тексту — отношения. */
  --leading-tight: 1.25;   /* заголовки          */
  --leading-prose: 1.6;    /* колонка и панель   */

  /* ---------- ритм прозы (em: переносится между 16px и 14px) ---
     Было 13 разных отступов, ни одного из шкалы, и межабзацный
     12px вдвое меньше межстрочного 27.2px — абзацы не читались
     как абзацы. */
  --flow-p:      1.25em;   /* абзац, список, pre, цитата, таблица */
  --flow-li:     0.5em;    /* между пунктами                      */
  --flow-h-top:  2em;      /* над заголовком                      */
  --flow-h-bot:  0.75em;   /* под заголовком                      */
  --flow-block:  2em;      /* линейка, блочная формула            */
  --flow-indent: 1.35em;   /* втяжка списка                       */

  /* ступени внутри текста — тоже em, иначе .ui-prose перестанет
     работать в панели на 14px */
  --prose-h1:   1.5em;    --prose-h2: 1.25em;  --prose-h3: 1.125em;
  --prose-code: 0.875em;  --prose-small: 0.925em;

  --font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semibold: 600;

  /* ---------- размеры: ритм строки и иконки --------------------
     2rem написан в коде 13 раз, 2.25rem — 8, 1rem иконки — 9.
     Теперь это имена, а не совпадения. */
  --row-h: 2rem;          /* строка панели, иконочная кнопка */
  --control-h: 2.25rem;   /* кнопка по умолчанию             */
  --control-h-lg: 2.5rem;
  --icon: 1rem;  --icon-sm: 0.75rem;  --icon-lg: 1.25rem;
  --tap: 2.75rem;         /* 44px — @media (pointer:coarse)  */

  /* ---------- раскладка -----------------------------------------
     Одно число задаёт ширину всего сайта: и колонки текста, и
     внутренней части верхней полосы. Отсюда общая вертикальная ось.

     37rem = 592px. Средняя ширина кириллического знака Inter —
     0.547em, значит 592 / (0.547 × 16) = 68 знаков. В ch мера не
     считается: ch мерит глиф «0» (0.6306em) и на кириллице врёт
     на 15%. Прежний clamp(60ch, 34rem+12vw, 72ch) давал 80—83
     знака на любом мониторе от 1280 до 2560.

     rem, а не em: полоса набрана 14px, колонка 16px — в em
     они разъехались бы на 12% и потеряли общую ось. */
  --shell-text: 37rem;
  --page-pad: 1.25rem;          /* → 3rem на ≥47.5em */
  --topbar-h: 3rem;

  /* ---------- тень --------------------------------------------- */
  --shadow-color: 0 0 0;
  --shadow-xs: 0 1px 2px 0 rgb(var(--shadow-color) / var(--a-shadow-xs));

  /* ---------- движение -----------------------------------------
     150—250 мс: пользователь в работе, а не смотрит анимацию.
     Литералы 200ms / 250ms / .7s / 2s из кода переехали сюда. */
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-in-out: cubic-bezier(.4, 0, .2, 1);
  --duration: 180ms;
  --duration-pulse: 2s;
  --delay-tooltip: 250ms;

  /* ---------- слои ---------------------------------------------
     Только эти значения. Ни одного 999. */
  --z-raised: 10;
  --z-sticky: 20;
  --z-tooltip: 60;

  /* ---------- перелом -------------------------------------------
     Остался один, и тот типографический: раскладка одноколонная,
     ломаться в ней нечему. Значение продублировано литералом
     в @media (в медиазапросе var() не работает); здесь записан
     курс: 1em = 16px, значит 47.5em = 760px.
     em, а не px: полное масштабирование браузера пиксели
     пересчитывает, а увеличение ТОЛЬКО шрифта — нет. */
  --bp-narrow: 47.5em;
}

/* Выше 760px поля страницы расходятся, а заголовок подрастает.
   Ширина колонки при этом не меняется: 68 знаков — это 68 знаков
   и на ноутбуке, и на 4K. Лишнюю ширину забирают поля, а не строка. */
@media (min-width: 47.5em){
  :root{ --page-pad: 3rem; --text-h1: 1.875rem }
}
