/* ==========================================================================
   KnowBase — таблица стилей
   1. Токены и тема      5. Навигация и дерево    9. Документ
   2. База и утилиты     6. Кнопки и меню        10. Редактор
   3. Шапка              7. Формы и таблицы      11. Markdown
   4. Раскладка          8. Карточки и списки    12. Адаптив и печать
   ========================================================================== */

/* ------------------------------------------------ 1. Токены и тема ------- */
/*
   Палитра построена на трёх слоях: подложка (bg), поверхность (surface) и
   приподнятый элемент (elev). Тёмная тема — не инверсия светлой, а свой
   набор с синеватыми нейтралями: на них глаз меньше устаёт вечером.
   Все переходы идут через --dur/--ease, поэтому скорость анимаций всего
   интерфейса меняется одной настройкой в «Админ → Оформление».

   Контраст. Приглушённый текст (--fg-muted) в обеих темах держит не меньше
   4.5:1 к своей подложке: подписи под строками, счётчики и хинты набраны
   именно им, и на прежних значениях (#8b93a3 / #6d788b) они читались как
   «серая каша». Тёмная тема вдобавок разведена по светлоте: подложка,
   поверхность и приподнятый слой отличаются заметно, иначе карточка на
   фоне страницы «слипалась» с ней и границы приходилось искать глазами.

   Тени. Мягкие тени с большим радиусом и высокой непрозрачностью давали
   ощущение «мыла»: под каждым окном висело серое облако. Радиусы урезаны,
   а вес перенесён на короткую контактную тень — край остаётся чётким.
*/
:root {
  color-scheme: light;

  --accent: #5b52e5;
  --accent-2: #8b5cf6;
  --accent-soft: color-mix(in srgb, var(--accent) 10%, transparent);
  --accent-mild: color-mix(in srgb, var(--accent) 16%, transparent);
  --accent-line: color-mix(in srgb, var(--accent) 28%, transparent);
  --accent-hover: color-mix(in srgb, var(--accent) 88%, #000);
  --accent-fg: #ffffff;
  --accent-glow: color-mix(in srgb, var(--accent) 22%, transparent);
  /* Акцент буквами и акцент заливкой — разные задачи. Заливке нужен цвет
     потемнее (по нему пойдёт белый текст), а буквам на тёмном фоне — тот же
     цвет, но светлее, иначе ссылка на подложке даёт 3:1 и тонет. В светлой
     теме это один и тот же цвет. */
  --accent-text: var(--accent);

  --bg: #ffffff;
  --bg-alt: #f5f6f9;
  --bg-elev: #ffffff;
  --bg-sunken: #ebedf2;
  --bg-hover: #eceef3;
  --bg-tint: color-mix(in srgb, var(--accent) 5%, var(--bg-alt));

  --fg: #0e1420;
  --fg-soft: #414b5d;
  --fg-muted: #667083;

  --border: #e2e5eb;
  --border-strong: #c3c9d5;
  --ring: color-mix(in srgb, var(--accent) 35%, transparent);

  --green: #0f8f47;
  --amber: #b87503;
  --red: #d32f42;
  --blue: #1f65d6;
  --success: var(--green);
  --warning: var(--amber);
  --danger: var(--red);
  --info: var(--blue);

  --r-xs: 6px;
  --r-sm: 9px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 22px;

  --shadow-xs: 0 1px 1px rgba(15, 22, 34, .05);
  --shadow-sm: 0 1px 2px rgba(15, 22, 34, .08), 0 1px 1px rgba(15, 22, 34, .04);
  --shadow: 0 6px 16px -6px rgba(15, 22, 34, .18), 0 2px 4px rgba(15, 22, 34, .06);
  --shadow-lg: 0 18px 40px -14px rgba(15, 22, 34, .3), 0 4px 10px rgba(15, 22, 34, .1);
  --shadow-glow: 0 0 0 4px var(--accent-soft);

  --scrim: rgba(12, 16, 24, .46);

  --sidebar-w: 288px;
  --aside-w: 236px;
  --topbar-h: 54px;
  --prose-w: 780px;
  --gap: 14px;
  --row-y: 5px;

  /* Движение: одна точка настройки для всего интерфейса */
  --dur-fast: 120ms;
  --dur: 190ms;
  --dur-slow: 320ms;
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --ease-spring: cubic-bezier(.34, 1.4, .64, 1);

  /* Шрифты.
     --font-ui и --font-content задаются из «Админ → Оформление»: интерфейс и
     текст страниц набираются разными гарнитурами, поэтому и переменные две.
     --font оставлен как псевдоним: на него ссылается остальная таблица. */
  --font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
             "Helvetica Neue", Arial, "Noto Sans", sans-serif;
  --font-content: var(--font-ui);
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", "Cascadia Mono", Menlo,
               Consolas, "Liberation Mono", monospace;
  --font: var(--font-ui);
  --mono: var(--font-mono);

  /* Множитель кегля из «Оформления». Сам размер задаётся корневым
     font-size (см. выше); переменная нужна предпросмотру и тем правилам,
     где пригодится знать выбранный масштаб. */
  --font-scale: 1;
}

/* --- тёмная тема --- */
html[data-theme="dark"] {
  color-scheme: dark;

  --accent-soft: color-mix(in srgb, var(--accent) 20%, transparent);
  --accent-mild: color-mix(in srgb, var(--accent) 28%, transparent);
  --accent-line: color-mix(in srgb, var(--accent) 46%, transparent);
  --accent-hover: color-mix(in srgb, var(--accent) 84%, #fff);
  --accent-glow: color-mix(in srgb, var(--accent) 30%, transparent);
  /* Тот же акцент, но подмешанный к белому: на тёмной подложке
     исходный даёт около 3:1 — ссылку приходится искать глазами. */
  --accent-text: color-mix(in srgb, var(--accent) 48%, #ffffff);

  --bg: #0d1219;
  --bg-alt: #141b25;
  --bg-elev: #1a2230;
  --bg-sunken: #090d13;
  --bg-hover: #232d3d;
  --bg-tint: color-mix(in srgb, var(--accent) 12%, var(--bg-alt));

  --fg: #eaf0f8;
  --fg-soft: #b6c1d1;
  --fg-muted: #8b96a9;

  --border: #283242;
  --border-strong: #3e4b5e;

  --green: #45d47c;
  --amber: #ecb13c;
  --red: #ff7b7b;
  --blue: #6cadff;

  --shadow-xs: 0 1px 1px rgba(0, 0, 0, .4);
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, .45);
  --shadow: 0 8px 20px -8px rgba(0, 0, 0, .6), 0 2px 5px rgba(0, 0, 0, .35);
  --shadow-lg: 0 22px 48px -16px rgba(0, 0, 0, .7), 0 6px 14px rgba(0, 0, 0, .4);

  --scrim: rgba(3, 6, 11, .66);
}

@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] {
    color-scheme: dark;

    --accent-soft: color-mix(in srgb, var(--accent) 20%, transparent);
    --accent-mild: color-mix(in srgb, var(--accent) 28%, transparent);
    --accent-line: color-mix(in srgb, var(--accent) 46%, transparent);
    --accent-hover: color-mix(in srgb, var(--accent) 84%, #fff);
    --accent-glow: color-mix(in srgb, var(--accent) 30%, transparent);
  /* Тот же акцент, но подмешанный к белому: на тёмной подложке
     исходный даёт около 3:1 — ссылку приходится искать глазами. */
  --accent-text: color-mix(in srgb, var(--accent) 48%, #ffffff);

    --bg: #0d1219;
    --bg-alt: #141b25;
    --bg-elev: #1a2230;
    --bg-sunken: #090d13;
    --bg-hover: #232d3d;
    --bg-tint: color-mix(in srgb, var(--accent) 12%, var(--bg-alt));

    --fg: #eaf0f8;
    --fg-soft: #b6c1d1;
    --fg-muted: #8b96a9;

    --border: #283242;
    --border-strong: #3e4b5e;

    --green: #45d47c;
    --amber: #ecb13c;
    --red: #ff7b7b;
    --blue: #6cadff;

    --shadow-xs: 0 1px 1px rgba(0, 0, 0, .4);
    --shadow-sm: 0 1px 3px rgba(0, 0, 0, .45);
    --shadow: 0 8px 20px -8px rgba(0, 0, 0, .6), 0 2px 5px rgba(0, 0, 0, .35);
    --shadow-lg: 0 22px 48px -16px rgba(0, 0, 0, .7), 0 6px 14px rgba(0, 0, 0, .4);

    --scrim: rgba(3, 6, 11, .66);
  }
}

/* --- плотность --- */
html[data-density="compact"] {
  --topbar-h: 46px;
  --gap: 10px;
  --row-y: 3px;
}
/* Кегли — в rem: они едут вместе с корневым размером, который двигает
   множитель из «Оформления». */
html[data-density="compact"] body { font-size: .875rem; }
html[data-density="compact"] .markdown-body { font-size: .97rem; }
html[data-density="compact"] .page-wrap { padding: 18px 32px 36px; }

/* --- скругления --- */
html[data-radius="sharp"] {
  --r-xs: 3px; --r-sm: 4px; --r-md: 6px; --r-lg: 8px; --r-xl: 12px;
}
html[data-radius="soft"] {
  --r-xs: 8px; --r-sm: 12px; --r-md: 16px; --r-lg: 22px; --r-xl: 28px;
}

/* --- плавность --- */
html[data-motion="subtle"] {
  --dur-fast: 90ms;
  --dur: 130ms;
  --dur-slow: 180ms;
  --ease-spring: cubic-bezier(.4, 0, .2, 1);
}
html[data-motion="off"] {
  --dur-fast: 1ms;
  --dur: 1ms;
  --dur-slow: 1ms;
}
html[data-motion="off"] *,
html[data-motion="off"] *::before,
html[data-motion="off"] *::after {
  animation-duration: 1ms !important;
  animation-delay: 0ms !important;
  transition-duration: 1ms !important;
}

/* ------------------------------------------------ 2. База и утилиты ------ */
*, *::before, *::after { box-sizing: border-box; }

/* Корневой кегль — точка отсчёта для всех rem в таблице. Множитель размера
   из «Оформления» двигает именно его: подписи, кнопки и текст страницы
   растут вместе, а отступы и высоты (они в px) остаются на месте.

   Значение подставляется готовым числом — `html{font-size:17.28px}` из
   partials/theme_head.html и из живого предпросмотра. Записать сюда
   `calc(16px * var(--font-scale))` нельзя: переменная объявлена на этом же
   элементе, а по спецификации это circular dependency (значение
   font-size влияет на разбор em внутри самой переменной), и правило просто
   отбрасывается. Проверено: браузер оставлял 16px и не реагировал на смену
   множителя. */
html { scroll-behavior: smooth; font-size: 16px; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* Кегль в rem, а не в px: множитель размера из «Оформления» двигает корневой
   font-size, и всё, набранное в rem, едет за ним. .94rem — это привычные 15px
   при масштабе 1. */
body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: .94rem;
  line-height: 1.6;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-size-adjust: 100%;
}

::selection { background: color-mix(in srgb, var(--accent) 24%, transparent); }

/* Прокрутка.
   Родная полоса забирает 10-15 px ширины: когда содержимое то длиннее, то
   короче экрана (открылось окно, отфильтровался список), раскладка дёргается
   вбок. У страницы, панели и холста редактора полоса спрятана — вместо неё
   app.js рисует накладную (.oscroll), которая лежит поверх и ширины не ест.
   У мелких блоков внутри страницы полоса остаётся родной, но тонкой: там она
   на раскладку страницы не влияет. */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { width: 7px; height: 7px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
  background: var(--border-strong); border-radius: 99px;
  border: 2px solid transparent; background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--fg-muted); background-clip: content-box; }

html.has-oscroll, html.has-oscroll body,
html.has-oscroll .sidebar, html.has-oscroll .ed-canvas,
html.has-oscroll [data-oscroll] { scrollbar-width: none; }
html.has-oscroll::-webkit-scrollbar,
html.has-oscroll body::-webkit-scrollbar,
html.has-oscroll .sidebar::-webkit-scrollbar,
html.has-oscroll .ed-canvas::-webkit-scrollbar,
html.has-oscroll [data-oscroll]::-webkit-scrollbar { width: 0; height: 0; }

.oscroll {
  position: fixed; width: 13px; z-index: 260;
  pointer-events: none; opacity: 0; visibility: hidden;
  transition: opacity var(--dur) var(--ease), visibility 0s linear var(--dur);
}
.oscroll.on { opacity: 1; visibility: visible; transition-delay: 0s; }
.oscroll i {
  position: absolute; left: 4px; right: 4px; top: 0;
  border-radius: 99px; background: var(--border-strong);
  pointer-events: auto; cursor: default; touch-action: none;
  transition: background var(--dur-fast) var(--ease),
              left var(--dur-fast) var(--ease), right var(--dur-fast) var(--ease);
}
.oscroll i:hover, .oscroll.dragging i { left: 2px; right: 2px; background: var(--fg-muted); }
.oscroll.dragging i { background: var(--accent); }
@media print { .oscroll { display: none; } }

a { color: var(--accent-text); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Атрибут hidden должен побеждать любые компонентные display-правила:
   иначе служебные поля (input[type=file], textarea с исходником) вылезают в вёрстку. */
[hidden] { display: none !important; }

:focus { outline: none; }
:focus-visible,
a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, summary:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

h1, h2, h3, h4 { line-height: 1.25; margin: 0 0 .5em; font-weight: 650; letter-spacing: -.014em; }
h1 { font-size: 1.75rem; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.05rem; }
p { margin: 0 0 1em; }

kbd {
  font-family: var(--font); font-size: .72em; font-weight: 600;
  padding: 2px 5px; min-width: 18px; display: inline-block; text-align: center;
  border: 1px solid var(--border-strong); border-bottom-width: 2px;
  border-radius: var(--r-xs); background: var(--bg-alt); color: var(--fg-soft);
  white-space: nowrap; line-height: 1.3;
}

.ico { flex: none; vertical-align: -.15em; }
.flip { transform: rotate(180deg); }
.muted { color: var(--fg-muted); }
.small { font-size: .85em; }
.grow { flex: 1 1 auto; min-width: 0; }
.pad { padding: 10px 12px; }
.nowrap { white-space: nowrap; }
.center { text-align: center; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.ellipsis { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dotsep { color: var(--fg-muted); }
.count {
  display: inline-block; min-width: 20px; padding: 1px 7px; margin-left: 6px;
  border-radius: 99px; background: var(--bg-sunken); color: var(--fg-soft);
  font-size: .73rem; font-weight: 650; vertical-align: 2px;
  font-variant-numeric: tabular-nums;
}

.linklike {
  background: none; border: 0; color: var(--accent-text); cursor: pointer;
  padding: 0; font: inherit; text-align: left;
}
.linklike:hover { text-decoration: underline; }
.linklike.danger { color: var(--red); }
.link { color: var(--accent-text); font-size: .9em; display: inline-flex; align-items: center; gap: 5px; }

.skip-link {
  position: absolute; left: -9999px; top: 8px; z-index: 300;
  padding: 9px 16px; background: var(--accent); color: var(--accent-fg);
  border-radius: var(--r-sm); font-weight: 600;
}
.skip-link:focus { left: 8px; text-decoration: none; }

/* Прогресс чтения */
.read-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 100;
  background: transparent; pointer-events: none;
}
.read-progress span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #22d3ee));
  transition: width 90ms linear;
}

/* Кнопка «наверх» */
.fab-top {
  position: fixed; right: 22px; bottom: 22px; z-index: 70;
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--border); background: var(--bg-elev); color: var(--fg-soft);
  box-shadow: var(--shadow); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  opacity: 0; transform: translateY(8px); transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.fab-top.show { opacity: 1; transform: none; }
.fab-top:hover { color: var(--accent-text); border-color: var(--accent-line); }
@media print { .fab-top { display: none; } }

/* ------------------------------------------------ 3. Шапка --------------- */
.topbar {
  position: sticky; top: 0; z-index: 60;
  height: var(--topbar-h);
  display: flex; align-items: center; gap: 10px;
  padding: 0 12px;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
}

.brand { display: flex; align-items: center; gap: 9px; color: var(--fg); flex: none; }
.brand:hover { text-decoration: none; }
.brand-mark { font-size: 20px; line-height: 1; }
.brand-text { display: flex; flex-direction: column; line-height: 1.2; }
.brand-text b { font-size: .9rem; letter-spacing: -.01em; }
.brand-text small { color: var(--fg-muted); font-size: .73rem; }

.search-trigger {
  flex: 1 1 auto; max-width: 440px; margin: 0 6px;
  display: flex; align-items: center; gap: 8px;
  height: 32px; padding: 0 6px 0 11px;
  border: 1px solid var(--border); border-radius: 99px;
  background: var(--bg-alt); color: var(--fg-muted);
  font: inherit; font-size: .84rem; cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.search-trigger:hover { border-color: var(--border-strong); background: var(--bg); box-shadow: var(--shadow-xs); }
.search-trigger > span { flex: 1; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-trigger kbd { font-size: .71rem; padding: 1px 4px; border-bottom-width: 1px; }

.topnav { display: flex; gap: 1px; }
.topnav a {
  display: flex; align-items: center; gap: 6px;
  padding: 6px 10px; border-radius: var(--r-sm);
  color: var(--fg-soft); font-size: .85rem; font-weight: 500;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.topnav a:hover { background: var(--bg-hover); text-decoration: none; color: var(--fg); }
.topnav a.active { color: var(--accent-text); background: var(--accent-soft); }

.topbar-right { display: flex; align-items: center; gap: 6px; margin-left: auto; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--fg-soft); cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.icon-btn:hover { background: var(--bg-hover); color: var(--fg); }
.icon-btn.tiny { width: 26px; height: 26px; }
.icon-btn.danger:hover { color: var(--red); background: color-mix(in srgb, var(--red) 12%, transparent); }
.icon-btn[hidden] { display: none; }

.theme-moon { display: none; }
html[data-theme="dark"] .theme-sun { display: none; }
html[data-theme="dark"] .theme-moon { display: inline-flex; }
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] .theme-sun { display: none; }
  html[data-theme="auto"] .theme-moon { display: inline-flex; }
}

.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  width: 29px; height: 29px; border-radius: 50%;
  color: #fff; font-size: .7rem; font-weight: 700; letter-spacing: .01em;
  flex: none; user-select: none; text-shadow: 0 1px 1px rgba(0, 0, 0, .18);
}
.avatar.xs { width: 18px; height: 18px; font-size: .54rem; }
.avatar.sm { width: 24px; height: 24px; font-size: .68rem; }
.avatar.lg { width: 40px; height: 40px; font-size: .88rem; }
.avatar.xl { width: 66px; height: 66px; font-size: 1.35rem; }
.avatar-btn {
  background: none; border: 0; padding: 2px; cursor: pointer; border-radius: 50%;
  transition: box-shadow var(--dur) var(--ease);
}
.avatar-btn:hover { box-shadow: 0 0 0 2px var(--accent-line); }

/* ------------------------------------------------ 4. Раскладка ----------- */
.layout {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  min-height: calc(100vh - var(--topbar-h));
  transition: grid-template-columns var(--dur-slow) var(--ease-out);
}
.layout.has-aside { grid-template-columns: var(--sidebar-w) minmax(0, 1fr) var(--aside-w); }
.layout.no-sidebar { grid-template-columns: minmax(0, 1fr); }
.layout.no-sidebar .sidebar { display: none; }

html.sidebar-collapsed { --sidebar-w: 0px; }
html.sidebar-collapsed .sidebar {
  opacity: 0; pointer-events: none; border-right-color: transparent; overflow: hidden;
}

.sidebar {
  border-right: 1px solid var(--border);
  background: var(--bg-alt);
  position: sticky; top: var(--topbar-h);
  height: calc(100vh - var(--topbar-h));
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain;
  transition: opacity var(--dur) var(--ease);
}
.sidebar-inner {
  padding: 12px 10px 20px; display: flex; flex-direction: column; gap: 14px;
  min-height: 100%; width: var(--sidebar-w); min-width: 240px;
}
.sidebar-backdrop { display: none; }

.content { min-width: 0; padding-bottom: 0; display: flex; flex-direction: column; }

.page-wrap { width: 100%; max-width: calc(var(--prose-w) + 96px); margin: 0 auto; padding: 26px 48px 48px; flex: 1 0 auto; }
.page-wrap.wide { max-width: 1160px; }
.page-wrap.narrow { max-width: 660px; }

.site-footer {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 16px 48px; margin-top: auto;
  border-top: 1px solid var(--border);
  font-size: .8rem; color: var(--fg-muted);
}
.site-footer a, .site-footer .linklike { color: var(--fg-muted); font-size: inherit; }
.site-footer a:hover, .site-footer .linklike:hover { color: var(--accent-text); }

/* ------------------------------------------------ 5. Навигация и дерево -- */
.space-switch { width: 100%; }
.space-current {
  width: 100%; display: flex; align-items: center; gap: 9px;
  padding: 7px 8px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev); cursor: pointer; color: var(--fg); font: inherit;
  text-align: left; transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.space-current:hover { border-color: var(--border-strong); box-shadow: var(--shadow-xs); }
.space-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.space-meta b { font-size: .875rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.space-meta small { color: var(--fg-muted); font-size: .73rem; }

.space-emoji {
  display: inline-flex; align-items: center; justify-content: center;
  width: 29px; height: 29px; border-radius: 8px; font-size: 15px; flex: none;
  background: color-mix(in srgb, var(--sc, var(--accent)) 15%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--sc, var(--accent)) 26%, transparent);
}
.space-emoji.sm { width: 21px; height: 21px; font-size: 11px; border-radius: 6px; }
.space-emoji.lg { width: 44px; height: 44px; font-size: 22px; border-radius: 12px; }
.space-emoji.xl { width: 76px; height: 76px; font-size: 38px; border-radius: 20px; }

.tree-toolbar { display: flex; align-items: center; gap: 3px; }
.tree-filter {
  flex: 1; display: flex; align-items: center; gap: 6px;
  padding: 0 6px 0 9px; height: 30px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg); color: var(--fg-muted);
  transition: border-color var(--dur) var(--ease);
}
.tree-filter:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.tree-filter input[type=text] {
  flex: 1; width: auto; min-width: 0; margin: 0; padding: 0;
  border: 0; background: none; outline: none; box-shadow: none;
  font: inherit; font-size: .82rem; color: var(--fg);
}
.tree-filter input[type=text]:focus { border: 0; box-shadow: none; }
.filter-clear {
  border: 0; background: none; color: var(--fg-muted); cursor: pointer;
  display: inline-flex; padding: 2px; border-radius: var(--r-xs);
}
.filter-clear:hover { color: var(--fg); background: var(--bg-hover); }

.tree-wrap { margin: 0 -2px; flex: 0 0 auto; }

/* Глубина дерева не ограничена, поэтому отступ не может расти линейно: при
   13 px на уровень к шестому от названия остаётся пара букв. Первые уровни
   получают полный шаг, дальше он сужается, а место уровня берёт на себя
   вертикальная направляющая — по ней видно, к какой ветке относится строка.
   Так вкладывать можно вдвое глубже, чем раньше, не теряя названий. */
.tree {
  list-style: none; margin: 0; position: relative;
  padding: 0 0 0 var(--tree-step, 13px);
}
.tree-wrap > .tree { padding-left: 0; }
.tree[data-depth="4"], .tree[data-depth="5"] { --tree-step: 11px; }
.tree[data-depth="6"], .tree[data-depth="7"] { --tree-step: 9px; }
.tree[data-depth="8"] { --tree-step: 8px; }
/* глубже девятого шаг не уменьшаем — иначе уровни сливаются. Отдельного
   правила для десятого и дальше не нужно: --tree-step наследуется. */
.tree[data-depth="9"] { --tree-step: 7px; }

/* Направляющая ветки: тонкая линия вдоль отступа вложенного списка. На
   глубине она и заменяет собой отступ — по ней видно, откуда растёт строка.
   Ветка, в которой лежит открытая страница, подсвечена акцентом. */
.tree-item > .tree::before {
  content: ""; position: absolute; left: 4px; top: 0; bottom: 4px;
  width: 1px; border-radius: 1px; background: var(--border-strong);
  transition: background var(--dur-fast) var(--ease);
}
.tree-item > .tree:hover::before { background: var(--fg-muted); }
.tree-item.open:has(> .tree .tree-row.active) > .tree::before {
  background: color-mix(in srgb, var(--accent) 60%, transparent);
}

.tree-item > .tree { display: none; }
.tree-item.open > .tree { display: block; animation: tree-open 190ms var(--ease); }
@keyframes tree-open {
  from { opacity: 0; transform: translateY(-5px); }
  to   { opacity: 1; transform: none; }
}

/* Одна кнопка на сворачивание и разворачивание: стрелка поворачивается,
   показывая, что произойдёт по клику. */
.tree-toggle .ico { transition: transform 220ms var(--ease); }
.tree-toggle.on .ico { transform: rotate(90deg); }
.tree-toggle.on { background: var(--accent-soft); color: var(--accent-text); }

@media (prefers-reduced-motion: reduce) {
  .tree-item.open > .tree { animation: none; }
  .tree-toggle .ico { transition: none; }
}
.tree-item.hidden { display: none; }

.tree-row {
  display: flex; align-items: center; gap: 1px;
  border-radius: var(--r-sm); padding-right: 2px; position: relative;
  transition: background var(--dur) var(--ease);
}
.tree-row:hover { background: var(--bg-hover); }
.tree-row.active { background: var(--accent-soft); }
.tree-row.active::before {
  content: ""; position: absolute; left: -6px; top: 5px; bottom: 5px;
  width: 3px; border-radius: 99px; background: var(--accent);
}
.tree-row.active .tree-link { color: var(--accent-text); font-weight: 600; }

.tree-caret {
  width: 17px; height: 25px; display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: none; color: var(--fg-muted); cursor: pointer; flex: none; padding: 0;
  transition: transform 120ms var(--ease);
}
.tree-caret:hover { color: var(--fg); }
.tree-caret.empty { cursor: default; }
.tree-item.open > .tree-row > .tree-caret { transform: rotate(90deg); }

.tree-link {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 7px;
  padding: 4px 2px; color: var(--fg-soft); font-size: .85rem; overflow: hidden;
}
.tree-link:hover { text-decoration: none; color: var(--fg); }
.tree-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tree-icon { flex: none; width: 16px; text-align: center; font-size: 13px; }
.tree-link mark { background: color-mix(in srgb, var(--accent) 28%, transparent); color: inherit; border-radius: 3px; }

/* Вид кнопок «+» и «…» описан ниже, вместе с .tree-tools */

.dot { width: 6px; height: 6px; border-radius: 50%; flex: none; }
.dot.draft { background: var(--amber); }

.tree-item.drag-over > .tree-row { box-shadow: inset 0 0 0 2px var(--accent); }
.tree-item.dragging { opacity: .4; }
.tree-nomatch { padding: 12px 10px; }

.side-block { display: flex; flex-direction: column; gap: 3px; }
.side-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 8px 2px; font-size: .73rem; text-transform: uppercase;
  letter-spacing: .08em; color: var(--fg-muted); font-weight: 700;
}
.side-head a { color: var(--fg-muted); display: inline-flex; padding: 2px; border-radius: var(--r-xs); }
.side-head a:hover { color: var(--accent-text); background: var(--bg-hover); }

.side-list { list-style: none; margin: 0; padding: 0; }
.side-list a {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: var(--r-sm);
  color: var(--fg-soft); font-size: .85rem;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.side-list a:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }

.side-empty { padding: 14px 10px; font-size: .82rem; color: var(--fg-muted); }
.side-empty p { margin: 0 0 6px; }

.side-foot {
  margin-top: auto; padding: 10px 8px 0; border-top: 1px solid var(--border);
  display: flex; gap: 14px; font-size: .8rem;
}
.side-foot a, .side-foot button {
  display: inline-flex; align-items: center; gap: 6px; color: var(--fg-muted);
}
.side-foot a:hover, .side-foot button:hover { color: var(--accent-text); text-decoration: none; }

/* ------------------------------------------------ 6. Кнопки и меню ------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 6px 12px; border: 1px solid var(--border);
  border-radius: var(--r-sm); background: var(--bg-elev); color: var(--fg);
  font: inherit; font-size: .86rem; font-weight: 550; cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform 80ms var(--ease);
  text-decoration: none; white-space: nowrap; line-height: 1.5;
}
.btn:hover { background: var(--bg-hover); border-color: var(--border-strong); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); box-shadow: var(--shadow-xs); }
.btn.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--fg-soft); }
.btn.ghost:hover { background: var(--bg-hover); color: var(--fg); }
.btn.dashed {
  background: transparent; border-style: dashed; border-color: var(--border-strong);
  color: var(--fg-soft); font-weight: 500;
}
.btn.dashed:hover,
.btn.dashed.active { border-color: var(--accent); color: var(--accent-text); background: var(--accent-soft); }
.btn.danger { color: var(--red); border-color: color-mix(in srgb, var(--red) 28%, var(--border)); }
.btn.danger:hover { background: color-mix(in srgb, var(--red) 10%, transparent); border-color: var(--red); }
.btn.small { padding: 5px 10px; font-size: .82rem; }
.btn.tiny { padding: 3px 8px; font-size: .76rem; }
.btn.block { width: 100%; }
.btn.icon-only { padding: 5px 7px; }
.btn.active { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 40%, var(--border)); background: color-mix(in srgb, var(--amber) 10%, transparent); }
.btn.active .ico { fill: currentColor; }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.dropdown { position: relative; display: inline-flex; }
.dropdown-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 80;
  min-width: 214px; padding: 5px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  display: none; flex-direction: column; gap: 1px;
  animation: dd-in 120ms var(--ease);
}
@keyframes dd-in { from { opacity: 0; transform: translateY(-4px); } }
.dropdown-menu.right { left: auto; right: 0; }
.dropdown-menu.wide { min-width: 270px; }
.dropdown-menu.up { top: auto; bottom: calc(100% + 6px); }
.dropdown.open > .dropdown-menu { display: flex; }

.dropdown-menu a,
.dropdown-menu button {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 9px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--fg); font: inherit; font-size: .85rem;
  cursor: pointer; text-align: left; width: 100%;
  transition: background var(--dur) var(--ease);
}
.dropdown-menu a:hover, .dropdown-menu button:hover { background: var(--bg-hover); text-decoration: none; }
.dropdown-menu a.sel { background: var(--accent-soft); color: var(--accent-text); font-weight: 600; }
.dropdown-menu .danger { color: var(--red); }
.dropdown-menu .danger:hover { background: color-mix(in srgb, var(--red) 12%, transparent); }
.dropdown-menu form { margin: 0; }
.dropdown-menu kbd { margin-left: auto; }
.dd-sep { height: 1px; background: var(--border); margin: 4px 2px; }
.dd-label {
  padding: 6px 9px 3px; font-size: .72rem; text-transform: uppercase;
  letter-spacing: .07em; color: var(--fg-muted); font-weight: 700;
}
.dd-head { display: flex; align-items: center; gap: 10px; padding: 8px 9px; }
.dd-head b { display: block; font-size: .875rem; }
.dd-head small { color: var(--fg-muted); font-size: .73rem; }

/* Уведомления — всегда в углу экрана, не в потоке страницы */
.toasts {
  position: fixed; right: 18px; z-index: 300;
  display: flex; flex-direction: column; gap: 10px;
  width: min(380px, calc(100vw - 36px));
  padding: 0; margin: 0; pointer-events: none;
}
.toasts.pos-bottom { bottom: 18px; flex-direction: column-reverse; }
.toasts.pos-top { top: calc(var(--topbar-h) + 12px); }
.toasts:empty { display: none; }

.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 13px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--bg-elev);
  box-shadow: var(--shadow-lg); font-size: .87rem; line-height: 1.45;
  pointer-events: auto;
  animation: toast-in var(--dur-slow) var(--ease-spring);
  will-change: transform, opacity;
}
.toast .ico { flex: none; margin-top: 2px; }
.toast > span { flex: 1; min-width: 0; overflow-wrap: anywhere; }
@keyframes toast-in { from { opacity: 0; transform: translateX(26px) scale(.97); } }
.toast.leaving {
  opacity: 0; transform: translateX(26px) scale(.97);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.toast.success { border-color: color-mix(in srgb, var(--green) 38%, var(--border)); color: var(--green); background: color-mix(in srgb, var(--green) 7%, var(--bg-elev)); }
.toast.error { border-color: color-mix(in srgb, var(--red) 38%, var(--border)); color: var(--red); background: color-mix(in srgb, var(--red) 7%, var(--bg-elev)); }
.toast-x {
  margin-left: auto; border: 0; background: none; color: inherit; cursor: pointer;
  opacity: .5; display: inline-flex; padding: 2px; border-radius: var(--r-xs); flex: none;
  transition: opacity var(--dur-fast) var(--ease);
}
.toast-x:hover { opacity: 1; }

@media (max-width: 560px) {
  .toasts { right: 10px; left: 10px; width: auto; }
  .toasts.pos-bottom { bottom: 10px; }
}

/* Модальные окна */
/* Подложка затемняет, но не размывает: blur(4px) под каждым окном мылил
   текст страницы и на слабых машинах ронял плавность появления. Достаточно
   плотной заливки — она же даёт нужный контраст в обеих темах. */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 200;
  background: var(--scrim);
  display: none; align-items: flex-start; justify-content: center;
  padding: 11vh 16px 16px;
}
.modal-backdrop.open { display: flex; animation: fade-in 140ms var(--ease); }

/* Подтверждение всегда поверх того, кто его позвал. Редакторы диаграммы и
   фото и окно ссылки лежат на 300, обычные окна — на 200, поэтому вопрос
   «закрыть без сохранения?» уезжал ПОД редактор и выглядел как полоса
   снизу. Отдельный слой выше всех окон — иначе на каждое новое окно
   пришлось бы вспоминать про этот случай заново. */
#confirmBackdrop { z-index: 500; }

@keyframes fade-in { from { opacity: 0; } }

.palette, .modal {
  width: 100%; max-width: 620px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  overflow: hidden; animation: pop 160ms var(--ease);
  display: flex; flex-direction: column; max-height: 78vh;
}
@keyframes pop { from { transform: translateY(-10px) scale(.985); opacity: 0; } }

/* --- окно поиска и команд (Ctrl+K) ---------------------------------------
   Окно открыто чаще любого другого, поэтому у него свои размеры и свой ритм:
   широкая строка ввода сверху, результаты одной колонкой, подсказка по
   клавишам снизу. Высота фиксирована (не «сколько получится»), иначе окно
   прыгало по экрану на каждый набранный символ: два результата — короткое,
   десять — во весь экран. Теперь оно стоит на месте, а список прокручивается
   внутри. */
.palette {
  max-width: 680px;
  height: min(560px, 76vh);
  max-height: 76vh;
  border-radius: var(--r-lg);
}
.modal-backdrop:has(.palette) { padding-top: 9vh; }

.palette-input {
  display: flex; align-items: center; gap: 11px;
  padding: 0 12px 0 16px; height: 56px; flex: none;
  border-bottom: 1px solid var(--border); color: var(--fg-muted);
}
.palette-input > .ico { color: var(--accent-text); flex: none; }
.palette-input input[type=text] {
  flex: 1; width: auto; min-width: 0; margin: 0; padding: 0;
  border: 0; box-shadow: none; background: none; outline: none;
  font: inherit; font-size: 1.02rem; font-weight: 500; color: var(--fg);
}
.palette-input input[type=text]:focus { border: 0; box-shadow: none; }
.palette-input input[type=text]::placeholder { color: var(--fg-muted); font-weight: 400; }
.palette-input .icon-btn { flex: none; }
/* Кнопка закрытия — подпись клавишей, а не крестиком: так видно, чем окно
   закрывается с клавиатуры. Ширина под текст, а не квадрат 26×26. */
.palette-input .icon-btn.tiny { width: auto; min-width: 34px; padding: 0 4px; }
.palette-input kbd { font-size: .6rem; }

.palette-results {
  flex: 1 1 auto; overflow-y: auto; overscroll-behavior: contain;
  padding: 6px 8px 10px; scroll-padding: 34px 0 8px;
}
.p-group {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; gap: 8px;
  padding: 9px 8px 5px; margin: 0;
  background: linear-gradient(var(--bg-elev) 72%, transparent);
  font-size: .72rem; text-transform: uppercase; letter-spacing: .07em;
  color: var(--fg-muted); font-weight: 700;
}
.p-group::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}
.p-item {
  position: relative;
  display: flex; align-items: center; gap: 11px;
  padding: 9px 11px; border-radius: var(--r-md); cursor: pointer; color: var(--fg);
  border: 1px solid transparent; width: 100%; background: none; font: inherit; text-align: left;
  scroll-margin: 6px;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.p-item:hover { background: var(--bg-hover); text-decoration: none; }
/* Выбранная строка помечена заливкой и полосой слева, а не одной рамкой:
   рамку в списке из десяти строк глаз не находил. */
.p-item.sel {
  background: var(--accent-soft); border-color: var(--accent-line); text-decoration: none;
}
.p-item.sel::before {
  content: ""; position: absolute; left: -1px; top: 8px; bottom: 8px;
  width: 3px; border-radius: 99px; background: var(--accent);
}
.p-item .grow { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.p-item b { font-size: .9rem; display: block; font-weight: 600; line-height: 1.35; }
.p-item small {
  color: var(--fg-muted); font-size: .77rem; line-height: 1.4; display: block;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.p-item mark { background: color-mix(in srgb, var(--accent) 26%, transparent); color: inherit; border-radius: 3px; padding: 0 2px; }
.p-item .p-icon {
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-sunken); color: var(--fg-soft); font-size: 15px;
  box-shadow: inset 0 0 0 1px var(--border);
}
.p-item.sel .p-icon { background: var(--bg-elev); box-shadow: inset 0 0 0 1px var(--accent-line); }
.p-item .p-icon .icon-img { width: 18px; height: 18px; border-radius: 4px; object-fit: cover; }
/* Пространство страницы — меткой, а не блёклой подписью: по ней взгляд
   отделяет одинаковые названия из разных разделов. */
.p-badge {
  flex: none; max-width: 30%; padding: 2px 8px; border-radius: 99px;
  background: var(--bg-sunken); color: var(--fg-soft);
  font-size: .7rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.p-item.sel .p-badge { background: var(--bg-elev); color: var(--accent-text); }
/* Подсказка «Enter» появляется только у выбранной строки — иначе десять
   одинаковых значков рябят в глазах. */
.p-enter { flex: none; opacity: 0; color: var(--accent-text); font-size: .73rem; }
.p-item.sel .p-enter { opacity: 1; }

.p-empty {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 46px 24px; text-align: center; color: var(--fg-muted); font-size: .875rem;
}
.p-empty .ico { opacity: .5; }
.p-empty b { color: var(--fg-soft); font-size: .92rem; font-weight: 600; }

.palette-foot {
  display: flex; align-items: center; gap: 14px; padding: 9px 16px; flex: none;
  border-top: 1px solid var(--border); background: var(--bg-alt);
  font-size: .72rem; color: var(--fg-muted); flex-wrap: wrap;
}
.palette-foot span { display: inline-flex; align-items: center; gap: 4px; }
.palette-foot kbd { font-size: .70rem; padding: 1px 5px; }

@media (max-width: 620px) {
  .palette { height: min(520px, 82vh); max-height: 82vh; }
  .modal-backdrop:has(.palette) { padding-top: 5vh; }
  .p-badge { display: none; }
  /* на узком экране подсказка по клавишам не нужна — там нет клавиатуры */
  .palette-foot { display: none; }
}

.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 16px; border-bottom: 1px solid var(--border); flex: none; }
.modal-head h3 { margin: 0; }
.modal-body { padding: 16px; overflow-y: auto; }
.modal-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--border); background: var(--bg-alt); flex: none; }
/* --- окно горячих клавиш: вкладки по контекстам ---
   Список рос вместе с редактором и перестал читаться: сорок строк подряд,
   в которых «на странице» и «в редакторе» различались только подзаголовком.
   Теперь у каждого контекста своя вкладка, а поиск идёт сразу по всем. */
.keys-modal { max-width: 780px; max-height: 82vh; }

/* Полоса не переносится: вкладки переносятся внутри себя, а поле поиска
   ужимается рядом. Раньше переносилась вся полоса целиком, и поле прыгало
   на строку ниже, как только вкладки занимали ширину. */
.keys-bar {
  display: flex; align-items: center; gap: 12px; flex: none; flex-wrap: nowrap;
  padding: 9px 14px; border-bottom: 1px solid var(--border); background: var(--bg-alt);
}
.keys-tabs { display: flex; gap: 4px; flex-wrap: wrap; flex: 1 1 auto; min-width: 0; }
.keys-tab {
  border: 1px solid transparent; background: none; color: var(--fg-soft);
  font: inherit; font-size: .8rem; font-weight: 600; cursor: pointer;
  padding: 5px 11px; border-radius: var(--r-sm); white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.keys-tab:hover { background: var(--bg-hover); color: var(--fg); }
.keys-tab.on {
  background: var(--bg-elev); color: var(--accent-text);
  border-color: var(--accent-line); box-shadow: var(--shadow-xs);
}
.keys-tab .keys-tab-count { color: var(--fg-muted); font-weight: 500; margin-left: 5px; }
.keys-tab.dim { opacity: .45; }
.keys-tab.dim:hover { opacity: 1; }

/* Коробки вокруг поля больше нет: рамка с заливкой и свечением спорили с
   вкладками рядом — получалось «выделение непонятно чего». Остались значок,
   текст и тонкая линия снизу, которая подсвечивается на фокусе.
   flex: 0 1 — поле ужимается до min-width вместо переноса на новую строку. */
.keys-find {
  display: flex; align-items: center; gap: 6px;
  flex: 0 1 200px; min-width: 132px;
  padding: 4px 2px; border: 0; border-radius: 0;
  background: none; color: var(--fg-muted);
  border-bottom: 1px solid var(--border);
  transition: border-color var(--dur-fast) var(--ease);
}
.keys-find:focus-within { border-bottom-color: var(--accent); box-shadow: none; }
.keys-find input {
  width: 100%; min-width: 0; margin: 0; padding: 0; border: 0; background: none;
  outline: none; font: inherit; font-size: .82rem; color: var(--fg);
}
.keys-find input:focus { border: 0; box-shadow: none; }

.keys-body { padding: 14px 16px 18px; }
.keys-pane[hidden] { display: none; }
.keys-title {
  margin: 18px 0 8px; font-size: .73rem; font-weight: 700; color: var(--fg-muted);
  text-transform: uppercase; letter-spacing: .07em;
}
.keys-pane > .keys-title:first-child { margin-top: 0; }
.keys-note { margin: -2px 0 8px; font-size: .78rem; color: var(--fg-muted); }
.keys-list { display: flex; flex-direction: column; gap: 2px; }

.key-row {
  display: grid; grid-template-columns: minmax(150px, auto) 1fr; gap: 8px 18px;
  align-items: baseline; padding: 5px 8px; border-radius: var(--r-xs); font-size: .86rem;
}
.key-row:hover { background: var(--bg-hover); }
.key-row[hidden] { display: none; }
.key-combo { color: var(--fg-soft); font-size: .8rem; }
.key-desc { color: var(--fg); }
.key-desc kbd, .key-combo kbd { vertical-align: baseline; }
.key-row mark {
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  color: inherit; border-radius: 3px; padding: 0 2px;
}
.keys-empty { padding: 28px; text-align: center; color: var(--fg-muted); font-size: .875rem; }

/* --- окно горячих клавиш на телефоне ---
   Раньше здесь стоял перенос: пять вкладок ложились в две строки, поле
   поиска занимало третью, и одна только шапка съедала 158 px из 730 —
   пятую часть окна. Под список оставалось место на девять строк, а
   каждая строка была в две линии.

   Теперь вкладки — полоса с горизонтальной прокруткой в одну строку
   (их всё равно перебирают подряд), поиск — узкая строка под ней, а
   сочетание уехало вправо от подписи: строка стала одной линией. */
@media (max-width: 620px) {
  .keys-bar {
    flex-direction: column; align-items: stretch; gap: 6px;
    padding: 8px 0 8px;
  }
  .keys-tabs {
    flex-wrap: nowrap; overflow-x: auto; gap: 2px;
    padding: 0 12px; scrollbar-width: none;
    scroll-padding: 0 12px; overscroll-behavior-x: contain;
  }
  .keys-tabs::-webkit-scrollbar { display: none; }
  .keys-tab { flex: none; padding: 7px 12px; }
  .keys-find { flex: none; margin: 0 14px; padding: 2px 2px 4px; }
  /* Кегль 16 — чтобы iOS не увеличивал страницу на фокусе; отступы поля
     сбрасываем в ноль (общее правило для input[type=text] стоит ниже по
     файлу и при равной силе выигрывало), высота идёт от строки. */
  .keys-find input[type=text] {
    width: 100%; font-size: 16px; padding: 0; height: auto; line-height: 1.4;
  }

  /* Подпись — главное, сочетание — справа, обе половины при нужде
     переносятся внутри себя, а не одна под другую. */
  .key-row {
    grid-template-columns: 1fr auto; gap: 2px 10px;
    align-items: center; padding: 7px 8px;
  }
  .key-row > .key-combo { order: 2; text-align: right; min-width: 0; }
  .key-row > .key-desc { order: 1; min-width: 0; }
  /* Двумя классами нарочно: телефонное правило для .modal-body стоит
     ниже по файлу и при равной силе перебивало бы это. */
  .modal-body.keys-body { padding: 10px 12px calc(12px + var(--safe-b, 0px)); }
  .keys-title { margin: 14px 0 6px; }
}

/* ------------------------------------------------ 7. Формы и таблицы ----- */
.form-card {
  padding: 22px; border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev); margin-bottom: 24px; box-shadow: var(--shadow-xs);
}
.form-card h3 { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--border); }
.form-card h3:first-of-type { margin-top: 0; padding-top: 0; border-top: 0; }
.form-card summary { cursor: pointer; margin-bottom: 14px; }

label { display: block; margin-bottom: 15px; font-size: .8rem; font-weight: 650; color: var(--fg-soft); }
label.check { display: flex; align-items: center; gap: 9px; font-weight: 500; font-size: .87rem; cursor: pointer; }
label.check input { width: auto; margin: 0; }
label .hint { display: block; margin-top: 5px; font-weight: 400; color: var(--fg-muted); font-size: .75rem; }

input[type=text], input[type=password], input[type=email], input[type=number],
input[type=search], input[type=file], select, textarea {
  display: block; width: 100%; margin-top: 6px;
  padding: 8px 11px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg); color: var(--fg); font: inherit; font-size: .88rem; font-weight: 400;
  outline: none; transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); outline: none; }
input[type=color] { width: 100%; height: 38px; margin-top: 6px; padding: 3px; border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg); cursor: pointer; }
input[type=checkbox] { accent-color: var(--accent); width: 15px; height: 15px; }
textarea { resize: vertical; line-height: 1.6; }
select { cursor: pointer; }

/* Заблокированное поле видно сразу: иначе «Активен» и «Роль» в своём же
   профиле выглядят рабочими, а форма их молча игнорирует. */
input:disabled, select:disabled, textarea:disabled {
  background: var(--bg-sunken); color: var(--fg-muted); cursor: not-allowed;
}
.switch input:disabled + span { opacity: .45; cursor: not-allowed; }
.switch:has(input:disabled) { cursor: not-allowed; }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 15px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 15px; }
.grid-5 { display: grid; grid-template-columns: repeat(5, 1fr) auto; gap: 0 12px; align-items: end; }
.grid-5 button { margin-bottom: 15px; }

.form-actions { display: flex; gap: 10px; align-items: center; margin-top: 8px; flex-wrap: wrap; }
.row-actions { display: flex; gap: 8px; align-items: center; }
.row-actions.wrap { flex-wrap: wrap; }
.row-actions form { margin: 0; }

.search-form { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.search-form input[type=text] { flex: 1 1 240px; margin-top: 0; }
.search-form select { width: auto; margin-top: 0; }

.hint-box {
  padding: 15px 17px; border-radius: var(--r-md); background: var(--bg-alt);
  border: 1px solid var(--border); font-size: .87rem;
}
.hint-box ul { margin: 8px 0 0; padding-left: 20px; }
.hint-box li { margin: 4px 0; }

.table-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-elev); }
.table { width: 100%; border-collapse: collapse; font-size: .87rem; }
.table th, .table td { padding: 10px 13px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table th {
  position: sticky; top: 0; z-index: 1;
  background: var(--bg-alt); font-size: .7rem; text-transform: uppercase;
  letter-spacing: .06em; color: var(--fg-muted); font-weight: 700;
}
.table tbody tr { transition: background var(--dur) var(--ease); }
.table tbody tr:hover { background: var(--bg-alt); }
.table tr:last-child td { border-bottom: 0; }
.table select, .table input { margin-top: 0; }
.users-table td { white-space: nowrap; }
.ghost-input {
  border-color: transparent !important; background: transparent !important;
  padding: 4px 7px !important; margin-bottom: 2px;
}
.ghost-input:hover { border-color: var(--border) !important; background: var(--bg) !important; }
.tiny-input { width: 118px; font-size: .8rem !important; padding: 4px 8px !important; }

/* ------------------------------------------------ 8. Карточки и списки --- */
.hero {
  display: flex; gap: 30px; align-items: center; flex-wrap: wrap;
  padding: 28px 30px; margin-bottom: 30px;
  border: 1px solid var(--border); border-radius: var(--r-xl);
  background:
    radial-gradient(900px 260px at 0% 0%, var(--accent-soft), transparent 70%),
    var(--bg-alt);
}
.hero h1 { margin-bottom: .35em; font-size: 1.85rem; }
.lead { color: var(--fg-soft); font-size: 1rem; max-width: 58ch; }
.hero-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
.hero-stats { display: grid; grid-template-columns: repeat(2, minmax(92px, 1fr)); gap: 10px; margin-left: auto; }
.stat {
  padding: 11px 15px; border-radius: var(--r-md); background: var(--bg);
  border: 1px solid var(--border); text-align: center;
}
.stat b { display: block; font-size: 1.5rem; line-height: 1.15; font-variant-numeric: tabular-nums; }
.stat span { font-size: .72rem; color: var(--fg-muted); }

.block { margin-bottom: 32px; }
.block-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 13px; }
.block-head h2 { display: flex; align-items: center; gap: 9px; margin: 0; font-size: 1.02rem; color: var(--fg-soft); }
.block-head h2 .ico { color: var(--fg-muted); }
.block-head.big { margin-bottom: 22px; }
.block-head.big h1 { display: flex; align-items: center; gap: 11px; margin: 0; }
.block-head.big h1 .ico { color: var(--fg-muted); }

.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(252px, 1fr)); gap: 14px; }
.cards.small { grid-template-columns: repeat(auto-fill, minmax(216px, 1fr)); }
.card {
  display: block; padding: 17px; border: 1px solid var(--border);
  border-radius: var(--r-lg); background: var(--bg-elev); color: var(--fg);
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.card:hover { text-decoration: none; border-color: var(--accent-line); box-shadow: var(--shadow); background: var(--bg-tint); }
.card h3, .card h4 { margin: 11px 0 6px; font-size: .98rem; }
.card h4 { margin-top: 0; display: flex; align-items: center; gap: 7px; }
.card p { margin: 0; color: var(--fg-muted); font-size: .83rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.card footer { display: flex; gap: 9px; align-items: center; margin-top: 13px; font-size: .73rem; color: var(--fg-muted); flex-wrap: wrap; }
.space-card { border-top: 3px solid var(--sc, var(--accent)); }

.vis { padding: 1px 8px; border-radius: 99px; background: var(--bg-sunken); }
.vis-public { color: var(--green); }
.vis-private { color: var(--amber); }

.row-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; background: var(--bg-elev); }
.row-list li + li { border-top: 1px solid var(--border); }
.row-list a { display: flex; align-items: center; gap: 11px; padding: 11px 14px; color: var(--fg); transition: background var(--dur) var(--ease); }
.row-list a:hover { background: var(--bg-alt); text-decoration: none; }
.row-list b { display: block; font-size: .89rem; font-weight: 600; }
.row-list small { color: var(--fg-muted); font-size: .76rem; }
.row-list.compact a { padding: 7px 12px; font-size: .85rem; }

.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 28px; align-items: start; }

.feed { list-style: none; margin: 0; padding: 0; }
.feed-item { display: flex; align-items: center; gap: 10px; padding: 9px 4px; border-bottom: 1px solid var(--border); font-size: .86rem; }
.feed-item:last-child { border-bottom: 0; }
.feed-item i { color: var(--fg-soft); font-style: normal; }
.feed-item time { color: var(--fg-muted); font-size: .75rem; white-space: nowrap; }

.badge {
  display: inline-block; padding: 2px 9px; border-radius: 99px;
  font-size: .73rem; font-weight: 600; line-height: 1.45;
  background: var(--bg-sunken); color: var(--fg-soft);
  border: 1px solid transparent;
}
.badge.draft { background: color-mix(in srgb, var(--amber) 16%, transparent); color: var(--amber); }
.badge.ok { background: color-mix(in srgb, var(--green) 16%, transparent); color: var(--green); }

.empty-box {
  padding: 38px; text-align: center; border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg); color: var(--fg-muted); grid-column: 1 / -1;
}
.empty-box p { margin: 0 0 12px; }
.empty-hero { text-align: center; padding: 64px 20px; }
.empty-hero .hero-actions { justify-content: center; }
.empty-hero .lead { margin: 0 auto; }
.err-code { font-size: 4.5rem; font-weight: 800; color: var(--accent-text); line-height: 1; letter-spacing: -.03em; }

.chips { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 11px; }
.chip { padding: 3px 11px; border-radius: 99px; background: var(--bg-sunken); font-size: .78rem; color: var(--fg-soft); }

.stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(134px, 1fr)); gap: 12px; margin-bottom: 30px; }
.stat-card { padding: 15px; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-elev); }
.stat-card b { display: block; font-size: 1.6rem; line-height: 1.15; font-variant-numeric: tabular-nums; }
.stat-card span { font-size: .74rem; color: var(--fg-muted); }

.kv { list-style: none; margin: 0 0 14px; padding: 0; }
.kv li { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: .87rem; }

/* --- профиль ---
   Раньше поля стояли в двух колонках по 1fr: справа «Смена пароля» с двумя
   строчками, слева всё остальное — колонки расходились по высоте втрое, а на
   планшете превращались в две узкие полосы. Теперь это те же карточки
   настроек, что и в админке: подпись над полем, пояснение под ним, действия
   отдельной полосой снизу. */
.profile-head {
  display: flex; gap: 22px; align-items: center; flex-wrap: wrap;
  padding-bottom: 22px; margin-bottom: 24px; border-bottom: 1px solid var(--border);
}
.profile-head h1 { margin-bottom: 6px; }
.profile-ident { flex: 1 1 260px; min-width: 0; }
.profile-sub {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin: 0 0 12px; font-size: .84rem;
}
.profile-login { color: var(--fg-soft); font-weight: 600; }
.profile-stats { display: flex; gap: 8px; flex-wrap: wrap; }
.profile-stats span {
  padding: 5px 12px; border-radius: 99px;
  border: 1px solid var(--border); background: var(--bg-alt);
  font-size: .78rem; color: var(--fg-muted);
}
.profile-stats b {
  color: var(--fg); font-size: .88rem; font-weight: 700;
  font-variant-numeric: tabular-nums; margin-right: 3px;
}

.profile-cols {
  display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: 16px; align-items: start; margin-bottom: 34px;
}
@media (max-width: 900px) { .profile-cols { grid-template-columns: 1fr; } }

/* Аватар правится в одной строке с именем и цветом: видно, что получится */
.avatar-edit { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.avatar-edit > .avatar { flex: none; margin-top: 20px; }
.avatar-edit .field.grow { flex: 1 1 200px; }

/* Полоса действий карточки настроек: в профиле и в админке одинаковая */
.setting-foot {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 18px; border-top: 1px solid var(--border); background: var(--bg-alt);
}
.setting-foot code {
  font-family: var(--font-mono); font-size: .82em;
  padding: 1px 6px; border-radius: var(--r-xs);
  background: var(--bg-sunken); border: 1px solid var(--border);
}

.search-results { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.search-results > li > a {
  display: block; padding: 15px 17px; border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--fg); background: var(--bg-elev);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.search-results > li > a:hover, .search-results > li > a.sel { text-decoration: none; border-color: var(--accent-line); box-shadow: var(--shadow-xs); }
.search-results h3 { margin: 0 0 6px; font-size: 1rem; }
.snip { color: var(--fg-soft); font-size: .86rem; margin: 0 0 9px; line-height: 1.6; }
.snip mark, .search-results mark { background: color-mix(in srgb, var(--accent) 22%, transparent); color: inherit; border-radius: 3px; padding: 0 2px; }
.search-results footer { display: flex; align-items: center; gap: 7px; font-size: .75rem; color: var(--fg-muted); }

.tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 10px; border-radius: 99px; font-size: .76rem; font-weight: 500;
  background: color-mix(in srgb, var(--tc, var(--accent)) 12%, transparent);
  color: var(--tc, var(--accent));
  border: 1px solid color-mix(in srgb, var(--tc, var(--accent)) 24%, transparent);
  transition: background var(--dur) var(--ease);
}
.tag:hover { text-decoration: none; background: color-mix(in srgb, var(--tc, var(--accent)) 22%, transparent); }
.tag.big { font-size: .92rem; padding: 7px 15px; }
.tag.big b { opacity: .65; font-variant-numeric: tabular-nums; }
.tag-cloud { display: flex; gap: 10px; flex-wrap: wrap; }
.tag-row { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 13px; }

.revs { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-elev); }
.rev { display: flex; gap: 12px; align-items: flex-start; padding: 13px 15px; }
.rev + .rev { border-top: 1px solid var(--border); }
.rev-head { display: flex; align-items: center; gap: 8px; }
.rev-stats { display: flex; gap: 8px; font-size: .75rem; font-family: var(--mono); margin-top: 4px; }
.rev-stats .add { color: var(--green); }
.rev-stats .del { color: var(--red); }
.rev-actions { display: flex; gap: 6px; align-items: center; }
.rev-actions form { margin: 0; }

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin: 22px 0 18px; }
.tab { padding: 9px 15px; border: 0; border-bottom: 2px solid transparent; background: none; color: var(--fg-muted); font: inherit; font-size: .87rem; font-weight: 550; cursor: pointer; transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.tab:hover { color: var(--fg); }
.tab.active { color: var(--accent-text); border-bottom-color: var(--accent); }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

.diff-table { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: .8rem; border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.diff-table td { padding: 1px 8px; vertical-align: top; }
.diff-ln { width: 46px; text-align: right; color: var(--fg-muted); user-select: none; background: var(--bg-alt); border-right: 1px solid var(--border); }
.diff-text { white-space: pre-wrap; word-break: break-word; }
.diff-sign { display: inline-block; width: 14px; color: var(--fg-muted); }
.diff-add { background: color-mix(in srgb, var(--green) 13%, transparent); }
.diff-add .diff-sign { color: var(--green); }
.diff-del { background: color-mix(in srgb, var(--red) 13%, transparent); }
.diff-del .diff-sign { color: var(--red); }
.diff-skip td { background: var(--bg-alt); color: var(--fg-muted); text-align: center; font-style: italic; padding: 5px; }
.src-view { background: var(--bg-alt); border: 1px solid var(--border); border-radius: var(--r-md); padding: 17px; overflow-x: auto; font-family: var(--mono); font-size: .82rem; white-space: pre-wrap; }

/* Вход */
/* 100dvh, а не 100vh: на телефоне адресная строка то есть, то нет, и по
   100vh карточка уезжала под её нижний край. */
.auth-page { display: flex; align-items: center; justify-content: center;
  min-height: 100vh; min-height: 100dvh;
  padding: calc(20px + env(safe-area-inset-top, 0px)) 20px calc(20px + env(safe-area-inset-bottom, 0px));
  background: radial-gradient(700px 380px at 50% 0%, var(--accent-soft), transparent 70%), var(--bg-alt); }
.auth-card { width: 100%; max-width: 384px; padding: 32px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--r-xl); box-shadow: var(--shadow); }
.auth-brand { display: flex; align-items: center; gap: 10px; font-size: 1.3rem; font-weight: 700; margin-bottom: 4px; }
.auth-brand span { font-size: 1.6rem; }
.auth-card form { margin-top: 22px; }
.auth-alt { text-align: center; font-size: .85rem; color: var(--fg-muted); margin: 14px 0 0; }

/* ------------------------------------------------ 9. Документ ------------ */
.doc { padding-top: 22px; }
.crumbs { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; font-size: .79rem; color: var(--fg-muted); margin-bottom: 16px; }
.crumbs a { color: var(--fg-muted); display: inline-flex; align-items: center; gap: 6px; }
.crumbs a:hover { color: var(--accent-text); text-decoration: none; }
.crumbs .cur { color: var(--fg-soft); font-weight: 500; }

.doc-head { border-bottom: 1px solid var(--border); padding-bottom: 18px; margin-bottom: 28px; }
.doc-title-row { display: flex; align-items: flex-start; gap: 16px; }
.doc-head h1 {
  display: flex; align-items: baseline; gap: 12px; flex: 1; min-width: 0;
  font-size: 2.1rem; margin-bottom: .3em; letter-spacing: -.022em;
}
.doc-emoji { font-size: 1.8rem; line-height: 1; }
.doc-actions { display: flex; gap: 7px; flex-wrap: wrap; flex: none; }
.doc-meta { display: flex; gap: 15px; flex-wrap: wrap; font-size: .78rem; color: var(--fg-muted); align-items: center; }
.doc-meta > span, .doc-meta > a { display: inline-flex; align-items: center; gap: 5px; }
.meta-author { gap: 6px !important; }
.meta-link { color: var(--fg-muted); }
.meta-link:hover { color: var(--accent-text); text-decoration: none; }

.toc-mobile { display: none; margin: 0 0 22px; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt); }
.toc-mobile summary { padding: 10px 14px; cursor: pointer; font-weight: 600; font-size: .87rem; display: flex; align-items: center; gap: 8px; }
.toc-mobile nav { padding: 0 14px 12px; display: flex; flex-direction: column; gap: 2px; }
.toc-mobile a { font-size: .84rem; color: var(--fg-soft); padding: 3px 0; }
.toc-mobile a.lvl-3 { padding-left: 14px; }
.toc-mobile a.lvl-4 { padding-left: 28px; }

.subpages, .attachments, .comments { margin-top: 42px; }
.subpages h3, .attachments h3, .comments h3 { display: flex; align-items: center; gap: 9px; font-size: 1rem; color: var(--fg-soft); margin-bottom: 14px; }
.subpages h3 .ico, .attachments h3 .ico, .comments h3 .ico { color: var(--fg-muted); }

.att-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-elev); }
.att-list li { display: flex; align-items: center; gap: 10px; padding: 9px 13px; font-size: .87rem; }
.att-list li + li { border-top: 1px solid var(--border); }
.att-icon { color: var(--fg-muted); display: inline-flex; }
.att-list form { margin: 0; display: flex; }

.pager { display: flex; justify-content: space-between; gap: 14px; margin-top: 50px; }
.pager-item {
  display: flex; align-items: center; gap: 13px; padding: 15px 19px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  color: var(--fg); flex: 1; max-width: 49%; background: var(--bg-elev);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.pager-item:hover { text-decoration: none; border-color: var(--accent-line); background: var(--bg-tint); box-shadow: var(--shadow-sm); }
.pager-item .ico { color: var(--fg-muted); }
.pager-item.next { justify-content: flex-end; text-align: right; margin-left: auto; }
.pager-item small { display: flex; align-items: center; gap: 6px; color: var(--fg-muted); font-size: .71rem; margin-bottom: 2px; }
.pager-item.next small { justify-content: flex-end; }
.pager-item b { font-size: .89rem; }

/* Комментарии */
.comment-form { display: flex; gap: 11px; align-items: flex-start; margin-bottom: 20px; }
.comment-form textarea {
  width: 100%; margin-top: 0; padding: 10px 12px; font-size: .88rem; min-height: 62px;
}
.comment-actions { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.reply-to {
  display: flex; align-items: center; gap: 8px; margin-bottom: 8px;
  padding: 6px 11px; border-radius: var(--r-sm); font-size: .8rem;
  background: var(--accent-soft); color: var(--fg-soft);
  border-left: 2px solid var(--accent);
}
.comment-list { list-style: none; margin: 0; padding: 0; }
.comment-list .comment-list { margin-left: 34px; margin-top: 8px; border-left: 2px solid var(--border); padding-left: 14px; }
.comment { display: flex; gap: 11px; padding: 11px 0; }
.comment.resolved { opacity: .55; }
.c-body { flex: 1; min-width: 0; }
.c-head { display: flex; align-items: center; gap: 9px; font-size: .82rem; flex-wrap: wrap; }
.c-head time { color: var(--fg-muted); font-size: .74rem; }
.c-tools { display: none; gap: 11px; font-size: .76rem; margin-left: auto; }
.comment:hover > .c-body > .c-head > .c-tools,
.c-head:focus-within .c-tools { display: flex; }
.c-text { margin-top: 4px; font-size: .89rem; }
.c-text > :last-child { margin-bottom: 0; }
.comments-empty { padding: 18px 0; }

/* Оглавление */
.toc-aside {
  position: sticky; top: var(--topbar-h); height: calc(100vh - var(--topbar-h));
  overflow-y: auto; padding: 28px 18px; border-left: 1px solid var(--border);
}
.toc-head { font-size: .73rem; text-transform: uppercase; letter-spacing: .08em; color: var(--fg-muted); font-weight: 700; margin-bottom: 11px; }
.toc ul { list-style: none; margin: 0; padding: 0; }
.toc ul ul { padding-left: 12px; }
.toc a {
  display: block; padding: 4px 9px; border-left: 2px solid transparent;
  color: var(--fg-muted); font-size: .81rem; line-height: 1.45;
  overflow: hidden; text-overflow: ellipsis;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.toc a:hover { color: var(--fg); text-decoration: none; border-left-color: var(--border-strong); }
.toc a.active { color: var(--accent-text); border-left-color: var(--accent); background: var(--accent-soft); font-weight: 550; }
.toc-foot { margin-top: 22px; padding-top: 13px; border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: 8px; font-size: .8rem; }
.toc-foot a { color: var(--fg-muted); display: inline-flex; align-items: center; gap: 7px; }
.toc-foot a:hover { color: var(--accent-text); text-decoration: none; }

/* ------------------------------------------------ 10. Редактор ----------- */
body.editor-mode { overflow: hidden; }
body.editor-mode .content { padding-bottom: 0; }

/* Общая шапка сайта в редакторе не нужна: три ряда управления над текстом
   съедали экран. Навигация остаётся в кнопке «Назад» и хлебной крошке. */
body.editor-mode .topbar { display: none; }
body.editor-mode .layout { min-height: 100vh; min-height: 100dvh; }

/* overflow:hidden прячет выехавшую панель свойств и убирает лишнюю прокрутку */
.editor { display: flex; flex-direction: column; height: 100vh; height: 100dvh;
          position: relative; overflow: hidden;
          --ed-zoom: .92; --ed-prose-w: 1040px; }

.ed-topbar { display: flex; align-items: center; gap: 7px; padding: 6px 12px; border-bottom: 1px solid var(--border); background: var(--bg-alt); flex: none; }
.ed-back { flex: none; }
.ed-crumb {
  display: flex; align-items: center; gap: 6px; max-width: 190px; flex: none;
  padding: 4px 8px 4px 5px; border-radius: var(--r-sm);
  font-size: .8rem; color: var(--fg-muted); white-space: nowrap;
}
.ed-crumb:hover { background: var(--bg-hover); color: var(--fg-soft); text-decoration: none; }
.ed-title {
  flex: 1; min-width: 0; margin: 0 !important; border: 1px solid transparent !important;
  background: none !important; font-size: 1.06rem !important; font-weight: 650;
  padding: 4px 8px !important; letter-spacing: -.015em;
}
.ed-title:hover { border-color: var(--border) !important; background: var(--bg) !important; }
.ed-title:focus { border-color: var(--accent) !important; background: var(--bg) !important; }
.ed-top-actions { display: flex; align-items: center; gap: 5px; flex: none; }
.ed-status { min-width: 118px; text-align: right; font-size: .76rem; color: var(--fg-muted); white-space: nowrap; }
.ed-status.dirty { color: var(--amber); }
.ed-status.ok { color: var(--green); }
.ed-status.err { color: var(--red); }
.icon-btn.on { background: var(--accent-soft); color: var(--accent-text); }

/* --- панель инструментов --- */
/* Панель переносится на вторую строку, а не прокручивается:
   иначе выпадающие меню обрезались бы контейнером со скроллом. */
.ed-toolbar {
  display: flex; align-items: center; gap: 2px; padding: 4px 10px;
  border-bottom: 1px solid var(--border); flex: none; flex-wrap: wrap;
  background: var(--bg); row-gap: 3px;
}
.tb {
  display: inline-flex; align-items: center; justify-content: center; gap: 3px;
  min-width: 29px; height: 29px; padding: 0 7px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--fg-soft); cursor: pointer; font: inherit; font-size: .8rem;
  flex: none; transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.tb:hover { background: var(--bg-hover); color: var(--fg); }
.tb.on { background: var(--accent-soft); color: var(--accent-text); }
.tb:disabled { opacity: .35; cursor: default; }
.tb:disabled:hover { background: none; color: var(--fg-soft); }
.tb.wide { min-width: 112px; justify-content: space-between; padding: 0 8px; font-size: .82rem; }
.tb.wide.up { min-width: 0; gap: 6px; justify-content: flex-start; }
.tb.zoomed { min-width: 62px; gap: 3px; font-size: .78rem; font-variant-numeric: tabular-nums; color: var(--fg-muted); }
.tb.zoomed:hover { color: var(--fg); }

/* меню шрифтов: каждый пункт написан своим начертанием — видно до выбора */
.tb.wide.font { min-width: 128px; max-width: 168px; }
.tb.wide.font .ellipsis { max-width: 128px; }
.tb-font .dropdown-menu { min-width: 244px; max-height: 62vh; overflow-y: auto; }
.tb-font .dropdown-menu button { gap: 10px; padding-top: 6px; padding-bottom: 6px; }
.fm-name { font-size: .95rem; line-height: 1.3; }
.fm-sample { margin-left: auto; color: var(--fg-muted); font-size: .82rem; }

/* пункты меню загрузки: подпись + список форматов */
.tb-upload .dropdown-menu { min-width: 264px; }
.tb-upload .dropdown-menu button { align-items: flex-start; padding-top: 8px; padding-bottom: 8px; }
.pick-t { display: flex; flex-direction: column; gap: 1px; text-align: left; }
.pick-t small { color: var(--fg-muted); font-size: .72rem; font-weight: 400; }
.dd-note { margin: 4px 10px 6px; font-size: .74rem; color: var(--fg-muted); line-height: 1.45; }
.ed-toolbar .sep { width: 1px; height: 19px; background: var(--border); margin: 0 5px; flex: none; }
.ed-toolbar .dropdown-menu button { justify-content: flex-start; height: auto; min-width: 0; }
.ed-toolbar .dropdown-menu button.on { background: var(--accent-soft); color: var(--accent-text); }
.ed-toolbar .dropdown-menu kbd { margin-left: auto; font-size: .71rem; }
.ed-counter { font-size: .76rem; color: var(--fg-muted); white-space: nowrap; padding-left: 10px; }
.mirror { transform: scaleX(-1); }

.bt-h1 { font-size: 1.15rem; font-weight: 700; }
.bt-h2 { font-size: 1.05rem; font-weight: 650; }
.bt-h3 { font-size: .95rem; font-weight: 650; }
.bt-h4 { font-size: .88rem; font-weight: 650; }

/* --- рабочая область --- */
.ed-main { flex: 1; display: flex; min-height: 0; }

.ed-outline {
  width: 216px; flex: none; border-right: 1px solid var(--border);
  background: var(--bg-alt); overflow-y: auto; padding: 14px 10px; display: none;
}
.editor.outline-open .ed-outline { display: block; }
.ed-outline-head { font-size: .72rem; text-transform: uppercase; letter-spacing: .08em; color: var(--fg-muted); font-weight: 700; margin-bottom: 9px; padding: 0 6px; }
.ed-outline nav { display: flex; flex-direction: column; gap: 1px; }
.ed-outline a {
  padding: 4px 8px; border-radius: var(--r-xs); color: var(--fg-soft);
  font-size: .81rem; cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ed-outline a:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }
.ed-outline a.lvl-2 { padding-left: 18px; }
.ed-outline a.lvl-3 { padding-left: 30px; font-size: .78rem; }
.ed-outline a.lvl-4 { padding-left: 42px; font-size: .78rem; color: var(--fg-muted); }
.ed-outline .empty { padding: 8px; color: var(--fg-muted); font-size: .8rem; }

.ed-canvas { flex: 1; min-width: 0; overflow-y: auto; position: relative; }
/* Составной селектор обязателен: правила .markdown-body объявлены ниже
   по файлу и с одиночным классом перебивали бы и ширину, и масштаб. */
.ed-doc.markdown-body {
  max-width: var(--ed-prose-w, 1040px); margin: 0 auto; padding: 26px 32px 45vh;
  outline: none; min-height: 100%; caret-color: var(--accent);
  font-size: calc(16px * var(--ed-zoom, 1));
}
/* Заголовки и таблицы в редакторе меряем в em, иначе масштаб бы их не трогал. */
.ed-doc.markdown-body h1 { font-size: 1.75em; }
.ed-doc.markdown-body h2 { font-size: 1.38em; }
.ed-doc.markdown-body h3 { font-size: 1.14em; }
.ed-doc.markdown-body h4 { font-size: 1em; }
.ed-doc.markdown-body table { font-size: .92em; }
.ed-doc.markdown-body .admonition-title { font-size: .8em; }
.ed-doc.markdown-body .footnote { font-size: .88em; }
.editor[data-width="full"] .ed-doc { padding-left: 44px; padding-right: 44px; }
.ed-doc:focus { outline: none; }
.ed-hint {
  position: absolute; top: 30px; left: 50%; transform: translateX(-50%);
  color: var(--fg-muted); font-size: .87rem; pointer-events: none; white-space: nowrap;
}
.ed-doc.kb-drop { outline: 2px dashed var(--accent); outline-offset: -14px; border-radius: var(--r-md); }

/* пустой абзац подсказывает, что можно писать */
.ed-doc > p:only-child:empty::before,
.ed-doc > p:only-child > br:only-child::before { content: ''; }

/* --- режим разметки --- */
.ed-rawpane { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.ed-rawpane[hidden], .ed-canvas[hidden] { display: none; }   /* иначе класс перебивает hidden */
.ed-rawhead {
  display: flex; align-items: baseline; gap: 10px; padding: 9px 16px;
  border-bottom: 1px solid var(--border); background: var(--bg-alt); flex: none;
}
.ed-rawpane textarea {
  flex: 1; margin: 0 !important; border: 0 !important; border-radius: 0 !important;
  padding: 24px 28px !important; resize: none; outline: none; box-shadow: none !important;
  font-family: var(--mono) !important; font-size: var(--ed-fs, 15px) !important;
  line-height: 1.75; background: var(--bg) !important; tab-size: 2;
}

/* --- элементы документа в редакторе --- */
.ed-doc [contenteditable="false"] { user-select: none; }

.ed-doc h1, .ed-doc h2, .ed-doc h3, .ed-doc h4 { scroll-margin-top: 90px; }
.ed-doc > *:first-child { margin-top: 0; }

.ed-doc pre {
  white-space: pre-wrap; word-break: break-word; position: relative;
  padding-top: 26px;
}
.ed-doc pre::before {
  content: attr(data-lang); position: absolute; top: 5px; left: 12px;
  font-family: var(--font); font-size: .72rem; text-transform: uppercase;
  letter-spacing: .07em; color: var(--fg-muted); font-weight: 700;
}
.ed-doc pre[data-lang=""]::before { content: 'код'; }

.ed-doc table { display: table; width: 100%; }
.ed-doc td, .ed-doc th { min-width: 60px; }
.ed-doc td[data-align="center"], .ed-doc th[data-align="center"] { text-align: center; }
.ed-doc td[data-align="right"], .ed-doc th[data-align="right"] { text-align: right; }

/* чек-листы */
.ed-doc ul.kb-tasks, .ed-doc ul.kb-tasks ul { list-style: none; padding-left: 1.5em; }
.ed-doc li.kb-task { position: relative; }
.kb-check {
  position: absolute; left: -1.45em; top: .32em;
  width: 16px; height: 16px; border: 1.5px solid var(--border-strong);
  border-radius: 5px; cursor: pointer; display: inline-block; background: var(--bg);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.kb-check:hover { border-color: var(--accent); }
li[data-checked="true"] > .kb-check { background: var(--accent); border-color: var(--accent); }
li[data-checked="true"] > .kb-check::after {
  content: ''; position: absolute; left: 4.5px; top: 1px;
  width: 4px; height: 9px; border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(42deg);
}
li[data-checked="true"] > .kb-li-body { color: var(--fg-muted); text-decoration: line-through; }
.kb-li-body { display: inline; }

/* callout-блоки */
.ed-doc .kb-callout {
  display: flex; gap: 12px; margin: 0 0 1.35em; padding: 14px 16px;
  border-radius: var(--r-md); border: 1px solid color-mix(in srgb, var(--kb-c, var(--blue)) 26%, var(--border));
  border-left: 3px solid var(--kb-c, var(--blue));
  background: color-mix(in srgb, var(--kb-c, var(--blue)) 6%, transparent);
}
.ed-doc .kb-callout[data-kind="note"] { --kb-c: var(--blue); }
.ed-doc .kb-callout[data-kind="tip"] { --kb-c: var(--green); }
.ed-doc .kb-callout[data-kind="important"] { --kb-c: var(--accent); }
.ed-doc .kb-callout[data-kind="warning"] { --kb-c: var(--amber); }
.ed-doc .kb-callout[data-kind="danger"] { --kb-c: var(--red); }
.kb-callout-mark {
  flex: none; font-size: 16px; line-height: 1.5; cursor: pointer;
  border-radius: var(--r-xs); padding: 0 2px;
}
.kb-callout-mark:hover { background: color-mix(in srgb, var(--kb-c) 18%, transparent); }
.kb-callout-body { flex: 1; min-width: 0; }
.kb-callout-body > :last-child { margin-bottom: 0; }

/* сырые блоки */
.kb-raw {
  position: relative; margin: 0 0 1.3em; border: 1px dashed var(--border-strong);
  border-radius: var(--r-md); background: var(--bg-alt); padding: 22px 14px 12px;
}
.kb-raw-tag {
  position: absolute; top: 5px; left: 12px; font-size: .71rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--fg-muted);
}
.kb-raw pre {
  background: none !important; border: 0 !important; padding: 0 !important; margin: 0 !important;
  font-size: .82rem; white-space: pre-wrap; outline: none;
}
.kb-raw pre:focus { outline: none; }

/* сноски и вики-ссылки */
.kb-fn {
  background: var(--accent-soft); color: var(--accent-text); border-radius: 4px;
  padding: 0 4px; font-size: .7em; cursor: default;
}
.kb-fndef {
  display: flex; gap: 8px; font-size: .88rem; color: var(--fg-soft);
  padding: 6px 0; border-top: 1px dashed var(--border);
}
.kb-fn-label { color: var(--accent-text); font-family: var(--mono); font-size: .82rem; flex: none; }
.kb-fn-body { flex: 1; }
.ed-doc a.kb-wiki { border-bottom-style: dashed; }

/* --- плавающая панель над выделением --- */
.kb-bubble {
  position: fixed; z-index: 150; display: flex; align-items: center; gap: 1px;
  padding: 4px; background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  animation: pop 120ms var(--ease);
}
.kb-bubble .sep { width: 1px; height: 18px; background: var(--border); margin: 0 4px; }
.kb-bubble[hidden] { display: none; }

/* --- меню вставки по «/» --- */
.kb-slash {
  position: fixed; z-index: 150; width: 268px; max-height: 320px; overflow-y: auto;
  padding: 5px; background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  animation: pop 120ms var(--ease);
}
.kb-slash[hidden] { display: none; }
.kb-slash-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 7px 9px; border: 0; border-radius: var(--r-sm);
  background: none; color: var(--fg); font: inherit; font-size: .87rem;
  cursor: pointer; text-align: left;
}
.kb-slash-item:hover, .kb-slash-item.sel { background: var(--bg-hover); }
.kb-slash-item.sel { box-shadow: inset 0 0 0 1px var(--accent-line); }
.si-icon {
  width: 26px; height: 26px; flex: none; border-radius: var(--r-xs);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-sunken); color: var(--fg-soft); font-size: 12px; font-weight: 700;
}

/* --- окно ссылки: адрес и страница базы рядом, в одном месте --- */
.lm-back {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(10, 14, 20, .5); backdrop-filter: blur(3px);
  display: flex; align-items: flex-start; justify-content: center; padding: 10vh 16px 16px;
  animation: fade-in 130ms var(--ease);
}
.lm-back[hidden] { display: none; }
.lm-win {
  width: min(520px, 100%); max-height: 80vh; display: flex; flex-direction: column;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  animation: pop 150ms var(--ease);
}
.lm-grow { flex: 1; }
.lm-head {
  display: flex; align-items: center; gap: 8px; flex: none;
  padding: 11px 12px 11px 16px; border-bottom: 1px solid var(--border);
}
.lm-head b { font-size: .95rem; }
.lm-body { padding: 14px 16px; overflow-y: auto; }
.lm-field { margin-bottom: 12px; }
.lm-label {
  display: block; margin-bottom: 5px;
  font-size: .74rem; font-weight: 650; color: var(--fg-soft);
}
.lm-field input { margin: 0; font-size: .88rem; }
.lm-or {
  display: flex; align-items: center; gap: 10px; margin: 14px 0 12px;
  font-size: .74rem; color: var(--fg-muted); text-transform: lowercase;
}
.lm-or::before, .lm-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.lm-search { position: relative; display: flex; align-items: center; }
.lm-search .ico { position: absolute; left: 9px; color: var(--fg-muted); pointer-events: none; }
.lm-search input { padding-left: 30px; }
.lm-list { display: flex; flex-direction: column; gap: 1px; max-height: 208px; overflow-y: auto; }
.lm-list:not(:empty) { margin-top: 7px; }
.lm-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 9px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; color: var(--fg); font: inherit; font-size: .85rem;
  cursor: pointer; text-align: left;
}
.lm-item:hover, .lm-item.sel { background: var(--bg-hover); }
.lm-item.sel { border-color: var(--accent-line); }
.lm-item.picked { background: var(--accent-soft); color: var(--accent-text); }
.lm-iicon { flex: none; width: 18px; text-align: center; }
.lm-ititle { flex: 1; min-width: 0; }
.lm-ipath { flex: none; max-width: 40%; color: var(--fg-muted); font-size: .74rem; }
.lm-empty { padding: 8px 9px; color: var(--fg-muted); font-size: .82rem; }
.lm-target {
  display: flex; align-items: center; gap: 8px; margin: 12px 0 10px;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-alt); font-size: .82rem; min-height: 36px;
}
.lm-target.empty { color: var(--fg-muted); }
.lm-tlabel { flex: none; color: var(--fg-muted); font-size: .74rem; }
.lm-tvalue { min-width: 0; font-weight: 600; }
.lm-tdrop {
  margin-left: auto; flex: none; border: 0; background: none; padding: 0;
  color: var(--fg-muted); font: inherit; font-size: .74rem; cursor: pointer;
  text-decoration: underline;
}
.lm-tdrop:hover { color: var(--danger); }
.lm-check { display: flex; align-items: center; gap: 8px; margin: 0; font-size: .84rem; cursor: pointer; }
.lm-check input { width: 15px; height: 15px; margin: 0; }

/* Подпись над списком недавних страниц: объясняет, что это не результат
   поиска, а «вот что есть» — иначе список выглядит как случайная выдача. */
.lm-listhead {
  padding: 7px 9px 5px; font-size: .74rem; color: var(--fg-muted);
  border-bottom: 1px solid var(--border); margin-bottom: 3px;
}

/* Выбор цвета кнопки */
.lm-colors { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lm-colors[hidden] { display: none; }
.lm-swatches { display: flex; gap: 6px; flex-wrap: wrap; }
.lm-swatch {
  width: 22px; height: 22px; padding: 0; cursor: pointer;
  border: 2px solid transparent; border-radius: 50%;
  box-shadow: 0 0 0 1px var(--border) inset;
  transition: transform var(--dur-fast) var(--ease-spring),
              border-color var(--dur-fast) var(--ease);
}
.lm-swatch:hover { transform: scale(1.12); }
.lm-swatch.on { border-color: var(--fg); }
.lm-swatch.accent { background: linear-gradient(135deg, var(--accent), var(--accent-2)); }
.lm-swatch.ghost  { background: var(--bg-alt); box-shadow: 0 0 0 1px var(--accent-line) inset; }
.lm-swatch.green  { background: linear-gradient(135deg, #1f9d5b, #34c77b); }
.lm-swatch.amber  { background: linear-gradient(135deg, #b8760a, #e0a021); }
.lm-swatch.red    { background: linear-gradient(135deg, #c33c3c, #e8635f); }
.lm-swatch.blue   { background: linear-gradient(135deg, #2563c9, #4b90ec); }
.lm-swatch.violet { background: linear-gradient(135deg, #6d3ec9, #9566ee); }

/* Значок в начале кнопки: эмодзи из набора или своя картинка */
.lm-icons { display: flex; flex-direction: column; gap: 8px; }
.lm-icons[hidden] { display: none; }
.lm-icon-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.lm-icon-preview {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; font-size: 20px; line-height: 1;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-alt);
}
.lm-icon-preview.empty { color: var(--fg-muted); font-size: 14px; }
.lm-icon-preview img { width: 24px; height: 24px; border-radius: 5px; object-fit: cover; }
.lm-emoji { display: flex; gap: 4px; flex-wrap: wrap; flex: 1 1 200px; }
.lm-emoji-btn {
  width: 28px; height: 28px; padding: 0; font-size: 16px; line-height: 1;
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.lm-emoji-btn:hover { background: var(--bg-hover); }
.lm-emoji-btn.on { border-color: var(--accent); background: var(--accent-soft); }
.lm-icon-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lm-icon-actions small { flex: 1 1 160px; font-size: .73rem; }

.lm-foot {
  display: flex; align-items: center; gap: 7px; flex: none; flex-wrap: wrap;
  padding: 11px 16px; border-top: 1px solid var(--border); background: var(--bg-alt);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}

/* --- режим без отвлечений --- */
body.zen .topbar { display: none; }
body.zen .editor { height: 100vh; height: 100dvh; }
body.zen .ed-toolbar { opacity: .25; transition: opacity var(--dur) var(--ease); }
body.zen .ed-toolbar:hover { opacity: 1; }
body.zen .ed-outline { display: none !important; }

/* --- боковая панель свойств --- */
.ed-settings {
  position: absolute; top: 0; right: 0; bottom: 0; width: 348px; z-index: 30;
  padding: 16px 18px; background: var(--bg-elev); border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg); overflow: hidden;
  transform: translateX(102%); transition: transform 200ms var(--ease);
}
.editor.settings-open .ed-settings { transform: none; }
.ed-settings-head {
  display: flex; align-items: center; justify-content: space-between; flex: none;
  padding-bottom: 12px; margin-bottom: 4px; border-bottom: 1px solid var(--border);
}
.ed-settings-body { flex: 1; min-height: 0; overflow-y: auto; margin: 0 -4px; padding: 0 4px 4px; }
.ed-settings-foot { margin-top: 6px; padding-top: 15px; border-top: 1px solid var(--border); }

.emoji-picker { display: flex; flex-wrap: wrap; gap: 3px; margin: -8px 0 16px; }
.emoji-picker button {
  width: 30px; height: 30px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; cursor: pointer; font-size: 15px; line-height: 1;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.emoji-picker button:hover { background: var(--bg-hover); border-color: var(--border); }

/* ------------------------------------------------ 11. Markdown ----------- */
/* Текст страниц набирается своей гарнитурой (--font-content) и своим кеглем:
   интерфейс и документ читают по-разному, и одна настройка на двоих всегда
   оказывалась компромиссом — либо мелкие подписи, либо огромные кнопки. */
.markdown-body {
  font-family: var(--font-content);
  font-size: 1.03rem; line-height: 1.72; color: var(--fg);
  word-wrap: break-word; max-width: var(--prose-w);
  text-wrap: pretty;
}
.markdown-body > *:first-child { margin-top: 0; }
.markdown-body > *:last-child { margin-bottom: 0; }

.markdown-body h1, .markdown-body h2, .markdown-body h3,
.markdown-body h4, .markdown-body h5, .markdown-body h6 {
  margin: 1.9em 0 .65em; scroll-margin-top: calc(var(--topbar-h) + 20px);
  position: relative; letter-spacing: -.018em;
}
.markdown-body h1 { font-size: 1.75rem; }
.markdown-body h2 { font-size: 1.38rem; padding-bottom: .32em; border-bottom: 1px solid var(--border); }
.markdown-body h3 { font-size: 1.14rem; }
.markdown-body h4 { font-size: 1rem; }

.markdown-body .headerlink {
  position: absolute; left: -.8em; opacity: 0; color: var(--fg-muted);
  text-decoration: none; font-weight: 400; border: 0;
  transition: opacity var(--dur) var(--ease);
}
.markdown-body h1:hover .headerlink, .markdown-body h2:hover .headerlink,
.markdown-body h3:hover .headerlink, .markdown-body h4:hover .headerlink { opacity: 1; }
.markdown-body .headerlink:hover { color: var(--accent-text); }

.markdown-body p { margin: 0 0 1.15em; }
.markdown-body ul, .markdown-body ol { margin: 0 0 1.15em; padding-left: 1.6em; }
.markdown-body li { margin: .35em 0; }
.markdown-body li > ul, .markdown-body li > ol { margin: .35em 0; }
.markdown-body li::marker { color: var(--fg-muted); }
.markdown-body li.task-item { list-style: none; margin-left: -1.45em; }
.markdown-body li.task-item input { margin-right: .55em; accent-color: var(--accent); }

.markdown-body blockquote {
  margin: 0 0 1.25em; padding: .35em 1.15em;
  border-left: 3px solid var(--border-strong); color: var(--fg-soft);
}
.markdown-body blockquote > :last-child { margin-bottom: 0; }
.markdown-body hr { border: 0; border-top: 1px solid var(--border); margin: 2.2em 0; }

.markdown-body code {
  font-family: var(--mono); font-size: .86em;
  background: var(--bg-sunken); padding: .16em .42em; border-radius: var(--r-xs);
  border: 1px solid var(--border); word-break: break-word;
}
.markdown-body pre {
  position: relative; margin: 0 0 1.25em; padding: 15px 17px; overflow-x: auto;
  background: var(--bg-sunken); border: 1px solid var(--border);
  border-radius: var(--r-md); line-height: 1.6;
}
.markdown-body pre code { background: none; border: 0; padding: 0; font-size: .85em; }
.code-copy {
  position: absolute; top: 8px; right: 8px; opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.markdown-body pre:hover .code-copy, .code-copy:focus-visible { opacity: 1; }

.markdown-body table {
  border-collapse: collapse; margin: 0 0 1.35em; font-size: .92rem;
  display: block; overflow-x: auto; max-width: 100%;
}
.markdown-body th, .markdown-body td { padding: 9px 14px; border: 1px solid var(--border); }
.markdown-body th { background: var(--bg-alt); font-weight: 650; text-align: left; }
.markdown-body tbody tr:nth-child(even) { background: color-mix(in srgb, var(--bg-alt) 50%, transparent); }

.markdown-body img { max-width: 100%; height: auto; border-radius: var(--r-md); }
.markdown-body a { text-decoration: none; border-bottom: 1px solid var(--accent-line); }
.markdown-body a:hover { border-bottom-color: var(--accent); }
.markdown-body .wikilink.missing { color: var(--red); border-bottom-style: dashed; border-bottom-color: color-mix(in srgb, var(--red) 45%, transparent); }

/* Погашенная ссылка на публичной странице: текст автора остаётся на месте,
   но никуда не ведёт — снаружи по базе знаний не ходят. Подчёркивание
   точками, чтобы было видно: здесь была ссылка, просто она недоступна. */
.markdown-body .link-off {
  color: var(--fg); border-bottom: 1px dotted var(--border-strong, var(--border));
  cursor: default;
}

.markdown-body details {
  margin: 0 0 1.25em; padding: 11px 15px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
}
.markdown-body summary { cursor: pointer; font-weight: 600; }
.markdown-body details[open] summary { margin-bottom: .7em; }
.markdown-body sup { font-size: .74em; }
.markdown-body .footnote { font-size: .88rem; color: var(--fg-soft); border-top: 1px solid var(--border); margin-top: 2.6em; padding-top: 1em; }
.markdown-body kbd { font-size: .8em; }

.markdown-body .admonition {
  margin: 0 0 1.35em; padding: 14px 17px;
  border-radius: var(--r-md); border: 1px solid color-mix(in srgb, var(--kb-c, var(--blue)) 26%, var(--border));
  border-left: 3px solid var(--kb-c, var(--blue));
  background: color-mix(in srgb, var(--kb-c, var(--blue)) 6%, transparent);
}
.markdown-body .admonition > :last-child { margin-bottom: 0; }
.markdown-body .admonition-title {
  font-weight: 700; font-size: .8rem; text-transform: uppercase;
  letter-spacing: .05em; color: var(--kb-c, var(--blue)); margin: 0 0 .55em;
}
.markdown-body .admonition.note { --kb-c: var(--blue); }
.markdown-body .admonition.tip { --kb-c: var(--green); }
.markdown-body .admonition.important { --kb-c: var(--accent); }
.markdown-body .admonition.warning { --kb-c: var(--amber); }
.markdown-body .admonition.danger { --kb-c: var(--red); }

.mermaid-wrap {
  margin: 0 0 1.35em; padding: 16px; background: var(--bg-alt);
  border: 1px solid var(--border); border-radius: var(--r-md);
  overflow-x: auto; text-align: center;
}
.mermaid-wrap pre.mermaid { background: none; border: 0; padding: 0; margin: 0; font-family: var(--mono); font-size: .82rem; text-align: left; }
.mermaid-wrap pre.mermaid[data-processed] { text-align: center; }

/* ------------------------------------------------ 12. Адаптив и печать ---
   Три ступени: 1240 — прячется правое оглавление, 1000 — планшет (сетки
   в одну-две колонки), 820 — телефон.

   Телефон — не «та же страница, только уже». Разница в том, чем по ней
   попадают. Управление собиралось в правом верхнем углу — там, куда большой
   палец не дотягивается; выпадающее меню шириной 214 px со строками по 30 px
   требовало прицеливаться; окна открывались от верха экрана и наполовину
   уезжали под клавиатуру. Поэтому на узком экране:

     · главные действия переезжают в нижнюю полосу (.mobnav);
     · дерево страниц становится шторкой во весь экран, с закрытием свайпом;
     · выпадающие меню и окна приезжают снизу, крупными строками;
     · панель редактора прилипает к верху клавиатуры;
     · всё, что показывалось по наведению, показывается сразу — на тач-экране
       наведения не существует.

   Отступы под «чёлку» и полосу жестов берутся из env(safe-area-inset-*):
   в шапке страницы стоит viewport-fit=cover, иначе нижняя полоса легла бы
   под системную полосу и не нажималась.
   ========================================================================= */
.only-mobile { display: none !important; }
.mobnav, .drawer-head, .sheet-backdrop { display: none; }

@media (max-width: 1240px) {
  .layout.has-aside { grid-template-columns: var(--sidebar-w) minmax(0, 1fr); }
  .toc-aside { display: none; }
  .toc-mobile { display: block; }
}

@media (max-width: 1000px) {
  .two-col { grid-template-columns: 1fr; }
  .grid-3, .grid-5 { grid-template-columns: 1fr 1fr; }
  .hero-stats { margin-left: 0; }
  .page-wrap { padding-left: 30px; padding-right: 30px; }
  .site-footer, .toasts { padding-left: 30px; padding-right: 30px; }
  .ed-outline { display: none !important; }
}

/* Телефонная ступень (820 px) и правила для пальца вынесены в самый конец
   файла — см. раздел 31. Иначе они проигрывали бы разделам, объявленным ниже
   по файлу: у `.tree-add` и `.av-head` та же специфичность, а при равной
   специфичности побеждает то правило, которое стоит позже. */

@media print {
  .topbar, .sidebar, .toc-aside, .toc-mobile, .doc-actions, .pager,
  .comments, .toasts, .site-footer, .fab-top, .read-progress, .code-copy,
  .crumbs, .tree-add, .mobnav, .sheet-backdrop { display: none !important; }
  .content { padding-bottom: 0 !important; }
  .layout, .layout.has-aside { grid-template-columns: 1fr !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .page-wrap { max-width: none; padding: 0; }
  .markdown-body { max-width: none; font-size: 11pt; }
  .markdown-body pre, .markdown-body table, .markdown-body .admonition,
  .markdown-body blockquote, .mermaid-wrap { break-inside: avoid; }
  .markdown-body h1, .markdown-body h2, .markdown-body h3 { break-after: avoid; }
  .markdown-body a { border: 0; color: #000; }
  .markdown-body a[href^="http"]::after { content: " (" attr(href) ")"; font-size: .8em; color: #555; }
}


/* ------------------------------------------------ 13. Подсказки ---------- */
.kb-tip {
  position: fixed; z-index: 400; max-width: 280px; pointer-events: none;
  padding: 6px 10px; border-radius: var(--r-sm);
  background: var(--fg); color: var(--bg);
  font-size: .76rem; font-weight: 500; line-height: 1.4; white-space: normal;
  box-shadow: var(--shadow); opacity: 0; transform: translateY(3px);
  transition: opacity 110ms var(--ease), transform 110ms var(--ease);
}
.kb-tip.below { transform: translateY(-3px); }
.kb-tip.on { opacity: 1; transform: none; }
html[data-theme="dark"] .kb-tip { background: #eef1f6; color: #10141b; }

/* ------------------------------------------------ 14. Медиа в редакторе -- */
.kb-media { padding: 22px 12px 12px; text-align: center; }
.kb-media video { max-width: 100%; max-height: 420px; border-radius: var(--r-sm); background: #000; }
.kb-media audio { width: 100%; }

/* ------------------------------------------------ 15. Вложения ----------- */
.attachments h3 .att-viewall { margin-left: auto; }

.att-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
}
.att-card {
  margin: 0; display: flex; flex-direction: column; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev); transition: border-color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.att-card.can-open { cursor: zoom-in; }
.att-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.att-card.can-open:hover { border-color: var(--accent-line); box-shadow: var(--shadow); }

.att-thumb {
  position: relative; height: 118px; display: flex; align-items: center;
  justify-content: center; background: var(--bg-sunken); overflow: hidden;
}
.att-thumb img, .att-thumb video { width: 100%; height: 100%; object-fit: cover; display: block; }
.att-card.video .att-thumb { background: #0b0d12; }
.att-play {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: #fff; text-shadow: 0 2px 10px rgba(0, 0, 0, .6);
  background: linear-gradient(transparent, rgba(0, 0, 0, .35));
}
.att-glyph { display: flex; flex-direction: column; align-items: center; gap: 6px; color: var(--fg-muted); }
.att-glyph b { font-size: .72rem; letter-spacing: .07em; }
.att-card.pdf .att-glyph { color: var(--red); }
.att-card.sheet .att-glyph { color: var(--green); }
.att-card.slides .att-glyph { color: var(--amber); }
.att-card.doc .att-glyph { color: var(--blue); }

.att-card figcaption { padding: 8px 10px 9px; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.att-name { font-size: .81rem; font-weight: 550; }
.att-meta { display: flex; align-items: center; gap: 4px; font-size: .74rem; }
.att-meta .muted { margin-right: auto; }
.att-meta form { margin: 0; display: flex; }

/* Курсор говорит, что картинка откроется в просмотрщике. В редакторе тот же
   .markdown-body правится текстом, поэтому там курсор остаётся обычным. */
.markdown-body img, .c-text img { cursor: zoom-in; }
.markdown-body a img, .c-text a img,
.ed-doc img, [contenteditable="true"] img { cursor: inherit; }
.markdown-body a.kb-file img { cursor: pointer; }

/* просмотрщик */
.modal-backdrop.viewer { align-items: center; padding: 3vh 3vw; }
.modal-backdrop.viewer .att-viewer {
  position: relative; display: flex; flex-direction: column;
  width: min(1180px, 94vw); height: min(88vh, 940px);
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg); overflow: hidden;
  animation: pop 150ms var(--ease);
}
.av-head {
  display: flex; align-items: center; gap: 9px; flex: none;
  padding: 9px 12px; border-bottom: 1px solid var(--border); background: var(--bg-alt);
}
.av-title { font-weight: 600; font-size: .88rem; max-width: 46%; }
.av-stage {
  flex: 1; min-height: 0; display: flex; align-items: center; justify-content: center;
  padding: 16px; background: var(--bg-sunken);
}
.av-media { max-width: 100%; max-height: 100%; }
.av-stage img { object-fit: contain; border-radius: var(--r-sm); }
.av-stage video { background: #000; border-radius: var(--r-sm); }
.av-stage iframe { width: 100%; height: 100%; border: 0; border-radius: var(--r-sm); background: var(--bg); }
.av-stage audio { width: min(560px, 100%); }
.av-nopreview { text-align: center; display: flex; flex-direction: column; gap: 14px; color: var(--fg-muted); }

.av-nav {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 38px; height: 54px; display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--r-md); cursor: pointer;
  background: color-mix(in srgb, var(--bg-elev) 88%, transparent);
  color: var(--fg-soft); box-shadow: var(--shadow-sm);
}
.av-nav:hover { color: var(--fg); background: var(--bg-elev); }
.av-nav.prev { left: 12px; }
.av-nav.next { right: 12px; }

.av-strip {
  flex: none; display: flex; gap: 6px; padding: 8px 12px; overflow-x: auto;
  border-top: 1px solid var(--border); background: var(--bg-alt);
}
.av-thumb {
  flex: none; width: 54px; height: 40px; padding: 0; cursor: pointer; overflow: hidden;
  border: 2px solid transparent; border-radius: var(--r-sm); background: var(--bg-sunken);
  color: var(--fg-muted); font-size: .7rem; display: flex; align-items: center; justify-content: center;
}
.av-thumb img { width: 100%; height: 100%; object-fit: cover; }
.av-thumb.sel { border-color: var(--accent); }

/* панель вложений в свойствах страницы */
.ed-att { margin: 4px 0 18px; }
.ed-att-head { font-size: .8rem; font-weight: 650; color: var(--fg-soft); margin-bottom: 8px; }
.ed-att-list { list-style: none; margin: 0; padding: 0; border: 1px solid var(--border); border-radius: var(--r-sm); }
.ed-att-list li { display: flex; align-items: center; gap: 8px; padding: 6px 8px; font-size: .8rem; }
.ed-att-list li + li { border-top: 1px solid var(--border); }
.att-kind { display: inline-flex; color: var(--fg-muted); flex: none; }
.att-kind.image { color: var(--blue); }
.att-kind.video, .att-kind.audio { color: var(--accent-text); }
.att-kind.pdf { color: var(--red); }

/* ------------------------------------------------ 16. Перекрёстные ссылки  */
.xrefs { margin-top: 42px; }
.xrefs h3 { display: flex; align-items: center; gap: 9px; font-size: 1rem; color: var(--fg-soft); margin-bottom: 14px; }
.xref-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.xref-col {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev); padding: 12px 13px;
}
.xref-head {
  display: flex; align-items: center; gap: 7px; margin-bottom: 8px;
  font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--fg-muted);
}
.xref-head .count { margin-left: auto; }
.xref-head.warn { color: var(--amber); margin-top: 12px; padding-top: 11px; border-top: 1px dashed var(--border); }
.xref-list { list-style: none; margin: 0; padding: 0; }
.xref-list a {
  display: flex; align-items: center; gap: 8px; padding: 6px 7px;
  border-radius: var(--r-sm); color: var(--fg-soft); font-size: .85rem;
}
.xref-list a:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }
.xref-list a.broken { color: var(--fg-muted); }
.xref-list a.broken:hover { color: var(--amber); }
.xref-empty { margin: 0; line-height: 1.55; }
.xref-empty code { font-family: var(--mono); font-size: .92em; background: var(--bg-sunken); padding: 1px 5px; border-radius: var(--r-xs); }

@media (max-width: 900px) {
  .xref-cols { grid-template-columns: 1fr; }
}
@media (max-width: 700px) {
  .att-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
  .modal-backdrop.viewer .att-viewer { width: 100vw; height: 100dvh; border-radius: 0; }
  .av-title { max-width: 40%; }
}


/* ------------------------------------------------ 17. Выбор файла -------- */
/* Системное «Выбрать файлы / Файл не выбран» выпадало из оформления —
   прячем его и рисуем свою зону в стиле остальных форм.                  */
.file-drop { position: relative; margin: 6px 0 15px; }
.file-drop input[type=file] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; padding: 0; border: 0; opacity: 0; cursor: pointer;
}
.file-drop-face {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 26px 20px; text-align: center; cursor: pointer;
  border: 1.5px dashed var(--border-strong); border-radius: var(--r-md);
  background: var(--bg-alt); color: var(--fg-soft); margin: 0; font-weight: 500;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.file-drop-face b { font-size: .92rem; font-weight: 650; color: var(--fg); }
.file-drop-face small { font-size: .78rem; color: var(--fg-muted); font-weight: 400; }
.fd-icon { color: var(--accent-text); display: inline-flex; }
.file-drop:hover .file-drop-face,
.file-drop input[type=file]:focus-visible + .file-drop-face {
  border-color: var(--accent); background: var(--accent-soft);
}
.file-drop.over .file-drop-face { border-color: var(--accent); background: var(--accent-soft); }
.file-drop.filled .file-drop-face { padding: 16px 20px; }

.file-drop-list {
  list-style: none; margin: 9px 0 0; padding: 0;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg-elev);
}
.file-drop-list li {
  display: flex; align-items: center; gap: 9px; padding: 7px 11px; font-size: .82rem;
}
.file-drop-list li + li { border-top: 1px solid var(--border); }
.file-drop-list .fd-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-drop-list .fd-size { color: var(--fg-muted); font-size: .76rem; }


/* ------------------------------------------------ 18. Свойства страницы -- */
.ed-settings { display: flex; flex-direction: column; }   /* шапка + прокручиваемое тело */

.ps-group { padding: 15px 0; border-bottom: 1px solid var(--border); }
.ps-group:first-child { padding-top: 12px; }
.ps-group:last-of-type { border-bottom: 0; }
.ps-title {
  display: flex; align-items: center; gap: 7px; margin: 0 0 12px;
  font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--fg-muted);
}
.ps-title .ico { color: var(--fg-muted); }
.ps-title .count { margin-left: auto; }

.ps-field { margin-bottom: 13px; }
.ps-field:last-child { margin-bottom: 0; }
.ps-label { display: block; margin-bottom: 6px; font-size: .8rem; font-weight: 650; color: var(--fg-soft); }
.ps-hint { margin: 6px 0 0; font-size: .74rem; line-height: 1.5; color: var(--fg-muted); }
.ps-hint code {
  font-family: var(--mono); font-size: .92em; padding: 1px 5px;
  border-radius: var(--r-xs); background: var(--bg-sunken); word-break: break-all;
}

/* поля панели: единый вид вместо разнобоя браузерных контролов */
.ed-settings input[type=text], .ed-settings select {
  margin: 0; padding: 8px 11px; font-size: .85rem;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg);
}
.ed-settings input[type=text]:hover { border-color: var(--border-strong); }

/* --- иконка --- */
.ps-icon { display: flex; gap: 12px; align-items: flex-start; margin-bottom: 12px; }
.ps-icon-preview {
  flex: none; width: 54px; height: 54px; display: flex; align-items: center;
  justify-content: center; font-size: 26px; line-height: 1; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
}
.ps-icon-preview.placeholder { opacity: .4; }
.ps-icon-preview .icon-img { width: 100%; height: 100%; object-fit: cover; border-radius: 0; }
.ps-icon-side { flex: 1; min-width: 0; }
.ps-icon-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }

.emoji-picker button.sel { border-color: var(--accent); background: var(--accent-soft); }

/* --- переключатель статуса --- */
.ps-segmented {
  display: flex; gap: 3px; padding: 3px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
}
.ps-seg {
  flex: 1; margin: 0; text-align: center; cursor: pointer; border-radius: var(--r-sm);
  padding: 6px 4px; font-size: .76rem; font-weight: 600; color: var(--fg-muted);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.ps-seg input { position: absolute; opacity: 0; width: 0; height: 0; }
.ps-seg:hover { color: var(--fg); background: var(--bg-hover); }
.ps-seg:has(input:checked) { background: var(--bg); color: var(--accent-text); box-shadow: var(--shadow-xs); }
.ps-seg:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Без права «Публикация» статус остаётся виден, но не переключается:
   сервер всё равно сохранит прежний, и живой переключатель обманывал бы. */
.ps-segmented.is-locked { opacity: .6; pointer-events: none; }

/* --- адрес --- */
.ps-slug {
  display: flex; align-items: center; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg);
}
.ps-slug:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.ps-slug-base {
  flex: none; padding: 8px 2px 8px 10px; font-family: var(--mono);
  font-size: .76rem; color: var(--fg-muted); white-space: nowrap;
}
.ps-slug input[type=text] {
  flex: 1; min-width: 0; border: 0 !important; box-shadow: none !important;
  background: none; padding-left: 2px; font-family: var(--mono); font-size: .78rem;
}

/* --- выпадающий список с своей стрелкой --- */
.ps-select { position: relative; display: flex; }
.ps-select select {
  flex: 1; min-width: 0; appearance: none; -webkit-appearance: none;
  padding-right: 32px; text-overflow: ellipsis;
}
.ps-select > .ico {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  pointer-events: none; color: var(--fg-muted);
}
.ps-select select option { font-family: var(--mono); }

/* --- теги как чипы --- */
.ps-tags {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px; padding: 6px;
  border: 1px solid var(--border); border-radius: var(--r-sm); background: var(--bg);
  cursor: text;
}
.ps-tags:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.ps-chips { display: contents; list-style: none; margin: 0; padding: 0; }
.ps-chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 5px 3px 9px;
  border-radius: 99px; background: var(--accent-soft); color: var(--accent-text);
  font-size: .76rem; font-weight: 600; max-width: 100%;
}
.ps-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-chip-x {
  border: 0; background: none; cursor: pointer; color: inherit; opacity: .65;
  font-size: 15px; line-height: 1; padding: 0 2px; border-radius: 50%;
}
.ps-chip-x:hover { opacity: 1; background: color-mix(in srgb, var(--accent) 18%, transparent); }
.ps-tags input[type=text] {
  flex: 1 1 130px; min-width: 110px; border: 0 !important; box-shadow: none !important;
  background: none; padding: 3px 4px !important; font-size: .8rem !important;
}

/* ------------------------------------------------ 19. Свои иконки -------- */
/* Иконкой страницы может быть загруженная картинка — она встаёт на место
   эмодзи в дереве, крошках и заголовке, не ломая высоту строки. */
.icon-img {
  width: 1.15em; height: 1.15em; object-fit: cover; border-radius: 4px;
  vertical-align: -.2em; display: inline-block; background: var(--bg-sunken);
}
.tree-icon .icon-img { width: 15px; height: 15px; vertical-align: -3px; }
.doc-emoji .icon-img { width: 1em; height: 1em; border-radius: 8px; vertical-align: -.08em; }
.space-emoji .icon-img { width: 100%; height: 100%; border-radius: inherit; vertical-align: 0; }
.p-icon .icon-img { width: 17px; height: 17px; vertical-align: -3px; }


/* ------------------------------------------------ 20. Папки вложений ----- */
.folder-list { margin-top: 16px; }
.folder-head {
  margin-bottom: 8px; font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--fg-muted);
}
.folder-head code { text-transform: none; letter-spacing: 0; font-family: var(--mono); }
.folder-name { display: flex; align-items: center; gap: 8px; min-width: 0; }
.folder-name code {
  font-family: var(--mono); font-size: .8rem; color: var(--fg);
  padding: 1px 5px; border-radius: var(--r-xs); background: var(--bg-sunken);
}
.folder-name small { max-width: 150px; }

/* ================================================ 21. Плавность ==========
   Показ и скрытие анимируются в обе стороны: вместо display:none элементы
   гасятся прозрачностью и visibility, поэтому закрытие видно так же, как
   открытие. Скорость задаётся токенами --dur*, а «Админ → Оформление»
   переключает их одним махом (data-motion на <html>).
   ========================================================================= */
html { interpolate-size: allow-keywords; }

/* --- выпадающие меню --- */
/* Закрытое меню полностью выпадает из раскладки (display:none), иначе оно
   растягивало бы страницу вбок на телефоне. Плавное закрытие обеспечивает
   discrete-переход display: где браузер его не знает — меню просто исчезает. */
.dropdown-menu {
  display: none;
  opacity: 0;
  transform: translateY(-6px) scale(.985);
  transform-origin: top var(--dd-origin, left);
  animation: none;
  transition: opacity var(--dur-fast) var(--ease),
              transform var(--dur) var(--ease-out),
              display var(--dur) var(--ease) allow-discrete;
}
.dropdown-menu.right { --dd-origin: right; }
.dropdown.open > .dropdown-menu {
  display: flex;
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-fast) var(--ease),
              transform var(--dur) var(--ease-spring),
              display var(--dur) var(--ease) allow-discrete;
}
@starting-style {
  .dropdown.open > .dropdown-menu { opacity: 0; transform: translateY(-6px) scale(.985); }
}

/* --- модальные окна --- */
.modal-backdrop {
  display: none;
  opacity: 0;
  overflow: auto;
  overscroll-behavior: contain;
  animation: none;
  transition: opacity var(--dur) var(--ease),
              display var(--dur) var(--ease) allow-discrete;
}
.modal-backdrop.open {
  display: flex;
  opacity: 1;
}
@starting-style {
  .modal-backdrop.open { opacity: 0; }
}

.modal-backdrop .modal,
.modal-backdrop .palette,
.modal-backdrop .att-viewer {
  animation: none;
  opacity: 1;
  transform: none;
  transition: opacity var(--dur) var(--ease), transform var(--dur-slow) var(--ease-out);
}
@starting-style {
  .modal-backdrop.open .modal,
  .modal-backdrop.open .palette,
  .modal-backdrop.open .att-viewer { opacity: 0; transform: translateY(-12px) scale(.975); }
}

/* --- дерево: раскрытие ветки --- */
.tree-item > .tree {
  display: block;
  height: 0;
  opacity: 0;
  transition: height var(--dur) var(--ease), opacity var(--dur-fast) var(--ease);
}
.tree-item:not(.open) > .tree { overflow: hidden; }
.tree-item.open > .tree { height: auto; opacity: 1; animation: none; }

/* --- смена темы: перекрашиваем весь интерфейс плавно --- */
/* Запасной путь для браузеров без View Transitions: перекрашиваем только
   крупные поверхности. Переход на *всех* элементах разом как раз и давал
   рывок — на большой странице это тысячи одновременных анимаций. */
html.theme-anim body,
html.theme-anim .topbar,
html.theme-anim .sidebar,
html.theme-anim .content,
html.theme-anim .block,
html.theme-anim .panel,
html.theme-anim .card,
html.theme-anim .markdown-body {
  transition: background-color 260ms var(--ease), color 260ms var(--ease),
              border-color 260ms var(--ease);
}

/* Телефон и планшет идут этим же путём — круговая заливка там слишком
   дорога (см. cheapTheme в app.js). Но и здесь переход надо держать в
   узде: `color` на .markdown-body наследуется всем текстом страницы, и
   браузер перерисовывает весь документ каждый кадр четверти секунды.
   Оставляем заливку крупных поверхностей и полторы десятых секунды —
   этого хватает, чтобы смена не била по глазам, и не хватает, чтобы
   она успела «залипнуть». */
@media (max-width: 820px), (hover: none) and (pointer: coarse) {
  html.theme-anim body,
  html.theme-anim .topbar,
  html.theme-anim .mobnav,
  html.theme-anim .sidebar {
    transition: background-color 150ms linear;
  }
  html.theme-anim .content,
  html.theme-anim .block,
  html.theme-anim .panel,
  html.theme-anim .card,
  html.theme-anim .markdown-body { transition: none; }
}

/* Круговая заливка новой темой от кнопки (там, где браузер умеет).
   Только на смене темы: без класса .theme-switch это правило ловило и обычные
   переходы между страницами — каждая ссылка открывалась кругом из угла.

   mix-blend-mode: normal обязателен обоим снимкам. По умолчанию браузер
   складывает их как plus-lighter, и внутри растущего круга старая и новая
   темы светились насквозь — по краю бежало выцветшее кольцо.

   Радиус (--tr), центр (--tx/--ty) и длительность (--vt-dur) считает app.js
   по месту кнопки и размеру окна: круг доходит до дальнего угла ровно к
   концу анимации, без запаса «за экран». Кривая — симметричная: у --ease-out
   почти весь путь проходил за первые полтораста миллисекунд, и переход
   выглядел рывком. */
html.theme-switch::view-transition-old(root) {
  animation: none;
  mix-blend-mode: normal;
  z-index: 0;
}
html.theme-switch::view-transition-new(root) {
  animation: theme-reveal var(--vt-dur, 520ms) cubic-bezier(.42, 0, .18, 1) both;
  mix-blend-mode: normal;
  z-index: 1;
  will-change: clip-path;
}
@keyframes theme-reveal {
  from { clip-path: circle(0px at var(--tx, 100%) var(--ty, 0px)); }
  to   { clip-path: circle(var(--tr, 160vmax) at var(--tx, 100%) var(--ty, 0px)); }
}

/* --- появление содержимого страницы ---
   Только там, где браузер не умеет View Transitions: иначе переход между
   страницами проигрывался дважды — кроссфейд документа и следом эта анимация,
   и это читалось как рывок. */
@supports not (view-transition-name: none) {
  @media (prefers-reduced-motion: no-preference) {
    .content > .page-wrap,
    .content > .doc { animation: page-in var(--dur) var(--ease-out); }
  }
}
@keyframes page-in { from { opacity: 0; } }

/* --- удаление строки/карточки --- */
.is-removing {
  opacity: 0 !important;
  transform: translateX(-14px) scale(.98);
  max-height: 0 !important;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
  padding-top: 0 !important;
  padding-bottom: 0 !important;
  overflow: hidden;
  transition: all var(--dur-slow) var(--ease) !important;
}

/* --- нажатия и наведения ---
   Наведение больше не двигает элемент по вертикали. Приподнятая карточка
   вылезала за край своего контейнера: в сетках со скруглением и в полосах с
   прокруткой верхушку срезало, а значок внутри «уезжал вверх» относительно
   подписи и выглядел оторванным. Обратная связь теперь строится на том, что
   ничего не смещает: заливка, граница и тень.

   Пружинное ускорение осталось только у нажатия. На наведении оно давало
   перелёт: элемент подпрыгивал выше конечной точки и возвращался — это и
   читалось как «иконка уходит вверх». */
.btn, .icon-btn, .card, .quick, .tree-row, .side-list a, .admin-tab, .chip,
.palette-swatch, .choice, .icon-cell, .att-card, .pager-item, .emoji-btn, .emoji-pick {
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur-fast) var(--ease), opacity var(--dur-fast) var(--ease);
}
.btn:active, .icon-btn:active { transform: scale(.96); transition-timing-function: var(--ease-spring); }
.card:hover, .quick:hover { box-shadow: var(--shadow); }

/* мягкое появление списков */
@media (prefers-reduced-motion: no-preference) {
  .stagger > * { animation: fade-up var(--dur-slow) var(--ease-out) backwards; }
  .stagger > *:nth-child(1) { animation-delay: 20ms; }
  .stagger > *:nth-child(2) { animation-delay: 45ms; }
  .stagger > *:nth-child(3) { animation-delay: 70ms; }
  .stagger > *:nth-child(4) { animation-delay: 95ms; }
  .stagger > *:nth-child(n+5) { animation-delay: 120ms; }
}
@keyframes fade-up { from { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-new(root), ::view-transition-old(root) { animation: none !important; }
}

/* ================================================ 22. Поиск в панели ===== */
.side-top { display: flex; flex-direction: column; gap: 6px; }

.side-search { position: relative; }
.side-search-field {
  display: flex; align-items: center; gap: 7px;
  height: 36px; padding: 0 7px 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg); color: var(--fg-muted);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
.side-search-field:hover { border-color: var(--border-strong); }
.side-search.open .side-search-field,
.side-search-field:focus-within {
  border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); background: var(--bg-elev);
}
.side-search-field input[type=search] {
  flex: 1; min-width: 0; width: auto; margin: 0; padding: 0;
  border: 0; background: none; outline: none; box-shadow: none;
  font: inherit; font-size: .86rem; color: var(--fg);
  -webkit-appearance: none; appearance: none;
}
.side-search-field input[type=search]:focus { border: 0; box-shadow: none; }
.side-search-field input[type=search]::-webkit-search-cancel-button { display: none; }
.side-search-kbd {
  font-size: .6rem; padding: 1px 5px; border-bottom-width: 1px;
  transition: opacity var(--dur-fast) var(--ease);
}
.side-search-field:focus-within .side-search-kbd { opacity: 0; }

.side-search-panel {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 90;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  overflow: hidden; display: flex; flex-direction: column;
  max-height: min(60vh, 460px);
  animation: dd-in var(--dur) var(--ease-out);
}
.side-search-scope {
  padding: 7px 10px; font-size: .72rem; color: var(--fg-muted);
  border-bottom: 1px solid var(--border); background: var(--bg-alt);
  display: flex; align-items: center; gap: 6px;
}
.side-search-results { overflow-y: auto; padding: 5px; flex: 1 1 auto; }
.ss-item {
  display: flex; gap: 9px; align-items: flex-start; width: 100%;
  padding: 7px 8px; border-radius: var(--r-sm); border: 1px solid transparent;
  color: var(--fg); text-align: left; background: none; font: inherit;
  transition: background var(--dur-fast) var(--ease);
}
.ss-item:hover, .ss-item.sel { background: var(--bg-hover); text-decoration: none; }
.ss-item.sel { border-color: var(--accent-line); background: var(--accent-soft); }
.ss-ico { flex: none; width: 20px; text-align: center; font-size: 14px; line-height: 1.4; }
.ss-ico .icon-img { width: 16px; height: 16px; border-radius: 4px; }
.ss-body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 1px; }
.ss-title { font-size: .85rem; font-weight: 550; line-height: 1.35; }
.ss-title mark, .ss-snip mark {
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  color: inherit; border-radius: 3px; padding: 0 1px;
}
.ss-snip {
  font-size: .76rem; color: var(--fg-muted); line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ss-path { font-size: .7rem; color: var(--fg-muted); display: flex; gap: 4px; flex-wrap: wrap; }
.ss-path b { font-weight: 600; color: var(--fg-soft); }
.side-search-foot {
  display: flex; align-items: center; gap: 10px; flex: none;
  padding: 6px 10px; border-top: 1px solid var(--border);
  background: var(--bg-alt); font-size: .7rem; color: var(--fg-muted);
}
.side-search-foot .grow-right { margin-left: auto; }
.ss-empty { padding: 18px 12px; text-align: center; color: var(--fg-muted); font-size: .82rem; }
.ss-loading { padding: 14px; display: flex; justify-content: center; }
.spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid var(--border-strong); border-top-color: var(--accent);
  animation: spin 620ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Блок дерева: заголовок вплотную к кнопке «Новая страница» */
.tree-block { display: flex; flex-direction: column; gap: 2px; }
.tree-head { padding-top: 2px; }
.sidebar-inner { gap: var(--gap); }
.side-top + .tree-block { margin-top: 2px; }

/* Инструменты строки дерева.
   Раньше «+» и «…» всегда занимали свои 42 px, даже невидимыми, — на глубине
   это ровно те три уровня вложенности, которых не хватало названию. Теперь они
   висят поверх правого края и появляются при наведении; под ними — короткая
   растушёвка, чтобы длинное название не упиралось в иконки. */
.tree-tools {
  display: flex; align-items: center; gap: 0; flex: none;
  position: absolute; right: 2px; top: 0; bottom: 0; z-index: 1;
  padding-left: 14px; border-radius: var(--r-sm);
  opacity: 0; pointer-events: none;
  background: linear-gradient(90deg, transparent, var(--bg-hover) 14px);
  transition: opacity var(--dur-fast) var(--ease);
}
.tree-row:hover > .tree-tools,
.tree-tools:focus-within,
.tree-tools:has(.tree-menu.open) { opacity: 1; pointer-events: auto; }
.tree-row.active > .tree-tools {
  background: linear-gradient(90deg, transparent, var(--accent-soft) 14px);
}
/* Видимостью заведует .tree-tools целиком — кнопкам остаётся только вид */
.tree-add, .tree-more {
  opacity: 1; width: 21px; height: 21px; border-radius: var(--r-xs);
  display: inline-flex; align-items: center; justify-content: center;
  color: var(--fg-muted); flex: none; border: 0; background: none; cursor: pointer;
  padding: 0; align-self: center;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.tree-add:hover, .tree-more:hover { background: var(--bg); color: var(--accent-text); }
.tree-menu.open .tree-more { background: var(--accent-soft); color: var(--accent-text); }
.tree-menu .dropdown-menu { min-width: 200px; }

/* Быстрое создание вложенной страницы прямо в дереве */
.tree-new {
  display: flex; align-items: center; gap: 6px;
  margin: 2px 0 2px 20px; padding: 3px 6px;
  border: 1px dashed var(--accent-line); border-radius: var(--r-sm);
  background: var(--accent-soft);
  animation: fade-up var(--dur) var(--ease-out);
}
.tree-new input {
  flex: 1; min-width: 0; margin: 0; padding: 2px 4px; height: 24px;
  border: 0; background: none; outline: none; box-shadow: none;
  font: inherit; font-size: .82rem; color: var(--fg);
}
.tree-new input:focus { border: 0; box-shadow: none; }
.tree-new .mini { font-size: .73rem; color: var(--fg-muted); }

/* Иконки, заменённые в админке */
.ico-emoji {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--isz, 16px); height: var(--isz, 16px);
  font-size: calc(var(--isz, 16px) * .92); line-height: 1; flex: none;
  vertical-align: -.15em;
}
img.ico-custom { object-fit: contain; border-radius: 3px; vertical-align: -.15em; }

/* ================================================ 23. Админка ============ */
.admin-layout .sidebar { background: var(--bg-alt); }
.admin-nav { gap: 10px; }

.admin-back {
  display: flex; align-items: center; gap: 7px;
  padding: 6px 8px; border-radius: var(--r-sm);
  color: var(--fg-muted); font-size: .82rem;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.admin-back:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }

.admin-brand {
  display: flex; align-items: center; gap: 10px; padding: 4px 8px 10px;
  border-bottom: 1px solid var(--border);
}
.admin-brand-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: var(--r-md); flex: none;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: #fff; box-shadow: var(--shadow-sm);
}
.admin-brand b { display: block; font-size: .9rem; }
.admin-brand small { color: var(--fg-muted); font-size: .7rem; }

.admin-tabs { display: flex; flex-direction: column; gap: 2px; }
.admin-tab {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 9px; border-radius: var(--r-sm);
  color: var(--fg-soft); position: relative;
}
.admin-tab b { display: block; font-size: .855rem; font-weight: 550; }
.admin-tab small { display: block; font-size: .7rem; color: var(--fg-muted); line-height: 1.3; }
.admin-tab-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: var(--r-sm); flex: none;
  background: var(--bg-sunken); color: var(--fg-soft);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.admin-tab .admin-tab-arrow { opacity: 0; transform: translateX(-4px); transition: all var(--dur) var(--ease); }
.admin-tab:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }
.admin-tab:hover .admin-tab-arrow { opacity: .5; transform: none; }
.admin-tab.active { background: var(--accent-soft); color: var(--accent-text); }
.admin-tab.active b { font-weight: 650; }
.admin-tab.active .admin-tab-ico { background: var(--accent); color: var(--accent-fg); }
.admin-tab.active::before {
  content: ""; position: absolute; left: -10px; top: 8px; bottom: 8px;
  width: 3px; border-radius: 99px; background: var(--accent);
}

.admin-wrap { padding-top: 20px; }
/* Списки, матрица прав и журнал занимают всю доступную ширину: зажимать их
   в колонку для чтения незачем — там таблицы и сетки, а не текст. */
.page-wrap.wide.roomy { max-width: min(1720px, 100%); padding-left: 36px; padding-right: 36px; }
@media (max-width: 1100px) { .page-wrap.wide.roomy { padding-left: 30px; padding-right: 30px; } }
.admin-head {
  display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap;
  padding-bottom: 14px; margin-bottom: 18px; border-bottom: 1px solid var(--border);
}
.admin-head h1 { font-size: 1.5rem; margin: 0 0 2px; }
.admin-head p { margin: 0; font-size: .85rem; }
.admin-head-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.admin-head-actions form { margin: 0; }

.panel {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev); padding: 16px 18px; margin-bottom: 18px;
  box-shadow: var(--shadow-xs);
}
.panel.collapsible { animation: fade-up var(--dur-slow) var(--ease-out); }

.form-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px 14px; align-items: start;
}
.form-grid label { margin-bottom: 0; }
.form-grid .span-2 { grid-column: span 2; }
.form-grid .span-all { grid-column: 1 / -1; }
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px 14px; }
.mt { margin-top: 12px; }
.sub-title { font-size: .8rem; text-transform: uppercase; letter-spacing: .06em;
             color: var(--fg-muted); margin: 0 0 8px; font-weight: 700; }
.block-head.sub { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--border); }
.block-head.sub h3 { margin: 0; font-size: .9rem; }

/* Полоса действий непрозрачна: полупрозрачный фон с blur(10px) превращал
   уезжающий под неё текст в размытое пятно и читался как дефект отрисовки. */
.sticky-actions {
  position: sticky; bottom: 10px; z-index: 20;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 16px; margin: 18px 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev);
  box-shadow: var(--shadow);
}

.chip-checks { display: flex; flex-wrap: wrap; gap: 6px; }
.chip-check input { position: absolute; opacity: 0; pointer-events: none; }
.chip-check span {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 99px; cursor: pointer;
  border: 1px solid var(--border); background: var(--bg); font-size: .8rem;
  transition: all var(--dur-fast) var(--ease);
}
.chip-check input:checked + span {
  border-color: var(--accent); background: var(--accent-soft); color: var(--accent-text);
}

.dd-check {
  display: flex; align-items: center; gap: 8px; padding: 6px 9px;
  border-radius: var(--r-sm); cursor: pointer; font-size: .84rem;
}
.dd-check:hover { background: var(--bg-hover); }

/* Переключатель «активен» */
.switch { display: inline-flex; cursor: pointer; }
.switch input { position: absolute; opacity: 0; pointer-events: none; }
.switch span {
  width: 34px; height: 20px; border-radius: 99px; background: var(--border-strong);
  position: relative; display: inline-block;
  transition: background var(--dur) var(--ease);
}
.switch span::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%; background: #fff;
  box-shadow: var(--shadow-xs);
  transition: transform var(--dur) var(--ease-spring);
}
.switch input:checked + span { background: var(--accent); }
.switch input:checked + span::after { transform: translateX(14px); }
.switch input:focus-visible + span { box-shadow: 0 0 0 3px var(--accent-soft); }

tr.is-off { opacity: .55; }

/* --- роли и права --- */
.role-list { display: flex; flex-direction: column; gap: 18px; }
.role-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid var(--border);
}
.role-title { flex: 1 1 240px; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.role-meta { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.role-dot {
  width: 12px; height: 12px; border-radius: 50%; flex: none;
  background: var(--rc, var(--accent));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--rc, var(--accent)) 20%, transparent);
}
.role-dot.lg { width: 20px; height: 20px; }
input[type=color].color-dot {
  width: 32px; height: 32px; padding: 2px; border-radius: 50%; margin: 0;
  border: 1px solid var(--border); cursor: pointer; flex: none; background: var(--bg);
}
input[type=color].color-dot::-webkit-color-swatch { border: 0; border-radius: 50%; }
input[type=color].color-dot::-moz-color-swatch { border: 0; border-radius: 50%; }
.ghost-input.big { font-size: 1.05rem; font-weight: 650; }
input.icon-field { width: 56px; text-align: center; flex: none; margin: 0; }
.role-title .ghost-input { margin: 0; }

/* Матрица прав.
   Колонки CSS (`columns`) раскладывали группы по высоте, а не по смыслу:
   «Страницы» разрывались между колонками, а порядок чтения шёл сверху вниз
   в одном столбце, потом опять сверху — найти нужное право было нельзя.
   Теперь это сетка карточек: одна группа — одна карточка, у карточки своя
   шапка со счётчиком «включено из всего» и своим переключателем «все».

   Ключ права (`page.delete`) больше не прячется до наведения: именно по нему
   право ищут глазами и в документации, поэтому он стоит в строке постоянно
   мелким моноширинным. */
.perm-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr));
  gap: 12px; align-items: start;
}
.perm-grid > * { min-width: 0; }
.perm-group {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: 0 0 6px; margin: 0; background: var(--bg-elev);
  display: flex; flex-direction: column; gap: 2px;
  box-shadow: var(--shadow-xs); min-width: 0;
}
/* Шапка группы — обычный блок, а не <legend>: у легенды своя раскладка
   внутри fieldset, и в flex-контейнере разные браузеры ставят её по-разному.
   Сам fieldset остался ради атрибута disabled — он гасит всю группу разом. */
.perm-group > .perm-head {
  padding: 0; margin: 0 0 4px;
  border-bottom: 1px solid var(--border); background: var(--bg-alt);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.perm-group { border-width: 1px; padding-inline: 0; min-inline-size: 0; }
.perm-all {
  display: flex; align-items: center; gap: 9px; cursor: pointer;
  padding: 9px 12px; margin: 0;
  font-size: .74rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--fg-soft);
}
.perm-all input { flex: none; margin: 0; }
.perm-all span { flex: 1; min-width: 0; }
.perm-all .perm-count {
  flex: none; padding: 1px 7px; border-radius: 99px;
  background: var(--bg-sunken); color: var(--fg-muted);
  font-size: .73rem; font-weight: 700; letter-spacing: 0;
  font-variant-numeric: tabular-nums; text-transform: none;
}
.perm-group.all-on .perm-all .perm-count { background: var(--accent-soft); color: var(--accent-text); }

.perm-item {
  position: relative;
  display: grid; grid-template-columns: auto 1fr; gap: 2px 10px;
  align-items: start; margin: 0 6px;
  padding: 7px 9px; border-radius: var(--r-sm); cursor: pointer;
  border: 1px solid transparent;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.perm-item:hover { background: var(--bg-hover); }
.perm-item.on { background: var(--accent-soft); border-color: var(--accent-line); }
.perm-item input { margin: 3px 0 0; flex: none; grid-row: span 2; }
.perm-text { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.perm-text b { font-size: .83rem; font-weight: 600; line-height: 1.3; }
.perm-item.on .perm-text b { color: var(--accent-text); }
.perm-text small { font-size: .73rem; color: var(--fg-muted); line-height: 1.4; }
.perm-key {
  grid-column: 2; justify-self: start; margin-top: 3px;
  font-family: var(--font-mono); font-size: .73rem; line-height: 1.4;
  color: var(--fg-muted); background: var(--bg-sunken);
  border: 1px solid var(--border); padding: 0 5px; border-radius: 4px;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.perm-group[disabled] { opacity: .78; }
.perm-group[disabled] .perm-item { cursor: default; }
/* Право не подошло под поиск по матрице — прячем вместе с пустой группой */
.perm-item.hidden, .perm-group.hidden { display: none; }

.form-actions.between { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }

/* --- группы ---
   Участники сверху, права под ними во всю ширину: в две колонки матрица прав
   растягивалась на три экрана, а список людей всё равно оставался коротким. */
.group-body { display: flex; flex-direction: column; gap: 18px; }
.group-part { min-width: 0; }
.group-cols { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 18px; }
@media (max-width: 1100px) { .group-cols { grid-template-columns: 1fr; } }

.member-picker {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev); overflow: hidden; box-shadow: var(--shadow-xs);
}
.member-search {
  display: flex; align-items: center; gap: 8px; padding: 8px 12px;
  border-bottom: 1px solid var(--border); background: var(--bg-alt); color: var(--fg-muted);
}
.member-search input {
  flex: 1; min-width: 0; margin: 0; padding: 0; border: 0; background: none;
  outline: none; box-shadow: none; font: inherit; font-size: .84rem; color: var(--fg);
}
.member-search input:focus { border: 0; box-shadow: none; }
.member-count { flex: none; white-space: nowrap; }
.member-count b { color: var(--accent-text); font-variant-numeric: tabular-nums; }
.member-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 3px; max-height: 246px; overflow-y: auto; overscroll-behavior: contain; padding: 6px;
}
.member-list > * { min-width: 0; }
/* Отмеченный участник виден заливкой, а не одной галочкой: в сетке из
   двадцати строк галочку глазами не собрать. */
.member {
  display: flex; align-items: center; gap: 9px; padding: 6px 9px;
  border: 1px solid transparent; border-radius: var(--r-md);
  cursor: pointer; font-size: .84rem;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.member:hover { background: var(--bg-hover); }
.member.sel { background: var(--accent-soft); border-color: var(--accent-line); }
.member input { flex: none; margin: 0; }
.member.hidden { display: none; }
.member-empty { padding: 20px 12px; text-align: center; margin: 0; grid-column: 1 / -1; }

/* --- хранилище --- */
.storage-hero {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: linear-gradient(140deg, var(--bg-tint), var(--bg-elev) 70%);
  padding: 18px; margin-bottom: 18px; box-shadow: var(--shadow-xs);
}
.storage-total { display: flex; flex-direction: column; gap: 1px; margin-bottom: 12px; }
.storage-total b { font-size: 1.85rem; line-height: 1.1; letter-spacing: -.02em; }
.storage-bar {
  display: flex; height: 14px; border-radius: 99px; overflow: hidden;
  background: var(--bg-sunken); box-shadow: inset 0 0 0 1px var(--border);
}
.storage-bar .seg {
  background: var(--c); min-width: 2px;
  transition: width var(--dur-slow) var(--ease-out), filter var(--dur-fast) var(--ease);
}
.storage-bar .seg:hover { filter: brightness(1.12); }
.storage-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 12px; font-size: .8rem; }
.legend-item { display: inline-flex; align-items: center; gap: 6px; color: var(--fg-soft); }
.legend-item i { width: 9px; height: 9px; border-radius: 3px; background: var(--c); flex: none; }

.webp-stat { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; margin-bottom: 12px; }
.webp-ring {
  --pct: 0;
  width: 96px; height: 96px; border-radius: 50%; flex: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--bg-sunken) 0);
  position: relative;
}
.webp-ring::before {
  content: ""; position: absolute; inset: 9px; border-radius: 50%; background: var(--bg-elev);
}
.webp-ring b { position: relative; font-size: 1.15rem; }
.webp-ring small { position: relative; font-size: .73rem; color: var(--fg-muted); }

.usage-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.usage-top { display: flex; align-items: center; gap: 8px; font-size: .85rem; }
.usage-bar {
  display: block; height: 7px; border-radius: 99px; background: var(--bg-sunken);
  overflow: hidden; margin: 5px 0 3px;
}
.usage-bar i {
  display: block; height: 100%; border-radius: 99px; background: var(--c, var(--accent));
  transition: width var(--dur-slow) var(--ease-out);
}

.file-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.file-row {
  display: flex; align-items: center; gap: 10px; padding: 7px 8px;
  border-radius: var(--r-sm); color: var(--fg); font-size: .85rem;
  transition: background var(--dur-fast) var(--ease);
}
.file-row:hover { background: var(--bg-hover); text-decoration: none; }
.file-row .grow { min-width: 0; display: flex; flex-direction: column; }
.file-row small { font-size: .72rem; }
.file-ico {
  width: 28px; height: 28px; border-radius: var(--r-sm); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-sunken); color: var(--fg-soft);
}
.file-ico.kind-image { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent-text); }
.file-ico.kind-video { background: color-mix(in srgb, #ec4899 16%, transparent); color: #ec4899; }
.file-ico.kind-archive { background: color-mix(in srgb, var(--amber) 16%, transparent); color: var(--amber); }

.mini-details { margin: 10px 0; }
.mini-details summary { cursor: pointer; font-size: .82rem; color: var(--fg-soft); padding: 4px 0; }
.mini-details summary:hover { color: var(--accent-text); }
.scroll-sm { max-height: 240px; overflow-y: auto; }
.warn-text { color: var(--amber); }

/* --- оформление --- */
.palette-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.palette-swatch {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 12px; border-radius: var(--r-md); cursor: pointer;
  border: 1px solid var(--border); background: var(--bg); min-width: 84px;
}
.palette-swatch input { position: absolute; opacity: 0; pointer-events: none; }
.swatch-dot {
  width: 30px; height: 30px; border-radius: 50%;
  background: linear-gradient(135deg, var(--pc), color-mix(in srgb, var(--pc) 55%, #fff));
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--pc) 35%, transparent);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease-spring);
}
.swatch-name { font-size: .76rem; color: var(--fg-soft); }
.palette-swatch:hover { border-color: var(--border-strong); }
.palette-swatch:hover .swatch-dot { transform: scale(1.08); }
.palette-swatch.sel { border-color: var(--pc); background: color-mix(in srgb, var(--pc) 8%, var(--bg)); }
.palette-swatch.sel .swatch-dot { box-shadow: 0 0 0 4px color-mix(in srgb, var(--pc) 28%, transparent); }
.palette-swatch.sel .swatch-name { color: var(--fg); font-weight: 600; }

.choice-row { display: flex; gap: 8px; flex-wrap: wrap; }
.choice {
  flex: 1 1 150px; display: flex; flex-direction: column; gap: 2px;
  padding: 10px 12px; border-radius: var(--r-md); cursor: pointer;
  border: 1px solid var(--border); background: var(--bg);
}
.choice input { position: absolute; opacity: 0; pointer-events: none; }
.choice b { font-size: .86rem; }
.choice small { font-size: .73rem; color: var(--fg-muted); }
.choice:hover { border-color: var(--border-strong); background: var(--bg-hover); }
.choice.sel { border-color: var(--accent); background: var(--accent-soft); }
.choice.sel b { color: var(--accent-text); }
.choice.slim { flex: 0 1 auto; padding: 7px 14px; }

.accent-preview {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px; border: 1px dashed var(--border-strong); border-radius: var(--r-md);
  background: var(--bg-alt);
}
.accent-bar { flex: 1; min-width: 80px; height: 8px; border-radius: 99px; background: var(--bg-sunken); overflow: hidden; }
.accent-bar i { display: block; width: 62%; height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-2)); }
.range-value { color: var(--accent-text); }
input[type=range] { width: 100%; accent-color: var(--accent); }

/* --- иконки ---
   Карточка значка при наведении остаётся на месте: она стоит в плотной сетке
   и, приподнимаясь, срезалась о соседей и о край секции. Вместо смещения —
   тень, акцентная граница и подсветка самой плитки со значком. Высота задана
   заранее, поэтому строки сетки не скачут, когда названия разной длины. */
.icon-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); gap: 8px; }
.icon-cell {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 12px 8px 10px; border-radius: var(--r-md); cursor: pointer;
  border: 1px solid var(--border); background: var(--bg-elev); color: var(--fg);
  font: inherit; min-height: 106px; justify-content: flex-start;
}
.icon-cell:hover {
  border-color: var(--accent-line); background: var(--bg-tint);
  box-shadow: var(--shadow-sm);
}
.icon-cell:hover .icon-cell-art { background: var(--accent-soft); color: var(--accent-text); }
.icon-cell.custom { border-color: var(--accent-line); }
.icon-cell-art {
  width: 40px; height: 40px; border-radius: var(--r-md); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-sunken); color: var(--fg-soft);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.icon-cell-emoji { font-size: 21px; line-height: 1; }
.icon-cell-name { font-size: .76rem; text-align: center; line-height: 1.25; }
.icon-cell-key {
  font-size: .70rem; color: var(--fg-muted); margin-top: auto;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.icon-cell-dot {
  position: absolute; top: 7px; right: 7px; width: 7px; height: 7px;
  border-radius: 50%; background: var(--accent);
}
.icon-dlg-preview { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.icon-preview-box {
  width: 52px; height: 52px; border-radius: var(--r-md); flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); background: var(--bg-alt); font-size: 26px;
}
.icon-preview-box img { width: 30px; height: 30px; object-fit: contain; }
/* Быстрый выбор эмодзи лежит в прокручиваемом теле окна: раздувать кнопку
   на наведении нельзя — у края её срезает. Подсвечиваем заливкой. */
.emoji-quick { display: flex; flex-wrap: wrap; gap: 4px; margin: 8px 0 14px; }
.emoji-pick {
  width: 32px; height: 32px; border-radius: var(--r-sm); border: 1px solid transparent;
  background: var(--bg-alt); cursor: pointer; font-size: 17px; line-height: 1;
}
.emoji-pick:hover { background: var(--accent-soft); border-color: var(--accent-line); }

/* --- события --- */
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px; border-radius: 99px; font-size: .78rem;
  border: 1px solid var(--border); background: var(--bg); color: var(--fg-soft);
}
.chip:hover { border-color: var(--accent-line); color: var(--accent-text); text-decoration: none; }
.chip.sel { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
/* Счётчик внутри метки — отдельной «таблеткой»: иначе «правка · 412»
   читалось как одно длинное слово. */
.chip b {
  padding: 0 6px; border-radius: 99px; font-size: .7rem; font-weight: 700;
  background: var(--bg-sunken); color: var(--fg-muted); font-variant-numeric: tabular-nums;
}
.chip.sel b { background: color-mix(in srgb, #000 18%, transparent); color: var(--accent-fg); }
.chip:hover b { color: var(--accent-text); }
.chip.sel:hover b { color: var(--accent-fg); }

.filter-chips { margin-bottom: 12px; }
.filter-chips-label {
  margin-right: 4px; font-size: .71rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--fg-muted);
}

/* Полоса фильтров.
   Подпись и список стояли впритык друг к другу: «Пользователь» читалось как
   часть выпадающего списка, а три пары подряд сливались в сплошную серую
   строку. Теперь каждый фильтр — отдельное поле с рамкой: подпись внутри
   сверху мелким прописным, значение под ней. Между полями — заметный
   промежуток и разделительная линия перед служебной частью справа. */
.filter-bar {
  display: flex; gap: 10px; align-items: stretch; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 14px;
  border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--bg-alt);
}
.filter-bar > label {
  display: flex; flex-direction: column; gap: 3px; margin: 0;
  flex: 0 1 auto; min-width: 0;
  padding: 5px 10px 6px; border-radius: var(--r-md);
  border: 1px solid var(--border); background: var(--bg);
  font-size: .71rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--fg-muted);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.filter-bar > label:focus-within {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}
/* Своя стрелка вместо системной: родная у каждого браузера своя и ломала
   выравнивание внутри поля. */
.filter-bar select {
  width: auto; min-width: 132px; max-width: 220px; margin: 0;
  padding: 0 22px 0 0; border: 0; background: none; box-shadow: none;
  font: inherit; font-size: .85rem; font-weight: 500; letter-spacing: 0;
  text-transform: none; color: var(--fg); cursor: pointer;
  appearance: none; -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 8px center, right 3px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
.filter-bar select:focus { border: 0; box-shadow: none; }
.filter-bar .filter-sep {
  flex: 1 1 auto; min-width: 0;
}
.filter-bar .filter-tail {
  display: flex; align-items: center; gap: 10px; flex: none;
  padding-left: 12px; border-left: 1px solid var(--border);
}
.filter-bar .filter-tail .muted { font-size: .76rem; white-space: nowrap; }

@media (max-width: 700px) {
  .filter-bar > label { flex: 1 1 160px; }
  .filter-bar select { min-width: 0; width: 100%; max-width: none; }
  .filter-bar .filter-tail { flex: 1 1 100%; padding-left: 0; border-left: 0; }
}

/* Записи журнала разделены линией: подряд идущие строки одной высоты без
   разделителя читались сплошным полотном, и взгляд не находил, где кончается
   одно событие и начинается следующее. */
.event-list {
  list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev); overflow: hidden;
}
.event {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  font-size: .84rem;
  transition: background var(--dur-fast) var(--ease);
}
.event + .event { border-top: 1px solid var(--border); }
.event:hover { background: var(--bg-alt); }
.event .grow { min-width: 0; display: flex; align-items: baseline; gap: 7px; }
.event-action {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .04em;
  padding: 2px 7px; border-radius: 99px; flex: none;
  background: var(--bg-sunken); color: var(--fg-muted); font-weight: 700;
}
.event.act-create .event-action { background: color-mix(in srgb, var(--green) 15%, transparent); color: var(--green); }
.event.act-delete .event-action { background: color-mix(in srgb, var(--red) 15%, transparent); color: var(--red); }
.event.act-update .event-action { background: color-mix(in srgb, var(--blue) 15%, transparent); color: var(--blue); }
.event.act-login .event-action, .event.act-signup .event-action { background: var(--accent-soft); color: var(--accent-text); }

.preset-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 10px 0; }
.inline-form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.inline-label { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-size: .82rem; }
.inline-label input { width: 76px; margin: 0; }

/* --- пароль --- */
.pass-strength { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
.pass-strength i {
  display: block; height: 5px; width: 0; border-radius: 99px; background: var(--red);
  transition: width var(--dur-slow) var(--ease-out), background var(--dur) var(--ease);
}
.pass-strength.mid i { background: var(--amber); }
.pass-strength.good i { background: var(--green); }
.pass-strength small { font-size: .72rem; color: var(--fg-muted); }

/* --- прочее --- */
.quick-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 10px; }
.quick {
  display: flex; flex-direction: column; gap: 3px;
  padding: 14px; border-radius: var(--r-md); border: 1px solid var(--border);
  background: var(--bg); color: var(--fg);
}
.quick:hover { border-color: var(--accent-line); background: var(--bg-tint); text-decoration: none; box-shadow: var(--shadow-sm); }
.quick .ico { color: var(--accent-text); margin-bottom: 4px; }
.quick b { font-size: .88rem; }
.quick small { font-size: .74rem; color: var(--fg-muted); }

.empty-state {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 46px 20px; text-align: center;
  border: 1px dashed var(--border-strong); border-radius: var(--r-lg);
  color: var(--fg-muted); background: var(--bg-alt);
}
.empty-state h3 { margin: 0; color: var(--fg); }
.empty-state p { max-width: 460px; margin: 0; font-size: .87rem; }
.empty-state .ico { color: var(--fg-muted); opacity: .7; }
.empty-state.small { padding: 26px; }

.badge.soft { background: var(--bg-sunken); color: var(--fg-soft); border-color: transparent; }
.badge.accent { background: var(--accent-soft); color: var(--accent-text); border-color: var(--accent-line); }

.hint-box.tight { display: flex; align-items: flex-start; gap: 9px; padding: 10px 12px; margin: 10px 0; }
.hint-box.tight .ico { flex: none; margin-top: 2px; color: var(--accent-text); }
.hint-box.warn { border-color: color-mix(in srgb, var(--amber) 40%, var(--border)); background: color-mix(in srgb, var(--amber) 8%, transparent); }
.hint-box.warn .ico { color: var(--amber); }

.form-card.flat { border: 0; padding: 0; background: none; box-shadow: none; }
.link.small { font-size: .8rem; }

/* Подтверждение действия — вместо системного confirm() */
.confirm-dialog { max-width: 440px; }
.confirm-dialog .modal-body { display: flex; flex-direction: column; gap: 14px; }
.confirm-text { font-size: .92rem; line-height: 1.5; margin: 0; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 8px; }

@media (max-width: 880px) {
  .admin-head { align-items: flex-start; }
  .admin-head-actions { margin-left: 0; }
  .group-cols { grid-template-columns: 1fr; }
  .storage-total b { font-size: 1.5rem; }
}

/* Переименование прямо в дереве */
.tree-rename {
  flex: 1; min-width: 0; margin: 0; padding: 1px 5px; height: 22px;
  border: 1px solid var(--accent); border-radius: var(--r-xs);
  background: var(--bg); color: var(--fg); font: inherit; font-size: .84rem;
  box-shadow: 0 0 0 3px var(--accent-soft); outline: none;
}

/* Переключатель области поиска в боковой панели */
.scope-seg {
  display: inline-flex; padding: 2px; gap: 2px; flex: none;
  border-radius: 99px; background: var(--bg-sunken);
}
.scope-seg button {
  border: 0; background: none; cursor: pointer; font: inherit;
  font-size: .7rem; padding: 2px 9px; border-radius: 99px; color: var(--fg-muted);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.scope-seg button:hover { color: var(--fg); }
.scope-seg button.on { background: var(--bg-elev); color: var(--accent-text); font-weight: 600; box-shadow: var(--shadow-xs); }

/* Страница поиска: сводка, фасеты, путь в результате */
.search-form.big input[type=text] { flex: 1 1 320px; font-size: 1rem; padding: 10px 14px; }
.search-summary {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 14px; font-size: .87rem; color: var(--fg-soft);
}
.search-facets { margin-bottom: 16px; }
.search-results .res-path { display: inline-flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.search-results .res-path .sep { color: var(--fg-muted); }
.search-results h3 mark, .search-results .snip mark {
  background: color-mix(in srgb, var(--accent) 26%, transparent);
  color: inherit; border-radius: 3px; padding: 0 2px;
}

/* Карточка «создать вложенную страницу» */
.card.add-card {
  border-style: dashed; border-color: var(--border-strong);
  background: transparent; color: var(--fg-muted);
}
.card.add-card:hover {
  border-color: var(--accent); color: var(--accent-text); background: var(--accent-soft);
}
.card.add-card h4 { color: inherit; }

/* Метка формата у вложения */
.att-tag {
  font-size: .6rem; font-weight: 700; letter-spacing: .04em;
  padding: 1px 5px; border-radius: 99px; flex: none;
  background: var(--accent-soft); color: var(--accent-text);
}

/* Хранилище на узком экране: кольцо над списком, ничего не выезжает */
.webp-stat > .kv { min-width: 0; flex: 1 1 220px; }
@media (max-width: 640px) {
  .webp-stat { flex-direction: column; align-items: stretch; }
  .webp-ring { align-self: center; }
  .admin-head-actions { width: 100%; }
  .admin-head-actions .btn { flex: 1; }
  .storage-total b { font-size: 1.5rem; }
  .icon-grid { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
  .perm-grid { columns: 1; }
}

/* Элементы сетки не должны раздувать колонку: без min-width:0 браузер
   держит их не уже min-content и страница уезжает вбок на телефоне. */
.two-col > *, .grid-2 > *, .grid-3 > *, .grid-5 > *,
.form-grid > *, .group-cols > *, .quick-grid > *, .stat-grid > * { min-width: 0; }
.kv li { min-width: 0; }
.kv li span, .kv li b { min-width: 0; overflow-wrap: anywhere; }

/* Длинные пути и ключи переносятся, а не растягивают страницу */
.block code, .hint-box code, .kv code, .muted code, .folder-name code,
.file-row code, .empty-state code { overflow-wrap: anywhere; }
input[type=range] { max-width: 100%; }

/* Содержимое окна прокручивается внутри себя, а не расширяет страницу. */
.modal-body { overflow-x: hidden; }
.keys-list, .key-row { min-width: 0; }

/* ================================================ 24. Переходы страниц ===
   Переход между страницами не должен ощущаться рывком: сверху появляется
   тонкая полоса, а сам обмен содержимым браузер (там, где умеет) делает
   кроссфейдом через View Transitions.
   ========================================================================= */
@view-transition { navigation: auto; }

/* Обычная навигация — короткий кроссфейд; смена темы живёт по своим правилам */
html:not(.theme-switch)::view-transition-old(root),
html:not(.theme-switch)::view-transition-new(root) { animation-duration: 220ms; }

.nav-progress {
  position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 400;
  pointer-events: none; opacity: 0;
  transition: opacity 200ms var(--ease);
}
.nav-progress.on { opacity: 1; }
.nav-progress span {
  display: block; height: 100%; width: 0;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  box-shadow: 0 0 10px var(--accent-glow);
  border-radius: 0 99px 99px 0;
  transition: width 260ms var(--ease-out);
}

/* Заглушка редактора: показываем каркас, пока поднимается редактор */
.ed-loading {
  position: fixed; inset: var(--topbar-h) 0 0; z-index: 120;
  background: var(--bg);
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  padding: 14vh 20px 0;
  transition: opacity var(--dur-slow) var(--ease), visibility 0s linear var(--dur-slow);
}
/* Погашенный каркас не должен перехватывать клики те доли секунды,
   пока идёт его собственный переход. */
body.editor-ready .ed-loading { opacity: 0; visibility: hidden; pointer-events: none; }
.ed-loading-bar {
  width: min(720px, 92vw); height: 14px; border-radius: 99px;
  background: linear-gradient(90deg, var(--bg-sunken) 25%, var(--bg-hover) 37%, var(--bg-sunken) 63%);
  background-size: 400% 100%;
  animation: skeleton 1.3s ease-in-out infinite;
}
.ed-loading-bar.short { width: min(420px, 60vw); }
.ed-loading-bar.title { height: 26px; width: min(520px, 70vw); }
@keyframes skeleton { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* Плавное появление длинных списков без дёрганья прокрутки */
.event-list, .icon-grid { content-visibility: auto; contain-intrinsic-size: auto 600px; }

@media (prefers-reduced-motion: reduce) {
  .nav-progress { display: none; }
  .ed-loading-bar { animation: none; }
}

/* ================================================ 25. Админка: разделы ===
   Разметка разделов администрирования: вкладки ролей, список пользователей,
   мастер-деталь групп, карточки настроек, постраничный журнал и состояние
   базы. Всё держится на тех же токенах, что и остальной интерфейс, поэтому
   плотность, скругления и плавность переключаются из «Оформления».
   ========================================================================= */

/* --- полоса вкладок (роли): вкладка на каждую роль, новая появляется сама -
   Вкладки-«лепестки» с подчёркиванием жили на общей линии снизу: активная
   роль отличалась только цветом текста, а цветной кружок роли обрезался о
   край полосы (overflow-y приходилось держать скрытым из-за прокрутки).
   Теперь это дорожка с пилюлями: активная роль — сплошная плашка своего
   цвета, кружку и его свечению отведено место внутри дорожки. */
.tabs-wrap { margin-top: 2px; }
.tabs-wrap > .tabs {
  display: flex; margin: 0 0 18px; gap: 4px; padding: 4px;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-alt);
  overflow-x: auto;
  scrollbar-width: none;
  align-items: stretch;
}
.tabs-wrap > .tabs::-webkit-scrollbar { height: 0; }
.tabs-wrap .tab {
  display: inline-flex; align-items: center; gap: 8px;
  flex: none; white-space: nowrap;
  padding: 7px 13px; border: 1px solid transparent; border-radius: var(--r-md);
  color: var(--fg-soft); font-size: .86rem; font-weight: 550;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.tabs-wrap .tab:hover { background: var(--bg-hover); color: var(--fg); }
.tabs-wrap .tab.active {
  background: var(--bg-elev); border-color: var(--border);
  color: var(--fg); box-shadow: var(--shadow-xs);
}
.tabs-wrap .tab .role-dot { width: 10px; height: 10px; }
.tab-title { min-width: 0; }
.tab-count {
  min-width: 19px; padding: 1px 7px; border-radius: 99px;
  background: var(--bg-sunken); color: var(--fg-muted);
  font-size: .73rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
.tabs-wrap .tab.active .tab-count {
  background: color-mix(in srgb, var(--rc, var(--accent)) 16%, transparent);
  color: var(--rc, var(--accent));
}
.tab.tab-add { color: var(--accent-text); margin-left: auto; }
.tab.tab-add .ico { opacity: .8; }
.tab.tab-add:hover { background: var(--accent-soft); }

/* --- шапка сущности: значок + поля в один ряд ----------------------------
   Карточка роли или группы: слева знак своего цвета, справа поля. Цветная
   полоса сверху повторяет цвет сущности — по ней вкладка и карточка
   узнаются как одно целое. */
.entity-head {
  position: relative; overflow: hidden;
  display: flex; align-items: flex-start; gap: 16px;
  padding: 18px 18px 16px;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev); box-shadow: var(--shadow-xs);
}
.entity-head::before {
  content: ""; position: absolute; inset: 0 0 auto; height: 3px;
  background: var(--rc, var(--sc, var(--accent)));
}
.entity-mark,
.entity-head > .space-emoji {
  flex: none;
  /* значок встаёт вровень с полем ввода, а не с его подписью */
  margin-top: 18px;
}
.entity-mark {
  width: 46px; height: 46px; border-radius: var(--r-md);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.2rem; font-weight: 700; color: #fff; line-height: 1;
  background: linear-gradient(135deg, var(--rc, var(--accent)),
              color-mix(in srgb, var(--rc, var(--accent)) 58%, #ffffff));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--rc, var(--accent)) 16%, transparent);
}
.entity-fields {
  flex: 1; min-width: 0;
  display: flex; flex-wrap: wrap; gap: 12px 14px; align-items: flex-start;
}

/* Поле-колонка: подпись сверху, контрол под ней. Без отступа общего label.
   Доля ширины задаётся только внутри строк: в колоночном контейнере
   flex-basis стал бы высотой и раздувал поле на пол-экрана. */
.field { display: flex; flex-direction: column; margin: 0; min-width: 0; }
.entity-fields > .field,
.setting-row > .field { flex: 1 1 190px; }
.entity-fields > .field.grow,
.setting-row > .field.grow { flex: 2 1 240px; }
.entity-fields > .field.narrow,
.setting-row > .field.narrow { flex: 0 0 auto; }
.field > span:first-child {
  font-size: .72rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--fg-muted);
}
.field > small { margin-top: 5px; font-weight: 400; line-height: 1.4; }
.field input, .field select, .field textarea { margin-top: 5px; }
.field.narrow input[type=color] { width: 32px; }

.range-line { display: flex; align-items: center; gap: 11px; margin-top: 7px; }
.range-line input[type=range] { flex: 1; min-width: 0; margin: 0; }
.range-line b {
  flex: none; min-width: 54px; text-align: right;
  font-size: .8rem; font-variant-numeric: tabular-nums;
}

.entity-meta {
  display: flex; flex-wrap: wrap; gap: 6px; align-items: center;
  margin: 12px 0 16px;
}

/* Полоса над матрицей: название блока, поиск по правам и пресеты.
   Поиск нужен именно тут: прав 27, и «где включается удаление вложений»
   быстрее набрать, чем найти взглядом. */
.perm-toolbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 10px;
}
.perm-toolbar .sub-title { margin: 0; flex: none; }
.perm-toolbar .grow { min-width: 0; }
.perm-group-all { margin: 0; }
.perm-find {
  display: flex; align-items: center; gap: 7px;
  flex: 0 1 240px; min-width: 150px;
  padding: 5px 11px; border-radius: 99px;
  border: 1px solid var(--border); background: var(--bg-alt); color: var(--fg-muted);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.perm-find:focus-within {
  border-color: var(--accent); background: var(--bg); box-shadow: 0 0 0 3px var(--accent-soft);
}
.perm-find input {
  flex: 1; min-width: 0; margin: 0; padding: 0; border: 0;
  background: none; box-shadow: none; outline: none;
  font: inherit; font-size: .83rem; color: var(--fg);
}
.perm-find input:focus { border: 0; box-shadow: none; }

/* Сколько прав включено — полосой, а не только цифрой: по ней сразу видно
   «почти всё» или «пара галочек». */
.perm-summary {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px; margin: 0 0 12px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
  font-size: .82rem; color: var(--fg-soft);
}
.perm-summary b { color: var(--fg); font-variant-numeric: tabular-nums; }
.perm-summary .bar {
  flex: 1 1 120px; min-width: 90px; height: 6px; border-radius: 99px;
  background: var(--bg-sunken); overflow: hidden;
}
.perm-summary .bar i {
  display: block; height: 100%; width: 0; border-radius: 99px;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  transition: width var(--dur-slow) var(--ease-out);
}
.perm-empty { padding: 26px 12px; text-align: center; margin: 0; }

/* --- мастер-деталь (группы): список слева, права справа ------------------
   Список групп — не «ещё одна панель», а оглавление раздела: он оформлен
   как единая карточка с шапкой и подвалом, выбранная строка помечена
   полосой своего цвета. Так видно, где ты находишься, даже когда групп
   десяток и список прокручен. */
.master-detail {
  display: grid; grid-template-columns: minmax(250px, 310px) minmax(0, 1fr);
  gap: 20px; align-items: start;
}
.md-list {
  display: flex; flex-direction: column;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev); box-shadow: var(--shadow-xs); overflow: hidden;
  position: sticky; top: calc(var(--topbar-h) + 14px);
}
.md-list-head {
  display: flex; align-items: center; gap: 8px;
  padding: 11px 14px; border-bottom: 1px solid var(--border); background: var(--bg-alt);
}
.md-list-head .sub-title { margin: 0; }
.md-items {
  display: flex; flex-direction: column; gap: 2px; padding: 6px;
  max-height: 56vh; overflow-y: auto; overscroll-behavior: contain;
}
.md-item {
  position: relative;
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 10px; border-radius: var(--r-md);
  border: 1px solid transparent; background: none;
  color: var(--fg); font: inherit; text-align: left; cursor: pointer;
  transition: background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.md-item .grow { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.md-item b { font-size: .86rem; font-weight: 600; }
.md-item small { font-size: .72rem; line-height: 1.3; color: var(--fg-muted); }
.md-item:hover { background: var(--bg-hover); }
.md-item.active { background: var(--bg-tint); border-color: var(--accent-line); }
.md-item.active b { color: var(--accent-text); }
/* Полоса слева повторяет цвет группы — тот же, что у карточки справа */
.md-item.active::before {
  content: ""; position: absolute; left: -1px; top: 7px; bottom: 7px;
  width: 3px; border-radius: 99px; background: var(--accent);
}
.md-item > .ico {
  opacity: 0; transform: translateX(-3px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.md-item:hover > .ico, .md-item.active > .ico { opacity: .55; transform: none; }
.md-empty { padding: 22px 12px; text-align: center; margin: 0; }
/* «Новая группа» — подвал карточки со списком, а не отдельная кнопка под ней */
.md-list > .btn.block {
  margin: 0; padding: 11px; border-radius: 0;
  border-width: 1px 0 0; border-style: solid; border-color: var(--border);
  background: var(--bg-alt); color: var(--accent-text); font-weight: 600;
}
.md-list > .btn.block:hover { background: var(--accent-soft); border-color: var(--border); }
.md-detail { min-width: 0; display: flex; flex-direction: column; }
/* панель группы проявляется, а не подменяется рывком */
.md-detail > .tab-panel.active,
.tabs-wrap > .tab-panel.active { animation: fade-up var(--dur-slow) var(--ease-out); }

/* --- панель списка: поиск + сегменты ------------------------------------ */
.list-toolbar,
.icons-toolbar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.list-search {
  display: flex; align-items: center; gap: 8px;
  flex: 1 1 260px; min-width: 0;
  padding: 7px 13px; border-radius: 99px;
  border: 1px solid var(--border); background: var(--bg-alt); color: var(--fg-muted);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
.list-search:focus-within {
  border-color: var(--accent); background: var(--bg);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.list-search input {
  flex: 1; min-width: 0; margin: 0; padding: 0;
  border: 0; background: none; box-shadow: none; outline: none;
  font: inherit; font-size: .86rem; color: var(--fg);
}
.list-search input:focus { border: 0; box-shadow: none; }

.seg-filter {
  display: inline-flex; gap: 2px; padding: 3px; flex: none;
  border-radius: 99px; background: var(--bg-sunken);
}
.seg-filter button {
  border: 0; background: none; cursor: pointer; font: inherit;
  font-size: .78rem; padding: 4px 12px; border-radius: 99px; color: var(--fg-muted);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.seg-filter button:hover { color: var(--fg); }
.seg-filter button.on {
  background: var(--bg-elev); color: var(--accent-text);
  font-weight: 600; box-shadow: var(--shadow-xs);
}

/* --- список пользователей ----------------------------------------------- */
.user-list {
  list-style: none; margin: 0 0 16px; padding: 0;
  display: flex; flex-direction: column; gap: 4px;
}
.user-row {
  display: grid; align-items: center; gap: 6px 12px;
  grid-template-columns:
    auto minmax(140px, 1.7fr) minmax(96px, .8fr) minmax(110px, 1fr) auto auto auto auto;
  padding: 8px 12px;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev);
  transition: border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}
.user-row:hover {
  border-color: var(--accent-line); background: var(--bg-tint);
  box-shadow: var(--shadow-xs);
}
.user-row.is-off { opacity: .62; }
.user-main { display: flex; flex-direction: column; min-width: 0; }
.user-name { display: flex; align-items: center; gap: 6px; font-size: .88rem; font-weight: 600; }
.user-main small {
  font-size: .73rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.user-role, .user-groups { display: flex; gap: 4px; min-width: 0; }
/* Метки групп не переносятся: иначе строки в списке скачут по высоте.
   Лишние уже свёрнуты в «+N» самим шаблоном. */
.user-groups { flex-wrap: nowrap; overflow: hidden; }
.role-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 99px;
  font-size: .74rem; font-weight: 600;
  color: var(--rc, var(--accent));
  background: color-mix(in srgb, var(--rc, var(--accent)) 11%, transparent);
  border: 1px solid color-mix(in srgb, var(--rc, var(--accent)) 26%, transparent);
}
.role-chip i { width: 6px; height: 6px; border-radius: 50%; background: var(--rc); flex: none; }
.mini-chip {
  display: inline-flex; align-items: center; gap: 4px;
  max-width: 128px; padding: 2px 8px; border-radius: 99px;
  font-size: .72rem; color: var(--fg-soft); background: var(--bg-sunken);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.user-stats, .user-seen { white-space: nowrap; font-size: .75rem; }
.user-stats { display: inline-flex; align-items: center; gap: 4px; }
.user-state { display: inline-flex; }
.state { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex: none; }
.state.on {
  background: var(--green);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--green) 20%, transparent);
}
.state.off { background: var(--border-strong); }
.user-actions { display: flex; gap: 5px; }

/* Кнопка-эмодзи: правка и удаление в списке видны сразу, без наведения.
   Кнопка стоит в строке фиксированной высоты — увеличивать её на наведении
   значит подрезать о край строки, поэтому меняются только цвета. */
.emoji-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; flex: none;
  border-radius: var(--r-sm); border: 1px solid transparent;
  background: var(--bg-sunken); cursor: pointer;
  font-size: 15px; line-height: 1;
}
.emoji-btn:hover {
  background: var(--accent-soft); border-color: var(--accent-line);
  box-shadow: var(--shadow-xs);
}
.emoji-btn.danger:hover {
  background: color-mix(in srgb, var(--red) 12%, transparent);
  border-color: color-mix(in srgb, var(--red) 32%, transparent);
}

.dlg-user-head {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 12px; margin-bottom: 15px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
}
.dlg-user-head > div { flex: 1; min-width: 0; }
.dlg-user-head b { display: block; font-size: .95rem; }
.dlg-user-head small { display: block; font-size: .76rem; overflow-wrap: anywhere; }
.switch-row {
  display: inline-flex; align-items: center; gap: 9px; flex: none;
  margin: 0; font-size: .8rem; cursor: pointer;
}

.field-block { margin-bottom: 15px; }
.field-label {
  display: block; margin-bottom: 7px;
  font-size: .8rem; font-weight: 650; color: var(--fg-soft);
}
.field-label small { font-weight: 400; margin-left: 4px; }

/* --- иконки: панель и быстрый переход по группам ------------------------- */
.icon-jump { display: flex; gap: 5px; flex-wrap: wrap; }
.icons-hint { display: flex; align-items: center; gap: 7px; margin: 0 0 16px; }
.icon-section { scroll-margin-top: calc(var(--topbar-h) + 16px); }

/* --- карточки настроек (оформление, настройки сайта) --------------------- */
.settings-form { display: flex; flex-direction: column; gap: 16px; }
.setting-group {
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev); box-shadow: var(--shadow-xs); overflow: hidden;
}
.setting-head {
  padding: 13px 18px 12px;
  border-bottom: 1px solid var(--border); background: var(--bg-alt);
}
.setting-head h2 {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 3px; font-size: 1rem;
}
.setting-head h2 .ico { color: var(--accent-text); }
.setting-head p { margin: 0; }
.setting-body { padding: 16px 18px; display: flex; flex-direction: column; gap: 14px; }
.setting-body > .btn { align-self: flex-start; }
.setting-row { display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-start; }
.setting-row > * { min-width: 0; }
.setting-field { display: flex; flex-direction: column; gap: 7px; }
.setting-field .field-label { margin: 0; }

.toggle-row {
  display: flex; align-items: flex-start; gap: 12px;
  margin: 0; padding: 11px 13px; cursor: pointer; font-weight: 400;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
  transition: border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.toggle-row:hover { border-color: var(--border-strong); background: var(--bg-hover); }
.toggle-row > .switch { flex: none; margin-top: 2px; }
.toggle-row > span:last-child { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.toggle-row b { font-size: .87rem; color: var(--fg); }
.toggle-row small { font-size: .76rem; line-height: 1.45; }
.toggle-row:has(input:checked) { border-color: var(--accent-line); background: var(--bg-tint); }

.choice-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; margin-bottom: 5px;
  border-radius: var(--r-sm); background: var(--bg-sunken); color: var(--fg-soft);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.choice.sel .choice-ico { background: var(--accent); color: var(--accent-fg); }

/* --- шрифты ---------------------------------------------------------------
   Образец показывает выбранные гарнитуры на месте: интерфейсную, текстовую и
   моноширинную — рядом и на одной строке текста, поэтому разницу видно до
   сохранения. Переменные --font-* переставляет живой предпросмотр. */
.font-sample {
  display: flex; flex-direction: column; gap: 10px;
  padding: 14px 16px; border-radius: var(--r-md);
  border: 1px dashed var(--border-strong); background: var(--bg-alt);
}
.font-sample-row { display: flex; align-items: baseline; gap: 12px; }
.font-sample-tag {
  flex: none; width: 78px; font-size: .71rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--fg-muted);
}
.font-sample-ui { font-family: var(--font-ui); font-size: .95rem; }
.font-sample-doc { font-family: var(--font-content); font-size: 1.02rem; line-height: 1.6; }
.font-sample-mono {
  font-family: var(--font-mono); font-size: .88rem;
  padding: 2px 7px; border-radius: var(--r-xs);
  background: var(--bg-sunken); border: 1px solid var(--border);
}
@media (max-width: 620px) {
  .font-sample-row { flex-direction: column; gap: 3px; }
  .font-sample-tag { width: auto; }
}

.font-uploads { border-top: 1px solid var(--border); }
.font-list {
  list-style: none; margin: 0; padding: 0;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-alt); overflow: hidden;
}
.font-list li {
  display: flex; align-items: center; gap: 10px; padding: 8px 12px;
}
.font-list li + li { border-top: 1px solid var(--border); }
.font-list-name { font-size: 1rem; }

/* Добавление шрифта — внутри раздела «Шрифты», а не отдельной карточкой после
   формы оформления: там она уезжала под липкую полосу «Сохранить оформление»
   и слипалась с ней. Поля принадлежат #fontUploadForm через атрибут form=. */
.font-add {
  display: flex; flex-direction: column; gap: 10px;
  padding: 13px 14px 14px; border: 1px solid var(--border);
  border-radius: var(--r-md); background: var(--bg-alt);
}
.font-add .file-drop { margin: 0; }
.font-add-foot { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.font-add-foot .muted { flex: 1 1 220px; }

/* --- аватарка сайта -------------------------------------------------------
   Показывается в трёх видах сразу: по одному значку не понять, как эмодзи
   ляжет плиткой приложения и как — строкой в шапке. Плитку рисует сервер
   (/icon-192.png), поэтому она видна ровно такой, какой попадёт на телефон. */
.logo-group { margin-bottom: 22px; }
.logo-body { display: flex; flex-direction: column; gap: 16px; }

/* По нижнему краю: макеты разной высоты (строка шапки, вкладка, плитка),
   и без выравнивания подписи под ними стояли лесенкой. */
.logo-preview { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-end; }
.logo-preview figure {
  margin: 0; display: flex; flex-direction: column; gap: 6px; min-width: 0;
  align-items: flex-start;
}
.logo-preview figcaption {
  font-size: .72rem; color: var(--fg-muted); text-transform: uppercase;
  letter-spacing: .06em; font-weight: 700;
}
.logo-shot {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 13px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev); min-width: 0;
}
.logo-shot-text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.logo-shot-text b { font-size: .9rem; letter-spacing: -.01em; }
.logo-shot-text small { color: var(--fg-muted); font-size: .73rem; }
.tab-shot {
  gap: 7px; padding: 7px 10px; background: var(--bg-alt);
  border-radius: var(--r-md) var(--r-md) 0 0; border-bottom: 0;
}
.tab-shot .logo-shot-text b { font-size: .8rem; font-weight: 500; }
.logo-tab-x { color: var(--fg-muted); font-size: .7rem; }
.logo-tile {
  display: inline-flex; align-items: center; justify-content: center;
  width: 68px; height: 68px; border-radius: 16px;
  background: var(--bg-alt); border: 1px solid var(--border);
}
.logo-tile img { width: 56px; height: 56px; border-radius: 12px; }
.logo-tile.stale { opacity: .35; }
.logo-tile, .logo-tile img { transition: opacity var(--dur) var(--ease); }
.logo-stale { display: block; font-weight: 500; text-transform: none; letter-spacing: 0; opacity: .8; }

/* Значок в предпросмотре и на странице входа: эмодзи и картинка занимают
   одну и ту же площадь, иначе строка прыгала при смене одного на другое. */
.logo-face { font-size: 22px; line-height: 1; flex: none; }
.logo-face.sm { font-size: 15px; }
.logo-face .icon-img { width: 1.15em; height: 1.15em; border-radius: 5px; vertical-align: -.18em; }

.logo-controls { display: flex; flex-direction: column; gap: 12px; }
.logo-controls .file-drop { margin: 0; }
.logo-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.logo-foot .muted { flex: 1 1 240px; }

/* Значок в шапке: картинка встаёт ровно на место эмодзи */
.brand-mark .icon-img { width: 22px; height: 22px; border-radius: 6px; vertical-align: -.22em; }
.auth-brand .icon-img { width: 1.6rem; height: 1.6rem; border-radius: 8px; vertical-align: -.24em; }

/* Полоса действий: пока настройки не сохранены, подпись меняется на
   предупреждение — иначе предпросмотр легко принять за уже применённое. */
.save-hint {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px; border-radius: 99px;
  background: color-mix(in srgb, var(--amber) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--amber) 34%, transparent);
  color: var(--amber); font-size: .78rem; font-weight: 600;
}
.save-hint .ico { flex: none; }

/* --- журнал: переключение страниц --------------------------------------- */
.pager-bar {
  display: flex; align-items: center; justify-content: center;
  gap: 10px; flex-wrap: wrap; margin-top: 16px;
}
.pager-pages { display: flex; align-items: center; gap: 3px; flex-wrap: wrap; }
.pager-num {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; padding: 0 8px;
  border: 1px solid transparent; border-radius: var(--r-sm);
  font-size: .82rem; font-variant-numeric: tabular-nums; color: var(--fg-soft);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.pager-num:hover { background: var(--bg-hover); color: var(--fg); text-decoration: none; }
.pager-num.on {
  background: var(--accent); border-color: var(--accent);
  color: var(--accent-fg); font-weight: 650;
}
.pager-num.on:hover { text-decoration: none; color: var(--accent-fg); }
.pager-gap { padding: 0 2px; color: var(--fg-muted); }
.btn.disabled { opacity: .45; pointer-events: none; }

/* --- обслуживание: состояние базы --------------------------------------- */
.health-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(228px, 1fr));
  gap: 12px; margin-bottom: 20px;
}
.health-grid > * { min-width: 0; }
.health {
  display: flex; align-items: center; gap: 12px; padding: 13px 14px;
  border: 1px solid var(--border); border-radius: var(--r-lg);
  background: var(--bg-elev); box-shadow: var(--shadow-xs);
}
.health > div { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.health b { font-size: .87rem; }
.health small { font-size: .75rem; color: var(--fg-muted); line-height: 1.4; }
.health form { margin: 0; flex: none; }
.health-ico {
  width: 38px; height: 38px; flex: none; border-radius: var(--r-md);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-sunken); color: var(--fg-soft);
}
.health.ok .health-ico { background: color-mix(in srgb, var(--green) 14%, transparent); color: var(--green); }
.health.warn { border-color: color-mix(in srgb, var(--amber) 34%, var(--border)); }
.health.warn .health-ico { background: color-mix(in srgb, var(--amber) 16%, transparent); color: var(--amber); }

/* --- узкие экраны -------------------------------------------------------- */
@media (max-width: 1180px) {
  .user-row { grid-template-columns: auto minmax(0, 1.7fr) minmax(0, 1fr) auto auto; }
  .user-groups, .user-stats { display: none; }
}
@media (max-width: 980px) {
  .master-detail { grid-template-columns: 1fr; }
  .md-list { position: static; }
  .md-items { max-height: 260px; }
}
@media (max-width: 720px) {
  .user-row {
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "ava main actions"
      "ava role actions";
    row-gap: 4px;
  }
  .user-row > .avatar { grid-area: ava; }
  .user-main { grid-area: main; }
  .user-role { grid-area: role; }
  .user-actions { grid-area: actions; }
  .user-seen, .user-state { display: none; }
  .entity-head { flex-direction: column; }
  .entity-mark, .entity-head > .space-emoji { margin-top: 0; }
  /* Строка настроек становится колонкой — и доля ширины превратилась бы
     в высоту, растянув каждое поле на треть экрана. */
  .setting-row { flex-direction: column; }
  .setting-row > .field,
  .setting-row > .field.grow,
  .setting-row > .field.narrow { flex: 0 0 auto; }
  .list-toolbar, .icons-toolbar { gap: 8px; }
}

/* ================================================ 26. Выбор цвета и файла ==
   Две вещи, которые браузер рисует по-своему и всегда мимо оформления:
   палитра input[type=color] и кнопка «Выберите файл». Обе подменены своими.
   ========================================================================= */

/* Родное поле остаётся в форме ради значения и имени, но не показывается */
input[type=color].cp-native {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  border: 0; opacity: 0; pointer-events: none; overflow: hidden; clip-path: inset(50%);
}

.color-swatch {
  width: 32px; height: 32px; flex: none; padding: 0; margin-top: 5px;
  border-radius: 50%; cursor: pointer;
  border: 1px solid var(--border);
  background:
    linear-gradient(135deg, var(--cv, var(--accent)), color-mix(in srgb, var(--cv, var(--accent)) 72%, #000));
  box-shadow: inset 0 0 0 2px var(--bg-elev), 0 0 0 0 var(--accent-soft);
  transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease-spring);
}
.color-swatch:hover { transform: scale(1.06); }
.color-swatch[aria-expanded="true"] {
  box-shadow: inset 0 0 0 2px var(--bg-elev), 0 0 0 3px var(--accent-soft);
  border-color: var(--accent);
}
.color-swatch.lg { width: 40px; height: 40px; }
/* В строке-фильтре и в шапке сущности кружок стоит рядом с подписью */
.field.narrow .color-swatch { margin-top: 5px; }

.cpop {
  position: fixed; z-index: 300; width: 236px;
  padding: 12px; border-radius: var(--r-lg);
  border: 1px solid var(--border); background: var(--bg-elev);
  box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: 10px;
  animation: cpop-in var(--dur) var(--ease-out);
}
@keyframes cpop-in { from { opacity: 0; transform: translateY(-6px) scale(.97); } }

.cpop-area {
  --hue: 250;
  position: relative; height: 132px; border-radius: var(--r-md); cursor: crosshair;
  background:
    linear-gradient(to top, #000, transparent),
    linear-gradient(to right, #fff, transparent),
    hsl(var(--hue) 100% 50%);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fg) 12%, transparent);
  touch-action: none;
}
.cpop-area i {
  position: absolute; width: 14px; height: 14px; margin: -7px 0 0 -7px;
  border-radius: 50%; border: 2px solid #fff; pointer-events: none;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35), 0 1px 3px rgba(0, 0, 0, .4);
}

.cpop-row { display: flex; align-items: center; gap: 10px; }
.cpop-preview {
  width: 30px; height: 30px; flex: none; border-radius: 50%;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fg) 14%, transparent);
}
.cpop-hue {
  position: relative; flex: 1; height: 12px; border-radius: 99px; cursor: pointer;
  touch-action: none;
  background: linear-gradient(to right, #f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fg) 12%, transparent);
}
.cpop-hue i {
  position: absolute; top: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border-radius: 50%; background: #fff; pointer-events: none;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .3), 0 1px 3px rgba(0, 0, 0, .35);
}

.cpop-hex {
  flex: 1; display: flex; align-items: center; gap: 7px; margin: 0;
  padding: 4px 8px; border-radius: var(--r-sm);
  border: 1px solid var(--border); background: var(--bg-alt);
}
.cpop-hex span { font-size: .71rem; font-weight: 700; letter-spacing: .06em; color: var(--fg-muted); }
.cpop-hex input {
  flex: 1; min-width: 0; margin: 0; padding: 0; border: 0; background: none;
  box-shadow: none; outline: none;
  font-family: var(--mono); font-size: .8rem; text-transform: lowercase; color: var(--fg);
}
.cpop-hex input:focus { border: 0; box-shadow: none; }
.cpop-hex:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.cpop-native {
  width: 30px; height: 30px; flex: none; padding: 0; font-size: 15px; line-height: 1;
  border-radius: var(--r-sm); border: 1px solid var(--border);
  background: var(--bg-alt); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.cpop-native:hover { background: var(--accent-soft); border-color: var(--accent-line); }

.cpop-presets { display: grid; grid-template-columns: repeat(8, 1fr); gap: 5px; }
.cpop-swatch {
  aspect-ratio: 1; padding: 0; border-radius: 6px; cursor: pointer;
  border: 1px solid color-mix(in srgb, var(--fg) 12%, transparent);
  transition: transform var(--dur-fast) var(--ease-spring), box-shadow var(--dur-fast) var(--ease);
}
.cpop-swatch:hover { transform: scale(1.16); box-shadow: var(--shadow-sm); }

/* --- поле выбора файла ---
   Родная кнопка «Выберите файл» приходит с системными шрифтом и рамкой и
   выбивается из всех форм. Прячем её (значение и имя поля остаются) и рисуем
   свою зону — по ней же можно перетащить файл. */
input[type=file].fd-native {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  border: 0; opacity: 0; overflow: hidden; clip-path: inset(50%);
}
.fd-zone {
  display: flex; align-items: center; gap: 11px; width: 100%; margin-top: 6px;
  padding: 11px 13px; text-align: left; font: inherit; font-size: .85rem;
  border: 1px dashed var(--border-strong); border-radius: var(--r-md);
  background: var(--bg-alt); color: var(--fg-soft); cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.fd-zone:hover, .fd-zone.over { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-text); }
.fd-zone:focus-visible { border-color: var(--accent); box-shadow: var(--shadow-glow); outline: none; }
.fd-zone-ico {
  width: 34px; height: 34px; flex: none; border-radius: var(--r-sm);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-sunken); font-size: 16px;
  transition: background var(--dur-fast) var(--ease);
}
.fd-zone.has .fd-zone-ico { background: var(--accent); color: var(--accent-fg); }
.fd-zone-text { min-width: 0; display: flex; flex-direction: column; flex: 1; }
.fd-zone-text b { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fd-zone-text small { font-size: .74rem; color: var(--fg-muted); }
.fd-zone.has {
  border-style: solid; border-color: var(--accent-line);
  background: var(--bg-tint); color: var(--fg);
}
.fd-zone-clear {
  flex: none; width: 26px; height: 26px; padding: 0; border: 0; border-radius: var(--r-sm);
  background: transparent; color: var(--fg-muted); cursor: pointer; font-size: 14px; line-height: 1;
}
.fd-zone-clear:hover { background: var(--bg-hover); color: var(--red); }

/* ================================================ 27. Кнопки в тексте =====
   Ссылка-кнопка: `[Текст](/адрес){.btn}` в Markdown. Так из одной инструкции
   делается заметный переход на другую — среди абзацев его видно сразу, в
   отличие от обычной подчёркнутой ссылки. `{.btn .ghost}` — тихий вариант.
   ========================================================================= */
.markdown-body a.btn,
.markdown-body a.kb-btn,
.ed-doc a.kb-btn {
  display: inline-flex; align-items: center; gap: 10px;
  min-height: 48px; min-width: min(300px, 100%); max-width: 100%;
  padding: 12px 18px; margin: 4px 8px 4px 0;
  border-radius: var(--r-md); border: 1px solid transparent;
  background: linear-gradient(135deg, var(--accent), var(--accent-2));
  color: var(--accent-fg); font-weight: 600; font-size: .92rem; line-height: 1.35;
  text-decoration: none; box-shadow: var(--shadow-sm);
  transition: transform var(--dur-fast) var(--ease-spring),
              box-shadow var(--dur) var(--ease), filter var(--dur-fast) var(--ease);
}
/* Стрелку прижимаем к правому краю: кнопка длинная, и посередине она
   выглядела бы случайной точкой, а не «идти сюда». */
.markdown-body a.btn::after,
.markdown-body a.kb-btn::after,
.ed-doc a.kb-btn::after {
  content: "→"; font-weight: 700; opacity: .75;
  margin-left: auto; padding-left: 12px;
  transition: transform var(--dur-fast) var(--ease);
}

/* Значок в начале кнопки: эмодзи или своя картинка (она уже в WebP —
   пережимается при загрузке). Хранится атрибутом data-icon на ссылке,
   в HTML разворачивается отдельным узлом перед текстом. */
.markdown-body a.btn .btn-ico,
.markdown-body a.kb-btn .btn-ico,
.ed-doc a.kb-btn .kb-btn-ico {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; font-size: 19px; line-height: 1;
  user-select: none;
}
.markdown-body a.btn .btn-ico img,
.markdown-body a.kb-btn .btn-ico img,
.ed-doc a.kb-btn .kb-btn-ico img {
  width: 24px; height: 24px; margin: 0; border-radius: 5px;
  object-fit: cover; display: block; box-shadow: none;
}
.markdown-body a.btn:hover,
.markdown-body a.kb-btn:hover {
  text-decoration: none; transform: translateY(-1px);
  box-shadow: var(--shadow); filter: brightness(1.05);
}
.markdown-body a.btn:hover::after,
.markdown-body a.kb-btn:hover::after { transform: translateX(3px); }

.markdown-body a.btn.ghost,
.markdown-body a.kb-btn.ghost,
.ed-doc a.kb-btn.ghost {
  background: var(--bg-alt); color: var(--accent-text);
  border-color: var(--accent-line); box-shadow: none;
}
.markdown-body a.btn.ghost:hover,
.markdown-body a.kb-btn.ghost:hover {
  background: var(--accent-soft); border-color: var(--accent); box-shadow: var(--shadow-sm);
}

/* Цвет кнопки перехода: класс рядом с .btn — [Текст](/a/b){.btn .green}.
   Заливка, наведение и тень остаются общими — меняются только две точки
   градиента, поэтому цветная кнопка ведёт себя как обычная. Текст белый:
   все пять заливок тёмные и в светлой, и в тёмной теме. */
.markdown-body a.btn.green,  .markdown-body a.kb-btn.green,  .ed-doc a.kb-btn.green,
.markdown-body a.btn.amber,  .markdown-body a.kb-btn.amber,  .ed-doc a.kb-btn.amber,
.markdown-body a.btn.red,    .markdown-body a.kb-btn.red,    .ed-doc a.kb-btn.red,
.markdown-body a.btn.blue,   .markdown-body a.kb-btn.blue,   .ed-doc a.kb-btn.blue,
.markdown-body a.btn.violet, .markdown-body a.kb-btn.violet, .ed-doc a.kb-btn.violet {
  background: linear-gradient(135deg, var(--btn-a), var(--btn-b));
  border-color: transparent; color: #fff;
}
.markdown-body a.btn.green,  .markdown-body a.kb-btn.green,  .ed-doc a.kb-btn.green  { --btn-a: #1f9d5b; --btn-b: #34c77b; }
.markdown-body a.btn.amber,  .markdown-body a.kb-btn.amber,  .ed-doc a.kb-btn.amber  { --btn-a: #b8760a; --btn-b: #e0a021; }
.markdown-body a.btn.red,    .markdown-body a.kb-btn.red,    .ed-doc a.kb-btn.red    { --btn-a: #c33c3c; --btn-b: #e8635f; }
.markdown-body a.btn.blue,   .markdown-body a.kb-btn.blue,   .ed-doc a.kb-btn.blue   { --btn-a: #2563c9; --btn-b: #4b90ec; }
.markdown-body a.btn.violet, .markdown-body a.kb-btn.violet, .ed-doc a.kb-btn.violet { --btn-a: #6d3ec9; --btn-b: #9566ee; }

/* Кнопка сама по себе абзацем — расстояние сверху и снизу как у блока */
.markdown-body p > a.btn:only-child,
.markdown-body p > a.kb-btn:only-child { margin: 4px 0; }

/* -------------------------------------------------------------------------
   Вложенный файл — карточкой, а не строчной ссылкой. Документ, прикреплённый
   к тексту, должен читаться как файл: значок, имя, подсказка с размером.
   В разметке это хвост {.file} — на сервере attr_list даёт class="file",
   в редакторе тот же узел носит kb-file.
   ========================================================================= */
.markdown-body a.file,
.markdown-body a.kb-file,
.ed-doc a.kb-file {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 9px 14px; margin: 3px 6px 3px 0; max-width: 100%;
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-alt); color: var(--fg);
  font-weight: 500; font-size: .9rem; line-height: 1.3;
  text-decoration: none; vertical-align: middle;
  transition: border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.markdown-body a.file::before,
.markdown-body a.kb-file::before,
.ed-doc a.kb-file::before {
  content: "📎"; font-size: 1rem; line-height: 1; flex: none;
}
.markdown-body a.file:hover,
.markdown-body a.kb-file:hover {
  text-decoration: none; background: var(--bg-elev);
  border-color: var(--accent-line); box-shadow: var(--shadow-sm);
}
.markdown-body p > a.file:only-child,
.markdown-body p > a.kb-file:only-child { margin: 4px 0; }
/* В редакторе карточка остаётся редактируемым текстом — имя можно поправить */
.ed-doc a.kb-file { cursor: text; }

/* В редакторе кнопка остаётся редактируемым текстом, но выглядит как кнопка */
.ed-doc a.kb-btn { cursor: text; }

@media print {
  .markdown-body a.btn, .markdown-body a.kb-btn {
    background: none; color: #000; border: 1px solid #999; box-shadow: none;
  }
}

/* ================================================ 28. Найденное на странице ==
   Из результата поиска человек попадает не «на страницу», а на нужное место:
   совпадения подсвечиваются, первое подводится к глазам, сверху висит полоса
   с их числом. Через несколько секунд подсветка гаснет сама — она нужна,
   чтобы найти, а не чтобы жить в тексте.
   ========================================================================= */
mark.kb-hit {
  background: color-mix(in srgb, var(--amber) 34%, transparent);
  color: inherit; border-radius: 3px; padding: 0 1px;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--amber) 30%, transparent);
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
mark.kb-hit.on {
  background: var(--accent);
  color: var(--accent-fg);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
@media (prefers-reduced-motion: no-preference) {
  mark.kb-hit.on { animation: hit-pulse 620ms var(--ease-out); }
}
@keyframes hit-pulse {
  0%   { box-shadow: 0 0 0 0 var(--accent-glow); }
  60%  { box-shadow: 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 0 3px var(--accent-soft); }
}
mark.kb-hit.gone {
  background: transparent; color: inherit; box-shadow: none;
}

.kb-findbar {
  position: fixed; z-index: 260;
  top: calc(var(--topbar-h) + 12px); left: 50%; transform: translateX(-50%);
  display: flex; align-items: center; gap: 8px;
  max-width: min(92vw, 560px);
  padding: 6px 8px 6px 14px;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--bg-elev); box-shadow: var(--shadow);
  font-size: .82rem; color: var(--fg-soft);
}
.kb-findbar[hidden] { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .kb-findbar { animation: findbar-in 220ms var(--ease-out); }
}
@keyframes findbar-in { from { opacity: 0; transform: translate(-50%, -10px); } }
.kb-findbar.gone { opacity: 0; transition: opacity 400ms var(--ease); }
.kb-findbar .fb-label { color: var(--fg-muted); flex: none; }
.kb-findbar .fb-q {
  color: var(--fg); font-weight: 650; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kb-findbar .fb-count { color: var(--fg-muted); flex: none; white-space: nowrap; }
.kb-findbar .fb-btn {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid transparent; background: none; color: var(--fg-soft);
  cursor: pointer; font: inherit; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.kb-findbar .fb-btn:hover { background: var(--bg-hover); color: var(--fg); }
.kb-findbar .fb-x { margin-left: 2px; border-left: 1px solid var(--border); border-radius: 0 999px 999px 0; width: 30px; }

@media (max-width: 820px) {
  /* Полоса «1 из 7» переезжает вниз, но выше нижней панели — иначе
     она ложится ровно на кнопки. */
  .kb-findbar {
    top: auto;
    bottom: calc(var(--mobnav-h, 60px) + var(--safe-b, 0px) + 12px);
    left: 10px; right: 10px; width: auto;
  }
  .kb-findbar .fb-label { display: none; }
}
@media print {
  .kb-findbar { display: none; }
  mark.kb-hit { background: none; box-shadow: none; }
}

/* ================================================ 29. Таблица в редакторе ==
   Размер выбирается сеткой, а не вводом чисел; дальше таблица правится на
   месте: ручки над колонками и слева от строк, «+» между ними и панель
   с выравниванием над таблицей.
   ========================================================================= */

/* --- выбор размера --- */
.kb-tablepick {
  position: fixed; z-index: 160; padding: 10px;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-lg);
  animation: pop 120ms var(--ease);
}
.kb-tablepick[hidden] { display: none; }
.tp-grid {
  display: grid; grid-template-columns: repeat(10, 20px);
  grid-auto-rows: 20px; gap: 3px;
}
.tp-cell {
  border: 1px solid var(--border-strong); border-radius: 3px;
  background: var(--bg-sunken); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.tp-cell.on { background: var(--accent-mild); border-color: var(--accent-line); }
.tp-cell.on.head { background: var(--accent); border-color: var(--accent); }
.tp-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  margin-top: 9px; padding-top: 8px; border-top: 1px solid var(--border);
  font-size: .8rem;
}
.tp-size { color: var(--fg); font-variant-numeric: tabular-nums; }
.tp-check {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-size: .78rem; font-weight: 500; color: var(--fg-soft); cursor: pointer;
}
.tp-check input { width: auto; margin: 0; }

/* --- ручки строк и колонок ---
   Ручки и «плюсы» видны, пока каретка стоит в таблице: сама .ed-tt живёт
   ровно столько. Раньше их показывал .ed-tt:hover, но у контейнера
   pointer-events: none — навести на него нельзя, и подсветка включалась,
   только если курсор случайно попадал на саму невидимую ручку в 9 пикселей.
   Найти строки и колонки было практически невозможно. */
.ed-tt { position: absolute; z-index: 6; pointer-events: none; }
.ed-tt[hidden] { display: none; }
.ed-tt .tt-cols, .ed-tt .tt-rows { position: absolute; inset: 0; }

.ed-tt .tt-h {
  position: absolute; pointer-events: auto; cursor: pointer; padding: 0;
  border: 1px solid var(--border-strong); background: var(--bg-sunken);
  border-radius: 3px; opacity: .4;
  transition: opacity var(--dur) var(--ease), background var(--dur-fast) var(--ease);
}
.ed-tt .tt-h:not(.row) { top: -13px; height: 9px; }
.ed-tt .tt-h.row { left: -13px; width: 9px; }
.ed-tt .tt-h:hover, .ed-tt .tt-h:focus-visible { opacity: 1; }
.ed-tt .tt-h:hover { background: var(--accent); border-color: var(--accent); }

.ed-tt .tt-ins {
  position: absolute; pointer-events: auto; cursor: pointer;
  width: 17px; height: 17px; padding: 0; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: 50%;
  background: var(--bg-elev); color: var(--fg-soft);
  font: inherit; font-size: 13px; opacity: .3;
  transition: opacity var(--dur) var(--ease), background var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease-spring);
}
.ed-tt .tt-ins.col { top: -26px; transform: translateX(-50%); }
.ed-tt .tt-ins.row { left: -26px; transform: translateY(-50%); }
.ed-tt .tt-ins:hover {
  opacity: 1; background: var(--accent); color: var(--accent-fg); border-color: var(--accent);
}
.ed-tt .tt-ins.col:hover { transform: translateX(-50%) scale(1.12); }
.ed-tt .tt-ins.row:hover { transform: translateY(-50%) scale(1.12); }

.ed-tt .tt-band {
  position: absolute; pointer-events: none; border-radius: var(--r-xs);
  background: var(--accent-soft); box-shadow: inset 0 0 0 1.5px var(--accent-line);
}
.ed-tt .tt-band[hidden] { display: none; }

/* --- панель таблицы --- */
.ed-tablebar {
  position: absolute; z-index: 7; display: flex; align-items: center; gap: 1px;
  padding: 3px; background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow);
  animation: pop 120ms var(--ease);
}
.ed-tablebar[hidden] { display: none; }
.ed-tablebar .sep { width: 1px; height: 17px; background: var(--border); margin: 0 4px; }
.ed-tablebar .tb { font-size: 13px; }
.ed-tablebar .tb small { font-size: .58rem; margin-left: 2px; letter-spacing: .02em; }
.ed-tablebar .tb.danger { color: var(--danger); }
.ed-tablebar .tb.danger:hover { background: color-mix(in srgb, var(--danger) 12%, transparent); }

@media (max-width: 820px) {
  /* на узком экране ручки только мешают: таблица правится панелью */
  .ed-tt { display: none; }
  .ed-tablebar { flex-wrap: wrap; max-width: calc(100% - 24px); }
}

/* ================================================ 30. Диаграммы ============
   Рисунок собирается скриптом в SVG, а цвета берутся отсюда: одна и та же
   диаграмма сама переодевается в тёмную тему и печатается без сюрпризов.
   Каждая фигура несёт класс kd-c-<цвет>, из него берутся заливка (--kdf)
   и линия (--kdc) — дальше их используют и фигура, и связь, и стрелка.
   ========================================================================= */
.kd-svg {
  display: block; max-width: 100%; height: auto;
  font-family: var(--font);
}
.kd-node, .kd-edge { --kdc: var(--border-strong); --kdf: var(--bg-elev); }
.kd-c-plain   { --kdc: var(--border-strong); --kdf: transparent; }
.kd-c-default { --kdc: var(--border-strong); --kdf: var(--bg-elev); }
.kd-c-accent  { --kdc: var(--accent); --kdf: color-mix(in srgb, var(--accent) 13%, var(--bg)); }
.kd-c-blue    { --kdc: var(--blue);   --kdf: color-mix(in srgb, var(--blue) 13%, var(--bg)); }
.kd-c-green   { --kdc: var(--green);  --kdf: color-mix(in srgb, var(--green) 14%, var(--bg)); }
.kd-c-amber   { --kdc: var(--amber);  --kdf: color-mix(in srgb, var(--amber) 16%, var(--bg)); }
.kd-c-red     { --kdc: var(--red);    --kdf: color-mix(in srgb, var(--red) 13%, var(--bg)); }
.kd-c-violet  { --kdc: var(--accent-2); --kdf: color-mix(in srgb, var(--accent-2) 13%, var(--bg)); }
.kd-c-gray    { --kdc: var(--fg-muted); --kdf: var(--bg-sunken); }
.kd-edge.kd-c-default { --kdc: var(--fg-soft); }

.kd-shape { fill: var(--kdf); stroke: var(--kdc); stroke-width: 1.6; }
.kd-line { fill: none; stroke: var(--kdc); stroke-width: 1.7; stroke-linejoin: round; }
.kd-line.dash { stroke-dasharray: 6 4; }
.kd-arrow { fill: var(--kdc); stroke: none; }
.kd-hit { fill: none; stroke: transparent; stroke-width: 14; }

.kd-label {
  width: 100%; height: 100%; box-sizing: border-box;
  display: flex; align-items: center;
  color: var(--fg); line-height: 1.25; overflow: hidden;
  overflow-wrap: anywhere; hyphens: auto;
}
.kd-label.b { font-weight: 700; }
.kd-label.i { font-style: italic; }
.kd-elabelbox {
  height: 100%; display: flex; align-items: center; justify-content: center;
}
.kd-elabel {
  max-width: 100%;
  padding: 1px 6px; border-radius: 5px;
  background: var(--bg); color: var(--fg-soft);
  font-size: 12px; line-height: 1.5;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--kdc) 35%, transparent);
}

/* --- диаграмма на странице --- */
.kb-diagram-wrap, .kb-diagram-view {
  margin: 18px 0; overflow-x: auto;
}
.kb-diagram-view { text-align: center; }
.kb-diagram-view .kd-svg { margin: 0 auto; }
pre.kb-diagram {                       /* до отрисовки скриптом */
  opacity: 0; height: 0; overflow: hidden; margin: 0; padding: 0; border: 0;
}
.kd-broken { color: var(--fg-muted); font-size: .85rem; }

/* --- блок диаграммы в редакторе --- */
.kb-dgm-block { cursor: pointer; }
.kb-dgm-block .kb-raw-tag { cursor: pointer; }
.kb-dgm-block .kb-dgm-canvas { padding: 6px 0; text-align: center; }
.kb-dgm-block:hover { outline: 2px solid var(--accent-line); outline-offset: 3px; border-radius: var(--r-sm); }

/* ================================================ 31. Окно диаграммы ======= */
.kd-back {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(10, 14, 20, .55); backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; padding: 2vh 2vw;
  animation: fade-in 140ms var(--ease);
}
.kd-win {
  width: min(1320px, 100%); height: min(92vh, 100%);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  animation: pop 160ms var(--ease);
}
.kd-head {
  display: flex; align-items: center; gap: 8px; flex: none; flex-wrap: wrap;
  padding: 9px 13px; border-bottom: 1px solid var(--border); background: var(--bg-alt);
}
.kd-title { font-size: .95rem; }
.kd-grow { flex: 1; }
.kd-hgroup {
  display: flex; align-items: center; gap: 2px;
  padding: 2px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-elev);
}
.kd-b {
  min-width: 28px; height: 26px; padding: 0 7px;
  border: 0; border-radius: var(--r-xs); background: none; color: var(--fg-soft);
  font: inherit; font-size: .9rem; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.kd-b:hover:not(:disabled) { background: var(--bg-hover); color: var(--fg); }
.kd-b:disabled { opacity: .35; cursor: default; }
.kd-b.danger { color: var(--danger); border: 1px solid var(--border); }
.kd-b.danger:hover:not(:disabled) { background: color-mix(in srgb, var(--danger) 12%, transparent); }
.kd-zoom { min-width: 46px; text-align: center; font-size: .78rem; color: var(--fg-muted); font-variant-numeric: tabular-nums; }

.kd-body { flex: 1; display: flex; min-height: 0; }
.kd-palette {
  width: 172px; flex: none; overflow-y: auto; padding: 10px;
  border-right: 1px solid var(--border); background: var(--bg-alt);
}
.kd-ptitle {
  font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--fg-muted); margin-bottom: 8px;
}
.kd-pgrid { display: flex; flex-direction: column; gap: 3px; }
.kd-shapebtn {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 6px 8px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; color: var(--fg); font: inherit; font-size: .8rem;
  cursor: grab; text-align: left;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.kd-shapebtn:hover { background: var(--bg-hover); border-color: var(--border); }
.kd-shapebtn:active { cursor: grabbing; }
.kd-shapebtn svg { flex: none; color: var(--fg-soft); }

.kd-stage { flex: 1; overflow: auto; background: var(--bg-sunken); }
.kd-holder {
  position: relative; display: inline-block; margin: 20px;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background-color: var(--bg);
  background-image: radial-gradient(circle, var(--border) 1px, transparent 1.2px);
  background-size: var(--kd-grid, 10px) var(--kd-grid, 10px);
}
.kd-editing .kd-node { cursor: move; }
.kd-editing .kd-edge { cursor: pointer; }
.kd-selbox { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-dasharray: 4 3; }
.kd-handle { fill: var(--bg-elev); stroke: var(--accent); stroke-width: 1.4; cursor: nwse-resize; }
.kd-port { fill: var(--bg-elev); stroke: var(--accent); stroke-width: 1.5; cursor: crosshair; }
.kd-port:hover { fill: var(--accent); }
.kd-ghost { fill: none; stroke: var(--accent); stroke-width: 1.6; stroke-dasharray: 5 4; }
/* Связь подведена к блоку: показываем её сплошной и по настоящей геометрии —
   это уже не «куда тянем», а «что получится», поэтому пунктир лишний. */
.kd-ghost-snap { stroke-dasharray: none; stroke-width: 2.2; }
/* Сам блок-цель обводим заливкой, чтобы было видно, к чему прицепится. */
.kd-droptarget {
  fill: color-mix(in srgb, var(--accent) 14%, transparent);
  stroke: var(--accent); stroke-width: 2;
}
.kd-seledge { fill: none; stroke: var(--accent); stroke-width: 6; opacity: .25; stroke-linecap: round; }
.kd-inline {
  position: absolute; z-index: 5; margin: 0; padding: 4px 6px;
  border: 2px solid var(--accent); border-radius: 5px;
  background: var(--bg-elev); color: var(--fg);
  font: inherit; line-height: 1.25; resize: none; overflow: hidden;
  box-shadow: var(--shadow);
}

.kd-props { width: 274px; flex: none; overflow-y: auto; padding: 12px; border-left: 1px solid var(--border); }
.kd-props .kd-ptitle { margin-top: 16px; }
.kd-props .kd-ptitle:first-child { margin-top: 0; }
.kd-empty { color: var(--fg-muted); font-size: .8rem; line-height: 1.5; }
.kd-row { margin-bottom: 12px; }
.kd-rlabel {
  display: block; margin-bottom: 5px;
  font-size: .72rem; font-weight: 650; color: var(--fg-soft);
}
.kd-chips, .kd-fmt { display: flex; flex-wrap: wrap; gap: 4px; }
.kd-chip {
  min-width: 30px; height: 30px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-elev); color: var(--fg-soft);
  font: inherit; font-size: .78rem; line-height: 1; cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.kd-chip:hover { background: var(--bg-hover); color: var(--fg); }
.kd-chip.on { border-color: var(--accent); color: var(--accent-text); background: var(--accent-soft); }
.kd-chip svg { display: block; }
.kd-sw {
  width: 15px; height: 15px; border-radius: 4px; display: block;
  background: var(--kdf); border: 1.5px solid var(--kdc);
}
.kd-text {
  width: 100%; margin: 0; font-size: .82rem;
}
.kd-size { display: flex; gap: 8px; }
.kd-num { display: flex; flex-direction: column; gap: 3px; margin: 0; flex: 1; font-size: .7rem; color: var(--fg-muted); font-weight: 500; }
.kd-num input { margin: 0; font-size: .82rem; }

.kd-hint {
  flex: none; padding: 7px 14px; border-top: 1px solid var(--border);
  background: var(--bg-alt); color: var(--fg-muted); font-size: .74rem;
}

@media (max-width: 900px) {
  .kd-back { padding: 0; }
  .kd-win { width: 100%; height: 100%; border-radius: 0; border: 0; }
  .kd-palette { width: 74px; }
  .kd-shapebtn span { display: none; }
  .kd-shapebtn { justify-content: center; }
  .kd-props { width: 210px; }
  .kd-hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .kd-back, .kd-win { animation: none; }
}
@media print {
  .kd-back { display: none; }
  .kb-diagram-view { break-inside: avoid; }
}

/* ================================================ 32. Фоторедактор ========
   Картинка правится не «где-то в графическом редакторе», а прямо здесь:
   кадр, поворот, размер и пометки — в одном окне, как у диаграмм.        */
.kp-back {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(10, 14, 20, .55); backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center; padding: 2vh 2vw;
  animation: fade-in 140ms var(--ease);
}
.kp-win {
  width: min(1240px, 100%); height: min(92vh, 100%);
  display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg-elev); border: 1px solid var(--border);
  border-radius: var(--r-xl); box-shadow: var(--shadow-lg);
  animation: pop 160ms var(--ease);
}
.kp-head {
  display: flex; align-items: center; gap: 8px; flex: none; flex-wrap: wrap;
  padding: 9px 13px; border-bottom: 1px solid var(--border); background: var(--bg-alt);
}
.kp-title { font-size: .95rem; }
.kp-grow { flex: 1; }
.kp-size {
  font-size: .74rem; color: var(--fg-muted); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.kp-hgroup {
  display: flex; align-items: center; gap: 2px;
  padding: 2px; border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-elev);
}
.kp-b {
  min-width: 28px; height: 26px; padding: 0 7px;
  border: 0; border-radius: var(--r-xs); background: none; color: var(--fg-soft);
  font: inherit; font-size: .95rem; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.kp-b:hover:not(:disabled) { background: var(--bg-hover); color: var(--fg); }
.kp-b:disabled { opacity: .35; cursor: default; }

.kp-body { flex: 1; display: flex; min-height: 0; }
.kp-tools {
  width: 176px; flex: none; overflow-y: auto; padding: 10px;
  border-right: 1px solid var(--border); background: var(--bg-alt);
}
.kp-ptitle {
  font-size: .72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--fg-muted); margin: 14px 0 8px;
}
.kp-ptitle:first-child { margin-top: 0; }
.kp-tgrid { display: flex; flex-direction: column; gap: 3px; }
.kp-tool {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 6px 8px; border: 1px solid transparent; border-radius: var(--r-sm);
  background: none; color: var(--fg); font: inherit; font-size: .8rem;
  cursor: pointer; text-align: left;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.kp-tool:hover { background: var(--bg-hover); border-color: var(--border); }
.kp-tool.on { background: var(--accent-soft); color: var(--accent-text); border-color: var(--accent-line); }
.kp-ticon {
  width: 24px; height: 24px; flex: none; border-radius: var(--r-xs);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--bg-elev); border: 1px solid var(--border); font-size: .82rem;
}

.kp-stage {
  flex: 1; min-width: 0; overflow: auto; background: var(--bg-sunken);
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.kp-holder { position: relative; line-height: 0; box-shadow: var(--shadow); }
.kp-canvas {
  display: block; max-width: 100%; touch-action: none; cursor: crosshair;
  background-color: #fff;
  background-image:
    linear-gradient(45deg, #e6e8ec 25%, transparent 25%, transparent 75%, #e6e8ec 75%),
    linear-gradient(45deg, #e6e8ec 25%, transparent 25%, transparent 75%, #e6e8ec 75%);
  background-size: 18px 18px; background-position: 0 0, 9px 9px;
}
.kp-inline-wrap { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.kp-inline {
  position: absolute; margin: 0; padding: 2px 6px; min-width: 140px; pointer-events: auto;
  border: 2px solid var(--accent); border-radius: 5px;
  background: var(--bg-elev); font: inherit; font-weight: 600; line-height: 1.25;
  box-shadow: var(--shadow);
}

.kp-props { width: 246px; flex: none; overflow-y: auto; padding: 12px; border-left: 1px solid var(--border); }
.kp-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.kp-chip {
  min-width: 30px; height: 28px; padding: 0 9px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: var(--r-sm);
  background: var(--bg-elev); color: var(--fg-soft);
  font: inherit; font-size: .78rem; line-height: 1; cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.kp-chip:hover { background: var(--bg-hover); color: var(--fg); }
.kp-chip.on { border-color: var(--accent); color: var(--accent-text); background: var(--accent-soft); }
.kp-sw {
  width: 26px; height: 26px; padding: 0; cursor: pointer;
  border: 2px solid var(--border); border-radius: var(--r-sm);
}
.kp-sw.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-line); }
.kp-slider { display: flex; align-items: center; gap: 9px; }
.kp-slider input { flex: 1; margin: 0; }
.kp-val {
  flex: none; min-width: 48px; text-align: right;
  font-size: .76rem; color: var(--fg-muted); font-variant-numeric: tabular-nums;
}
.kp-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.kp-hint {
  flex: none; padding: 7px 14px; border-top: 1px solid var(--border);
  background: var(--bg-alt); color: var(--fg-muted); font-size: .74rem;
}

/* панелька над картинкой в редакторе: открыть фоторедактор, убрать файл */
.ed-imgbar {
  position: fixed; z-index: 120; display: flex; align-items: center; gap: 3px;
  padding: 3px; border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--bg-elev); box-shadow: var(--shadow-lg);
}
.ed-imgbar[hidden] { display: none; }
.ed-doc img.kb-img-sel { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--r-xs); }

/* Квадратики по углам выделенной картинки — за них меняют размер.
   Рамка накладывается поверх картинки и сама мышь не ловит (иначе не
   выделить текст рядом), а ловят её только сами квадратики. */
.ed-grips { position: absolute; z-index: 8; pointer-events: none; }
.ed-grips[hidden] { display: none; }
.ed-grip {
  position: absolute; width: 11px; height: 11px; pointer-events: auto;
  background: var(--bg-elev); border: 2px solid var(--accent);
  border-radius: 3px; box-shadow: var(--shadow-xs);
}
.ed-grip.nw { left: -6px; top: -6px; cursor: nwse-resize; }
.ed-grip.ne { right: -6px; top: -6px; cursor: nesw-resize; }
.ed-grip.se { right: -6px; bottom: -6px; cursor: nwse-resize; }
.ed-grip.sw { left: -6px; bottom: -6px; cursor: nesw-resize; }
.ed-grip-size {
  position: absolute; left: 50%; bottom: -12px; transform: translateX(-50%);
  padding: 2px 7px; border-radius: var(--r-sm);
  background: var(--accent); color: var(--accent-fg);
  font-size: .73rem; font-weight: 600; white-space: nowrap;
  pointer-events: none;
}

/* Картинка с заданной шириной не должна плющиться: высоту считает браузер */
.ed-doc img[width], .markdown-body img[width] { height: auto; max-width: 100%; }

@media (max-width: 900px) {
  .kp-back { padding: 0; }
  .kp-win { width: 100%; height: 100%; border-radius: 0; border: 0; }
  .kp-tools { width: 66px; }
  .kp-tool span:not(.kp-ticon) { display: none; }
  .kp-tool { justify-content: center; }
  .kp-props { width: 200px; }
  .kp-hint { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .kp-back, .kp-win { animation: none; }
}
@media print {
  .kp-back, .ed-imgbar, .ed-grips { display: none; }
}


/* ================================================ 31. Телефон ==============
   Ступень 820 px и правила для тач-экрана держатся в конце файла нарочно:
   при равной специфичности побеждает правило, стоящее позже, а компонентные
   разделы (дерево, просмотрщик вложений, администрирование) объявлены ниже
   раздела «Адаптив». Пока эти правила стояли там, `.tree-add { width: 21px }`
   из раздела про дерево перебивал телефонные 32 px, и кнопка «+» на строке
   оставалась размером с курсор — пальцем в неё было не попасть.
   ========================================================================= */
/* Второе условие — телефон, повёрнутый набок. По ширине он не телефон
   (iPhone 14 в альбоме — 844 px), а по высоте на нём 390 px: раскладка с
   панелью на 288 px и шапкой оставляла бы полоску текста. Проверка
   `pointer: coarse` не даёт правилам сработать в низком окне на десктопе. */
@media (max-width: 820px),
       (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  :root {
    --topbar-h: 52px;
    --mobnav-h: 60px;
    --tap: 44px;                       /* минимальная цель для пальца */
    --safe-t: env(safe-area-inset-top, 0px);
    --safe-b: env(safe-area-inset-bottom, 0px);
    --safe-l: env(safe-area-inset-left, 0px);
    --safe-r: env(safe-area-inset-right, 0px);
  }

  .only-mobile { display: inline-flex !important; }
  .no-mobile { display: none !important; }
  .topnav { display: none; }

  /* Серый прямоугольник от браузера поверх своей подсветки только мешает,
     а touch-action: manipulation убирает задержку в 300 мс перед кликом. */
  a, button, summary, label, [role="button"] { -webkit-tap-highlight-color: transparent; }
  a, button, summary, label, .btn, .icon-btn, .tb, .tree-row { touch-action: manipulation; }

  /* iOS увеличивает страницу, когда кегль поля меньше 16 px, и обратно её
     уже не возвращает. Поэтому во всех полях ровно 16. */
  input[type=text], input[type=password], input[type=email], input[type=number],
  input[type=search], input[type=tel], input[type=url], select, textarea {
    font-size: 16px;
  }

  /* --- шапка ---
     Название базы остаётся (по нему понятно, где ты), подпись уходит:
     на 375 px она вытесняла поиск. Шапка прячется при листании вниз и
     возвращается при листании вверх — экран отдан тексту. */
  .topbar {
    height: calc(var(--topbar-h) + var(--safe-t));
    padding: var(--safe-t) calc(8px + var(--safe-r)) 0 calc(6px + var(--safe-l));
    gap: 4px;
    transition: transform 240ms var(--ease);
  }
  body.tb-hide .topbar { transform: translateY(calc(-100% - 2px)); }
  .brand-text { display: flex; }
  .brand-text small { display: none; }
  .brand-text b { font-size: .92rem; }
  .brand { min-width: 0; overflow: hidden; }
  .topbar .icon-btn { width: 40px; height: 40px; }

  /* --- шторка с деревом страниц ---
     Во весь экран, поверх шапки: на 375 px «панель ниже шапки» отдавала
     половину ширины полупрозрачному фону, а закрыть её было нечем. */
  .layout, .layout.has-aside { grid-template-columns: minmax(0, 1fr); }
  html.sidebar-collapsed { --sidebar-w: 0px; }
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 195;
    width: min(87vw, 348px); max-width: none; height: 100dvh;
    opacity: 1; pointer-events: auto; background: var(--bg);
    padding: var(--safe-t) 0 0 var(--safe-l);
    border-right: 0; box-shadow: var(--shadow-lg);
    transform: translateX(-102%);
    transition: transform 260ms var(--ease-out);
    overscroll-behavior: contain;
  }
  body.sidebar-open { overflow: hidden; }
  body.sidebar-open .sidebar { transform: none; }
  body.sidebar-open .sidebar-backdrop {
    display: block; position: fixed; inset: 0;
    background: var(--scrim); z-index: 190; animation: fade-in 180ms var(--ease);
  }
  .drawer-head {
    display: flex; align-items: center; gap: 10px;
    position: sticky; top: 0; z-index: 3;
    height: 52px; padding: 0 6px 0 14px; flex: none;
    background: var(--bg); border-bottom: 1px solid var(--border);
  }
  .drawer-head b { flex: 1; min-width: 0; font-size: .95rem; }
  .drawer-head .icon-btn { width: 40px; height: 40px; }
  .sidebar-inner {
    width: 100%; min-width: 0; padding: 12px 12px calc(20px + var(--safe-b));
    min-height: calc(100dvh - 52px - var(--safe-t));
  }

  /* Строки дерева и списков — под палец, а не под курсор.
     Кнопки «+» и «⋯» показываются всегда: наводить на узком экране нечем. */
  .tree-link { padding: 9px 2px; font-size: .93rem; }
  .tree-caret { width: 30px; height: 40px; }
  /* Кнопки встают в строку, а не поверх неё: на широком экране они всплывают
     по наведению и подложены градиентом, здесь же видны всегда — и длинное
     название уезжало прямо под них. В потоке название просто обрезается. */
  .tree-tools {
    position: static; opacity: 1; pointer-events: auto;
    background: none; padding-left: 2px;
  }
  .tree-row.active > .tree-tools { background: none; }
  .tree-add, .tree-more { width: 32px; height: 32px; }
  .side-list a { padding: 10px 10px; font-size: .93rem; }
  .space-current { padding: 10px 9px; }
  .side-search-field, .tree-filter { height: 42px; }
  .side-search-kbd { display: none; }
  /* Подсказка сжимается под клавиатуру: она занимает нижнюю половину экрана,
     и панель на 60vh наполовину уходила под неё. */
  .side-search-panel { max-height: min(46dvh, 380px); }
  .ss-item { padding: 11px 9px; }
  .side-search-foot span { display: none; }
  .side-search-foot .grow-right { font-size: .82rem; padding: 4px 0; }
  .side-foot { padding-top: 14px; font-size: .88rem; }
  .side-foot a, .side-foot button { padding: 8px 0; }

  /* --- нижняя полоса действий --- */
  .mobnav {
    display: flex; align-items: stretch;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 150;
    height: calc(var(--mobnav-h) + var(--safe-b));
    padding: 0 calc(2px + var(--safe-r)) var(--safe-b) calc(2px + var(--safe-l));
    background: var(--bg); border-top: 1px solid var(--border);
  }
  .mobnav-item {
    flex: 1 1 0; min-width: 0; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 3px;
    border: 0; background: none; padding: 4px 2px; cursor: pointer;
    color: var(--fg-muted); font: inherit; font-size: .64rem; font-weight: 600;
    line-height: 1.2; text-decoration: none; border-radius: var(--r-md);
    transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
  }
  .mobnav-item span {
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .mobnav-item .ico { color: inherit; }
  .mobnav-item:hover { text-decoration: none; color: var(--fg-soft); }
  .mobnav-item:active { background: var(--bg-hover); }
  .mobnav-item.on { color: var(--accent-text); }
  .dropdown.open > .mobnav-item { color: var(--accent-text); }
  /* «Создать» — единственное действие, которое должно бросаться в глаза */
  .mobnav-item.accent .ico {
    width: 32px; height: 32px; border-radius: var(--r-md);
    padding: 5px; background: var(--accent); color: var(--accent-fg);
    box-shadow: var(--shadow-sm);
  }
  .mobnav-item.accent { color: var(--accent-text); }
  .mobnav-more { display: flex; flex: 1 1 0; min-width: 0; }
  .mobnav-more > .mobnav-item { width: 100%; }
  .mobnav-item .avatar.sm { width: 21px; height: 21px; font-size: .58rem; }
  body.editor-mode .mobnav, body.zen .mobnav { display: none; }

  /* Место под нижнюю полосу: иначе она накрывает последние строки текста */
  .content { padding-bottom: calc(var(--mobnav-h) + var(--safe-b)); }
  .fab-top {
    right: calc(14px + var(--safe-r));
    bottom: calc(var(--mobnav-h) + var(--safe-b) + 14px);
    width: 44px; height: 44px;
  }
  .toasts.pos-bottom { bottom: calc(var(--mobnav-h) + var(--safe-b) + 10px); }
  .toasts.pos-top { top: calc(var(--topbar-h) + var(--safe-t) + 10px); }

  /* --- выпадающие меню приезжают снизу --- */
  /* Меню у верхнего края экрана, шириной в треть и строками по 30 px —
     самая неудобная вещь на телефоне. Здесь любое такое меню становится
     шторкой во всю ширину: крупные строки, ручка сверху, закрытие
     нажатием мимо. */
  .dropdown-menu, .dropdown-menu.right, .dropdown-menu.up, .dropdown-menu.wide {
    position: fixed;
    top: auto; right: 0; bottom: 0; left: 0;
    width: auto; min-width: 0; max-width: none;
    max-height: min(74dvh, 620px); overflow-y: auto; overscroll-behavior: contain;
    z-index: 210;
    padding: 6px 10px calc(10px + var(--safe-b));
    border-radius: var(--r-xl) var(--r-xl) 0 0;
    border-bottom: 0; box-shadow: var(--shadow-lg);
    animation: sheet-up 240ms var(--ease-out);
  }
  .dropdown-menu::before {
    content: ""; display: block; flex: none;
    width: 40px; height: 4px; margin: 4px auto 8px;
    border-radius: 99px; background: var(--border-strong);
  }
  .dropdown-menu a, .dropdown-menu button {
    padding: 12px 12px; font-size: .95rem; border-radius: var(--r-md); gap: 12px;
    min-height: var(--tap);
  }
  .dropdown-menu a:active, .dropdown-menu button:active { background: var(--bg-hover); }
  .dropdown-menu .dd-label { padding: 10px 12px 4px; }
  .dropdown-menu kbd { display: none; }
  /* Затемнение под шторкой.
     Порядок наложения считается внутри ближайшего «слоя» — панели с
     собственным z-index. Меню-шторка почти всегда живёт в такой панели
     (нижняя полоса, боковая панель, панель редактора), и её z-index: 210
     действует только внутри панели: снаружи всё меню лежит на уровне самой
     панели — ниже затемнения. Поэтому экран темнел, а меню оставалось под
     затемнением: невидимое и ненажимаемое.
     Лечится двумя правилами: панель с открытым меню поднимается над всем
     остальным (.sheet-host), а затемнение app.js переносит внутрь меню —
     там оно снова оказывается под ним и заодно гасит саму панель. */
  body .sheet-host { z-index: 220; }
  .sheet-backdrop.on {
    display: block; position: fixed; inset: 0; z-index: 205;
    background: var(--scrim); animation: fade-in 160ms var(--ease);
    touch-action: none;               /* страница под шторкой не листается */
  }
  body.sheet-open { overflow: hidden; }
  @keyframes sheet-up { from { transform: translateY(100%); } }

  /* --- окна тоже снизу --- */
  .modal-backdrop { align-items: flex-end; padding: 0; }
  .modal {
    max-width: none; width: 100%; max-height: 90dvh;
    border-radius: var(--r-xl) var(--r-xl) 0 0; border-bottom: 0;
    animation: sheet-up 260ms var(--ease-out);
  }
  .modal-head { position: relative; padding: 20px 10px 12px 16px; }
  .modal-head::before {
    content: ""; position: absolute; left: 50%; top: 8px;
    width: 40px; height: 4px; margin-left: -20px;
    border-radius: 99px; background: var(--border-strong);
  }
  .modal-head .icon-btn { width: 40px; height: 40px; }
  .modal-body { padding: 14px 16px calc(14px + var(--safe-b)); }
  .modal-foot { padding: 12px 16px calc(12px + var(--safe-b)); }
  .modal-foot .btn { flex: 1; min-height: var(--tap); }
  .confirm-actions .btn { flex: 1; min-height: var(--tap); }
  /* Высота задана, а не «сколько получится»: вкладки разной длины (в
     «Дереве» четыре строки, в «Разметке» под тридцать) заставляли шторку
     прыгать по экрану на каждое переключение. */
  .keys-modal { height: min(660px, 88dvh); max-height: 88dvh; }

  /* Поиск — на весь экран: он открыт чаще любого другого окна, и половина
     его площади уходила под клавиатуру. */
  .modal-backdrop:has(.palette) { padding: 0; align-items: stretch; }
  .palette {
    height: 100dvh; max-height: none; width: 100%; max-width: none;
    border-radius: 0; border: 0;
    animation: fade-in 140ms var(--ease);
  }
  .palette-input {
    height: calc(58px + var(--safe-t)); padding-top: var(--safe-t);
    padding-left: 14px; padding-right: 8px;
  }
  .palette-input input[type=text] { font-size: 16px; }
  .palette-results { padding-bottom: calc(16px + var(--safe-b)); }
  .p-item { padding: 12px 11px; min-height: 54px; }
  .p-badge { display: none; }
  .palette-foot { display: none; }

  /* --- страница --- */
  .page-wrap { padding: 16px 16px 32px; }
  .page-wrap.wide.roomy { padding-left: 16px; padding-right: 16px; }
  /* Подвал: ссылки высотой в строку текста — 20 px, вдвое меньше пальца.
     Разводим их по вертикали и добавляем каждой свою площадь нажатия. */
  .site-footer { padding: 16px 16px 24px; gap: 4px 14px; }
  .site-footer a, .site-footer .linklike { padding: 9px 0; }
  .site-footer .dotsep, .site-footer .grow { display: none; }
  /* «все», «вся лента» и прочие подписи-ссылки рядом с заголовками блоков */
  .link { padding: 8px 4px; margin: -8px -4px; }
  .side-head a { width: 34px; height: 34px; justify-content: center; padding: 0; }
  /* Плотные списки (последнее, популярное, лента, связи) — строки в рост пальца */
  .row-list a { min-height: 46px; }
  .row-list.compact a { padding: 9px 12px; min-height: 44px; }
  .xref-list a { min-height: 42px; }
  /* Хлебные крошки: ссылки высотой в строку, да ещё вплотную друг к другу */
  .crumbs { gap: 2px 6px; }
  .crumbs a, .crumbs .cur { padding: 6px 2px; }
  /* Название базы в шапке: ссылка была ростом с текст, а не с самой шапкой */
  .brand { align-self: stretch; align-items: center; padding-right: 4px; }
  .toasts { padding-left: 12px; padding-right: 12px; }
  .grid-2, .grid-3, .grid-5 { grid-template-columns: 1fr; }
  .doc { padding-top: 14px; }
  .crumbs { font-size: .76rem; margin-bottom: 12px; }
  .doc-head h1 { font-size: 1.55rem; gap: 9px; }
  .doc-emoji { font-size: 1.4rem; }
  .doc-title-row { flex-direction: column; gap: 12px; }
  /* Кнопки страницы в один ряд во всю ширину: «Редактировать» тянется,
     остальные остаются квадратными значками рядом. */
  .doc-actions { width: 100%; gap: 8px; flex-wrap: nowrap; }
  .doc-actions .btn { min-height: 42px; }
  .doc-actions .btn.primary { flex: 1; }
  .doc-actions .btn.icon-only { width: 42px; padding: 0; }
  .doc-meta { gap: 10px 14px; font-size: .76rem; }
  .toc-mobile summary { min-height: 46px; padding: 12px 14px; }
  .toc-mobile nav { padding: 0 14px 14px; gap: 0; }
  .toc-mobile a { padding: 9px 0; font-size: .88rem; }
  .markdown-body { font-size: 16px; }
  .markdown-body h1 { font-size: 1.5em; }
  .markdown-body h2 { font-size: 1.28em; }
  .markdown-body pre { padding: 13px 14px; border-radius: var(--r-sm); }
  .markdown-body table { font-size: .88rem; }
  .markdown-body th, .markdown-body td { padding: 8px 11px; }
  .markdown-body .admonition { padding: 12px 14px; }
  /* Кнопки перехода в тексте — во всю ширину: так по ним попадают, не целясь */
  .markdown-body a.btn { display: flex; width: 100%; min-height: 46px; }
  .pager { flex-direction: column; }
  .pager-item { max-width: 100%; }
  .subpages, .comments, .xrefs { margin-top: 32px; }
  .comment-list .comment-list { margin-left: 12px; padding-left: 10px; }
  .comment-form { gap: 8px; }
  .comment-form > .avatar { display: none; }
  .cards { grid-template-columns: 1fr; }
  .hero { padding: 20px 18px; }
  .hero h1 { font-size: 1.7rem; }
  .hero-actions .btn { width: 100%; justify-content: center; min-height: 46px; }
  .hero-actions kbd { display: none; }
  /* Четыре счётчика в один ряд на 375 px не встают: под «пространств»
     нужно 75 px, а остаётся 70. Оставляем две колонки, но пониже. */
  .hero-stats { width: 100%; gap: 8px; }
  .hero-stats .stat { padding: 10px 8px; }
  .hero-stats .stat b { font-size: 1.25rem; }

  /* --- просмотрщик вложений --- */
  .modal-backdrop.viewer { padding: 0; align-items: stretch; }
  .modal-backdrop.viewer .att-viewer {
    width: 100vw; height: 100dvh; border-radius: 0; border: 0;
  }
  .av-head { padding: calc(8px + var(--safe-t)) 8px 8px; }
  .av-head .icon-btn { width: 42px; height: 42px; }
  .av-title { max-width: 42%; }
  .av-stage { padding: 6px; }
  .av-nav { display: none; }          /* листается свайпом, стрелки не нужны */
  .av-strip { padding: 8px 10px calc(8px + var(--safe-b)); }

  /* --- редактор --- */
  /* Панель оформления прилипает к низу экрана и поднимается вместе с
     клавиатурой (--kb-inset ставит app.js по visualViewport). Сверху её
     держать нельзя: на телефоне текст пишется у нижнего края, и рука
     закрывала бы кнопки. */
  body.editor-mode { overflow: hidden; }
  .editor { height: 100dvh; }
  .ed-topbar {
    flex-wrap: wrap; row-gap: 4px;
    padding: calc(6px + var(--safe-t)) 8px 6px;
  }
  .ed-title { order: 3; flex: 1 0 100%; font-size: 16px !important; }
  .ed-top-actions { margin-left: auto; gap: 2px; }
  .ed-top-actions .icon-btn { width: 38px; height: 38px; }
  /* Структура документа на узком экране не показывается, режим без
     отвлечений и список горячих клавиш телефону не нужны — освободившееся
     место отдано подписи «Сохранить». */
  #toggleOutline, #toggleZen, .ed-top-actions #helpBtn { display: none; }
  .ed-status { min-width: 0; }
  .ed-crumb { display: none; }
  .ed-toolbar {
    position: fixed; left: 0; right: 0; bottom: var(--kb-inset, 0px);
    z-index: 120; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
    gap: 3px; padding: 6px 8px calc(6px + var(--safe-b));
    border-top: 1px solid var(--border); border-bottom: 0;
    background: var(--bg); scrollbar-width: none;
    scroll-padding: 0 24px; overscroll-behavior-x: contain;
    transition: bottom 120ms var(--ease);
  }
  .ed-toolbar::-webkit-scrollbar { display: none; }
  body.kb-open .ed-toolbar { padding-bottom: 6px; }

  /* --- порядок кнопок на телефоне ---
     Панель не помещается в экран и никогда не поместится: команд два
     десятка. Значит, важно не сколько её листать, а что видно без
     листания. В исходном порядке четвёртым шёл выбор шрифта — блок
     шириной в три кнопки, который на телефоне трогают раз в сто правок:
     из-за него списки и вставка блока начинались уже за краем экрана,
     и до них приходилось листать две с лишним ширины.

     Теперь в первом экране — тип блока, начертание, ссылка, списки и
     вставка; отмена, файл, шрифт и масштаб уехали в хвост. Разделители
     убраны: четыре полоски по 11 px — это ещё одна кнопка ширины,
     а группы и так читаются по смыслу.

     Порядок задаётся flex-order, а не перестановкой в разметке: на
     широком экране разметка остаётся прежней, вместе с разделителями. */
  .ed-toolbar > .sep { display: none; }
  .ed-toolbar > * { order: 20; }
  .ed-toolbar > .tb-block { order: 1; }
  .ed-toolbar > .tb[data-cmd="bold"] { order: 2; }
  .ed-toolbar > .tb[data-cmd="italic"] { order: 3; }
  .ed-toolbar > .tb[data-act="link"] { order: 4; }
  .ed-toolbar > .tb[data-cmd="ul"] { order: 5; }
  .ed-toolbar > .tb[data-cmd="ol"] { order: 6; }
  .ed-toolbar > .tb[data-cmd="task"] { order: 7; }
  .ed-toolbar > .tb-insert { order: 8; }
  .ed-toolbar > .tb[data-cmd="undo"] { order: 9; }
  .ed-toolbar > .tb[data-cmd="redo"] { order: 10; }
  .ed-toolbar > .tb-upload { order: 11; }
  .ed-toolbar > .tb[data-cmd="strike"] { order: 12; }
  .ed-toolbar > .tb[data-cmd="code"] { order: 13; }
  .ed-toolbar > .tb-font { order: 14; }
  .ed-toolbar > .grow { order: 15; }
  .ed-toolbar > .tb-zoom { order: 16; }
  /* Меню с панели редактора тоже поднимается над клавиатурой: она остаётся
     открытой (фокус из текста не уходит), и шторка у нижнего края экрана
     оказалась бы под ней. */
  .ed-toolbar .dropdown-menu { bottom: var(--kb-inset, 0px); }
  .tb { min-width: 40px; height: 40px; }
  .tb.wide { min-width: 88px; max-width: 116px; padding-left: 8px; padding-right: 6px; }
  .tb.wide > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tb.wide.font { min-width: 84px; max-width: 104px; }
  .ed-counter { display: none; }
  /* Место под панель и под клавиатуру. Раньше в отступ входила только
     панель: телефон не сжимает layout viewport под клавиатуру, и нижняя
     треть текста — вместе с кареткой — оказывалась под ней. Прокрутка
     каретки к видимой части сама этого не чинит: браузер считает, что
     место на экране есть. */
  .ed-main { padding-bottom: calc(52px + var(--safe-b) + var(--kb-inset, 0px)); }
  body.kb-open .ed-main { padding-bottom: calc(46px + var(--kb-inset, 0px)); }
  .ed-doc.markdown-body { padding: 18px 16px 50vh; font-size: 16px; }
  /* 60 px на ячейку — это шесть колонок в 360 px при 343 px полосы текста:
     таблица из шести колонок уводила весь холст вбок. */
  .ed-doc td, .ed-doc th { min-width: 46px; padding: 7px 9px; }
  .ed-hint { display: none; }
  /* Ровно 16 px: при меньшем кегле iOS увеличивает страницу на фокусе и
     обратно её уже не возвращает — исходник открывался «в лупе». */
  .ed-rawpane textarea { padding: 16px !important; font-size: 16px !important; }
  /* Панель свойств — во весь экран: 348 px на 375 экрана оставляли
     бесполезную полоску страницы сбоку. Нижний отступ растёт вместе с
     клавиатурой: поле тегов и адрес страницы стоят внизу, и под открытой
     клавиатурой до них было не долистать. */
  .ed-settings {
    width: 100%;
    padding: calc(14px + var(--safe-t)) 16px calc(16px + var(--safe-b) + var(--kb-inset, 0px));
    display: flex; flex-direction: column;
    z-index: 130;      /* выше прибитой к низу панели оформления */
  }
  .ed-settings-head { padding-bottom: 14px; }
  .ed-settings-head .icon-btn { width: 40px; height: 40px; }
  .emoji-picker button { width: 40px; height: 40px; font-size: 19px; }
  /* Меню вставки по «/» — шторкой над панелью, а не у каретки:
     у каретки его половину закрывала бы клавиатура. */
  .kb-slash {
    left: 8px !important; right: 8px; width: auto;
    top: auto !important; bottom: calc(var(--kb-inset, 0px) + 56px + var(--safe-b));
    max-height: 46dvh; border-radius: var(--r-lg);
  }
  .kb-slash-item { padding: 11px 10px; font-size: .95rem; }
  /* Плавающая панель над выделением на телефоне только спорит с системным
     меню «Копировать / Вставить»: все её команды и так внизу, на панели. */
  .kb-bubble { display: none !important; }
  .lm-back { padding: 0; align-items: flex-end; }
  .lm-win {
    width: 100%; max-height: 92dvh; border-radius: var(--r-xl) var(--r-xl) 0 0;
    padding-bottom: var(--safe-b);
  }

  /* --- мелкие кнопки: их на телефоне не бывает ---
     26–32 px — меньше подушечки пальца. Рекомендация платформ — 44 px;
     в плотных полосах (пагинация, панель списка) разумный минимум — 38. */
  .btn { min-height: 42px; }
  .btn.small, .btn.tiny { min-height: 38px; padding-left: 12px; padding-right: 12px; }
  .icon-btn.tiny { width: 34px; height: 34px; }
  .pager-num { min-width: 38px; min-height: 38px; }
  .seg-filter button { min-height: 38px; }
  .emoji-btn { width: 40px; height: 40px; }
  .ps-seg { min-height: 40px; }
  .filter-clear { padding: 6px; }

  /* --- администрирование --- */
  .admin-head { flex-direction: column; align-items: flex-start; gap: 12px; }
  .admin-head-actions { width: 100%; flex-wrap: wrap; }
  .admin-tab { padding: 11px 10px; }
  .role-tabs, .list-toolbar, .icons-toolbar { overflow-x: auto; }
  .seg, .segmented { flex-wrap: wrap; }

  /* --- полоса «Сохранить» ---
     `bottom: 10px` считается от низа окна, а не от низа видимой части:
     полоса липла ровно под нижнюю панель навигации и показывалась целиком
     только в самом конце страницы, когда переставала быть липкой. Отступ
     теперь равен высоте панели, а сама полоса — компактная: кнопка и
     подпись в одну строку, подпись при нехватке места обрезается, а не
     переносится и не растит полосу вдвое.

     Пояснение «Изменения увидят все пользователи» на телефоне уходит:
     на 375 px оно занимало вторую строку ради того, что и так понятно.
     Предупреждение о несохранённом остаётся — оно про состояние. */
  .sticky-actions {
    bottom: calc(var(--mobnav-h) + var(--safe-b) + 8px);
    gap: 8px; padding: 8px 10px; margin: 14px 0 6px;
    row-gap: 8px;
  }
  /* Распорка между «сохранить» и «удалить» на телефоне только разрывает
     полосу надвое: места на две кнопки в строке и так впритык. */
  .sticky-actions > .grow { display: none; }
  .sticky-actions > .btn { flex: 1 1 auto; min-width: 0; min-height: 40px; }
  .sticky-actions > .btn.small { min-height: 36px; }
  .sticky-actions > .muted { display: none; }
  .sticky-actions > select { flex: 1 1 100%; }
  .sticky-actions .save-hint { flex: 0 1 auto; min-width: 0; }
  /* В редакторе нижней панели нет — там полоса стоит у самого края */
  body.editor-mode .sticky-actions { bottom: calc(var(--safe-b) + 8px); }
}

/* --- палец вместо курсора ------------------------------------------------
   Всё, что показывалось по наведению, на тач-экране не показывалось никогда:
   наведения там нет, а значит, кнопки «+» и «⋯» в дереве, «копировать» у
   кода и действия комментария были попросту недоступны. Условие по
   возможностям устройства, а не по ширине: планшет тоже трогают пальцем. */
@media (hover: none) and (pointer: coarse) {
  .tree-tools { position: static; opacity: 1; pointer-events: auto; background: none; }
  .tree-row.active > .tree-tools { background: none; }
  .code-copy { opacity: 1; }
  .c-tools { display: flex; }
  .att-card:hover { box-shadow: none; }

  /* Нажатие должно быть видно сразу — на тач-экране это единственный отклик */
  .btn:active, .icon-btn:active, .tb:active { background: var(--bg-hover); }
  .tree-row:active { background: var(--bg-hover); }
  .card:active { border-color: var(--accent-line); }

  /* Таблицы и код в тексте прокручиваются пальцем, страница при этом стоит */
  .markdown-body table, .markdown-body pre, .mermaid-wrap, .kb-diagram-wrap {
    overscroll-behavior-x: contain;
  }
}

/* Телефон набок: высоты почти нет, и подписи под значками съедают её на
   ровном месте. Полоса становится вдвое ниже, остаются одни значки. */
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  :root { --mobnav-h: 44px; }
  .mobnav-item span { display: none; }
  .mobnav-item.accent .ico { width: 28px; height: 28px; padding: 4px; }
  .ed-doc.markdown-body { padding-bottom: 60vh; }
}


/* ================================================ 33. Страница по ссылке ===
   То, что видит человек со стороны: заголовок, текст и подпись внизу.
   Ни панели, ни поиска, ни перехода куда бы то ни было — страница здесь
   заканчивается, и это должно читаться с первого взгляда, а не выясняться
   методом тыка по ссылкам, которые никуда не ведут.
   ========================================================================= */
.share-page { background: var(--bg-alt); }

.share-wrap {
  max-width: 860px; margin: 0 auto;
  padding: 22px 20px calc(40px + env(safe-area-inset-bottom));
}

.share-top {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding-bottom: 14px; margin-bottom: 22px;
  border-bottom: 1px solid var(--border);
}
/* Название базы — текстом, а не ссылкой: кликать тут некуда */
.share-brand {
  display: inline-flex; align-items: center; gap: 8px;
  font-weight: 650; letter-spacing: -.01em; color: var(--fg);
}
.share-brand .icon-img { width: 22px; height: 22px; border-radius: 6px; }
.share-badge {
  display: inline-flex; align-items: center; gap: 6px; margin-left: auto;
  padding: 4px 10px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent-text);
  font-size: .78rem; font-weight: 600; white-space: nowrap;
}

.share-doc {
  padding: 30px 34px 36px; border-radius: var(--r-lg);
  background: var(--bg); border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
}
.share-doc > h1 {
  margin: 0 0 10px; font-size: 1.95rem; line-height: 1.2; letter-spacing: -.02em;
}
.share-doc > h1 .doc-emoji { margin-right: 10px; }
.share-meta {
  display: flex; align-items: center; gap: 6px;
  margin: 0 0 26px; color: var(--fg-muted); font-size: .85rem;
}

.share-toc {
  margin: 0 0 26px; padding: 12px 16px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
}
.share-toc summary { cursor: pointer; font-weight: 600; font-size: .9rem; }
.share-toc nav { display: flex; flex-direction: column; gap: 2px; margin-top: 10px; }
.share-toc nav a { padding: 3px 0; font-size: .88rem; color: var(--fg-muted); }
.share-toc nav a:hover { color: var(--accent-text); }
.share-toc .lvl-3 { padding-left: 14px; }
.share-toc .lvl-4 { padding-left: 28px; }

/* Просмотрщика вложений здесь нет — лупа на картинке обещала бы то, чего
   не будет. Открыть покрупнее можно средствами браузера. */
.share-page .markdown-body img { cursor: default; }

.share-foot {
  margin-top: 26px; padding: 0 4px;
  color: var(--fg-muted); font-size: .82rem; line-height: 1.6; text-align: center;
}
.share-foot p { margin: 0; }

/* Экран «ссылка больше не работает» */
.share-page.gone { display: grid; place-items: center; min-height: 100vh; min-height: 100dvh; }
.share-gone {
  max-width: 460px; margin: 0 auto; padding: 38px 32px; text-align: center;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--r-lg); box-shadow: var(--shadow-sm);
}
.share-gone-mark {
  display: inline-flex; align-items: center; justify-content: center;
  width: 62px; height: 62px; margin-bottom: 18px; border-radius: 50%;
  background: var(--bg-alt); color: var(--fg-muted);
}
.share-gone h1 { margin: 0 0 10px; font-size: 1.35rem; }
.share-gone p { margin: 0; color: var(--fg-muted); line-height: 1.6; }

@media (max-width: 700px) {
  .share-wrap { padding: 16px 12px 40px; }
  .share-doc { padding: 22px 18px 28px; border-radius: var(--r-md); }
  .share-doc > h1 { font-size: 1.55rem; }
}

/* Окно выдачи ссылок и таблица ссылок в админке ---------------------------- */
.share-modal { width: min(620px, 94vw); }

.share-new {
  display: grid; grid-template-columns: 160px 1fr auto; gap: 12px; align-items: end;
  padding: 14px; margin: 16px 0 18px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg-alt);
}
.share-new label { display: flex; flex-direction: column; gap: 5px; font-size: .84rem; font-weight: 600; }
.share-new input, .share-new select { width: 100%; }

.share-list-head { margin-bottom: 10px; font-size: .84rem; font-weight: 600; color: var(--fg-muted); }

.share-item {
  padding: 12px 14px; margin-bottom: 10px;
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--bg);
}
/* Закрытая ссылка остаётся в списке, но не должна притягивать взгляд:
   её показывают, чтобы было видно историю, а не чтобы ею пользовались. */
.share-item.expired, .share-item.revoked { opacity: .62; }
.share-item-url { display: flex; gap: 8px; align-items: center; }
.share-item-url input {
  flex: 1; min-width: 0; font-family: var(--font-mono); font-size: .8rem;
}
.share-item.expired .share-item-url input,
.share-item.revoked .share-item-url input { text-decoration: line-through; }

.share-item-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px;
  margin-top: 9px; font-size: .8rem; color: var(--fg-muted);
}
.share-item-meta .share-revoke { margin-left: auto; }

.share-state {
  padding: 2px 9px; border-radius: 999px;
  font-size: .74rem; font-weight: 650; text-transform: lowercase;
}
.share-state.active  { background: color-mix(in srgb, var(--green) 16%, transparent); color: var(--green); }
.share-state.expired { background: var(--bg-alt); color: var(--fg-muted); }
.share-state.revoked { background: color-mix(in srgb, var(--red) 14%, transparent); color: var(--red); }

@media (max-width: 640px) {
  .share-new { grid-template-columns: 1fr; }
  .share-item-meta .share-revoke { margin-left: 0; }
}

/* Список ссылок в админке ------------------------------------------------- */
.shares-list { list-style: none; margin: 14px 0 0; padding: 0; }
.share-row {
  display: grid; gap: 6px 14px; align-items: center;
  grid-template-columns: minmax(180px, 1.4fr) minmax(200px, 1.6fr) 120px 90px 130px auto;
  padding: 11px 12px; border-bottom: 1px solid var(--border);
}
.share-row:last-child { border-bottom: 0; }
.share-row:hover { background: var(--bg-alt); }
.share-row.expired, .share-row.revoked { opacity: .62; }
.share-row > span { display: flex; flex-direction: column; gap: 2px; min-width: 0; font-size: .85rem; }
.share-row small { font-size: .76rem; }
.share-row-page a { display: flex; align-items: center; gap: 7px; font-weight: 600; }
.share-row-page a, .share-row-page small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.share-row-url {
  width: 100%; min-width: 0; font-family: var(--font-mono); font-size: .76rem;
}
.share-row-views { flex-direction: row !important; align-items: baseline; gap: 5px; flex-wrap: wrap; }
.share-row-act form { margin: 0; }

@media (max-width: 1000px) {
  .share-row { grid-template-columns: 1fr auto; }
  .share-row-url { grid-column: 1 / -1; }
  .share-row-views, .share-row-author { grid-column: auto; }
}
