﻿/* Стили десктопа и веба — один файл, слоями от общего к частному:
   шрифты → палитра → основа → компоненты → каркас → экраны.
   Компоненты — то, что стоит на двух экранах и больше; экран подправляет
   их только селектором со своим классом. Карта и правила — DESIGN.md,
   порядок слоёв и место общих деталей сторожит tests/unit/visual-rules.test.js. */

/* ========== Слой: Шрифты ========== */

/* ---------- Шрифты ----------
   С 9 октября 2026 всё набирается Onest — и текст, и заголовки, и крупные
   числа (--font-display ниже — тот же Onest, плотнее). С 10 октября и
   логотип: лицензии на Basique Pro, которым он был набран, нет.

   Onest — переменный шрифт: одна гарнитура даёт любой вес от 100 до 900,
   поэтому лесенка 400/500/600/700 в разметке работает без подмен. Файлов
   четыре — кириллица, расширенная кириллица (казахские буквы и ₴),
   латиница, расширенная латиница (₽ ₸ ₺); браузер грузит только те, чьи
   буквы встретились на экране. Своих цифр одинаковой ширины у Onest хватает
   (tabular-nums) — таймер не дрожит. Курсива нет, браузер наклоняет сам.
   Лицензия — OFL, assets/fonts/Onest-OFL.txt. */

@font-face { font-family: 'Onest'; src: url('vendor/fonts/Onest-Cyrillic.woff2') format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; }
@font-face { font-family: 'Onest'; src: url('vendor/fonts/Onest-CyrillicExt.woff2') format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; }
@font-face { font-family: 'Onest'; src: url('vendor/fonts/Onest-Latin.woff2') format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Onest'; src: url('vendor/fonts/Onest-LatinExt.woff2') format('woff2'); font-weight: 100 900; font-style: normal; font-display: swap; unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

/* ========== Слой: Палитра ========== */

/* ---------- Палитра ---------- */

:root {
  color-scheme: dark;

  --font-ui: 'Onest', -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* Крупное — заголовки, числа, суммы — тот же Onest, что текст, только
     плотнее (--fw-display). Логотип — тоже Onest, но своим токеном: у знака
     свой вес и своя разрядка (.tb-logo-text). */
  --font-display: var(--font-ui);
  --font-logo: var(--font-ui);
  /* Вес обычного текста. В светлой теме на полступени плотнее: тёмные буквы
     на белом читаются тоньше, чем светлые на тёмном. Onest переменный, 450
     у него настоящий, а не подобранный. */
  --fw-text: 400;
  /* Вес крупного: заголовки, крупные числа, суммы. Onest переменный, и
     светлая тема берёт ступень между: Bold тёмным по белому слипается.
     Лого — знак, а не текст, и остаётся Bold в обеих темах. */
  --fw-display: 700;

  /* Острова, редакция 7 октября 2026. Предмет отличается от земли только
     цветом: ни обводок, ни теней, ни градиентов. Три ступени — земля,
     остров, поле внутри острова; четвёртая (--raise) — то, что лежит на
     поле: активный сегмент, карточка доски. */
  --bg: #111215;
  --panel: #1a1b1f;
  --panel-2: #232428;
  --raise: #2a2b31;
  /* Столбец доски — поле внутри острова, карточка на нём — ступень выше. */
  --board-col: #232428;
  --board-card: #2a2b31;
  /* Доля цвета тега в надписи на бейдже — см. .tag-chip. */
  --tag-ink: 62%;
  /* Единственная линия — разделитель строк внутри острова. Обводок у
     предметов нет, поэтому --border — псевдоним той же линии: старое имя
     остаётся у разделителей, новые правила берут --line. */
  --line: rgba(255, 255, 255, 0.06);
  --border: var(--line);
  --border-soft: var(--line);
  --border-strong: #45474f;
  /* Полоса прокрутки — приглушённая, а под курсором чуть ярче. */
  --scrollbar: #3b3d44;
  --scrollbar-hover: #5b5e68;
  /* Рейл и пилюли шапки — острова, как всё остальное. */
  --rail: #1a1b1f;
  --pill: #232428;

  --text: #f2f3f5;
  --text-dim: #aeb1ba;
  --text-faint: #8f929c;      /* третья ступень: подписи дней, счётчики */
  --icon: #979ba5;            /* монохромные иконки: не текст, не акцент */

  /* Акцент — только у главного: кнопка действия, квадрат стоп/плей у
     идущего таймера, точка капсулы, «сегодня». Деньги и сроки — обычный
     текст. Акцент текстом — отдельный токен: на белом неон не читается. */
  --accent: #69d345;
  --accent-hover: #7add58;
  --accent-text: #0d1a07;
  --accent-ink: #69d345;

  --link: #5ec8f2;
  --danger: #ef7a72;
  /* Приглушённый красный: опасный пункт меню в покое. Смесь --danger с
     --panel на 85%, посчитанная вперёд — токеном, а не color-mix на месте, как
     и все остальные цвета. Читается на --panel (tests/unit/contrast.test.js). */
  --danger-dim: #cf6c66;
  --running: #7add58;
  /* Белое поверх насыщенной заливки: текст опасной кнопки, цифра в значке.
     В обеих темах одно и то же. Бегунок включённого переключателя — не
     здесь: на зелёной дорожке белый не виден, он берёт --accent-text. */
  --text-on-color: #fff;
  /* Затемнение под модалкой и фон блока кода в редакторе тёмные в обеих
     темах: код читается светлым по тёмному и в светлой теме. */
  --scrim: rgba(0, 0, 0, 0.5);
  --code-bg: #0f1012;

  --tab-active-bg: #2a2b31;
  --nav-active-bg: #232428;
  /* Выделенный период на сетке месяца, столбец «сегодня» в неделе. */
  --sel: rgba(105, 211, 69, 0.10);

  /* Иллюстрации пустых экранов (core/illustrations.js): подложка-круг, лист
     поверх неё и линии на листе. Подложка отличается и от земли, и от
     острова, поэтому сценка одна и та же на любом из них. Акцент — свой,
     --accent. */
  --art-plate: var(--panel-2);
  --art-sheet: #34363e;
  --art-ink: #4c4f58;

  /* Тени только у того, что парит над страницей: меню, пикеры, модалки.
     Острова и пилюли теней не носят. */
  --shadow: none;
  --shadow-pop: 0 10px 28px rgba(0, 0, 0, 0.5);
  --shadow-modal: 0 16px 44px rgba(0, 0, 0, 0.55);
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  /* Пружины для «жидких» анимаций (linear() — Chromium 113+). --spring —
     затухающая пружина с перехлёстом ~20%: капля, галочка, значок, который
     выпрыгивает. --spring-soft — подложка вкладок: к середине пути ещё в
     пути, у самого конца мягкий перехлёст ~3% и возврат. */
  --spring: linear(0, 0.043, 0.153, 0.306, 0.479, 0.652, 0.812, 0.949, 1.057, 1.134, 1.182, 1.203, 1.203, 1.186, 1.158, 1.124, 1.088, 1.053, 1.023, 0.998, 0.979, 0.967, 0.96, 0.958, 0.96, 0.965, 0.971, 0.978, 0.986, 0.992, 0.998, 1.003, 1.006, 1.008, 1.009, 1.009, 1.008, 1.007, 1.005, 1.004, 1);
  --spring-soft: linear(0, 0.143, 0.271, 0.386, 0.489, 0.579, 0.66, 0.73, 0.791, 0.844, 0.89, 0.929, 0.961, 0.986, 1.006, 1.02, 1.028, 1.03, 1.026, 1.016, 1);
  --radius: 14px;
  --radius-sm: 10px;
  /* Кнопка запуска и галочка задачи — один скруглённый квадрат во всех
     местах. Треть самой мелкой стороны (галочка 16 px): галочка читается
     квадратом, а не кругом, и кнопки 28–44 px не выглядят острыми. */
  --radius-xs: 5px;
  --gap: 12px;
  /* Ширина зоны полосы прокрутки: полоса накладная (см. «Скроллбар»), места в
     раскладке не занимает; бегунок внутри зоны — 4 px, под курсором 8 px. */
  --sb: 10px;
  --nav-w: 184px;
  --nav-w-collapsed: 52px;
  /* Ширина зоны под нативные кнопки окна macOS в шапке. Не связана с рейлом:
     шапка едина и не переламывается при его сворачивании. */
  --traffic-w: 92px;

  /* Редактор: оттенки текста, рисунка и графиков (--led-c-*) и заливки
     маркера, выносок, ячеек (--led-hl-*). Документ хранит имя цвета, а не
     число, — поэтому тот же «жёлтый маркер» читается в обеих темах. */
  --led-c-gray: #9aa0aa;
  --led-c-red: #ff7b72;
  --led-c-orange: #ffa657;
  --led-c-yellow: #f2cc60;
  --led-c-green: #7ee787;
  --led-c-teal: #56d4c4;
  --led-c-blue: #79b8ff;
  --led-c-purple: #c297ff;
  --led-c-pink: #ff8fc7;
  --led-hl-gray: rgba(154, 160, 170, 0.24);
  --led-hl-red: rgba(255, 123, 114, 0.26);
  --led-hl-orange: rgba(255, 166, 87, 0.26);
  --led-hl-yellow: rgba(242, 204, 96, 0.3);
  --led-hl-green: rgba(126, 231, 135, 0.22);
  --led-hl-teal: rgba(86, 212, 196, 0.22);
  --led-hl-blue: rgba(121, 184, 255, 0.24);
  --led-hl-purple: rgba(194, 151, 255, 0.24);
  --led-hl-pink: rgba(255, 143, 199, 0.24);
}

/* ---------- Светлая тема ----------
   Острова (7 октября): светло-серая земля, белые предметы, серые
   нейтральные, текст почти чёрный; зелёный буквами глубже, чем заливкой.
   Явный выбор пользователя (data-theme="light") работает всегда. Системная
   тема (когда пользователь не переопределил её — нет data-theme="dark"/"light")
   следует за ОС через prefers-color-scheme. Оба блока одинаковые — это
   сторожит tests/unit/visual-rules.test.js. */
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]):not([data-theme="light"]) {
    color-scheme: light;
    --fw-text: 450;
    --fw-display: 600;
    --bg: #eceef1;
    --panel: #ffffff;
    --panel-2: #f1f2f4;
    --raise: #ffffff;
    --board-col: #f1f2f4;
    --board-card: #ffffff;
    --tag-ink: 40%;
    --line: rgba(10, 10, 12, 0.07);
    --border-strong: #9d9da5;
    --scrollbar: #c8c8cf;
    --scrollbar-hover: #a4a4ad;
    --rail: #ffffff;
    --pill: #ffffff;
    --text: #0a0a0c;
    --text-dim: #45454d;
    --text-faint: #6a6a73;
    --icon: #55555d;
    --accent: #63c841;
    --accent-hover: #56b337;
    --accent-text: #0d1a07;
    --accent-ink: #1f7a12;
    --link: #1764a3;
    --danger: #c22a1d;
    --danger-dim: #cb4a3f;
    --running: #49982f;
    --code-bg: #232428;
    --tab-active-bg: #ffffff;
    --nav-active-bg: #f1f2f4;
    --sel: rgba(99, 200, 65, 0.14);
    --art-plate: #e3e5e9;
    --art-sheet: #ffffff;
    --art-ink: #c9ccd3;
    --shadow-pop: 0 8px 24px rgba(9, 9, 11, 0.16);
    --shadow-modal: 0 18px 48px rgba(9, 9, 11, 0.22);
    --led-c-gray: #5f6670;
    --led-c-red: #c8281e;
    --led-c-orange: #b04a00;
    --led-c-yellow: #8a6100;
    --led-c-green: #1a7f37;
    --led-c-teal: #0b7369;
    --led-c-blue: #0a64c8;
    --led-c-purple: #7c4bd6;
    --led-c-pink: #b8337f;
    --led-hl-gray: #e5e7ea;
    --led-hl-red: #ffdcd7;
    --led-hl-orange: #ffe3c6;
    --led-hl-yellow: #fff0a6;
    --led-hl-green: #d5f3d3;
    --led-hl-teal: #ccefea;
    --led-hl-blue: #d9e9ff;
    --led-hl-purple: #e9defe;
    --led-hl-pink: #ffdcee;
  }
}
:root[data-theme="light"] {
  color-scheme: light;
  --fw-text: 450;
  --fw-display: 600;
  --bg: #eceef1;
  --panel: #ffffff;
  --panel-2: #f1f2f4;
  --raise: #ffffff;
  --board-col: #f1f2f4;
  --board-card: #ffffff;
  --tag-ink: 40%;
  --line: rgba(10, 10, 12, 0.07);
  --border-strong: #9d9da5;
  --scrollbar: #c8c8cf;
  --scrollbar-hover: #a4a4ad;
  --rail: #ffffff;
  --pill: #ffffff;
  --text: #0a0a0c;
  --text-dim: #45454d;
  --text-faint: #6a6a73;
  --icon: #55555d;
  --accent: #63c841;
  --accent-hover: #56b337;
  --accent-text: #0d1a07;
  --accent-ink: #1f7a12;
  --link: #1764a3;
  --danger: #c22a1d;
  --danger-dim: #cb4a3f;
  --running: #49982f;
  --code-bg: #232428;
  --tab-active-bg: #ffffff;
  --nav-active-bg: #f1f2f4;
  --sel: rgba(99, 200, 65, 0.14);
  --art-plate: #e3e5e9;
  --art-sheet: #ffffff;
  --art-ink: #c9ccd3;
  --shadow-pop: 0 8px 24px rgba(9, 9, 11, 0.16);
  --shadow-modal: 0 18px 48px rgba(9, 9, 11, 0.22);
  --led-c-gray: #5f6670;
  --led-c-red: #c8281e;
  --led-c-orange: #b04a00;
  --led-c-yellow: #8a6100;
  --led-c-green: #1a7f37;
  --led-c-teal: #0b7369;
  --led-c-blue: #0a64c8;
  --led-c-purple: #7c4bd6;
  --led-c-pink: #b8337f;
  --led-hl-gray: #e5e7ea;
  --led-hl-red: #ffdcd7;
  --led-hl-orange: #ffe3c6;
  --led-hl-yellow: #fff0a6;
  --led-hl-green: #d5f3d3;
  --led-hl-teal: #ccefea;
  --led-hl-blue: #d9e9ff;
  --led-hl-purple: #e9defe;
  --led-hl-pink: #ffdcee;
}

/* ========== Слой: Основа ========== */

/* ---------- Крупное ----------
   Заголовки страниц и крупные числа — --font-display (Onest плотнее, см.
   «Шрифты»). Название периода в календаре и статистике — тоже, но шрифт
   задан в самом компоненте .period-title. Логотип — свой шрифт, ниже. */
#task-title,
.history-head h2,
.modal-title,
.ph-name,
.timer-display,
.stat-card b {
  font-family: var(--font-display);
}

* { box-sizing: border-box; }
input, select, button, textarea { font-family: inherit; }
[hidden] { display: none !important; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ---------- Скроллбар: накладной, тонкий, в цветах темы ----------
   Полоса места не занимает и содержимое не двигает: у прокручиваемых областей
   приложения (атрибут data-ovs — его ставит attachOverlayScroll в app.js)
   нативная полоса скрыта, а поверх содержимого, у правого края области,
   рисуется своя: дорожка .ovs-track с бегунком .ovs-thumb. Дорожки лежат в
   <body> и в разметку областей не вмешиваются. Вбок полосы нет совсем —
   ни накладной, ни нативной: ленты, что листаются вбок, показывают свой край
   растворением и кнопкой-стрелкой (компонент «Край ленты», слой «Компоненты»). Видна, пока область
   крутят или над ней мышь, и гаснет через секунду тишины; под самой дорожкой
   бегунок толще и ярче. Размер и положение бегунка считает app.js — от
   scrollHeight, clientHeight и scrollTop; здесь — только вид. Цвет — токены
   --scrollbar и --scrollbar-hover, зона дорожки — --sb. Отступов под полосу
   и scrollbar-gutter нет нигде: их нет и в раскладке экранов.

   Нативная полоса осталась там, куда накладной ещё нет хода: внутри текста
   редактора (блоки кода, таблицы) и его подсказок. Она тонкая и в тех же
   цветах, но место занимает. Только webkit-псевдоэлементы, БЕЗ
   scrollbar-width/scrollbar-color: в Chromium если на элементе заданы обе
   группы свойств одновременно, побеждают стандартные и весь webkit-кастом (в
   т.ч. ::-webkit-scrollbar-button) молча игнорируется — полоса откатывается на
   вид по умолчанию (широкий, со стрелками, без скругления). Исключение —
   [data-ovs]: там полоса скрыта целиком, и оба способа говорят одно. */
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background-color: var(--scrollbar);
  background-clip: padding-box;
  border: 2px solid transparent;
  border-radius: 9px;
}
*::-webkit-scrollbar-thumb:hover { background-color: var(--scrollbar-hover); background-clip: padding-box; }
*::-webkit-scrollbar-corner { background: transparent; }
/* Вбок область не едет, пока у неё самой не сказано иное: лента карточек
   проектов (.projects-deck) и дорожки доски (.board-cols) объявляют свой
   overflow-x ниже и подключены к «Краю ленты». Страница или колонка, чьё
   содержимое чуть шире, обрежет его, а не обзаведётся полосой снизу. */
[data-ovs] { scrollbar-width: none; overflow-x: hidden; }
[data-ovs]::-webkit-scrollbar { display: none; width: 0; height: 0; }
/* Дорожка не видна и не ловит мышь, пока область не трогают. visibility
   меняется после затухания, а при появлении — сразу. Пока видна, мышь она
   тоже не ловит (pointer-events: none): лежит поверх содержимого, и щелчок в
   правых 10 px строки списка или пункта меню должен дойти до строки. Ловит
   только бегунок — его ширина, а не вся зона --sb. */
.ovs-track {
  position: fixed; z-index: 500; box-sizing: border-box;
  opacity: 0; visibility: hidden;
  transition: opacity 0.18s var(--ease), visibility 0s linear 0.18s;
  width: var(--sb); user-select: none; touch-action: none; pointer-events: none;
}
.ovs-track.on { opacity: 1; visibility: visible; transition: opacity 0.12s var(--ease), visibility 0s; }
.ovs-thumb { position: absolute; top: 0; right: calc((var(--sb) - 4px) / 2); width: 4px; border-radius: 99px; background: var(--scrollbar); pointer-events: auto; transition: background-color 0.12s var(--ease), width 0.12s var(--ease), right 0.12s var(--ease); }
.ovs-track:hover .ovs-thumb, .ovs-track.drag .ovs-thumb { right: calc((var(--sb) - 8px) / 2); width: 8px; background: var(--scrollbar-hover); }
body.ovs-dragging { user-select: none; }
@media (prefers-reduced-motion: reduce) {
  .ovs-track, .ovs-track.on, .ovs-thumb { transition: none; }
}

html, body { margin: 0; height: 100%; overflow: hidden; }
body {
  font-family: var(--font-ui);
  font-size: 14px;
  font-weight: var(--fw-text);
  color: var(--text);
  background: var(--bg);
  display: flex;
  flex-direction: column;
}

/* <b>/<strong> без своего правила берут браузерный bold (700) — для
   выделения внутри строки это слишком тяжело. Полужирный 600 заметен и не
   рвёт строку. */
b, strong { font-weight: 600; }

.muted { color: var(--text-dim); }

/* иконки */
.icon {
  width: 15px;
  height: 15px;
  flex: none;
  fill: currentColor;
  color: var(--icon);
  vertical-align: -2px;
}

/* ---------- Анимации ---------- */

@keyframes viewIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes tileIn { from { opacity: 0; transform: translateY(10px) scale(0.98); } to { opacity: 1; transform: none; } }
@keyframes popIn { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: none; } }
@keyframes backdropIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes toastIn { from { opacity: 0; transform: translate(-50%, 10px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* Строка переезжает на новое место (app.js, «Порядок строк»): остановили
   задачу, и она встала первой в «Недавних», в карточке, в «Проектах» на
   «Сегодня». Код замеряет, где строка стояла и где встала, и кладёт разницу
   в --flip-x/--flip-y; строка едет из прежнего места в новое. Перерисовка
   посреди переезда доигрывает его с того же момента (--flip-t —
   отрицательная задержка). Остановленная (.flip-lead) идёт над остальными
   на подложке — как поднятая карточка, а не текст по тексту. Без движения
   код класс не ставит. */
@keyframes flipMove { from { transform: translate(var(--flip-x, 0), var(--flip-y, 0)); } }
.flip-move { position: relative; animation: flipMove 0.4s var(--ease) var(--flip-t, 0s) both; }
.flip-move.flip-lead { z-index: 1; background: var(--panel-2); }

/* «Жидкий» старт таймера (см. «Кнопка запуска» и «Таймер в правом верхнем
   углу»). Желе — упругое колебание формы: сплющило ударом капли,
   растеклось, качнулось обратно и улеглось; амплитуда тает к концу. */
@keyframes liqJelly {
  0% { transform: none; }
  14% { transform: scale(0.86, 1.1); }
  34% { transform: scale(1.12, 0.9); }
  52% { transform: scale(0.95, 1.05); }
  70% { transform: scale(1.03, 0.98); }
  86% { transform: scale(0.99, 1.01); }
  100% { transform: none; }
}
/* Слив мягче налива: форма проседает и выпрямляется. */
@keyframes liqSag {
  0% { transform: none; }
  30% { transform: scale(1.06, 0.92); }
  58% { transform: scale(0.98, 1.03); }
  80% { transform: scale(1.01, 0.99); }
  100% { transform: none; }
}
/* Жидкость в кнопке — большой скруглённый квадрат: пока он поднимается и
   поворачивается, его край над кнопкой ходит волной. Конец подъёма
   накрывает кнопку целиком при любом повороте. */
@keyframes liqRise {
  from { transform: translate(-50%, 0) rotate(0deg); }
  to { transform: translate(-50%, -54%) rotate(200deg); }
}
@keyframes liqFall {
  from { transform: translate(-50%, -46%) rotate(0deg); }
  to { transform: translate(-50%, 2%) rotate(-170deg); }
}
@keyframes liqRing { from, 70% { border-color: var(--panel-2); } to { border-color: var(--accent); } }
@keyframes liqPop { from { transform: scale(0.2); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes liqFadeIn { from { opacity: 0; transform: translateX(8px); } to { opacity: 1; transform: none; } }
@keyframes liqFadeOut { to { opacity: 0; } }
/* Капсула шапки: проявляется справа налево от места «Старта» (край —
   полукруг, как у пилюли) и обратно стекает в него. */
@keyframes liqReveal {
  from { clip-path: inset(0 0 0 calc(100% - var(--liq-from, 34px)) round 999px); }
  to { clip-path: inset(0 0 0 0 round 999px); }
}
@keyframes liqDrain {
  from { clip-path: inset(0 0 0 0 round 999px); }
  to { clip-path: inset(0 0 0 calc(100% - var(--liq-from, 34px)) round 999px); }
}
/* Капсула растягивается — тоньше, перехлёст — толще; качается у правого края. */
@keyframes liqStretch {
  0% { transform: none; }
  12% { transform: scale(1, 1.1); }
  40% { transform: scale(1.015, 0.9); }
  60% { transform: scale(0.995, 1.05); }
  78% { transform: scale(1.004, 0.98); }
  100% { transform: none; }
}
/* Зелёная капля «Стопа»: набухает из точки и вздрагивает, пока не встанет. */
@keyframes liqDropIn {
  0% { transform: scale(0.3, 0.55); }
  30% { transform: scale(1.12, 0.84); }
  50% { transform: scale(0.94, 1.1); }
  70% { transform: scale(1.03, 0.96); }
  85% { transform: scale(0.99, 1.01); }
  100% { transform: none; }
}
@keyframes liqDropOut {
  0%, 46% { transform: none; }
  62% { transform: scale(1.1, 0.9); }
  100% { transform: scale(0.2, 0.4); }
}
/* Бусина — капля, что отрывается от «Стопа» перемычкой (фильтр #liq-goo) и
   катится к точке «идёт» слева; на обратном пути — вливается назад. */
@keyframes liqBeadOut {
  0% { transform: scale(0.5); }
  18% { transform: scale(1); }
  30% { transform: translateX(calc(var(--liq-run, 0px) * 0.12)) scale(1, 0.86); }
  68% { transform: translateX(var(--liq-run, 0px)) scale(1.12, 0.9); }
  84%, 100% { transform: translateX(var(--liq-run, 0px)) scale(0); }
}
@keyframes liqBeadIn {
  0%, 8% { transform: translateX(var(--liq-run, 0px)) scale(0.7); }
  50% { transform: translateX(calc(var(--liq-run, 0px) * 0.1)) scale(1, 0.86); }
  62%, 100% { transform: scale(0.4); }
}
/* «Старт» выходит из стёкшей капсулы и вздрагивает, как улёгшаяся капля. */
@keyframes liqSettle {
  0%, 70% { opacity: 0; transform: none; }
  80% { opacity: 1; transform: scale(1.06, 0.9); }
  91% { transform: scale(0.98, 1.03); }
  100% { opacity: 1; transform: none; }
}

/* Колокольчик звенит: короткий звон с затуханием и длинная пауза в одном
   периоде. Язычок (первый контур иконки) отстаёт и бьёт в другую сторону. */
@keyframes bellRing {
  0%, 15%, 100% { transform: none; }
  2% { transform: rotate(16deg); }
  4.5% { transform: rotate(-13deg); }
  7% { transform: rotate(9deg); }
  9.5% { transform: rotate(-6deg); }
  12% { transform: rotate(3deg); }
}
@keyframes bellClapper {
  0%, 16%, 100% { transform: none; }
  3% { transform: translateX(-2.5px); }
  5.5% { transform: translateX(2px); }
  8% { transform: translateX(-1.5px); }
  10.5% { transform: translateX(1px); }
  13% { transform: translateX(-0.5px); }
}
@keyframes badgeBump { 0%, 6%, 100% { transform: none; } 1.5% { transform: scale(1.2); } }

.view.anim { animation: viewIn 0.22s var(--ease); }
/* Строки и карточки въезжают лесенкой только вместе с экраном; на осевшем
   экране (перерисовка на месте) появляются сразу, без мигания. */
.view.settled .task-item, .view.settled .ptile, .view.settled .session-item,
.view.settled .period-list li, .view.settled .cal-day-list li { animation: none; }

/* ========== Слой: Компоненты ========== */

/* ---------- Кнопки ---------- */
button.danger, button.ghost {
  border: 0;
  background: var(--panel-2);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  cursor: pointer;
  font-size: 13px;
  transition: border-color 0.12s var(--ease), color 0.12s var(--ease);
}
button.danger { color: var(--danger); }
button.danger:hover { border-color: var(--danger); }
button.ghost { color: var(--text); }
button.ghost:hover { background: var(--raise); }
button.ghost:disabled { opacity: 0.45; cursor: default; }
button.ghost:disabled:hover { border-color: var(--border); color: var(--text); }
button.danger:active, button.ghost:active { transform: scale(0.97); }

.icon-btn {
  flex: none;
  border: 1px solid transparent;
  background: none;
  color: var(--icon);
  cursor: pointer;
  border-radius: 8px;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s var(--ease), border-color 0.12s var(--ease), color 0.12s var(--ease);
}
.icon-btn:hover { background: var(--panel-2); color: var(--text); border-color: var(--border); }
.icon-btn:active { transform: scale(0.92); }

.icon-btn-accent { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.icon-btn-accent .icon { color: var(--accent-text); }
.icon-btn-accent:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--accent-text); }

/* Край ленты — 11 октября. Вбок листаются три области: лента карточек
   «Проектов», дорожки доски и переключатель режимов «Времени» на узкой
   ширине. Полосы вбок у них нет — ни накладной, ни нативной: край, за которым
   есть что листать, растворяется (маска на самой ленте), а на подложке у края
   стоит кнопка-стрелка. Подключает attachScrollEdges в app.js: ставит на ленту
   класс .edge-scroll и атрибут data-edge — «l», «r» или «l r», с какой стороны
   есть что листать (нечего — атрибута нет, маски тоже), а кнопки вписывает в
   .edge-host, обёртку ленты: она держит их на месте, пока страница
   прокручивается. У ленты без обёртки (переключатель) кнопок нет, только
   растворение. Ширина растворения — --edge-size. */
@property --edge-l { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --edge-r { syntax: '<length>'; inherits: false; initial-value: 0px; }
.edge-host { position: relative; }
.edge-scroll { --edge-size: 56px; scrollbar-width: none; }
.edge-scroll::-webkit-scrollbar { display: none; width: 0; height: 0; }
/* Маска читает только прозрачность, цвета в ней нет: black — «виден целиком». */
.edge-scroll[data-edge] {
  mask-image: linear-gradient(to right, transparent, black var(--edge-l), black calc(100% - var(--edge-r)), transparent);
  transition: --edge-l 0.2s var(--ease), --edge-r 0.2s var(--ease);
}
.edge-scroll[data-edge~="l"] { --edge-l: var(--edge-size); }
.edge-scroll[data-edge~="r"] { --edge-r: var(--edge-size); }
.edge-btn {
  position: absolute; top: 50%; z-index: 2;
  width: 36px; height: 36px; margin-top: -18px; padding: 0;
  display: inline-flex; align-items: center; justify-content: center;
  /* Обводки нет (13 октября 2026): от ленты кнопку отбивает тень. */
  border: 0; border-radius: 50%;
  background: color-mix(in srgb, var(--raise) 88%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: var(--shadow-pop);
  color: var(--text-dim); cursor: pointer;
  opacity: 0; visibility: hidden; transform: scale(0.85);
  transition: opacity 0.18s var(--ease), transform 0.18s var(--ease), visibility 0s linear 0.18s, background-color 0.12s var(--ease), color 0.12s var(--ease);
}
.edge-btn[data-side="l"] { left: 12px; }
.edge-btn[data-side="r"] { right: 12px; }
.edge-btn.on { opacity: 1; visibility: visible; transform: scale(1); transition: opacity 0.12s var(--ease), transform 0.12s var(--ease), visibility 0s, background-color 0.12s var(--ease), color 0.12s var(--ease); }
.edge-btn:hover { background: var(--raise); color: var(--text); }
.edge-btn.on:active { transform: scale(0.92); }
.edge-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.edge-btn .icon { width: 16px; height: 16px; color: inherit; vertical-align: 0; }
@media (prefers-reduced-motion: reduce) {
  .edge-scroll[data-edge], .edge-btn, .edge-btn.on { transition: none; }
}

.dp-btn {
  min-width: 116px;
  text-align: left;
  background: var(--panel-2);
  color: var(--text);
  border: 0;
  border-radius: 8px;
  padding: 5px 10px;
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: border-color 0.12s var(--ease), color 0.12s var(--ease);
}
.dp-btn:hover { background: var(--raise); }
.dp-btn.on, .dp-btn.open { box-shadow: inset 0 0 0 1.5px var(--accent); color: var(--text); }
.dp-btn-wide { width: 100%; min-width: 0; }
/* Пустой дедлайн — это действие, а не пустое поле: акцент даёт понять, что
   сюда можно нажать, а не что здесь чего-то не хватает. */
.dp-btn.is-empty { color: var(--text-dim); }
.dp-btn.is-empty:hover { color: var(--text); }
/* Строка версии в редакторе задачи: «Без версии» звучит тише выбранной. */
.dp-btn.unset { color: var(--text-faint); }
/* Кнопка-выпадашка на всю ширину (.dp-btn.dp-select): название слева, стрелка
   вниз справа — по ней видно, что кнопка раскрывается; длинное название
   кончается многоточием, а не растягивает кнопку. Меню под ней — той же
   ширины (openMenu, opts.width). Фильтр документов, период и проекты в окне
   экспорта. */
.dp-select { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; min-width: 0; padding: 7px 10px; font-size: 13px; }
.dp-select-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dp-select .icon { width: 12px; height: 12px; flex: none; color: var(--text-faint); transition: transform 0.12s var(--ease); }
.dp-select:hover .icon { color: var(--text-dim); }
.dp-select.open .icon { transform: rotate(180deg); }

/* Вторичная кнопка: заметнее ссылки, но без акцентной заливки — «Сегодня»
   не должна спорить по весу с зелёными действиями. */

.btn-soft {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 30px;
  padding: 0 12px;
  background: var(--panel-2);
  color: var(--text);
  border: 0;
  border-radius: var(--radius-sm);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.12s var(--ease), background 0.12s var(--ease);
}
.btn-soft .icon { color: inherit; width: 13px; height: 13px; flex: none; }
.btn-soft:hover { background: var(--raise); }
.btn-soft:active { transform: scale(0.97); }
/* Акцентная кнопка — одна на экран: создать проект, задачу, аккаунт. */
.btn-accent {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--accent-text);
  font-family: inherit;
  font-weight: 600;
  font-size: 13px;
  padding: 9px 14px;
  cursor: pointer;
  transition: background 0.13s var(--ease), transform 0.08s var(--ease);
}
.btn-accent .icon { color: var(--accent-text); width: 13px; height: 13px; }
.btn-accent:hover { background: var(--accent-hover); }
.btn-accent:active { transform: scale(0.97); }

/* ---------- Переключатель ---------- */
.switch {
  display: flex;
  align-items: center;
  gap: 8px;
  border: none;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  color: var(--text-dim);
  transition: color 0.12s var(--ease);
}
.switch:hover { color: var(--text); }
.switch[aria-pressed='true'] { color: var(--text); }
.switch-track {
  position: relative;
  width: 30px;
  height: 17px;
  border-radius: 9px;
  /* Выключенная дорожка — ступень темнее разделителя, а не --panel-2: на
     карточке (--panel) та была неотличима (1.1:1), и переключатель
     читался как одиноко висящий кружок. */
  background: var(--border-strong);
  border: 0;
  flex: none;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
}
/* Кружок отступает от дорожки на 2 px со всех сторон — и сверху, и снизу, и
   от торца в обоих положениях. Раньше было 1 px сверху и 3 снизу, и кружок
   казался съехавшим вниз. */
.switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--text-dim);
  transition: transform 0.15s var(--ease), background 0.15s var(--ease);
}
/* Включённый свитчер: дорожка — акцент, кружок — цветом текста на акцентной
   кнопке (--accent-text), то есть тем, что на этом зелёном и так читается.
   Белый кружок на зелёной дорожке давал 1.3:1 в тёмной теме и 1.8:1 в
   светлой — его не было видно. Контраст кружка к дорожке в обоих
   состояниях и обеих темах не ниже 3:1 держит tests/e2e/switch.spec.js. */
.switch[aria-pressed='true'] .switch-track { background: var(--accent); border-color: var(--accent); }
.switch[aria-pressed='true'] .switch-thumb { transform: translateX(13px); background: var(--accent-text); }

/* ---------- Сегментный переключатель ----------
   Один вид на все места: режимы календаря и расписания, вкладки задачи,
   сетка повторения, выбор темы. Компактный (.segmented-sm) — где места мало: фильтр
   статусов в узкой боковой панели проекта. До 6 октября это были семь своих копий с
   разными отступами, шрифтом и скруглением. */
.segmented { display: flex; gap: 2px; padding: 2px; background: var(--panel-2); border-radius: var(--radius-sm); }
.segmented > button, .segmented-row > button { border: none; background: none; color: var(--text-dim); font-family: inherit; font-size: 12.5px; font-weight: 500; padding: 5px 11px; border-radius: 8px; white-space: nowrap; cursor: pointer; transition: background 0.12s var(--ease), color 0.12s var(--ease); }
.segmented > button:hover, .segmented-row > button:hover { color: var(--text); }
.segmented > button.on, .segmented-row > button.on { background: var(--tab-active-bg); color: var(--text); }
/* Значок перед подписью — с воздухом. Без отступа «Список», «Доска» и
   «Версии» стояли вплотную к своим значкам. Кнопка из одного значка (выбор
   темы) отступа не получает. */
.segmented > button > .icon:not(:last-child), .segmented-row > button > .icon:not(:last-child) { margin-right: 6px; }
/* Несколько рядов на одной подложке. Пресеты экспорта, ради которых они
   заводились, с 11 октября выпадашка; правила остались, пока их не снесёт
   пересборка редактора: селекторы .segmented* входят в его хэш. */
.segmented-rows { flex-direction: column; }
.segmented-row { display: flex; gap: 3px; }
.segmented-sm { gap: 2px; padding: 2px; border-radius: 7px; }
.segmented-sm > button { font-size: 12px; padding: 4px 6px; border-radius: 5px; }
/* Подложка, которая переезжает. Переключатель с ней (.seg-glide — ставит
   attachSegGlide в app.js) не красит выбранную кнопку сам: под ней едет
   один общий .seg-pill — положение и ширину выбранной кнопки ему задаёт
   код, вид — здесь. Новая выбранная — подложка переезжает пружиной;
   первая отрисовка, смена языка или ширины — встаёт на место без
   анимации (.still). Селекторы начинаются не с .segmented нарочно: те
   уезжают в сборку редактора телефона (scripts/build-editor.js), а
   подложку телефон не рисует. */
.seg-glide { position: relative; }
.seg-glide > button { position: relative; }
.seg-glide > button.on { background: none; }
.seg-pill {
  position: absolute; left: 0; top: 0; width: 0; height: 0;
  border-radius: 8px; background: var(--tab-active-bg); pointer-events: none;
  transition: transform 0.42s var(--spring-soft), width 0.42s var(--spring-soft), height 0.42s var(--spring-soft);
}
.seg-glide.segmented-sm > .seg-pill { border-radius: 5px; }
.seg-pill.still { transition: none; }
.seg-pill.none { visibility: hidden; }
@media (prefers-reduced-motion: reduce) {
  .seg-pill { transition: none; }
}

/* ---------- Шапка периода ----------
   Календарь и статистика листают время одной шапкой: слева «Сегодня»,
   стрелки и название периода, справа, через .spacer, — режимы. До 6 октября
   у статистики было наоборот: режимы слева, «Сегодня» справа. Шапка
   переносится целиком, когда ей тесно, а не по одной кнопке. */
.period-head { flex: none; display: flex; align-items: center; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; row-gap: 6px; }
.period-nav { display: flex; gap: 2px; }
.period-title { font-family: var(--font-display); font-size: 16px; font-weight: var(--fw-display); white-space: nowrap; }
/* Режимы держатся у правого края и тогда, когда шапка перенеслась. */

/* ---------- Поле ввода ----------
   Один вид: заливка, рамка, скругление 8 (как у текстовых кнопок), акцентная
   рамка в фокусе. Обычный
   размер — поля модалок; компактный — поле в строке: ставка, число в
   настройках и в повторении. Новое поле берёт класс .field или .field-sm.
   В редакторе поля те же: адрес ссылки, подпись, поиск. */
.field, .field-sm, #modal-input, #modal-input2, .modal-lg input[type='text'], .modal-lg textarea, #sdlg-backdrop input, #auth-backdrop input, .settings-row-input input, .rpdlg input.rp-num[type='text'] {
  background: var(--panel-2); color: var(--text); border: 0; border-radius: var(--radius-sm);
  font-family: inherit; outline: none; transition: box-shadow 0.12s var(--ease);
}
.field, #modal-input, #modal-input2, .modal-lg input[type='text'], .modal-lg textarea, #sdlg-backdrop input, #auth-backdrop input { padding: 8px 10px; font-size: 14px; }
.field-sm, .settings-row-input input, .rpdlg input.rp-num[type='text'] { padding: 5px 8px; font-size: 13px; }
.field:focus, .field-sm:focus, #modal-input:focus, #modal-input2:focus, .modal-lg input:focus, .modal-lg textarea:focus, #sdlg-backdrop input:focus, #auth-backdrop input:focus, .settings-row-input input:focus, .rpdlg input.rp-num[type='text']:focus { box-shadow: inset 0 0 0 1.5px var(--accent); }

/* ---------- Меню / модалки ---------- */

.ctx-menu {
  position: fixed;
  /* Самый верхний слой: выше модалок (100), всплывающих календарей (120) и
     окон-пикеров (130). Меню вызывается изнутри них — из диалога статусов, из
     окна новой записи на календаре, — и на одном слое с пикером оно уходило
     под него: пикер добавляется в body позже и потому рисуется поверх. */
  z-index: 140;
  min-width: 190px;
  background: var(--panel);
  border: 0;
  border-radius: 9px;
  box-shadow: var(--shadow-pop);
  padding: 5px;
  /* Длинный список не вылезает за экран, а прокручивается внутри. */
  max-height: calc(100vh - 16px);
  overflow-y: auto;
  animation: popIn 0.12s var(--ease);
}
/* Короткий выбор из чисел (часы и минуты): узко и на восемь строк, дальше
   прокрутка, выбранное — в поле зрения. */
.ctx-menu.compact { min-width: 76px; max-height: 268px; }
.ctx-item {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  width: 100%; text-align: left; border: none; background: none;
  color: var(--text-dim); font-family: inherit; font-size: 13px; padding: 7px 9px;
  border-radius: 6px; cursor: pointer; transition: color 0.1s var(--ease);
}
/* Подложки у пунктов нет нигде: наведение и стрелки (.led-cur — курсор в меню
   редактора) видны только цветом. Клавиатурному фокусу одного цвета мало —
   у соседних пунктов разница в оттенок, — поэтому к цвету добавляется контур
   (без заливки), как у остальных элементов с :focus-visible. Токен
   --accent-ink, а не --accent: на белой панели светлой темы неон не виден. */
.ctx-item:hover, .ctx-item:focus-visible, .ctx-item.led-cur { color: var(--text); }
.ctx-item:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
/* background: none — общая button.danger красит кнопку подложкой, пункту меню она не нужна. */
.ctx-item.danger { color: var(--danger-dim); background: none; border: none; padding: 7px 9px; }
.ctx-item.danger:hover, .ctx-item.danger:focus-visible, .ctx-item.danger.led-cur { color: var(--danger); }
.ctx-item.sel { color: var(--accent-ink); font-weight: 500; }
.ctx-item .ctx-check { color: var(--accent-ink); flex: none; }
/* Значок пункта (openMenu, it.icon) — справа, на месте галочки: подписи
   остаются в один столбец у пунктов со значком и без. Цвет тот же, что у
   подписи: тусклый в покое, яркий под указателем. Через #ctx-menu, а не
   .ctx-item: правила на .ctx-* уезжают в стили редактора телефона, и этому
   значку там делать нечего. */
#ctx-menu .ctx-icon { flex: none; width: 14px; height: 14px; }
.ctx-main { display: flex; align-items: center; gap: 8px; min-width: 0; }
/* Меню шириной с кнопку (openMenu, opts.width): ширину задаёт кнопка, а не
   самое длинное название, и название, что не поместилось, кончается
   многоточием. Цветная точка проекта и галочка выбранного остаются на месте.
   Селектор через #ctx-menu, а не .ctx-menu: правила на .ctx-* попадают в стили
   редактора телефона (scripts/build-editor.js), а этому меню там делать нечего. */
#ctx-menu.fit { min-width: 0; }
#ctx-menu.fit .ctx-item { min-width: 0; }
#ctx-menu.fit .ctx-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ctx-dot { flex: none; width: 9px; height: 9px; border-radius: 3px; background: var(--sc, var(--accent)); }
.ctx-sep { height: 1px; background: var(--border); margin: 4px 6px; }

/* Слои поверх шапки (#titlebar — drag, см. слой «Каркас»). Зона перетаскивания
   не «закрывается» тем, что нарисовано поверх неё: Chromium собирает её из разметки, а не из того, что видно, и
   под наложенным элементом она остаётся зоной окна. В Electron на Windows она
   забирает и настоящие щелчки мыши — кнопка под ней не нажимается, хотя
   программный .click() проходит. Поэтому всё, что может лечь на верхние 52 px,
   объявляется no-drag: полноэкранный редактор целиком (панель, меню и окна
   внутри него), меню и всплывающие панели (они прижимаются к краю окна, когда
   места мало) и коробки диалогов. Подложка диалога — не в списке: за её
   пределами окно как перетаскивалось, так и перетаскивается. Порядок в
   разметке важен: no-drag вычитает из drag только то, что идёт в документе
   позже шапки, а все эти слои — после неё. Сторожит tests/unit/ui-rules.test.js,
   вычисленное значение в настоящем окне — scripts/smoke.js. */
.led.led-fullscreen,
.ctx-menu, #notif-panel, .tag-pop, .tp-pop, .dp-pop, .color-pop,
.modal {
  -webkit-app-region: no-drag;
}

#modal-backdrop, #pdlg-backdrop, #sdlg-backdrop, #confirm-backdrop, #auth-backdrop, #tmdlg-backdrop, #expdlg-backdrop, #tagdlg-backdrop, #rpdlg-backdrop, #sldlg-backdrop, #rmdlg-backdrop, #ledmodal-backdrop, .led-sheet-backdrop {
  position: fixed; inset: 0; background: var(--scrim);
  display: flex; align-items: center; justify-content: center; z-index: 100;
  animation: backdropIn 0.13s var(--ease);
}
/* Подтверждение всегда поверх того окна, которое его вызвало: удаление тега
   спрашивают из окна тега, и вопрос, спрятавшийся под ним, выглядел бы как
   зависшее приложение. */
#confirm-backdrop { z-index: 110; }
/* Окно времени работы зовут из окна задачи (оно на 100), а окно повторения —
   уже из окна времени работы: каждое следующее поверх предыдущего. */
#sldlg-backdrop { z-index: 101; }
/* Окно напоминания зовут из свойств задачи (в том числе из её окна с
   календаря) — на слое окна времени работы. */
#rmdlg-backdrop { z-index: 101; }
#rpdlg-backdrop { z-index: 102; }
/* Окно ввода (одно поле) зовут и из свойств задачи — ставку, — в том числе
   из окна задачи с календаря: оно встаёт поверх любого из них. */
#modal-backdrop { z-index: 103; }
/* Окно тега зовут из окна проекта (раздел «Теги», пикер при создании), и на
   одном слое с ним оно оказывалось снизу: окно проекта стоит в разметке
   позже. Ниже подтверждения — удаление тега спрашивают из этого окна. */
#tagdlg-backdrop { z-index: 105; }
/* Окно редактора (график, сочетания клавиш) открывается и из полноэкранного
   редактора — он стоит на 145, окно должно быть выше. */
#ledmodal-backdrop { z-index: 155; }
.modal {
  background: var(--panel);
  border-radius: var(--radius);
  box-shadow: var(--shadow-modal);
  padding: 18px;
  width: min(360px, 90vw);
  animation: popIn 0.16s var(--ease);
}
.modal-lg { width: min(440px, 92vw); }
.modal-title { font-size: 15px; font-weight: 500; margin-bottom: 12px; }
#modal-label, #modal-label2 { display: block; font-size: 13px; font-weight: 500; margin-bottom: 8px; }
.confirm-text { margin: 0; font-size: 13px; color: var(--text-dim); line-height: 1.5; }
.modal label, .modal-lg label, #sdlg-backdrop label {
  display: block; font-size: 12px; color: var(--text-dim); margin: 10px 0 5px;
}
#modal-input, #modal-input2, .modal-lg input[type='text'], .modal-lg textarea, #sdlg-backdrop input, #auth-backdrop input { width: 100%; resize: vertical; }

.auth-sub { margin: -4px 0 4px; font-size: 12px; line-height: 1.4; }
.auth-google-btn {
  width: 100%; display: flex; align-items: center; justify-content: center; gap: 10px;
  border: 0; background: var(--panel-2); color: var(--text);
  border-radius: 8px; padding: 9px 12px; font-size: 13px; font-family: inherit; font-weight: var(--fw-text);
  cursor: pointer; margin-top: 6px;
  transition: border-color 0.12s var(--ease), background 0.12s var(--ease);
}
.auth-google-btn:hover { border-color: var(--border-strong); background: var(--panel); }
.auth-google-btn:active { transform: scale(0.98); }
.auth-google-btn:disabled { opacity: 0.6; cursor: default; }
.auth-divider {
  display: flex; align-items: center; gap: 10px; margin: 12px 0; font-size: 12px;
  color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em;
}
.auth-divider::before, .auth-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.auth-error { margin: 8px 0 0; font-size: 12px; color: var(--danger); }
/* Строка-переключатель «Нет аккаунта? Создать аккаунт» под кнопками окна входа. */
.auth-switch { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 14px; font-size: 12px; }
.auth-switch .linklike { color: var(--accent-ink); }
.auth-switch .linklike:hover { color: var(--text); }
.auth-usecases { display: flex; flex-wrap: wrap; gap: 6px; }
.auth-usecase {
  border: 0; background: var(--panel-2); color: var(--text-dim);
  border-radius: 7px; padding: 7px 11px; font-size: 12.5px; font-family: inherit; cursor: pointer;
  transition: border-color 0.12s var(--ease), color 0.12s var(--ease), background 0.12s var(--ease);
}
.auth-usecase:hover { border-color: var(--border-strong); color: var(--text); }
.auth-usecase.on { background: color-mix(in srgb, var(--accent) 15%, transparent); border-color: var(--accent); color: var(--accent-ink); }
/* Согласие с Условиями и Политикой: общий переключатель .switch и подпись со
   ссылками рядом. Подпись — не внутри кнопки: ссылка внутри кнопки — это
   кнопка в кнопке. Пока переключатель выключен, «Продолжить» неактивна. */
.auth-consent { display: flex; align-items: flex-start; gap: 10px; margin-top: 16px; }
.auth-consent .switch { padding: 1px 0 0; }
#auth-consent-text { font-size: 12.5px; line-height: 1.45; color: var(--text-dim); }
#auth-consent-text a { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 2px; }
.modal-buttons .auth-decline { margin-right: auto; }
.modal-buttons { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
.modal-buttons button { border: 0; background: var(--panel-2); color: var(--text); border-radius: var(--radius-sm); padding: 8px 12px; font-size: 13px; cursor: pointer; transition: border-color 0.12s var(--ease), background 0.12s var(--ease); }
.modal-buttons button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); font-weight: 500; }
.modal-buttons button:hover { background: var(--raise); }
.modal-buttons button.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.modal-buttons button:active { transform: scale(0.97); }
.modal-buttons button.confirm-danger { background: var(--danger); border-color: var(--danger); color: var(--text-on-color); }
.modal-buttons button.confirm-danger:hover { filter: brightness(1.08); background: var(--danger); border-color: var(--danger); }

.swatches { display: flex; flex-wrap: wrap; gap: 8px; }
/* Палитра проекта — ровно 16 цветов, фиксируем 8 в ряд, чтобы вышло два
   равных ряда, а не 12+4 по ширине диалога. Палитры редактора текста
   (.led-colors) — своей сеткой: у них другое число образцов. */
#pdlg-swatches { display: grid; grid-template-columns: repeat(8, 26px); justify-content: start; }
.swatch {
  width: 26px; height: 26px; border-radius: 7px; border: 2px solid transparent;
  cursor: pointer; padding: 0; background-clip: padding-box;
  transition: transform 0.1s var(--ease);
}
.swatch:hover { transform: scale(1.1); }
.swatch.sel { border-color: var(--text); }

/* Ряд из двух подписанных кнопок: начало и конец записи; он же — «с» и «по»
   своего периода в окне экспорта. */
.sdlg-times { display: flex; gap: 10px; }
.sdlg-times > div { flex: 1; }
.sdlg-times .dp-btn { width: 100%; min-width: 0; }
.sdlg-dur { margin-top: 10px; font-size: 12px; font-variant-numeric: tabular-nums; }

.modal-error { margin-top: 8px; color: var(--danger); font-size: 12.5px; }
.modal input + label { margin-top: 12px; }

/* ---------- Остров ----------
   Предмет на земле: подложка и скругление общие, содержимое — своё у
   экрана. Шапка острова (.island-head), список строк с разделителями
   (.row-list), заголовок страницы (.page-head) и квадратная кнопка
   таймера (.sq-btn) стоят на двух экранах и больше, потому живут здесь. */
.island, .settings-card {
  background: var(--panel);
  border-radius: var(--radius);
  overflow: hidden;
}
.island-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 22px; }
.island-title { font-weight: 600; font-size: 14px; }
.island-note { font-size: 12px; color: var(--text-faint); }
/* ---------- Группа строк-настроек ----------
   13 октября: как на телефоне (SettingRow и RowGroup в Island.js). Всё, у
   чего свои параметры, — строкой «название · значение ›» на острове-группе;
   значение словами, нажатие открывает окно этой настройки. Подпись группы —
   над островом (.sgroup-label), тихо и обычными буквами. Остров — вторая
   ступень (--panel-2): группы стоят на острове панели. Стоят в правой панели
   задачи и в окне «Время работы». Экран подстраивает их своим классом. */
.sgroup-label { margin: 14px 2px 6px; font-size: 12px; color: var(--text-faint); }
.sgroup { display: flex; flex-direction: column; background: var(--panel-2); border-radius: var(--radius); overflow: hidden; }
.sgroup[hidden], .sgroup-label[hidden] { display: none; }
.srow {
  display: flex; align-items: center; gap: 10px; width: 100%; min-width: 0; min-height: 40px;
  padding: 7px 12px; margin: 0; border: 0; border-top: 1px solid var(--line); border-radius: 0;
  background: none; color: var(--text); font-family: inherit; font-size: 13px; text-align: left;
  cursor: pointer; transition: background 0.1s var(--ease);
}
.srow:first-child { border-top: 0; }
.srow[hidden] { display: none; }
.srow:hover { background: var(--raise); }
.srow:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
.srow > .icon { width: 15px; height: 15px; flex: none; color: var(--icon); }
.srow-label { flex: none; max-width: 60%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Значение и подстрока под ним — справа, в одну колонку; длинное кончается
   многоточием, а не растягивает строку. */
.srow-box { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: flex-end; text-align: right; }
.srow-value { max-width: 100%; color: var(--text-dim); font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.srow-sub { max-width: 100%; color: var(--text-faint); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
.srow-sub[hidden] { display: none; }
.srow-chev { flex: none; width: 12px; height: 12px; color: var(--text-faint); }
.srow:hover .srow-chev { color: var(--text-dim); }
/* Строка-действие («Добавить напоминание»): тихая, без значения и шеврона. */
.srow.srow-add { color: var(--text-dim); }
.srow.srow-add:hover { color: var(--text); }
.srow.srow-add .srow-label { flex: 1; max-width: none; }
/* Настройка, которая сейчас ни на что не действует (напоминание «до начала»
   без времени работы): строка тише. */
.srow.dim .srow-label { color: var(--text-faint); }
/* ---------- Пустой экран ----------
   Когда показать нечего: по центру сценка, заголовок, одна строка пояснения
   и, если действие очевидно, одна акцентная кнопка («Проекты», «Документы»,
   «Время»). Сценка — инлайн-SVG из core/illustrations.js (.es-art), формы
   красятся здесь из токенов --art-* и --accent, поэтому верны обеим темам и
   любой подложке. Экран добавляет своё место, но не вид.
   Компактный (.empty-state-sm) — для панелей, списков и выпадашек: сценка
   56 × 40, заголовок обычным шрифтом, текст мельче, кнопка — тихая, а
   акцентная только там, где другой на экране нет («Сегодня» без проектов).
   В строку (.empty-state-row) — компактный для выпадашек и списков в окне,
   где строка создания стоит сразу под ним: сценка слева, слова справа. */
.empty-state { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 24px; text-align: center; max-width: 420px; margin: 0 auto; line-height: 1.55; }
.empty-state-title { margin: 6px 0 0; font-family: var(--font-display); font-weight: var(--fw-display); font-size: 20px; line-height: 1.3; text-wrap: balance; }
.empty-state-text { margin: 0 0 6px; color: var(--text-dim); font-size: 13.5px; text-wrap: pretty; }
.empty-state-sm { flex: none; gap: 6px; padding: 20px 14px; max-width: 300px; line-height: 1.45; }
.empty-state-sm .es-art { width: 56px; height: 40px; margin-bottom: 4px; }
.empty-state-sm .empty-state-title { margin: 0; font-family: var(--font-ui); font-weight: 600; font-size: 13.5px; line-height: 1.35; }
.empty-state-sm .empty-state-text { margin: 0; font-size: 12.5px; }
.empty-state-sm .btn-soft, .empty-state-sm .btn-accent { margin-top: 6px; }
.empty-state-row { flex-direction: row; justify-content: flex-start; gap: 12px; max-width: none; margin: 0; padding: 10px 12px; text-align: left; }
.empty-state-row .es-art { margin-bottom: 0; }
.empty-state-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* Сценка: появляется вместе с экраном, акцент — на миг позже. */
.es-art { display: block; flex: none; width: 120px; height: 88px; overflow: visible; animation: popIn 0.32s var(--ease) both; }
.es-plate { fill: var(--art-plate); }
.es-sheet { fill: var(--art-sheet); }
.es-sheet.es-back { opacity: 0.6; }
.es-ink { fill: var(--art-ink); }
.es-ink-soft { fill: var(--art-ink); opacity: 0.55; }
.es-dash { fill: none; stroke: var(--art-ink); stroke-width: 1.5; stroke-dasharray: 3 3; }
.es-mark { fill: var(--accent); transform-box: fill-box; transform-origin: center; animation: esMark 0.4s 0.16s var(--ease) both; }
.es-mark.es-caret { animation: esMark 0.4s 0.16s var(--ease) both, esCaret 1.1s 0.6s steps(1) infinite; }
.es-on-mark { fill: var(--accent-text); transform-box: fill-box; transform-origin: center; animation: esMark 0.4s 0.16s var(--ease) both; }
@keyframes esMark { from { opacity: 0; transform: scale(0.4); } to { opacity: 1; transform: none; } }
@keyframes esCaret { 50% { opacity: 0; } }
/* Без движения курсор просто стоит: общее правило «Основы» сжимает
   длительность, а бесконечное мигание от этого стало бы мельканием. */
@media (prefers-reduced-motion: reduce) {
  .es-mark.es-caret { animation: none; }
}
/* Заголовок страницы не уезжает при прокрутке: страница («Проекты»,
   «Настройки») прокручивается целиком, а строка с названием и кнопками
   остаётся сверху — липкая, на земле (--bg), чтобы содержимое уходило под
   неё, а не просвечивало. Полоса ::after — зазор под строкой того же цвета:
   без неё острова упирались бы в низ заголовка вплотную. Там, где страница
   сама не прокручивается, sticky ничего не меняет. */
.page-head { display: flex; align-items: center; gap: 10px; padding: 4px 4px 0; flex: none; position: sticky; top: 0; z-index: 3; background: var(--bg); }
.page-head::after { content: ''; position: absolute; left: 0; right: 0; top: 100%; height: var(--gap); background: var(--bg); pointer-events: none; }
.page-title { margin: 0; font-size: 20px; font-weight: var(--fw-display); font-family: var(--font-display); }
.page-title .h-count { font-family: var(--font-ui); }
.row-list { list-style: none; margin: 4px 0 0; padding: 0; }
.row-list li { display: flex; gap: 10px; align-items: center; padding: 9px 0; border-top: 1px solid var(--line); cursor: pointer; }
.row-list li:first-child { border-top: 0; }
.rl-main { flex: 1; min-width: 0; }
.rl-name { display: block; font-weight: 500; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rl-sub { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-faint); white-space: nowrap; overflow: hidden; }
.rl-dot { width: 7px; height: 7px; border-radius: 2px; flex: none; background: var(--pc, var(--accent)); }
.rl-when { font-size: 12.5px; color: var(--text-dim); white-space: nowrap; }
.rl-when.overdue { color: var(--danger); }
/* ---------- Кнопка запуска ----------
   Плей/стоп в строках задач (.rl-play: «Сегодня», карточки и «Недавние
   задачи» на «Проектах») и квадрат таймера (.sq-btn: «Сейчас идёт», страница
   задачи). Форма везде одна — скруглённый квадрат --radius-xs, размеры у
   мест свои. Идёт — заливка акцентом. .icon-btn.rl-play — потому что узкий
   веб (web/responsive.css) переписывает скругление .icon-btn. */
.rl-play, .icon-btn.rl-play { flex: none; border-radius: var(--radius-xs); }
.rl-play.run { background: var(--accent); color: var(--accent-text); }
.rl-play.run .icon { color: inherit; }
.rl-play.run:hover { background: var(--accent-hover); }
/* Квадрат таймера: плей, когда стоит; стоп на акценте, когда идёт. С 13
   октября 2026 скругление крупнее — --radius, как у острова вокруг: кнопки
   записи (квадрат, «Запись», «Открыть») скруглены одинаково. Маленькая
   .rl-play в строках остаётся --radius-xs. */
.sq-btn { width: 44px; height: 44px; border-radius: var(--radius); border: 0; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; flex: none; background: var(--panel-2); color: var(--text); transition: background 0.12s var(--ease); }
.sq-btn:hover { background: var(--raise); }
.sq-btn.run { background: var(--accent); color: var(--accent-text); }
.sq-btn.run:hover { background: var(--accent-hover); }
.sq-btn .icon { width: 16px; height: 16px; color: inherit; }

/* Налив и слив. Запустили — кнопка «наливается»: снизу волной поднимается
   акцент, форма вздрагивает желе, значок «стоп» выпрыгивает; остановили —
   акцент стекает вниз. Класс на время анимации ставит и снимает liqMark в
   app.js (одна функция на все места); --liq-t — сколько анимации уже прошло,
   если строку перерисовали посреди неё. ::before — прежняя подложка (под
   ней уже акцент кнопки, которая идёт), ::after — сама жидкость. */
.liq-fill, .liq-drain { position: relative; overflow: hidden; isolation: isolate; }
/* liqRing: под прозрачной рамкой .icon-btn акцент кнопки проглядывал бы
   кольцом, пока жидкость не поднялась, — рамка до тех пор цвета подложки. */
.liq-fill { animation: liqJelly 0.62s var(--ease) var(--liq-t, 0s) both, liqRing 0.52s linear var(--liq-t, 0s) both; }
.liq-drain { animation: liqSag 0.52s var(--ease) var(--liq-t, 0s) both; }
.liq-fill::before, .liq-fill::after, .liq-drain::after {
  content: ''; position: absolute; z-index: -1; pointer-events: none;
}
.liq-fill::before { inset: 0; background: var(--panel-2); }
.liq-fill::after, .liq-drain::after {
  left: 50%; top: 100%; width: 240%; aspect-ratio: 1; border-radius: 40%;
  background: var(--accent);
}
.liq-fill::after { animation: liqRise 0.52s var(--ease) var(--liq-t, 0s) both; }
.liq-drain::after { animation: liqFall 0.46s cubic-bezier(0.45, 0, 0.55, 1) var(--liq-t, 0s) both; }
.liq-fill .icon { animation: liqPop 0.42s var(--spring) calc(var(--liq-t, 0s) + 0.18s) both; }
.liq-drain .icon { animation: liqPop 0.4s var(--spring) calc(var(--liq-t, 0s) + 0.22s) both; }
@media (prefers-reduced-motion: reduce) {
  .liq-fill, .liq-drain, .liq-fill .icon, .liq-drain .icon { animation: none; }
  .liq-fill::before, .liq-fill::after, .liq-drain::after { display: none; }
}

/* ---------- Галочка задачи ----------
   Списки задач и карточки проектов. Тот же скруглённый квадрат, что у
   кнопки запуска рядом: пустая — обводка, выполнено — заливка акцентом и
   галочка цветом надписи на акценте. Переход — заливкой и выпрыгивающей
   галочкой, без рывка. Галочка — ::before с clip-path: у нативной
   отметки нет ни нашего скругления, ни наших цветов. */
.task-done {
  appearance: none; display: inline-grid; place-content: center; flex: none;
  width: 16px; height: 16px; margin: 0; border: 0; border-radius: var(--radius-xs);
  background: transparent; box-shadow: inset 0 0 0 1.5px var(--border-strong); cursor: pointer;
  transition: background 0.16s var(--ease), box-shadow 0.16s var(--ease);
}
.task-done::before {
  content: ''; width: 10px; height: 10px; background: var(--accent-text);
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
  transform: scale(0); transition: transform 0.36s var(--spring);
}
.task-done:hover { box-shadow: inset 0 0 0 1.5px var(--text-dim); }
.task-done:checked { background: var(--accent); box-shadow: inset 0 0 0 1.5px var(--accent); }
.task-done:checked::before { transform: none; }
.task-done:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
/* В режиме высокой контрастности тени и заливки снимает система — галочке
   нечем было бы рисоваться. Там она снова нативная. */
@media (forced-colors: active) {
  .task-done { appearance: auto; box-shadow: none; }
  .task-done::before { display: none; }
}

/* ---------- Toast ---------- */

#toast {
  position: fixed;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  background: var(--panel-2);
  color: var(--text);
  border: 0;
  padding: 9px 16px;
  border-radius: 8px;
  font-size: 13px;
  z-index: 110;
  animation: toastIn 0.2s var(--ease);
}

/* ---------- Теги ---------- */
/* Чип повторяет метку статуса: тот же рост, та же подложка, тот же вес. Это
   соседние по смыслу пометки, и разный вид у них читался бы как разная
   важность. Цвет тега — только в точке: залитый цветом чип на доске
   перетягивал бы внимание с самой задачи. */
/* Бейдж тега. Цвет тега смешивается с цветом текста темы, а не берётся
   напрямую: на светлой теме ярко-зелёная надпись на белом нечитаема, а такая
   смесь темнеет вместе с темой сама. Подложка — тот же цвет прозрачностью
   16%: тег виден с одного взгляда, но не перетягивает внимание с названия
   задачи, а на карточке доски их может быть и три. */
.tag-chip {
  display: inline-flex; align-items: center; flex: none; max-width: 100%;
  font-size: 12px; font-weight: 600; line-height: 1.5;
  color: color-mix(in srgb, var(--sc) var(--tag-ink), var(--text));
  background: color-mix(in srgb, var(--sc) 16%, transparent);
  border-radius: 5px; padding: 1px 7px; position: relative;
}
.tag-dot { width: 8px; height: 8px; border-radius: 3px; background: var(--sc, var(--accent)); flex: none; display: inline-block; }
.tag-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Значок удаления. Плашка при этом не меняется: поля слева и справа равны
   всегда (padding у .tag-chip), и по наведению она не дёргается. Значок —
   маленький круг поверх правого верхнего угла плашки: в покое его нет (и он
   не ловит щелчки), по наведению и по клавиатурному фокусу он появляется.
   Рамки нет — круг отличается от плашки цветом (--panel-2), как и всё остальное. */
.tag-chip-x {
  position: absolute; top: -6px; right: -6px;
  display: flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; padding: 0; margin: 0; flex: none;
  border: none; border-radius: 50%; cursor: pointer;
  background: var(--panel-2); color: var(--text-dim);
  opacity: 0; pointer-events: none;
  transition: opacity 0.12s var(--ease), color 0.12s var(--ease);
}
.tag-chip-x .icon { width: 9px; height: 9px; }
.tag-chip:hover .tag-chip-x, .tag-chip:focus-within .tag-chip-x { opacity: 1; pointer-events: auto; }
.tag-chip-x:hover { color: var(--text); }
.tag-chips { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; min-width: 0; }

.tag-add-btn {
  flex: none; width: 22px; height: 22px; line-height: 1;
  border: 1px dashed var(--border); border-radius: 999px; background: none;
  color: var(--text-faint); font-size: 14px; cursor: pointer;
  transition: border-color 0.12s var(--ease), color 0.12s var(--ease);
}
.tag-add-btn:hover { border-color: var(--accent); color: var(--text); border-style: solid; }
.tag-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.bc-tags { margin-top: 6px; }
.tagdlg-error { margin: -6px 0 10px; font-size: 12px; color: var(--danger); }
/* Поле названия — общее (.field, как в окне проекта); окно узкое, поле во всю
   его ширину. */
#tagdlg-name { width: 100%; margin-bottom: 12px; }

/* Пикер тегов — поиск и он же вход в создание. */
.tag-pop {
  position: fixed; z-index: 130;
  width: 232px; max-height: 300px; display: flex; flex-direction: column;
  background: var(--panel); border: 0; border-radius: 10px;
  box-shadow: var(--shadow-pop); overflow: hidden;
}
.tag-pop-search {
  border: none; border-bottom: 1px solid var(--line); background: none;
  color: var(--text); font-family: inherit; font-size: 12.5px; padding: 9px 11px; outline: none;
}
.tag-pop-list { overflow-y: auto; padding: 4px; }
.tag-pop-item, .tag-pop-create {
  display: flex; align-items: center; gap: 7px; width: 100%;
  border: none; background: none; border-radius: 6px; cursor: pointer;
  color: var(--text); font-family: inherit; font-size: 12.5px; text-align: left; padding: 6px 8px;
}
.tag-pop-item:hover, .tag-pop-create:hover { background: var(--panel-2); }
.tag-pop-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Выбранный тег помечен галочкой справа, а не заливкой: заливка спорила бы с
   наведением, и было бы непонятно, что выбрано, а что под курсором. */
/* Строка тега — сеткой (13 октября 2026): точка · имя · подпись «общий» ·
   галочка. Подпись и галочка — колонками постоянной ширины у правого края:
   у всех строк они стоят друг под другом, есть они у строки или нет. */
.tag-pop-item { display: grid; grid-template-columns: 8px minmax(0, 1fr) 60px 12px; align-items: center; column-gap: 7px; }
.tag-pop-item::after { content: ''; }
.tag-pop-item.sel::after { content: '✓'; color: var(--accent-ink); font-size: 12px; text-align: center; }
.tag-pop-create { color: var(--text-dim); border-top: 1px solid var(--border-soft); border-radius: 0; margin-top: 4px; padding-top: 9px; }
.tag-pop-create:hover { color: var(--text); }

/* Воздух между полосой вкладок и содержимым вкладки настроек: карточка
   параметров начиналась вплотную под ними. */
#tab-settings { padding-top: 14px; }

/* ---------- Редактор ----------
   Свой редактор на ProseMirror (src/editor/, сборка — src/renderer/editor.js).
   Один и тот же на десктопе, в вебе и в WebView телефона: телефону этот
   раздел уезжает строкой (scripts/build-editor.js), а значения токенов он
   подставляет из своего theme.js. Цвета — только токенами: оттенки
   --led-c-*, заливки маркера --led-hl-*. */

#editor-wrap {
  margin-top: 14px;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-radius: 10px;
}

.led {
  --led-size: 16px;
  /* Масштаб текста (setZoom): 0.8–2, только шрифт страницы. Телефон его не
     шлёт с 13 октября 2026 — щипка там больше нет; остался для десктопа. */
  --led-zoom: 1;
  /* Квадрат галочки чек-листа (24 с 13 октября 2026, было 28) и кнопка
     вокруг него — зона пальца 44. */
  --led-task: 24px;
  --led-task-hit: 44px;
  --led-page: 760px;
  --led-serif: 'Iowan Old Style', 'Palatino Linotype', Georgia, 'PT Serif', serif;
  --led-mono: ui-monospace, 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace;
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
  height: 100%;
  color: var(--text);
  font-family: var(--font-ui);
  container-type: inline-size;
  container-name: led;
}
.led [hidden], .led[hidden] { display: none !important; } /* как в «Основе»: телефону этот раздел уезжает без неё */
.led.led-w-narrow { --led-page: 620px; }
.led.led-w-wide { --led-page: 1000px; }
.led.led-w-full { --led-page: 100%; }
.led.led-fullscreen { position: fixed; inset: 0; z-index: 145; background: var(--bg); height: auto; }
.led.led-fullscreen .led-scroll { background: var(--panel); }
/* Развёрнутый редактор закрывает шапку, а вместе с ней и место, которое она
   оставляла под нативные кнопки окна: на Windows и Linux они справа поверх
   страницы (titleBarOverlay), на маке «светофор» слева. Без отступа кнопка
   «Выйти из полного экрана», стоящая у правого края панели, оказывалась под
   кнопками окна, и нажать её было нельзя. Отступы берутся так же, как у
   #titlebar: env(titlebar-area-*) даёт полосу без кнопок, в браузере её нет,
   и фолбэки обнуляют всё это. Высота панели доводится до полосы кнопок: те
   стоят по центру 52 px, и кнопки панели — по центру с ними. */
.led.led-fullscreen .led-toolbar {
  padding-left: calc(8px + env(titlebar-area-x, 0px));
  padding-right: calc(8px + 100% - env(titlebar-area-x, 0px) - env(titlebar-area-width, 100%));
  padding-block: max(6px, calc((env(titlebar-area-height, 0px) - 30px) / 2));
}
body.platform-mac .led.led-fullscreen .led-toolbar {
  padding-left: var(--traffic-w);
  padding-block: 11px;
}

/* --- панели --- */
.led-toolbar {
  flex: none; display: flex; align-items: center; gap: 2px;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line);
}
/* Панель — одна строка везде (11 октября 2026): не переносится и не
   прокручивается. Что не влезло по ширине, toolbar.js убирает в меню групп
   («Формат», «Вставить», «…»); overflow: hidden — только страховка на долю
   пикселя. Расстояние между кучками кнопок — их собственный отступ и черта
   (.led-group), своего зазора у строки нет: так раскладка считается теми же
   числами, что видны. */
.led-toolbar-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: 0; flex-wrap: nowrap; overflow: hidden; }
/* «Во весь экран» — у правого края всегда, вне строки и её раскладки (круг 4). */
.led-toolbar-end { flex: none; display: flex; align-items: center; padding-left: 4px; border-left: 1px solid var(--line); }
/* Остров таблицы — тем же видом, что панель над выделением: плавает под
   таблицей, пока в ней курсор (положение — из JS, editor placeTableBar). */
.led-tablebar {
  position: absolute; z-index: 6; display: flex; align-items: center; gap: 1px;
  max-width: calc(100% - 16px); padding: 4px; overflow-x: auto;
  border-radius: 11px; background: var(--panel); box-shadow: var(--shadow-pop);
  animation: popIn 0.12s var(--ease);
}
.led-tablebar .led-btn:hover { background: var(--panel-2); }
/* Линия таблицы под указателем и шестерёнка у её конца (tablehandles.js). */
.led-tline { position: absolute; z-index: 5; background: var(--accent); border-radius: 1px; pointer-events: none; }
.led-tgear {
  position: absolute; z-index: 6; width: 22px; height: 22px; display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 50%; background: var(--panel); color: var(--text-dim); box-shadow: var(--shadow-pop); cursor: pointer;
  animation: popIn 0.1s var(--ease);
}
.led-tgear:hover { background: var(--accent); color: var(--accent-text); }
.led-toolbar::-webkit-scrollbar, .led-tablebar::-webkit-scrollbar { height: 0; }
.led-group { display: flex; align-items: center; gap: 1px; flex: none; padding-right: 4px; margin-right: 4px; border-right: 1px solid var(--line); }
.led-group:last-child { border-right: 0; padding-right: 0; margin-right: 0; }
.led-spacer { flex: 1 1 8px; min-width: 8px; }
/* Узкая панель (toolbar.js, шаг «dense»; телефон — сразу): без черт между
   кучками и без зазора перед «…» — на эти пиксели помещается ещё кнопка. */
.led-toolbar.led-dense .led-group { padding-right: 0; margin-right: 1px; border-right: 0; }
.led-toolbar.led-dense .led-group:last-child { margin-right: 0; }
.led-toolbar.led-dense .led-spacer { min-width: 0; }
.led-btn {
  position: relative; flex: none;
  height: 30px; min-width: 30px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  border: 0; border-radius: 7px; background: none; color: var(--icon);
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: background 0.1s var(--ease), color 0.1s var(--ease);
}
.led-btn:hover { background: var(--panel-2); color: var(--text); }
.led-btn.on { background: var(--sel); color: var(--accent-ink); }
.led-btn:disabled { opacity: 0.35; cursor: default; background: none; }
.led-btn.danger { color: var(--danger); }
/* Фокус с клавиатуры — контуром внутрь, как у пунктов меню: строка панели
   обрезает всё, что за её краем. Кнопка с открытым меню — подложкой. */
.led-btn:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
.led-btn[aria-expanded='true'] { background: var(--panel-2); color: var(--text); }
.led-btn[data-count]:not([data-count=''])::after {
  content: attr(data-count); position: absolute; top: 1px; right: 0;
  min-width: 14px; height: 14px; padding: 0 3px; border-radius: 7px;
  background: var(--accent); color: var(--accent-text); font-size: 9.5px; font-weight: 600; line-height: 14px; text-align: center;
}
.led-text-btn { color: var(--text-dim); }
.led-icon { display: block; flex: none; }
/* Ширина постоянная, а не по подписи: «Текст» и «Заголовок 2» иначе разной
   ширины, и строка панели перестраивалась бы от движения курсора. */
.led-block-btn { width: 124px; justify-content: space-between; color: var(--text); }
.led-block-label, .led-turn-label { white-space: nowrap; }
.led-block-btn .led-block-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Кнопка группы (toolbar.js: «Формат», «Вставить», списки): подпись и
   галочка, сжатая (.led-compact) — значок и галочка. */
.led-drop { gap: 2px; padding: 0 4px 0 7px; }
.led-drop.led-compact { gap: 1px; padding: 0 2px 0 5px; }
.led-drop.led-compact .led-drop-chev { width: 10px; height: 10px; }
/* Подпись — цветом текста, как «Текст ▾»; через :where, чтобы наведение и
   «включено» (.led-btn:hover, .on) перекрашивали её как любую кнопку. */
.led-drop:where(:not(.led-compact)) { color: var(--text); }
.led-drop:not(.led-compact) .led-drop-icon, .led-drop.led-compact .led-drop-label { display: none; }
.led-drop-label { white-space: nowrap; }
.led-drop-chev { color: var(--text-faint); }
.led-drop.on .led-drop-chev, .led-drop:hover .led-drop-chev { color: inherit; }
/* Пункт меню, за которым следующее меню (цвет, таблица, группа). */
.led-menu-sub { flex: none; color: var(--text-faint); transform: rotate(-90deg); }
.led-bar-sep { width: 1px; align-self: stretch; margin: 4px 3px; background: var(--line); flex: none; }
.led-mini {
  display: inline-grid; place-items: center; width: 20px; height: 20px; padding: 0;
  border: 0; border-radius: 5px; background: none; color: var(--text-faint); cursor: pointer;
}
.led-mini:hover { background: var(--panel-2); color: var(--text); }
.led-kbd { color: var(--text-faint); font-size: 12px; white-space: nowrap; }
.led-menu-head { padding: 6px 9px 3px; font-size: 12px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; }
.led-menu-label { white-space: nowrap; }
.led-hint { font-size: 12px; color: var(--text-faint); line-height: 1.5; }

/* --- поле текста --- */
.led-body { flex: 1; min-height: 0; display: flex; }
.led-viewport { position: relative; flex: 1; min-width: 0; display: flex; }
.led-scroll { flex: 1; min-width: 0; overflow: auto; }
.led-page-wrap { position: relative; max-width: var(--led-page); margin: 0 auto; padding: 26px 56px 160px; box-sizing: border-box; }
.led-page { position: relative; }
.led-pm {
  position: relative; outline: none; min-height: 160px;
  font-size: calc(var(--led-size) * var(--led-zoom)); line-height: 1.65; font-weight: var(--fw-text);
  white-space: pre-wrap; white-space: break-spaces; word-wrap: break-word; overflow-wrap: anywhere;
  font-variant-ligatures: none; font-feature-settings: "liga" 0;
  caret-color: var(--accent-ink);
  -webkit-font-smoothing: antialiased;
}
.led-f-serif .led-pm { font-family: var(--led-serif); }
.led-f-mono .led-pm { font-family: var(--led-mono); font-size: calc(var(--led-size) * 0.92 * var(--led-zoom)); }
/* Размер и гарнитура выделенного текста (метки fontSize, fontFamily —
   schema.js): ступени от размера текста, гарнитуры — те же, что в «Виде». */
.led-ff-sans { font-family: var(--font-ui); }
.led-ff-serif { font-family: var(--led-serif); }
.led-ff-mono { font-family: var(--led-mono); }
.led-fs-xs { font-size: 0.75em; }
.led-fs-s { font-size: 0.875em; }
.led-fs-l { font-size: 1.25em; }
.led-fs-xl { font-size: 1.5em; }
.led-fs-xxl { font-size: 2em; }
.led-font-menu .led-menu-label { line-height: 1.25; }
.led-pm > * { margin: 0 0 0.55em; }
.led-pm p { margin-top: 0; }
.led-pm h1, .led-pm h2, .led-pm h3, .led-pm h4 { font-family: var(--font-display); line-height: 1.25; margin: 1.1em 0 0.45em; font-weight: 700; }
.led-pm > h1:first-child, .led-pm > h2:first-child, .led-pm > h3:first-child { margin-top: 0.2em; }
.led-pm h1 { font-size: 1.9em; }
.led-pm h2 { font-size: 1.45em; }
.led-pm h3 { font-size: 1.2em; }
.led-pm h4 { font-size: 1.02em; letter-spacing: 0.01em; color: var(--text-dim); }
.led-pm a { color: var(--link); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.led-pm code { background: var(--panel-2); border-radius: 5px; padding: 0.1em 0.35em; font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 0.88em; }
.led-pm ul, .led-pm ol { padding-left: 1.6em; }
.led-pm li { position: relative; margin: 0.1em 0; }
.led-pm li > p { margin: 0; }
.led-pm li > ul, .led-pm li > ol { margin: 0.1em 0; }
.led-pm blockquote { margin-left: 0; padding: 0.1em 0 0.1em 1em; border-left: 3px solid var(--border-strong); color: var(--text-dim); }
.led-pm blockquote > :last-child, .led-pm .led-callout > :last-child { margin-bottom: 0; }
.led-pm hr { border: 0; height: 1px; background: var(--border-strong); margin: 1.4em 0; }
.led-pm hr.sel, .led-pm hr.ProseMirror-selectednode { outline: 2px solid var(--accent); outline-offset: 4px; }
.led-pm sub, .led-pm sup { font-size: 0.72em; }
.led-pm mark { color: inherit; border-radius: 3px; padding: 0 1px; }
.led-pm .led-empty::before, .led-pm:focus .led-empty-line::before {
  content: attr(data-ph); float: left; height: 0; pointer-events: none; color: var(--text-faint);
}
.led-pm .led-empty-line::before { opacity: 0.8; }
/* Рисуют — не пишут: подсказка ввода не нужна. */
.led-annotating .led-pm .led-empty::before, .led-annotating .led-pm .led-empty-line::before,
.led-drawing-active .led-pm .led-empty::before, .led-drawing-active .led-pm .led-empty-line::before { display: none; }
.led-pm ::selection { background: var(--sel); }
.led-readonly .led-toolbar, .led-readonly .led-tablebar, .led-readonly .led-handle { display: none; }
.led-readonly .led-pm { caret-color: transparent; }

/* Цвета текста и маркера — по палитре. */
.led-tc-gray { color: var(--led-c-gray); } .led-tc-red { color: var(--led-c-red); } .led-tc-orange { color: var(--led-c-orange); }
.led-tc-yellow { color: var(--led-c-yellow); } .led-tc-green { color: var(--led-c-green); } .led-tc-teal { color: var(--led-c-teal); }
.led-tc-blue { color: var(--led-c-blue); } .led-tc-purple { color: var(--led-c-purple); } .led-tc-pink { color: var(--led-c-pink); }
.led-hl-gray { background: var(--led-hl-gray); } .led-hl-red { background: var(--led-hl-red); } .led-hl-orange { background: var(--led-hl-orange); }
.led-hl-yellow { background: var(--led-hl-yellow); } .led-hl-green { background: var(--led-hl-green); } .led-hl-teal { background: var(--led-hl-teal); }
.led-hl-blue { background: var(--led-hl-blue); } .led-hl-purple { background: var(--led-hl-purple); } .led-hl-pink { background: var(--led-hl-pink); }

/* Выноска */
.led-pm .led-callout { position: relative; padding: 0.7em 1em 0.7em 2.6em; border-radius: 10px; background: var(--led-hl-blue); }
.led-pm .led-callout::before { content: 'i'; position: absolute; left: 0.95em; top: 0.75em; width: 1.15em; height: 1.15em; border-radius: 50%; display: grid; place-items: center; font-size: 0.8em; font-weight: 700; background: var(--led-c-blue); color: var(--panel); }
.led-pm .led-callout.tone-warn { background: var(--led-hl-orange); }
.led-pm .led-callout.tone-warn::before { content: '!'; background: var(--led-c-orange); }
.led-pm .led-callout.tone-ok { background: var(--led-hl-green); }
.led-pm .led-callout.tone-ok::before { content: '✓'; background: var(--led-c-green); }
.led-pm .led-callout.tone-idea { background: var(--led-hl-purple); }
.led-pm .led-callout.tone-idea::before { content: '★'; background: var(--led-c-purple); }

/* Код */
.led-pm .led-code { position: relative; background: var(--code-bg); color: var(--text); border-radius: 10px; padding: 34px 14px 12px; overflow-x: auto; white-space: pre; font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 0.86em; line-height: 1.55; }
.led-pm .led-code code { background: none; padding: 0; font-size: inherit; white-space: pre; }
.led-code-head { position: absolute; top: 6px; left: 8px; right: 8px; display: flex; justify-content: space-between; user-select: none; }
.led-code-lang, .led-code-copy { border: 0; background: none; color: var(--text-faint); font: 500 12px var(--font-ui); padding: 2px 6px; border-radius: 5px; cursor: pointer; }
.led-code-lang:hover, .led-code-copy:hover { background: var(--panel-2); color: var(--text); }
.led-lang-menu { max-height: 300px; overflow: auto; }

/* Чек-лист */
.led-pm ul.led-tasks { list-style: none; padding-left: 0.2em; }
.led-pm ul.led-tasks ul.led-tasks { padding-left: 1.5em; }
.led-pm .led-task { display: flex; align-items: flex-start; gap: 10px; }
.led-task-text { flex: 1; min-width: 0; }
.led-pm .led-task-text > p { margin: 0; }
/* Галочка: квадрат --led-task (24 px с 13 октября 2026, было 28) по
   центру первой строки, кнопка вокруг — --led-task-hit (44 px), зона
   пальца. Лишнее съедают отрицательные поля (слева --led-task-x, справа
   4 px — к тексту зона почти не заходит; сверху и снизу --led-task-y), так
   что строка не растёт. Квадрат — ::before, галочка — ::after. Отметили
   — квадрат наливается акцентом снизу, как жидкостью (круг растёт от
   нижнего края: background-size), галочка проявляется; у только что
   отмеченного пункта (.led-just-checked, views.js) квадрат пружинит, а
   галочка дорисовывается штрихом — сначала короткая черта, потом длинная. */
.led-task-box {
  --led-task-x: calc(var(--led-task-hit) - var(--led-task) - 4px);
  --led-task-y: calc((var(--led-task-hit) - var(--led-task)) / 2);
  flex: none; position: relative; box-sizing: border-box;
  width: var(--led-task-hit); height: var(--led-task-hit);
  margin: calc((1.65em - var(--led-task-hit)) / 2) -4px calc(0px - var(--led-task-y)) calc(0px - var(--led-task-x));
  padding: 0; border: 0; background: none; font: inherit; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.led-task-box::before {
  content: ''; position: absolute; left: var(--led-task-x); top: var(--led-task-y); box-sizing: border-box;
  width: var(--led-task); height: var(--led-task);
  border: 2px solid var(--border-strong); border-radius: 7px;
  background: radial-gradient(circle at 50% 100%, var(--accent) 0 62%, transparent 63%) 50% 100% / 0% 0% no-repeat;
  transition: background-size 0.38s cubic-bezier(0.3, 1.2, 0.5, 1), border-color 0.18s var(--ease);
}
.led-task-box::after {
  content: ''; position: absolute; box-sizing: border-box;
  left: calc(var(--led-task-x) + var(--led-task) * 0.37); top: calc(var(--led-task-y) + var(--led-task) * 0.19);
  width: calc(var(--led-task) * 0.26); height: calc(var(--led-task) * 0.46);
  border: solid var(--accent-text); border-width: 0 3px 3px 0; transform: rotate(45deg);
  opacity: 0; transition: opacity 0.12s var(--ease);
}
.led-task-box:hover::before { border-color: var(--accent); }
.led-task-box:focus-visible { outline: none; }
.led-task-box:focus-visible::before { box-shadow: 0 0 0 2px var(--panel), 0 0 0 4px var(--accent-ink); }
.led-task[data-checked='true'] > .led-task-box::before { border-color: var(--accent); background-size: 300% 300%; }
.led-task[data-checked='true'] > .led-task-box::after { opacity: 1; }
.led-task.led-just-checked > .led-task-box::before { animation: ledTaskPop 0.42s var(--ease); }
.led-task.led-just-checked > .led-task-box::after { animation: ledTaskTick 0.34s 0.12s var(--ease) both; }
@keyframes ledTaskPop {
  0% { transform: scale(1); }
  30% { transform: scale(0.84); }
  65% { transform: scale(1.08); }
  100% { transform: scale(1); }
}
@keyframes ledTaskTick {
  0% { clip-path: inset(100% 100% 0 0); }
  40% { clip-path: inset(calc(100% - 3px) 0 0 0); }
  100% { clip-path: inset(0 0 0 0); }
}
.led-task > .led-task-text > p:first-child { transition: color 0.2s var(--ease); }
.led-task[data-checked='true'] > .led-task-text > p:first-child { color: var(--text-faint); text-decoration: line-through; text-decoration-color: var(--border-strong); }
@media (prefers-reduced-motion: reduce) {
  .led-task-box::before, .led-task-box::after, .led-task > .led-task-text > p:first-child { transition: none; }
  .led-task.led-just-checked > .led-task-box::before, .led-task.led-just-checked > .led-task-box::after { animation: none; }
}

/* Таблицы (prosemirror-tables) */
/* Сверху места больше: туда встаёт шестерёнка столбца (tablehandles.js). */
.led-pm .tableWrapper { overflow-x: auto; margin: 1.5em 0 0.9em; }
.led-pm table { border-collapse: collapse; table-layout: fixed; width: 100%; margin: 0; overflow: hidden; }
.led-pm td, .led-pm th { position: relative; vertical-align: top; box-sizing: border-box; min-width: 48px; padding: 6px 9px; border: 1px solid var(--border-strong); }
.led-pm th { background: var(--panel-2); font-weight: 600; text-align: left; }
.led-pm td > p, .led-pm th > p { margin: 0; }
.led-pm td[data-bg='gray'], .led-pm th[data-bg='gray'] { background: var(--led-hl-gray); }
.led-pm td[data-bg='red'], .led-pm th[data-bg='red'] { background: var(--led-hl-red); }
.led-pm td[data-bg='orange'], .led-pm th[data-bg='orange'] { background: var(--led-hl-orange); }
.led-pm td[data-bg='yellow'], .led-pm th[data-bg='yellow'] { background: var(--led-hl-yellow); }
.led-pm td[data-bg='green'], .led-pm th[data-bg='green'] { background: var(--led-hl-green); }
.led-pm td[data-bg='teal'], .led-pm th[data-bg='teal'] { background: var(--led-hl-teal); }
.led-pm td[data-bg='blue'], .led-pm th[data-bg='blue'] { background: var(--led-hl-blue); }
.led-pm td[data-bg='purple'], .led-pm th[data-bg='purple'] { background: var(--led-hl-purple); }
.led-pm td[data-bg='pink'], .led-pm th[data-bg='pink'] { background: var(--led-hl-pink); }
.led-pm .selectedCell::after { content: ''; position: absolute; inset: 0; background: var(--sel); pointer-events: none; }
.led-pm .column-resize-handle { position: absolute; right: -2px; top: 0; bottom: -2px; width: 4px; background: var(--accent); pointer-events: none; }
.led-pm.resize-cursor { cursor: col-resize; }

/* Картинка */
.led-pm .led-figure { position: relative; display: flex; flex-direction: column; align-items: center; margin: 1em 0; }
.led-pm .led-figure.align-left { align-items: flex-start; }
.led-pm .led-figure.align-right { align-items: flex-end; }
.led-img-frame { position: relative; max-width: 100%; }
.led-img-frame img { display: block; max-width: 100%; height: auto; border-radius: 8px; }
.led-figure.align-full .led-img-frame, .led-figure.align-full img,
.led-figure.align-row img, .led-figure.align-wrap-left img, .led-figure.align-wrap-right img { width: 100%; }
.led-figure.sel .led-img-frame { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 8px; }
.led-img-status { min-width: 220px; min-height: 120px; display: grid; place-items: center; padding: 12px; border-radius: 8px; background: var(--panel-2); color: var(--text-faint); font-size: 12.5px; text-align: center; }
.led-figure.align-row .led-img-status, .led-figure.align-wrap-left .led-img-status, .led-figure.align-wrap-right .led-img-status { min-width: 0; }
.led-img-handle { position: absolute; top: 50%; right: -7px; width: 8px; height: 44px; margin-top: -22px; border-radius: 4px; background: var(--accent); cursor: ew-resize; opacity: 0; transition: opacity 0.12s var(--ease); touch-action: none; }
.led-figure.align-right .led-img-handle, .led-figure.align-wrap-right .led-img-handle { right: auto; left: -7px; }
.led-figure.sel .led-img-handle, .led-figure:hover .led-img-handle { opacity: 1; }
.led-readonly .led-img-handle { display: none; }
.led-caption { width: 100%; max-width: 100%; margin-top: 6px; padding: 2px 4px; border: 0; background: none; outline: none; color: var(--text-dim); font: inherit; font-size: 0.85em; text-align: center; }
.led-figure.align-left .led-caption { text-align: left; }
.led-figure.align-right .led-caption { text-align: right; }

/* Обтекание: картинка прижата к краю, текст идёт рядом. Ширину держит сама
   фигура (из JS — доля полосы, данные пользователя). */
.led-pm .led-figure.align-wrap-left { float: left; margin: 0.3em 1.4em 0.6em 0; }
.led-pm .led-figure.align-wrap-right { float: right; margin: 0.3em 0 0.6em 1.4em; }
/* Полоса держит плавающие картинки внутри себя, а блоки, которым рядом с
   картинкой тесно, встают под неё. Списки, цитаты и выноски — рядом, но
   своим прямоугольником: маркеры и подложка не уезжают под картинку. */
.led-pm { display: flow-root; }
.led-pm > ul, .led-pm > ol, .led-pm > blockquote, .led-pm > .led-callout { display: flow-root; }
.led-pm > .tableWrapper, .led-pm > .led-gallery, .led-pm > .led-chart, .led-pm > .led-drawing, .led-pm > pre, .led-pm > hr,
.led-pm > .led-figure.align-left, .led-pm > .led-figure.align-center, .led-pm > .led-figure.align-right, .led-pm > .led-figure.align-full { clear: both; }

/* Ряд картинок */
.led-pm .led-gallery { display: flex; align-items: flex-start; gap: 10px; margin: 1em 0; }
.led-pm .led-gallery > .led-figure { margin: 0; min-width: 0; }
.led-gallery.ProseMirror-selectednode { outline: 2px solid var(--accent); outline-offset: 4px; border-radius: 10px; }

/* Панель у выбранного блока: картинка, график */
.led-node-bar { position: absolute; top: 8px; right: 8px; z-index: 3; display: none; gap: 1px; padding: 3px; border-radius: 9px; background: var(--panel); box-shadow: var(--shadow-pop); }
.led-node-group { display: flex; gap: 1px; }
.led-figure.align-row .led-node-bar, .led-figure.align-wrap-left .led-node-bar, .led-figure.align-wrap-right .led-node-bar { flex-wrap: wrap; max-width: calc(100% - 16px); }
.led-figure.sel .led-node-bar, .led-chart.sel .led-node-bar, .led-chart:hover .led-node-bar { display: flex; }
.led-readonly .led-node-bar { display: none !important; }

/* График */
.led-pm .led-chart { position: relative; margin: 1em 0; padding: 12px 12px 8px; border-radius: 12px; background: var(--panel-2); cursor: default; }
.led-chart.sel { outline: 2px solid var(--accent); outline-offset: 2px; }
.led-chart-svg { display: block; width: 100%; height: auto; overflow: visible; font-family: var(--font-ui); }
.led-ch-title { fill: var(--text); font-size: 14px; font-weight: 600; }
.led-ch-axis { fill: var(--text-faint); font-size: 12px; }
.led-ch-val { fill: var(--text-dim); font-size: 12px; }
.led-ch-legend { fill: var(--text-dim); font-size: 12px; }
.led-ch-grid { stroke: var(--line); stroke-width: 1; }
.led-ch-zero { stroke: var(--border-strong); stroke-width: 1; }
.led-series-0 { fill: var(--accent); stroke: var(--accent); }
.led-series-1 { fill: var(--led-c-blue); stroke: var(--led-c-blue); }
.led-series-2 { fill: var(--led-c-orange); stroke: var(--led-c-orange); }
.led-series-3 { fill: var(--led-c-purple); stroke: var(--led-c-purple); }
.led-series-4 { fill: var(--led-c-teal); stroke: var(--led-c-teal); }
.led-series-5 { fill: var(--led-c-pink); stroke: var(--led-c-pink); }
.led-series-6 { fill: var(--led-c-yellow); stroke: var(--led-c-yellow); }
.led-series-7 { fill: var(--led-c-red); stroke: var(--led-c-red); }
.led-ch-line { fill: none; stroke-width: 2.5; stroke-linejoin: round; stroke-linecap: round; }
.led-ch-area { fill-opacity: 0.18; stroke: none; }
.led-ch-dot { stroke: var(--panel-2); stroke-width: 2; }
.led-ch-slice { stroke: var(--panel-2); stroke-width: 2; }
.led-ch-slice-label { fill: var(--accent-text); font-size: 12px; font-weight: 600; }
.led-series-key { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: middle; }
span.led-series-key.led-series-0 { background: var(--accent); }
span.led-series-key.led-series-1 { background: var(--led-c-blue); }
span.led-series-key.led-series-2 { background: var(--led-c-orange); }
span.led-series-key.led-series-3 { background: var(--led-c-purple); }
span.led-series-key.led-series-4 { background: var(--led-c-teal); }
span.led-series-key.led-series-5 { background: var(--led-c-pink); }
span.led-series-key.led-series-6 { background: var(--led-c-yellow); }
span.led-series-key.led-series-7 { background: var(--led-c-red); }
.led-chart-modal { width: min(940px, 95vw); max-height: 92vh; overflow: auto; }
.led-chart-editor { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 18px; }
.led-chart-left { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.led-chart-right { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.led-chart-preview { padding: 10px; border-radius: 10px; background: var(--panel-2); }
.led-chart-opts { display: flex; flex-wrap: wrap; gap: 14px; }
.led-chart-grid { overflow: auto; max-height: 420px; }
.led-chart-table { border-collapse: separate; border-spacing: 4px; }
.led-chart-table th { font-size: 12px; font-weight: 500; color: var(--text-faint); text-align: left; white-space: nowrap; }
.led-cell-in { width: 92px; box-sizing: border-box; }
.led-cell-head { width: 96px; }
.led-add-row { margin-top: 6px; display: inline-flex; align-items: center; gap: 4px; }

/* Рисунок */
.led-pm .led-drawing { position: relative; margin: 1em 0; border-radius: 12px; background: var(--panel-2); overflow: hidden; }
.led-drawing.sel, .led-drawing.active { box-shadow: inset 0 0 0 2px var(--accent); }
.led-drawing .led-draw-bar { padding: 4px 6px; border-bottom: 1px solid var(--line); background: var(--panel); flex-wrap: nowrap; overflow-x: auto; }
.led-drawing .led-draw-bar::-webkit-scrollbar { height: 0; }
.led-drawing:not(.active) .led-draw-bar { display: none; }
.led-draw-area { position: relative; width: 100%; height: 320px; outline: none; touch-action: pan-x pan-y; cursor: pointer; user-select: none; -webkit-user-select: none; }
.led-draw-area[data-touch='draw'] { touch-action: none; }
.led-drawing.active .led-draw-area { cursor: crosshair; }
.led-drawing.active .led-draw-area[data-tool='eraser'] { cursor: cell; }
.led-drawing.active .led-draw-area[data-tool='lasso'] { cursor: default; }
.led-draw-canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.led-draw-area.bg-grid { background-image: linear-gradient(color-mix(in srgb, var(--text) 9%, transparent) 1px, transparent 1px), linear-gradient(90deg, color-mix(in srgb, var(--text) 9%, transparent) 1px, transparent 1px); background-size: 24px 24px; }
.led-draw-area.bg-dots { background-image: radial-gradient(color-mix(in srgb, var(--text) 22%, transparent) 1.1px, transparent 1.5px); background-size: 20px 20px; }
.led-draw-area.bg-lines { background-image: repeating-linear-gradient(transparent 0 31px, color-mix(in srgb, var(--text) 11%, transparent) 31px 32px); }
.led-draw-hint { position: absolute; inset: 0; display: grid; place-items: center; padding: 16px; text-align: center; font-size: 13px; color: var(--text-faint); pointer-events: none; }
.led-draw-grip { height: 12px; cursor: ns-resize; display: grid; place-items: center; touch-action: none; }
.led-draw-grip::after { content: ''; width: 36px; height: 4px; border-radius: 2px; background: var(--border-strong); }
.led-readonly .led-draw-grip { display: none; }
.led-pm .led-drawing.full { position: fixed; inset: 0; z-index: 150; margin: 0; border-radius: 0; display: flex; flex-direction: column; background: var(--panel); }
.led-drawing.full .led-draw-area { flex: 1; height: auto !important; }
.led-drawing.full .led-draw-grip { display: none; }

/* Панель рисования */
.led-inkbar { display: flex; align-items: center; gap: 2px; flex-wrap: wrap; }
.led-ink-group, .led-ink-recent { display: flex; align-items: center; gap: 1px; }
.led-ink-recent { gap: 2px; padding: 0 2px; }
.led-ink-recent-btn { width: 26px; height: 30px; display: grid; place-items: center; border: 0; border-radius: 8px; background: none; cursor: pointer; }
.led-ink-recent-btn:hover { background: var(--panel-2); }
.led-ink-dot { display: block; width: var(--sz, 12px); height: var(--sz, 12px); border-radius: 50%; background: currentColor; }
.led-ink-dot.tool-marker { border-radius: 3px; opacity: 0.55; }
/* Текущий цвет — точка в кольце: не путается с быстрыми перьями рядом. */
.led-ink-colorbtn .led-ink-dot { box-shadow: 0 0 0 2px var(--panel), 0 0 0 3.5px currentColor; }
.led-ink-size-dot { display: block; width: var(--sz, 12px); height: var(--sz, 12px); border-radius: 50%; background: var(--text-dim); }
.led-ink-sizes, .led-ink-shapes { display: flex; gap: 2px; padding: 2px; }
.led-ink-colors .led-swatch.ink-sw { background: currentColor; }
.led-ink-custom-row { display: flex; align-items: center; gap: 8px; padding: 8px 4px 2px; font-size: 12.5px; color: var(--text-dim); cursor: pointer; }
.led-ink-custom { width: 28px; height: 24px; padding: 0; border: 0; background: none; cursor: pointer; }
/* Настройки рисования: разделы с подписью, строки через тонкую линию,
   подпись слева, управление справа или во всю ширину под ней (круг 4). */
.led-ink-settings { width: min(340px, 86vw); display: flex; flex-direction: column; gap: 12px; padding: 2px 6px 6px; }
.led-sheet .led-ink-settings { width: auto; padding: 0; }
.led-set-title { padding: 6px 6px 8px; font-size: 14px; font-weight: 600; color: var(--text); }
.led-set-sec { display: flex; flex-direction: column; }
.led-set-cap { padding: 4px 0 2px; font-size: 12px; font-weight: 500; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.04em; }
.led-set-row { padding: 9px 0; border-top: 1px solid var(--line); }
.led-set-cap + .led-set-row { border-top: 0; }
.led-set-row.switch { width: 100%; padding-left: 0; padding-right: 0; }
.led-set-row .segmented { width: 100%; }
.led-set-row .segmented > button { flex: 1; }
.led-set-row .led-setting-slider { grid-template-columns: auto minmax(80px, 1fr) 40px; gap: 10px; }

/* Нижний лист (ui.js, sheet) — на телефоне вместо всплывашки. */
/* Подложка — общая с модалками (правило подложек выше); лист прижат к низу. */
.led-sheet-backdrop { z-index: 158; align-items: flex-end; }
.led-sheet {
  width: 100%; max-height: 86vh; overflow: auto; overscroll-behavior: contain;
  padding: 4px 18px calc(18px + env(safe-area-inset-bottom));
  border-radius: 18px 18px 0 0; background: var(--panel); box-shadow: var(--shadow-pop);
  animation: sheetIn 0.22s var(--ease); transition: transform 0.15s var(--ease);
}
.led-sheet-grip { width: 38px; height: 4px; margin: 6px auto 4px; border-radius: 2px; background: var(--line); touch-action: none; }
.led-sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 0 10px; touch-action: none; }
.led-sheet-title { font-size: 16px; font-weight: 600; color: var(--text); }
@keyframes sheetIn { from { transform: translateY(100%); } to { transform: none; } }

/* Слой пометок поверх текста */
.led-overlay { position: absolute; z-index: 5; pointer-events: none; overflow: hidden; }
.led-overlay.on { pointer-events: auto; cursor: crosshair; touch-action: none; }
.led-overlay.on[data-tool='eraser'] { cursor: cell; }
.led-overlay-canvas { display: block; width: 100%; height: 100%; }
.led-annotating .led-pm { user-select: none; -webkit-user-select: none; }
.led-overlay-bar { position: absolute; left: 50%; bottom: 44px; z-index: 30; transform: translateX(-50%); max-width: calc(100% - 24px); flex-wrap: nowrap; overflow-x: auto; padding: 5px 6px; border-radius: 14px; background: var(--panel); box-shadow: var(--shadow-pop); }
.led-overlay-done { white-space: nowrap; }
/* Телефон: панель пера в два ряда (ink.js, rows) — сверху, на месте панели
   редактора, которая на время пометок прячется. Внизу она уезжала под нижнее
   меню приложения (круг 3, 7 октября 2026). */
.led-inkbar-rows { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 2px; }
.led-ink-row { display: flex; align-items: center; gap: 2px; min-width: 0; overflow-x: auto; overflow-y: hidden; }
.led-ink-row::-webkit-scrollbar { height: 0; }
.led-ink-spacer { flex: 1; }
.led-ink-done { color: var(--accent-ink); }
/* Толщина и прозрачность — одна сетка на два ползунка: подписи разной длины,
   а ползунки начинаются с одной линии и ужимаются, а не вылезают за край. */
.led-ink-sizepop { display: grid; grid-template-columns: auto minmax(64px, 1fr) 40px; align-items: center; gap: 8px; width: min(280px, calc(100vw - 40px)); }
.led-ink-sizepop .led-ink-sizes { grid-column: 1 / -1; }
.led-ink-sizepop .led-setting-slider { display: contents; }
.led-mobile .led-ink-sizes { justify-content: space-between; }
.led-mobile .led-ink-sizes .led-btn { min-width: 32px; padding: 0; }
.led-mobile .led-overlay-bar { position: static; transform: none; max-width: none; padding: 4px 6px; border-radius: 0; box-shadow: none; border-bottom: 1px solid var(--line); overflow: visible; }
.led-mobile.led-annotating .led-toolbar { display: none; }
/* Ряд должен влезть в 280 пикселей — столько остаётся редактору на
   экране шириной 360 (самый узкий из ходовых Android). */
.led-mobile .led-ink-row { gap: 1px; }
.led-mobile .led-ink-row .led-ink-group { gap: 0; }
.led-mobile .led-ink-recent { gap: 1px; padding: 0 1px; }
.led-mobile .led-ink-recent-btn { height: 32px; }
.led-mobile .led-ink-row .led-btn { min-width: 32px; padding: 0 4px; }
.led-mobile .led-drawing .led-draw-bar { overflow: visible; }
/* Рисунок на телефоне — от края до края: на полосе шириной 250 пикселей
   тесно и рисовать, и панели. Поля страницы — .led-mobile .led-page-wrap. */
.led-mobile .led-pm > .led-drawing { margin-left: -16px; margin-right: -16px; border-radius: 0; }

/* Ручка блока слева */
.led-handle { position: absolute; z-index: 4; display: flex; align-items: center; opacity: 0; transition: opacity 0.12s var(--ease); }
.led-page-wrap:hover .led-handle:not([hidden]), .led-handle:focus-within { opacity: 1; }
.led-handle-btn { width: 24px; height: 24px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 6px; background: none; color: var(--text-faint); cursor: pointer; }
.led-handle-btn:hover { background: var(--panel-2); color: var(--text); }
.led-grip { cursor: grab; }
.led-grip:active { cursor: grabbing; }
.led-dropcursor { background: var(--accent); }
.led-pm .ProseMirror-gapcursor { display: none; pointer-events: none; position: absolute; }
.led-pm .ProseMirror-gapcursor::after { content: ''; display: block; position: absolute; top: -2px; width: 20px; border-top: 1px solid var(--text); animation: ledCaret 1.1s steps(2, start) infinite; }
.led-pm.ProseMirror-focused .ProseMirror-gapcursor { display: block; }
@keyframes ledCaret { to { visibility: hidden; } }
.led-pm.ProseMirror-hideselection *::selection { background: transparent; }
.led-pm.ProseMirror-hideselection { caret-color: transparent; }
.led-pm [draggable][contenteditable='false'] { user-select: text; }
.led-pm li.ProseMirror-selectednode { outline: none; }

/* Всплывающее: панель над выделением, меню «/», панели у кнопок */
.led-bubble { position: fixed; z-index: 160; display: flex; align-items: center; gap: 1px; padding: 4px; border-radius: 11px; background: var(--panel); box-shadow: var(--shadow-pop); animation: popIn 0.12s var(--ease); }
.led-turn { color: var(--text); }
.led-pop, .led-slash { z-index: 160; }
.led-pop { max-height: min(70vh, 520px); overflow: auto; }
.led-pop-wide { width: min(360px, 90vw); }
.led-slash { width: 270px; max-height: 330px; overflow: auto; }
.led-colors { display: grid; grid-template-columns: repeat(5, 28px); gap: 6px; padding: 4px; }
.led-swatch { width: 28px; height: 28px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 7px; background: var(--panel-2); color: var(--text); font: 700 14px var(--font-ui); cursor: pointer; }
.led-swatch.on { box-shadow: inset 0 0 0 2px var(--accent); }
.led-swatch.none { color: var(--text-faint); }
/* Цвета пера — после .led-swatch: та задаёт color: var(--text) тем же весом,
   и в палитре пера все квадраты были чёрными (круг 4, 7 октября). */
.ink-ink { color: var(--text); } .ink-gray { color: var(--led-c-gray); } .ink-red { color: var(--led-c-red); }
.ink-orange { color: var(--led-c-orange); } .ink-yellow { color: var(--led-c-yellow); } .ink-green { color: var(--led-c-green); }
.ink-teal { color: var(--led-c-teal); } .ink-blue { color: var(--led-c-blue); } .ink-purple { color: var(--led-c-purple); } .ink-pink { color: var(--led-c-pink); }
.sw-tc-gray { color: var(--led-c-gray); } .sw-tc-red { color: var(--led-c-red); } .sw-tc-orange { color: var(--led-c-orange); }
.sw-tc-yellow { color: var(--led-c-yellow); } .sw-tc-green { color: var(--led-c-green); } .sw-tc-teal { color: var(--led-c-teal); }
.sw-tc-blue { color: var(--led-c-blue); } .sw-tc-purple { color: var(--led-c-purple); } .sw-tc-pink { color: var(--led-c-pink); }
.sw-hl-gray { background: var(--led-hl-gray); } .sw-hl-red { background: var(--led-hl-red); } .sw-hl-orange { background: var(--led-hl-orange); }
.sw-hl-yellow { background: var(--led-hl-yellow); } .sw-hl-green { background: var(--led-hl-green); } .sw-hl-teal { background: var(--led-hl-teal); }
.sw-hl-blue { background: var(--led-hl-blue); } .sw-hl-purple { background: var(--led-hl-purple); } .sw-hl-pink { background: var(--led-hl-pink); }
.led-tpick { padding: 4px; }
.led-tgrid-label { font-size: 12px; color: var(--text-dim); padding: 0 2px 6px; }
.led-tgrid { display: grid; grid-template-columns: repeat(8, 18px); gap: 3px; }
.led-tcell { width: 18px; height: 18px; padding: 0; border: 1px solid var(--border-strong); border-radius: 4px; background: none; cursor: pointer; }
.led-tcell.on { background: var(--sel); border-color: var(--accent); }
.led-check { display: flex; align-items: center; gap: 6px; margin-top: 8px; font-size: 12.5px; color: var(--text-dim); cursor: pointer; }
.led-check input { accent-color: var(--accent); }
.led-ask, .led-link-pop { display: flex; flex-direction: column; gap: 6px; width: min(300px, 80vw); padding: 4px; }
.led-ask-label { font-size: 12px; color: var(--text-dim); }
.led-ask-row { display: flex; align-items: center; gap: 4px; }
.led-setting, .led-setting-col { display: flex; align-items: center; justify-content: space-between; gap: 12px; text-align: left; }
.led-setting-col { flex-direction: column; align-items: stretch; gap: 6px; }
.led-setting.switch { width: 100%; flex-direction: row-reverse; justify-content: space-between; }
.led-setting-text { display: flex; flex-direction: column; gap: 2px; font-size: 13px; color: var(--text); }
.led-setting-hint { font-size: 12px; color: var(--text-faint); }
.led-setting-slider { display: grid; grid-template-columns: 1fr 120px 38px; }
.led-range { width: 100%; accent-color: var(--accent); }
.led-slider-val { font-size: 12px; color: var(--text-dim); text-align: right; }
.led-switch .led-setting-text { flex: 1; }
.led-chart-opts .switch { font-size: 12.5px; }
.led-help { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.led-help-modal { width: min(760px, 95vw); max-height: 88vh; overflow: auto; }
.led-keys { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.led-keys td { padding: 3px 4px; border-bottom: 1px solid var(--line); }
.led-keys td:last-child { text-align: right; }
.led-keys kbd { font: 500 12px var(--font-ui); color: var(--text-dim); background: var(--panel-2); border-radius: 5px; padding: 1px 6px; }

/* Поиск */
.led-find { flex: none; display: flex; flex-direction: column; gap: 4px; padding: 6px 8px; border-bottom: 1px solid var(--line); background: var(--panel-2); }
.led-find-row { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.led-find .field-sm { background: var(--panel); }
.led-find-in { width: 230px; max-width: 100%; }
.led-flag { min-width: 28px; height: 26px; padding: 0 6px; border: 0; border-radius: 6px; background: none; color: var(--text-faint); font: 600 12px ui-monospace, Menlo, monospace; cursor: pointer; }
.led-flag:hover { color: var(--text); }
.led-flag.on { background: var(--sel); color: var(--accent-ink); }
.led-find-count { min-width: 64px; font-size: 12px; color: var(--text-dim); text-align: center; }
.led-find-count.none { color: var(--danger); }
.led-pm .led-find-hit { background: var(--led-hl-orange); border-radius: 2px; }
.led-pm .led-find-hit.cur { box-shadow: 0 0 0 2px var(--led-c-orange); }

/* Комментарии и оглавление — боковые панели */
.led-side { flex: none; width: 300px; display: flex; flex-direction: column; min-height: 0; border-left: 1px solid var(--line); background: var(--panel); }
.led-outline { width: 230px; border-left: 0; border-right: 1px solid var(--line); }
.led-side-head { flex: none; display: flex; align-items: center; gap: 2px; padding: 8px 8px 8px 14px; }
.led-side-title { flex: 1; font-size: 13px; font-weight: 600; }
.led-cm-count { color: var(--text-faint); font-weight: 500; }
.led-cm-list, .led-outline-list { flex: 1; overflow: auto; padding: 0 10px 12px; display: flex; flex-direction: column; gap: 8px; }
.led-outline-list { gap: 1px; }
.led-outline-item { display: block; width: 100%; text-align: left; border: 0; background: none; color: var(--text-dim); font: inherit; font-size: 13px; padding: 5px 8px; border-radius: 6px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.led-outline-item:hover { background: var(--panel-2); color: var(--text); }
.led-outline-item.lvl-1 { color: var(--text); font-weight: 600; }
.led-outline-item.lvl-2 { padding-left: 18px; }
.led-outline-item.lvl-3 { padding-left: 28px; font-size: 12.5px; }
.led-outline-item.lvl-4 { padding-left: 38px; font-size: 12.5px; }
.led-cm-empty { padding: 18px 8px; font-size: 12.5px; color: var(--text-faint); text-align: center; line-height: 1.5; }
.led-cm-card { display: flex; flex-direction: column; gap: 8px; padding: 10px; border-radius: 10px; background: var(--panel-2); cursor: pointer; }
.led-cm-card.active { box-shadow: inset 0 0 0 1.5px var(--led-c-yellow); }
.led-cm-card.resolved { opacity: 0.7; }
.led-cm-top { display: flex; align-items: flex-start; gap: 4px; }
.led-cm-quote { flex: 1; min-width: 0; font-size: 12px; color: var(--text-faint); border-left: 2px solid var(--led-c-yellow); padding-left: 8px; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.led-cm-card.orphan .led-cm-quote { border-left-color: var(--border-strong); font-style: italic; }
.led-cm-actions { display: flex; flex: none; }
.led-cm-actions .led-btn { height: 26px; min-width: 26px; padding: 0 4px; }
.led-cm-msg { display: flex; flex-direction: column; gap: 3px; }
.led-cm-meta { display: flex; align-items: center; gap: 6px; font-size: 12px; }
.led-cm-avatar { width: 20px; height: 20px; flex: none; display: grid; place-items: center; border-radius: 50%; background: var(--sel); color: var(--accent-ink); font-size: 12px; font-weight: 700; }
.led-cm-author { font-weight: 600; color: var(--text); }
.led-cm-time { color: var(--text-faint); }
.led-cm-meta .led-mini { margin-left: auto; }
.led-cm-text { font-size: 13px; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; }
.led-cm-reply { display: flex; align-items: flex-end; gap: 4px; }
.led-cm-input { flex: 1; resize: none; min-height: 32px; max-height: 160px; padding: 6px 9px; font-size: 13px; line-height: 1.45; background: var(--panel); }
.led-cm-resolved { font-size: 12px; color: var(--text-faint); }
.led-cm-cancel { align-self: flex-start; }
.led-pm .led-comment { background: var(--led-hl-yellow); border-bottom: 2px solid var(--led-c-yellow); cursor: pointer; }
.led-pm .led-comment.led-comment-resolved, .led-pm .led-comment-resolved .led-comment { background: none; border-bottom: 0; }
.led-pm .led-comment-active { background: var(--led-c-yellow); color: var(--panel); }

/* Счётчик слов, тост, печать */
.led-status { flex: none; padding: 5px 14px; border-top: 1px solid var(--line); font-size: 12px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.led-toast { position: absolute; left: 50%; bottom: 40px; z-index: 40; transform: translateX(-50%); padding: 8px 14px; border-radius: 10px; background: var(--raise); box-shadow: var(--shadow-pop); font-size: 13px; }
.led-print-frame { position: fixed; right: 0; bottom: 0; width: 0; height: 0; border: 0; }

/* Режим фокуса: всё, кроме текущего блока, приглушено. */
.led-focus-mode .led-pm > * { opacity: 0.3; transition: opacity 0.2s var(--ease); }
.led-focus-mode .led-pm > .led-current, .led-focus-mode .led-pm:not(.ProseMirror-focused) > * { opacity: 1; }

/* Узкий редактор — контейнерный запрос: редактор бывает узким и на широком
   окне (страница задачи с колонкой справа), а не только на телефоне. */
@container led (max-width: 760px) {
  .led-page-wrap { padding: 18px 18px 140px; }
  .led-handle { display: none !important; }
  .led-side { position: absolute; left: 0; right: 0; bottom: 0; z-index: 25; width: auto; max-height: 62%; border: 0; border-radius: 14px 14px 0 0; box-shadow: var(--shadow-modal); }
  .led-chart-editor, .led-help { grid-template-columns: minmax(0, 1fr); }
}

/* Ширина телефона: рядом с картинкой тексту места нет — она встаёт строкой,
   ряд картинок складывается в столбик. */
@container led (max-width: 520px) {
  .led-pm .led-figure.align-wrap-left, .led-pm .led-figure.align-wrap-right { float: none; width: auto !important; margin: 1em 0; }
  .led-pm .led-gallery { flex-direction: column; }
  .led-pm .led-gallery > .led-figure { flex: none !important; width: 100%; }
}

/* Телефон: кнопки крупнее, ручки блоков нет — блок двигают из меню. */
.led-mobile .led-btn { height: 38px; min-width: 38px; }
.led-mobile .led-toolbar { padding: 4px 6px; }
.led-mobile .led-handle { display: none !important; }
.led-mobile .led-page-wrap { padding: 16px 16px 50vh; }
/* Поле текста на телефоне — не ниже экрана: ткнуть, чтобы писать, и
   рисовать пером можно до самого низа; длинный текст растягивает его.
   Вычитаются панель (46) и поле страницы сверху (16) с запасом. */
.led-mobile .led-pm { min-height: calc(100vh - 78px); }
.led-mobile .led-status { display: none; }
/* Панель над выделением на телефоне — четыре кнопки под палец (menus.js). */
.led-mobile .led-bubble-touch { padding: 3px; border-radius: 14px; }
.led-mobile .led-bubble-touch .led-btn { height: 44px; min-width: 44px; }
/* Высота по тексту (opts.autoHeight — живой редактор на странице задачи
   телефона): прокручивает экран вокруг, а редактор сообщает свою высоту
   (сообщение height). Поле «не ниже экрана» и запас в полэкрана снизу здесь
   растили бы WebView сами себя. */
.led.led-autoheight { flex: none; height: auto; }
.led-autoheight .led-body { flex: none; }
.led-autoheight .led-scroll { overflow: visible; }
.led-autoheight .led-pm, .led-mobile.led-autoheight .led-pm { min-height: 3.3em; }
.led-mobile.led-autoheight .led-page-wrap { padding-bottom: 16px; }

/* ---------- Статус задачи в интерфейсе ---------- */

/* Квадратик цвета статуса — один и тот же приём в списке, в редакторе и на
   доске, чтобы статус узнавался по цвету, а не только по подписи. */
.st-swatch { width: 8px; height: 8px; border-radius: 3px; background: var(--sc, var(--accent)); flex: none; display: inline-block; }
/* Метка статуса в строке задачи — рядом со сроком, тем же весом. */
.task-status {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  font-size: 12px; color: var(--text-dim);
  background: var(--panel-2); border-radius: 999px; padding: 2px 8px 2px 6px;
  white-space: nowrap;
}
.board-dot { width: 8px; height: 8px; border-radius: 3px; background: var(--sc, var(--accent)); flex: none; }

/* ---------- Чип версии ---------- */
/* Бейдж версии в списке задач — рядом с меткой статуса и того же роста:
   это соседние по смыслу пометки. Цвета у версии нет, поэтому она остаётся
   нейтральной и не спорит со статусом за внимание. */
.task-version {
  display: inline-flex; align-items: center; flex: none;
  font-size: 12px; font-weight: 600; line-height: 1.5;
  color: var(--text-dim);
  background: var(--panel-2);
  border-radius: 5px; padding: 2px 7px;
  max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.task-version.released { color: var(--text-faint); }

/* ========== Слой: Каркас ========== */

/* ---------- Строка заголовка: лого + поиск (drag) ---------- */

#titlebar {
  position: relative;
  flex: none;
  height: 52px;
  background: var(--bg);
  -webkit-app-region: drag;
  /* На Windows кнопки окна рисует система поверх страницы
     (titleBarOverlay), и без этого отступа таймер уезжал бы
     прямо под «свернуть/закрыть». env(titlebar-area-width) — ширина
     шапки без них; в вебе переменной нет и фолбэк 100% даёт ноль. */
  padding-right: calc(100% - env(titlebar-area-width, 100%));
}
/* Зона под нативные трафик-лайты macOS (см. trafficLightPosition в
   src/main.js:x=14, три кнопки заканчиваются примерно на 80px). Только там
   она и нужна: на Windows кнопки окна рисуются справа, а в браузере их нет
   вовсе, и лого начинается от самого края.

   Ширина фиксированная и НЕ связана с рейлом: шапка — единая полоса во всю
   ширину окна, она не должна ездить и переламываться, когда рейл под ней
   сворачивается. */
.tb-nav-strip { display: none; }
body.platform-mac .tb-nav-strip {
  display: block;
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: var(--traffic-w);
  background: var(--bg);
  -webkit-app-region: drag;
}

/* Шапка — сетка из пяти колонок: лого · поиск · колокольчик · распорка ·
   таймер (или «Старт»). Колонки заданы вперёд, а не раздаются остатком, как в
   прежнем flex-ряду: там поиск и распорка делили то, что осталось от таймера,
   и стоило «Старту» стать капсулой с названием и «Стоп», как поле слева
   ужималось на глазах. Теперь правому блоку отведена полоса, не зависящая от
   того, что в ней лежит, и поиск считается только от ширины окна: до 400 px (+16
   отступа слева), а в тесном окне — сколько осталось за вычетом этой полосы.
   Полоса — 30% строки, но не уже 150 и не шире 380 px (капсула с самым
   длинным названием): в узком окне капсула ужимает название, а не поиск. */
.tb-rest {
  --tb-right-w: clamp(150px, 30%, 380px);
  display: grid;
  grid-template-columns: auto minmax(0, 416px) auto minmax(12px, 1fr) var(--tb-right-w);
  align-items: center;
  height: 100%;
  margin-left: 0;
  padding-right: 16px;
}
body.platform-mac .tb-rest { margin-left: var(--traffic-w); }

/* Поиск — пилюля того же цвета, что острова: на земле она предмет. */
.tb-search {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  /* Справа отступ меньше: колокольчик относится к поиску и стоит вплотную к
     нему, а не висит сам по себе посреди шапки. */
  margin: auto 0 auto 16px;
  height: 34px;
  padding: 0 12px;
  background: var(--panel);
  border-radius: var(--radius-sm);
  -webkit-app-region: no-drag;
  transition: box-shadow 0.12s var(--ease);
}
.tb-search:focus-within { box-shadow: inset 0 0 0 1.5px var(--accent); }

/* Лого открывает шапку. Порядок один на всех платформах:
   [трафик-лайты только на маке] лого · поиск · колокольчик … таймер.
   Профиль — внизу левой панели. */
.tb-logo {
  display: flex;
  align-items: center;
  gap: 9px;
  flex: none;
  padding-left: 16px;
  padding-right: 4px;
  user-select: none;
  -webkit-app-region: drag;
}
/* Знак шире, чем высок: рамка в разметке впритык (4:3), высота = ширина × 0.75. */
.tb-logo-mark { width: 22px; height: 16.5px; flex: none; color: var(--accent-ink); }
/* Вес и разрядка подобраны замером под прежний логотип (Basique Pro Bold,
   16 px, разрядка 0.4): у Onest 800 та же «краска» (352 против 349 px²) и
   высота заглавной (12.3 px), а разрядка −0.1 возвращает ширину слова
   (64.5 против 64.6 px). */
.tb-logo-text {
  font-family: var(--font-logo);
  font-weight: 800;
  font-size: 16px;
  letter-spacing: -0.1px;
  white-space: nowrap;
}
.tb-search .icon { color: var(--icon); flex: none; }
#search-input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  outline: none;
}

/* ---------- Каркас: нав-рейл + основное ---------- */

/* Линия под шапкой живёт здесь, а не на #titlebar и не на #main.
   Не на #titlebar: на Windows кнопки окна (titleBarOverlay) закрывают
   последнюю строку титлбара сплошным прямоугольником, и граница пропадала бы
   под ними. Не на #main: он начинается за левой панелью, и линия обрывалась
   на её границе — шапка выглядела разрезанной надвое. На #shell она идёт во
   всю ширину окна и строкой ниже полосы оверлея, то есть видна везде. */
#shell {
  flex: 1;
  min-height: 0;
  display: flex;
  position: relative;
}

/* Тоже вынесен из flex-потока — см. комментарий у .tb-logo про баг Chromium. */
/* Рейл — остров: отступ от края и от шапки, как у всех островов. */
#navrail {
  position: absolute;
  left: var(--gap);
  top: 0;
  bottom: var(--gap);
  width: var(--nav-w);
  background: var(--rail);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  padding: 10px 8px;
  gap: 3px;
  overflow: hidden;
  transition: width 0.24s var(--ease);
}
body.nav-collapsed #navrail { width: var(--nav-w-collapsed); }

.nav-item {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  border: none;
  background: none;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 13.5px;
  font-weight: 500;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.13s var(--ease), color 0.13s var(--ease);
}
.nav-item .icon { color: inherit; width: 16px; height: 16px; }
.nav-item .nav-label { transition: opacity 0.12s var(--ease); }
body.nav-collapsed .nav-item .nav-label { opacity: 0; }
.nav-item:hover { background: var(--panel-2); color: var(--text); }
.nav-item:active { transform: scale(0.98); }
.nav-item.active { background: var(--nav-active-bg); color: var(--text); }

.nav-update {
  position: relative;
  overflow: hidden;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent-ink);
  animation: popIn 0.2s var(--ease);
}
.nav-update:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.nav-update.downloading { pointer-events: none; opacity: 0.75; }
.nav-update .nav-progress {
  position: absolute;
  left: 0; bottom: 0;
  height: 2px;
  background: var(--accent);
  transition: width 0.2s linear;
}

.nav-items { display: flex; flex-direction: column; gap: 3px; }

/* Проекты в меню. Открыть проект — один щелчок с любого экрана, а отдельный
   пункт «Доска» не нужен: доска стала вкладкой проекта. В свёрнутом меню
   остаются цветные квадраты проектов. */
.nav-sec {
  display: flex; align-items: center; justify-content: space-between;
  min-height: 28px; padding: 12px 6px 2px 10px;
  font-size: 12px; font-weight: 600; color: var(--text-faint); white-space: nowrap;
}
body.nav-collapsed .nav-sec .nav-label { opacity: 0; }
.nav-sec-add {
  flex: none; display: grid; place-items: center; width: 24px; height: 24px;
  border: none; border-radius: 6px; background: none; color: var(--icon); cursor: pointer;
}
.nav-sec-add .icon { width: 12px; height: 12px; }
.nav-sec-add:hover { background: var(--panel-2); color: var(--text); }
body.nav-collapsed .nav-sec-add { display: none; }
.nav-projects { display: flex; flex-direction: column; gap: 2px; min-height: 0; overflow-y: auto; }
.nav-project { padding-top: 7px; padding-bottom: 7px; }
/* Документы открытого проекта — под ним в левом меню, со сдвигом (круг 5). */
.nav-doc { padding-top: 5px; padding-bottom: 5px; padding-left: 26px; font-size: 13px; color: var(--text-dim); }
.nav-doc .icon { width: 13px; height: 13px; flex: none; }
.nav-doc .nav-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-doc-more { color: var(--text-faint); }
body.nav-collapsed .nav-doc { display: none; }
.nav-pdot { flex: none; width: 10px; height: 10px; margin: 0 3px; border-radius: 3px; }
.nav-pname { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Группа «Быстрый доступ»: подпись с булавкой. В свёрнутом меню подпись
   гаснет, как у «Проектов», и группы разделяет её пустая строка. */
.nav-sec-pinned .nav-label { display: inline-flex; align-items: center; gap: 6px; }
.nav-sec-pinned .icon { width: 12px; height: 12px; color: var(--icon); }
.nav-pcount { margin-left: auto; font-size: 12px; font-weight: var(--fw-text); color: var(--text-faint); font-variant-numeric: tabular-nums; }
body.nav-collapsed .nav-pcount { opacity: 0; }
.nav-spacer { flex: 1; }

.theme-tabs { align-items: center; margin: 2px 0; }
.theme-tab { flex: 1; display: flex; align-items: center; justify-content: center; }
.theme-tab .icon { color: inherit; }

/* ---------- Панель поиска ---------- */

#search-panel {
  position: fixed;
  left: 0;
  top: 53px;
  width: 460px;
  max-width: calc(100vw - 24px);
  max-height: 70vh;
  background: var(--panel);
  border: 0;
  border-radius: 12px;
  box-shadow: var(--shadow-modal);
  z-index: 80;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: popIn 0.14s var(--ease);
}
#search-results { overflow-y: auto; padding: 6px; }
.sr-group { font-size: 12px; letter-spacing: 0.6px; text-transform: uppercase; color: var(--text-dim); padding: 8px 8px 4px; }
.sr-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  text-align: left;
  padding: 7px 8px;
  border-radius: 7px;
  cursor: pointer;
  transition: background 0.1s var(--ease);
}
.sr-item:hover, .sr-item.sel { background: var(--panel-2); }
.sr-dot { width: 8px; height: 8px; border-radius: 2px; flex: none; }
.sr-main { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.sr-title { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sr-sub { font-size: 12px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sr-meta { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; flex: none; }

/* ---------- Основная область ---------- */

/* Линия под шапкой — на #shell, см. комментарий там. */
#main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  margin-left: calc(var(--nav-w) + var(--gap) * 2);
  padding: 0 var(--gap) var(--gap) 0;
  transition: margin-left 0.24s var(--ease);
}
body.nav-collapsed #main { margin-left: calc(var(--nav-w-collapsed) + var(--gap) * 2); }

/* ---------- Виды ---------- */

.view { flex: 1; min-height: 0; }
/* .view только растягивается по высоте; настройкам нужен свой скролл,
   иначе длинный список просто обрезается снизу. */
#settings-view { overflow-y: auto; }
/* Экран проекта: шапка одной строкой, под ней одна из трёх вкладок. */
#project-view { display: flex; flex-direction: column; overflow: hidden; }
/* Страница задачи — см. раздел «Страница задачи». */
#project-view[hidden] { display: none !important; }

/* «Сегодня»: слева день, числа, проекты и сроки; справа идущая задача и
   недавние. Обе колонки — стопки островов, каждая со своей прокруткой. */
#home-view { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--gap); overflow: hidden; }
.home-main, .home-side { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; min-width: 0; overflow-y: auto; }
/* «Проекты»: шапка строкой, сетка карточек, таблица недавних задач. */
/* Страница доходит до правого края окна (поле --gap — внутри неё): так
   ряд карточек ниже может уйти до самого края, а не обрываться в воздухе
   за 12 px до него. Шапка и таблица недавних стоят на прежних местах. */
#projects-view { display: flex; flex-direction: column; gap: var(--gap); overflow-y: auto; margin-right: calc(var(--gap) * -1); padding-right: var(--gap); }
/* Строка стоит на прежнем месте (поле справа — как было), а закрашенная ею
   земля доходит до края окна, как ряд карточек под ней: иначе сквозь поле
   справа от строки просвечивала бы карточка, ушедшая вверх. Закраска — тенью
   без размытия: в отличие от рамки она не растягивает прокручиваемую область. */
#projects-view .page-head, #projects-view .page-head::after { box-shadow: var(--gap) 0 0 var(--bg); }

/* ---------- Скелетон начальной загрузки ---------- */

#app-skeleton {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  transition: opacity 0.18s var(--ease);
}
#app-skeleton.hide { opacity: 0; pointer-events: none; }
/* Раскладка — та же, что у настоящих шапки, рейла и «Сегодня»: те же
   --gap, --nav-w, --radius, высота шапки 52 и правая колонка 300. Острова —
   --panel на земле --bg, внутри — переливающиеся полоски --panel-2, как
   поля и кнопки на островах. Своих цветов у скелетона нет, поэтому он
   верен обеим темам. */
.skel {
  display: block;
  background: linear-gradient(90deg, var(--panel-2) 25%, var(--raise) 50%, var(--panel-2) 75%);
  background-size: 200% 100%;
  animation: skelShimmer 1.4s ease-in-out infinite;
  border-radius: 6px;
}
@keyframes skelShimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.skel-gap { flex: 1; }
.skel-bar { height: 10px; }
.skel-w-xs { width: 40px; }
.skel-w-s { width: 50px; }
.skel-w-m { width: 80px; }
.skel-w-l { width: 120px; }
.skel-w-xl { width: 150px; }
.skel-w-45 { width: 45%; }
.skel-w-60 { width: 60%; }
.skel-w-80 { width: 80%; }

.skel-topbar { height: 52px; flex: none; display: flex; align-items: center; gap: 6px; padding: 0 16px; }
body.platform-mac .skel-topbar { padding-left: calc(var(--traffic-w) + 16px); }
.skel-logo { width: 104px; height: 20px; margin-right: 10px; }
.skel-pill { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 12px; background: var(--panel); border-radius: var(--radius-sm); }
.skel-search { flex: 1; max-width: 400px; }
.skel-dot { width: 14px; height: 14px; border-radius: 999px; }
.skel-bell { width: 16px; height: 16px; margin: 0 7px; border-radius: 5px; }
.skel-start { height: 34px; padding: 0 14px; border-radius: 999px; background: var(--pill); }

.skel-body { flex: 1; display: flex; gap: var(--gap); min-height: 0; padding: 0 var(--gap) var(--gap); }
.skel-rail {
  width: var(--nav-w); flex: none; display: flex; flex-direction: column; gap: 27px;
  padding: 22px 18px; background: var(--rail); border-radius: var(--radius);
}
/* Шаг строк — как у пунктов рейла: 36 px пункт и 3 px зазор. */
.skel-row { height: 12px; width: 70%; flex: none; }
.skel-sec { width: 40%; height: 8px; }
.skel-main { flex: 1; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--gap); }
.skel-col { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; }
.skel-island { background: var(--panel); border-radius: var(--radius); padding: 16px; display: flex; flex-direction: column; gap: 10px; flex: none; }
.skel-grow { flex: 1; }
.skel-h1 { width: 200px; height: 18px; }
.skel-track { height: 52px; margin-top: 6px; border-radius: var(--radius-sm); }
.skel-day { padding: 18px 20px 30px; }
.skel-kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; padding: 0; }
.skel-kpis > div { display: flex; flex-direction: column; gap: 9px; padding: 16px 20px; }
.skel-num { height: 18px; width: 48px; }
.skel-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; }
.skel-card { height: 64px; border-radius: var(--radius-sm); }
.skel-now-row { display: flex; align-items: center; gap: 12px; margin-top: 6px; }
.skel-sq { width: 44px; height: 44px; border-radius: 12px; flex: none; }

/* ---------- Профиль внизу левой панели ----------
   С 9 октября 2026 профиль не в шапке, а последним пунктом рейла — под
   языком и «Свернуть»: вход, имя, синхронизация, выход. Пункт рейла как
   все, у вошедшего значок заменяет кружок с буквой. */
.nav-account .nav-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.nav-avatar { width: 18px; height: 18px; margin: -1px; border-radius: 999px; background: var(--panel-2); color: var(--text); display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; flex: none; }
.nav-account:hover .nav-avatar { background: var(--raise); }

/* ---------- Таймер в правом верхнем углу ----------
   Виден на каждом экране. Идёт — капсула: точка, задача, время, «Стоп»;
   капсула ведёт на страницу задачи, «Стоп» — отдельная кнопка внутри.
   Стоит — на её месте компактная «▶ Старт» (последняя задача). */
/* Капсула и «Старт» стоят в одной клетке сетки шапки: обычно видна одна из
   них, а пока капсула стекает обратно в «Старт» (.liq-shrink), они на
   миг лежат друг на друге — и соседи шапки об этом не знают. */
.tb-timer, .tb-start { grid-column: 5; grid-row: 1; }
.tb-timer {
  -webkit-app-region: no-drag;
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  gap: 9px;
  /* Стоит у правого края своей колонки шапки и не шире её: в узком окне
     название задачи (.tb-timer-name) ужимается, а колонка поиска не трогается. */
  justify-self: end;
  min-width: 0;
  height: 34px;
  margin: auto 0;
  padding: 0 4px 0 12px;
  max-width: 100%;
  background: var(--pill);
  border: 0;
  border-radius: 999px;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}
.tb-timer:hover { background: var(--panel-2); }
.tb-timer-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--accent); flex: none; }
.tb-timer-time { font-family: var(--font-display); font-weight: var(--fw-display); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; font-size: 14px; }
.tb-timer-name { min-width: 0; max-width: 200px; overflow: hidden; text-overflow: ellipsis; color: var(--text-dim); font-weight: 500; }
.tb-timer-stop {
  height: 26px; border: 0; border-radius: 999px; padding: 0 10px 0 8px; flex: none; gap: 5px;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  background: var(--accent); color: var(--accent-text); font-size: 12.5px; font-weight: 600;
}
.tb-timer-stop .icon { width: 11px; height: 11px; color: inherit; }
.tb-timer-stop:hover { background: var(--accent-hover); }
.tb-start {
  -webkit-app-region: no-drag;
  display: flex; align-items: center; gap: 6px; justify-self: end;
  height: 34px; margin: auto 0; padding: 0 14px 0 12px;
  background: var(--pill); border: 0; border-radius: 999px;
  color: var(--text); font-family: inherit; font-size: 13px; font-weight: 500;
  cursor: pointer; white-space: nowrap;
  transition: background 0.12s var(--ease);
}
.tb-start:hover { background: var(--panel-2); }
.tb-start .icon { width: 13px; height: 13px; color: inherit; }

/* Жидкий перелив «Старт» ↔ капсула. Запустили: капсула проявляется справа
   налево из места «Старта» и качается желе у правого края; зелёная капля
   «Стопа» набухает из точки, от неё отрывается бусина и катится влево —
   там она становится точкой «идёт». Остановили: бусина катится назад и
   вливается в каплю, капсула стекает в размер «Старта», капля
   втягивается, и «Старт» вздрагивает, выходя из-под неё.
   Капля и бусина — слой .liq-goo под содержимым капсулы с SVG-фильтром
   #liq-goo (размытие и резкий порог по прозрачности): два близких пятна
   сливаются перемычкой, как капли воды. Слой и фильтр создаёт setupLiquid,
   классы и координаты (--liq-from — ширина «Старта», --liq-run — путь
   бусины, место капли — под «Стопом») ставит tbPour в app.js. */
.liq-goo { display: none; position: absolute; inset: 0; z-index: -1; pointer-events: none; filter: url(#liq-goo); }
.liq-drop, .liq-bead { position: absolute; display: block; background: var(--accent); border-radius: 999px; }
.liq-bead { width: 12px; height: 12px; }
.liq-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.tb-timer.liq-grow .liq-goo, .tb-timer.liq-shrink .liq-goo { display: block; }
.tb-timer.liq-grow .tb-timer-stop, .tb-timer.liq-shrink .tb-timer-stop { background: transparent; }
.tb-timer.liq-grow {
  transform-origin: right center;
  animation: liqReveal 0.5s var(--ease) both, liqStretch 0.62s var(--ease) both;
}
.tb-timer.liq-grow .liq-drop { animation: liqDropIn 0.56s var(--ease) both; }
.tb-timer.liq-grow .liq-bead { animation: liqBeadOut 0.62s var(--ease) both; }
.tb-timer.liq-grow .tb-timer-name, .tb-timer.liq-grow .tb-timer-time { animation: liqFadeIn 0.32s var(--ease) 0.2s both; }
.tb-timer.liq-grow .tb-timer-stop > * { animation: liqFadeIn 0.24s var(--ease) 0.24s both; }
.tb-timer.liq-grow .tb-timer-dot { animation: liqPop 0.26s var(--spring) 0.38s both; }
.tb-timer.liq-shrink {
  pointer-events: none;
  animation: liqDrain 0.46s cubic-bezier(0.55, 0, 0.75, 0.4) both, liqFadeOut 0.1s linear 0.42s both;
}
.tb-timer.liq-shrink .liq-drop { animation: liqDropOut 0.46s var(--ease) both; }
.tb-timer.liq-shrink .liq-bead { animation: liqBeadIn 0.46s var(--ease) both; }
.tb-timer.liq-shrink .tb-timer-name, .tb-timer.liq-shrink .tb-timer-time,
.tb-timer.liq-shrink .tb-timer-dot, .tb-timer.liq-shrink .tb-timer-stop > * { animation: liqFadeOut 0.14s var(--ease) both; }
.tb-start.liq-settle { animation: liqSettle 0.62s var(--ease) both; }
@media (prefers-reduced-motion: reduce) {
  .tb-timer.liq-grow, .tb-timer.liq-shrink, .tb-start.liq-settle,
  .tb-timer.liq-grow *, .tb-timer.liq-shrink * { animation: none; }
}

/* ---------- Колокольчик и панель уведомлений ---------- */

.tb-notif {
  -webkit-app-region: no-drag;
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  /* Колокольчик — сразу справа от поиска; вправо распорка прижимает
     только таймер. */
  margin: auto 0 auto 6px;
  background: none;
  border: none;
  cursor: pointer;
}
.tb-notif:hover .icon { color: var(--text); }
.tb-notif .icon { width: 15px; height: 15px; color: var(--icon); transform-origin: 50% 8%; }
.tb-notif.on .icon { color: var(--text); }
/* Есть непрочитанные — колокольчик звенит: качнулся вокруг верхней точки с
   затуханием (~1 с), потом шесть секунд тишины; так три раза, и всё. Снова
   — только когда непрочитанных стало больше (класс .ring ставит ringBell в
   app.js). Язычок отстаёт и бьёт в другую сторону, кружок с числом
   вздрагивает на первом ударе. */
.tb-notif.ring .icon { animation: bellRing 7s var(--ease) 3; }
.tb-notif.ring .icon path:first-child { animation: bellClapper 7s var(--ease) 3; }
.tb-notif.ring .notif-badge { animation: badgeBump 7s var(--ease) 3; }
@media (prefers-reduced-motion: reduce) {
  .tb-notif.ring .icon, .tb-notif.ring .icon path, .tb-notif.ring .notif-badge { animation: none; }
}
.notif-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--danger);
  color: var(--text-on-color);
  font-size: 10px;
  line-height: 16px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* left/top выставляет toggleNotifPanel по фактическому положению кнопки:
   колокольчик стоит у поиска, а не у края окна. */
#notif-panel {
  position: fixed;
  width: 340px;
  max-width: calc(100vw - 24px);
  max-height: 70vh;
  background: var(--panel);
  border: 0;
  border-radius: 12px;
  box-shadow: var(--shadow-modal);
  z-index: 90;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  animation: popIn 0.14s var(--ease);
}
.notif-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
}
#notif-list { list-style: none; margin: 0; padding: 0; overflow-y: auto; }
#notif-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}
#notif-list li:last-child { border-bottom: none; }
#notif-list li:hover { background: var(--panel-2); }
#notif-list li.unread { background: color-mix(in srgb, var(--accent) 9%, transparent); }
#notif-list li.unread:hover { background: color-mix(in srgb, var(--accent) 15%, transparent); }
.notif-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--pc, var(--accent)); }
.notif-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.notif-name { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notif-sub { font-size: 12px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notif-when { flex: none; font-size: 12px; border-radius: 999px; padding: 2px 7px; background: var(--panel-2); color: var(--text-dim); white-space: nowrap; }
.notif-when.overdue { background: color-mix(in srgb, var(--danger) 20%, transparent); color: var(--danger); }
.notif-when.soon { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent-ink); }

/* ========== Слой: Экраны ========== */

/* ---------- Карточки чисел (статистика) ---------- */

/* Четыре карточки в ряд, пока им хватает места; в узком окне — два на два.
   Решает ширина того, в чём они лежат (контейнерный запрос), а не окна:
   на «Обзоре» рядом с ними стоит идущий таймер, в статистике — нет. */
.stat-cards { flex: 1; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }
@container (max-width: 720px) {
  .stat-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.stat-card {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--panel);
  border: 0;
  border-radius: 10px;
  padding: 15px 14px;
}
.stat-card .icon { width: 17px; height: 17px; }
.stat-card > div { min-width: 0; display: flex; flex-direction: column; }
.stat-card b {
  font-size: 17px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Подпись переносится, а не режется многоточием: с 12 px «заработано в этом
   месяце» не влезала в карточку, а по-казахски подписи ещё длиннее. */
.stat-card span { font-size: 12px; line-height: 1.3; color: var(--text-dim); }

/* ---------- Шапка проекта ----------
   Остров: назад, цвет, название, описание, теги, «+ Задача»; второй
   строкой — вкладки сегментом, итоги и действия. */
.proj-head { flex: none; display: flex; flex-direction: column; gap: 8px; padding: 12px 16px 10px; margin-bottom: var(--gap); }
.ph-line { display: flex; align-items: center; gap: 10px; min-width: 0; }
#proj-back { margin-left: -6px; }
.ph-dot { flex: none; width: 12px; height: 12px; border-radius: 4px; }
/* Первая строка — кто это: название не сжимается, пока есть что сжать,
   первым уступает описание (оно же подсказкой на названии). Предел — чтобы
   «+ Задача» и кнопка назад всегда помещались. */
.proj-head { container-type: inline-size; }
.ph-name { margin: 0; font-size: 19px; font-weight: var(--fw-display); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 0 0 auto; max-width: calc(100% - 170px); }
.ph-desc { color: var(--text-faint); font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; flex: 0 10000 auto; }
/* Вторая строка — вкладки, теги, числа. Теги уступают числам: сколько чипов
   влезает, меряет fitHeaderTags; не влезает и «+N» — прячутся целиком. */
.ph-tags { flex: 0 1 auto; min-width: 0; display: flex; flex-wrap: nowrap; gap: 6px; overflow: hidden; white-space: nowrap; max-width: 50%; }
/* В узкой шапке вкладки остаются значками: подписи не помещаются рядом с
   числами проекта. */
@container (max-width: 720px) {
  .proj-tabs button > span:not(.ptab-count) { display: none; }
  .proj-tabs button { padding-left: 9px; padding-right: 9px; }
}
.ph-tags .tag-more { color: var(--text-dim); background: var(--panel-2); }
.proj-tabs button .icon { color: inherit; }
.ptab-count { font-size: 12px; color: var(--text-faint); margin-left: 4px; }
.proj-kpis { display: flex; align-items: baseline; gap: 6px; margin-right: 6px; font-size: 13px; color: var(--text-dim); white-space: nowrap; font-variant-numeric: tabular-nums; }
.proj-kpis b { font-family: var(--font-display); font-weight: var(--fw-display); color: var(--text); }
.proj-kpis > * + *::before { content: '·'; margin-right: 6px; color: var(--text-faint); font-family: var(--font-ui); font-weight: var(--fw-text); }
.proj-new { display: inline-flex; align-items: center; gap: 6px; margin-left: 4px; }
.proj-new .icon { width: 13px; height: 13px; color: inherit; }

/* Вкладка «Список»: остров списка во всю ширину, справа колонка островов —
   прогресс, версии, последние записи. */
.proj-list { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: var(--gap); }
.proj-side { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; overflow-y: auto; }
.proj-card { padding: 14px 16px; flex: none; }
#proj-sessions { flex: 1; }
.pp-line { display: flex; align-items: baseline; gap: 6px; margin-top: 6px; }
.pp-num { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 22px; }
.pp-pct { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 13px; color: var(--text-dim); }
.pp-bar { display: flex; gap: 2px; height: 6px; margin-top: 8px; border-radius: 3px; overflow: hidden; background: var(--panel-2); }
.pp-bar i { display: block; height: 100%; }
.pp-legend { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 10px; margin-top: 10px; font-size: 12px; color: var(--text-dim); }
.pp-legend span { display: flex; align-items: center; gap: 6px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pp-legend i { width: 8px; height: 8px; border-radius: 3px; flex: none; }
.pv-row { margin-top: 10px; cursor: pointer; }
.pv-head { display: flex; justify-content: space-between; gap: 8px; font-size: 12.5px; }
.pv-name { font-weight: 600; }
.pv-sum { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.pv-bar { display: block; height: 4px; border-radius: 2px; background: var(--panel-2); margin-top: 5px; overflow: hidden; }
.pv-bar i { display: block; height: 100%; background: var(--text-dim); }
.pv-none { margin-top: 10px; font-size: 12px; color: var(--text-faint); }
#ps-list .rl-when { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 12.5px; }
#ps-list .rl-money { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 12.5px; color: var(--text-dim); min-width: 56px; text-align: right; font-variant-numeric: tabular-nums; }

/* Доска и версии — острова во всю ширину под шапкой. */
.proj-board { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; padding: 12px; }
/* Столбиком: пустой экран вкладки (.empty-state, flex: 1) встаёт по центру
   того, что осталось под шапкой. */
.proj-versions { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 18px; display: flex; flex-direction: column; }
/* Документы проекта (круг 5): строки — общие .doc-item из раздела «Документы». */
.proj-docs { flex: 1; min-height: 0; overflow-y: auto; padding: 14px 18px; display: flex; flex-direction: column; }
.pdoc-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; max-width: 760px; }
.pdoc-list { display: flex; flex-direction: column; gap: 2px; max-width: 760px; }
.pver-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; max-width: 760px; }
.pver-row { padding: 12px 14px; border-radius: var(--radius-sm); background: var(--panel-2); cursor: pointer; transition: background 0.12s var(--ease); }
.pver-row:hover { background: var(--raise); }
.pver-head { display: flex; align-items: baseline; gap: 10px; }
.pver-name { font-family: var(--font-display); font-size: 16px; font-weight: var(--fw-display); }
.pver-state { font-size: 12px; color: var(--text-faint); }
.pver-bar { height: 5px; margin: 10px 0 8px; border-radius: 3px; background: var(--raise); overflow: hidden; }
.pver-fill { display: block; height: 100%; border-radius: 3px; background: var(--text-dim); }
.pver-meta { display: flex; gap: 16px; font-size: 13px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.pver-meta .kpi-money { margin-left: auto; font-weight: 600; color: var(--text); }

/* ---------- Список задач проекта ----------
   Колонки: галочка, задача (ниже версия, точки тегов, повтор), срок,
   время, деньги. Группы статусов — плашками с суммами. */
#sidebar { display: flex; flex-direction: column; min-height: 0; padding: 12px 6px 8px; }
.task-filter { display: flex; align-items: center; gap: 8px; padding: 0 6px 6px; flex-wrap: wrap; }
.tf-status button { white-space: nowrap; }
.task-filter-version { display: flex; margin-left: auto; min-width: 0; }
.tl-head, .task-item, .task-group { display: grid; grid-template-columns: 22px minmax(0, 1fr) 128px 72px 84px; align-items: center; gap: 12px; }
.tl-head { padding: 6px 12px 8px; font-size: 12px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
.tl-head span:nth-child(4), .tl-head span:nth-child(5) { text-align: right; }
#task-list { list-style: none; margin: 0; padding: 0 0 8px; overflow-y: auto; flex: 1; }
.task-item {
  padding: 8px 12px; border-top: 1px solid var(--line); cursor: pointer;
  transition: background 0.12s var(--ease);
  animation: tileIn 0.2s var(--ease) backwards;
}
.task-group + .task-item { border-top: 0; }
.task-item:hover { background: var(--panel-2); }
.ti-main { min-width: 0; display: flex; flex-direction: column; }
.ti-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.task-item .task-name { flex: 1; min-width: 0; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.task-item.done .task-name { color: var(--text-faint); }
.ti-meta { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-faint); margin-top: 2px; white-space: nowrap; min-height: 0; }
.ti-meta:empty { display: none; }
.ti-meta .task-version { height: 16px; line-height: 16px; padding: 0 5px; max-width: 110px; overflow: hidden; text-overflow: ellipsis; }
.ti-tags { display: inline-flex; gap: 3px; }
.ti-tags .tag-dot { width: 7px; height: 7px; border-radius: 50%; }
.ti-due { font-size: 12.5px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ti-due.overdue { color: var(--danger); }
.task-item .task-time { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 12.5px; text-align: right; font-variant-numeric: tabular-nums; }
.ti-money { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 12.5px; text-align: right; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.running-dot { color: var(--accent-ink); font-size: 10px; animation: pulse 1.4s ease-in-out infinite; }
.task-pin {
  border: none; background: none; cursor: pointer; padding: 0; width: 14px; flex: none;
  color: var(--icon); opacity: 0; transition: opacity 0.1s var(--ease), color 0.1s var(--ease);
}
.task-pin .icon { width: 12px; height: 12px; color: inherit; }
.task-item:hover .task-pin { opacity: 0.7; }
.task-item .task-pin:hover { opacity: 1; color: var(--text); }
.task-item.pinned .task-pin { opacity: 1; color: var(--text); }

.task-group {
  list-style: none; margin-top: 10px; padding: 7px 12px; border-radius: 8px; background: var(--panel-2);
  font-size: 12px; font-weight: 600; color: var(--text-dim); cursor: pointer; user-select: none;
}
.task-group:first-child { margin-top: 0; }
.task-group:hover { color: var(--text); }
.tg-chev { display: flex; justify-content: center; }
.tg-chev .icon { width: 12px; height: 12px; transition: transform 0.12s var(--ease); }
.task-group.collapsed .tg-chev .icon { transform: rotate(-90deg); }
.tg-main { display: flex; align-items: center; gap: 8px; min-width: 0; }
.tg-dot { flex: none; width: 8px; height: 8px; border-radius: 3px; }
.tg-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tg-count { font-weight: 500; color: var(--text-faint); }
.tg-time, .tg-money { font-weight: 500; color: var(--text-faint); text-align: right; font-variant-numeric: tabular-nums; }
.tg-time { grid-column: 4; }
.tg-money { grid-column: 5; }
/* Пусто — заголовки колонок и сам список уступают место пустому экрану. */
#sidebar:has(> #sidebar-empty:not([hidden])) > .tl-head,
#sidebar-empty:not([hidden]) ~ #task-list { display: none; }
/* Компактный (фильтр мимо) — тоже посередине острова, как большой. */
#sidebar > .empty-state-sm { flex: 1; }

/* ---------- Страница задачи ----------
   Крошки сверху; слева остров с названием, тегами и редактором; справа
   таймер (квадратная кнопка, время, деньги) и остров «Свойства / История». */
#task-view { display: flex; flex-direction: column; gap: 6px; overflow: hidden; }
#task-view[hidden] { display: none !important; }
.task-crumbs { display: flex; align-items: center; gap: 6px; padding: 4px 4px 0; font-size: 12.5px; color: var(--text-faint); flex: none; min-width: 0; }
#task-back { width: 28px; height: 28px; margin-left: -6px; }
.crumb { border: 0; background: none; padding: 0; font: inherit; color: var(--text-faint); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 240px; }
.crumb:hover { color: var(--text); }
.crumb-cur { color: var(--text-dim); cursor: default; }
.crumb-sep { color: var(--text-faint); }
.task-grid { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--gap); }
.task-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: 18px 22px; gap: 10px; }
.task-title-row { display: flex; align-items: center; gap: 8px; }
#task-title {
  flex: 1; min-width: 140px; font-size: 22px; font-weight: var(--fw-display);
  border: none; background: transparent; color: var(--text); padding: 2px 0; outline: none;
  /* Длинное название вне фокуса — одной строкой с многоточием, а не обрезанное
     по краю поля. В фокусе поле обычное: иначе на месте курсора стояло бы
     многоточие, а не конец текста. */
  text-overflow: ellipsis;
}
#task-title:focus { text-overflow: clip; }
.tab-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; }
#tab-history { overflow-y: auto; }
.task-side { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; overflow-y: auto; }
.task-timer-island { padding: 14px 16px; flex: none; }
.timer-bar { display: flex; align-items: center; gap: 12px; }
.timer-block { display: flex; flex-direction: column; min-width: 0; }
.timer-display { font-size: 28px; font-weight: var(--fw-display); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; line-height: 1; }
.timer-line { display: flex; align-items: baseline; gap: 6px; margin-top: 4px; font-size: 12.5px; color: var(--text-dim); white-space: nowrap; }
.timer-earned { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums; }
.timer-rate { color: var(--text-faint); }
.timer-sub { font-size: 12px; color: var(--text-faint); margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
.timer-sub[hidden] { display: none; }
.timer-btn-icon { display: inline-flex; }
#timer-btn-label {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.task-props-island { padding: 10px 16px 12px; flex: 1; display: flex; flex-direction: column; min-height: 0; }
.task-tabs { align-self: stretch; flex: none; }
.task-tabs button { flex: 1; justify-content: center; }
#task-props { display: flex; flex-direction: column; flex: 1; min-height: 0; }
#task-props[hidden] { display: none; }
/* Свойства — как на телефоне (13 октября): статус и версия чипами, теги
   бейджами и «+ теги», дальше группы строк «название · значение ›» —
   «Когда», «Напоминания», «Ещё» (.sgroup, .srow в компонентах). Разметку
   собирает app.js (taskParamsHtml); тот же узел одалживает окно задачи с
   календаря — там он такой же. */
.task-params { display: flex; flex-direction: column; padding-bottom: 12px; }
.task-params > .sgroup-label:first-child { margin-top: 12px; }
.tp-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-width: 0; }
.tp-chips[hidden] { display: none; }
.tp-chips .dp-btn { display: inline-flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; height: 28px; padding: 0 10px; font-size: 12.5px; }
.tp-chip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Колонка узкая (300 px): «Пн, Ср 10:00–12:00 +1» или «как у проекта —
   5 000 ₽/ч» в одну строку рядом с названием не помещаются — значение и
   подстрока переносятся на вторую строку, а не режутся многоточием посреди
   времени. Дальше двух строк — многоточием. */
.task-params .srow-value, .task-params .srow-sub {
  white-space: normal; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
/* Бейджи тегов стоят в том же ряду, что и «+ теги»: обёртка ряду не мешает. */
.tp-chips > .tag-chips { display: contents; }
/* «+ теги» — чип, как на телефоне: слово строчными (подпись группы над ним
   с заглавной). */
.tp-chips .tp-tag-add .icon { width: 11px; height: 11px; flex: none; }
.tp-tag-add span { text-transform: lowercase; }
/* Срок жирным и цветом своего состояния, как в строках задач: просрочен —
   --danger, в пределах суток — --accent-ink. */
#due-value.set { color: var(--text); font-weight: 600; }
#due-value.soon { color: var(--accent-ink); }
#due-value.overdue { color: var(--danger); }
/* «Выполнено» и «Удалить задачу» — парой внизу панели. Дублировать — в меню
   «⋯» задачи (крошки сверху), как в меню на строке списка. */
.task-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; padding-top: 10px; border-top: 1px solid var(--line); }
.task-actions .ghost, .task-actions .danger { flex: 1 1 calc(50% - 3px); }
/* Меню задачи — у правого края строки крошек. */
.task-crumbs .task-more { margin-left: auto; flex: none; }
/* Галочка чек-листа в редакторе на десктопе и в вебе под мышью — 22 px в
   кнопке 36 px (13 октября 2026): 24/44 — размер под палец, под курсором
   он крупный. Телефон (и веб на сенсорном экране) остаются 24/44: сборка
   телефона берёт только раздел «Редактор», куда это правило не входит. */
@media (pointer: fine) {
  #editor-wrap .led, #doc-editor-wrap .led { --led-task: 22px; --led-task-hit: 36px; }
}

/* ---------- История записей (правая панель задачи) ---------- */
.history-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; margin: 10px 0 4px; }
.history-head h2 { margin: 0; font-size: 13px; font-weight: var(--fw-display); }
.history-head .h-count { font-size: 12px; font-weight: 500; color: var(--text-faint); margin-left: 4px; }
/* Обе кнопки — один класс .btn-soft: «+ Запись» и «Excel» были разной высоты и
   вида (вторая — серая .ghost без иконки), и в одной строке это читалось как
   случайность. */
.history-actions { display: flex; gap: 6px; }
/* Кнопки записи скруглены крупнее (--radius, 13 октября 2026) — как квадрат
   таймера над ними. Общий .btn-soft не трогается: он скруглён, как поля. */
.history-actions .btn-soft { display: inline-flex; align-items: center; gap: 5px; border-radius: var(--radius); }
.history-actions .btn-soft .icon { width: 12px; height: 12px; }
/* Недоступная кнопка (у задачи нет записей — выгружать нечего) гаснет, как гасла
   серая .ghost. Правило не общее, а по месту: селектор `.btn-soft` попадает в
   стили редактора телефона (scripts/build-editor.js), и ради гаснущей кнопки
   истории пересобирать редактор незачем. */
.history-actions .btn-soft:disabled { opacity: 0.45; cursor: default; }
.history-actions .btn-soft:disabled:hover { background: var(--panel-2); }
.history-actions .btn-soft:disabled:active { transform: none; }
#session-list { list-style: none; margin: 0; padding: 0; }
.session-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 9px 0; font-size: 12.5px; border-bottom: 1px solid var(--line);
  animation: tileIn 0.18s var(--ease) backwards;
}
.session-item:last-child { border-bottom: none; }
.session-when { color: var(--text-dim); cursor: pointer; transition: color 0.1s var(--ease); }
.session-when:hover { color: var(--text); }
.session-side { display: flex; align-items: center; gap: 8px; }
.session-dur { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 13px; font-variant-numeric: tabular-nums; }
.session-del {
  border: none; background: transparent; color: var(--icon); cursor: pointer; padding: 0 3px; line-height: 1;
  display: inline-flex; align-items: center; transition: color 0.1s var(--ease);
}
.session-del .icon { width: 13px; height: 13px; color: inherit; }
.session-del:hover { color: var(--danger); }
.spacer { flex: 1; }

/* Узкое окно: правые колонки встают под основное, список и задача — одним
   столбцом. */
@media (max-width: 900px) {
  /* #docs-view — не для красоты: раздел «Документы» описан ниже, и голый
     .docs-grid перебивался его же правилом — сетка не складывалась, и
     пустой экран на телефоне уезжал за край. */
  #home-view, .proj-list, .task-grid, #docs-view .docs-grid { grid-template-columns: minmax(0, 1fr); }
  .docs-side { max-height: 40vh; }
  .home-side, .proj-side, .task-side { overflow: visible; margin-right: 0; }
  .tl-head, .task-item, .task-group { grid-template-columns: 22px minmax(0, 1fr) 72px; }
  .tl-head span:nth-child(3), .ti-due, .tl-head span:nth-child(5), .ti-money, .tg-money { display: none; }
  .tg-time { grid-column: 3; }
}

/* ---------- Документы ----------
   Слева остров со списком (поиск, фильтр по проекту), справа — документ:
   название, проект, закрепление и тот же редактор, что в заметках задачи. */
#docs-view { display: flex; flex-direction: column; overflow: hidden; }
#docs-view[hidden] { display: none !important; }
.docs-grid { flex: 1; min-height: 0; display: grid; grid-template-columns: 280px minmax(0, 1fr); gap: var(--gap); }
.docs-side { display: flex; flex-direction: column; gap: 10px; min-height: 0; padding: 16px 12px 12px; }
.docs-side-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 0 4px; }
.docs-side-head .page-title { font-size: 20px; }
/* Поиск: лупа внутри поля слева (та же иконка, что в поиске шапки), текст
   отступает под неё. Лупа не ловит щелчки — они идут в поле. */
.docs-search-box { position: relative; }
.docs-search-box .icon { position: absolute; left: 9px; top: 50%; width: 14px; height: 14px; margin-top: -7px; color: var(--icon); pointer-events: none; }
.docs-search { width: 100%; box-sizing: border-box; padding-left: 30px; }
.doc-list { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; margin: 0 -4px; padding: 0 4px; }
.doc-item { display: flex; flex-direction: column; gap: 3px; width: 100%; padding: 8px 10px; border: 0; border-radius: var(--radius-sm); background: none; color: var(--text); font: inherit; text-align: left; cursor: pointer; transition: background 0.1s var(--ease); }
.doc-item:hover { background: var(--panel-2); }
.doc-item.active { background: var(--nav-active-bg); }
.doc-item-title { display: flex; align-items: center; gap: 6px; font-size: 13.5px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.doc-pin { width: 12px; height: 12px; color: var(--text-faint); flex: none; }
.doc-item-meta { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Поиск мимо — список пуст и уступает место пустому экрану под фильтром. */
.doc-list:empty { display: none; }
.docs-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: 0; overflow: hidden; }
.docs-doc { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.docs-doc[hidden] { display: none; }
.doc-head { display: flex; align-items: center; gap: 8px; padding: 14px 18px 4px; flex: none; }
.doc-title { flex: 1; min-width: 120px; font-family: var(--font-display); font-size: 22px; font-weight: 700; border: 0; background: none; color: var(--text); outline: none; padding: 2px 0; }
.doc-title::placeholder { color: var(--text-faint); }
#doc-pin.on { color: var(--text); background: var(--panel-2); }
#doc-project.empty { color: var(--text-faint); }
#doc-editor-wrap { flex: 1; min-height: 0; display: flex; flex-direction: column; }

/* ---------- Сегодня ---------- */

.h-count { font-size: 15px; font-weight: 500; color: var(--text-dim); margin-left: 4px; }

.linklike {
  border: none; background: none; padding: 0; cursor: pointer;
  font-family: inherit; font-size: 12px; color: var(--text-faint);
  transition: color 0.12s var(--ease);
}
.linklike:hover { color: var(--text); }

/* День: заголовок, записано за день, лента записей по часам. Лента —
   поле внутри острова, записи на ней — ступень выше, идущая — акцент. */
.day-island { padding: 16px 20px 14px; flex: none; }
.day-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; }
.day-title { margin: 0; font-size: 20px; font-family: var(--font-display); font-weight: var(--fw-display); }
.day-sub { color: var(--text-dim); margin-top: 3px; font-size: 13px; }
.day-sub b { font-family: var(--font-display); font-weight: var(--fw-display); color: var(--text); font-variant-numeric: tabular-nums; }
.day-actions { display: flex; gap: 6px; flex: none; }
.day-actions .btn-soft { display: inline-flex; align-items: center; gap: 5px; }
.day-actions .btn-soft .icon { width: 12px; height: 12px; }
/* «Запись» и «Открыть день» — кнопки записи: скругление --radius, как у
   квадрата таймера (13 октября 2026). */
.day-actions .btn-soft, .day-actions .ghost { border-radius: var(--radius); }
.day-track { position: relative; height: 54px; border-radius: var(--radius-sm); background: var(--panel-2); margin-top: 12px; overflow: hidden; }
.day-grid { position: absolute; inset: 0; display: flex; }
.day-grid i { flex: 1; border-right: 1px solid var(--line); }
.day-grid i:last-child { border-right: 0; }
/* Запись — цветом своего проекта (--pc ставит renderDayIsland), как событие в
   панели «Время» (.ag-ev): полоса слева чистым цветом, заливка и подпись — из
   него же, смешанные с землёй (--tag-ink подобран под обе темы). Чистый неон
   заливкой смешался бы с идущей записью — та одна на ленте и зелёная. */
.day-blk {
  position: absolute; top: 7px; bottom: 7px; min-width: 3px;
  border: 0; border-left: 3px solid var(--pc, var(--accent)); border-radius: 7px; padding: 0 8px;
  background: color-mix(in srgb, var(--pc, var(--accent)) 22%, var(--panel-2));
  color: color-mix(in srgb, var(--pc, var(--accent)) var(--tag-ink), var(--text));
  font-family: inherit; font-size: 12px; font-weight: 600; text-align: left;
  display: flex; align-items: center; white-space: nowrap; overflow: hidden; cursor: pointer;
}
.day-blk.run { border-left: 0; background: var(--accent); color: var(--accent-text); }
.day-now { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--danger); border-radius: 1px; pointer-events: none; }
.day-hours { display: flex; margin-top: 6px; }
.day-hours span { flex: 1; font-size: 12px; color: var(--text-faint); }

/* Числа: сегодня, неделя, месяц — один остров, три колонки через линию. */
.kpi-island { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); flex: none; }
.kpi { padding: 14px 20px; min-width: 0; }
.kpi + .kpi { border-left: 1px solid var(--line); }
.kpi-label { font-size: 12px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.07em; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kpi-num { display: block; font-family: var(--font-display); font-weight: var(--fw-display); font-size: 22px; margin-top: 5px; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.kpi-sub { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 13.5px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.kpi-sub .muted { font-family: var(--font-ui); font-weight: var(--fw-text); font-size: 12px; color: var(--text-faint); }

#home-projects, #home-recent, .now-island { padding: 14px 16px; flex: none; }
#home-due { padding: 14px 16px; flex: 1; }
#home-recent { flex: 1; }
.home-proj-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-top: 10px; }
.hp-card { display: block; padding: 12px 14px; border-radius: var(--radius-sm); background: var(--panel-2); color: var(--text); text-align: left; border: 0; font-family: inherit; cursor: pointer; min-width: 0; transition: background 0.12s var(--ease); }
.hp-card:hover { background: var(--raise); }
.hp-head { display: flex; align-items: center; gap: 8px; }
.hp-dot { width: 8px; height: 8px; border-radius: 3px; flex: none; background: var(--pc, var(--accent)); }
.hp-name { font-weight: 600; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 13.5px; }
.hp-figs { display: flex; justify-content: space-between; gap: 8px; font-size: 12.5px; color: var(--text-dim); margin: 6px 0; font-variant-numeric: tabular-nums; }
.hp-figs b { font-family: var(--font-display); font-weight: var(--fw-display); color: var(--text); }
.hp-bar { display: block; height: 4px; border-radius: 2px; background: var(--raise); overflow: hidden; }
.hp-bar i { display: block; height: 100%; background: var(--pc, var(--accent)); }

/* Идущая задача: подпись акцентом, квадрат стоп, время и деньги. Когда
   таймер стоит — та же карточка с последней задачей и плеем. */
.now-label { font-size: 12px; text-transform: uppercase; letter-spacing: 0.07em; font-weight: 600; color: var(--accent-ink); }
.now-island.idle .now-label { color: var(--text-faint); }
.now-title { display: block; width: 100%; text-align: left; border: 0; background: none; padding: 0; margin-top: 6px; font-family: inherit; font-weight: 600; font-size: 14px; color: var(--text); cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.now-proj { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-faint); margin-top: 2px; white-space: nowrap; overflow: hidden; }
/* Плей, время и «Открыть» — одной строкой: на Onest цифры шире, чем были
   на Basique, и с переносом «Открыть» уезжала под время. */
.now-row { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.now-row .btn-soft { border-radius: var(--radius); }
.now-figures { min-width: 0; }
.now-time { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 24px; line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.now-money { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 13px; color: var(--text-dim); margin-top: 3px; font-variant-numeric: tabular-nums; }

/* ---------- Проекты ---------- */

/* Ряд больших карточек, как колода на телефоне: карточка — проект со
   своими задачами. Не влезли — ряд листается вбок (стрелки по краям,
   тачпад, Shift+колесо) и встаёт по краю карточки; край, за которым есть
   ещё карточки, растворяется — «Край ленты» в компонентах. Высота ряда —
   экран без шапки и строки таблицы недавних, но не ниже, чем нужно на пять
   задач. */
/* Ряд — до края окна: карточка, ушедшая вправо, видна до самого края, а
   в конце ряда последняя карточка встаёт с полем --gap. Это отступ
   обёртки, а не ряда: стрелка справа встаёт на поле ряда, а не на край окна. */
.projects-deck-host { flex: none; margin-right: calc(var(--gap) * -1); }
.projects-deck-host .edge-btn[data-side="r"] { right: calc(var(--gap) + 12px); }
.projects-deck-host:has(> .projects-deck:empty) { display: none; }
.projects-deck {
  display: flex; gap: var(--gap);
  padding-right: var(--gap);
  height: clamp(440px, calc(100vh - 230px), 680px);
  overflow-x: auto; overflow-y: hidden;
  scroll-snap-type: x proximity; scroll-padding-inline: 0;
  overscroll-behavior-x: contain;
}
.projects-deck:empty { display: none; }
.ptile {
  flex: 0 0 320px;
  scroll-snap-align: start;
  background: var(--panel);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  min-width: 0; min-height: 0;
  overflow: hidden;
  color: var(--text);
  animation: tileIn 0.24s var(--ease) backwards;
}
.ptile-head { display: flex; align-items: center; gap: 10px; min-width: 0; padding: 14px 12px 6px 16px; cursor: pointer; border-radius: var(--radius) var(--radius) 0 0; }
.ptile-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.ptile-dot { width: 11px; height: 11px; border-radius: 4px; flex: none; background: var(--pc, var(--accent)); }
.ptile-title { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ptile-name { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 17px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ptile-head:hover .ptile-name { text-decoration: underline; text-decoration-color: var(--border-strong); text-underline-offset: 3px; }
.ptile-sub { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; }
.ptile-sub .icon { width: 11px; height: 11px; flex: none; }
.ptile-due { font-weight: 600; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; }
.ptile-due.soon { color: var(--accent-ink); }
.ptile-due.overdue { color: var(--danger); }
.ptile-chev { display: inline-flex; color: var(--text-faint); flex: none; }
.ptile-chev .icon { width: 13px; height: 13px; }
/* Меню проявляется по наведению, чтобы не шуметь в ряду. Закрепление —
   пунктом меню: закреплённый проект встаёт в левое меню, а не на карточку. */
.ptile-menu { opacity: 0; transition: opacity 0.12s var(--ease); }
.ptile:hover .ptile-menu, .ptile-menu.open, .ptile-menu:focus-visible { opacity: 1; }
.ptile-figs { display: flex; align-items: baseline; gap: 8px; padding: 4px 16px 8px; font-variant-numeric: tabular-nums; }
.ptile-time { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 20px; }
.ptile-money { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 13px; color: var(--text-dim); }
.ptile-progress { display: block; flex: none; height: 4px; margin: 0 16px; border-radius: 2px; background: var(--panel-2); overflow: hidden; }
.ptile-progress > i { display: block; height: 100%; background: var(--pc, var(--accent)); transition: width 0.3s var(--ease); }
/* Поле новой задачи — сразу под шкалой, как на телефоне. */
.ptile-qa { display: flex; gap: 6px; margin: 12px 10px 4px; flex: none; }
.ptile-qa .field { flex: 1; min-width: 0; font-size: 13.5px; }
/* Задачи — своей прокруткой; строка — общий список строк (.row-list). */
.ptile-tasks { flex: 1; min-height: 0; overflow-y: auto; margin: 0; padding: 0 0 0 6px; }
.ptile-tasks li { padding: 8px 8px 8px 10px; border-radius: var(--radius-sm); transition: opacity 0.24s var(--ease), transform 0.24s var(--ease); }
.ptile-tasks li:hover { background: var(--panel-2); }
.ptile-tasks li + li { border-top-color: var(--line); }
.ptile-tasks li.leaving { opacity: 0; transform: scale(0.9); }
/* Задач нет — компактный пустой экран по центру поля задач. */
.ptile-tasks li.ptile-empty { justify-content: center; min-height: 100%; padding: 0; cursor: default; }
.ptile-tasks li.ptile-empty:hover { background: none; }
/* Карточки собираются заново на каждую перерисовку; осевший экран
   (.settled) сценку не проигрывает — как и сами карточки. */
.view.settled .ptile-empty .es-art, .view.settled .ptile-empty .es-mark, .view.settled .ptile-empty .es-on-mark { animation: none; }
.ptile-task .rl-name { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.ptile-task .rl-sub { margin-top: 2px; gap: 5px; }
.ptile-status { display: inline-flex; align-items: center; gap: 5px; color: var(--text-dim); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ptile-running { color: var(--accent-ink); font-weight: 600; }
.ptile-sep { color: var(--text-faint); }
.ptile-task .task-time { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.ptile-task .rl-play { width: 34px; height: 34px; background: var(--panel-2); color: var(--text); }
.ptile-task .rl-play:hover { background: var(--raise); }
.ptile-task .rl-play.run { background: var(--accent); color: var(--accent-text); }
.ptile-task .rl-play.run .icon { color: inherit; }
/* Закрытые задачи — под открытыми, как на телефоне (13 октября 2026):
   выполненные серые и зачёркнутые, с отмеченной галочкой; отменённые — в
   самом низу, серые без зачёркивания, на месте галочки серый крестик. */
.ptile-task.done .rl-name { color: var(--text-faint); text-decoration: line-through; }
.ptile-task.cancelled .rl-name { color: var(--text-faint); }
.ptile-task.done .rl-sub, .ptile-task.cancelled .rl-sub { opacity: 0.7; }
.ptile-x { display: inline-grid; place-content: center; flex: none; width: 16px; height: 16px; color: var(--text-faint); }
.ptile-x .icon { width: 10px; height: 10px; color: inherit; }
.ptile-open {
  flex: none; display: flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 44px; border: 0; border-top: 1px solid var(--line); background: none;
  color: var(--text-dim); font: 600 13px var(--font-ui); cursor: pointer;
}
.ptile-open:hover { color: var(--text); background: var(--panel-2); }
.ptile-open .icon { width: 12px; height: 12px; }

#recent-section { padding: 12px 6px 6px; flex: none; }
#recent-section .island-head { padding: 0 12px 6px; }
.recent-head, .recent-row { display: grid; grid-template-columns: 32px minmax(0, 1fr) 150px 90px 100px; align-items: center; gap: 12px; padding: 6px 12px; }
.recent-head { font-size: 12px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
.recent-head span:nth-child(4), .recent-head span:nth-child(5) { text-align: right; }
.recent-row { padding: 9px 12px; border: 0; border-top: 1px solid var(--line); border-radius: 0; background: none; cursor: pointer; color: var(--text); text-align: left; font-family: inherit; width: 100%; font-size: 13.5px; }
.recent-row:hover { background: var(--panel-2); }
.recent-main { min-width: 0; }
.recent-name { display: block; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.recent-sub { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-faint); white-space: nowrap; overflow: hidden; }
.recent-when { font-size: 12.5px; color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.recent-when.run { color: var(--accent-ink); }
.recent-num { font-family: var(--font-display); font-weight: var(--fw-display); font-size: 13px; text-align: right; font-variant-numeric: tabular-nums; }
.recent-num.money { color: var(--text-dim); }

/* ---------- Полный календарь ---------- */

/* ---------- Раздел «Время» ----------
   Шапка-остров: режимы, «Сегодня», стрелки, название периода, «Выбрать
   период» (в месяце), фильтр проекта, «скрыть статистику», «Запись», Excel.
   Ниже слева — числа и сетка (часовая или итогов), справа — день. Со
   спрятанной статистикой остаются только шапка и сетка. */
#time-view { display: flex; flex-direction: column; gap: var(--gap); overflow: hidden; }
#time-view[hidden] { display: none !important; }
.time-head { flex: none; margin-bottom: 0; padding: 10px 14px; flex-wrap: wrap; row-gap: 8px; }
.time-head .period-title { min-width: 0; font-size: 18px; }
.time-head .filter-bar { margin: 0; }
/* Фильтр в шапке без подписи «Проект»: значение («Все проекты», имя) само за
   себя говорит, а место в строке на счету. */
.time-head .filter-bar .fchip-k { display: none; }
/* «Экспорт» и «+ Запись» — одна пара: одна высота и форма, разный вес.
   Запись — главная кнопка экрана, выгрузка — вторичная. */
.time-head .btn-accent, .time-head .time-export { height: 30px; padding: 0 12px; font-size: 12.5px; }
.time-head .time-export { font-weight: 500; }
.time-head .btn-accent .icon { width: 12px; height: 12px; }
#time-stats-toggle[aria-pressed="true"] { background: var(--panel-2); color: var(--text); }
.time-body { flex: 1; min-height: 0; display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: var(--gap); }
.time-main { display: flex; flex-direction: column; gap: var(--gap); min-height: 0; min-width: 0; container-type: inline-size; }
#time-view.stats-hidden .time-kpis, #time-view.stats-hidden .cal-day { display: none; }
#time-view.stats-hidden .time-body { grid-template-columns: minmax(0, 1fr); }
/* Числа — один остров, четыре колонки через линию. */
.time-kpis { flex: none; padding: 8px 10px; display: flex; align-items: center; gap: 12px; }
.time-kpis .stat-cards { flex: 1; gap: 0; }
.time-kpis .stat-card { background: none; border-radius: 0; padding: 6px 14px; }
.time-kpis .stat-card + .stat-card { border-left: 1px solid var(--line); }
/* Выгрузки здесь нет: она одна на раздел — кнопка «Экспорт» в шапке.
   В узкой колонке числа — две на две. */
@container (max-width: 720px) {
  .time-kpis { flex-wrap: wrap; row-gap: 4px; }
  .time-kpis .stat-cards { flex-basis: 100%; row-gap: 4px; }
  .time-kpis .stat-card + .stat-card { border-left: 0; }
  .time-kpis .stat-card:nth-child(even) { border-left: 1px solid var(--line); }
}
/* На узком окне панель дня — под сеткой. */
@media (max-width: 900px) {
  .time-body { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr) auto; }
  #time-view .cal-day { max-height: 36vh; }
}
.ag-main { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 12px 12px 0; }
.cal-main { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 12px; overflow-y: auto; }
/* Строка над сеткой месяца: переключатель периода и, когда он включён,
   границы с итогом. Период выбирается на самом календаре. */
.period-bar { display: flex; align-items: center; gap: 14px; padding: 0 2px 10px; font-size: 13px; flex: none; }
.period-bar .switch { font-size: 12.5px; }
.period-bar-info { display: inline-flex; align-items: center; gap: 8px; }
.period-bar b { font-weight: 600; }

.cal-range { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-dim); margin: -4px 0 10px; }
.cal-range.anim { animation: rangeIn 0.22s var(--ease); }
/* Границы периода — показания, а не кнопки: даты набираются кликами по
   большому календарю ниже. Обводка нейтральная, без акцента, чтобы их не
   принимали за элемент управления. */
.cal-range-val {
  min-width: 116px;
  padding: 5px 10px;
  border: 0;
  border-radius: 6px;
  background: var(--panel-2);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

@keyframes rangeIn { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }

/* Выбор времени — 13 октября 2026: поле и под ним подсказки, один на все
   места (запись, отрезок, напоминание, дедлайн). Поле — общее компактное
   (.field-sm); подсказки — колонка через 15 минут вокруг значения, своей
   прокруткой; выбранная — как выбранный день, под стрелками — как под
   указателем. Окно встаёт над окном даты, если его открыли оттуда. */
.tp-pop {
  position: fixed;
  z-index: 120;
  display: flex;
  flex-direction: column;
  gap: 6px;
  width: 132px;
  background: var(--panel);
  border: 0;
  border-radius: 12px;
  box-shadow: var(--shadow-pop);
  padding: 8px;
  animation: popIn 0.14s var(--ease);
}
.tp-input { width: 100%; text-align: center; font-variant-numeric: tabular-nums; }
.tp-input.bad { box-shadow: inset 0 0 0 1.5px var(--danger); }
.tp-list { position: relative; max-height: 196px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.tp-opt {
  flex: none;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  padding: 6px 0;
  border-radius: 6px;
  cursor: pointer;
  text-align: center;
  transition: background 0.1s var(--ease), color 0.1s var(--ease);
}
.tp-opt:hover, .tp-opt.cur { background: var(--panel-2); }
.tp-opt.sel { background: var(--accent); color: var(--accent-text); font-weight: 500; }

.dp-pop {
  position: fixed;
  z-index: 120;
  width: 232px;
  background: var(--panel);
  border: 0;
  border-radius: 12px;
  /* Окно лежит на правой колонке того же цвета — без тени его края не видно. */
  box-shadow: var(--shadow-pop);
  padding: 10px;
  animation: popIn 0.14s var(--ease);
}
.dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.dp-head span { font-size: 13px; font-weight: 500; }
.dp-weekdays, .dp-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dp-weekdays { font-size: 12px; color: var(--text-dim); text-align: center; margin-bottom: 4px; }
.dp-day {
  aspect-ratio: 1;
  border: none;
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 12px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.1s var(--ease), color 0.1s var(--ease);
}
.dp-day.empty { visibility: hidden; cursor: default; }
.dp-day:hover:not(.empty) { background: var(--border); }
.dp-day.today { outline: 1px solid var(--accent); }
.dp-day.sel { background: var(--accent); color: var(--accent-text); font-weight: 500; }
/* Время под календарём: кнопка с часами открывает общий выбор времени
   (.tp-pop) поверх окна даты. «Готово» и «Убрать» (только у дедлайна) —
   строкой во всю ширину под ней. */
.dp-time { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--border-soft); }
.dp-time-label { font-size: 12px; color: var(--text-dim); }
.dp-time .dp-time-btn { min-width: 0; margin-left: auto; padding: 5px 12px; font-size: 13px; font-variant-numeric: tabular-nums; }
.dp-time-actions { flex-basis: 100%; display: flex; gap: 6px; margin-top: 2px; }
.dp-done, .dp-clear { flex: 1; border: none; border-radius: 8px; padding: 7px 10px; font-family: inherit; font-size: 12.5px; cursor: pointer; }
.dp-done { background: var(--accent); color: var(--accent-text); font-weight: 600; }
.dp-clear { background: var(--panel-2); color: var(--text-dim); }
.dp-clear:hover { color: var(--text); }
.dp-clear[hidden] { display: none; }
.dp-done:hover { background: var(--accent-hover); }
.cal-weekdays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; font-size: 12px; color: var(--text-dim); padding: 0 2px 6px; }
.cal-days {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: 92px;
  align-content: start;
  gap: 6px;
  overflow-y: auto;
}
.cal-days.week { grid-auto-rows: minmax(220px, 1fr); }
/* Клетка — поле внутри острова (--panel-2), а не цвет самого острова: с
   заливкой --panel сетка месяца сливалась с фоном, и оставались одни числа.
   Рамки у клетки нет, поэтому наведение и «сегодня» — внутренней линией. */
.cal-cell {
  border: 0;
  background: var(--panel-2);
  border-radius: 9px;
  padding: 6px 8px;
  min-height: 84px;
  text-align: left;
  font-family: inherit;
  color: var(--text);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 2px;
  position: relative;
  overflow: hidden;
  transition: box-shadow 0.12s var(--ease), background 0.12s var(--ease);
}
.cal-cell.empty { background: none; cursor: default; }
.cal-cell:hover:not(.empty) { box-shadow: inset 0 0 0 1px var(--border-strong); }
.cal-cell.today { box-shadow: inset 0 0 0 1.5px var(--accent); }
.cal-cell.sel { outline: 2px solid var(--accent); outline-offset: -1px; }
/* Ячейки пересоздаются на каждый рендер (innerHTML='' + заново), поэтому
   переход (transition) между классами никогда не проигрывался — новый узел
   сразу появляется в финальном состоянии. Анимация (@keyframes) же
   проигрывается при монтировании независимо от истории элемента — этим и
   получаем "загорание" зелёным при каждом клике по диапазону. */
@keyframes cellGlow {
  from { background: var(--panel-2); border-color: var(--border); }
  to { background: color-mix(in srgb, var(--accent) 9%, var(--panel-2)); border-color: color-mix(in srgb, var(--accent) 35%, var(--border)); }
}
.cal-cell.in-range, .cal-cell.range-end {
  background: color-mix(in srgb, var(--accent) 9%, var(--panel-2));
  border-color: color-mix(in srgb, var(--accent) 35%, var(--border));
  animation: cellGlow 0.32s var(--ease);
}
.cal-cell.range-end { outline: 2px solid var(--accent); outline-offset: -1px; }
.cc-num { font-size: 12px; font-weight: 500; color: var(--text-dim); }
.cal-cell.today .cc-num { color: var(--accent-ink); }
/* Время и сумма в клетке — одной строкой каждое: в узкой клетке сумма
   ломалась на «3 750» и «₽» по разным строкам. Не влезло — обрезается. */
.cc-time { font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cc-money { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cc-bar { position: absolute; left: 0; bottom: 0; height: 3px; background: var(--accent); transition: width 0.3s var(--ease); }
.cc-done-badge {
  position: absolute; top: 6px; right: 7px;
  display: inline-flex; align-items: center; gap: 2px;
  font-size: 12px; color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  padding: 1px 6px; border-radius: 8px;
}
.cc-done-badge .icon { width: 9px; height: 9px; }
.cc-done-list { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; min-height: 0; overflow: hidden; }
.cc-done-item {
  display: flex; align-items: center; gap: 4px;
  font-size: 12px; color: var(--text-dim);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cc-done-item .icon { width: 10px; height: 10px; color: var(--accent-ink); flex: none; }

/* День — почасовая раскладка */
.cal-days.day { display: flex; flex-direction: column; gap: 2px; }
.hour-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 22px;
  flex-shrink: 0;
  padding: 2px 8px;
  border-radius: 6px;
  opacity: 0.5;
}
.hour-row.has { opacity: 1; background: var(--panel); border: 0; padding: 6px 8px; }
.hour-label { flex: none; width: 42px; font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.hour-chips { display: flex; flex-wrap: wrap; gap: 6px; flex: 1; }
.hour-chip {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  max-width: 100%;
  border: none;
  border-left: 3px solid var(--pc, var(--accent));
  background: var(--panel-2);
  border-radius: 6px;
  padding: 4px 9px;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
  color: var(--text);
  transition: background 0.1s var(--ease);
}
.hour-chip:hover { background: var(--border); }
.hour-chip b { font-size: 12px; font-weight: 500; }
.hour-chip span { font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* Сводка за период */
.period-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.period-list li {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  border: 0;
  border-radius: 8px;
  padding: 7px 10px;
  cursor: pointer;
  font-size: 12px;
  transition: background 0.1s var(--ease);
  animation: tileIn 0.18s var(--ease) backwards;
}
.period-list li:hover { background: var(--panel-2); }
.pl-check { color: var(--icon); flex: none; }
.pl-check.done { color: var(--accent-ink); }
.pl-check .icon { width: 13px; height: 13px; }
.pl-name { display: block; font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-proj { display: block; font-weight: var(--fw-text); color: var(--text-dim); font-size: 12px; margin-top: 1px; }
.pl-proj::before { content: ''; display: inline-block; width: 6px; height: 6px; border-radius: 2px; background: var(--pc, var(--accent)); margin-right: 4px; }
/* Справа, как в записях дня: длительность основным цветом, под ней деньги
   приглушённо. Деньги — обычным текстом, не акцентом. */
.pl-right { text-align: right; font-variant-numeric: tabular-nums; }
.pl-time { display: block; font-weight: 500; }
.pl-money { display: block; color: var(--text-dim); }

.cal-day {
  padding: 14px 16px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Колонка нужна только ради кнопки экспорта внизу; всё остальное должно
   сохранять свою высоту, иначе flex сожмёт список записей. */
.cal-day > * { flex: none; }
.cal-export {
  margin-top: auto;
  position: sticky;
  bottom: 0;
  width: 100%;
  justify-content: center;
  padding-top: 11px;
  padding-bottom: 11px;
}
.cal-day-list + .cal-export, .muted + .cal-export { margin-top: auto; }
.cal-view-tot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  background: var(--panel-2);
  border: 0;
  border-radius: 9px;
  padding: 9px 12px;
  margin-bottom: 16px;
  font-size: 12px;
  color: var(--text-dim);
}
/* Режим периода не заводит отдельную плашку: тот же блок итога меняет
   содержимое и обводится акцентом. Текст при этом остаётся обычным —
   зелёные цифры на светлой теме читались хуже чёрных. */
.cal-view-tot.period { background: var(--sel); }
.cal-view-tot b { color: var(--text); font-size: 13.5px; font-weight: 500; font-variant-numeric: tabular-nums; }
/* День: заголовок слева, итог справа — одной строкой. Длинному заголовку
   уступает место многоточие, а не итог: он не переносится и не уезжает. */
.cal-day-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 16px; }
.cal-day-head { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 16px; font-weight: 500; }
.cal-day-tot { flex: none; white-space: nowrap; font-size: 13px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.cal-day-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
/* Строка записи — две строки: задача и длительность, под ними интервал и
   деньги приглушённо. Подсвечивается заливкой: обводки у строк нет. */
.cal-day-list li {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: 2px 12px;
  border: 0; border-radius: 8px; padding: 7px 10px; cursor: pointer; font-size: 12px;
  transition: background 0.1s var(--ease);
  animation: tileIn 0.18s var(--ease) backwards;
}
.cal-day-list li:hover { background: var(--panel-2); }
/* Название задачи в записи — не больше трёх строк, дальше многоточие: длинное
   название раздувало запись на пол-панели и оттесняло остальные. */
.cdl-task {
  min-width: 0; font-size: 12.5px; font-weight: var(--fw-text); overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
.cdl-dur { font-variant-numeric: tabular-nums; font-weight: 500; white-space: nowrap; text-align: right; }
.cdl-time { color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cdl-money { text-align: right; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
.cdl-proj { display: inline-flex; align-items: center; gap: 4px; margin-left: 6px; font-weight: var(--fw-text); color: var(--text-dim); font-size: 12px; }
.cdl-proj::before { content: ''; width: 6px; height: 6px; border-radius: 2px; background: var(--pc, var(--accent)); }

/* ---------- Срок задачи ---------- */

/* Метка срока в списке задач: просрочено — --danger, в пределах суток —
   --accent-ink (тот же код, что у значения дедлайна в свойствах, #due-value). */
.task-due { flex: none; font-size: 12px; border-radius: 999px; padding: 2px 7px; background: var(--panel-2); color: var(--text-dim); white-space: nowrap; }
.task-due.soon { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent-ink); }
.task-due.overdue { background: color-mix(in srgb, var(--danger) 20%, transparent); color: var(--danger); }

/* ---------- Окно «Экспорт в Excel» ----------
   Два поля друг под другом — период и проекты, обе выпадашки на всю ширину
   (.dp-select) — и сводка того, что уйдёт в файл. Пара дат своего периода —
   тот же ряд из двух кнопок, что у времени записи (.sdlg-times). */

/* Точные даты выбранного периода под полем. Строка занимает место и
   пустой: иначе окно прыгало бы на «Всём времени», когда записей ещё нет. */
.exp-hint { min-height: 18px; margin-top: 6px; font-size: 12px; font-variant-numeric: tabular-nums; }
.exp-dates { margin-bottom: 2px; }
/* Сводка отделена чертой: это итог выбора, а не третье поле. Место под две
   строки закреплено: «Записей нет…» на узком окне переносится, и окно, растя
   посреди выбора, уезжало бы из-под открытого меню проектов. */
.exp-summary { margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--border); font-size: 13px; line-height: 1.4; box-sizing: content-box; min-height: 2.8em; color: var(--text); }
.exp-summary.empty { color: var(--text-dim); }
/* «Экспорт» без записей гаснет. Правило по id, а не общим .modal-buttons:
   такие селекторы попадают в стили редактора телефона, и ради одного окна
   пришлось бы пересобирать редактор. */
#expdlg-ok:disabled { opacity: 0.45; cursor: default; }
#expdlg-ok:disabled:hover { background: var(--accent); border-color: var(--accent); }
#expdlg-ok:disabled:active { transform: none; }

/* ---------- Страница статистики ---------- */

.stats-wrap { max-width: 760px; margin: 0 auto; padding: 24px 24px 40px; container-type: inline-size; }
.stats-wrap .stat-cards { margin-bottom: 14px; }
.stats-actions { display: flex; gap: 8px; margin-bottom: 18px; }
.stats-wrap .st-running { margin-bottom: 18px; }
.stats-list { list-style: none; margin: 0 0 6px; padding: 0; display: flex; flex-direction: column; }
.stats-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}
.stats-list li:first-child { border-radius: 10px 10px 0 0; }
.stats-list li:last-child { border-bottom: none; border-radius: 0 0 10px 10px; }
.stats-list li:only-child { border-radius: 10px; }
.stats-list li.clickable { cursor: pointer; }
.stats-list li.clickable:hover { background: var(--panel-2); }
.stats-dot { width: 8px; height: 8px; border-radius: 3px; flex: none; background: var(--pc, var(--accent)); }
.stats-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stats-val { flex: none; color: var(--text-dim); font-size: 12.5px; font-variant-numeric: tabular-nums; min-width: 76px; text-align: right; }
.stats-empty { color: var(--text-dim); text-align: center; padding: 28px 0; font-size: 13px; }

/* ---------- Страница настроек ----------
   Профиль-остров, под ним сетка островов два в ряд: Аккаунт, Основное,
   Данные, Уведомления, Работа, Теги; «О приложении» — на всю ширину, его
   строки в две колонки. Подпись раздела живёт внутри острова. */
.settings-wrap { max-width: 960px; width: 100%; margin: 0 auto; padding: 0 0 24px; display: flex; flex-direction: column; gap: var(--gap); }
.settings-profile { display: flex; align-items: center; gap: 14px; padding: 16px 18px; flex-wrap: wrap; }
.settings-avatar {
  width: 46px; height: 46px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--accent-text); font-size: 18px; font-weight: 700;
  font-family: var(--font-display);
}
.settings-avatar.guest { background: var(--panel-2); color: var(--text-dim); }
.settings-profile-main { flex: 1; min-width: 160px; }
.settings-profile-name { font-size: 15px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.settings-profile-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.settings-guest-actions { display: flex; gap: 8px; margin-left: auto; }
.settings-guest-actions button { justify-content: center; }

.settings-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap); align-items: start; }
#settings-view .settings-card { padding: 6px 0 2px; }
.settings-card-wide { grid-column: 1 / -1; }
.settings-rows-2col { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); column-gap: 24px; }
.settings-section-label {
  font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint); font-weight: 600;
  margin: 0; padding: 8px 16px 4px;
}
.settings-row {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  min-height: 44px;
  padding: 9px 16px;
  border: none;
  border-bottom: 1px solid var(--line);
  background: none;
  color: var(--text);
  font-family: inherit;
  font-size: 13px;
  text-align: left;
}
.settings-row-last, #settings-view .settings-card .settings-row:last-child { border-bottom: none; }
.settings-row .icon { width: 15px; height: 15px; flex: none; color: var(--icon); }
.settings-row-label { flex: 1; min-width: 0; }
.settings-row-value { color: var(--text-dim); font-size: 12.5px; }
/* Стрелка у строк, которые уводят наружу приложения: по ней видно, что нажатие
   откроет сайт, а не развернёт что-то на месте. */
.settings-row-arrow { margin-left: auto; width: 13px; height: 13px; color: var(--text-faint, var(--text-dim)); flex: none; }
.settings-row-btn:hover .settings-row-arrow { color: var(--text-dim); }
.settings-row-btn { cursor: pointer; transition: background 0.1s var(--ease); }
.settings-row-btn:hover { background: var(--panel-2); }
.settings-row-input { display: flex; align-items: center; gap: 6px; }
.settings-row-input input { width: 70px; text-align: right; }

.settings-row-danger .settings-row-label { color: var(--danger); }
.settings-row-danger .icon { color: var(--danger); }
.settings-row.switch { cursor: pointer; }
.settings-row.switch .switch-track { margin-left: auto; }
.settings-footer { display: flex; flex-wrap: wrap; justify-content: center; align-items: baseline; gap: 2px var(--gap); text-align: center; color: var(--text-faint); font-size: 12px; margin-top: 4px; }
.settings-footer .linklike:disabled { cursor: default; }
@media (max-width: 900px) {
  .settings-grid, .settings-rows-2col { grid-template-columns: minmax(0, 1fr); }
}

/* ---------- Проект: доска ---------- */

/* Колонки без собственной рамки и подложки: видимую форму держат карточки,
   а колонка — это только заголовок и отступ. Так доска остаётся спокойной
   при большом числе статусов, где сетка из рамок начинала бы рябить. */
/* Обёртка дорожек: держит стрелки «Края ленты» и занимает то, что занимали
   сами дорожки. Нет проекта — дорожки спрятаны, и обёртка тоже. */
.board-host { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.board-host:has(> .board-cols[hidden]) { display: none; }
.board-cols {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: stretch;
  /* Колонки стоят тесно, а воздух — внутри них, вокруг карточек: так видно,
     что карточка принадлежит колонке, а не висит между двумя. */
  gap: 8px;
  padding: 14px 16px 0;
  overflow-x: auto;
}
.board-col {
  flex: 0 0 272px;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border-radius: 10px;
  /* Все столбцы одного нейтрального цвета. Шесть разных размывок цветом
     статуса давали шесть разных фонов под одинаковыми белыми карточками:
     это читалось шумом, а не сведениями. Цвет статуса остался там, где он
     что-то значит — точка в заголовке и полоса на карточке.
     Столбец — углубление: темнее страницы, карточка поверх светлее их обоих,
     и три слоя различаются с одного взгляда в любой теме. */
  background: var(--board-col);
  transition: background 0.12s var(--ease);
}
/* Колонка под курсором во время переноса — единственное место, где цвет
   статуса заливает весь столбец: здесь он отвечает на вопрос «куда упадёт». */
.board-col.over { background: color-mix(in srgb, var(--sc, var(--accent)) 22%, var(--board-col)); }
.board-col-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 12px 10px;
}
.board-col-name { font-size: 12.5px; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-count { font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
/* Сумма времени прижата к правому краю заголовка: слева — что это за
   столбец, справа — сколько в нём работы. Между ними пусто, поэтому
   длинное название статуса сжимается, а не выталкивает сумму за край. */
.board-col-time { margin-left: auto; font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; flex: none; }
.board-col-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 10px 12px;
}
/* Добавление — такая же карточка, как задачи, только с плюсом по центру:
   она встаёт в тот же ряд и сразу читается как «здесь появится ещё одна».
   Появляется при наведении на любое место колонки. */
.board-add {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  border: 1px dashed var(--border);
  background: none;
  border-radius: 8px;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 17px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s var(--ease), color 0.12s var(--ease), border-color 0.12s var(--ease), background 0.12s var(--ease);
}
.board-col:hover .board-add, .board-add:focus-visible { opacity: 1; }
.board-add:hover { color: var(--text); border-color: var(--border-strong); background: var(--panel-2); }
.board-card {
  /* Своя поверхность, а не общая panel: на главной карточка проекта лежит
     на белой странице и потому чуть серая, а здесь — в сером углублении
     столбца, и потому белая. Правило одно: карточка на ступень светлее
     того, на чём лежит. */
  background: var(--board-card);
  border: 0;
  border-left: 3px solid var(--sc, var(--accent));
  border-radius: 8px;
  padding: 9px 10px;
  cursor: pointer;
  transition: border-color 0.12s var(--ease), opacity 0.12s var(--ease);
}
.board-card:hover { border-color: var(--border-strong); }
.board-card.dragging { opacity: 0.4; }
.board-card.done .bc-title { color: var(--text-dim); text-decoration: line-through; }
.bc-title { font-size: 13px; line-height: 1.35; }
.bc-foot { display: flex; align-items: center; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.bc-time { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.bc-time .icon { width: 10px; height: 10px; }
/* Деньги приглушены сильнее времени: на доске это справка, а не то, ради
   чего её открыли. Цифры моноширинные, чтобы столбец карточек читался
   колонкой, а не лесенкой. */
.bc-money { font-size: 12px; color: var(--text-faint); font-variant-numeric: tabular-nums; }

/* ---------- Настройка статусов проекта ---------- */

.modal-wide { width: min(560px, calc(100vw - 32px)); }
/* Окно проекта: все разделы одним списком с подзаголовками, как на телефоне.
   Окно — колонка: заголовок, середина (.pjdlg-body — её и прокручивают) и
   кнопки внизу, которые стоят на месте. Место под полосу вынесено в поле
   окна (margin-right), чтобы поля не сужались, когда полоса появляется. */
.pjdlg { display: flex; flex-direction: column; max-height: calc(100vh - 48px); }
.pjdlg-body { position: relative; flex: 1; min-height: 0; overflow-y: auto; }
.pjdlg .modal-title, .pjdlg .modal-buttons { flex: none; }
.pjdlg-sec > label:first-child { margin-top: 0; }
.pjdlg-sec + .pjdlg-sec { margin-top: 22px; }
.pjdlg-head { margin: 0 0 6px; }
.pjdlg-hint { margin: 8px 0 0; font-size: 12px; line-height: 1.5; }
.pjdlg .rate-row { display: flex; align-items: center; gap: 8px; }
.pjdlg .rate-row .field { width: 140px; }
.tag-pop-scope { min-width: 0; text-align: right; font-size: 12px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.st-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.st-row { display: flex; align-items: center; gap: 6px; }
.st-color {
  flex: none; width: 22px; height: 22px; border-radius: 6px;
  border: 0; background: var(--sc, var(--accent)); cursor: pointer;
}
/* Поле названия — общее компактное (.field-sm): своего вида у него нет,
   здесь только место в строке. */
.st-name { flex: 1; min-width: 0; }
.st-kind { flex: none; max-width: 170px; }
.st-del .icon { color: var(--danger); }
.st-row .icon-btn[disabled] { opacity: 0.35; cursor: default; }
/* «Новый статус» — тем же тихим приёмом, что и «Добавить задачу» на доске. */
.st-add {
  align-self: flex-start;
  border: none; background: none; border-radius: 6px;
  padding: 5px 6px; color: var(--text-dim);
  font-family: inherit; font-size: 12.5px; cursor: pointer;
  transition: color 0.12s var(--ease), background 0.12s var(--ease);
}
.st-add:hover { color: var(--text); background: var(--panel-2); }

/* Палитра у якоря — для цвета статуса. */
.color-pop {
  position: fixed;
  z-index: 120;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 5px;
  padding: 8px;
  background: var(--panel);
  border: 0;
  border-radius: 10px;
  box-shadow: var(--shadow);
  animation: popIn 0.14s var(--ease);
}
.color-dot {
  width: 20px; height: 20px; border-radius: 6px;
  border: 0; background: var(--sc); cursor: pointer;
  transition: transform 0.1s var(--ease);
}
.color-dot:hover { transform: scale(1.12); }

/* ---------- Задача, открытая с календаря ----------
   Верх окна — то, что нельзя поменять в параметрах: название, проект, итог.
   Ниже — запись, по которой щёлкнули, и следом переехавший сюда блок
   .task-params из вкладки задачи. */
.tmdlg { display: flex; flex-direction: column; gap: 10px; max-height: calc(100vh - 48px); overflow-y: auto; }
.tmdlg-head { display: flex; align-items: center; gap: 9px; }
.tmdlg-dot { flex: none; width: 10px; height: 10px; border-radius: 3px; background: var(--pc, var(--accent)); }
#tmdlg-title {
  flex: 1; min-width: 0;
  border: none; background: none; color: var(--text);
  font-family: var(--font-display); font-size: 18px; font-weight: 500;
  padding: 2px 0; outline: none;
  border-bottom: 1px solid transparent;
}
#tmdlg-title:focus { border-bottom-color: var(--border); }
.tmdlg-sub {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: -4px 0 0 19px; font-size: 12px; color: var(--text-dim);
}
.tmdlg-tot { margin-left: auto; font-variant-numeric: tabular-nums; }

/* Строка записи: та же тройка кнопок, что в окне правки времени, но править
   можно не выходя из задачи. */
.tmdlg-entry {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  padding: 9px 11px;
  background: var(--panel-2); border-radius: 9px;
}
.tmdlg-entry-label {
  flex: none; font-size: 12px; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--text-faint);
}
.tmdlg-dash { color: var(--text-dim); }
/* Три кнопки, подпись и длительность должны помещаться в одну строку: с
   общей минимальной шириной .dp-btn в 116px строка переносилась пополам. */
.tmdlg-entry .dp-btn { min-width: 0; padding: 5px 8px; }
.tmdlg-dur { margin-left: auto; font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.tmdlg-entry .icon-btn { flex: none; }

/* .task-params приехал сюда целиком — ему нужен только сброс внешних отступов
   вкладки, всё остальное у него своё. */
.tmdlg-params > .task-params { margin: 0; }

/* Модалка задачи в режиме черновика: подсказка сверху, проект переключаемой
   кнопкой и список подходящих существующих задач под названием. */
.tmdlg-kicker {
  font-size: 12px; letter-spacing: 0.6px; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: -4px;
}
.tmdlg-proj { display: inline-flex; align-items: center; min-width: 0; max-width: 220px; }
.tmdlg-proj:disabled {
  border-color: transparent; background: none; padding-left: 0; cursor: default;
  color: var(--text-dim); font-size: 12px;
}
.tmdlg-found { display: flex; flex-direction: column; gap: 4px; }
.tmdlg-found-label {
  font-size: 12px; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--text-faint);
}
.tmdlg-found .tag-pop-list { padding: 0; max-height: 140px; }

/* ---------- Версии ---------- */
/* Версия принадлежит проекту, а не всему приложению, как тег. На доске версии
   показываются дорожками: полоса на версию, внутри полосы — те же столбцы
   статусов. Пока версий нет, доска остаётся ровно такой, какой была. */
.board-cols.has-lanes {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 16px;
  padding-bottom: 16px;
  overflow: auto;
}
/* Полоса шире окна, когда столбцов много: ширину ей задаёт содержимое, иначе
   столбцы вылезали бы за пределы дорожки, а не прокручивались вместе с ней. */
/* Дорожка шириной по содержимому — иначе столбцы вылезали бы за неё, а не
   прокручивались вместе с ней. */
.board-lane { width: max-content; min-width: 100%; display: flex; flex-direction: column; }
.board-lane-cols { display: flex; align-items: stretch; gap: 8px; }
/* Столбец в дорожке живёт по высоте содержимого: дорожка — это полоса, а не
   вся страница, и растягивать её до низа экрана незачем. */
.board-lane-cols .board-col { min-height: 88px; }

/* Заголовок — полоса во всю видимую ширину доски, и он остаётся на месте
   при сдвиге вправо: иначе к дальним столбцам теряется единственное, что
   говорит, какая это версия.
   И ширина, и удержание — замером в app.js, потому что чистым CSS ни то ни
   другое не выражается: дорожка шире окна, проценты считались бы от неё, а
   position: sticky двигает элемент только внутри его дорожки — заголовку
   шириной с неё сдвигаться уже некуда. Поэтому ширина приходит в --lane-w,
   а горизонтальный сдвиг гасится обратным translate по --lane-x. */
.board-lane-head {
  position: relative;
  z-index: 1;
  transform: translateX(var(--lane-x, 0px));
  display: flex;
  align-items: center;
  gap: 8px;
  width: var(--lane-w, 100%);
  margin: 0 0 6px;
  padding: 5px 10px 5px 6px;
  border: none;
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
  transition: background 0.12s var(--ease);
}
.board-lane-head:hover { background: var(--panel-2); }
/* Заголовок принимает карточку и сам: у свёрнутой дорожки столбцов на экране
   нет, и отправить туда задачу было бы нечем. */
.board-lane-head.over { background: color-mix(in srgb, var(--accent) 22%, var(--panel-2)); }
.lane-chev { flex: none; color: var(--text-faint); transition: transform 0.14s var(--ease); }
.board-lane.collapsed .lane-chev { transform: rotate(-90deg); }
.board-lane.collapsed .board-lane-cols { display: none; }
.lane-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lane-released { flex: none; font-size: 12px; font-weight: 500; color: var(--text-faint); }
/* Выпущенная версия закрыта: её дорожка звучит тише живой работы. */
.board-lane-head.released .lane-name { color: var(--text-dim); font-weight: 600; }

/* Настройки проекта: два раздела в одном окне — статусы и версии. */
/* У версии нет цвета, зато есть выпуск и счётчик задач — остальное такое же,
   как у строки статуса, и раскладку она берёт оттуда же. */
/* Пустое место под кружок цвета, которого у версии нет: без него поля
   версий стояли на 27 пикселей левее полей статусов, и два списка в одном
   окне читались как случайно сдвинутые. */
.ver-row::before { content: ''; flex: none; width: 22px; }
/* Ширина кнопки выпуска зафиксирована: «в работе» и «выпущена 12 сент.»
   разной длины, и без этого счётчик задач и стрелки гуляли из строки в
   строку. Класс .on здесь не годится — в приложении он значит «список
   открыт», и выпущенная версия выглядела бы вечно раскрытым выбором. */
.ver-rel { flex: none; width: 158px; }
.ver-rel.released { color: var(--text-dim); }
.ver-use { flex: none; min-width: 58px; text-align: right; font-size: 12px; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Одинаковые названия не запрещаем — только показываем: двух «v1.2» в одном
   проекте всё равно не различить на глаз. */
.ver-row.dup .st-name { box-shadow: inset 0 0 0 1.5px var(--danger); }

/* ---------- Дорожки доски: плотнее и на своей поверхности ---------- */
/* Заголовок стоял на цвете страницы и читался висящим в воздухе. Теперь он
   на той же поверхности, что и столбцы под ним, а промежутки между
   дорожками меньше промежутка внутри дорожки — полоса читается целым. */
.board-cols.has-lanes { gap: 10px; }
.board-lane-head { background: var(--board-col); margin: 0 0 3px; }
/* На светлой теме --panel-2 и --board-col совпадают, поэтому наведение
   считается от самой поверхности, а не берётся готовым токеном. */
.board-lane-head:hover { background: color-mix(in srgb, var(--text) 7%, var(--board-col)); }

/* ---------- Полоска фильтров ---------- */
/* Фильтр статистики: кнопка читается как выбор — подпись «Проект», цвет
   и имя проекта, стрелка. Серая пилюля с одним именем выбором не читалась. */
.filter-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.filter-bar .dp-btn { display: inline-flex; align-items: center; gap: 7px; height: 32px; padding: 0 9px 0 10px; border-radius: 8px; font-size: 13px; }
.filter-bar .fchip-k { color: var(--text-faint); }
.filter-bar .fchip-v { font-weight: 500; }
.filter-bar .dp-btn .icon { width: 12px; height: 12px; color: var(--text-faint); }
.filter-bar .dp-btn.on { background: var(--panel); }
.filter-reset {
  border: none; background: none; border-radius: 6px;
  padding: 5px 8px; color: var(--text-dim);
  font-family: inherit; font-size: 12px; cursor: pointer;
  transition: color 0.12s var(--ease), background 0.12s var(--ease);
}
.filter-reset:hover { color: var(--text); background: var(--panel-2); }
/* Выбор версии живёт под названием проекта, рядом с описанием и тегами:
   это свойство того, на что смотришь, а не третья пилюля к статусам — в
   ряду с ними он вдобавок сжимал их до переноса текста.
   Вид — как у выбора проекта на доске: без подложки и рамки, тихим текстом
   и с шевроном. Рамка поля ввода тут кричала бы на пустом месте, а без
   шеврона кнопка читалась подписью, а не выбором. */
.ph-version {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin: 5px 0 0 -6px;
  padding: 2px 6px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background 0.12s var(--ease), color 0.12s var(--ease);
}
.ph-version:hover { background: var(--panel-2); color: var(--text); }
.ph-version .icon { width: 11px; height: 11px; flex: none; color: var(--text-faint); }
.ph-version:hover .icon { color: var(--text-dim); }
.ph-version-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Выбранная версия заметнее не рамкой, а весом текста: это пометка «смотрю
   срез», а не тревога. */
.ph-version.on { color: var(--text); font-weight: 600; }

/* ---------- Правая панель: записи по проектам ---------- */
/* Обёртка группы — не карточка. Группу связывает слева полоса цвета проекта
   (--pc приходит из calGroupNode), под заголовком с отступом лежат записи.
   Полоса ::before привязана к низу обёртки, поэтому при складывании едет
   вместе с её высотой. */
.cal-day-list > li.cdl-group,
.period-list > li.cdl-group {
  display: block;
  position: relative;
  padding: 0 0 0 12px;
  border: none;
  background: none;
  cursor: default;
}
.cal-day-list > li.cdl-group:hover,
.period-list > li.cdl-group:hover { background: none; }
.cal-day-list > li.cdl-group + li.cdl-group,
.period-list > li.cdl-group + li.cdl-group { margin-top: 10px; }
.cdl-group::before {
  content: '';
  position: absolute; left: 0; top: 2px; bottom: 2px;
  width: 3px; border-radius: 2px;
  background: var(--pc, var(--accent));
}

/* Имя проекта — главное в группе: основным цветом и полужирным, а не
   приглушённым, как итог справа. Длинное имя — многоточием, итог остаётся. */
.cdl-group-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  border: none; background: none; cursor: pointer;
  padding: 2px 0 6px;
  color: var(--text); font-family: inherit; font-size: 13.5px; font-weight: 600;
  text-align: left;
}
.cdl-group-head:hover .cdl-group-name { color: var(--accent-ink); }
.cdl-chev { flex: none; width: 13px; height: 13px; color: var(--text-faint); transition: transform var(--cdl-t) var(--ease); }
.cdl-group.closed .cdl-chev { transform: rotate(-90deg); }
.cdl-group-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; background: var(--pc, var(--accent)); }
.cdl-group-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cdl-group-tot { margin-left: auto; flex: none; font-size: 12px; font-weight: var(--fw-text); color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Складывание записей: высота идёт от auto к 0, и это умеет только
   interpolate-size (Chromium 129+, то есть Electron 33 и Chrome). Приём
   «grid-template-rows: 1fr → 0fr» проверен и не годится: Chromium делит
   дробные доли дважды, и записи сжимаются по квадрату, пока высота группы —
   а с ней и полоса слева — идёт по прямой; полоса уезжала бы ниже записей.
   Где interpolate-size нет, группа просто складывается сразу — как раньше.
   Длительность одна на всё (--cdl-t): высота, проявление записей и поворот
   стрелки. */
.cdl-group { --cdl-t: 0.2s; interpolate-size: allow-keywords; }
/* Без движения — сразу: нулевое время обнуляет и задержку скрытия записей. */
@media (prefers-reduced-motion: reduce) {
  .cdl-group { --cdl-t: 0s; }
}
/* Левый отступ равен шеврону с зазором: текст записей начинается там же,
   где метка проекта в заголовке. overflow: hidden обрезает записи по
   убывающей высоте. */
.cdl-rows {
  list-style: none; margin: 0; padding: 0 0 0 11px; display: flex; flex-direction: column; gap: 2px;
  height: auto; overflow: hidden;
  transition: height var(--cdl-t) var(--ease), opacity var(--cdl-t) var(--ease), visibility 0s;
}
/* Записи проявляются и гаснут вместе со складыванием. visibility уходит в
   конце: свёрнутые записи не должны ни получать фокус, ни читаться
   скринридером — как при прежнем display: none. */
.cdl-group.closed .cdl-rows {
  height: 0; opacity: 0; visibility: hidden;
  transition: height var(--cdl-t) var(--ease), opacity var(--cdl-t) var(--ease), visibility 0s linear var(--cdl-t);
}

/* ---------- Календарь-расписание ----------
   Часовая сетка внутри раздела «Время»: записи времени блоками, дедлайны
   полосой «весь день»; записи можно заводить протягиванием, двигать и
   растягивать. */
.ag-total { color: var(--text-dim); font-size: 12.5px; font-variant-numeric: tabular-nums; }

/* Часовая сетка */
.ag-time { flex: 1; min-height: 0; display: flex; flex-direction: column; --ag-gutter: 54px; --ag-h: 1200px; --ag-sb: 0px; --ag-sb-row: 0px; }
/* --ag-sb — ширина полосы прокрутки у сетки, её меряет syncAgendaScrollbar.
   Шапка дней и строка «весь день» лежат вне прокрутки, и без этого запаса
   их границы уезжали вправо относительно линий сетки. */
.ag-daynames {
  flex: none;
  display: grid;
  grid-template-columns: repeat(var(--ag-days, 7), minmax(0, 1fr));
  margin-left: var(--ag-gutter);
  margin-right: var(--ag-sb);
}
.ag-dayname {
  border: none; background: none; cursor: pointer;
  display: flex; align-items: baseline; justify-content: center; gap: 6px;
  padding: 4px 0 8px;
  color: var(--text-dim); font-family: inherit; font-size: 12px;
  border-left: 1px solid transparent;
}
.ag-dayname:hover .ag-dnum { background: var(--panel-2); }
.ag-dnum {
  font-size: 15px; font-weight: 600; color: var(--text);
  min-width: 26px; height: 26px; line-height: 26px; border-radius: 999px;
  transition: background 0.12s var(--ease);
}
.ag-dayname.today .ag-dnum { background: var(--accent); color: var(--accent-text); }
.ag-dayname.today .ag-dow { color: var(--accent-ink); }

/* Подпись — обычный флекс-сосед ячеек, а не absolute: абсолютная выпадала
   из потока, строка переставала под неё растягиваться, подпись вылезала за
   край — и строка получала полосу прокрутки на пустом месте. Колонки мимо
   линий сетки ставил не флекс, а 1fr = minmax(auto, 1fr): длинный чип
   дедлайна раздвигал свой столбец. Отсюда minmax(0, 1fr) ниже. */
.ag-allday-row {
  flex: none;
  display: flex;
  align-items: stretch;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  max-height: 88px;
  overflow-y: auto;
  padding-right: var(--ag-sb-row);
}
.ag-allday-label {
  flex: none; width: var(--ag-gutter);
  padding: 5px 8px 0 0; text-align: right;
  font-size: 12px; color: var(--text-faint);
}
.ag-allday {
  flex: 1; min-width: 0;
  display: grid;
  grid-template-columns: repeat(var(--ag-days, 7), minmax(0, 1fr));
}
.ag-allday-cell {
  display: flex; flex-direction: column; gap: 2px;
  padding: 4px 3px; border-left: 1px solid var(--border-soft);
  min-height: 26px; min-width: 0;
}
.ag-dl {
  border: none; border-radius: 5px; cursor: pointer;
  padding: 2px 6px; text-align: left;
  font-family: inherit; font-size: 12px; font-weight: 600;
  color: color-mix(in srgb, var(--pc) var(--tag-ink), var(--text));
  background: color-mix(in srgb, var(--pc) 20%, transparent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ag-dl.done { opacity: 0.55; text-decoration: line-through; }

.ag-scroll { flex: 1; min-height: 0; overflow-y: auto; display: flex; }
.ag-gutter {
  flex: none; width: var(--ag-gutter); height: var(--ag-h);
  display: grid; grid-template-rows: repeat(24, 1fr);
}
.ag-hour {
  font-size: 12px; color: var(--text-faint); text-align: right;
  padding-right: 8px; transform: translateY(-5px);
  font-variant-numeric: tabular-nums;
}
.ag-cols {
  flex: 1; height: var(--ag-h);
  display: grid; grid-template-columns: repeat(var(--ag-days, 7), minmax(0, 1fr));
  position: relative;
  /* Протягивание по сетке не должно выделять текст под курсором. */
  user-select: none;
  touch-action: none;
}
.ag-col { position: relative; border-left: 1px solid var(--border-soft); }
.ag-col.today { background: color-mix(in srgb, var(--accent) 4%, transparent); }
.ag-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--border-soft); pointer-events: none; }
/* Получасовая тише часовой: она подсказывает шаг, а не размечает час. */
.ag-line.half { border-top-color: color-mix(in srgb, var(--border-soft) 50%, transparent); }

.ag-ev {
  position: absolute;
  border-radius: 6px;
  padding: 2px 6px 0;
  overflow: hidden;
  cursor: grab;
  color: color-mix(in srgb, var(--pc) var(--tag-ink), var(--text));
  background: color-mix(in srgb, var(--pc) 22%, var(--panel));
  border-left: 3px solid var(--pc, var(--accent));
  font-size: 12px; line-height: 1.3;
  transition: filter 0.12s var(--ease);
}
.ag-ev:hover { filter: brightness(1.08); }
.ag-ev.dragging { cursor: grabbing; opacity: 0.85; z-index: 3; }
/* Кусок записи, перешедшей за полночь: срезанный угол говорит, что она
   продолжается в соседнем дне. */
.ag-ev.cross { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.ag-ev-time { display: block; font-variant-numeric: tabular-nums; opacity: 0.85; }
.ag-ev-name { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-ev-grip { position: absolute; left: 0; right: 0; bottom: 0; height: 7px; cursor: ns-resize; }
.ag-ghost { background: color-mix(in srgb, var(--accent) 26%, var(--panel)); border-left-color: var(--accent); color: var(--text); opacity: 0.9; pointer-events: none; }

.ag-now { position: absolute; left: 0; right: 0; height: 2px; background: var(--danger); pointer-events: none; z-index: 2; }
.ag-now::before {
  content: ''; position: absolute; left: -4px; top: -3px;
  width: 8px; height: 8px; border-radius: 999px; background: var(--danger);
}

/* Месяц */
.ag-month { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.ag-month-week { display: grid; grid-template-columns: repeat(7, 1fr); }
.ag-month-dow { text-align: center; padding: 4px 0 8px; font-size: 12px; color: var(--text-faint); }
.ag-month-grid {
  flex: 1; min-height: 0;
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(0, 1fr);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
.ag-month-cell {
  min-height: 0; overflow: hidden;
  display: flex; flex-direction: column; gap: 2px;
  padding: 3px 4px 4px;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.ag-month-cell.out { background: color-mix(in srgb, var(--text) 3%, transparent); }
.ag-month-num {
  align-self: flex-start; border: none; background: none; cursor: pointer;
  color: var(--text-dim); font-family: inherit; font-size: 12px;
  min-width: 22px; height: 22px; border-radius: 999px;
}
.ag-month-num:hover { background: var(--panel-2); color: var(--text); }
.ag-month-cell.out .ag-month-num { color: var(--text-faint); }
.ag-month-cell.today .ag-month-num { background: var(--accent); color: var(--accent-text); font-weight: 700; }
.ag-mchip {
  display: flex; align-items: baseline; gap: 5px;
  border: none; border-radius: 5px; cursor: pointer; text-align: left;
  padding: 2px 6px;
  font-family: inherit; font-size: 12px;
  color: color-mix(in srgb, var(--pc) var(--tag-ink), var(--text));
  background: color-mix(in srgb, var(--pc) 18%, transparent);
  overflow: hidden;
}
.ag-mchip.dl { font-weight: 700; }
.ag-mchip.done { opacity: 0.55; text-decoration: line-through; }
.ag-mchip-time { flex: none; font-variant-numeric: tabular-nums; opacity: 0.8; }
.ag-mchip-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-mmore { align-self: flex-start; border: none; background: none; cursor: pointer; color: var(--text-dim); font-family: inherit; font-size: 12px; padding: 1px 4px; }
.ag-mmore:hover { color: var(--text); }

/* Расписание */
.ag-list { flex: 1; min-height: 0; overflow-y: auto; padding-bottom: 24px; }
/* Пустой период — пустой экран посреди острова. */
.ag-list.is-empty { display: flex; flex-direction: column; }
.ag-list-day { margin-bottom: 14px; }
.ag-list-date { font-size: 12px; font-weight: 700; color: var(--text-dim); margin-bottom: 6px; }
.ag-list-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  border: none; border-radius: 8px; cursor: pointer; text-align: left;
  padding: 8px 10px; margin-bottom: 4px;
  /* Как клетка месяца — поле внутри острова, иначе строка сливается с ним. */
  background: var(--panel-2);
  color: var(--text); font-family: inherit; font-size: 12.5px;
  border-left: 3px solid var(--pc, var(--accent));
  transition: box-shadow 0.12s var(--ease);
}
.ag-list-row:hover { box-shadow: inset 0 0 0 1px var(--border-strong); }
.ag-list-time { flex: none; min-width: 92px; color: var(--text-dim); font-variant-numeric: tabular-nums; font-size: 12px; }
.ag-list-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ag-list-dur { flex: none; color: var(--text-dim); font-variant-numeric: tabular-nums; font-size: 12px; }
.ag-list-tag { flex: none; font-size: 12px; color: color-mix(in srgb, var(--pc) var(--tag-ink), var(--text)); background: color-mix(in srgb, var(--pc) 18%, transparent); border-radius: 5px; padding: 1px 7px; }

/* Выбор задачи для новой записи — тот же попап, что у тегов. */

/* ---------- Повторение задач ---------- */
/* Значок в списке задач: повторяющуюся задачу видно, не открывая её. */
.task-repeat-mark {
  flex: none; font-size: 12px; color: var(--text-faint); cursor: default;
}

/* Окно тонкой настройки. Вместо плоского списка «подпись — поле» —
   сегментные переключатели: у правила мало значений, и выбор из трёх-четырёх
   видно целиком, не открывая список. Сами сегменты, кружки дней и
   переключатель взяты у режимов календаря, фильтра задач и «Выбрать период»:
   заводить под окно свои элементы незачем. */
/* Окно высокое: на низком экране оно должно прокручиваться внутри себя, а не
   вылезать за края — центровку даёт общий механизм подложки. */
.rpdlg {
  display: flex; flex-direction: column; gap: 14px;
  max-height: calc(100vh - 48px);
  overflow-y: auto;
}
.rpdlg .modal-title { margin: 0; }

.rp-seg { display: grid; }
.rp-seg-2 { grid-template-columns: repeat(2, 1fr); }
.rp-seg-3 { grid-template-columns: repeat(3, 1fr); }
.rp-seg-4 { grid-template-columns: repeat(4, 1fr); }
/* Подписи в сетке повторения бывают длиннее клетки — многоточием. */
.rp-seg button { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* «Повторять каждые [2] нед.» — одной фразой, а не подписью и полем порознь. */
.rp-line { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-dim); }
/* Вес селектора поднят намеренно: у широких окон есть общее правило
   «.modal-lg input[type=text] — во всю ширину», и оно растягивало это поле,
   выдавливая «раз» за край. */
.rpdlg input.rp-num[type='text'] { flex: none; width: 54px; text-align: center; font-variant-numeric: tabular-nums; }
.rp-unit { font-size: 12.5px; color: var(--text); }

/* Дни недели — ряд одинаковых квадратов во всю ширину: так видно всю неделю
   разом, а выбранные читаются пятном. Скругление то же, что у сегментов
   рядом, — круги выбивались из окна, где всё остальное прямоугольное. */
.rp-days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; }
.rp-day {
  aspect-ratio: 1;
  border: 0; border-radius: 9px; background: none;
  color: var(--text-dim); font-family: inherit; font-size: 12px; cursor: pointer;
  transition: background 0.12s var(--ease), color 0.12s var(--ease), border-color 0.12s var(--ease);
}
.rp-day:hover { border-color: var(--border-strong); color: var(--text); }
.rp-day.on { background: var(--accent); border-color: var(--accent); color: var(--accent-text); font-weight: 700; }

.rp-field { display: flex; flex-direction: column; gap: 6px; }
.rp-field-label {
  font-size: 12px; letter-spacing: 0.6px; text-transform: uppercase;
  color: var(--text-faint);
}
.rp-ends-extra { display: flex; align-items: center; gap: 8px; }

/* Переключатель «оставлять копии» — тот же, что у «Выбрать период» на
   календаре. Галочка рядом с двухстрочной подписью читалась хуже, да и
   общее правило «.modal label — блочный» ставило её над текстом. */
.rpdlg .rp-switch { align-items: flex-start; text-align: left; gap: 10px; }
.rpdlg .rp-switch .switch-track { margin-top: 1px; }
.rp-switch-text { display: flex; flex-direction: column; gap: 2px; font-size: 12.5px; }
.rp-switch.on .rp-switch-text > span:first-child { color: var(--text); }
.rp-hint { font-size: 12px; line-height: 1.4; color: var(--text-faint); }

/* Сводка: правило словами и ближайшие сроки. Без неё «каждый второй вторник
   месяца» проверить нечем — приходилось закрывать окно и смотреть. */
.rp-summary {
  display: flex; align-items: flex-start; gap: 9px;
  padding: 11px 12px;
  background: color-mix(in srgb, var(--accent) 12%, var(--panel-2));
  border-radius: 10px;
}
.rp-summary-mark { flex: none; color: var(--accent-ink); font-size: 14px; line-height: 1.2; }
.rp-summary-main { display: flex; flex-direction: column; gap: 3px; min-width: 0; font-size: 12.5px; }
.rp-summary-dates { color: var(--text-dim); font-size: 12px; font-variant-numeric: tabular-nums; }

/* Будущее повторение на календаре — прогноз, а не запись: тише, пунктиром. */
.ag-dl.ghost, .ag-mchip.ghost {
  background: none;
  border: 1px dashed color-mix(in srgb, var(--pc) 55%, transparent);
  color: var(--text-dim);
}
.ag-list-row.ghost, .ag-list-row.plan { background: none; border: 1px dashed var(--border-strong); border-left: 3px dashed var(--pc, var(--accent)); }
.ag-list-row.ghost .ag-list-name, .ag-list-row.plan .ag-list-name { color: var(--text-dim); }

/* ---------- Время работы ---------- */
/* В свойствах задачи — строка «Время работы · Пн, Ср 10:00–12:00 +1 ›» в
   группе «Когда» (.srow): отрезков нет — щелчок сразу открывает окно нового,
   есть — список отрезков (.ctx-menu) и «Добавить время». */

/* Окно времени работы — строки на острове, как лист отрезка на телефоне
   (13 октября 2026). Длительность — тихой подстрокой под «Концом»; конец не
   позже начала — та же подстрока красным, и «Сохранить» окно не закрывает.
   «Повторение задачи» — своим островом ниже: значение словами («Повторяется
   каждую неделю вместе с задачей») переносится, а не режется. «Удалить»
   стоит слева, подальше от «Сохранить». */
.sldlg .sldlg-repeat { margin-top: 10px; }
.sldlg .sldlg-repeat .srow-value { white-space: normal; }
.sldlg #sldlg-dur.bad { color: var(--danger); }
.sldlg .sldlg-delete { margin-right: auto; }

/* ---------- Напоминания ---------- */
/* В свойствах задачи — группа «Напоминания»: строка на каждое (.srow с
   колокольчиком, щелчок — окно этого напоминания) и «Добавить» последней.
   Подпись напоминания длинная — строке без значения отдана вся ширина. */
.remind-item .srow-label { flex: 1; max-width: none; }

/* Окно напоминания — окно повторения (.rpdlg), в котором те же сегменты, ряд
   дней недели и поле числа. Свои тут только мелочи. Сегменты бывают с
   разным числом кнопок, а у «До начала / до дедлайна» одну могут спрятать:
   колонки делятся поровну по тем, что остались. */
.rm-seg { grid-auto-flow: column; grid-auto-columns: 1fr; }
.rm-seg > button:disabled { opacity: 0.45; cursor: default; }
.rp-line .rm-seg { flex: none; }
.rmdlg .rp-line { flex-wrap: wrap; }
.rm-panel { display: flex; flex-direction: column; gap: 14px; }
/* Подпись над кнопкой даты — тесно, как в окне записи времени. */
#rm-at { gap: 6px; }
#rm-at > label { margin: 0; }
/* Быстрые смещения — чипы в несколько рядов: «В момент начала» длиннее
   остальных, и в одну строку они на узком окне не встанут. */
.rm-presets { display: flex; flex-wrap: wrap; gap: 6px; }
.rm-presets .dp-btn { min-width: 0; }
.rm-error { font-size: 12px; color: var(--danger); }
/* «Удалить» слева, подальше от «Сохранить»; без заполненных полей «Сохранить»
   гаснет. Правило по id, как у «Экспорта»: общий .modal-buttons попал бы в
   стили редактора телефона. */
.rmdlg .rmdlg-delete { margin-right: auto; }
#rmdlg-save:disabled { opacity: 0.45; cursor: default; }
#rmdlg-save:disabled:hover { background: var(--accent); border-color: var(--accent); }
#rmdlg-save:disabled:active { transform: none; }

/* Плановый блок на часовой сетке: полоса во всю ширину столбца, под записями
   времени. Из семейства призраков (.ag-dl.ghost): контур цветом проекта и
   лёгкая подкладка, без заливки записи — это план, а не сделанное. */
.ag-plan {
  position: absolute; left: 1px; right: 1px; box-sizing: border-box;
  border: 1px dashed color-mix(in srgb, var(--pc) 55%, transparent);
  border-radius: 6px;
  background: color-mix(in srgb, var(--pc) 7%, transparent);
  color: var(--text-dim);
  padding: 2px 6px 0; overflow: hidden; cursor: pointer;
  font-size: 12px; line-height: 1.3;
}
.ag-plan:hover { background: color-mix(in srgb, var(--pc) 12%, transparent); }
.ag-plan-time { display: block; font-variant-numeric: tabular-nums; }
.ag-plan-name { display: block; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
