/* ---------- Шрифты --------------------------------------------------------- */

/*
 * Golos Text и JetBrains Mono, оба со СВОЕГО домена.
 *
 * Не с чужого CDN: общий кэш между сайтами отменён изоляцией по origin, так
 * что выигрыша нет никакого, а зависимость от чужой доступности остаётся.
 * Лицензии (OFL 1.1 и Apache 2.0) лежат рядом с файлами — обе допускают
 * размещение у себя, но требуют, чтобы текст лицензии ехал вместе со шрифтом.
 *
 * КИРИЛЛИЦА ОТДЕЛЬНО ОТ ЛАТИНИЦЫ. Браузер грузит только те куски, знаки
 * которых на странице есть: русскому читателю не приезжают 38 килобайт
 * латиницы, и наоборот. Делит их `unicode-range`, и работает он сам — ни
 * строки скрипта.
 *
 * `swap`, а не `optional`: на медленной сети `optional` просто не применит
 * шрифт, и человек весь сеанс просидит на системном, не зная об этом.
 */
@font-face {
    font-family: "Golos Text";
    src: url("/static/fonts/golos-text-cyrillic-wght-normal.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    /* U+2116 — знак «№». В кириллических текстах он нужен постоянно, а в
       латинском куске его нет. */
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
    font-family: "Golos Text";
    src: url("/static/fonts/golos-text-latin-wght-normal.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F,
        U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}

@font-face {
    font-family: "JetBrains Mono";
    src: url("/static/fonts/jetbrains-mono-cyrillic-wght-normal.woff2") format("woff2");
    font-weight: 400 700;
    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: "JetBrains Mono";
    src: url("/static/fonts/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+2000-206F,
        U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215;
}


/*
 * ФОЛБЭК С ПОДОГНАННЫМИ МЕТРИКАМИ — против скачка при подмене.
 *
 * `swap` показывает системный шрифт, пока грузится Golos, и это правильно:
 * `optional` на медленной сети не применил бы Golos вовсе, и человек весь
 * сеанс просидел бы на системном, не зная об этом.
 *
 * Плохо не то, что шрифт подменяется, а то, что при подмене ПРЫГАЕТ ТЕКСТ:
 * строки перескакивают, абзацы меняют высоту, и страница дёргается уже после
 * того, как человек начал читать.
 *
 * НАЧЕРТАНИЙ ДВА, И ЭТО ГЛАВНОЕ ЗДЕСЬ. Сначала блок был один — обычного веса.
 * Заголовки у нас идут весом 600 и 700, а `font-synthesis: none` (ниже)
 * запрещает браузеру подделывать жирность своими силами. Значит пока грузился
 * Golos, каждый заголовок показывался ОБЫЧНЫМ весом и через полсекунды прыгал
 * в полужирный — самая заметная часть скачка, и совсем не та, о которой
 * думаешь, глядя на числа подгонки.
 *
 * Замер, на котором это видно: ширина строки в «Golos fallback» была
 * одинаковой на весах 400, 500, 600 и 700 — 1997 пикселей. У настоящего Golos
 * она растёт: 1994, 2009, 2019, 2038.
 *
 * ЧИСЛА СНЯТЫ ЗАМЕРОМ, а не подобраны. Строка «Съешь ещё этих мягких
 * французских булок, да выпей чаю…» при кегле 100:
 *
 *   Golos Text 400      5187        Segoe UI            4839  → 107.2 %
 *   Golos Text 600      5264        Segoe UI Semibold   4973  → 105.9 %
 *   Golos Text 700      5318        Segoe UI Semibold   4973  → 106.9 %
 *
 * Для полужирного взято 106.4 % — середина между 600 и 700, потому что оба
 * веса ходят через одно системное начертание.
 *
 * Восходящая и нисходящая у Golos — 98 % и 22 % кегля на всех весах. Здесь они
 * заданы делением на size-adjust: он масштабирует и метрики тоже, и без
 * деления строка стала бы выше, чем нужно. Прежние 92/24 давали нисходящую
 * 26 % вместо 22 % — то есть строки в фолбэке были выше, и текст ехал по
 * вертикали при подмене.
 */
@font-face {
    font-family: "Golos fallback";
    src: local("Segoe UI"), local("Helvetica Neue"), local("Arial");
    font-weight: 400 500;
    size-adjust: 107.2%;
    ascent-override: 91.4%;
    descent-override: 20.5%;
    line-gap-override: 0%;
}

@font-face {
    font-family: "Golos fallback";
    src: local("Segoe UI Semibold"), local("Helvetica Neue Bold"), local("Arial Bold");
    font-weight: 600 700;
    size-adjust: 106.4%;
    ascent-override: 92.1%;
    descent-override: 20.7%;
    line-gap-override: 0%;
}

/*
 * БЛОКОВ `font-style: italic` НЕТ НАМЕРЕННО.
 *
 * Курсива у Golos Text не существует. Объявить italic значило бы разрешить
 * браузеру наклонить прямое начертание самому — в кириллице это выглядит
 * грязно, буквы «д», «л», «я» ломаются. Поэтому и `font-synthesis: none`
 * ниже: наклонять и утолщать своими силами запрещено.
 */
body {
    font-synthesis: none;
}

/*
 * Наш файл. skins.css — файл дизайнера, он заменяется целиком.
 *
 * Здесь две вещи:
 *
 *   1. ПОВЕДЕНИЕ — что показано, что спрятано, что прокручивается. Без этого
 *      интерфейс перестаёт работать, поэтому подменой оформления его нельзя
 *      случайно погасить.
 *   2. Узлы, которых в пакете передачи не оказалось: мета-строка документа,
 *      шапка истории, значок пользователя. Они оформлены ТОКЕНАМИ дизайна
 *      (var(--text-3) и прочими), поэтому меняются вместе с ним и не
 *      расходятся при смене скина или темы.
 *
 * Собственных цветов и размеров здесь нет и быть не должно — только токены.
 */

/* ---------- Редактор ------------------------------------------------------ */

/*
 * По умолчанию виден textarea: без скрипта редактор остаётся обычным полем
 * ввода, и форма работает как работала. Скрипт поднимает CodeMirror и ставит
 * .is-live — с этого момента видно его.
 *
 * Прятать textarea прямо в разметке нельзя: тогда без скрипта редактор исчезнет
 * совсем.
 */
.editor-host {
    display: none;
}

.editor.is-live textarea {
    display: none;
}

.editor.is-live .editor-host {
    display: block;
}

/*
 * Поле растёт по содержимому.
 *
 * Не «высота в пол-экрана»: документ из четырёх строк занимал семьсот точек, и
 * кнопка сохранения с историей уезжали за нижний край. Нижний предел — чтобы
 * пустой документ не выглядел щелью.
 */
/*
 * Поле растёт по содержимому, а прокручивается страница.
 *
 * Три правила работают только вместе:
 *   - `height: auto` — поле вытягивается на весь документ;
 *   - `overflow: visible` у прокрутки — так CodeMirror понимает, что
 *     прокручивается не он, и следит за прокруткой страницы;
 *   - `overflow: visible` у обёртки — иначе обрезающий предок остаётся, и
 *     видимой областью снова считается только он.
 *
 * Долго не работало не из-за значений, а из-за ПОРЯДКА ПОДКЛЮЧЕНИЯ: base.css
 * шёл перед skins.css, и `overflow: hidden` из оформления побеждал по правилу
 * «позже — сильнее». Документ на 94 строки показывал 25, без полосы прокрутки
 * и без сообщения. Порядок исправлен в шапке страницы.
 *
 * Скруглённые углы обёртки при этом теряются. Видимый текст важнее.
 */
.cm-editor {
    min-height: 240px;
    height: auto;
}

.cm-editor .cm-scroller {
    overflow: visible;
}

.editor-host {
    overflow: visible;
}

/*
 * Ширина редактора ограничена колонкой.
 *
 * У прокрутки редактора `overflow: visible` — иначе он не отдаёт прокрутку
 * странице. Побочное следствие: широкая таблица внутри перестаёт прокручиваться
 * сама и растягивает редактор за пределы колонки, а вместе с ним и страницу.
 * Таблица на пять колонок уводила текст вбок на треть экрана.
 *
 * Ограничение по ширине возвращает таблице её собственную полосу прокрутки —
 * ту же, что у таблицы в отрисованном документе.
 */
.cm-editor .cm-content {
    max-width: 100%;
}

/* ---------- Всплывающее --------------------------------------------------- */

/*
 * Слэш-меню, подсказки `[[` и панель над выделением ставятся скриптом по
 * координатам курсора. Позиционирование живёт здесь, а не в оформлении: без
 * `absolute` координаты не действуют вовсе, и меню падает в конец страницы —
 * ровно это и случилось, когда оформление сменилось.
 *
 * Скрипт кладёт их в конец `body` и прибавляет прокрутку страницы к координатам
 * от `coordsAtPos`. Значит система отсчёта — страница, то есть `absolute`.
 * Заменить на `fixed` без правки скрипта нельзя: прокрутка учтётся дважды.
 */
.popover {
    position: absolute;
    top: 0;
    left: 0;
    max-height: 320px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.selection-bar {
    max-height: none;
    overflow: visible;
}

/* ---------- Прокрутка ----------------------------------------------------- */

/*
 * Страница не едет вбок — но ТОЛЬКО на html, и никогда на body.
 *
 * `overflow-x: hidden` на body по правилам CSS превращает вторую ось в `auto`:
 * body становится контейнером прокрутки. Прокручивается при этом не он, а html
 * — то есть body оказывается контейнером, который не прокручивается никогда.
 *
 * Вреда от него на глаз не видно, и потому он и живёт долго. Но CodeMirror
 * ищет ближайшего прокручиваемого предка, чтобы понять, какую часть документа
 * рисовать, и такой предок он находит первым. Пока его геометрия совпадает с
 * окном, всё сходится; стоит странице стать длиннее — перестаёт.
 *
 * Правило живёт здесь, а не в оформлении: подменяя skins.css, сломать редактор
 * двумя словами про горизонтальную прокрутку нельзя.
 */
html {
    overflow-x: hidden;
}


/*
 * Широкая таблица прокручивается ВНУТРИ своего ящика. Без этого на телефоне
 * вбок едет вся страница вместе с заголовком, и каждый абзац приходится возить
 * туда-сюда. Обёртку ставит отрисовщик Markdown.
 */
.table-scroll {
    overflow-x: auto;
    overscroll-behavior-x: contain;
}

.content pre {
    overflow-x: auto;
}

/*
 * Прокручивается ДЕРЕВО, а не вся панель: иначе шапка с названием проекта и
 * подвал с именем уезжают вместе с длинным списком документов, и до кнопки
 * выхода приходится долистывать.
 */
.sidebar {
    overflow: hidden;
}

/* ---------- Поиск --------------------------------------------------------- */

/*
 * Поле поиска в панели. Обычная форма: без скрипта она работает так же, а
 * скрипт добавляет только переход фокуса по ⌘K.
 */
.sidebar-search {
    flex: none;
    padding: 0 var(--sp-2);
}

.sidebar-search input {
    width: 100%;
    min-width: 0;
    min-height: 32px;
    padding: 0 var(--sp-3);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-ui);
    font-size: var(--fs-small);
}

.sidebar-search input::placeholder {
    color: var(--text-3);
}

.sidebar-search input:hover {
    border-color: var(--line-strong);
}

/* Крестик очистки в WebKit рисуется тёмным квадратом на светлой теме. */
.sidebar-search input::-webkit-search-cancel-button {
    filter: grayscale(1) opacity(0.5);
}

/* ---------- Кнопки, зависящие от ширины ----------------------------------- */

/* Кнопка со значком вместо подписи. Пока таких ровно две — открыть и закрыть
   панель на узком экране. */
.icon-button {
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text-2);
    font: inherit;
    line-height: 1;
    cursor: pointer;
}

.icon-button:hover {
    background: var(--surface-2);
    color: var(--text);
}

/*
 * Три полосы. Не знаком «≡»: его начертание в системных шрифтах то уже подписи,
 * то выше её, а стоит он ровно там, где промахнуться нельзя, — единственный
 * путь к навигации на телефоне.
 */
.burger {
    width: 16px;
    height: 2px;
    border-radius: 1px;
    background: currentColor;
    box-shadow: 0 -5px 0 currentColor, 0 5px 0 currentColor;
}

/*
 * Бургер и крестик закрытия панели нужны только там, где панель — выдвижной
 * ящик. На широком экране панель стоит на месте, и обе кнопки превращаются в
 * необъяснимые значки: серый прямоугольник у крошек и × у названия проекта.
 *
 * `display` этих двух правил обязан идти ПОСЛЕ вида кнопки выше — иначе
 * `inline-flex` побеждает и бургер вылезает туда, где он бессмыслен.
 */
.drawer-open,
.drawer-close {
    display: none;
}

@media (max-width: 860px) {
    .drawer-open,
    .drawer-close {
        display: inline-flex;
    }
}

/* ---------- Списки без маркеров -------------------------------------------- */

/*
 * История и дерево — это списки по смыслу разметки, но не по виду: точки перед
 * версиями ничего не значат и читаются как мусор.
 */
.tree {
    list-style: none;
}

/* ---------- Доступность --------------------------------------------------- */

/* Ярлык, нужный программе чтения с экрана и лишний на странице. */
.sr {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Скрытое остаётся скрытым, что бы ни говорило оформление. */
[hidden] {
    display: none !important;
}

/* ---------- Узлы, которых не было в пакете передачи ----------------------- */
/*
 * Всё ниже оформлено ТОКЕНАМИ дизайна. Своих цветов и размеров нет: иначе при
 * смене скина или темы эти куски остались бы жить прежней жизнью.
 */

/*
 * Лист и правая колонка.
 *
 * `.sheet` — строка из двух: сам документ и колонка рядом. Колонка есть только
 * на странице документа; на остальных страницах в обёртке лежит один лист, и
 * она ничего не меняет.
 */
.sheet {
    display: flex;
    flex: 1 1 auto;
    min-width: 0;
    min-height: 0;
}

/*
 * Правая колонка: оглавление и время чтения.
 *
 * Прилипает под шапкой и прокручивается отдельно — оглавление, уезжающее вверх
 * вместе с текстом, перестаёт быть оглавлением на второй же странице.
 */
.rail {
    flex: none;
    /* 276, а не 252: в колонке появилась третья строка — источник под названием
       материала, — и на 252 домен переносился на вторую строку. */
    width: 276px;
    align-self: flex-start;
    position: sticky;
    top: var(--topbar-h);
    max-height: calc(100vh - var(--topbar-h));
    overflow-y: auto;
    overscroll-behavior: contain;
    display: flex;
    flex-direction: column;
    gap: var(--sp-6);
    padding: var(--content-pad-y) 24px 40px;
    border-left: 1px solid var(--line);
    background: var(--canvas);
    font-family: var(--font-ui);
}

/*
 * Узкому экрану колонка не достаётся.
 *
 * Она вспомогательная: под ней нет ничего, чего нельзя получить прокруткой. На
 * телефоне же она отняла бы у текста половину ширины.
 */
@media (max-width: 1100px) {
    .rail {
        display: none;
    }
}

.rail-block {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.rail-head {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-3);
}

.rail-time {
    margin-left: auto;
    font-family: var(--font-mono);
    letter-spacing: 0;
    text-transform: none;
}

/*
 * Пункт оглавления. Полоска слева — не рамка, а тень: рамка сдвигала бы текст
 * при переходе от обычного пункта к текущему, и список подрагивал бы.
 */
.rail-item {
    padding-left: 11px;
    font-size: var(--fs-small);
    line-height: 1.45;
    color: var(--text-3);
    text-decoration: none;
    box-shadow: inset 1px 0 0 var(--line);
}

.rail-item:hover {
    color: var(--text-2);
    text-decoration: none;
}

/*
 * В редакторе пункт — кнопка: якорей там нет, скрипт уводит курсор к строке.
 * Браузер даёт кнопке свою подложку, рамку, шрифт и выравнивание по центру —
 * сбрасываем ровно это, остальное задаёт оформление пункта.
 */
button.rail-item {
    display: block;
    width: 100%;
    border: 0;
    background: transparent;
    font: inherit;
    font-size: var(--fs-small);
    text-align: left;
    cursor: pointer;
}

.rail-item.is-active {
    color: var(--text);
    font-weight: 500;
    font-weight: 600;
}

/* Вложенный заголовок отступает — уровень видно, не читая. */
.rail-item.is-sub {
    padding-left: 22px;
}

/*
 * Метка-плашка: `#в-работе` показывается как «В РАБОТЕ».
 *
 * Цвет даётся по закрытому списку — он в TagRenderer, и там же объяснено
 * почему. Здесь только вид: неизвестная метка нейтральная, и это не ошибка, а
 * решение по умолчанию.
 */
.tag {
    display: inline-block;
    padding: 2px 7px;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface-2);
    color: var(--text-3);
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    line-height: 1.5;
    text-transform: uppercase;
    white-space: nowrap;
    /* Плашка мельче строки, и без подъёма она провисает под базовую линию. */
    vertical-align: 1px;
}

.tag-work {
    color: var(--accent);
    background: var(--accent-quiet);
    border-color: var(--accent-line);
}

.tag-done {
    color: var(--ok);
    background: var(--ok-quiet);
    border-color: color-mix(in srgb, var(--ok) 28%, var(--ok-quiet));
}

.tag-urgent {
    color: var(--bad);
    background: var(--bad-quiet);
    border-color: color-mix(in srgb, var(--bad) 28%, var(--bad-quiet));
}

/* Заголовок документа и строка «автор · изменён · версия» под ним. */
.doc-head {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
}

.doc-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    color: var(--text-3);
}

.doc-meta .sep {
    color: var(--line-strong);
}

/*
 * Кружок с инициалами вместо портрета.
 *
 * Портретов у нас нет и не планируется: это рабочая база знаний, а не
 * социальная сеть. Инициалы отвечают на единственный вопрос, который строка
 * задаёт, — кто это писал.
 */
.doc-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--surface-3);
    color: var(--text-2);
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
}

/*
 * Подвал документа: кто менял последним и ссылка в историю.
 *
 * Черта сверху — единственная горизонтальная линия на странице. Она отделяет
 * не раздел от раздела, а документ от служебного: здесь текст кончился.
 */
.doc-foot {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    margin-top: var(--sp-10);
    padding-top: var(--sp-5);
    border-top: 1px solid var(--line);
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    color: var(--text-3);
}

.doc-foot a {
    margin-left: auto;
}

.editor-page {
    display: flex;
    flex-direction: column;
    gap: var(--block-gap, var(--sp-5));
    min-width: 0;
}

/* Шапка истории: название и число версий. */
.history-block {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    margin-top: var(--sp-10);
    padding-top: var(--sp-5);
    border-top: 1px solid var(--line);
}

.history-head {
    display: flex;
    align-items: baseline;
    gap: var(--sp-3);
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

.history-title {
    font-weight: 600;
    color: var(--text);
}

.history-more > summary {
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    color: var(--text-3);
    padding: var(--sp-1) 0;
}

.history-more > summary:hover {
    color: var(--text);
}

.history-more .history {
    margin-top: var(--sp-3);
}

.version {
    font-variant-numeric: tabular-nums;
    color: var(--text-3);
    flex: none;
}

/* Номер версии — ссылка на неё. Подчёркивание появляется под указателем: в
   ленте истории десяток номеров, и десяток подчёркиваний читается как рябь. */
a.version {
    text-decoration: none;
    border-bottom: 1px solid transparent;
}

a.version:hover,
a.version:focus-visible {
    color: var(--text);
    border-bottom-color: var(--line-strong);
}

/* ---------- Сравнение версий ---------------------------------------------- */

/*
 * Знак «+ / −» стоит отдельной колонкой, а не в самой строке: так он не
 * попадает в скопированный текст, и различие видно не только по цвету — тем,
 * кто цвета различает иначе, ничего не теряется.
 *
 * Моноширинный шрифт и `pre-wrap`: сравниваются строки исходного Markdown, где
 * отступы и пробелы — часть смысла.
 */
.diff {
    font-family: var(--font-mono);
    font-size: var(--fs-small);
    line-height: 1.7;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: var(--sp-2) 0;
    overflow-x: auto;
}

.diff-line {
    display: flex;
    gap: var(--sp-3);
    padding: 0 var(--sp-4);
    /* Пустая строка — тоже строка: без высоты она исчезает, и абзацы в
       сравнении слипаются в один. */
    min-height: 1.7em;
}

.diff-mark {
    flex: none;
    width: 1ch;
    color: var(--text-3);
    user-select: none;
}

/*
 * `pre-wrap` — ТОЛЬКО на самом тексте.
 *
 * На строке целиком он ломает вёрстку молча: строка — flex-контейнер, а
 * неразрывные пробелы и переводы строк из разметки шаблона перестают
 * схлопываться и становятся отдельными элементами между знаком и текстом.
 * Каждая строка сравнения растягивалась тогда на три.
 */
.diff-text {
    min-width: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.diff-line.is-add {
    background: var(--ok-quiet);
}

.diff-line.is-add .diff-mark {
    color: var(--ok);
}

.diff-line.is-remove {
    background: var(--bad-quiet);
}

.diff-line.is-remove .diff-mark {
    color: var(--bad);
}

/* Разрыв между далёкими кусками: без него соседние строки врут о соседстве. */
.diff-gap {
    padding: var(--sp-1) var(--sp-4);
    color: var(--text-3);
    user-select: none;
}

/* Квадратик с буквой: у системы вместо логотипа, у человека вместо аватара. */
.brand-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: var(--radius-s);
    background: var(--accent);
    color: var(--canvas);
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    font-weight: 600;
}

.brand-mark-small {
    width: 22px;
    height: 22px;
    background: var(--surface-3);
    color: var(--text-2);
}

/* ---------- Типографика документа ----------------------------------------- */
/*
 * Снято с эталона типографики. Правила общие для отрисованного документа
 * (`.content`) и для живого просмотра (`.cm-*`): иначе правка и просмотр
 * выглядят по-разному, и человек не верит ни тому ни другому.
 *
 * ЦВЕТОВЫХ СЕМЕЙСТВ У ВЫНОСОК ПЯТЬ, А НЕ ШЕСТНАДЦАТЬ. Значок говорит, что это
 * за выноска, цвет — насколько срочно. Пятнадцать разных красок не несут
 * пятнадцати смыслов, они просто пестрят.
 */

/*
 * Пять семейств — ТОЛЬКО ТОКЕНАМИ.
 *
 * Раньше здесь стояли готовые цвета, снятые с тёмного эталона: #14202a, #251a18
 * и прочие. На тёмной теме это выглядело правильно и потому долго не мешало, а
 * на светлой давало тёмно-синюю плашку посреди белого листа. Своё значение в
 * этом файле — это значение, которое не меняется вместе со скином и темой,
 * то есть однажды окажется чужим.
 */
:root {
    --family-neutral-line: var(--line-strong);
    --family-neutral-bg: var(--surface-2);
    --family-neutral-text: var(--text-2);

    --family-blue-line: var(--info);
    --family-blue-bg: var(--info-quiet);
    --family-blue-text: var(--text-2);

    --family-green-line: var(--ok);
    --family-green-bg: var(--ok-quiet);
    --family-green-text: var(--text-2);

    --family-sand-line: var(--accent);
    --family-sand-bg: var(--accent-quiet);
    --family-sand-text: var(--text-2);

    --family-red-line: var(--bad);
    --family-red-bg: var(--bad-quiet);
    --family-red-text: var(--text-2);
}

.content p{
    /* Не даёт последней строке абзаца остаться одним словом. */
    text-wrap: pretty;
}

.content strong,
.cm-strong {
    color: var(--text);
}

.content del,
.cm-strike {
    color: var(--text-3);
    text-decoration-color: var(--line-strong);
}

.content mark,
.cm-highlight {
    background: var(--mark);
    color: var(--text);
    border-radius: 3px;
    padding: 0 3px;
}

.content code,
.cm-inline-code {
    font-family: var(--font-mono);
    font-size: 0.88em;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    padding: 1px 5px;
    color: var(--text);
}

/*
 * Подчёркивание ссылки — решение скина, а не поведение, поэтому его здесь нет.
 * Оно живёт в skins.css: в quiet и dense ссылка подчёркнута всегда, в paper —
 * только под указателем, как в его эталоне.
 */
.content a,
.cm-link {
    text-decoration: none;
}

/* Ссылка на соседний документ отличается подложкой: видно, что она внутренняя. */
.content .wikilink{
    background: var(--accent-quiet);
    border-radius: 3px;
    padding: 0 4px;
}

/* Точка списка — акцентная и мелкая: маркер не должен спорить с текстом. */
.content ul:not([class]) {
    list-style: none;
    padding-left: 20px;
}

.content ul:not([class]) > li {
    position: relative;
}

.content ul:not([class]) > li::before {
    content: "";
    position: absolute;
    left: -20px;
    top: 0.62em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
}

.content ol:not([class]) {
    padding-left: 34px;
}

.content ol:not([class]) > li::marker {
    font-family: var(--font-mono);
    font-size: 0.8em;
    color: var(--text-3);
}

/*
 * Иллюстрация с подписью.
 *
 * Подпись приходит из заголовка ссылки — `![что видно](адрес "подпись")`. Она
 * стоит ПОД картинкой и мельче текста: подпись объясняет картинку, а не спорит
 * с абзацем, рядом с которым лежит.
 */
.content figure{
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin: 0;
}

.content img{
    max-width: 100%;
    height: auto;
}

.content figure img{
    display: block;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-2);
}

.content figcaption{
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    line-height: 1.5;
    color: var(--text-3);
}

.content blockquote,
.cm-quote {
    padding-left: 18px;
    /* Цитата держится ОТСТУПОМ, а не полосой: полоса делала её «важной»,
       хотя цитата — чужие слова, а не выделенное место. */
    padding-left: 22px;
    font-style: italic;
    color: var(--text-2);
}

/* ---------- Задачи --------------------------------------------------------- */

/*
 * Чекбокс — орган управления, а не картинка чекбокса.
 *
 * Размеры с эталона: 18 точек, скругление 5, рамка полтора пикселя. Отмеченный
 * заливается акцентом и получает галочку, а подпись гаснет и зачёркивается —
 * список читается сверху вниз одним взглядом, без вчитывания.
 */
.cm-task,
.content input[type='checkbox']{
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 18px;
    height: 18px;
    margin: 0 8px 0 0;
    border: 1.5px solid var(--line-strong);
    border-radius: var(--radius-s);
    background: transparent;
    color: transparent;
    font-family: var(--font-ui);
    font-size: 11px;
    line-height: 1;
    vertical-align: -3px;
    cursor: pointer;
}

.cm-task:hover,
.content input[type='checkbox']:hover{
    border-color: var(--accent);
}

.cm-task:focus-visible,
.content input[type='checkbox']:focus-visible{
    outline: var(--focus-width) solid var(--accent);
    outline-offset: 2px;
}

.cm-task.is-done,
.content input[type='checkbox']:checked{
    background: var(--ok);
    border-color: var(--ok);
    color: var(--accent-contrast);
}



/* Сделанное гаснет: список читается по тому, что осталось. */
.cm-task-done,
.content li:has(input[type='checkbox']:checked){
    color: var(--text-3);
    text-decoration: line-through;
    text-decoration-color: var(--line-strong);
}

/* У пунктов с задачами своей точки нет — её заменяет чекбокс. */
.content li:has(input[type='checkbox'])::before{
    display: none;
}

/* ---------- Выноски: пять семейств ---------------------------------------- */

/*
 * ОДНА ПЛАШКА НА ДВА СОСТОЯНИЯ.
 *
 * В отрисованном документе плашка — один узел с рамкой. В редакторе целого
 * блока не существует: декорация висит на КАЖДОЙ строке, и рамка собирается из
 * боков у всех, верха у первой и низа у последней.
 *
 * Сборка разная, числа одни. Они держатся в переменных ровно затем, чтобы их
 * нельзя было поправить в одном месте и забыть в другом, — а именно это и
 * случилось: рамку плашки переделали в чтении, а в правке осталась прежняя
 * полоса в две точки цветом акцента, и она рисовалась ПОВЕРХ новой рамки.
 * Разошлось молча, потому что каждое состояние по отдельности выглядело
 * осмысленно.
 */
.callout,
.cm-callout {
    --line-colour: var(--family-neutral-line);
    --bg-colour: var(--family-neutral-bg);
    --body-colour: var(--family-neutral-text);
    --callout-pad-x: 18px;
    --callout-pad-y: 16px;
    /* Готовый цвет рамки, если он у семейства назван, иначе осветлённая линия. */
    --callout-frame: var(--frame-colour, color-mix(in srgb, var(--line-colour) 28%, var(--bg-colour)));
}

.callout {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 4px 12px;
    padding: var(--callout-pad-y) var(--callout-pad-x);
    background: var(--bg-colour);
    /*
     * РАМКА И ПОЛОСА ВМЕСТЕ, и рамка светлее полосы.
     *
     * Полоса слева называет семейство в полную силу — по ней плашку узнают, не
     * читая. Рамка только замыкает блок, и сплошная линия в ту же силу спорила
     * бы с текстом, ради которого плашка нарисована.
     *
     * Я это уже переделывал в другую сторону — оставлял одну рамку без полосы.
     * Здесь пара, и она осознанная: одна рамка не отличала семейства с
     * расстояния, с которого читают заголовок.
     */
    border: 1px solid var(--callout-frame);
    border-radius: var(--radius-s);
}

.callout .callout-icon {
    grid-row: 1 / span 2;
    align-self: start;
    font-size: 15px;
    line-height: 1.5;
}

.callout .callout-title,
.cm-callout .callout-title {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    font-family: var(--font-ui);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--line-colour);
}

.callout .callout-body {
    grid-column: 2;
    font-size: 17px;
    line-height: 1.62;
    color: var(--body-colour);
}

/*
 * Внутри плашки отступы задаём мы, а не браузер.
 *
 * У `ul` и `p` есть свои поля по умолчанию, и снаружи, в `.content`, они
 * обнулены — а внутри выноски оставались. Список внутри заметки из-за этого
 * отбивался снизу лишними пятнадцатью точками, и плашка выглядела с провисшим
 * дном.
 */
.callout .callout-body > * {
    margin: 0;
}

.callout .callout-body > * + * {
    margin-top: var(--sp-2);
}

.callout .callout-body > :first-child {
    margin-top: 0;
}

/* Сворачиваемая: та же плашка, шапка строкой. */
details.callout {
    display: block;
    padding: 0;
    overflow: hidden;
}

details.callout > summary {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 18px;
}

details.callout > .callout-body {
    padding: 0 18px 16px 44px;
}

/*
 * Подпись «свернуть» и шеврон перед ней.
 *
 * СЛОВО ОСТАЁТСЯ. Один значок пришлось бы разгадывать; слово говорит, что
 * произойдёт, и говорит это на языке страницы.
 *
 * Треугольник из шрифта заменён своим контуром: он был единственным местом,
 * где вид знака решала операционная система. Оба псевдоэлемента — элементы
 * флексбокса, поэтому порядок задаётся `order`, а не тем, какой из них
 * `::before`.
 */
details.callout > summary::before {
    content: "";
    order: 1;
    width: 12px;
    height: 12px;
    margin-left: auto;
    background: var(--line-colour);
    -webkit-mask: var(--ico-disclose) center / contain no-repeat;
    mask: var(--ico-disclose) center / contain no-repeat;
    transition: transform var(--dur, .15s) var(--ease, ease);
    --ico-disclose: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.25 3.75L10.5 8l-4.25 4.25'/%3E%3C/svg%3E");
}

details.callout[open] > summary::before {
    transform: rotate(90deg);
}

details.callout > summary::after {
    content: "свернуть";
    order: 2;
    font-family: var(--font-ui);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--line-colour);
}

details.callout:not([open]) > summary::after {
    content: "раскрыть";
}

/* Распределение типов по семействам. */
.callout-note, .cm-callout-note,
.callout-info, .cm-callout-info,
.callout-abstract, .cm-callout-abstract,
.callout-todo, .cm-callout-todo {
    --line-colour: var(--family-blue-line);
    --bg-colour: var(--family-blue-bg);
    --body-colour: var(--family-blue-text);
    /* Цвет рамки эталон задаёт отдельным значением, а не осветлением своего
       акцента: подобрать его смешиванием нельзя — по трём каналам получаются
       три разные доли. */
    --frame-colour: var(--info-line);
}

.callout-tip, .cm-callout-tip,
.callout-success, .cm-callout-success {
    --line-colour: var(--family-green-line);
    --bg-colour: var(--family-green-bg);
    --body-colour: var(--family-green-text);
}

.callout-important, .cm-callout-important,
.callout-warning, .cm-callout-warning,
.callout-caution, .cm-callout-caution,
.callout-question, .cm-callout-question {
    --line-colour: var(--family-sand-line);
    --bg-colour: var(--family-sand-bg);
    --body-colour: var(--family-sand-text);
    --frame-colour: var(--accent-line);
}

.callout-danger, .cm-callout-danger,
.callout-bug, .cm-callout-bug,
.callout-failure, .cm-callout-failure {
    --line-colour: var(--family-red-line);
    --bg-colour: var(--family-red-bg);
    --body-colour: var(--family-red-text);
}

/* Пример и цитата остаются нейтральными: они ничего не требуют от читателя. */

/* ---------- Таблица -------------------------------------------------------- */

.content .table-scroll,
.cm-editor .table-scroll {
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.content .table-scroll table,
.cm-editor .table-scroll table {
    font-family: var(--font-ui);
    font-size: 14px;
    border-collapse: collapse;
    width: 100%;
}

.content .table-scroll th,
.cm-editor .table-scroll th {
    background: var(--surface-2);
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
}

.content .table-scroll th,
.content .table-scroll td,
.cm-editor .table-scroll th,
.cm-editor .table-scroll td {
    padding: 11px 16px;
    border: 0;
    border-left: 1px solid var(--line);
    border-bottom: 1px solid var(--surface-3);
    color: var(--text-2);
    vertical-align: top;
}

.content .table-scroll th:first-child,
.content .table-scroll td:first-child,
.cm-editor .table-scroll th:first-child,
.cm-editor .table-scroll td:first-child {
    border-left: 0;
}

.content .table-scroll tr:last-child td,
.cm-editor .table-scroll tr:last-child td {
    border-bottom: 0;
}

/* ---------- Блок кода ------------------------------------------------------ */

.content pre{
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 14px 16px;
    font-family: var(--font-mono);
    font-size: 14px;
    line-height: 1.65;
    color: var(--text);
}

/* ---------- Разделитель ---------------------------------------------------- */

/*
 * Черта — точка — черта. Обычная линия во всю ширину режет страницу пополам;
 * точка посередине превращает разрыв в паузу.
 */
.content hr,
.cm-editor hr {
    border: 0;
    height: 4px;
    margin: 8px 0;
    background:
        linear-gradient(var(--line), var(--line)) left center / calc(50% - 12px) 1px no-repeat,
        radial-gradient(circle, var(--line-strong) 2px, transparent 2px) center / 100% 100% no-repeat,
        linear-gradient(var(--line), var(--line)) right center / calc(50% - 12px) 1px no-repeat;
}

/*
 * Та же плашка, собранная из строк.
 *
 * Селектор начинается с `.cm-editor` не для красоты. CodeMirror добавляет своё
 * `.cm-line { padding: 0 2px 0 6px }` в head во время работы — то есть ПОЗЖЕ
 * наших файлов, и при равной силе побеждает. Пока правило звалось просто
 * `.cm-callout`, поля плашки в правке были шесть точек против шестнадцати в
 * чтении: заявленные восемнадцать не доезжали никогда.
 */
.cm-editor .cm-callout {
    padding-left: var(--callout-pad-x);
    padding-right: var(--callout-pad-x);
    background: var(--bg-colour);
    color: var(--body-colour);
    /* Полоса слева — у КАЖДОЙ строки: в чтении она идёт во всю высоту плашки,
       и разорванная на строках читалась бы пунктиром. */
    border-left: 1px solid var(--callout-frame);
    border-right: 1px solid var(--callout-frame);
}

.cm-editor .cm-callout-first {
    padding-top: var(--callout-pad-y);
    border-top: 1px solid var(--callout-frame);
    border-top-left-radius: var(--radius-s);
    border-top-right-radius: var(--radius-s);
}

.cm-editor .cm-callout-last {
    padding-bottom: var(--callout-pad-y);
    border-bottom: 1px solid var(--callout-frame);
    border-bottom-left-radius: var(--radius-s);
    border-bottom-right-radius: var(--radius-s);
}

.cm-callout .callout-title {
    display: inline-flex;
    align-items: center;
    gap: 12px;
}

/* Перемещение по дереву: спрятано под сводкой, потому что делают его редко. */
.move-block {
    margin-top: var(--sp-5);
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    color: var(--text-3);
}

.move-block > summary {
    cursor: pointer;
    padding: var(--sp-1) 0;
}

.move-block > summary:hover {
    color: var(--text);
}

/*
 * Сколько документов внутри раздела.
 *
 * Справа и приглушённо: это справка, а не то, ради чего строку читают. Число
 * моноширинное — иначе колонка счётчиков дёргается на каждой строке.
 */
.tree-count {
    margin-left: auto;
    flex: none;
    font-family: var(--font-mono);
    font-size: var(--fs-small);
    font-variant-numeric: tabular-nums;
    color: var(--text-3);
}

/* Треугольник у раздела с вложенными документами. */
.tree-mark {
    flex: none;
    color: var(--text-3);
    font-size: 10px;
}

.sidebar-foot-out {
    margin-left: auto;
}

/* Меню «ещё» в тулбаре. Родной details: раскрывается без единой строки скрипта. */
.tool-more {
    position: relative;
}

.tool-more > summary {
    list-style: none;
    cursor: pointer;
}

.tool-more > summary::-webkit-details-marker {
    display: none;
}

.tool-more-menu {
    position: absolute;
    top: calc(100% + var(--sp-2));
    right: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/*
 * Пункт меню — кнопка, а оформление рассчитано на ссылку.
 *
 * Браузер добавляет кнопке свою подложку, рамку и шрифт, и пункты превращались
 * в серые прямоугольники, налезающие друг на друга. Сбрасываем ровно это, не
 * трогая всё остальное: цвета, отступы и подсветку задаёт оформление.
 */
button.popover-item {
    width: 100%;
    border: 0;
    background: transparent;
    font: inherit;
    text-align: left;
}

/* Название и пояснение под ним — как в эталоне. */
.popover-label {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.popover-name {
    color: inherit;
}

.popover-desc {
    font-size: var(--fs-small);
    color: var(--text-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ---------- Страницы без оболочки ----------------------------------------- */

/* Вход и подтверждение входа: боковой панели ещё нет. */
.plain {
    min-height: 100%;
    display: grid;
    place-items: center;
}

/* ---------- Задачи: доска, список, карточка ------------------------------- */

/*
 * Полоса вида и фильтров. Обычная форма method="get": экран остаётся адресом,
 * который можно послать коллеге, и работает без единой строчки скрипта.
 */
.task-bar {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    flex-wrap: wrap;
    margin-top: var(--sp-4);
    padding-bottom: var(--sp-4);
    border-bottom: 1px solid var(--line);
}

.task-views {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
}

.task-view {
    padding: 4px 12px;
    border-radius: calc(var(--radius-s) - 2px);
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    color: var(--text-3);
    text-decoration: none;
    white-space: nowrap;
}

.task-view:hover {
    color: var(--text);
    text-decoration: none;
}

.task-view.is-active {
    background: var(--surface);
    color: var(--text);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
}

/* Номер задачи. Моноширинный, потому что о номерах говорят вслух и их сверяют
   глазами: «сорок вторая» ищется в столбце, а не в потоке. */
.task-number {
    font-family: var(--font-mono);
    font-size: var(--fs-small);
    color: var(--text-3);
    white-space: nowrap;
}

.task-new {
    display: flex;
    gap: var(--sp-2);
    align-items: center;
    flex-wrap: wrap;
    margin-top: var(--sp-4);
}

/*
 * Доска. Колонки прокручиваются вбок ВНУТРИ себя, а не всей страницей:
 * горизонтальная прокрутка body уносит вместе с доской и боковую панель, и
 * заголовок — это ровно та поломка, которую однажды уже чинили в редакторе.
 */
.board {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(260px, 1fr);
    gap: var(--sp-4);
    align-items: start;
    margin-top: var(--sp-6);
    overflow-x: auto;
    padding-bottom: var(--sp-2);
}

.board-column {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    min-width: 0;
}

.board-head {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin: 0;
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
    font-weight: 600;
    color: var(--text-2);
}

.board-cards {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    min-height: 60px;
    padding: var(--sp-2);
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

/* Колонка, над которой держат карточку. Подсветка всей колонки, а не щели
   между карточками: порядка внутри колонки нет, и целиться некуда. */
.board-cards.is-target {
    border-color: var(--accent);
    background: var(--accent-quiet);
}

.board-empty {
    margin: 0;
    padding: var(--sp-3) var(--sp-2);
    text-align: center;
    font-size: var(--fs-small);
}

.card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-3);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
}

.card:hover {
    border-color: var(--line-strong);
}

/* Карточка, которую тащат. Полупрозрачная, чтобы было видно, куда кладут. */
.card.is-dragging {
    opacity: 0.5;
}

.card-title {
    color: var(--text);
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
    line-height: 1.4;
    text-decoration: none;
}

.card-title:hover {
    text-decoration: underline;
}

.card-meta {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    flex-wrap: wrap;
}

.card-who {
    font-family: var(--font-ui);
    font-size: var(--fs-small);
    color: var(--text-3);
}

/* Стрелки переноса. Прижаты вправо и приглушены: это запасной путь для тех,
   кто не тащит мышью, а не главное действие карточки. */
.card-move {
    display: flex;
    gap: var(--sp-2);
    justify-content: flex-end;
    margin-top: -2px;
}

.card-move button {
    padding: 0 var(--sp-2);
    color: var(--text-3);
    font-size: 15px;
    line-height: 1.2;
}

.card-move button:hover {
    color: var(--accent);
}

/* На узком экране доска перестаёт быть доской: три колонки в 360 пикселей не
   помещаются ни при каком размере шрифта. Становится списком колонок сверху
   вниз — то же содержимое, тот же порядок, без бокового возюканья. */
@media (max-width: 720px) {
    .board {
        grid-auto-flow: row;
        grid-auto-columns: auto;
        overflow-x: visible;
    }
}

/* ---------- Таблица в редакторе ------------------------------------------- */

/*
 * Ячейка — поле ввода, и это должно быть видно ДО щелчка, а не после.
 * Курсор-текст вместо стрелки: единственный признак, который человек читает,
 * не нажимая.
 */
.cm-table th,
.cm-table td {
    cursor: text;
}

/* Ячейка под правкой. Подсветка внутренней тенью, а не рамкой: рамка сдвигает
   содержимое на свою толщину, и вся таблица дёргается при переходе Tab'ом. */
.cm-table th:focus,
.cm-table td:focus {
    outline: none;
    background: var(--accent-quiet);
    box-shadow: inset 0 0 0 2px var(--accent);
}

/* Пустая ячейка не должна схлопываться в невидимую полоску: попасть в неё
   мышью иначе нечем. */
.cm-table th:empty::after,
.cm-table td:empty::after {
    content: "";
    display: inline-block;
    min-width: 1px;
}

/* ---------- Ширина колонок таблицы ---------------------------------------- */

/*
 * ФИКСИРОВАННАЯ ШИРИНА ЗАДАЁТСЯ ДВОЕТОЧИЯМИ В СТРОКЕ-РАЗДЕЛИТЕЛЕ — теми же,
 * что задают выравнивание, и ничего нового учить не приходится.
 *
 * В эталоне первая колонка 44px под номер, последняя 132px под статус, а
 * середина забирает остаток. Само по себе из Markdown это не следует: браузер
 * раздаёт ширину по содержимому, и колонка «#» с числом «01» получает столько
 * же, сколько колонка с предложением.
 *
 * Правило простое: колонка, выровненная по центру или по правому краю, — это
 * колонка коротких значений (номер, статус, срок, сумма). Ей хватает ширины
 * содержимого, и растягиваться ей незачем. Всё остальное делят остаток.
 *
 * Так `| :---: |` и `| ---: |` начинают значить не только «как показать», но и
 * «сколько занять», — и это честно: короткие значения и центруют, потому что
 * они короткие.
 */
.table-scroll th[align="center"],
.table-scroll th[align="right"],
.table-scroll td[align="center"],
.table-scroll td[align="right"] {
    width: 1%;
    white-space: nowrap;
}

/* Ячейка, которой всё же не хватило: перенос важнее неразрывности. */
.table-scroll th[align="center"] > *,
.table-scroll th[align="right"] > *,
.table-scroll td[align="center"] > *,
.table-scroll td[align="right"] > * {
    white-space: normal;
}

/*
 * Служебная пустая строка внутри выноски.
 *
 * `>` без текста в Markdown склеивает ссылку с её подписью в один пункт — в
 * отрисованном документе между ними нет ничего. В редакторе строка существует,
 * в неё ставят курсор, и убрать её нельзя; но занимать целую полосу во всю
 * ширину плашки она не должна — так правка выглядела иначе, чем чтение.
 */
.cm-callout-gap {
    font-size: 0;
    line-height: 8px;
}

/* ---------- Оснастка правки: появляется, когда правят ---------------------- */

/*
 * Панель разметки и счётчик слов нужны в те минуты, когда в тексте стоит
 * курсор. Висели они всегда — и человек, пришедший прочитать регламент,
 * встречал их первыми.
 *
 * `visibility`, а не `display`: место остаётся занятым, и текст не прыгает
 * вверх-вниз при каждом входе в редактор и выходе из него. Прыгающий текст
 * под курсором хуже лишней панели.
 */
.editor-page .toolbar,
.editor-page .editor-foot {
    visibility: hidden;
    opacity: 0;
    transition: opacity var(--dur) var(--ease);
}

.editor-page.is-editing .toolbar,
.editor-page.is-editing .editor-foot {
    visibility: visible;
    opacity: 1;
}

/* Без скрипта оснастка видна всегда: прятать то, что нечем показать обратно,
   значит оставить человека без кнопки сохранения. */
.editor:not(.is-live) ~ .editor-foot,
.editor-page:has(.editor:not(.is-live)) .toolbar,
.editor-page:has(.editor:not(.is-live)) .editor-foot {
    visibility: visible;
    opacity: 1;
}

/* ---------- Доработка: заголовок и ритм разделов -------------------------- */

[data-skin="paper"] .content h1,
[data-skin="paper"] .title-input {
    line-height: 1.1;
    letter-spacing: var(--tracking-title, -0.01em);
}

/* Раздел отбивается сильнее, раз заголовок статьи стал крупнее: 52 сверху,
   8 снизу. Заголовок по-прежнему принадлежит следующему абзацу, а не пустоте. */
[data-skin="paper"] .content > h2 {
    margin-top: 52px;
    letter-spacing: -0.016em;
}

/* ---------- Доработка: решётка таблицы ------------------------------------ */

/*
 * Лестница линий: внешняя рамка темнее внутренних вертикальных, а те темнее
 * горизонтальных. Раньше все три были одного цвета, и решётка спорила с
 * текстом — глаз читал сетку раньше строк.
 *
 * Правило написано и для редактора: одна разметка — один вид.
 */
[data-skin="paper"] :is(.content, .cm-editor) .table-scroll :is(th, td) {
    padding: 13px 14px;
    border-bottom: 1px solid var(--line-hair);
    border-left: 1px solid var(--line-soft);
    border-right: 0;
}

[data-skin="paper"] :is(.content, .cm-editor) .table-scroll :is(th, td):first-child {
    border-left: 0;
}

[data-skin="paper"] :is(.content, .cm-editor) .table-scroll th {
    /* Шапка ниже строк: в ней одна строка прописными, и полные 13 сверху и
       снизу делают её тяжелее того, что она подписывает. */
    padding: 9px 14px;
    background: var(--canvas);
    border-bottom: 1px solid var(--line);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-3);
}

/*
 * У последней строки своей линии нет — её роль играет рамка обёртки. Две
 * линии подряд в одну точку читаются как утолщение, и низ таблицы получается
 * тяжелее верха.
 */
[data-skin="paper"] .content tr:last-child td {
    border-bottom: 0;
}

/*
 * Колонка номера и колонка статуса не переносятся и потому забирают минимум
 * ширины — остаток достаётся описанию. Предел в три знака при этом остаётся:
 * без него «01» разваливалось на «0» и «1» там, где ячейка наследует от
 * CodeMirror `white-space: break-spaces`.
 */
[data-skin="paper"] :is(.content, .cm-editor) .table-scroll td:first-child,
[data-skin="paper"] :is(.content, .cm-editor) .table-scroll :is(th, td):last-child {
    white-space: nowrap;
}

[data-skin="paper"] .content tbody tr:hover {
    background: color-mix(in srgb, var(--canvas) 55%, var(--surface));
}

/* ---------- Классы, стоявшие в разметке без единого правила ----------------- */

/*
 * Все шесть нашлись в один час — когда весь набор элементов свели на одну
 * страницу и половину из них оказалось не на что поставить. Каждый стоял в
 * шаблонах с самого начала, и каждый молча ничего не делал:
 *
 *   .row и .stack получали в разметке `gap`, `align-items` и даже `flex: 1` на
 *   потомке — всё это без `display: flex` не значит ничего;
 *   .error красил сообщение «Неверная почта или пароль» цветом обычного текста;
 *   .link оставлял «Выйти» и «Снять правило» кнопками системного вида;
 *   .icon-button и .burger давали на телефоне пустую кнопку открытия панели —
 *   ярлык для программы чтения с экрана на месте, поэтому незрячий человек
 *   панель открывал, а зрячий не видел, чем.
 *
 * Ни одно из этого не падало и не попадало в проверки: невидимое оформление
 * ошибкой не считается нигде, кроме глаз.
 */

.row {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
}

.stack {
    display: flex;
    flex-direction: column;
    gap: var(--sp-3);
    min-width: 0;
}

/* Сообщение о том, что действие не прошло. Цветом, а не только словами: до слов
   человек доходит уже после того, как заметил, что что-то не так. */
.error {
    color: var(--bad);
}

/* Действие без веса кнопки: «Выйти», «Снять правило», «Ссылка для входа». */
.link {
    padding: 0;
    border: 0;
    background: none;
    color: var(--accent);
    font: inherit;
    cursor: pointer;
}

.link:hover {
    text-decoration: underline;
}

/*
 * Вид кнопки со значком объявлен ВЫШЕ, рядом с правилами показа: `display` у
 * него свой, и стоя ниже он побеждал бы `display: none` по правилу «позже —
 * сильнее». Ровно это и случилось: бургер вылез на широкий экран, где панель
 * и так на месте.
 */

/* ---------- Каталог интерфейса (/design) ----------------------------------- */

/*
 * Оформление самой витрины, а не того, что на ней выставлено. Держится в
 * стороне от продуктовых классов и ничего у них не переопределяет: витрина,
 * которая подкрашивает экспонаты, врёт.
 */

.catalog-modes {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-3);
    margin-top: var(--sp-5);
}

.catalog-modes-set {
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-2);
}

.catalog-mode {
    padding: 4px 10px;
    border: 0;
    border-radius: var(--radius-s);
    background: none;
    color: var(--text-3);
    font: inherit;
    font-size: var(--fs-small);
    cursor: pointer;
}

.catalog-mode.is-on {
    background: var(--surface);
    color: var(--text);
    box-shadow: var(--shadow);
}

.catalog-toc {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2) var(--sp-4);
    margin-top: var(--sp-5);
    padding: var(--sp-3) 0;
    border-top: 1px solid var(--line-soft, var(--line));
    border-bottom: 1px solid var(--line-soft, var(--line));
    font-size: var(--fs-small);
}

.catalog-section {
    margin-top: var(--sp-12);
    scroll-margin-top: calc(var(--topbar-h) + var(--sp-4));
}

.catalog-lead {
    max-width: 62ch;
    color: var(--text-2);
}

.catalog-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: var(--sp-3);
    margin-top: var(--sp-4);
}

.catalog-grid-wide {
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.catalog-cell,
.catalog-frame {
    min-width: 0;
    padding: var(--sp-3);
    border: 1px solid var(--line-soft, var(--line));
    border-radius: var(--radius);
    background: var(--surface);
}

.catalog-frame {
    margin-top: var(--sp-4);
    padding: var(--sp-2);
}

.catalog-demo {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 46px;
    margin-bottom: var(--sp-2);
}

.swatch {
    height: 46px;
    margin-bottom: var(--sp-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
}

.catalog-name {
    font-family: var(--font-mono);
    font-size: 11px;
    line-height: 1.4;
    color: var(--text-3);
    overflow-wrap: break-word;
}

.catalog-value {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-4, var(--text-3));
}

.catalog-note {
    margin-top: 4px;
    font-size: 12px;
    line-height: 1.45;
    color: var(--text-3);
}

/* Отношение контраста считается скриптом и приписывается рядом со значением. */
.catalog-ratio {
    display: inline-block;
    margin-top: 2px;
    padding: 0 5px;
    border-radius: 3px;
    font-family: var(--font-mono);
    font-size: 10px;
}

.catalog-ratio.is-ok { background: var(--ok-quiet); color: var(--ok); }
.catalog-ratio.is-warn { background: var(--warn-quiet); color: var(--warn); }
.catalog-ratio.is-bad { background: var(--bad-quiet); color: var(--bad); }

.catalog-scale {
    margin-top: var(--sp-4);
}

.catalog-ruler {
    margin-top: var(--sp-4);
}

.catalog-ruler-row {
    display: grid;
    grid-template-columns: 92px 1fr 48px;
    align-items: center;
    gap: var(--sp-3);
    padding: 3px 0;
}

.catalog-bar {
    height: 10px;
    border-radius: 2px;
    background: var(--accent-quiet);
    box-shadow: inset 0 0 0 1px var(--accent-line);
}

.catalog-icons {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: var(--sp-3);
    margin-top: var(--sp-4);
}

.catalog-icon-cell {
    display: grid;
    grid-template-columns: 40px minmax(0, 1fr);
    gap: var(--sp-3);
    align-items: start;
    min-width: 0;
    padding: var(--sp-3);
    border: 1px solid var(--line-soft, var(--line));
    border-radius: var(--radius);
    background: var(--surface);
}

.catalog-glyph {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border: 1px solid var(--line-hair, var(--line));
    border-radius: var(--radius-s);
    background: var(--canvas);
    font-size: 17px;
    color: var(--text-2);
}

.catalog-icon-means {
    font-size: var(--fs-ui);
    color: var(--text);
}

.catalog-callouts {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--sp-3);
    margin-top: var(--sp-4);
}

/* ---------- Правый край шапки: состояние и смена режима --------------------- */

/*
 * Шапка — единственная полоса, которая не уезжает с текстом, поэтому режим
 * страницы переключается именно здесь: он свойство страницы, а не текста.
 * Слева «где я» (крошки), справа «что я могу».
 *
 * Состояние сохранения стоит вплотную к кнопке намеренно — это причина и
 * следствие: «я правлю» и «и это сохранено» читаются одной строкой.
 */
.topbar-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-left: auto;
}

.mode-button {
    display: inline-flex;
    align-items: center;
    /* 32 по высоте и 12 по бокам: на телефоне это уже палец, а не попадание. */
    min-height: 32px;
    padding: 0 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text-2);
    font: inherit;
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
    line-height: 1;
    text-decoration: none;
    cursor: pointer;
    white-space: nowrap;
}

.mode-button:hover {
    border-color: var(--line-strong);
    background: var(--surface-2);
    color: var(--text);
    text-decoration: none;
}

/*
 * «Готово» — единственное действие на странице, которое что-то закрывает, и
 * потому единственное, набранное в полную силу. «Изменить» остаётся тихим:
 * оно ничего не меняет, а только разрешает менять.
 */
.mode-button.is-done {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--accent-contrast);
}

.mode-button.is-done:hover {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--accent-contrast);
    filter: brightness(1.08);
}

/* На узком экране от крошек остаётся хвост, а кнопка не жмётся никогда:
   уйти из правки надо иметь возможность всегда. */
@media (max-width: 560px) {
    .topbar .crumbs {
        min-width: 0;
        overflow: hidden;
    }

    .topbar-actions {
        flex: none;
    }
}

/*
 * Поле заголовка — многострочное, и растёт по содержимому.
 *
 * `<input>` не переносится в принципе: длинный заголовок в чтении ложился в две
 * строки, а в правке уезжал за край колонки. Оформлением это не лечится, лечится
 * только сменой элемента.
 *
 * Без скрипта поле остаётся в одну строку и прокручивается — редко, некрасиво,
 * но заголовок правится и сохраняется. Со скриптом высота считается по
 * содержимому и совпадает с заголовком в чтении.
 */
textarea.title-input {
    display: block;
    height: auto;
    overflow: hidden;
    resize: none;
    /* Поле наследует шрифт от `.title-input`, но не перенос: у textarea свой. */
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

/*
 * Поле заголовка встаёт ТОЧНО ТУДА, где стоит заголовок в чтении.
 *
 * Числа не выдуманы, а сняты с чтения: там `h1` берёт отбивку 0.67em из
 * умолчаний браузера, а межстрочный — 1.1 из скина. Записаны той же формулой, а
 * не готовыми точками, чтобы обе величины ехали за кеглем вместе.
 *
 * Расхождение было 31 точка по вертикали: при смене состояния строка автора
 * прыгала, и это первое, что видно глазом.
 */
/* Селектор из двух имён намеренно: в скине межстрочный задан как
   `[data-skin="paper"] .title-input`, и одного имени ему не перебить. */
.doc-head .title-input {
    margin: 0.67em 0;
    line-height: 1.1;
}

/*
 * Галки готовности в чтении.
 *
 * Вид у них тот же, что и был: это по-прежнему флажок, и всё его оформление —
 * размер, галочка, отбивка — описано ОДИН раз, там же, где для документа,
 * который только показывают. Здесь добавляется ровно то, чем рабочая галка
 * отличается от нарисованной: по ней можно попасть.
 *
 * Запрет снимает скрипт, поэтому селектор смотрит на `:not(:disabled)`, а не
 * на класс: без скрипта галка остаётся такой же недоступной, какой её видит
 * читатель без права писать.
 */
.content input[type="checkbox"]:not(:disabled) {
    cursor: pointer;
}

/*
 * ТАБЛИЧНЫЕ ЦИФРЫ там, где числа стоят столбцом.
 *
 * В пропорциональном начертании единица уже семёрки, и колонка номеров едет
 * зубцами: «11» короче «77» на глаз, хотя знаков поровну. Заметно ровно там,
 * где числа читают вертикально — в номерах строк, счётчиках дерева, номерах
 * версий и времени.
 */
:is(.content, .cm-editor) .table-scroll td:first-child,
.tree-count,
.task-number,
.version,
.rail-time,
.catalog-value {
    font-variant-numeric: tabular-nums;
}

/* Номер строки таблицы — служебное, а не содержание: моно и четвёртой ступенью. */
[data-skin="paper"] :is(.content, .cm-editor) .table-scroll td:first-child {
    font-family: var(--font-mono);
    font-size: 13px;
    color: var(--text-4, var(--text-3));
}

/* ---------- Значки выносок ------------------------------------------------- */

/*
 * МАСКОЙ, А НЕ РАЗМЕТКОЙ. Из текста статьи в DOM не попадает ничего, кроме
 * имени класса из закрытого списка: контуры живут в CSS, отрисовщик разметку
 * не собирает, санитайзеру не приходится разрешать `svg` — а разрешив его для
 * значков, мы разрешили бы его и для содержимого документа.
 *
 * Цвет даёт `background`, маска берёт только альфу. Поэтому значок сам следует
 * за семейством, темой и палитрой, и своих цветов у него нет.
 *
 * Тем же кодом закрывается редактор: `.cm-callout-*` получает ту же
 * переменную, и виджет CodeMirror писать не нужно.
 *
 * Было пятнадцать эмодзи. Их рисует система: на трёх ОС три разных рисунка,
 * ни один не наследует цвет и все светятся в тёмной теме цветными пятнами
 * поперёк делового документа.
 */
.callout-icon {
    flex: none;
    width: 16px;
    height: 16px;
    /* Штрих 1,5 иначе провисает относительно прописных в заголовке плашки. */
    margin-top: 2px;
    background: var(--line-colour);
    -webkit-mask: var(--icon) center / 16px 16px no-repeat;
    mask: var(--icon) center / 16px 16px no-repeat;
}

/* Значок ничего не сообщает сверх подписи, и второй источник правды здесь не
   нужен: смысл несёт слово «ВНИМАНИЕ», а не треугольник рядом с ним. */
.callout-icon {
    display: block;
}
.callout-note,
.cm-callout-note,
.callout-abstract,
.cm-callout-abstract {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.75' y='2.75' width='10.5' height='10.5' rx='2'/%3E%3Cpath d='M5.5 6.6h5M5.5 9.6h3.2'/%3E%3C/svg%3E");
}

.callout-info,
.cm-callout-info {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='8' cy='8' r='5.5'/%3E%3Cpath d='M8 7.3v3.5'/%3E%3Ccircle cx='8' cy='5.2' r='0.35' fill='%23000' stroke='none'/%3E%3C/svg%3E");
}

.callout-todo,
.cm-callout-todo {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.75' y='2.75' width='10.5' height='10.5' rx='2'/%3E%3Cpath d='M5.6 8.2 7.4 10l3.2-3.6'/%3E%3C/svg%3E");
}

.callout-tip,
.cm-callout-tip {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2.6a3.4 3.4 0 0 0-2 6.1v1.6h4V8.7a3.4 3.4 0 0 0-2-6.1Z'/%3E%3Cpath d='M6.6 12.6h2.8'/%3E%3C/svg%3E");
}

.callout-success,
.cm-callout-success {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='8' cy='8' r='5.5'/%3E%3Cpath d='M5.6 8.2 7.4 10l3.2-3.6'/%3E%3C/svg%3E");
}

.callout-important,
.cm-callout-important {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 3.2v5.6'/%3E%3Ccircle cx='8' cy='12.1' r='0.45' fill='%23000' stroke='none'/%3E%3C/svg%3E");
}

.callout-warning,
.cm-callout-warning,
.callout-caution,
.cm-callout-caution {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2.8 14 13.2H2Z'/%3E%3Cpath d='M8 6.6v2.8'/%3E%3Ccircle cx='8' cy='11.3' r='0.42' fill='%23000' stroke='none'/%3E%3C/svg%3E");
}

.callout-question,
.cm-callout-question {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='8' cy='8' r='5.5'/%3E%3Cpath d='M6.3 6.2a1.8 1.8 0 1 1 2.4 2.2c-.5.3-.7.6-.7 1.1'/%3E%3Ccircle cx='8' cy='11.2' r='0.4' fill='%23000' stroke='none'/%3E%3C/svg%3E");
}

.callout-danger,
.cm-callout-danger {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='8' cy='8' r='5.5'/%3E%3Cpath d='M4.5 11.5 11.5 4.5'/%3E%3C/svg%3E");
}

.callout-bug,
.cm-callout-bug,
.callout-failure,
.cm-callout-failure {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.75' y='2.75' width='10.5' height='10.5' rx='2'/%3E%3Cpath d='M6 6l4 4M10 6l-4 4'/%3E%3C/svg%3E");
}

.callout-example,
.cm-callout-example {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.4 3.2H4.9A1.9 1.9 0 0 0 3 5.1v1.4c0 .8-.4 1.5-1 1.5.6 0 1 .7 1 1.5v1.4a1.9 1.9 0 0 0 1.9 1.9h1.5'/%3E%3Cpath d='M9.6 3.2h1.5A1.9 1.9 0 0 1 13 5.1v1.4c0 .8.4 1.5 1 1.5-.6 0-1 .7-1 1.5v1.4a1.9 1.9 0 0 1-1.9 1.9H9.6'/%3E%3C/svg%3E");
}

.callout-quote,
.cm-callout-quote {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.2 4.4C4.4 5.3 3.4 6.9 3.4 9v2.6h3.2V8.2H5.1c0-1.4.4-2.4 1.1-2.9Z'/%3E%3Cpath d='M12.4 4.4c-1.8.9-2.8 2.5-2.8 4.6v2.6h3.2V8.2h-1.5c0-1.4.4-2.4 1.1-2.9Z'/%3E%3C/svg%3E");
}

/* ---------- Шапка документа: строка над заголовком ------------------------- */

/*
 * Состояние документа и его область. Раньше состояние стояло в шапке приложения
 * рядом с крошками и читалось как состояние страницы; здесь оно рядом с тем,
 * чему принадлежит.
 */
.doc-eyebrow {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 10px;
    margin-bottom: 12px;
}

/*
 * Лид статьи. Класс и ступень шкалы заведены, применяются только по явному
 * указанию автора.
 *
 * Вытаскивать лид из текста самостоятельно — первый абзац до первого заголовка
 * и тому подобное — нельзя: это молча переверстает существующий абзац и в ту же
 * секунду разведёт чтение с правкой. В редакторе тот же абзац остаётся строкой
 * Markdown кеглем 16, а в чтении станет 19. Ровно тот класс расхождений, из-за
 * которого мы уже трижды переделывали одно и то же.
 */
.doc-lede {
    max-width: 640px;
    font-size: var(--fs-lede, 19px);
    line-height: 1.6;
    color: var(--text-2);
}

/* ---------- Индикатор прочтения -------------------------------------------- */

/*
 * Полоса по нижнему краю шапки. Отвечает на вопрос «сколько ещё осталось» —
 * то есть про страницу целиком, а шапка единственное, что видно всегда.
 *
 * Без скрипта ширина остаётся нулевой: полосы просто нет, и место она не
 * занимает.
 */
.topbar {
    position: sticky;
    /* Полоса лежит на нижней границе шапки и выходит за неё на точку. */
    overflow: visible;
}

.read-progress {
    position: absolute;
    inset: auto 0 -1px 0;
    height: 2px;
    pointer-events: none;
}

.read-progress i {
    display: block;
    width: 0;
    height: 2px;
    background: var(--accent);
    /* Короткий переход, а не мгновенный: полоса, дёргающаяся на каждый пиксель
       прокрутки, читается как помеха. */
    transition: width 90ms linear;
}

@media (prefers-reduced-motion: reduce) {
    .read-progress i {
        transition: none;
    }
}

/* ---------- Поверхность правки — сам лист, а не поле на нём ---------------- */

/*
 * `.editor-host` оформлен как поле ввода: своя подложка, рамка, скругление,
 * подсветка по фокусу. Поверх листа это второй слой — в чтении текст лежит
 * прямо на листе, в правке оказывался в коробке, и при переключении вокруг
 * документа появлялась рамка, которой в чтении нет.
 *
 * Одна поверхность на два состояния — то самое решение, ради которого всё
 * остальное и делалось. Коробка снимается, лист остаётся.
 *
 * Подсветка по фокусу тоже уходит: в состоянии правки и так всё говорит, что
 * человек правит, — кнопка «Готово» и строка сохранения в шапке. Обводить ради
 * этого весь документ значит обводить страницу целиком.
 */
.editor-host,
.editor-host:focus-within {
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

/* ---------- Правая колонка: строка материала ------------------------------- */

/*
 * Ссылка наружу перечислена строкой: значок, название, источник под ним.
 * Отрицательные поля по бокам нужны затем, чтобы подсветка по наведению
 * выходила за колонку текста и строка читалась как строка, а не как абзац с
 * подложкой.
 */
.rail-link {
    display: grid;
    grid-template-columns: 24px minmax(0, 1fr);
    gap: 2px 10px;
    align-items: center;
    margin: 0 -10px;
    padding: 9px 10px;
    border-radius: var(--radius-s);
    text-decoration: none;
}

.rail-link:hover {
    background: var(--surface);
    text-decoration: none;
}

.rail-ico {
    grid-row: 1 / span 2;
    display: grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border: 1px solid var(--info-line);
    border-radius: var(--radius-s);
    background: var(--info-quiet);
    color: var(--info);
    font-size: 11px;
}

.rail-name {
    grid-column: 2;
    font-size: 13px;
    line-height: 1.4;
    color: var(--info);
    /* Название переносится по словам, а не обрезается: обрезанное имя документа
       отвечает на вопрос «тот ли это документ» хуже, чем две строки. */
    overflow-wrap: break-word;
}

.rail-src {
    grid-column: 2;
    font-size: 11px;
    color: var(--text-4, var(--text-3));
}

/* Справка под колонкой: версия и сравнение. Тише всего на странице. */
.rail-block-quiet {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 10px;
    font-size: 12px;
    color: var(--text-3);
}

/*
 * Текущий раздел в оглавлении: полоса слева и вес, а не только цвет. Цветом
 * одним отличать нельзя — при слабом контрасте экрана он теряется, а полоса
 * видна всегда.
 */
.rail-item.is-active {
    color: var(--text);
    font-weight: 500;
    font-weight: 600;
}

/* ---------- Левая панель: шапка, поиск, дерево ----------------------------- */

/*
 * Переключатель проекта. Сетка закреплена по колонкам ЯВНО: аватар занимает
 * две строки, а элементы с `grid-row: span 2` без явной колонки расставляются
 * по порядку в DOM и ломают раскладку — название уезжает под аватар.
 */
.project-switch {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr) 12px;
    gap: 0 10px;
    align-items: center;
    min-width: 0;
    padding: 6px 8px;
    margin: 0 -8px;
    border-radius: var(--radius-s);
    text-decoration: none;
}

.project-switch:hover {
    background: var(--surface-2);
    text-decoration: none;
}

.project-switch .brand-mark {
    grid-column: 1;
    grid-row: 1 / span 2;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-s);
}

.project-name {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.project-note {
    grid-column: 2;
    grid-row: 2;
    min-width: 0;
    font-size: 11px;
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.project-chevron {
    grid-column: 3;
    grid-row: 1 / span 2;
    color: var(--text-4, var(--text-3));
}

/* Поиск и «новый документ» — одной строкой: два действия над одним списком. */
.sidebar-find {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 var(--sp-2);
}

.sidebar-find .sidebar-search {
    position: relative;
    flex: 1;
    min-width: 0;
    padding: 0;
}

.sidebar-find .sidebar-search input {
    border-color: var(--line-soft, var(--line));
    border-radius: var(--radius-s);
    /* Место справа под подсказку сочетания: без него текст запроса въезжает
       под неё. */
    padding-right: 40px;
}

.search-hint {
    position: absolute;
    top: 50%;
    right: 8px;
    transform: translateY(-50%);
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-4, var(--text-3));
    pointer-events: none;
}

/* Поле сузилось — подсказка мешает больше, чем помогает. */
.sidebar-search input:focus + .search-hint {
    display: none;
}

.icon-button.sidebar-new {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-s);
    font-size: 17px;
}

/* Микро-заголовок с волосяной линией во всю оставшуюся ширину. */
.tree-heading {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: var(--sp-4) 8px var(--sp-2);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-4, var(--text-3));
}

.tree-heading .rule {
    flex: 1;
    height: 1px;
    background: var(--line-soft, var(--line));
}

/*
 * Вложенные документы: ветка показана линией, а не отступом.
 *
 * `min-width: 0` обязателен и здесь, и на самой навигации: без него длинное
 * название не сжимается, и панель едет вбок вместе с деревом.
 */
.sidebar-tree,
.tree-nest {
    min-width: 0;
}

.tree-nest {
    margin-left: 16px;
    padding-left: 8px;
    border-left: 1px solid var(--line-soft, var(--line));
}

.tree-item {
    padding-left: 8px;
}

/*
 * Открытый документ — приподнятая карточка, а не просто другой цвет. Полоса
 * слева говорит «вот он», лёгкая тень отделяет от списка. Название переносится
 * по словам: обрезанное отвечает на вопрос «тот ли это документ» хуже, чем две
 * строки.
 */
.tree-item.is-active {
    background: var(--surface);
    border: 1px solid var(--line-soft, var(--line));
    border-radius: var(--radius-s);
    /* Открытый документ — ПОДЛОЖКОЙ и весом, а не полосой. Полоса делала
       каждый выделенный элемент «важным» и спорила с сеткой. */
    background: var(--surface-sel, var(--surface));
    font-weight: 600;
    box-shadow: 0 1px 2px rgba(28, 27, 24, 0.05);
}

.tree-item.is-active .tree-title {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    overflow-wrap: break-word;
}

/* ---------- Кнопки: одно описание вместо пяти -------------------------------- */

/*
 * До этого места общего описания кнопки в продукте НЕ БЫЛО. Каждое место
 * красило свои: `.login-card button`, `.card-move button`, `button.rail-item`,
 * `button.popover-item`. Пока их было четыре вида, это не мешало; на пятом они
 * разъехались бы, и разъехались бы молча.
 *
 * Описан сам элемент, а не класс `.btn`: тогда правило достаёт до всех кнопок
 * сразу, не требуя переписать разметку. Места со своим видом сохраняют его —
 * у них селектор сильнее.
 */
button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 32px;
    padding: 0 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
    line-height: 1;
    cursor: pointer;
}

button:hover {
    border-color: var(--line-strong);
    background: var(--surface-2);
}

/* Главная: одна на экран. Две главные кнопки рядом — это ни одной главной. */
button.primary {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--accent-contrast);
    font-weight: 600;
}

button.primary:hover {
    border-color: var(--accent);
    background: var(--accent);
    filter: brightness(1.08);
}

/* Тихая: действие, которое ничего не меняет либо уводит со страницы. */
.link {
    min-height: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-3);
}

.link:hover {
    border: 0;
    background: none;
    color: var(--text);
    text-decoration: underline;
}

/*
 * Недоступная. Цветом И курсором: одного цвета мало — человек с бледным экраном
 * жмёт и не понимает, почему ничего не происходит.
 */
:where(button, input, select, textarea):disabled {
    border-color: var(--line-soft, var(--line));
    background: var(--surface-2);
    color: var(--text-4, var(--text-3));
    cursor: not-allowed;
}

/* Кнопка в шапке ниже прочих: полоса шапки и так тесная. */
.topbar button,
.topbar .mode-button {
    min-height: 30px;
}

/* ---------- Поля ----------------------------------------------------------- */

:where(input[type="text"], input[type="email"], input[type="password"],
       input[type="search"], input[type="number"], select, textarea) {
    min-height: 32px;
    padding: 0 10px;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

textarea {
    padding: 8px 10px;
    line-height: 1.5;
}

/*
 * Поле, которое не приняли, — рамкой. Тем же классом, что и сообщение об
 * ошибке: одно слово на одно значение, а вид у текста и у поля разный сам
 * собой, потому что это разные элементы.
 */
:where(input, select, textarea).error {
    border-color: var(--bad);
}

/* ---------- Состояния страницы --------------------------------------------- */

/*
 * Полоса предупреждения. Значок тот же контур «риск», что и в выносках, — не
 * эмодзи: тот рисовала система, и на трёх ОС он выглядел по-разному.
 */
.notice::before {
    content: "";
    flex: none;
    width: 16px;
    height: 16px;
    margin-top: 2px;
    background: var(--warn);
    -webkit-mask: var(--icon-risk) center / 16px 16px no-repeat;
            mask: var(--icon-risk) center / 16px 16px no-repeat;
}

/* Пустое место: пунктир говорит «здесь может быть», сплошная рамка — «здесь
   что-то есть». Разница ровно в этом. */
.board-empty {
    padding: var(--sp-5) var(--sp-4);
    border: 1px dashed var(--line);
    border-radius: var(--radius-s);
    font-size: var(--fs-ui);
    color: var(--text-3);
    text-align: center;
}

/* Сравнение версий: моно и знак отдельной колонкой — так строки не съезжают
   и знак не путается с содержимым строки. */
.diff {
    font-family: var(--font-mono);
    font-size: 13px;
}

.diff-mark {
    flex: none;
    width: 1.5em;
    text-align: center;
    color: var(--text-4, var(--text-3));
}

/*
 * Контур «риск» доступен всей странице, а не только выноскам: тем же знаком
 * помечена полоса предупреждения. Один контур на одно значение.
 */
:root {
    --icon-risk: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2.8 14 13.2H2Z'/%3E%3Cpath d='M8 6.6v2.8'/%3E%3Ccircle cx='8' cy='11.3' r='0.42' fill='%23000' stroke='none'/%3E%3C/svg%3E");
}

/*
 * СОБСТВЕННОЕ ПОЛЕ РЕДАКТОРА СНЯТО.
 *
 * CodeMirror добавляет `.cm-content { padding: … 16px }` от себя. Пока
 * редактор был полем ввода в рамке, это поле было уместно — оно отбивало текст
 * от рамки. Рамку мы сняли, а поле осталось: весь текст в правке стоял на
 * шестнадцать точек правее, чем в чтении. Глазом это не видно ни на одном
 * элементе по отдельности — видно только при переключении, и то как «что-то
 * дёрнулось».
 *
 * Найдено приёмкой: одинаковый сдвиг вбок у выноски, у таблицы и у раздела.
 * Отступ строки (6 точек) остаётся — на нём стоит курсор в начале строки.
 */
.cm-editor .cm-content {
    padding-left: 0;
    padding-right: 0;
}

/*
 * ФОРМА ПРАВКИ НАЧИНАЕТСЯ ТАМ ЖЕ, ГДЕ ТЕКСТ В ЧТЕНИИ.
 *
 * Ритм документа задан правилом `.content > * + *`, и оно честно дало форме
 * отступ 12 сверху: перед ней в разметке стоят служебные формы — ширины,
 * статуса, архива. Они `hidden` и не занимают ни точки, но соседями быть не
 * перестают, а соседний селектор смотрит на разметку, а не на видимость.
 *
 * Отсюда и все семь оставшихся расхождений: шапка документа съезжала на 12, и
 * дальше сдвиг накапливался по всей странице. Одна строка наверху страницы
 * стоила сдвига в пятьдесят четыре точки у таблицы внизу.
 */
[data-skin="paper"] .content > .editor-page,
[data-skin="paper"] .content > .task-form {
    margin-top: 0;
}

/*
 * Строка редактора начинается там же, где строка чтения.
 *
 * CodeMirror держит `.cm-line { padding: 0 2px 0 6px }` — шесть точек слева
 * под курсор в начале строки. Курсор рисуется и без них, а шесть точек сдвига
 * видны при переключении на каждом абзаце сразу.
 */
.cm-editor .cm-line {
    padding-left: 0;
    padding-right: 0;
}

.cm-editor .cm-callout {
    padding-left: var(--callout-pad-x);
    padding-right: var(--callout-pad-x);
}

/*
 * У поля заголовка нет рамки — есть подчёркивание тенью.
 *
 * Рамка в одну точку входила в высоту поля, и поле выходило на четыре точки
 * выше заголовка в чтении: 88 против 84. Тень места не занимает, а намёк
 * «это правится» остаётся — он и нужен только при наведении.
 */
.doc-head .title-input {
    border-bottom: 0;
}

.doc-head .title-input:hover {
    box-shadow: 0 1px 0 var(--line);
}

.doc-head .title-input:focus {
    box-shadow: 0 1px 0 var(--accent);
}

/* ---------- Полоса разметки и свойства документа --------------------------- */

/*
 * Полоса идёт под шапкой во всю рабочую область и прилипает вместе с ней.
 * Ширина несёт смысл: полоса во всю ширину читается как часть приложения,
 * полоса по колонке — как украшение текста.
 *
 * Одна строка всегда. Не влезло — уезжает в «⋯», а на узком экране полоса
 * прокручивается вбок, но НЕ ПЕРЕНОСИТСЯ: вторая строка — то, из-за чего
 * панель однажды и начали прятать.
 */
.toolbar {
    position: sticky;
    top: var(--topbar-h);
    z-index: 19;
    display: flex;
    align-items: center;
    gap: var(--sp-5);
    min-height: 40px;
    /* Слева выравнено по колонке текста, а не по краю окна: полоса относится к
       документу, и начинаться должна там же, где он. */
    padding: 0 24px 0 calc(var(--content-pad-x) - 8px);
    background: var(--canvas);
    border-bottom: 1px solid var(--line);
    /*
     * НЕ ОБРЕЗАТЬ. Здесь стоял `overflow-x: auto` ради узких экранов — и он же
     * съедал раскрытые меню «Вставить» и «⋯»: они лежат в потоке панели, а
     * обрезающий предок отрезает всё, что вышло за него. Кнопки выглядели
     * сломанными, хотя работали.
     *
     * Узкие экраны решаются иначе и лучше: лишние группы не прокручиваются
     * вбок, а прячутся. Боковая прокрутка в панели всё равно бесполезна —
     * человек не знает, что справа что-то есть.
     */
    overflow: visible;
}

.tool-group {
    display: flex;
    flex: none;
    align-items: center;
    gap: 2px;
}

/*
 * ГРУППЫ РАЗДЕЛЕНЫ ВОЗДУХОМ, А НЕ ЛИНИЯМИ.
 *
 * Линий было четыре на дюжину кнопок, и полоса читалась как забор. Воздух
 * группирует не хуже, а рисует меньше: чем меньше нарисовано, тем виднее то,
 * что осталось.
 */
.tool-group-end {
    margin-left: auto;
}

/*
 * ТОЛЬКО ПРЯМЫЕ КНОПКИ ПОЛОСЫ, а не всё, что внутри неё.
 *
 * Пока правило звалось `.toolbar button`, оно доставало и до пунктов
 * раскрытого меню — они ведь тоже внутри полосы. Пункты становились
 * выключно-строчными и выравнивались по центру, отчего значки в столбце
 * вставали вразнобой. Видно это было только с раскрытым меню.
 */
.tool-group > button,
.tool-group > details > summary {
    display: inline-flex;
    align-items: center;
    min-height: 28px;
    padding: 0 9px;
    border: 0;
    border-radius: var(--radius-s);
    background: transparent;
    color: var(--text-2);
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
    list-style: none;
    cursor: pointer;
}

.tool-group > details > summary::-webkit-details-marker {
    display: none;
}

.tool-group > button:hover,
.tool-group > details > summary:hover {
    background: var(--surface-2);
    color: var(--text);
}

/*
 * «Вставить» — единственное выделенное на полосе. Это дверь ко всему
 * остальному, и если не выделить ничего, глазу не за что зацепиться: дюжина
 * одинаково серых слов читается как строка текста, а не как набор кнопок.
 */
.tool-insert {
    border: 1px solid var(--line) !important;
    background: var(--surface) !important;
    color: var(--text) !important;
}

.tool-insert:hover {
    border-color: var(--line-strong) !important;
    background: var(--surface-2) !important;
}

/*
 * На узком экране лишнее прячется, а не уезжает вбок. Остаются уровни
 * заголовков, начертание и «Вставить» — то, без чего править нельзя вовсе.
 */
@media (max-width: 900px) {
    .toolbar {
        gap: var(--sp-3);
        padding: 0 12px;
    }

    .toolbar .tool-group:nth-child(3) {
        display: none;
    }
}

/* Свойства документа в правой колонке. */
.rail-prop {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
}

.rail-prop-name {
    flex: none;
    font-size: 12px;
    color: var(--text-3);
}

.rail-prop .link,
.rail-prop a {
    min-width: 0;
    font-size: 12px;
    text-align: right;
}

/* Архив тише всего в блоке: действие редкое, и попасть в него случайно не
   должно быть легче, чем в остальные. */
.rail-archive {
    align-self: flex-start;
    margin-top: var(--sp-2);
    font-size: 11px;
    color: var(--text-4, var(--text-3));
}

/* ---------- Хлебные крошки ------------------------------------------------- */

/*
 * Самая тихая навигация на экране. Если крошки спорят с заголовком, у страницы
 * два заголовка, и человек не знает, что тут главное. Поэтому ни рамок, ни
 * плашек: только цвет, вес и разделитель.
 */
.crumbs {
    min-width: 0;
    /* Место кнопке достаётся первым: уйти из правки надо иметь возможность
       всегда, а путь есть и в дереве слева. */
    flex: 1 1 auto;
    overflow: hidden;
}

.crumbs ol {
    display: flex;
    align-items: center;
    min-width: 0;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--fs-ui);
    color: var(--text-3);
}

.crumbs li {
    display: flex;
    align-items: center;
    min-width: 0;
}

/*
 * Разделитель рисуется оформлением, а не стоит буквой в разметке: скопировав
 * путь, человек получает слова, а не слова со слэшами.
 */
.crumbs li + li::before {
    content: "/";
    flex: none;
    margin: 0 8px;
    color: var(--text-4, var(--text-3));
}

.crumbs a,
.crumbs span {
    min-width: 0;
    /* Одно длинное название не должно съедать строку целиком: у каждой ступени
       свой предел, и обрезается она сама, а не выталкивает соседей. */
    max-width: 26ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: inherit;
    text-decoration: none;
}

.crumbs a:hover {
    color: var(--text);
    text-decoration: underline;
}

/*
 * Где мы сейчас — весом и цветом, а не отдельной плашкой. И появляется он
 * только когда заголовок ушёл вверх: пока заголовок виден, имя документа на
 * экране дважды.
 */
/*
 * Селектор из двух имён: `.crumbs li` выше уже задал `display: flex`, и одного
 * имени ему не перебить. Проверено замером — ступень с именем документа
 * показывалась всегда.
 */
.crumbs .crumb-here {
    display: none;
}

.crumb-here span {
    color: var(--text);
    font-weight: 500;
}

.is-scrolled .crumbs .crumb-here {
    display: flex;
}

/*
 * На узком экране путь не исчезает, а сжимается: остаётся последняя ступень.
 * Одна ступень лучше, чем ни одной, — «ни одной» человек читает как «я нигде».
 */
@media (max-width: 700px) {
    .crumbs li:not(:last-child):not(:nth-last-child(2)) {
        display: none;
    }
}

/*
 * Пустой индикатор сохранения не показывается вовсе.
 *
 * Точка рисуется псевдоэлементом, а подпись приходит скриптом — и до первого
 * сохранения рядом с «Готово» висел одинокий кружок без слова. Кружок без
 * подписи не значит ничего: спросить у него нельзя, а объяснять он не умеет.
 */
.save-state:empty {
    display: none;
}

/*
 * Пункт меню: значок в своей колонке, подпись в своей.
 *
 * Без явной сетки значки вставали вразнобой — каждый по центру своей строки, а
 * строки разной длины. Столбец значков, который не столбец, читается как
 * дрожание: глаз ищет вертикаль и не находит её.
 */
.tool-more-menu .popover-item {
    display: grid;
    grid-template-columns: 20px minmax(0, 1fr);
    gap: 10px;
    align-items: center;
    width: 100%;
    padding: 7px 10px;
    text-align: left;
}

.tool-more-menu .popover-icon {
    justify-self: center;
    color: var(--text-3);
}

.tool-more-menu .popover-label {
    display: block;
    min-width: 0;
}

/* ---------- Кнопка «скопировать» у блока кода ------------------------------ */

.code-block {
    position: relative;
}

/*
 * Появляется по наведению И ПО ФОКУСУ. Только по наведению — значит нет на
 * телефоне и нет у клавиатуры; а человек, работающий с клавиатуры, копирует
 * команды чаще прочих.
 */
.code-copy {
    position: absolute;
    top: 8px;
    right: 8px;
    min-height: 26px;
    padding: 0 10px;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text-3);
    font-family: var(--font-ui);
    font-size: 11px;
    opacity: 0;
    transition: opacity 90ms linear;
}

.code-block:hover .code-copy,
.code-copy:focus-visible {
    opacity: 1;
}

.code-copy:hover {
    color: var(--text);
}

/* Сработало — говорим цветом и словом сразу: цвет замечают, слово читают. */
.code-copy.is-done {
    border-color: var(--ok);
    color: var(--ok);
    opacity: 1;
}

.code-copy.is-bad {
    border-color: var(--bad);
    color: var(--bad);
    opacity: 1;
}

/* На узком экране кнопка поверх кода мешает больше, чем помогает: выделить
   пальцем всё равно проще, чем целиться в неё. */
@media (max-width: 700px) {
    .code-copy {
        display: none;
    }
}

/*
 * Подраздел получает свой трекинг, как и раздел.
 *
 * 17 против прежних 20: между разделом 23 и текстом 16 подраздел обязан быть
 * ближе к тексту, иначе он читается как второй раздел и уровни слипаются в
 * один.
 */
[data-skin="paper"] .content h3 {
    letter-spacing: -0.012em;
}

/*
 * КУРСИВ ПОКА ОСТАЁТСЯ КУРСИВОМ.
 *
 * Задание меняет `em` на подчёркивание, потому что у Golos Text курсива нет и
 * браузер наклонял бы прямое начертание. Пока шрифтовых файлов нет и мы на
 * системном шрифте, курсив настоящий — подменять его подчёркиванием значило бы
 * лечить болезнь, которой ещё нет, а заодно спутать выделенное со ссылкой.
 *
 * Менять вместе с подключением шрифтов, не раньше.
 */

/* ---------- Шапка документа: убрать сложенные отбивки --------------------- */

/*
 * ТРИ ОТСТУПА СКЛАДЫВАЛИСЬ В ОДНУ ПУСТОТУ.
 *
 * Поле листа 44, собственный отступ строки над заголовком 12 и умолчание
 * браузера у `h1` — 0.67em, то есть ещё 25. Сверху получалось восемьдесят с
 * лишним точек ни о чём, а между заголовком и строкой автора — ещё двадцать
 * пять, хотя эта строка принадлежит заголовку и должна стоять при нём.
 *
 * Заголовок теперь начинается сразу от поля листа, а мета жмётся к нему.
 * У поля правки те же числа: иначе состояния разъедутся, а мы это уже чинили.
 */
.doc-eyebrow {
    margin-bottom: 8px;
}

.doc-head h1,
.doc-head .title-input {
    margin: 0 0 12px;
}

/*
 * РИТМ ЗАДАЮТ ОТСТУПЫ, А НЕ ЩЕЛЬ КОЛОНКИ.
 *
 * `.content` — колонка с `gap: 16px`, и щель ПРИБАВЛЯЕТСЯ к каждому отступу
 * сверху: заявленные 28 до выноски давали 44, 52 перед разделом — 68, 8 после
 * заголовка — 24. То есть весь ритм страницы всё это время был на шестнадцать
 * больше объявленного, и ни один замер этого не показывал: я мерил отступы
 * элементов, а щель живёт на родителе.
 *
 * Нашлось это по тридцати двум точкам между строкой автора и первым блоком —
 * двум щелям подряд, потому что между ними стоит скрытая форма галок: высоты
 * у неё нет, а щели с обеих сторон есть.
 *
 * Щель убрана, ритм остаётся на отступах: он объявлен числами в шести местах,
 * и держать его в двух механизмах сразу — способ каждый раз получать сумму
 * вместо значения.
 */
[data-skin="paper"] .content {
    gap: 0;
}

/* ---------- Фильтр над таблицей задач -------------------------------------- */

.filter-bar {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    margin-top: 18px;
    margin-bottom: 8px;
}

/*
 * Переключатель одного значения: кнопки лежат в общем углублении, выбранная
 * поднята на поверхность листа. Так видно, что это ОДИН выбор из нескольких, а
 * не набор независимых кнопок.
 */
.filter {
    display: flex;
    gap: 2px;
    padding: 2px;
    border-radius: var(--radius);
    background: var(--surface-2);
}

.filter > button {
    min-height: 26px;
    padding: 0 11px;
    border: 0;
    border-radius: var(--radius-s);
    background: transparent;
    color: var(--text-3);
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

.filter > button:hover {
    color: var(--text);
    background: transparent;
}

.filter > .is-on {
    background: var(--surface);
    color: var(--text);
    font-weight: 500;
    box-shadow: var(--shadow);
}

/* Сколько показано из скольких. Моно и табличные — число здесь меняется на
   месте, и прыгающая ширина читается как мигание. */
.filter-count {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-4, var(--text-3));
    font-variant-numeric: tabular-nums;
}

/* Отбор журнала — те же кнопки, что над таблицей задач, но ссылками: отбор
   живёт в адресе, чтобы им можно было поделиться и вернуться назад. */
.filter a {
    display: inline-flex;
    align-items: center;
    min-height: 26px;
    padding: 0 11px;
    border-radius: var(--radius-s);
    color: var(--text-3);
    font-size: var(--fs-ui);
    text-decoration: none;
}

.filter a.is-on {
    background: var(--surface);
    color: var(--text);
    font-weight: 500;
    box-shadow: var(--shadow);
}

/*
 * Аварийный доступ виден без чтения: это системный администратор в чужом
 * проекте, то есть ровно то, ради чего журнал открывают.
 */
.is-emergency td {
    background: var(--bad-quiet);
}

/* ---------- Задачи: строки статей в одном месте --------------------------- */

/*
 * ГРУППА — ДОКУМЕНТ. Первичный контекст здесь документ, а не состояние: чинят
 * задачу, открывая статью. Поэтому рамка обводит документ целиком, а строки
 * внутри разделены волосяной линией, а не собственными рамками.
 */
.task-group {
    border: 1px solid var(--line);
    border-radius: var(--radius-m, 7px);
    overflow: hidden;
}

.content > .task-group + .task-group,
.task-group + .task-group {
    margin-top: 20px;
}

/* У черновика рамка светлее, а название тише: он ещё не для всех. */
.task-group.is-draft {
    border-color: var(--line-soft);
}

.task-group.is-draft .task-group-name {
    color: var(--text-2);
}

.task-group-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 14px;
    background: var(--canvas);
    border-bottom: 1px solid var(--line);
}

.task-group-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text);
    text-decoration: none;
}

.task-group-name:hover {
    text-decoration: underline;
}

.task-group-count {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-4, var(--text-3));
    font-variant-numeric: tabular-nums;
}

.task-group-when {
    font-size: 12px;
    color: var(--text-3);
}

/* Ссылка на документ прижата вправо: она уводит со страницы, и место у края
   говорит об этом раньше, чем текст. */
.task-group-open {
    margin-left: auto;
    font-size: 12px;
    color: var(--accent);
    text-decoration: none;
    white-space: nowrap;
}

.task-group-open:hover {
    text-decoration: underline;
}

/*
 * СТРОКА ЗАДАЧИ. Ширины служебных колонок постоянные, текстовая забирает
 * остаток: так номера и состояния стоят столбцом, а не пляшут от длины текста.
 */
.task-line {
    display: grid;
    grid-template-columns: 22px 30px minmax(0, 1fr) 108px 92px;
    gap: 12px;
    align-items: center;
    padding: 9px 14px;
    border-bottom: 1px solid var(--line-hair, var(--line-soft));
    transition: background 100ms ease;
}

.task-line:last-child {
    border-bottom: 0;
}

.task-line:hover {
    background: var(--surface-2);
}

.task-box {
    width: 17px;
    height: 17px;
    margin: 0;
    accent-color: var(--ok);
    cursor: pointer;
}

/* У строки таблицы галки нет: её состояние записано тегом в тексте. Место
   всё равно занято — иначе строки разъезжаются по вертикали. */
.task-box.is-empty {
    display: inline-block;
    cursor: default;
}

.task-number,
.task-scope {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--text-4, var(--text-3));
    font-variant-numeric: tabular-nums;
}

.task-scope {
    color: var(--text-3);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * ТЕКСТ ВЫПОЛНЕННОЙ НЕ ГАСНЕТ И НЕ ЗАЧЁРКИВАЕТСЯ. Сделанное остаётся частью
 * списка, а не превращается в след: его перечитывают, чтобы вспомнить, что
 * именно сделали.
 */
.task-text {
    font-size: 14px;
    line-height: 1.45;
    min-width: 0;
}

/* Состояние — слово цветом, без плашки: его читают, а не разглядывают. */
.task-state {
    font-size: 13px;
    white-space: nowrap;
}

.state-warn { color: var(--warn); }
.state-accent { color: var(--accent); }
.state-ok { color: var(--ok); }
.state-bad { color: var(--bad); }
.state-quiet { color: var(--text-3); }

.task-mark-form {
    padding: 8px 14px 0;
}

.task-hidden {
    font-size: 13px;
    color: var(--text-3);
}

/*
 * Сноска о механике. Не украшение: это единственное место, где объяснена
 * разница между этой страницей и обычным трекером.
 */
.task-note {
    padding: 12px 14px;
    background: var(--surface-2);
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-m, 7px);
    font-size: 13px;
    line-height: 1.55;
    color: var(--text-2);
}

/* Ниже 780px остаются отметка, номер, текст и состояние: область — первое,
   без чего список читается. */
@media (max-width: 780px) {
    .task-line {
        grid-template-columns: 22px 30px minmax(0, 1fr) 96px;
    }

    .task-line > .task-scope {
        display: none;
    }
}

/* ---------- Задачи: управление, колонка, панель --------------------------- */

/*
 * Сегменты выбора вида. Группа на подложке, включённый сегмент светлее и с
 * тенью в один пиксель — он приподнят, а не подкрашен: подкрашенный читается
 * как «особый», приподнятый как «выбранный».
 */
.segments {
    display: inline-flex;
    padding: 2px;
    background: var(--surface-2);
    border-radius: var(--radius-s, 6px);
}

.segments a {
    padding: 4px 10px;
    border-radius: 4px;
    font-size: 13px;
    color: var(--text-2);
    text-decoration: none;
}

.segments a.is-on {
    background: var(--surface);
    color: var(--text);
    font-weight: 500;
    box-shadow: 0 1px 1px rgba(28, 27, 24, .06);
}

.filter-split {
    width: 1px;
    height: 20px;
    background: var(--line-soft);
}

.filter-pills {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
}

/*
 * КАПСУЛЫ ОТБОРА — ЕДИНСТВЕННОЕ МЕСТО НА СТРАНИЦЕ СО СКРУГЛЕНИЕМ НЕ 6/7.
 *
 * Это не оплошность: капсула — переключаемое условие, а не элемент управления,
 * и форма должна отличаться на взгляд, чтобы её не искали среди кнопок.
 */
.pill {
    padding: 3px 10px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--surface);
    font-size: 12px;
    color: var(--text-3);
    text-decoration: none;
    white-space: nowrap;
}

.pill:hover {
    color: var(--text);
}

.pill.is-on {
    background: var(--warn-quiet);
    border-color: var(--warn-line, var(--warn));
    color: var(--warn);
}

/* Состав в правой колонке: число, название, точка того же цвета. */
.rail-state {
    display: grid;
    grid-template-columns: 26px 1fr 10px;
    align-items: center;
    gap: 8px;
    padding: 3px 0;
    font-size: 13px;
    color: var(--text-2);
    text-decoration: none;
}

.rail-state:hover .rail-state-name {
    color: var(--text);
}

.rail-state.is-on .rail-state-name {
    color: var(--text);
    font-weight: 500;
}

.rail-state-count {
    font-family: var(--font-mono);
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.rail-state-dot {
    font-size: 6px;
    line-height: 1;
}

.rail-alarm {
    display: grid;
    gap: 6px;
    padding: 8px 10px;
    background: var(--warn-quiet);
    border: 1px solid var(--warn-line, var(--warn));
    border-radius: var(--radius-s, 6px);
    font-size: 13px;
}

.rail-stale {
    display: grid;
    gap: 2px;
    padding: 4px 0;
    font-size: 13px;
}

.rail-note {
    margin-top: 6px;
    font-size: 12px;
    color: var(--text-3);
}

/* Клавиши показаны, а не спрятаны в справку: страницу открывают каждый день. */
.rail-keys {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 10px;
    margin: 0;
    font-size: 12px;
    color: var(--text-3);
}

.rail-keys dt,
.rail-keys dd {
    margin: 0;
}

.rail-keys kbd {
    padding: 1px 5px;
    border: 1px solid var(--line);
    border-radius: 4px;
    background: var(--surface-2);
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--text-2);
}

/* Выбранная строка — подложкой, без полосы слева. */
.task-line.is-picked {
    background: var(--surface-sel, var(--surface-2));
}

.task-line:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -2px;
}

.task-where {
    margin-left: 8px;
    font-size: 12px;
    color: var(--text-3);
    text-decoration: none;
}

.task-where:hover {
    text-decoration: underline;
}

/*
 * ПАНЕЛЬ МАССОВОГО ДЕЙСТВИЯ. Снизу по центру, тёмная: она поверх страницы и
 * должна читаться как отдельный слой, а не как ещё одна полоса содержимого.
 */
.bulk {
    position: fixed;
    left: 50%;
    bottom: 22px;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-radius: 999px;
    background: #23211d;
    box-shadow: 0 8px 28px -10px rgba(28, 27, 24, .6);
    color: #f4f1ea;
    font-size: 13px;
    z-index: 40;
}

.bulk button {
    height: 28px;
    padding: 0 10px;
    border: 0;
    border-radius: 999px;
    background: rgba(244, 241, 234, .12);
    color: inherit;
    font: inherit;
    cursor: pointer;
}

.bulk button:hover {
    background: rgba(244, 241, 234, .22);
}

.bulk-split {
    width: 1px;
    height: 18px;
    background: rgba(244, 241, 234, .25);
}

/*
 * Подпись про число документов обязательна: массовое действие по задачам из
 * трёх статей создаёт три версии в трёх документах, и человек должен видеть
 * это ДО нажатия, а не в истории после.
 */
.bulk-where {
    font-size: 12px;
    color: rgba(244, 241, 234, .65);
}

.bulk-close {
    background: transparent !important;
}

/* ==========================================================================
   Проекты: список по доступу, карточки участника и панель создания.
   ========================================================================== */

/* Заголовок и главное действие в одной строке: кнопка «Новый проект» нужна
   там, где взгляд уже находится, а не внизу под таблицей. */
.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    flex-wrap: wrap;
}

.page-head h1 {
    margin: 0;
}

/* Ссылка, которая по смыслу кнопка. Отдельным правилом, потому что общее
   правило описывает элемент button, а не класс. */
a.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 32px;
    padding: 0 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
}

a.button:hover {
    border-color: var(--line-strong);
    background: var(--surface-2);
    text-decoration: none;
}

a.button.primary {
    border-color: var(--accent);
    background: var(--accent);
    color: var(--accent-contrast);
    font-weight: 600;
}

a.button.primary:hover {
    filter: brightness(1.08);
    background: var(--accent);
}

/* Таблица проектов. Столбцы сравниваются взглядом по вертикали — ради этого
   она и таблица, а не карточки. */
table.projects {
    width: 100%;
    margin-top: var(--sp-5);
    border-collapse: collapse;
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

table.projects th {
    padding: var(--sp-2) var(--sp-3);
    border-bottom: 1px solid var(--line);
    text-align: left;
    font-weight: 500;
    font-size: var(--fs-small);
    color: var(--text-3);
    white-space: nowrap;
}

table.projects td {
    padding: var(--sp-3);
    border-bottom: 1px solid var(--line);
    vertical-align: top;
    color: var(--text-2);
}

table.projects tr:last-child td {
    border-bottom: 0;
}

table.projects td a {
    color: var(--text);
    font-weight: 500;
}

/* Числа справа: так их видно колонкой, а не рваным краем. */
table.projects .num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* Ширина под многоточием держится всегда, даже когда меню закрыто: иначе
   открытие сдвигает соседние ячейки. */
table.projects .actions {
    width: 40px;
    text-align: right;
}

.block {
    display: block;
}

/* Проект, открытый всей команде, — единственное, что стоит выделить цветом. */
.pill-open {
    border-color: var(--warn-line, var(--warn));
    background: var(--warn-quiet);
    color: var(--warn);
}

/* Меню действий. Элемент details вместо скрипта: работает без JavaScript,
   закрывается по Escape и не требует ни одной строки обработчиков. */
.menu {
    position: relative;
    display: inline-block;
}

.menu > summary {
    list-style: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-s);
    color: var(--text-3);
    cursor: pointer;
    user-select: none;
}

.menu > summary::-webkit-details-marker {
    display: none;
}

.menu > summary:hover,
.menu[open] > summary {
    background: var(--surface-2);
    color: var(--text);
}

.menu-body {
    position: absolute;
    right: 0;
    z-index: 20;
    display: flex;
    flex-direction: column;
    min-width: 180px;
    padding: var(--sp-1);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
    text-align: left;
}

.menu-body a {
    padding: var(--sp-2) var(--sp-3);
    border-radius: var(--radius-s);
    color: var(--text-2);
    font-weight: 400;
    text-decoration: none;
    white-space: nowrap;
}

.menu-body a:hover {
    background: var(--surface-2);
    color: var(--text);
}

/* Чужие проекты — отдельным разделом с предупреждением, а не строкой в общей
   таблице: разницу между «мой» и «вижу системным доступом» нельзя показывать
   значком, который перестают замечать на второй неделе. */
.foreign {
    margin-top: var(--sp-9);
    padding-top: var(--sp-5);
    border-top: 1px solid var(--line);
}

.foreign h2 {
    margin: 0;
}

/* Лента последних правок. Без полос слева: строки здесь равноправны и ни во
   что не вложены, а полоса рисует вложенность, которой нет. */
.feed {
    margin-top: var(--sp-9);
}

.feed-list {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    margin: var(--sp-4) 0 0;
    padding: 0;
    list-style: none;
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

.feed-list > li {
    display: flex;
    align-items: baseline;
    gap: var(--sp-3);
    flex-wrap: wrap;
}

.card-foot {
    margin-top: auto;
    font-size: var(--fs-small);
}

.footnote {
    margin-top: var(--sp-9);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--line);
    font-size: var(--fs-small);
}

/* --- Боковая панель создания -------------------------------------------- */

.panel-shade {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgb(0 0 0 / 28%);
}

/* 452 пикселя: поле названия помещается целиком, а список проектов позади
   остаётся читаемым — заводя проект, на него и смотрят. */
.panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 61;
    width: 452px;
    max-width: 100vw;
    display: flex;
    flex-direction: column;
    border-left: 1px solid var(--line);
    background: var(--surface);
    box-shadow: -12px 0 32px rgb(0 0 0 / 10%);
}

.panel-form {
    display: flex;
    flex-direction: column;
    min-height: 0;
    height: 100%;
}

.panel-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-4);
    padding: var(--sp-5) var(--sp-5) var(--sp-4);
    border-bottom: 1px solid var(--line);
}

.panel-head h2 {
    margin: 0;
    font-size: 18px;
}

.panel-close {
    font-size: 22px;
    line-height: 1;
    color: var(--text-3);
    text-decoration: none;
}

.panel-close:hover {
    color: var(--text);
}

.panel-body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-2);
    padding: var(--sp-5);
    overflow-y: auto;
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

.panel-body label {
    margin-top: var(--sp-3);
    color: var(--text-2);
    font-size: var(--fs-small);
}

.panel-body > label:first-of-type {
    margin-top: 0;
}

.panel-body input,
.panel-body select {
    width: 100%;
}

/* Пояснение под полем: почему это спрашивают и что будет дальше. Серым и
   мелким — читают его один раз, а мешать оно не должно каждый. */
.field-note {
    margin: 0;
    color: var(--text-3);
    font-size: var(--fs-small);
}

.field-note code {
    color: var(--text-2);
}

.choices {
    margin-top: var(--sp-4);
    padding: 0;
    border: 0;
}

.choices legend {
    padding: 0 0 var(--sp-2);
    color: var(--text-2);
    font-size: var(--fs-small);
}

.choice {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-3);
    margin: 0 0 var(--sp-2);
    padding: var(--sp-3);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    cursor: pointer;
}

.choice:hover {
    border-color: var(--line-strong);
}

.choice:has(input:checked) {
    border-color: var(--accent);
    background: var(--surface-2);
}

.choice input {
    width: auto;
    margin-top: 2px;
}

.choice-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.choice-body .muted {
    font-size: var(--fs-small);
}

/* Предупреждение появляется в тот момент, когда выбирают открытый доступ, а не
   после создания: отменять поздно — прочитанное уже прочитано. */
.choice-warning {
    margin: var(--sp-2) 0 0;
    padding: var(--sp-3);
    border: 1px solid var(--warn-line, var(--warn));
    border-radius: var(--radius);
    background: var(--warn-quiet);
    color: var(--warn);
    font-size: var(--fs-small);
}

.panel-foot {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-top: auto;
    padding: var(--sp-4) var(--sp-5);
    border-top: 1px solid var(--line);
}

@media (max-width: 640px) {
    .panel {
        width: 100vw;
    }
}

/* Заголовок столбца, который нужен только тому, кто читает страницу голосом:
   глазами он и так понятен, а пустой заголовок озвучивается как пропуск. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}


/* Списки интерфейса живут в том же `.content`, что и статья, но отступ и
   маркер им задаёт браузер по умолчанию — свои правила статьи их больше не
   трогают. Сбрасываем явно. */
.cards,
.feed-list {
    margin-left: 0;
    padding-left: 0;
    list-style: none;
}

/*
 * Узкий экран: столбцы УБИРАЮТСЯ, а не уезжают в горизонтальную прокрутку.
 *
 * Прокрутка выглядела дешевле, но она означает контейнер с `overflow`, а
 * контейнер с `overflow` обрезает всё, что из него торчит, — в том числе
 * выпадающее меню строки. Меню, которое видно наполовину и требует прокрутить
 * таблицу, хуже отсутствующего столбца «Статьи».
 *
 * Порядок исчезновения — от наименее нужного: число статей, дата, число людей.
 * Название, доступ и ответственный остаются всегда: без них строка ничего не
 * сообщает.
 */
@media (max-width: 1000px) {
    table.projects th:nth-child(5),
    table.projects td:nth-child(5),
    table.projects col:nth-child(5) {
        display: none;
    }
}

@media (max-width: 820px) {
    table.projects th:nth-child(6),
    table.projects td:nth-child(6),
    table.projects col:nth-child(6) {
        display: none;
    }
}

@media (max-width: 640px) {
    table.projects th:nth-child(4),
    table.projects td:nth-child(4),
    table.projects col:nth-child(4) {
        display: none;
    }
}

/* ==========================================================================
   Люди: список с раскрытием, поиск, отбор.
   ========================================================================== */

.people-search {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    margin-top: var(--sp-5);
    max-width: 520px;
}

.people-search input {
    flex: 1;
    min-width: 0;
}

.people {
    margin: var(--sp-4) 0 0;
    padding: 0;
    list-style: none;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
}

.person + .person {
    border-top: 1px solid var(--line);
}

/* Отключённый бледнее, но читается: он всё ещё автор половины статей, и
   разбирать его доступ приходится именно после отключения. */
.person.is-off > details > summary {
    color: var(--text-3);
}

.person > details > summary {
    display: flex;
    align-items: baseline;
    gap: var(--sp-3);
    padding: var(--sp-3) var(--sp-4);
    list-style: none;
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

.person > details > summary::-webkit-details-marker {
    display: none;
}

.person > details > summary:hover,
.person > details[open] > summary {
    background: var(--surface-2);
}

/* Треугольник рисуем сами: у встроенного маркера нет общего вида в браузерах,
   а поворот подсказывает, что строка раскрывается, до первого щелчка. */
.person > details > summary::before {
    content: "›";
    display: inline-block;
    width: 12px;
    color: var(--text-3);
    transition: transform var(--dur, .15s) var(--ease, ease);
}

.person > details[open] > summary::before {
    transform: rotate(90deg);
}

.person-name {
    display: flex;
    align-items: baseline;
    gap: var(--sp-3);
    flex-wrap: wrap;
    min-width: 0;
}

/* Итог по человеку прижат вправо: столбцом он читается сверху вниз, и видно,
   у кого доступа нет вовсе. */
.person-count {
    margin-left: auto;
    font-size: var(--fs-small);
    white-space: nowrap;
}

.person-body {
    padding: 0 var(--sp-4) var(--sp-4) calc(var(--sp-4) + 12px);
}

.person-body > p {
    margin: 0 0 var(--sp-3);
}

table.access {
    width: 100%;
    border-collapse: collapse;
    font-family: var(--font-ui);
    font-size: var(--fs-ui);
}

table.access td {
    padding: var(--sp-2) var(--sp-3) var(--sp-2) 0;
    vertical-align: baseline;
    color: var(--text-2);
}

table.access td.right {
    text-align: right;
    white-space: nowrap;
}

/* Правило на статье — под своим проектом и со сдвигом: так видно, что оно
   действует внутри проекта, а не вместо него. */
table.access tr.rule td:first-child {
    padding-left: var(--sp-4);
}

.rule-mark {
    color: var(--text-3);
}

/* Запрет — единственное, что выделяется цветом: он сильнее любого разрешения
   и действует даже на администратора проекта. */
.pill-deny {
    border-color: var(--danger-line, var(--danger));
    background: var(--danger-quiet, var(--warn-quiet));
    color: var(--danger, var(--warn));
}

.orphans {
    margin-top: var(--sp-4);
}

.person-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-4);
    margin-top: var(--sp-4);
    padding-top: var(--sp-3);
    border-top: 1px solid var(--line);
    font-family: var(--font-ui);
    font-size: var(--fs-small);
}

.badge-off {
    color: var(--text-3);
}

.new-person {
    margin-top: var(--sp-9);
    max-width: 360px;
}

.new-person h2 {
    margin: 0 0 var(--sp-3);
}

/* ==========================================================================
   Значки интерфейса.

   ЗНАК СИСТЕМНОГО ШРИФТА — ЭТО ЧУЖОЙ РИСУНОК. ▾, ‹‹, ↗, ▤, ✓ и × берутся из
   шрифта операционной системы: на трёх ОС три разных начертания, разная
   толщина, разная посадка по базовой линии. Теме они тоже не подчиняются —
   эмодзи остаётся цветным на тёмном фоне, а треугольник из шрифта не
   становится тоньше оттого, что весь интерфейс монолинейный.

   ТЕХНИКА ТА ЖЕ, ЧТО У ВЫНОСОК: контур лежит в `--icon` как SVG, ставится
   маской, а цвет берётся из `currentColor`. Значит значок наследует цвет
   текста рядом — и в тёмной теме, и в наведении, и в отключённом состоянии,
   без единого отдельного правила.

   16×16, штрих 1,5, скруглённые концы — одна сетка со значками выносок.
   ========================================================================== */

.ico {
    display: inline-block;
    flex: none;
    width: 16px;
    height: 16px;
    background: currentColor;
    -webkit-mask: var(--icon) center / contain no-repeat;
    mask: var(--icon) center / contain no-repeat;
}

.ico-chevron {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.25 3.75L10.5 8l-4.25 4.25'/%3E%3C/svg%3E");
}

/* Свернуть панель: две шевронные скобки. Одна читалась бы как «назад». */
.ico-collapse {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.5 3.75L3.75 8l3.75 4.25M12.75 3.75L9 8l3.75 4.25'/%3E%3C/svg%3E");
}

.ico-close {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.25 4.25l7.5 7.5M11.75 4.25l-7.5 7.5'/%3E%3C/svg%3E");
}

.ico-check {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.4l3.1 3.1L12.5 5'/%3E%3C/svg%3E");
}

/* Статья: тот же прямоугольник со строками, что у значка заметки. */
.ico-document {
    --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2.75' y='2.75' width='10.5' height='10.5' rx='2'/%3E%3Cpath d='M5.5 6.6h5M5.5 9.6h3.2'/%3E%3C/svg%3E");
}

/* --- Замены знаков в конкретных местах ---------------------------------- */

/*
 * Знак у раздела с вложенными статьями.
 *
 * СМОТРИТ ВНИЗ, И ВНИЗ ВСЕГДА. Дерево у нас не сворачивается: вложенные видны
 * сразу, под родителем. Шеврон вправо обещал бы, что раздел можно раскрыть, —
 * а раскрывать нечего, он уже раскрыт. Тот же контур, повёрнутый один раз,
 * говорит правду: продолжение ниже.
 */
.tree-mark {
    width: 12px;
    height: 12px;
    color: var(--text-3);
    transform: rotate(90deg);
}

.project-chevron {
    width: 14px;
    height: 14px;
    align-self: center;
    color: var(--text-4, var(--text-3));
}

/* Стрелка «уводит наружу» — своим контуром, а не знаком ↗ из шрифта. */
[data-skin="paper"] :is(.content, .preview) a.external::after,
:is(.content, .preview) a.external::after {
    content: "";
    display: inline-block;
    width: 11px;
    height: 11px;
    margin-left: 3px;
    vertical-align: -1px;
    background: var(--text-3);
    -webkit-mask: var(--ico-external) center / contain no-repeat;
    mask: var(--ico-external) center / contain no-repeat;
    --ico-external: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3.75h5.75V9.5M12.25 3.75L4.25 11.75'/%3E%3C/svg%3E");
}

/*
 * Галочка в чеклисте.
 *
 * Была знаком ✓ из шрифта — на одной системе тонкая, на другой жирная, и обе
 * не совпадали со штрихом остального интерфейса.
 */
.cm-task.is-done::after,
.content input[type='checkbox']:checked::after {
    content: "";
    display: block;
    width: 11px;
    height: 11px;
    background: currentColor;
    -webkit-mask: var(--ico-check) center / contain no-repeat;
    mask: var(--ico-check) center / contain no-repeat;
    --ico-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.4l3.1 3.1L12.5 5'/%3E%3C/svg%3E");
}

/* Крестик снятия отбора — внутри таблетки и мельче её: он здесь гость, а не
   вторая кнопка. */
.pill-x {
    width: 11px;
    height: 11px;
    margin-left: 4px;
    vertical-align: -1px;
}

/*
 * Сворачиваемая выноска: свой шеврон вместо браузерного треугольника.
 *
 * `list-style-type: disclosure-closed` рисует БРАУЗЕР, и рисует по-своему в
 * каждом: в одном треугольник, в другом стрелка, толщина ни к чему не
 * привязана. Это ровно тот случай, ради которого набор и заводили.
 *
 * Шеврон стоит справа, а не слева: слева уже есть значок выноски, и два знака
 * подряд читаются как один сложный.
 */
.callout > summary,
details.callout > summary {
    list-style: none;
    cursor: pointer;
}

.callout > summary::-webkit-details-marker,
details.callout > summary::-webkit-details-marker {
    display: none;
}



/*
 * Число пунктов у раздела в правой колонке.
 *
 * Пункт становится строкой флексбокса: без этого `margin-left: auto` не
 * прижимает число вправо, а точка — элемент строчный, и заданные ей шесть на
 * шесть просто не применяются. Пустой `span` с размером, который никуда не
 * приложился, не видно вовсе, и разбирать это пришлось бы глазами.
 */
.rail-item {
    display: flex;
    align-items: baseline;
    gap: 6px;
}

.rail-count {
    margin-left: auto;
    font-size: var(--fs-small);
    font-variant-numeric: tabular-nums;
    color: var(--text-3);
}

/*
 * Точка стоит ПОСЛЕ числа, и прижимать её отдельно не нужно — вправо уже ушло
 * число. Приподнята на пиксель: кружок по базовой линии садится ниже цифр.
 */
.rail-item .dot {
    margin-left: 0;
    align-self: center;
}

.dot-done {
    background: var(--ok);
}

.dot-work {
    background: var(--warn);
}
