/* ===========================================================================
   Lingo — design system (single source of truth for colour, shape, type, depth)
   Loaded BEFORE the style-NN-*.css shared layer. Components must consume the semantic tokens below,
   never raw hex. The five brand colours come from the owner's palette:

     deep sky blue   #5cc8ff   accent / selection / links      -> --sky-*
     lavender veil   #f2d5f8   soft surface / draft state      -> --veil-*
     vintage grape   #493657   ink / primary fill (the anchor) -> --grape-*
     celadon         #afd5aa   success / done                  -> --cel-*
     grapefruit pink #fe6d73   attention / danger              -> --gf-*

   Contrast rules that keep the whole app readable:
     light fill + grape ink   (sky-300 -> 5.7:1, cel-300 -> 6.5:1)
     grape fill + white text  (10.6:1)
     never white text on a light sky/celadon/grapefruit fill.
   =========================================================================== */

:root{
  /* ---- ramps (the brand hex sits at the starred stop) ---------------------- */
  --sky-50:#f0faff;  --sky-100:#dbf3ff; --sky-200:#b9e7fd; --sky-300:#8fdaff;
  --sky-400:#5cc8ff; /* * */            --sky-500:#2cb0f2; --sky-600:#0d91d3;
  --sky-700:#0971a5; --sky-800:#07567e;

  --veil-50:#fcf7fd; --veil-100:#f8e9fb;
  --veil-200:#f2d5f8; /* * */           --veil-300:#e7beef; --veil-400:#d6a3e0;
  --veil-500:#ba80c6; --veil-600:#9d60a9; --veil-700:#794983; --veil-800:#5b3762;

  --grape-50:#f5f2f7; --grape-100:#ebe6ef; --grape-200:#dad2e0; --grape-300:#beb2c7;
  --grape-400:#9b8ba7; --grape-500:#786388; --grape-600:#5f496e;
  --grape-700:#493657; /* * */          --grape-800:#352541; --grape-900:#251a2e;

  /* ── бумага (blox51 #2): НЕЙТРАЛЬ БАЗОВОЙ СХЕМЫ ───────────────────────────
     Виноградная рампа остаётся брендовой (шапка, логотип), но роль нейтрали у
     неё забирает бумага: приложение должно читаться как хорошая полиграфия, а
     не как белый интерфейс. Виноград светит холодно-сиреневым, и на нём любая
     карточка выглядела вклеенной в фон, а не лежащей на нём.
     Синие схемы (scheme2/scheme3) НЕ трогаем — они переопределяют нейтраль у
     себя и остаются холодными. Рельеф и слои от цвета не зависят.
     Ключевые стопы (замер контраста к бумаге --paper-100 #fbf9f5):
       300 — СТОЛ, −11% светлоты от бумаги: с него глаз уверенно видит слой;
       600 — 3.0:1, нейтральный рельс (тише синего, иначе ломается иерархия);
       700 — 4.66:1, подсказки;  800 — 6.4:1 и 5.1:1 на столе, вторичный текст. */
  --paper-50:#fdfcfa;  --paper-100:#fbf9f5; --paper-200:#efe9dc;
  --paper-300:#e2dac9; /* стол */          --paper-400:#cfc3ab; --paper-500:#b3a68f;
  --paper-600:#9c8f7c; --paper-700:#7a6f63; --paper-800:#5f5749;
  --paper-900:#39312a; --paper-950:#241e19;

  --cel-50:#f1f9f0; --cel-100:#e4f3e2; --cel-200:#cee7ca;
  --cel-300:#afd5aa; /* * */            --cel-400:#86bd7f; --cel-500:#60a857;
  --cel-600:#4b8943; --cel-700:#396c33; --cel-800:#2b5426;

  --gf-50:#ffebeb; --gf-100:#ffdbdc; --gf-200:#fdbec0; --gf-300:#fe9a9d;
  --gf-400:#fe6d73; /* * */             --gf-500:#f5474d; --gf-600:#db242a;
  --gf-700:#a92327; --gf-800:#7e2023;

  /* ---- semantic: text ----------------------------------------------------- */
  --ink:var(--paper-900);         /* headings & body, 12.1:1 на бумаге          */
  --ink-strong:var(--paper-950);  /* the one loud line on a screen              */
  --muted:var(--paper-800);       /* secondary text, 6.4:1                      */
  --faint:var(--paper-700);       /* hints, disabled, timestamps, 4.66:1        */
  /* ТЕКСТ, ЛЕЖАЩИЙ НА СТОЛЕ, а не на бумаге. Стол темнее бумаги на 11%, поэтому
     --faint на нём даёт 1.9:1 и просто исчезает (замер, blox51 #2). Любая подпись
     вне карточки — заголовок дня, счётчик над списком, подпись раздела — берёт
     этот тон: 5.1:1 на столе. В синих схемах стол светлый, там он равен --muted. */
  --on-bg:var(--paper-800);
  --on-dark:#fff;

  /* ---- semantic: surfaces ------------------------------------------------- */
  /* ПРАВИЛО СЛОЁВ (blox51 #2): уровня ровно ДВА и они чередуются —
     СТОЛ (--bg, тёмный) и БУМАГА (--card, светлая). Никогда два светлых подряд:
     до этого страница #faf7fb, панель #fff и плашка #fcf7fd отличались на 3-4%,
     и плашка читалась не как листок сверху, а как вмятина внутри. Панель между
     ними заливки больше не имеет — она держится волоском (см. .opane). */
  --bg:var(--paper-300);          /* СТОЛ — на нём лежит всё                    */
  --card:var(--paper-100);        /* БУМАГА — карточки, плашки, шторки          */
  --surface:var(--paper-200);     /* inset panels, wells — углубление в бумаге  */
  --surface-2:var(--paper-200);   /* softer, warmer inset                       */
  --task-plaque:var(--card);      /* плашка таска — тоже БУМАГА, не подложка    */
  --line:var(--paper-400);        /* default border                             */
  /* ВОЛОСОК НЕ МОЖЕТ БЫТЬ ЦВЕТОМ СТОЛА. Он был ровно var(--paper-300), то есть
     байт в байт --bg: карточка, панель или чип, лежащие на столе, рисовали свою
     границу цветом того самого стола — 1.00:1, рамки не существовало вовсе (а её
     просят ~30 мест: .rect, .hub-card, .opane, .rchip, .stat-tile…). Берём стоп
     МЕЖДУ столом и рамкой по умолчанию: волосок темнее и бумаги, и стола, поэтому
     виден на обоих. Замер: на бумаге 1.32→1.51, на столе 1.00→1.14, на подносе
     --surface 1.15→1.31. Гуще брать нельзя — на подносе у плашки есть ещё и тень,
     и жирный контур поверх неё читается двойным краем. Синие и тёмная схемы
     переопределяют волосок у себя, там совпадения со столом не было. */
  --line-soft:color-mix(in srgb, var(--paper-400) 60%, var(--paper-300));
  --line-strong:var(--paper-500);

  /* ---- semantic: accent (sky) --------------------------------------------- */
  /* АКЦЕНТ БАЗОВОЙ СХЕМЫ — ЧЁРНЫЙ (blox51 #3, заход 3.2, решение владельца).
     Небесно-синий был акцентом с самого начала палитры и после перехода на тёплую бумагу
     остался единственным холодным пятном: обводка выбранной группы, заливка выбранного дня,
     рамка на наведении, ссылки — всё это светилось синим посреди баклажана и бумаги.
     «Чёрный» здесь НЕ #000: чистый чёрный на тёплой бумаге читается дырой ровно по той же
     причине, по которой стол не серый, а бежевый. Чёрный этой схемы — её собственные чернила
     --paper-900. Синий никуда не делся: он остаётся брендовым (радуга логотипа, радуга
     плейлиста) и остаётся акцентом ОБЕИХ синих схем — там он свой.
     Акцент как ТЕКСТ на тон темнее корпуса: акцент-текст отличается от обычного не другим
     цветом, а бОльшим количеством чернил. Ссылки при этом подчёркнуты, так что не теряются. */
  --accent:var(--paper-900);      /* обводки, выделение, подчёркивание           */
  --accent-ink:var(--paper-950);  /* акцент ТЕКСТОМ — гуще корпуса, 15.8:1       */
  /* АКЦЕНТ ЛИНИЕЙ (blox52 #5). Обводка на наведении, рамка выбранного, контур
     играющего трека — всё, где акцент работает ЛИНИЕЙ, а не заливкой, берёт этот
     токен, а не --accent. Разница видна только в синих схемах: там акцент — светлый
     Maya, заведённый под заливки (на нём лежит --ink), и линией он давал 2.02:1 на
     белой карточке и 1.53 на столе — наведение мышью не отличалось от покоя. Средняя
     Maya даёт 3.52 и 2.67. В базовой и ночной схемах --accent-deep РАВЕН --accent
     (там акцент и так предельно контрастен), поэтому правка их не касается вовсе. */
  --accent-deep:var(--paper-900); /* иконки-акценты + акцент линией                */
  /* тот же рецепт, что у состояний: пигмент подмешивается В БУМАГУ, поэтому поверхность сама
     следует бумаге своей схемы. Держим их СВЕТЛЫМИ намеренно: на обеих лежит --ink, и стоит
     подмешать гуще — текст на них уйдёт под AA. Стережёт проба «акцентные поверхности». */
  --accent-tint:color-mix(in srgb, var(--paper-900) 9%, var(--card));
  --accent-line:var(--paper-500);

  /* ---- semantic: states ---------------------------------------------------- */
  /* ТИНТ СОСТОЯНИЯ = БУМАГА + 12% ПИГМЕНТА (blox51 #3, заход 3). Раньше каждый тинт
     был самым бледным стопом своей лестницы, то есть пигментом, разбавленным БЕЛЫМ.
     Пока фон был бело-сиреневым, это работало. На тёплой бумаге три состояния из
     четырёх дали к --card 1.01–1.02 при пороге различимости ~1.06 — то есть на листе
     их не стало видно ВООБЩЕ, а лёжа на столе они читались как ещё один чистый лист
     (1.29–1.31 — ровно столько же, сколько у самой бумаги, 1.32). Уцелел один
     грейпфрут, и оттого казалось, что он полез вперёд: он не полез, вокруг стало тихо.
     Замешивать бледный стоп гуще бесполезно — селадон даже вдвое гуще даёт 1.07,
     вуаль 1.04. Поэтому пигментом работает СРЕДНИЙ стоп той же лестницы: ни одного
     нового цвета в проекте не появляется, а все четыре звучат в один голос, 1.12–1.16.
     Основа — var(--card), поэтому тинт сам следует бумаге СВОЕЙ схемы: в синих схемах
     --card белый, и подмес идёт в белое. Отдельных значений для схем не нужно.
     Порог стережёт проба «состояния слышно» в tools/interaction-dom.js. */
  /* ok/done — celadon */
  --ok:var(--cel-500); --ok-ink:var(--cel-700); --ok-line:var(--cel-200);
  --ok-tint:color-mix(in srgb, var(--cel-500) 12%, var(--card));
  /* alert — the ONE "teacher must act" colour (unassigned homework, to-check
     counters, nag frames). Was amber; grapefruit now owns it. */
  --alert:var(--gf-500); --alert-ink:var(--gf-700); --alert-line:var(--gf-200);
  --weekend:var(--alert);   /* blox83 #5 — Сб/Вс на каретке: розовый грейпфрут, как выходные в календаре */
  --alert-tint:color-mix(in srgb, var(--gf-500) 12%, var(--card));
  /* white text on a SOLID alert fill needs the darker stop: #fff on gf-500 is only 3.6:1,
     on gf-600 it is 4.9:1. Filled white-on-red badges (к-проверке counter, group nag number,
     edited flag) use this; the tint/dot/nag-frame keep the brand gf-500. */
  --alert-solid:var(--gf-600);
  /* danger — destructive only (delete, graduate) */
  --danger:var(--gf-600); --danger-ink:var(--gf-700);
  /* draft — unpublished work in progress. Was amber (clashed with alert); the
     lavender veil now carries it, so "черновик" and "надо действовать" never
     look alike again. */
  --draft:var(--veil-500); --draft-ink:var(--veil-700); --draft-line:var(--veil-300);
  /* ШТРИХОВКА ЧЕРНОВИКА (blox52 #8) — «лист, который ещё не отпечатан». Кладётся на
     подложку панели черновика косой линейкой поверх --surface; сила ≤4%, потому что это
     ФАКТУРА, а не состояние: заметно гуще — и панель прочиталась бы отключённой.
     Тон — тот же тон тени схемы (--sh-rgb), поэтому штрих тёплый на тёплой бумаге и
     холодный на холодной. Ночью ПЕРЕВОРАЧИВАЕТСЯ (см. ночную схему): по тёмной подложке
     тёмный штрих не виден вовсе — тот же приём, что у обрезного края листа. */
  --draft-hatch:rgba(var(--sh-rgb),.04);
  /* ЛИНОВКА ПУСТОЙ СТРАНИЦЫ (blox52 #15) — горизонтальные линии пустой панели монитора
     («раньше занятий не было»). Как и штриховка черновика — ФАКТУРА, потолок 4%; но тон —
     ЧЕРНИЛА схемы, не тень: линейка ежедневника проведена тем же пером, что и записи, и
     через var(--ink) сама переворачивается ночью (светлые линии по тёмной бумаге) — своей
     копии в блоке схем не нужно (ловушка §11 не срабатывает: роль собрана из роли). */
  --page-rule:color-mix(in srgb, var(--ink) 4%, transparent);
  --draft-tint:color-mix(in srgb, var(--veil-500) 12%, var(--card));

  /* ---- semantic: homework task types (student rectangles) ------------------ */
  /* ИЕРАРХИЯ ОБЯЗАТЕЛЬНА: «нужна сдача» должно быть ГРОМЧЕ, чем «просто сделать».
     На бумаге это проверяется контрастом к --card: sky-700 даёт 5.9:1, paper-600 —
     3.0:1. Тёмный нейтральный стоп (paper-800, 6.4:1) кричал бы громче синего —
     ровно эта ошибка всплыла на замере (blox51 #2), не повторять. */
  --task-plain:var(--paper-600);  /* nothing to hand in — тише                   */
  --task-sub:var(--sky-700);      /* has a turn-in — громче                      */
  /* theme-frame outline colour (blox26 #5): ONE token per scheme so the unified
     frame recolours with the palette. Scheme2 — ink; scheme3 — the header's
     deep-Maya right edge (overrides below).
     blox51 #4: базовая схема была --paper-400 — тот же тон, что и стол под листом,
     поэтому скобка темы на снимке ПРОПАДАЛА (комментарий обещал grape, но его тут
     никогда не было). Теперь --ink: та же линия, что и в графитовой схеме, 12.1:1
     на бумаге. Рамка темы — единственный контур, который группирует таски, и он
     обязан быть виднее волоска самой карточки. */
  --frame-line:var(--ink);
  /* challenge — the ONE gold in the product (blox15 #6). A challenge is a task
     everybody can see everybody do; gold is what makes it read as a prize, not
     as an alert. Nothing else may use it. */
  /* золото потемнело с #c9962c до #b07d16: на белом оно давало 2.3:1 и на тёплой
     бумаге терялось совсем; теперь 3.45:1 — приз виден, но тише синего рельса. */
  --gold:#b07d16; --gold-line:#eddcae;
  --gold-tint:color-mix(in srgb, var(--gold) 12%, var(--card));
  /* чернила углублены с #8a6412: на новом тинте старые давали 4.49:1 — на волосок
     ниже AA; теперь 5.15:1, и заодно 4.54:1 на золотой рамке вместо 3.95:1. */
  --gold-ink:#7f5b10;
  /* НАДПИСЬ НА ЗОЛОТОЙ ЗАЛИВКЕ (номер главы у книги, общий проход редизайна 27.10). Днём это та же
     самая тёмная --ink-strong; ночью --ink-strong становится белой, а золото светлеет — белое на
     нём давало 2.2:1. Ночное значение — ниже, в блоке тёмной схемы. */
  --on-gold:var(--ink-strong);

  /* Файловое окно «Классный проводник» (blox33 #1, story 7-bis; перекрашено blox51 #10).
     Тут проходит ГРАНИЦА между чужим и своим, и она проведена по одному признаку:
       ПОВЕРХНОСТЬ — яндексовская. Белая рабочая область, серая обвязка, красная «Я»:
       чужой диск обязан читаться как чужой диск, поэтому это СЫРОЙ бренд-hex,
       сознательно вне блока схем (как --gold) — окно выглядит так в любой схеме.
       КОНТРОЛЫ — НАШИ. Заливка кнопки, выделение, обводка берут палитру ТЕКУЩЕЙ схемы
       (владелец, blox51 #10: «все кнопки в проводнике — к текущей палитре»). Раньше
       и они были яндексовскими, и посреди баклажана с бумагой горел чужой синий.
     Применяется scoped на .plscreen / .exp-shutter (см. explorer.css — там весь скин). */
  --ya-surface:#ffffff;     /* рабочая область файлов — белая, как у Диска */
  --ya-soft:#f4f5f7;        /* серые полосы: шапка окна, адресная строка, тулбар */
  --ya-line:#e6e7ea;        /* тонкие границы-волоски */
  --ya-red:#fc3f1d;         /* фирменная красная «Я» (playlist.css, .pl-ya) */
  /* СИНИЙ ПРОВОДНИКА — единственный цвет контролов, который остался синим, и это
     решение владельца: синий есть в палитре (знак Lingo, радуга плейлиста), поэтому
     ссылки окна менять не потребовалось. Но синий теперь НАШ, а не яндексовский
     #2b5fd9: sky-700 даёт 5.4:1 на белой области файлов. Синие схемы переопределяют
     его на собственные акцентные чернила — см. блок схем ниже. */
  --exp-link:var(--sky-700);

  /* ---- РАСПИСАНИЕ ШКОЛЫ: цвет педагога (blox61 #8) -------------------------
     На бумажном листе школы цвет плашки означает ПЕДАГОГА — так методист читает сетку,
     не вчитываясь в подписи. Палитра КАТЕГОРИАЛЬНАЯ: восемь пастельных заливок, которые
     не означают состояния (в отличие от --ok/--danger) и не должны конкурировать с ними
     по громкости. Поэтому они — сырые пастели вне блока схем, как --gold и --ya-*: лист
     расписания выглядит одинаково в любой цветовой схеме, иначе «зелёная = Angie» перестала
     бы быть правдой при переключении палитры.
     Текст на них — --ink (те же чернила, что на бумаге): каждая заливка проверена на
     контраст с ним, минимум 8:1, поэтому подпись читается и на самой тёмной из восьми.
     Номер = позиция педагога в списке с сервера, а не свойство человека. */
  --sched-t1:#bbe9cd;  --sched-t2:#d6cdf5;  --sched-t3:#fbe79a;  --sched-t4:#f8c0c4;
  --sched-t5:#f9c489;  --sched-t6:#bcd8f5;  --sched-t7:#a8e0de;  --sched-t8:#e7cdb6;
  --sched-ink:var(--ink);

  /* ---- САЛЮТ (22.09.2026) ---------------------------------------------------
     Конфетти, которым отвечает поставленная реакция учителя (public/salute.js).
     Цвета КАТЕГОРИАЛЬНЫЕ и сознательно вне блока схем — как --sched-t* и --ya-*:
     праздник выглядит праздником в любой палитре, а привязать их к акценту значило бы
     получить салют цвета фона в схемах, где акцент приглушён до бумаги.
     Шесть штук: частиц 14, цвета идут по кругу, поэтому меньше четырёх дают полосатость.
     Все шесть — насыщенные, средней светлоты: читаются и на белой карточке, и на ночной. */
  --salute-1:#f5a524;  --salute-2:#e0679b;  --salute-3:#4cc38a;
  --salute-4:#5b8def;  --salute-5:#f2d024;  --salute-6:#a06bde;
  /* накладка: плашка обводится тревожной линией, а не перекрашивается — цвет уже занят
     педагогом, и подмена цвета стёрла бы главный признак сетки */
  --sched-clash:var(--danger);

  /* ---- component role tokens (blox26) --------------------------------------
     Added so components speak ROLES, never raw ramp stops (var(--grape-500)…).
     `npm run check` now BLOCKS a raw ramp reference outside this file. Each token
     points at a ramp stop; a colour scheme re-skins the app by overriding the
     token here — so all screens follow the 5-colour palette from ONE place. */
  --muted-strong:var(--paper-900);  /* label a shade darker than --muted; AA on --fill-soft */
  --fill-soft:var(--paper-200);     /* subtle neutral fill (tab track, hover well, chip) — kept
                                       distinct from --surface so a hover over a well still reads */
  --line-mid:var(--paper-400);      /* input & visible borders, between --line and --line-strong */
  --primary:var(--paper-900);       /* dark anchor FILL under white text: selected tab, dragged
                                       lesson tile, pool play button (the sky accent is too light) */
  --primary-strong:var(--paper-950);/* darkest chrome fill: toasts, drag readout */
  /* ЯКОРЬ СХЕМЫ (blox51 #3, заход 3.1) — СПЛОШНАЯ тёмная заливка под белым текстом:
     кнопка-заливка, вкладка выбранного учителя, выбранный сегмент, полоса загрузки,
     акцент плеера, перетаскиваемый чип урока. Раньше эту роль звали --accent-solid и
     она была НЕБЕСНО-СИНЕЙ во всех трёх схемах (базовая sky-700, обе синих #12689e):
     схема перекрашивала шапку и первичную кнопку, а всё остальное сплошное оставалось
     синим — в баклажановой схеме синева бралась из ниоткуда. Теперь у каждой схемы
     ОДИН якорь, тот же, что в шапке: баклажан · графит · Maya.
     Якорь действует и в окне проводника: чужой там только ФОН, кнопки наши (blox51 #10). */
  --anchor:var(--grape-700);        /* баклажан; белый текст 10.6:1                    */
  /* ЯКОРЬ, РАБОТАЮЩИЙ ЧЕРНИЛАМИ (заголовки плиток хаба .hub-t, blox51 #4). В светлых схемах
     это тот же цвет — светлая бумага позволяет ОДНОМУ тону нести и белую подпись на себе, и
     себя на бумаге. Тёмная схема (blox51 #11) сделала это невозможным арифметически: чтобы
     белый на якоре давал 4.5:1, якорь должен быть темнее L=0.18, а чтобы сам якорь читался на
     ночной бумаге — светлее L=0.25. Одного значения на два конца не существует, поэтому роль
     разъехалась на два токена. Светлые схемы держат их равными и ничего не замечают. */
  --anchor-ink:var(--anchor);
  --accent-fill:color-mix(in srgb, var(--paper-900) 16%, var(--card)); /* шаг гуще --accent-tint */
  /* ВЫДЕЛЕНИЕ ТЕКСТА МЫШЬЮ — свой токен, а не --accent-fill. Раньше ::selection брал
     заливку, и это давало 1.34:1 к бумаге: протащил мышью по абзацу — и не видно, что
     выделено. Отдельный токен нужен потому, что у заливки другая работа: на ней лежат
     свои пузыри чата и выбранные записи, её стережёт проба «акцентные поверхности»
     (--ink на ней обязан держать AA), и подкрутить её ради выделения значит подвинуть
     полдюжины поверхностей. Тот же рецепт, только пигмента 26% вместо 16%: 1.63:1 к
     бумаге в базовой, 1.99 в тёмной, при этом текст на выделении 7.4 и 6.4. */
  --sel-bg:color-mix(in srgb, var(--accent) 26%, var(--card));
  --ok-solid:var(--cel-700);        /* green FILL under white text — cel-600 was 4.2:1, under AA */
  --ok-fill:color-mix(in srgb, var(--cel-500) 22%, var(--card));   /* done fill, гуще --ok-tint */
  --alert-fill:color-mix(in srgb, var(--gf-500) 22%, var(--card)); /* drag-over, trash — гуще --alert-tint */
  --alert-strong:var(--gf-700);     /* dark red FILL under white text: recording-on, count-badge hover */
  /* объявление — a STANDING note, deliberately lavender so it never reads as a state
     (draft/alert/done). Fixed across schemes: veil is not a re-skinned family. */
  --note-bg:color-mix(in srgb, var(--veil-500) 12%, var(--card));
  --note-line:var(--veil-300); --note-ink:var(--veil-700);

  /* ---- shape --------------------------------------------------------------- */
  /* ЛЕСТНИЦА РАДИУСОВ (blox51 #3, заход 5). Правило одно: РАДИУС ПО РАЗМЕРУ ПРЕДМЕТА —
     чем крупнее вещь, тем мягче её угол. До этого в public/*.css лежало 165 радиусов числом,
     СЕМНАДЦАТЬ разных значений от 1 до 999, против 38 через токен. Значения при этом не были
     случайны: 9px стоял на мелких контролах (чип, тег, строка, «⋯»), 12px — на контейнерах
     (карточка, панель, поле). То есть правило соблюдалось интуитивно, но одна и та же роль
     записывалась то девяткой, то десяткой, то двенадцаткой, и соседние предметы одного класса
     скруглялись по-разному без причины. Ступени названы по КЛАССУ предмета:
       2xs — полоска, точка, прогресс (браузер всё равно режет радиус до половины высоты);
       xs  — мелкий контрол: кнопка-иконка, бейдж, ползунок;
       sm  — чип, тег, строка списка, сегмент;
       md  — карточка, панель, поле ввода, коробка;
       lg  — крупный контейнер, шторка;
       xl  — лист, модалка;  2xl — гигант;  pill — таблетка. */
  --r-2xs:4px; --r-xs:8px; --r-sm:10px; --r-md:14px; --r-lg:18px; --r-xl:24px; --r-2xl:30px;
  --r-pill:999px;

  /* ---- depth — тень всегда в тон поверхности, никогда серая ----------------
     Тон вынесен в ОДИН токен: без него тёплая тень бумаги протекла бы в синие
     схемы, где поверхность холодная (та же §11-ловушка, что с --card). Схема
     переопределяет только --sh-rgb, все пять теней следуют за ним сами.
     Третий слой (дальнее рассеяние) добавлен к --sh-1 и --sh-2: он и создаёт
     ощущение «лежит», которого не даёт пара контакт+ближний. */
  --sh-rgb:70,55,35;              /* тёплый — тон бумажного стола               */
  /* ВОЛНА ОТ КАСАНИЯ — РЕЖИМ НАЛОЖЕНИЯ (blox52 #8). На бумаге волна работает как
     чернила: она УМНОЖАЕТ поверхность (краска впитывается в лист, тон и зерно бумаги
     видны сквозь неё), а не кладёт полупрозрачное пятно сверху. Роль живёт здесь, а не
     у .ripple, потому что она СХЕМНАЯ: ночью бумага тёмная, чернила светлые, и
     умножение светлым по тёмному не даёт ровно ничего — ночь переопределяет на normal.
     Залитые роли кнопок гасят её у себя (см. .btn--primary в style-06-buttons.css): у них волна
     белая, а умножение белым — тождество. */
  --ripple-blend:multiply;
  --sh-1:0 1px 1px rgba(var(--sh-rgb),.05), 0 2px 4px rgba(var(--sh-rgb),.05),
         0 8px 16px -12px rgba(var(--sh-rgb),.28);
  --sh-2:0 1px 2px rgba(var(--sh-rgb),.05), 0 5px 12px rgba(var(--sh-rgb),.06),
         0 16px 28px -18px rgba(var(--sh-rgb),.40);
  --sh-3:0 3px 8px rgba(var(--sh-rgb),.07), 0 12px 28px rgba(var(--sh-rgb),.10);
  --sh-4:0 10px 24px rgba(var(--sh-rgb),.12), 0 30px 60px rgba(var(--sh-rgb),.16);
  /* вдавливание кнопки. Раньше рядом жила --sh-inset (мягкая внутренняя тень «колодца»), но
     колодец в этом проекте выражен ЦВЕТОМ (--surface), а не тенью, и последнее её место — окно
     согласия — оказалось не колодцем, а листом на столе (blox52 #4). Токен снят как остаток. */
  --sh-press:inset 0 2px 5px rgba(var(--sh-rgb),.30);
  /* ФОКУС-КОЛЬЦО — ДВУСЛОЙНОЕ (зазор + контур). Одним полупрозрачным слоем оно не
     работает: кольцо ложится на ЧЕТЫРЕ разных фона (бумага, стол, тёмная шапка,
     цветная заливка кнопки), и любой один цвет на каком-то из них исчезает —
     в синих схемах прежнее rgba(123,190,234,.45) давало на белом 1.35:1, то есть
     с клавиатуры не было видно ВООБЩЕ, где ты находишься.
     Внутренний слой — 2px цветом БУМАГИ: он отрезает кольцо от самого предмета,
     и он же и есть видимая часть кольца на тёмной шапке. Внешний — 2px тёмным
     фирменным (--ring-c): он и есть кольцо на светлых фонах (12.1:1 на бумаге,
     9.2:1 на столе в базовой; 6.0 и 4.6 в синих; в тёмной схеме наоборот — светлый
     контур, 10.5 и 13.3).
     Третьим слоем ОБЯЗАТЕЛЬНО идёт --sh-1: :focus-visible ставит box-shadow, а он
     заменяет тень целиком — без этой строки кнопка и чип группы теряли бы свою
     тень покоя ровно в момент фокуса и на кадр «проваливались» в лист. */
  --ring-c:var(--accent);
  --ring:0 0 0 2px var(--card), 0 0 0 4px var(--ring-c), var(--sh-1);
  /* КОЛЬЦО ВНУТРЬ (ночной редизайн 27.10.2026). Внешнее кольцо выступает на 4px за край
     предмета — и у предмета, стоящего в обрезающей ленте (чип группы в .gstrip, день
     каретки, вкладка в прокручиваемом ряду), его срезает overflow соседа: с клавиатуры
     не видно, где ты. Тот же рецепт, перевёрнутый внутрь: контур — по самому краю, зазор
     цветом бумаги — под ним. Тени покоя у него нет намеренно: такой предмет ставит её
     себе сам, а кольцо внутрь её не заменяет, а дописывается к ней (box-shadow списком). */
  --ring-inset:inset 0 0 0 2px var(--ring-c), inset 0 0 0 4px var(--card);

  /* ---- ТИСНЕНИЕ (letterpress) — материал самой плашки (blox51 #3, заход 2) --
     Плашка перестала быть «прямоугольником с цветной границей слева» и стала
     ЛИСТОМ БУМАГИ, в который рельс ВДАВЛЕН. Два разных эффекта, и их нельзя
     путать:
       --emb        лежит на плашке: светлый бортик по верхней грани листа +
                    едва заметная тень по нижней. Это то, что делает край
                    бумаги видимым, когда лист лежит на столе такого же тона.
       --emb-groove лежит на рельсе (::before): тень ВНУТРИ канавки сверху-слева,
                    отблеск снизу-справа, и белый бортик СНАРУЖИ снизу — бумага
                    приподнялась по краю продавленной канавки.
     ГЛУБИНА (blox51 #4): дно канавки было .5 — на крупном снимке рельс сидел в
     чёрной борозде, и тиснение читалось как грязь, а не как оттиск. Ослаблено до
     .32 (и .28 в холодных схемах): оттиск остался, тень перестала спорить с самим
     цветом рельса. Смотреть только через `shot.js --el ".oent" --dpr 4`.
     Схемы переопределяют --emb-lo: тёплая грязь в канавке на холодной бумаге
     читается как пятно, а не как тень (та же §11-ловушка, что с --card). */
  --emb-hi:rgba(255,255,255,.95);         /* бортик листа — верхняя грань бумаги  */
  --emb-lo:rgba(20,12,4,.32);             /* дно канавки под рельсом              */
  --emb-edge:rgba(var(--sh-rgb),.18);     /* волосок по краю канавки              */
  --emb:inset 0 1px 0 var(--emb-hi), inset 0 -1px 0 rgba(var(--sh-rgb),.05);
  --emb-groove:inset 2px 2px 2.5px var(--emb-lo),
               inset -1px -1px 1.5px rgba(255,255,255,.28),
               0 1px 0 var(--emb-hi),
               0 0 0 .5px var(--emb-edge);
  /* пигмент рельса подмешивает к --rail тень сверху и отблеск снизу. Сам градиент
     (--emb-rail) живёт НЕ здесь, а в style-02-hw-card.css на самой плашке: токен на :root
     подставил бы var(--rail) от :root, где рельса нет, и фон обнулился бы. */
  --emb-deep:#000;                        /* верх рельса — в тени борта канавки  */
  --emb-lift:#fff;                        /* низ рельса — отражённый свет        */

  /* ---- ЛИСТ — ОДИН РЕЦЕПТ НА ВСЮ БУМАГУ (blox52 #4, пп. 1-2) ---------------
     Тиснение придумали в blox51 для плашки таска — и там оно и осталось. Панель,
     плитка кабинета, всплывашка настроек и окно согласия собирались КАЖДАЯ по
     своей тени (--sh-1 / --sh-2 / --sh-3 / --sh-4, а окно согласия — внутренней), и светлого
     бортика по верхней грани у них не было вовсе: эффект «лист имеет толщину»
     был придуман и оплачен, но роздан одному предмету из пяти.
     Рецепт теперь ОДИН, и слоёв в нём три, всегда в этом порядке:
       1. ОБРЕЗНОЙ КРАЙ (--sheet-edge) — полупиксельный контур в тон тени. У
          настоящей бумаги край — это не тень, а ТОРЕЦ: без него лист выглядит
          нарисованным, с ним — вырезанным. Полпикселя на экране БЕЗ удвоения
          точек округляется до целого и стало бы заметной рамкой, поэтому
          прозрачность взята вдвое ниже той, при которой контур читается линией:
          на обычном экране это волосок на грани видимости, на retina — торец.
       2. ТИСНЕНИЕ (--emb) — светлый бортик по верхней грани и тень по нижней.
       3. ТЕНЬ (--sh-N) — ступень подъёма, и выбирают именно её: 1 — лист лежит,
          2 — приподнят, 3 — всплыл над содержимым, 4 — модалка.
     Два частных случая, оба по делу, а не «ещё один рецепт»:
       --sheet-pop  — бортик ОСЛАБЛЕН: всплывашка настроек висит вплотную под
                      тёмной шапкой, и 95%-белый бортик блестел бы там полосой;
       --sheet-rise — тень уходит ВВЕРХ: шторка поднимается снизу, а свет
                      по-прежнему падает сверху.
     Инвариант «у всех листов один рецепт» стережёт «рецепт листа» в
     `npm run check` и проба «материал бумаги» в tools/interaction-dom.js. */
  --sheet-edge:0 0 0 .5px rgba(var(--sh-rgb),.12);
  /* ЗАТЕМНЕНИЕ ПОД МОДАЛКОЙ. Тоже тон тени схемы, но своим токеном и своей плотностью:
     цвет тени — не чёрный, а средний тёплый (70,55,35), и той же .52, что стояла у зашитого
     тёмно-фиолетового числа, он затемняет ЗАМЕТНО слабее (стол уходил бы в 151, а не в 124).
     .68 возвращает прежнюю силу, и теперь она одна на оба места, где накладка встречается. */
  --scrim:rgba(var(--sh-rgb),.68);
  --emb-hi-soft:rgba(255,255,255,.45);    /* бортик под тёмной шапкой — вполсилы */
  --emb-pop:inset 0 1px 0 var(--emb-hi-soft), inset 0 -1px 0 rgba(var(--sh-rgb),.05);
  --sheet-1:var(--sheet-edge), var(--emb), var(--sh-1);
  --sheet-2:var(--sheet-edge), var(--emb), var(--sh-2);
  --sheet-3:var(--sheet-edge), var(--emb), var(--sh-3);
  --sheet-4:var(--sheet-edge), var(--emb), var(--sh-4);
  --sheet-pop:var(--sheet-edge), var(--emb-pop), var(--sh-4);
  --sheet-rise:var(--sheet-edge), var(--emb), 0 -8px 34px rgba(var(--sh-rgb),.18);

  /* ---- ПЛАНКА ШАПКИ (blox52 #5) --------------------------------------------
     Шапка — НЕ лист. Рецепт листа выше говорит «бумага лежит на столе и чуть
     приподнята»; шапка же прибита к верхнему краю, и бумага уезжает ПОД неё.
     Это другой предмет — тяжёлая тёмная планка, — и собран он тремя слоями,
     ни один из которых не повторяет --sheet-*:
       ВОЛОСОК (--plank-lip) — светлая нить по нижней кромке, отблеск на торце
         планки. Он же и есть «материал» шапки: у залитой кнопки фаска (--bevel)
         была, а у шапки не было ничего, и рядом они выглядели сделанными из
         разного. Волосок ПОСТОЯНЕН при любой прокрутке: это торец, а не тень.
       ЛИНИЯ КОНТАКТА (--plank-line) — чёткая тёмная черта БЕЗ размытия прямо
         под кромкой: место, где планка касается стола. Без неё край шапки
         читался обрывом заливки, а не краем предмета.
       КОРОТКАЯ ТЕНЬ (--plank-cast) — 6px рассеяния вместо 28 у --sh-2. Длинная
         размытая тень означает «предмет высоко над столом», то есть парение, —
         а планка прижата.
     ПЛОСКАЯ В НУЛЕ (--plank-flat). Пока страница не прокручена, бумага начинается
     вплотную под шапкой и тени взяться неоткуда — она нужна ровно тогда, когда
     под планку что-то уехало. Слоёв здесь СТОЛЬКО ЖЕ и они той же формы, меняется
     только прозрачность двух нижних: браузер умеет плавно переводить одну тень в
     другую лишь при совпадающем числе слоёв, иначе переход был бы рывком.
     Переключает их привязка к прокрутке в style-01-chrome.css (см. @supports у header).
     СВЕТ В УГЛУ (--hdr-sheen) — лёгкое пятно света сверху слева, чтобы заливка
     читалась поверхностью, а не краской. Потолок в 8% белого назван судьёй и
     не случаен: на шапке лежит БЕЛЫЙ текст, а самая светлая из четырёх шапок
     («Lingo», #1a75b0) держит его на 4.98:1 при норме 4.5 — запаса нет вовсе.
     Поэтому пятно посажено в УГОЛ и гаснет раньше, чем доходит до логотипа, а
     СИЛА света у «Lingo» своя (см. её блок ниже): рецепт один на все схемы,
     переопределено только число, и ровно по замеру. Числа меряются пробой
     «планка шапки» по пикселям снимка, а не выводятся из токенов: свет — это
     градиент ПОВЕРХ --grad-header, и в токенах его не видно. */
  --plank-lip:inset 0 -1px 0 rgba(255,255,255,.10);
  --plank-line:0 1px 0 rgba(var(--sh-rgb),.42);
  --plank-cast:0 4px 6px -2px rgba(var(--sh-rgb),.30);
  --plank:var(--plank-lip), var(--plank-line), var(--plank-cast);
  --plank-flat:var(--plank-lip), 0 1px 0 rgba(var(--sh-rgb),0),
               0 4px 6px -2px rgba(var(--sh-rgb),0);
  --hdr-sheen-a:.08;
  --hdr-sheen:radial-gradient(38% 190% at 3% -30%,
              rgba(255,255,255,var(--hdr-sheen-a)) 0%, rgba(255,255,255,0) 68%);

  /* ---- ГРАВИРОВАННАЯ ЛИНЕЙКА (blox52 #4, п.3) ------------------------------
     То же тиснение, что на карточке, но в одну строку: волосок + светлый блик
     ПОД ним. Разделитель секции в настройках, шапка панели и строка списка
     перестают быть просто серой чертой и читаются как оттиск в бумаге.
     Форм две, потому что блик всегда лежит СНИЗУ от линии, а сама линия бывает
     и по верхней грани предмета (--rule-t: блик уходит внутрь), и по нижней
     (--rule-b: блик уходит наружу). Ставить их на предмет, у которого уже есть
     своя тень, нельзя — box-shadow заменяет её целиком; такому предмету линейка
     дописывается в его собственный рецепт. */
  --rule-t:inset 0 1px 0 var(--emb-hi);
  --rule-b:0 1px 0 var(--emb-hi);

  /* ---- МАТЕРИАЛ СТОЛА: ЗЕРНО И СВЕТ КОМНАТЫ (blox52 #4, пп. 4-5) -----------
     Стол был ровной заливкой — на широком экране это большое пустое поле, по
     которому глазу не за что зацепиться, а ровная заливка читается «интерфейс»,
     а не «картон».
     ЗЕРНО (--grain-img) — процедурный шум, нарисованный ПРЯМО ЗДЕСЬ фильтром
     feTurbulence. Никаких картинок и фотографий текстуры: снимок бумаги — это
     уже скевоморфизм, он стареет и весит. Плитка 128×128 рисуется в свой
     натуральный размер (background-size = размеру svg): любое масштабирование
     плитки и есть источник муара на телефоне. Потолок непрозрачности — 4%,
     стоит 3.5%: выше зерно начинает читаться как грязь на экране.
     СВЕТ КОМНАТЫ (--room-o) — лампа над столом: сверху светлее, к нижним углам
     ровный тон. Сделан ПЛЮСОМ К ЦЕНТРУ СВЕТА, а не минусом к краям, и это не
     вкус, а замер. Затемнение к краям (как просил судья) отнимает яркость у
     СТОЛА, а на столе лежит текст --on-bg: в базовой схеме у него 5.12:1, а в
     синих — 4.72:1 при норме 4.5, то есть запаса нет вовсе, и вуаль в 7% уводила
     подпись на столе под норму (4.18:1). Свет, добавленный сверху, работает в ту
     же сторону глазом и в БЕЗОПАСНУЮ сторону по контрасту: тёмный текст на чуть
     более светлом столе читается только лучше. Цвет света — не белый, а
     var(--card): бумага СВОЕЙ схемы, поэтому лампа тёплая на тёплом столе,
     холодная на холодном и виноградная ночью (белый выбелил бы тёплый стол).
     Оба слоя ПРИБИТЫ К ЭКРАНУ (position:fixed у псевдоэлементов ниже), а не к
     странице: иначе на длинной странице градиент растянулся бы вместе с
     содержимым и стал бы частью содержимого, а не освещением комнаты. */
  --grain-o:.035;
  --room-o:20%;
  --grain-img:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='2' intercept='-.5'/%3E%3CfeFuncG type='linear' slope='2' intercept='-.5'/%3E%3CfeFuncB type='linear' slope='2' intercept='-.5'/%3E%3CfeFuncA type='discrete' tableValues='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='128' height='128' filter='url(%23g)'/%3E%3C/svg%3E");

  /* ---- type ---------------------------------------------------------------- */
  /* Onest (self-hosted, see fonts/onest.css). The system stack stays as the fallback
     that renders while the woff2 loads. */
  /* СТЕКИ ЧЕТЫРЁХ ШРИФТОВ — ОДИН ИСТОЧНИК ПРАВДЫ (16.09.2026). Раньше они жили числом в
     public/font.js и подставлялись инлайном — `:root.style['--font']`. Инлайн-стиль бьёт
     ЛЮБОЕ правило CSS, поэтому выбранный шрифт мог появиться только после того, как
     выполнится модуль, то есть ПОСЛЕ первой отрисовки: страница всегда успевала мигнуть
     Onest. Теперь стек каждого шрифта — свой токен, а выбор — признак data-font на :root
     (правила сразу под этим блоком). Признак умеют поставить оба, кто знает выбор ДО
     первого кадра: сервер (штампует в разметку, см. server.js) и /prefs-boot.js.
     font.js хранит теперь только ключи и подписи, а превью в меню настроек ссылается на
     тот же токен — стеки не продублированы больше нигде. */
  --font-sys:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,Roboto,
             "Helvetica Neue",Arial,sans-serif;
  --font-onest:'Onest',var(--font-sys);       /* onest/nunito/rubik — заглушка blox72 #7: из меню убраны */
  --font-nunito:'Nunito',var(--font-sys);
  --font-rubik:'Rubik',var(--font-sys);
  --font-andika:'Andika',var(--font-sys);     /* blox69 #7 — «а» как в прописях */
  --font-inter:'Inter a',var(--font-sys);
  --font:var(--font-inter);   /* умолчание — Inter (26.09.2026); три копии сверяет check.js «умолчание шрифта» */
  /* ЛЕСТНИЦА ТЕКСТА (blox51 #3, заход 4). Ступеней девять, и они не выбираются «на глаз»
     каждый раз: до этого в style.css лежало 225 размеров числом — ВОСЕМНАДЦАТЬ разных
     значений от 10 до 38, включая 12.5 и 13.5. Это не шкала, а россыпь: глаз не находит
     ритма, потому что ритма нет, и экран читается как «аккуратно, но без системы».
     Промежуточные значения СХЛОПНУТЫ, а не узаконены: 13 и 14 рядом различаются на глаз
     не как две ступени, а как ошибка. Направление схлопывания выбиралось по РОЛИ, а не по
     близости числа: подписи, метки и кнопки ушли вниз в --fs-sm, а то, что человек читает
     предложениями (текст ошибки, пустое состояние, предупреждение, тост), — вверх в --fs-md. */
  --fs-2xs:11px; --fs-xs:12px; --fs-sm:13px; --fs-md:15px; --fs-lg:17px;
  --fs-xl:20px;  --fs-2xl:24px; --fs-3xl:30px; --fs-4xl:38px;
  /* ПОЛЕ ВВОДА — 16px это НЕ ступень лестницы, а заслон: Safari на iOS зумит страницу при
     фокусе в поле со шрифтом меньше 16px и обратно не отзумливает. Ниже по файлу тот же
     заслон стоит глобально на @media (pointer:coarse), этот токен держит тот же размер и
     на десктопе, чтобы поле не прыгало между устройствами. Отдельное имя — чтобы никто не
     «причесал» 16 к 15 ради красоты лестницы и не сломал ввод на телефоне молча. */
  --fs-input:16px;
  /* ИКОНКИ-ГЛИФЫ. Часть «размеров шрифта» в проекте — вовсе не текст, а размер эмодзи или
     знака (× закрыть, ⋯ меню, ▶ play, стрелка карусели). Их нельзя ставить на текстовую
     лестницу: подпись и знак живут по разным законам — подпись должна читаться, знак должен
     попадать в свою кнопку. Три ступени, шаг 4px. Векторные иконки (.ic) сюда не относятся:
     они меряются в em и следуют за своей подписью сами. */
  --ic-sm:14px; --ic-md:18px; --ic-lg:22px;
  /* КНИЖНЫЙ ВЕС (blox52 #6, пятая пачка судьи). В наборе не было «читательского» веса вообще:
     сто с лишним правил в 700, шесть десятков в 800 и ровно три в 400 — экран читался как
     афиша, а не как документ, потому что «это читают» и «на это нажимают» были написаны
     ОДНИМ весом. Onest переменный (100…900), лишний вес ничего не стоит по весу страницы.
     450, а не 400: 400 у переменного шрифта — это то, что браузер и так ставит по умолчанию,
     то есть НЕ выбор, а его отсутствие; полступени вверх заметно держат мелкий кегль на
     бумаге и не дают строке «поплыть» в ночной схеме, где светлая буква на тёмном визуально
     тоньше. Кому он достаётся — закрытый реестр в tools/check.js (секция «книжный вес»):
     абзацы согласия, описания плиток кабинета, текст задания, тело объявления, сообщение в
     чате, запись досье. Подписи, кнопки, заголовки и ярлыки остаются жирными — иначе разница
     снова исчезнет, только в другую сторону.
     ЕСТЬ МЕСТО, ГДЕ ЕГО СОЗНАТЕЛЬНО НЕТ: текст, лежащий прямо на СТОЛЕ (у экрана согласия
     своей заливки нет). Там буква тоньше и фон темнее одновременно, поэтому подзаголовок
     .cs-sub оставлен на 600 — замеры в Blox_done52. */
  --fw-read:450;
  --lh-tight:1.2; --lh:1.45;
  --tracking-tight:-.015em;   /* iOS headings are slightly negative-tracked */
  --tracking-caps:.06em;

  /* ---- rhythm --------------------------------------------------------------- */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px;
  --sp-7:32px; --sp-8:44px;

  /* ---- rhythm: крупные шаги (ночной редизайн 27.10.2026) ---------------------
     Две ступени сверх --sp-8 — для ритма МЕЖДУ разделами на широком экране (монитор
     и Домашка на 1280 стоят плотно, а промежутки сверх 44px писались числом). Только
     ДОБАВЛЕНЫ: значения прежних ступеней не тронуты, их потребляет весь продукт. */
  --sp-9:56px; --sp-10:72px;

  /* ---- motion --------------------------------------------------------------- */
  /* ДВИЖЕНИЕ — «ПЛАВНО-СРЕДНЕ» (решение владельца, ночной редизайн 27.10.2026).
     Раньше длительности были россыпью (.14/.22/.34/.08/.18 и числа прямо в правилах),
     а кривая — одна на всё. Теперь две оси, обе названы по СМЫСЛУ, а не по числу:
       ДЛИТЕЛЬНОСТЬ — по тому, ЧТО меняется:
         --dur-press-in   80ms  вдавливание (сухое и быстрое, без перелёта)
         --dur-press     120ms  отклик на нажатие целиком: вдавился-отпустил, волна
         --dur-release   180ms  возврат в покой с пружиной (--ease-spring)
         --dur-state     200ms  мелкая смена состояния на месте: цвет, рамка, галочка,
                                выбранный чип, наведение
         --dur-panel     280ms  панель, шторка, модалка, смена содержимого (день, вкладка)
         --dur-panel-out 220ms  то же на УХОДЕ: исчезающее не задерживает взгляд, уход
                                всегда короче появления
         --dur-max       400ms  ПОТОЛОК. Длиннее не бывает ничего, что отвечает на касание;
                                этот токен — для одного «праздничного» момента на экране.
       КРИВАЯ — по НАПРАВЛЕНИЮ:
         --ease-standard  на месте (меняется вид, предмет никуда не уезжает)
         --ease-enter     появление/приезд: быстро стартует и мягко садится
         --ease-exit      уход: разгоняется и не тормозит у края — уходящее не «висит»
         --ease-spring    только отпускание (возврат в покой), см. ниже
     Прежние имена (--t-fast/--t/--t-slow/--t-press/--t-spring/--ease) СОХРАНЕНЫ как
     псевдонимы: ими пишут ~170 правил, в том числе экраны, которые сегодня никто не
     перерисовывает. Сдвиг их значений — .14→.12, .22→.20, .34→.28 — на глаз не виден,
     раскладку не трогает (длительность не геометрия), но сводит всё к одной лестнице.
     Новым правилам — только новые имена. */
  --dur-press-in:80ms; --dur-press:120ms; --dur-release:180ms;
  --dur-state:200ms;   --dur-panel:280ms; --dur-panel-out:220ms; --dur-max:400ms;
  --ease-standard:cubic-bezier(.2,0,0,1);
  --ease-enter:cubic-bezier(.32,.72,0,1);   /* = прежний --ease: быстрый старт, мягкая посадка */
  --ease-exit:cubic-bezier(.3,0,.8,.15);
  /* ПРУЖИНА — кривая с ПЕРЕЛЁТОМ: элемент проскакивает конечную точку и мягко
     возвращается. Это и есть «сочность» отпускания: палец ушёл — поверхность
     отпрыгнула. Число взято из каталога silk-design («playful overshoot»),
     не подобрано на глаз. Применять ТОЛЬКО к отпусканию (возврату в покой):
     на само нажатие перелёт не ставят — вдавливание должно быть сухим и быстрым. */
  --ease-spring:cubic-bezier(.22,.68,0,1.2);
  /* псевдонимы — старые имена, новые значения */
  --ease:var(--ease-enter);
  --t-fast:var(--dur-press); --t:var(--dur-state); --t-slow:var(--dur-panel);
  --t-press:var(--dur-press-in);   /* вдавливание — заметно быстрее возврата */
  --t-spring:var(--dur-release);   /* возврат с перелётом */
  /* ВЕЛИЧИНА ДВИЖЕНИЯ — тоже токен, и вот зачем: при просьбе «уменьшить движение»
     (ниже, @media prefers-reduced-motion) эти шесть чисел становятся тождеством —
     масштаб 1, сдвиг 0. Правило, написанное через них, само превращается в простую
     смену цвета/прозрачности, без отдельного блока у каждого компонента.
     Вдавливание по РАЗМЕРУ предмета (как и радиус): мелкий контрол проседает сильнее,
     крупная карточка — едва, иначе большая плитка «проваливается» на полэкрана. */
  --press-scale-sm:.94;   /* иконка-кнопка, галочка, чип                       */
  --press-scale:.97;      /* кнопка                                            */
  --press-scale-lg:.98;   /* карточка, плитка, плашка таска                    */
  --lift:-1px;            /* приподнять на наведении (translateY)              */
  --enter-shift:8px;      /* въезд содержимого: строка, карточка, смена дня    */
  --enter-shift-lg:24px;  /* въезд панели/шторки, если не на всю свою высоту   */

  /* ---- signature gradients --------------------------------------------------- */
  /* the playlist's identity: the full palette, left to right */
  --grad-playlist:linear-gradient(100deg,var(--sky-400) 0%,#a8b0ef 34%,var(--veil-300) 55%,var(--gf-400) 100%);
  --grad-playlist-v:linear-gradient(180deg,var(--sky-400),#a8b0ef,var(--veil-300),var(--gf-400));
  --grad-header:linear-gradient(135deg,var(--grape-600) 0%,var(--grape-800) 62%,var(--grape-900) 100%);
  /* Цвет системной полосы вокруг окна установленного приложения (meta theme-color; ставит
     public/theme-color.js). Средняя точка градиента шапки: она занимает бОльшую часть её
     площади, поэтому полоса сливается с шапкой, а не подчёркивает её кантом. Свой --chrome
     обязан быть у КАЖДОЙ схемы — иначе при переключении полоса останется от прежней. */
  --chrome:#352541;
  --grad-primary:linear-gradient(180deg,var(--grape-600),var(--grape-700));
  /* button engine — «juicy» filled surfaces: a hair lighter at the top so the fill
     reads as a rounded, lit surface, settling to the role's solid at the bottom.
     DERIVED from the role token via color-mix, so they follow EVERY scheme on their
     own (no scheme-block copy — the §11 trap): --ok-solid is a fixed state colour
     (accept stays green everywhere). Kept subtle —
     text sits mid-height where the colour ≈ solid, so AA contrast holds. */
  --grad-accept:linear-gradient(180deg,color-mix(in srgb,var(--ok-solid) 88%,#fff),var(--ok-solid));
  /* ФАСКА ЗАЛИТОЙ КНОПКИ (blox52 #3, п.4). Был только светлый блик по ВЕРХНЕЙ кромке, а низ
     кнопки просто обрывался — предмет читался как прямоугольник с бликом, а не как объём.
     У настоящей кнопки, вдавленной в бумагу, низ ТЕМНЕЕ: свет падает сверху. Вторая строка
     и есть эта тёмная кромка — те же 1px, только снизу и чёрным.
     Почему чёрный, а не «свой тёмный» у каждой роли: кромка в 1px не читается как ЦВЕТ, она
     читается как тень. Проверено на всех заливках — баклажан, графит, Maya, ночной виноград,
     зелёная «Принять», ночная. Ни зелёную, ни красную не грязнит: .22 чёрного на 1px — это
     тот же край, что и снизу у любого напечатанного предмета. */
  --bevel:inset 0 1px 0 rgba(255,255,255,.18), inset 0 -1px 0 rgba(0,0,0,.22);
  /* the Lingo wordmark — the brand rainbow, deliberately FIXED across schemes */
  --grad-wordmark:linear-gradient(100deg,var(--sky-600),var(--veil-600) 55%,var(--gf-500));
}

/* ===========================================================================
   ПЕРЕРИСОВКА B «КЛАСС НА ЛАДОНИ» (redraw-b, 28.10.2026) — ФУНДАМЕНТ.
   Владелец выбрал вариант B: светлый холодный стол, белые карточки без тени, сверху
   экрана — сплошная полоса цвета ГРУППЫ. Блок ниже — второй голый :root: он стоит
   ПОСЛЕ базового и потому перекрывает его значения, а схемы (scheme2/scheme3/dark)
   по-прежнему перекрывают оба — у них специфичность выше. Итог:
     • БАЗОВАЯ схема теряет тёплую бумагу и говорит холодной нейтралью B (ниже);
     • «Графитовая», «Lingo» и ночь держат свои столы, бумагу и чернила, как прежде;
     • полоса — ВСЕГДА цвет группы (в ночи — его тёмный вариант), схема её не красит.
   Бумажная лестница --paper-* остаётся (на неё ссылаются тени, шапка и проба
   «материал бумаги» — зерно и свет комнаты тоже не тронуты), но роли нейтрали у
   базовой схемы она отдаёт сланцевой лестнице --slate-*. Замеры контраста — на белой
   карточке #fff / на столе #f1f3f5. Источник значений — эскизы MonB/ReviewB/HwB.
   =========================================================================== */
:root{
  /* ---- сланцевая нейтраль B (лестница; компоненты берут РОЛИ, не ступени) ------- */
  --slate-50:#f6f7f9;  --slate-100:#f1f3f5; /* стол */  --slate-125:#eef1f3; /* колодец */
  --slate-150:#e9ecef; /* Nope, заливка */
  --slate-200:#e2e6ea; /* вторичная кнопка */           --slate-300:#d3d9de; /* волосок */
  --slate-400:#c3cad1; --slate-450:#b7bfc7; --slate-500:#aab3bb;
  --slate-600:#8b95a0; /* 3.04 — рельс */  --slate-700:#5c6670; /* 5.85 / 5.26 */  --slate-800:#4c5660; /* 7.48 / 6.72 */
  --slate-850:#353d45; --slate-900:#1d2329; /* 15.9 / 14.3 */  --slate-950:#12171c;

  /* ---- нейтраль базовой схемы → B (перекрывает значения бумаги выше) ------------ */
  --ink:var(--slate-900);
  --ink-strong:var(--slate-950);
  --muted:var(--slate-800);       /* вторичный текст: 7.48 на карточке, 6.72 на столе */
  --faint:var(--slate-700);       /* подсказки: 5.85 / 5.26 — AA и на столе тоже      */
  --muted-strong:var(--slate-850);
  --on-bg:var(--slate-800);       /* стол светлый — подпись на нём = вторичный текст  */
  --bg:var(--slate-100);          /* СТОЛ B — светлый холодный, #f1f3f5               */
  --card:#ffffff;                 /* карточка B — белая                               */
  /* КОЛОДЕЦ В КАРТОЧКЕ ТЕМНЕЕ СТОЛА — так в эскизе ReviewB (#eef1f3 в белой карточке на
     #f1f3f5). Стопка «карточка > колодец > стол» из blox51 #4 (проба «поднос конструктора»)
     при светлом столе B невозможна: весь зазор белый↔стол 1.12, а двум ступеням нужно
     1.06² = 1.124. Это осознанная смена правила для базовой схемы — решает агент экрана
     конструктора (см. docs/redraw/log.md, агент 1). */
  --surface:var(--slate-125);
  --surface-2:var(--slate-50);
  --fill-soft:var(--slate-150);   /* подложка: Nope, дорожка вкладок                  */
  --line:var(--slate-400);
  --line-soft:var(--slate-300);   /* волосок: 1.42 на белом, 1.28 на столе — виден на обоих */
  --line-mid:var(--slate-450);
  --line-strong:var(--slate-500);
  --accent:var(--slate-900);      /* акцент базовой — по-прежнему «чёрный» её чернил  */
  --accent-ink:var(--slate-950);
  --accent-deep:var(--slate-900);
  --accent-tint:color-mix(in srgb, var(--slate-900) 9%, var(--card));
  --accent-fill:color-mix(in srgb, var(--slate-900) 16%, var(--card));
  --accent-line:var(--slate-500);
  --primary:var(--slate-900);     /* заливка под белым: 15.9:1                       */
  --primary-strong:var(--slate-950);
  /* ЯКОРЬ БАЗОВОЙ СХЕМЫ = её собственный акцент, сланец-900 (агент 6, решение оркестратора по
     ADR «первичное действие носит акцент своей схемы; зелёный — только сделано»). До этого здесь
     оставался баклажан прежней бумаги: «Установить ДЗ», «Сохранить», рамка черновика, громкие
     «Открыть …» были единственным виноградным пятном на сланцевом мире. Белый на нём 15.9:1, сам
     якорь на белом/столе 15.9/14.4. Синие схемы и ночь держат свои якоря. «Ждёт учителя» на
     полосе уже носит --group. Плоский переход 850→900 — фаски у B нет (агент 2). */
  --anchor:var(--slate-900);
  --grad-primary:linear-gradient(180deg,var(--slate-850),var(--slate-900));
  --task-plain:var(--slate-600);  /* нейтральный рельс таска: 3.04 на белом, как у бумаги */
  --sh-rgb:29,35,41;              /* тень в тон сланца, а не тёплая                   */
  --emb-lo:rgba(8,16,24,.28);

  /* ---- вторичная кнопка B: серая заливка без рамки ------------------------------ */
  --btn-2-bg:var(--slate-200);    /* --ink на ней 12.6:1, --muted 5.96:1              */
  --btn-2-bg-hover:var(--slate-300);
  --btn-2-ink:var(--ink);
  /* выбранный сегмент переключателя (Notes | Tasks) — белая плашка на серой дорожке --btn-2-bg */
  --seg-on:var(--card);
  /* ПОДНОС КОНСТРУКТОРА ДЗ (агент 3, blox51 #4 в языке B): панель черновика и открытого
     конструктора. На светлом столе B «средний уровень» между белой карточкой и столом невозможен
     (весь зазор 1.12), поэтому поднос — ВМЯТИНА НИЖЕ стола: slate-150, к столу 1.07, к белой
     плашке на нём 1.19. Синие схемы и ночь оставляют прежний средний уровень --surface. */
  --tray:var(--slate-150);

  /* ---- радиусы B по ролям (ступени --r-* выше не меняются, роли ссылаются на них) - */
  --r-tile:var(--r-md);           /* 14 — плитка ребёнка, клетка сетки                */
  --r-card:16px;                  /* 16 — карточка таска, сдачи (эскиз: 14–18)        */
  --r-sheet:var(--r-lg);          /* 18 — крупная карточка, шторка                    */
  --r-btn:12px;                   /* 12 — кнопка, клетка дня на полосе                */
  --r-chip:var(--r-pill);         /* таблетка — чипы групп (36px высоты → 18)         */
  --r-badge:6px;                  /* бейдж Check N / Nope / ✓                          */
  --r-badge-sm:var(--r-2xs);      /* 4 — «Check» на клетке дня (прямоугольник blox86 #5) */

  /* ---- шрифтовые роли B ---------------------------------------------------------- */
  /* Витрина — Unbounded: заголовок экрана, дата урока, название таска, числа дней на
     полосе, крупные счётчики, инициалы в кружках. Тело — то, что выбрал человек (меню
     шрифтов, data-font = inter / andika), т. е. --font. Решение владельца 28.10: в меню
     остаются оба, своего тела у эскиза B нет. */
  --font-display:'Unbounded',var(--font-sys);
  --font-body:var(--font);
  --fw-display:700;
  --fw-display-soft:500;          /* число дня без урока на полосе                    */
  --fs-title:34px;                /* «Homework», крупный заголовок экрана             */
  --fs-counter:34px;              /* «5 из 8 сдали» — большое число                  */
  --fs-heading:var(--fs-xl);      /* 20 — дата урока, название таска (эскиз 19 → 20) */
  /* 19, не 18 эскиза (агент 7): с 18.66px полужирное — КРУПНЫЙ текст по WCAG (порог 3:1), и только так
     розовое число выходного дня с уроком читается на заливке клетки (худшее 3.23 на #a3501a) */
  --fs-daynum:19px;               /* число дня на полосе (клетка 72px)                */
  --fs-check:10px;               /* «Check» на клетке дня (эскиз 10px): поле вокруг слова */
  --fs-initials:13px;             /* инициалы в кружке 34–36px                        */
  --fs-initials-lg:14px;          /* инициалы в кружке 40px (карточка сдачи)          */
  --lh-display:1.1;
  /* 14 — кегль B для кнопок, чипов групп и сегментов (эскизы: 600 14px). Между
     --fs-sm 13 и --fs-md 15 ступени не было, а эскиз берёт 14 у каждого органа управления. */
  --fs-ctl:14px;

  /* ---- ПАЛИТРА ГРУПП: восемь цветов, номер = id группы mod 8 (public/group-color.js).
     Каждый цвет — сплошная полоса под БЕЛЫМ текстом (≥ 4.5:1) и цвет текста на своём
     тинте (тинт = color-mix 14% цвета в белое, пара ≥ 4.5:1). Цвета различимы и
     светлотой, не только тоном: белый на них от 5.65 до 10.1, и СОСЕДНИЕ номера (группы,
     заведённые подряд) расходятся по нему не меньше чем на 0.6 — порядок подобран под это. Ночные пары: -dk —
     полоса (72% цвета в чёрное), -nt — тинт (30% цвета в ночную карточку #272233),
     -nk — текст на ночном тинте (38% цвета в белое). Все пары считает и сверяет
     tools/unit/group-color.test.mjs — правишь число здесь, тест пересчитает.
     Белый на цвете · цвет на тинте · белый на -dk · -nk на -nt: */
  --grp-0:#33566f; --grp-0-tint:#e2e7eb; --grp-0-dk:#253e50; --grp-0-nt:#2b3245; --grp-0-nk:#b1bfc8; /* сланец   7.77·6.24·11.2·6.8 */
  --grp-1:#1d6f63; --grp-1-tint:#dfebe9; --grp-1-dk:#155047; --grp-1-nt:#243941; --grp-1-nk:#a9c8c4; /* бирюза   5.99·4.90· 9.3·6.8 */
  --grp-2:#6a3d7c; --grp-2-tint:#eae4ed; --grp-2-dk:#4c2c59; --grp-2-nt:#3b2a49; --grp-2-nk:#c6b5cd; /* слива    8.17·6.54·11.6·6.8 */
  --grp-3:#a3501a; --grp-3-tint:#f2e6df; --grp-3-dk:#753a13; --grp-3-nt:#4c302b; --grp-3-nk:#dcbda8; /* ржавчина 5.65·4.61· 8.9·6.7 */
  --grp-4:#253f7a; --grp-4-tint:#e0e4ec; --grp-4-dk:#1b2d58; --grp-4-nt:#262b48; --grp-4-nk:#acb6cc; /* индиго  10.14·7.96·13.4    */
  --grp-5:#7a5c12; --grp-5-tint:#ece8de; --grp-5-dk:#58420d; --grp-5-nt:#403329; --grp-5-nk:#ccc1a5; /* охра     6.24·5.10· 9.6    */
  --grp-6:#35601a; --grp-6-tint:#e3e9df; --grp-6-dk:#264513; --grp-6-nt:#2b352b; --grp-6-nk:#b2c3a8; /* хвоя     7.40·5.98·10.8    */
  --grp-7:#a3324f; --grp-7-tint:#f2e2e6; --grp-7-dk:#752439; --grp-7-nt:#4c273b; --grp-7-nk:#dcb1bc; /* малина   6.72·5.37·10.2    */
  /* РОЛИ НОМЕРА — то, что ставит group-color.js: --group указывает на --grp-N-band и т. д.
     Днём роль = дневные значения, ночь перекрывает их ночными (блок dark ниже), поэтому
     скрипт про схему не знает ничего. */
  --grp-0-band:var(--grp-0); --grp-0-soft:var(--grp-0-tint); --grp-0-ink:var(--grp-0);
  --grp-1-band:var(--grp-1); --grp-1-soft:var(--grp-1-tint); --grp-1-ink:var(--grp-1);
  --grp-2-band:var(--grp-2); --grp-2-soft:var(--grp-2-tint); --grp-2-ink:var(--grp-2);
  --grp-3-band:var(--grp-3); --grp-3-soft:var(--grp-3-tint); --grp-3-ink:var(--grp-3);
  --grp-4-band:var(--grp-4); --grp-4-soft:var(--grp-4-tint); --grp-4-ink:var(--grp-4);
  --grp-5-band:var(--grp-5); --grp-5-soft:var(--grp-5-tint); --grp-5-ink:var(--grp-5);
  --grp-6-band:var(--grp-6); --grp-6-soft:var(--grp-6-tint); --grp-6-ink:var(--grp-6);
  --grp-7-band:var(--grp-7); --grp-7-soft:var(--grp-7-tint); --grp-7-ink:var(--grp-7);
  /* ЦВЕТ ТЕКУЩЕЙ ГРУППЫ — то, что читают компоненты. Умолчание (экран без группы) —
     номер 0; корень экрана перекрывает его через applyGroupColor(el, groupId). */
  --group:var(--grp-0-band);      /* полоса; цвет группы как заливка под белым        */
  --group-tint:var(--grp-0-soft); /* подложка инициалов                               */
  --group-ink:var(--grp-0-ink);   /* цвет группы ТЕКСТОМ на тинте и на карточке       */
  --on-group:#fff;                /* текст на полосе                                  */
  /* НА ПОЛОСЕ — БЕЛОЕ ПОЛУПРОЗРАЧНОЕ (агент 2, общие части). Полоса бывает восьми цветов и
     ночной, поэтому всё, что лежит на ней, берёт не цвет, а долю белого: контур невыбранного
     чипа (эскиз MonB: 1.5px при .45; у нас 1px — лестница линий — и .5), заливка клетки дня с уроком (.14),
     наведение (.22). Текст на полосе — только сплошной --on-group: доля белого на самом
     светлом цвете (#a3501a, белый 5.65) опустила бы его под 4.5. */
  --on-group-line:rgba(255,255,255,.5);
  /* .10, не .14 эскиза (агент 6, замер всех восьми): белый текст НА этой заливке — числа дней с
     уроком, «⧗ 4 на проверку», подсказка экрана задания — при .14 давал 4.44 на #1d6f63 и 4.28 на
     #a3501a; при .10 худший 4.63 (#a3501a), ночью ≥ 6.8. */
  --on-group-fill:rgba(255,255,255,.10);
  --on-group-hover:rgba(255,255,255,.22);
  /* Сб/Вс на полосе (эскиз #ffc4cd давал 3.8 на #a3501a — под AA); этот светлее: ≥4.5 на всех восьми */
  --on-group-weekend:#ffe0e6;
  /* ВЫХОДНОЙ С УРОКОМ (агент 7, владелец 28.10: «выходные не отмечены цветом»). На заливке клетки ни один
     розовый не дотягивает до 4.5, поэтому розовым — только ЧИСЛО (19px 700 = крупный текст, порог 3:
     худшее 3.23 на #a3501a, ночью ≥4.76), подписи «Сб» и месяц — белые. Насыщеннее --on-group-weekend:
     бледный #ffe0e6 на цветной полосе читался почти белым. */
  --on-group-weekend-big:#ffcad3;
  /* ВЫБРАННЫЙ выходной — белая плитка, на ней красный грейпфрут (4.89 на белом — и подписи, и число).
     Плитка белая и ночью, поэтому значение одно на все схемы. */
  --on-group-weekend-ink:var(--gf-600);
  /* ПЛИТКА ПЛЕЙЛИСТА НА ДОМАШКЕ (агент 5, эскиз HwB): тёмная плитка с янтарной кнопкой «играть».
     Обе — ФИРМЕННЫЕ, вне блока схем (как --gold): плитка тёмная в любой схеме, белый текст на ней
     15.9:1; значок --tile-dark на янтаре 7.6:1 (нетекстовый знак, порог 3). Ночью плитка своя
     (блок ночи): белый 13.0:1, значок на янтаре 6.2:1. */
  --tile-dark:#1d2329;
  --amber:#f2a33a;
  /* ШАПКА ВНЕ ТРЁХ ЭКРАНОВ ПОЛОСЫ — сланец B, а не виноград бумажной базы: там, где текущей
     группы нет (оплаты, документы, кабинет, чаты), шапка нейтральна. Ровная, без градиента —
     B плоский. Синие схемы и ночь держат свои шапки (их блоки ниже). */
  --grad-header:linear-gradient(var(--slate-900),var(--slate-900));
  --chrome:#1d2329;
}

/* ВЫБОР ШРИФТА (blox10 #9, переписан 16.09.2026). Один признак на :root вместо инлайн-стиля —
   ровно та же механика, что у цветовых схем ниже, и по той же причине: признак можно поставить
   до первого кадра, инлайн из отложенного модуля — нельзя. Ключи (onest/nunito/rubik/system)
   лежат в localStorage и в users.ui_prefs, менять их нельзя; список — public/font.js и
   helpers/prefs.js. Умолчание (Inter) прописано и голым :root выше: без признака страница остаётся на нём. */
/* blox72 #7 — правила onest/nunito/rubik/system сняты (заглушка, см. public/font.js): старый ключ
   в памяти устройства теперь не совпадает ни с чем, и prefs-boot.js оставляет страницу на Inter. */
:root[data-font="andika"]{ --font:var(--font-andika); }
:root[data-font="inter"]{  --font:var(--font-inter); }

/* ===========================================================================
   СИНИЕ СХЕМЫ LINGO (blox26 #4 + доп. запрос владельца) — «синяя база» с реального
   сайта школы lingo-school.com. Пять цветов палитры:  Jet Black #262e35 · Pale Sky
   #d0effe · Maya Blue #7bbeea · Alice Blue #f3f9fb · White.
   Их ДВЕ, и они делят одну палитру — различаются ТОЛЬКО «якорем» (во что окрашена
   шапка + первичные кнопки):
     • «Графитовая» (ключ scheme2) — тёмная ГРАФИТОВАЯ шапка, белый текст;
     • «Lingo» (ключ scheme3) — сам Maya Blue выходит В ШАПКУ, текст на ней белый.
   Имена в меню — из SCHEMES (public/settings.js); ключи scheme2/scheme3 менять НЕЛЬЗЯ,
   они лежат в localStorage и в users.ui_prefs у уже выбравших схему.
   Общая база (текст / фон / акцент / линии) — в сгруппированном правиле ниже; отличие
   каждой схемы — в её собственном коротком блоке.
   Зелёный «сделано» (--ok*), красный «внимание» (--alert* и --danger) и золото челленджа
   (--gold*) СОЗНАТЕЛЬНО НЕ трогаем — наследуются из :root, чтобы «сделано»/«тревога»/«приз»
   читались одинаково во всех схемах (на Alice-Blue фоне контраст тот же, что на белой карточке).
   Значения, которых в 5 цветах нет, ВЫВЕДЕНЫ из базы (затемнение/осветление) — помечены ниже.
   =========================================================================== */
:root[data-scheme="scheme2"],
:root[data-scheme="scheme3"]{
  --tray:var(--surface);      /* поднос конструктора — средний уровень, как до B (blox51 #4) */
  /* текст: Jet Black как чернила; strong/muted/faint выведены затемнением/осветлением */
  --ink:#262e35;              /* Jet Black — заголовки и текст (12.96:1 на фоне)        */
  --ink-strong:#171c22;       /* выведен: тёмный Jet Black — одна громкая строка          */
  --muted:#566270;            /* выведен: сине-серый, 5.85:1 — вторичный текст            */
  --faint:#7c8894;            /* выведен: светлее — подсказки, таймстемпы, disabled       */

  /* фон и подложки: Alice Blue как основной фон; inset-панели выведены из него */
  /* СТОЛ синих схем (blox51 #3). Alice Blue #f3f9fb был фоном, но отличался от
     белой карточки на 1.17 — глазу этого мало, и после снятия заливки с .opane
     плашка (#e3f1fb) оказалась ТЕМНЕЕ фона, то есть читалась как вмятина.
     Выведен более глубокий стоп той же холодной базы: 1.32 к белому — ровно та
     же разница, что бумага/стол в базовой схеме. Alice Blue остался в --surface:
     он теперь не фон, а углубление В бумаге, где ему и место. */
  --bg:#d6e2ea;               /* выведен: СТОЛ — на нём лежит всё, 1.32 к бумаге          */
  --surface:#eaf3f8;          /* выведен: чуть темнее бумаги — вложенные панели           */
  --surface-2:#f3f9fb;        /* Alice Blue — мягкий inset внутри бумаги                  */
  --line:#cbe0ee;             /* выведен: сине-серая граница по умолчанию                  */
  --line-soft:#e0edf5;        /* выведен: волосяная линия / разделитель                    */
  --line-strong:#9ab4c6;      /* выведен: заметная граница                                 */

  /* акцент: Maya Blue как заливка/выделение; deep/ink/line выведены из него */
  --accent:#7bbeea;           /* Maya Blue — заливки, выделение (с --ink 6.82:1)          */
  --accent-ink:#10608f;       /* выведен: тёмная Maya — акцент ТЕКСТОМ: на белом 6.8:1, на
                                 --accent-fill 5.05:1 (ник в своём пузыре чата; axe: было 4.47) */
  --accent-deep:#2f8fd0;      /* выведен: средняя Maya — hover/ссылки                      */
  --accent-tint:#d0effe;      /* Pale Sky — акцентный фон                                  */
  --accent-line:#a9dbf6;      /* выведен: светлая Maya — акцентная граница                 */

  /* новые ролевые ярлыки (blox26) — выведены из той же базы (нейтраль Jet Black + акцент Maya).
     Состояния (--ok* и --alert*) НЕ трогаем: наследуются из :root, чтобы «сделано»/«тревога»
     читались одинаково во всех схемах.
     ОСТОРОЖНО: «звёздочка/слэш» в тексте комментария (как в старой записи «ок-звёздочка/
     алерт») ЗАКРЫВАЕТ комментарий досрочно, и парсер съедает всё до ближайшей «;» — так эта
     самая запись молча глотала --muted-strong с момента своего появления (найдено blox52 #13;
     теперь это стережёт проверка «комментарии CSS» в tools/check.js). */
  /* ОБЪЯВЛЕНИЕ — В СЕМЬЕ АКЦЕНТА (blox52 #13). Лавандовая заметка из :root была на детском
     экране синих схем ЧЕТВЁРТЫМ цветовым семейством (Maya + нейтраль + зелёный + вуаль) —
     оба судьи второго прогона сошлись, что здесь плашка должна жить в акценте схемы. Рецепт
     фона — тот же, что у :root (бумага + 12% пигмента), пигмент — Maya; линия — --frame-line
     (рамка темы своей схемы: в Графитовой графит, в «Lingo» светлый край шапки), заголовок
     «ОБЪЯВЛЕНИЕ» — якорь схемы. Замер 06.09.2026: --ink на фоне 12.7, заголовок-якорь
     12.7 (scheme2) / 5.6 (scheme3). Базовую лаванду и ночь НЕ трогаем: в базовой схеме
     судьи разошлись — оставлено как есть (дешевле), помечено в отчёте blox52 #13. */
  --note-bg:color-mix(in srgb, var(--accent) 12%, var(--card));
  --note-line:var(--frame-line);
  --note-ink:var(--anchor);
  --muted-strong:#3b4653;     /* выведен: между --ink и --muted                            */
  --fill-soft:#e0edf5;        /* = --line-soft: та же светлая подложка, роль «заливка»      */
  --line-mid:#b6cfe0;         /* выведен: между --line и --line-strong                     */
  --primary:#262e35;          /* якорь-заливка = Jet Black (как --ink), белый текст 12.96:1 */
  --primary-strong:#171c22;   /* тёмная заливка чрома (тосты/ридаут)                        */
  /* B (агент 2): вторичная кнопка синих схем — НЕ сланец базы. Сланцевый #e2e6ea на столе
     #d6e2ea даёт 1.06 — серая кнопка на столе пропала бы (§12: контрол обязан выглядеть
     контролом в покое). Холодный серо-голубой темнее стола: к столу 1.17, к белой карточке
     1.5, --ink на нём 9.4:1. */
  --btn-2-bg:#c5d5e1;
  --btn-2-bg-hover:#b8cad7;
  --anchor:#12689e;           /* ЯКОРЬ: глубокий Maya под белый текст = первичная кнопка
                                 (проба blox51 #3); --accent-ink темнее ради контраста на fill */
  --accent-fill:#bce4fb;      /* выведен: светлая Maya-заливка, темнее --accent-tint        */
  /* рельсы тасков по типу: нейтральный = нейтраль схемы; «нужна сдача» = Maya. Без этого
     grape-500/sky-500 из :root не следовали бы за синей схемой (остаточная утечка). */
  /* ИЕРАРХИЯ БЫЛА ПЕРЕВЁРНУТА (blox55 #8). Нейтральный рельс стоял на #566270 — тёмном сине-сером,
     а бумага плашки в этой схеме БЕЛАЯ, и он давал к ней 6.22:1 против 3.52:1 у рельса «нужна
     сдача». То есть таск «просто сделать» кричал вдвое громче того, по которому ждут работу
     ребёнка, — ровно наоборот смыслу, который рельс несёт. Дефект жил тут с рождения схемы и не
     всплывал, потому что проба «рельс плашки» меряет ТЕКУЩУЮ схему, а текущей была базовая; он
     вышел на свет в тот день, когда Lingo стала схемой по умолчанию.
     Взят тот же тон и та же насыщенность, только светлее (HSL 209°/13%, светлота 39%→66%): 2.40:1,
     разрыв со сдачей 1.47× — как в «Графитовой» (1.45×), с которой эта схема делит палитру.
     Стережёт всё та же проба «blox51 #3 · рельс плашки · иерархия: сдача громче». */
  --task-plain:#9da9b4; --task-sub:#2f8fd0;
  /* ссылка в окне проводника — акцентные чернила СВОЕЙ схемы (они уже синие), а не
     sky-700 базовой: иначе холодная схема несла бы чужой оттенок синего (blox51 #10) */
  --exp-link:var(--accent-ink);

  /* ЗАГЛУШКИ ПРОТИВ УТЕЧКИ ТЁПЛОЙ БУМАГИ (blox51 #2). Эти четыре токена раньше
     не переопределялись здесь и брались из :root. После перевода базовой схемы на
     бумагу они принесли бы бежевый в синие схемы — карточки, плашки, подписи и
     тени стали бы тёплыми на холодном фоне. Значения — прежнее поведение схем,
     байт в байт: карточка белая, плашка = --surface-2 (как и раньше через :root),
     подпись на светлом фоне = --muted, тень в тон Jet Black. */
  --card:#ffffff;              /* БУМАГА синих схем — белая, а не бежевая            */
  --task-plaque:var(--card);   /* плашка таска — тоже бумага (правило слоёв общее)   */
  --on-bg:var(--muted);        /* текст на столе: --faint на #d6e2ea дал бы 2.4:1     */
  --sh-rgb:38,46,53;           /* тень в тон Jet Black, а не тёплая                   */
  --emb-lo:rgba(8,16,24,.28);  /* дно канавки — холодное; тёплое читалось бы пятном */

  /* ФОКУС-КОЛЬЦО и ВЫДЕЛЕНИЕ — по общему рецепту (см. :root), но своим цветом.
     Контур кольца — акцентные ЧЕРНИЛА (глубокая Maya): 6.0:1 на белой карточке и
     4.55 на столе против 1.35 и 1.21 у прежнего полупрозрачного Maya.
     Выделение — сам Maya: рецепт «акцент 26% в бумагу» тут не годится, бумага белая
     и светлый Maya в ней растворяется (1.2:1). Чистый Maya даёт 2.02:1 к белому,
     а --ink на нём 6.82:1 — те самые цифры, под которые он и заведён. */
  --ring-c:var(--accent-ink);
  --sel-bg:var(--accent);
}

/* ── «Графитовая» (scheme2): тёмный ГРАФИТОВЫЙ якорь ─────────────────────────────────
   Шапка и первичные кнопки — тёмный Jet Black вместо винограда (иначе на синей базе
   верхняя панель осталась бы фиолетовой). Оттенки выведены из #262e35. */
:root[data-scheme="scheme2"]{
  --grad-header:linear-gradient(135deg,#323c46 0%,#1e252c 62%,#141920 100%);
  --chrome:#1e252c;   /* системная полоса — под стать графитовой шапке */
  --grad-primary:linear-gradient(180deg,#323c46,#262e35);
  --anchor:#262e35;          /* ЯКОРЬ схемы — тот же графит, что в шапке (белый 12.96:1) */
  --frame-line:var(--ink);   /* тёмный графитовый контур рамки темы — как якорь схемы */
  /* blox28 #3: рельс обычного таска (без сдачи) — ЧИСТО нейтральный светло-серый,
     а не сине-серый #566270 из общего блока (тот остаётся для scheme3 «голубоватой»). */
  --task-plain:#a6a6a4;
  /* blox28 #3 (уточнение): само ТЕЛО плашки таска на мониторе (.oent) — светло-серое
     в тон рельсу, а не голубоватый --surface-2 (#e3f1fb). В scheme3 тело остаётся голубым. */
  /* blox51 #3: тело плашки остаётся НЕЙТРАЛЬНЫМ (не голубым) — как решил владелец
     в blox28 #3, — но теперь это бумага, а не полупрозрачная подложка: под ней
     больше нет белой панели, сквозь которую она просвечивала. */
  --task-plaque:#fbfbfa;
}

/* ── «Lingo» (scheme3): сам Maya Blue выходит в ШАПКУ (БЕЛЫЙ текст) ───────────────
   Владелец хотел видеть бренд-цвет Maya Blue именно наверху, а не только в акцентах,
   и чтобы текст на шапке остался БЕЛЫМ. Ограничение: белый на светлом Maya Blue
   #7bbeea нечитаем (1.9:1). Поэтому «якорь» шапки — ГЛУБОКИЙ Maya Blue (из того же
   семейства, не графит как в «Графитовой»), затемнённый ровно настолько, чтобы белый текст
   прошёл AA: самый светлый стоп #1a75b0 даёт с белым 5.0:1, центр #12689e — 6.0:1.
   Белый текст, полупрозрачно-белые подложки и Maya-точка логотипа работают как в
   базовой тёмной шапке — поэтому НИКАКИХ переопределений chrome тут не нужно. */
:root[data-scheme="scheme3"]{
  --grad-header:linear-gradient(135deg,#1a75b0 0%,#12689e 58%,#0d5077 100%);  /* глубокий Maya Blue, белый текст ≥5:1 */
  --chrome:#12689e;   /* системная полоса — под стать шапке */
  /* ВЕРХНИЙ СТОП ЗАТЕМНЁН (blox52 #10): было #2f8fd0 — белый текст на нём 3.52:1, и даже в
     верхней точке самой СТРОКИ ТЕКСТА (t≈.31 от высоты кнопки) выходило 4.12:1 при норме 4.5.
     Пока градиент носила одна «Отправить учителю», этого никто не мерил; теперь он на каждой
     кнопке-решении. #1c78b5 даёт белому 4.77:1 уже на самом верхнем крае кнопки (замер по
     ХУДШЕЙ точке, не по середине — урок --hdr-sheen-a выше: 4.52 это округление от провала),
     и остаётся светлее верхнего стопа шапки #1a75b0 — кнопки по-прежнему выделяются. */
  --grad-primary:linear-gradient(180deg,#1c78b5,#12689e);
  --frame-line:#1a75b0;   /* ЛЕВЫЙ (светлый) край шапки — рамка темы в тон, но легче */
  /* СВЕТ В УГЛУ ШАПКИ — ВПОЛСИЛЫ, и это замер, а не вкус (blox52 #5). Три другие шапки
     тёмные: белый текст держит на них 8–13:1, и полные 8% белого им ничего не стоят.
     Здесь же в шапку вышел сам Maya, самый светлый её стоп #1a75b0 даёт белому 4.98:1
     при норме 4.5 — запаса ноль. Полные 8% уводили угол на 4.52, а левый край на
     телефоне на 4.87: формально проход, фактически округление от провала. .05 держит
     угол на 4.69 и край на 4.96, и пятно на шапке при этом видно. */
  --hdr-sheen-a:.05;
}

/* ===========================================================================
   ТЁМНАЯ СХЕМА (ключ dark, blox51 #11) — ЧЕТВЁРТАЯ схема, а не отдельный
   переключатель поверх трёх. Владелец: «тёмная тема — одна или по-разному
   ляжет на каждую? если одна — делай».
   ПОЧЕМУ ОДНА. Схем формально три, но нейтралей у них ДВЕ: тёплая бумага
   базовой и холодный Alice Blue у синих; scheme2/scheme3 делят одну палитру и
   различаются только шапкой. Тёмная ночь стирает именно нейтраль — «тёплый
   светлый» и «холодный светлый» на тёмном фоне перестают различаться, и три
   тёмных палитры оказались бы тремя копиями одной. Осью (день/ночь × 3 схемы)
   это стоило бы шести комбинаций в каждой проверке контраста навсегда и трёх
   значений у каждого нового токена. Плата за «одну»: выбравший «Lingo» на ночь
   уходит из «Lingo», а не гасит её. Если это когда-нибудь помешает — ось
   достраивается поверх этого блока тремя короткими правилами (только --anchor
   и --grad-header), переписывать палитру не придётся.
   ЧТО ЗДЕСЬ ПЕРЕВЕРНУТО, а что нет:
     • ПРАВИЛО СЛОЁВ живёт как есть, только меняет направление: уровня по-прежнему
       два и они чередуются, но теперь СТОЛ ТЕМНЕЕ бумаги (в светлых схемах —
       наоборот), а колодец (--surface) по-прежнему темнее листа. Шаг стол↔бумага
       1.27 — тот же порядок, что 1.32 в светлых: на тёмном разница сжимается,
       поэтому стол уведён почти в чёрный.
     • ЯКОРЬ ОСТАЛСЯ ТЁМНОЙ ЗАЛИВКОЙ ПОД БЕЛЫМ ТЕКСТОМ — это и есть причина, по
       которой тёмная схема обошлась без ломки: возьми якорь светлым, и --on-dark
       перестал бы быть белым во всём приложении (21 место). Взят grape-500:
       белый на нём 5.33:1, а от стола он отделяется на 3.66 — кнопка читается
       как приподнятая, а не как дыра.
     • СОСТОЯНИЯ СОХРАНЯЮТ СВОИ СПЛОШНЫЕ ЗАЛИВКИ (--ok-solid, --alert-solid,
       --alert-strong наследуются из :root): «сделано» и «тревога» обязаны
       выглядеть одинаково во всех схемах, и на тёмном столе они держатся —
       зелёный 6.24:1 с белым и 3.10 к столу, красный 4.89 и 3.96. Переопределены
       только их ЧЕРНИЛА, ТИНТЫ и ЛИНИИ: бледные стопы на тёмной бумаге исчезают.
     • АКЦЕНТ БАЗОВОЙ СХЕМЫ — её собственные чернила (blox51 #3). Ночью чернила
       светлые, значит и акцент светлый; рецепт «тинт = бумага + N% пигмента»
       переживает переворот сам собой, потому что основа у него --card.
   =========================================================================== */
:root[data-scheme="dark"]{
  --tray:var(--surface);      /* поднос конструктора — средний уровень, как до B (blox51 #4) */
  --tile-dark:#352d48;        /* плитка плейлиста ночью — СВЕТЛЕЕ ночной карточки #272233: тёмная тонула в ночном столе */
  /* ЕДИНСТВЕННАЯ строка, которую нельзя заменить токеном: она говорит САМОМУ БРАУЗЕРУ,
     что страница тёмная. Без неё полоса прокрутки, галочки, ползунки, выпадашки и
     подсветка автозаполнения остаются светлыми — на снимке ленты уроков белая полоса
     скролла била по глазам сильнее всего остального вместе взятого. */
  color-scheme:dark;

  /* текст: ночная бумага — светлая, с виноградным подмесом, а не чистый белый */
  --ink:#ece8f2;              /* 12.8:1 на бумаге, 16.2:1 на столе                */
  --ink-strong:#ffffff;       /* одна громкая строка                             */
  --muted:#a89fb8;            /* вторичный текст, 6.1:1                          */
  --faint:#958ca6;            /* подсказки, таймстемпы, disabled, 4.83:1         */
  --muted-strong:#c6bed3;     /* на тон гуще --muted, 8.6:1                      */
  /* текст НА СТОЛЕ. В светлых схемах стол темнее бумаги и подпись на нём
     приходилось УСИЛИВАТЬ; ночью стол темнее ВСЕГО, поэтому там контраста больше,
     а не меньше — хватает обычного --muted (7.7:1). */
  --on-bg:var(--muted);

  /* слои: стол почти чёрный, бумага приподнята, колодец утоплен обратно */
  --bg:#0e0b14;               /* СТОЛ                                            */
  --card:#272233;             /* БУМАГА — карточки, плашки, шторки, 1.27 к столу */
  --task-plaque:var(--card);
  --surface:#1d1926;          /* колодец В бумаге — темнее листа, как и в свете   */
  --surface-2:#221d2d;        /* мягкий inset                                    */
  --line:#3d3750;             /* граница по умолчанию                            */
  --line-soft:#332e44;        /* волосок                                         */
  --line-mid:#4a4360;         /* поле ввода, заметная граница                    */
  /* НЕЙТРАЛЬНАЯ ЗАЛИВКА (дорожка вкладок, лунка на ховере, чип «Nope»). Пропустить её
     здесь — самая дешёвая версия §11-ловушки: токен просто остаётся бежевым из :root, и
     посреди ночного монитора горят светлые пилюли. Ровно это и случилось на первом снимке.
     Значение = --line-soft, как и в синих схемах: «та же светлая подложка, роль заливка». */
  --fill-soft:#332e44;        /* 1.19 к бумаге; --muted-strong на нём 7.3:1       */
  --line-strong:#5d5474;

  /* акцент = светлые чернила схемы (в базовой он чёрный — ночью тот же приём) */
  --accent:#d9d2e4;           /* обводки, выделение, 10.5:1 на бумаге            */
  --accent-ink:#f4f1f8;       /* акцент ТЕКСТОМ — гуще корпуса                   */
  --accent-deep:#d9d2e4;
  --accent-line:#5d5474;
  --accent-tint:color-mix(in srgb, #d9d2e4 9%, var(--card));   /* 1.25 к бумаге  */
  --accent-fill:color-mix(in srgb, #d9d2e4 16%, var(--card));  /* 1.50, ::selection */

  /* якорь и тёмные заливки хрома */
  --anchor:#786388;                 /* grape-500: белый 5.33:1, к столу 3.66     */
  --anchor-ink:var(--grape-300);    /* якорь ЧЕРНИЛАМИ — светлый виноград, 7.7:1 */
  --primary:#564a68;                /* заливка под белым текстом, 8.16:1         */
  --primary-strong:#675a7b;         /* тосты, ридаут перетаскивания, 6.32:1      */
  --grad-header:linear-gradient(135deg,#3a2b46 0%,#2a1f33 62%,#1e1626 100%);
  --chrome:#2a1f33;   /* системная полоса — виноградная шапка ночной схемы */
  --grad-primary:linear-gradient(180deg,#8a729c,#786388);

  /* состояния: заливки НЕ трогаем, чернила/тинты/линии — на светлые стопы.
     Тинт по тому же рецепту (бумага + 12% среднего стопа), только пигмент светлее:
     на тёмной бумаге бледный стоп даёт меньше 1.06 и состояния не слышно. */
  --ok:var(--cel-400);   --ok-ink:var(--cel-300);   --ok-line:#3d6238;
  --ok-tint:color-mix(in srgb, var(--cel-400) 12%, var(--card));
  --ok-fill:color-mix(in srgb, var(--cel-400) 22%, var(--card));
  --alert:var(--gf-400); --alert-ink:var(--gf-300); --alert-line:#7a3336;
  --alert-tint:color-mix(in srgb, var(--gf-400) 12%, var(--card));
  --alert-fill:color-mix(in srgb, var(--gf-400) 22%, var(--card));
  --danger:var(--gf-400); --danger-ink:var(--gf-300);
  --draft:var(--veil-400); --draft-ink:var(--veil-300); --draft-line:#6b4574;
  /* штриховка черновика ночью — СВЕТЛАЯ: --sh-rgb ночью 0,0,0, и чёрный штрих по
     тёмной подложке не увидит никто (та же логика, что у обрезного края). */
  --draft-hatch:rgba(255,255,255,.035);
  --draft-tint:color-mix(in srgb, var(--veil-400) 12%, var(--card));
  --note-bg:color-mix(in srgb, var(--veil-400) 12%, var(--card));
  --note-line:#6b4574; --note-ink:var(--veil-300);
  /* золото: #b07d16 подбиралось под бумагу и на тёмном тонет (1.9:1) — поднято */
  --gold:#d9a83a; --gold-ink:#e8c473; --gold-line:#6b5218;
  --on-gold:#211a0c;          /* тёмная надпись на светлом ночном золоте, 8:1 */
  --gold-tint:color-mix(in srgb, var(--gold) 12%, var(--card));

  /* рельсы тасков: иерархия та же — «нужна сдача» ГРОМЧЕ «просто сделать».
     Ночью громким становится сам небесно-синий (8.2:1), а нейтральный рельс тише (3.3). */
  --task-plain:#7a7186; --task-sub:var(--sky-400);

  /* ОКНО ПРОВОДНИКА ТОЖЕ ГАСНЕТ. Граница blox51 #10 («поверхность чужая»)
     сохранена, но чужое ≠ обязательно белое: у самого Я.Диска есть тёмная тема,
     а белый прямоугольник посреди ночного приложения выжигает глаз сильнее, чем
     любая потеря узнаваемости. Чужим окно остаётся тем, чем и было по существу, —
     красной «Я», плоским списком и серой обвязкой. Различается оно с нашей
     бумагой теперь ТОНОМ: диск нейтрально-серый, наша бумага виноградная.
     Ссылка остаётся синей (решение владельца), но светлой: sky-300 даёт 10.7:1
     на тёмной области файлов, тогда как sky-700 базовой дал бы 1.4. */
  --ya-surface:#1c1b20; --ya-soft:#141317; --ya-line:#33323a;
  --exp-link:var(--sky-300);

  /* ФОКУС-КОЛЬЦО и ВЫДЕЛЕНИЕ отдельных значений НЕ требуют: общий рецепт (:root)
     переворачивается сам. Контур кольца = --ring-c = var(--accent), а ночью акцент
     светлый — 10.5:1 на бумаге, 13.3 на столе; внутренний зазор = --card, то есть
     ночная бумага. Выделение = «акцент 26% в бумагу» = 1.99:1 к листу при --ink 6.4. */

  /* ГЛУБИНА. Тень на тёмном почти не работает — разделяют СЛОИ, а не тени;
     оставляем их чёрными и слабыми, чтобы край листа всё же читался.
     ТИСНЕНИЕ переворачивается: 95%-белый бортик, который ночью был бы сияющей
     полосой по верхней грани каждой плашки, ослаблен до .08; дно канавки
     наоборот углублено — на тёмной бумаге тень видна хуже, чем на светлой. */
  --sh-rgb:0,0,0;
  /* НОЧЬЮ ВОЛНА НЕ УМНОЖАЕТ. Умножение — это «краска в бумагу», и работает оно, пока
     бумага светлее краски. Ночью наоборот: бумага почти чёрная, а чернила (--ink)
     светлые, и multiply дал бы чёрное на чёрном — то есть отклик на касание исчез бы
     ровно там, где он и заведён, на телефоне. Ночью волна остаётся светлым следом. */
  --ripple-blend:normal;
  --emb-hi:rgba(255,255,255,.08);
  --emb-hi-soft:rgba(255,255,255,.05);
  --emb-lo:rgba(0,0,0,.55);
  --emb-edge:rgba(0,0,0,.35);
  /* ОБРЕЗНОЙ КРАЙ НОЧЬЮ ПЕРЕВОРАЧИВАЕТСЯ. Днём торец листа темнее и бумаги, и
     стола — тень в тон. Ночью стол ТЕМНЕЕ листа, и чёрный торец просто растворился
     бы в столе: край листа исчез бы ровно там, где он и нужен. Поэтому ночью торец
     ловит свет — тем же белым, что и бортик, только ещё тише. */
  --sheet-edge:0 0 0 .5px rgba(255,255,255,.06);
  /* blox53 #27 — ЛИНИЯ КОНТАКТА ШАПКИ ПЕРЕВОРАЧИВАЕТСЯ ПО ТОЙ ЖЕ ПРИЧИНЕ. «Чёткая тёмная
     черта под кромкой» ночью не существует: --sh-rgb здесь 0,0,0, а стол под планкой почти
     чёрный (#0e0b14) — планку от стола отделяла ОДНА разница тона (1.08), и край шапки
     читался обрывом заливки. Судья первого прогона это и назвал: «ночью нужен светлый
     волосок». Ставим ровно его — той же белой нитью, что торец листа, только чуть громче:
     это НЕ тень (тень ночью бесполезна), а торец планки. Тень (--plank-cast) намеренно
     оставлена чёрной и невидимой: слоёв в --plank и --plank-flat должно быть поровну, иначе
     переход по прокрутке пойдёт рывком. */
  --plank-line:0 1px 0 rgba(255,255,255,.10);
  /* ЗЕРНО НОЧЬЮ ПОЧТИ ГАСНЕТ. Шум — это светлые точки на тёмном, и на почти чёрном
     столе те же 3.5% читаются не картоном, а цифровым шумом дешёвой матрицы.
     СВЕТ КОМНАТЫ, наоборот, усилен: ночная бумага отличается от ночного стола всего
     на 1.27, и лампа в дневной силе на почти чёрном столе просто не читается. */
  --grain-o:.012;
  --room-o:26%;
  /* СВЕТ В УГЛУ ШАПКИ — ПОЛНОЙ СИЛЫ, и сказано это здесь ВСЛУХ. Ночная шапка тёмная
     (белый на ней 14.9:1), запас у неё огромный, и гасить свет незачем: вполсилы он
     стоит только у «Lingo», где белому тесно. Строка не лишняя — без неё §11-гейт
     справедливо ругается, что число перекрыто одной схемой и молчит в другой. */
  --hdr-sheen-a:.08;
  /* B (redraw-b): вторичная кнопка — ночная серая заливка, а не дневной сланец (тот горел
     бы светлой пилюлей — та самая §11-ловушка с --fill-soft). --ink на ней 9.9:1. */
  --btn-2-bg:#3a3448;
  --btn-2-bg-hover:#453e56;
  /* ночью карточка ТЕМНЕЕ дорожки, и выбранный сегмент читался бы вмятиной — он светлее дорожки */
  --seg-on:#554c6b;
  /* B: полоса группы ночью — тёмный вариант цвета, тинт и текст на нём — ночная пара
     (значения и контраст — в палитре групп, блок B выше). */
  --grp-0-band:var(--grp-0-dk); --grp-0-soft:var(--grp-0-nt); --grp-0-ink:var(--grp-0-nk);
  --grp-1-band:var(--grp-1-dk); --grp-1-soft:var(--grp-1-nt); --grp-1-ink:var(--grp-1-nk);
  --grp-2-band:var(--grp-2-dk); --grp-2-soft:var(--grp-2-nt); --grp-2-ink:var(--grp-2-nk);
  --grp-3-band:var(--grp-3-dk); --grp-3-soft:var(--grp-3-nt); --grp-3-ink:var(--grp-3-nk);
  --grp-4-band:var(--grp-4-dk); --grp-4-soft:var(--grp-4-nt); --grp-4-ink:var(--grp-4-nk);
  --grp-5-band:var(--grp-5-dk); --grp-5-soft:var(--grp-5-nt); --grp-5-ink:var(--grp-5-nk);
  --grp-6-band:var(--grp-6-dk); --grp-6-soft:var(--grp-6-nt); --grp-6-ink:var(--grp-6-nk);
  --grp-7-band:var(--grp-7-dk); --grp-7-soft:var(--grp-7-nt); --grp-7-ink:var(--grp-7-nk);
}

/* ---- icons (see icons.svg / icons.js) ---------------------------------------
   One stroked family, coloured by the text around it. Sized in em so an icon always
   matches its label. .ic-lg for the hub tiles, .ic-xl for empty states.

   ПЕРО ЗНАКА = ПЕРО ШРИФТА (blox52 #3, п.5). Иконка нарисована в квадрате 24×24 и сжимается
   вместе с подписью — значит вместе с ней ужимался и ШТРИХ: рядом с подписью в 11-13px
   (а они почти все жирные, 700-800) штрих выходил 0.9-1.1px и знак был БЛЕДНЕЕ соседней
   буквы. В типографике толщина знака равна толщине шрифта, поэтому штриху нужен ПОЛ.
   Одним числом это не решается: толщина задаётся в единицах картинки, а сжатие зависит
   от кегля подписи — делить длину на длину CSS не умеет. Поэтому штрих переведён на
   vector-effect:non-scaling-stroke (см. icons.svg): он перестаёт сжиматься вместе с
   картинкой, и его толщина пишется прямо в пикселях экрана. Дальше max() и делает пол:
     .084em — ровно та толщина, что была (1.75 × 1.15em ÷ 24), поэтому у крупного знака
              не меняется НИЧЕГО: 20px подписи → 1.68px и до, и после;
     1.35px — пол: включается только при подписи мельче ~16px (13px → 1.09 стало 1.35).
   У .ic-lg и .ic-xl картинка крупнее при том же кегле, поэтому коэффициент у них свой —
   иначе плитки хаба и пустые состояния ПОХУДЕЛИ бы. Прежний stroke-width на .ic-xl был
   мёртвой строкой: правило symbol{} внутри icons.svg ближе к фигуре и всегда его било.
   ОБА значения едут ОТСЮДА переменными, и это страховка: icons.svg подключён внешней ссылкой,
   а браузеры по-разному пускают наши переменные внутрь чужого документа. Где не пустят —
   не приедет ни выключатель --ic-ve, ни толщина --icw, и иконка нарисуется ровно как до этой
   правки (запасные значения внутри icons.svg — прежние). */
.ic{width:1.15em;height:1.15em;flex:0 0 auto;vertical-align:-.17em;
    fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;
    --ic-ve:non-scaling-stroke; --icw:max(1.35px,.084em)}
.ic-lg{width:1.7em;height:1.7em;vertical-align:-.3em;--icw:max(1.35px,.124em)}
.ic-xl{width:2em;height:2em;vertical-align:-.35em;--icw:max(1.35px,.146em)}

/* ---- base ------------------------------------------------------------------- */
*{box-sizing:border-box}
/* ПОЛОСА ПРОКРУТКИ В ТОН. Chrome/Safari красит её через ::-webkit-scrollbar (так сделана
   лента дней, .ncar), Firefox такого не понимает вовсе и слушает только scrollbar-color —
   поэтому в Firefox все полосы приложения оставались системно-серыми поверх бумаги и
   ночного стола. Два значения: ползунок = заметная линия схемы, дорожка прозрачная (фон
   виден насквозь, лишней светлой колеи не появляется). Свойство наследуется, так что
   одного объявления на корне хватает на каждую прокручиваемую область. */
html{-webkit-text-size-adjust:100%;scrollbar-color:var(--line-strong) transparent}
body{
  margin:0;
  font-family:var(--font);
  font-size:var(--fs-md);
  line-height:var(--lh);
  /* ТАБЛИЧНЫЕ ЦИФРЫ ВЕЗДЕ (blox51 #3, заход 6). В Onest пропорциональная единица ВТРОЕ уже
     нуля: замер на 20px — «1111» занимает 28px, «0000» — 52px. Значит любое число, которое
     меняется на месте (таймер плеера, счётчик «к проверке», «5/8», номер дня в ленте) при
     каждом обновлении дёргает соседей на несколько пикселей, а числа в столбик не
     выстраиваются в столбик. Свойство наследуется, поэтому одного объявления на body хватает
     на всё приложение — курировать список счётчиков не нужно, и новый счётчик получит
     табличные цифры сам. В прозе они чуть шире, и это осознанная плата: текста с числами в
     приложении почти нет, а числа есть на каждом экране. Стережёт проба «цифры не дёргаются». */
  font-variant-numeric:tabular-nums;
  /* КЕРНИНГ ЯВНО (blox52 #6, п.2). У Onest пары вроде «Го», «АV», «Ту» описаны в самом файле
     шрифта, но по умолчанию браузер включает их не всегда: `auto` разрешает движку отключить
     кернинг ради скорости — на мелком кегле именно это и происходило. `normal` требует его
     всегда. Свойство наследуется, поэтому одного объявления на body хватает на приложение. */
  font-kerning:normal;
  color:var(--ink);
  background:var(--bg);
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}
/* ЗЕРНО И СВЕТ КОМНАТЫ — ДВА ПРИБИТЫХ К ЭКРАНУ СЛОЯ ПОВЕРХ СТОЛА (blox52 #4, пп. 4-5).
   Зачем два псевдоэлемента, а не один: у зерна и у света разная сила, и ночь гасит одно и
   усиливает другое — на одном слое их одной непрозрачностью не развести. Зерно живёт на
   html::before, а не на body::after, потому что body::after занят дев-инспектором
   (inspector.css) и в его режиме зерно бы пропадало.
   z-index:-1 — слои лежат ПОД всем содержимым и НАД заливкой стола. Работает это так:
   у html своей заливки нет, поэтому фон body по правилу CSS уезжает на холст страницы,
   а сам body остаётся прозрачным — и отрицательный слой оказывается поверх холста.
   ЕСЛИ КОГДА-НИБУДЬ ЗАДАТЬ html СВОЙ background — оба слоя окажутся под ним и исчезнут
   молча; это и стережёт проба «материал бумаги» (она меряет разброс пикселей на снимке,
   а не наличие правила в CSS).
   pointer-events:none — слой не имеет права перехватить ни одного касания; та же проба
   бьёт по этому факту отдельно, потому что ломается он тихо и целиком. */
html::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background-image:var(--grain-img);background-size:128px 128px;opacity:var(--grain-o)}
body::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(150% 115% at 50% 0%,
    color-mix(in srgb, var(--card) var(--room-o), transparent) 0%, transparent 66%)}
/* печать: зерно и виньетка — свойство ЭКРАНА, на бумаге это просто серый налёт поверх текста */
@media print{ html::before,body::before{display:none} }
/* ЗАГОЛОВОК ЛОМАЕТСЯ ПО СМЫСЛУ, А НЕ ПО СЛУЧАЙНОМУ СЛОВУ (blox52 #6, п.2). До этого во всём
   продукте стояло РОВНО ОДНО правило красивой разбивки строк (.estate-t) — остальные заголовки
   рвались там, где кончилась ширина, и на телефоне регулярно оставляли одно слово на второй
   строке. `balance` выравнивает длину строк заголовка между собой. Действует только на короткие
   блоки (браузер применяет его до нескольких строк), поэтому длинному абзацу он не повредит, а
   там, где свойства нет, строка ломается ровно как раньше — деградация без вреда. */
h1,h2,h3,h4{letter-spacing:var(--tracking-tight);line-height:var(--lh-tight);text-wrap:balance}
/* поля и кнопки не наследуют шрифт от body сами (UA-стили), поэтому и семейство, и
   табличные цифры передаём им явно: в поле ввода PIN-кода это особенно заметно. */
/* ...и кернинг тоже: UA-стиль задаёт кнопке свой шрифт целиком, поэтому font-kerning:normal с
   body до неё не доезжает — описание плитки кабинета лежит ВНУТРИ <button>, и без этой строки
   единственный длинный читаемый текст с кернингом оставался бы «auto» (blox52 #6). */
button,input,select,textarea{font-family:inherit;font-variant-numeric:inherit;font-kerning:inherit}
/* МИГАЮЩИЙ КУРСОР В ПОЛЕ — цветом схемы, а не системным. Системный курсор в Chrome
   чёрный, в тёмной схеме на почти чёрной бумаге его попросту не видно, а в дневных
   схемах он единственная деталь ввода, которая не слушалась палитры. Берём акцентные
   ЧЕРНИЛА: они тёмные в светлых схемах и светлые в ночной, то есть контрастны бумаге
   в каждой из четырёх. Курсор ставится только полям — у кнопок его нет. */
input,textarea{caret-color:var(--accent-ink)}
/* СИСТЕМНЫЕ ГАЛОЧКА, РАДИО, ПОЛЗУНОК И ПОЛОСА ЗАГРУЗКИ. Их рисует сам браузер, и без
   accent-color они синие (Chrome) или серые — включая галочку на воротах согласия, где
   это первый управляющий элемент, который человек видит в приложении. --anchor — тёмная
   сплошная заливка СВОЕЙ схемы (баклажан · графит · Maya · ночной виноград), та же, что
   под белым текстом кнопки: белая галочка на ней читается по построению. Ночная схема
   берёт свой якорь автоматически, отдельного правила не нужно. */
input[type=checkbox],input[type=radio],input[type=range],progress{accent-color:var(--anchor)}
/* РАЗМЕР галочки и радио. Браузер рисует их 13×13px — ниже линии WCAG 2.5.8 AA (24px) и ниже
   порога G5 ночного обходчика, который на этом и краснел: «Челлендж» и «Личное» в окне таска.
   Подпись рядом кликабельна (<label for>), но палец целится в саму коробочку, а 13px на телефоне
   промахивается. 24px — минимум правила, а не вкус; правило общее, потому что галочек в проекте
   ровно шесть и все они стоят в строке с подписью, где лишние 11px по высоте ничего не ломают. */
input[type=checkbox],input[type=radio]{inline-size:24px;block-size:24px;flex:none;margin:0}
/* Safari на iOS зумит страницу, когда фокус попадает в поле со шрифтом меньше 16px, и обратно
   уже не отзумливает — приложение остаётся «съехавшим» вправо даже после ухода с экрана
   (blox11 #3, поле чата было 15px). На тач-экранах держим все поля ровно на 16px. !important —
   потому что точечные правила компонентов задают свой font-size и иначе перебьют это. */
@media (pointer:coarse){
  input,select,textarea{font-size:16px !important}
}
:focus-visible{outline:none;box-shadow:var(--ring)}
/* КОЛЬЦО В РЕЖИМЕ ВЫСОКОЙ КОНТРАСТНОСТИ (ночной редизайн 27.10.2026). Windows с включённой
   высокой контрастностью (forced-colors) снимает box-shadow со ВСЕГО — а кольцо --ring и есть
   тень, так что с клавиатуры там не было видно, где ты, ни на одном контроле. Контур (outline)
   этот режим не снимает. !important — потому что полтора десятка компонентов пишут себе
   outline:none рядом с кольцом; вне этого режима блок не действует вовсе, ничего не сдвигает. */
@media (forced-colors:active){
  :focus-visible{outline:2px solid Highlight !important;outline-offset:2px !important}
}

/* ===========================================================================
   «УМЕНЬШИТЬ ДВИЖЕНИЕ» — ОБЩЕЕ ПРАВИЛО (ночной редизайн 27.10.2026)
   Просьба человека к системе, не пожелание. До этой ночи её исполнял каждый компонент сам
   (два десятка точечных блоков), и новая анимация, у которой блок забыли, играла бы вопреки
   просьбе. Теперь умолчание — ПОКОЙ:
     • КАДРОВЫЕ АНИМАЦИИ (@keyframes) под просьбой выключены у всех. Предмет, которому
       нужна своя тихая версия (крутилка загрузки медленнее, волна касания простой
       вспышкой), объявляет её в --motion-reduced в своём блоке @media — и получает её.
       Почему не «animation-duration:.01ms на всё»: так делать прямо запрещает руководство
       modern-web-guidance (резкий скачок хуже движения), а волна касания (ripple.js)
       удаляет себя по animationend — её тихая версия обязана доиграть.
     • ПЕРЕХОДЫ (transition) не трогаем: смена цвета и прозрачности — не движение, и там,
       где компонент уже решил «цвет едет, сдвиг нет», это решение стережётся автотестами
       (день каретки, кнопки). Сдвиг и масштаб гасятся ТОКЕНАМИ величины движения
       (--press-scale*, --lift, --enter-shift*): ниже они становятся тождеством.
   @property — чтобы переменная НЕ НАСЛЕДОВАЛАСЬ: тихая версия, объявленная на кнопке,
   не должна доставаться её иконке. Где @property нет, var() без значения делает объявление
   недействительным, и анимация так же выключается — тот же итог. */
@property --motion-reduced{syntax:"*";inherits:false;initial-value:none}
@media (prefers-reduced-motion:reduce){
  :root{
    --press-scale-sm:1; --press-scale:1; --press-scale-lg:1;
    --lift:0px; --enter-shift:0px; --enter-shift-lg:0px;
  }
  *,*::before,*::after{animation:var(--motion-reduced) !important}
}
/* выделение текста идёт за акцентом СВОЕЙ схемы (blox51 #3, заход 3.2). Раньше базовая брала
   sky-200 напрямую, а обе синих повторяли Pale Sky каждая у себя — три места на один факт,
   и после ухода базового акцента в чёрный первое из них осталось бы синим. --accent-fill
   уже есть, уже светлый в каждой схеме и уже стережётся пробой «акцентные поверхности». */
/* blox52 #2: заливка --accent-fill давала выделению 1.34:1 к бумаге — протащить мышью по
   абзацу и не увидеть, что выделено. Теперь у выделения свой токен --sel-bg (см. theme
   выше), а --accent-fill остался тем, чем был, — поверхностью. */
::selection{background:var(--sel-bg);color:var(--ink)}
