/* ════════════════════════════════════════════════════════════════════
   mailrust — стили.

   Один файл на весь продукт, и устроен он как словарь: сверху то, из
   чего собирается всё остальное, ниже — то, что из этого собрано.

     1. Токены       шаг, кегли, размеры, цвета. Ни одного числа ниже
                     этой части руками не пишется.
     2. Основа       сброс, шрифты, фокус, полосы прокрутки.
     3. Кирпичи      кнопка, поле, галочка, меню, плашка — то, из чего
                     собран любой экран.
     4. Оболочка     панель слева, шапка, полоса списка, строка состояния.
     5. Экраны       почта, письмо, редактор, настройки, сегодня,
                     календарь, аутрич, вход.
     6. Движение     всё, что едет и проявляется.
     7. Узкие экраны три порога: 1280, 900, 620.

   Законы, по которым он написан:

   — Прямой угол. Скруглений нет ни одного.
   — Монохром. Цвет в интерфейсе один — лайм, и он занят непрочитанным.
     Главная кнопка — чернилами. Красный — только беда.
   — Текст читается. Любая надпись не слабее Lc 60 по APCA, основной
     текст — не слабее 90. Серое на сером здесь не пишут.
   — Одно место на правило. Компонент описан один раз; экран его
     расставляет, но не перекрашивает.
   ════════════════════════════════════════════════════════════════════ */


/* ═══ 1. ТОКЕНЫ ═════════════════════════════════════════════════════ */

:root {
  /* ── Шаг. Всё кратно четырём; имя — сколько четвёрок. ───────────── */
  --sp-px: 1px;
  --sp-0h: 2px;
  --sp-1:  4px;
  --sp-1h: 6px;
  --sp-2:  8px;
  --sp-3:  12px;
  --sp-4:  16px;
  --sp-5:  20px;
  --sp-6:  24px;
  --sp-8:  32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;

  /* ── Шрифты ──────────────────────────────────────────────────────── */
  --font-sans: "Geist", ui-sans-serif, system-ui, -apple-system, "Segoe UI",
               Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Кегли. Семь ступеней интерфейса и две для чисел на «Сегодня». */
  --text-2xs:  11px;   /* подпись капсом */
  --text-xs:   12px;   /* время, счётчик, подсказка */
  --text-sm:   13px;   /* второй план: превью, панель */
  --text-base: 14px;   /* интерфейс */
  --text-md:   15px;   /* текст письма */
  --text-lg:   18px;   /* заголовок экрана и раздела */
  --text-xl:   22px;   /* тема открытого письма */
  --text-2xl:  28px;   /* число на плитке */
  --text-3xl:  40px;   /* главное число дня */

  --lh-tight:  1.2;
  --lh-snug:   1.4;
  --lh-normal: 1.5;
  --lh-read:   1.65;

  --fw-normal: 400;
  --fw-medium: 500;
  --fw-semi:   600;

  --track-caps: 0.06em;

  /* ── Размеры ─────────────────────────────────────────────────────── */
  --h-xs: 24px;        /* плашка, мелкая кнопка в строке */
  --h-sm: 28px;
  --h-md: 32px;        /* кнопка и поле по умолчанию */
  --h-lg: 40px;

  --icon-sm: 14px;
  --icon:    16px;
  --icon-lg: 20px;

  --hair: 1px;

  --w-rail:   248px;
  --w-reader: 760px;
  --w-form:   560px;   /* мера формы */
  --w-toast:  400px;   /* всплывающая строка */
  --w-read:   720px;   /* мера текста письма */
  --w-page:   1280px;  /* мера экрана с карточками */

  --h-bar:    56px;    /* шапка экрана */
  --h-strip:  40px;    /* полоса над списком */
  --h-status: 28px;
  --h-nav:    32px;    /* пункт панели */
  --row-h:    40px;    /* строка письма */

  --pad:      20px;    /* поле экрана слева и справа */

  /* ── Слои ────────────────────────────────────────────────────────── */
  --z-stick: 5;
  --z-rail:  20;
  --z-panel: 30;
  --z-pop:   40;
  --z-peek:  50;
  --z-toast: 60;

  /* ── Движение ────────────────────────────────────────────────────── */
  --t-fast: 120ms;
  --t-norm: 200ms;
  --t-slow: 1600ms;    /* один проход полоски ожидания */
  --ease:   cubic-bezier(0.2, 0, 0, 1);

  /* ── Цвет ────────────────────────────────────────────────────────── *
     Каждый токен объявлен один раз для обеих тем: слева светлая,
     справа тёмная. Какая из двух — решает color-scheme ниже.          */

  /* Поверхности: от самой глубокой к самой близкой. */
  --bg-rail:    light-dark(#f4f4f2, #0b0b0c);
  --bg-page:    light-dark(#ffffff, #101011);
  --bg-raised:  light-dark(#ffffff, #18181a);
  --bg-sunken:  light-dark(#f6f6f4, #0b0b0c);
  --bg-control: light-dark(#f0f0ed, #1f1f22);
  --bg-hover:   light-dark(#f5f5f2, #19191b);
  --bg-active:  light-dark(#e8e8e4, #27272b);
  --bg-picked:  light-dark(#f2f7d6, #1c2011);

  /* Линии. */
  --line:        light-dark(#e7e7e3, #232326);
  --line-strong: light-dark(#cfcfca, #3a3a40);

  /* Чернила: четыре ступени. Первые три — текст, четвёртая — только
     знаки, плейсхолдеры и выключенное. */
  --ink:       light-dark(#111113, #f4f4f5);
  --ink-2:     light-dark(#3f3f45, #d8d8dc);
  --ink-muted: light-dark(#63636a, #bcbcc2);
  --ink-faint: light-dark(#8c8c93, #85858b);

  /* Акцент — непрочитанное. Заливка, текст на ней и тонкий знак. */
  --accent:      light-dark(#d2ee45, #d6f24b);
  --accent-ink:  #0b0b0c;
  --accent-line: light-dark(#5d7600, #d6f24b);

  /* Смысловые. */
  --danger: light-dark(#c0271a, #ff9f94);
  --warn:   light-dark(#8a5a00, #f0b545);
  --ok:     light-dark(#177a43, #6fd596);

  --danger-bg: light-dark(#fdf0ee, #2a1513);
  --warn-bg:   light-dark(#fbf3e2, #2a2110);
  --ok-bg:     light-dark(#ebf6ef, #12241a);

  --focus: var(--ink);
  --scrim: light-dark(rgb(17 17 19 / 0.32), rgb(0 0 0 / 0.56));
  /* Тень того, что лежит поверх: меню, окно, панель письма, всплывающая
     строка. Вынос и цвет записаны порознь: `light-dark()` принимает
     только цвета. Прежде в нём стояла тень целиком — такое значение
     недействительно, и теней в интерфейсе не было вовсе. */
  --shadow-lift: 0 12px 32px;
  --shadow-ink:  light-dark(rgb(17 17 19 / 0.16), rgb(0 0 0 / 0.6));
  --shadow-pop:  var(--shadow-lift) var(--shadow-ink);

  /* Тона — ящики, метки, аватары. Восемь, и сервер знает только номер. */
  --tone-1: light-dark(#c2410c, #ff9d7a);
  --tone-2: light-dark(#a16207, #f2c14e);
  --tone-3: light-dark(#15803d, #7ddc9a);
  --tone-4: light-dark(#0f766e, #5fd4c6);
  --tone-5: light-dark(#0369a1, #7cc4f5);
  --tone-6: light-dark(#4338ca, #a5adff);
  --tone-7: light-dark(#7e22ce, #d0a0ff);
  --tone-8: light-dark(#be185d, #ff9cc7);

  color-scheme: dark light;
}

/* Тема: «как в системе» — по умолчанию, остальное — выбором человека. */
:root[data-theme="dark"]  { color-scheme: dark; }
:root[data-theme="light"] { color-scheme: light; }

/* Плотность списка — одна цифра. */
:root[data-density="compact"] { --row-h: 32px; }
:root[data-density="roomy"]   { --row-h: 48px; }

.tone-1 { --tone: var(--tone-1); }
.tone-2 { --tone: var(--tone-2); }
.tone-3 { --tone: var(--tone-3); }
.tone-4 { --tone: var(--tone-4); }
.tone-5 { --tone: var(--tone-5); }
.tone-6 { --tone: var(--tone-6); }
.tone-7 { --tone: var(--tone-7); }
.tone-8 { --tone: var(--tone-8); }


/* ═══ 2. ОСНОВА ═════════════════════════════════════════════════════ */

@font-face {
  font-family: "Geist";
  src: url("/assets/geist.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: "Geist Mono";
  src: url("/assets/geist-mono.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}

html,
body {
  height: 100%;
  /* Страница не прокручивается никогда — прокручиваются её колонки.
     Иначе колесо над панелью, которой некуда ехать, тянет весь экран.

     Именно clip, а не hidden: спрятанное переполнение всё равно можно
     прокрутить программно, и переход по якорю (#rules) утаскивал весь
     интерфейс вверх, открывая под ним чёрную полосу. */
  overflow: clip;
  overscroll-behavior: none;
}

body {
  background: var(--bg-page);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--lh-normal);
  font-weight: var(--fw-normal);
  font-feature-settings: "ss01" off, "tnum" off;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3, h4 {
  font-size: inherit;
  font-weight: var(--fw-semi);
  line-height: var(--lh-tight);
}

ul, ol {
  list-style: none;
}

a {
  color: inherit;
  text-decoration: none;
}

img, svg, canvas, iframe {
  display: block;
  max-width: 100%;
}

button, input, select, textarea {
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
}

button {
  background: none;
  border: 0;
  border-radius: 0;
  cursor: pointer;
}

table {
  border-collapse: collapse;
}

summary {
  list-style: none;
  cursor: pointer;
}

summary::-webkit-details-marker {
  display: none;
}

[hidden] {
  display: none !important;
}

::selection {
  background: var(--accent);
  color: var(--accent-ink);
}

/* Фокус — чернилами и снаружи контура: так его видно на любой заливке. */
:focus {
  outline: none;
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Полоса прокрутки. Только вебкитовые правила: стоит задать рядом
   scrollbar-width или scrollbar-color — и Chrome перестаёт применять
   этот блок целиком. */
::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border: 4px solid transparent;
  background-clip: content-box;
}

::-webkit-scrollbar-thumb:hover {
  background-color: var(--ink-faint);
}

::-webkit-scrollbar-corner {
  background: transparent;
}

/* Только для программ чтения с экрана. */
.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Спрайт значков лежит в разметке и места не занимает. */
.sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* Моноширинные цифры там, где числа стоят столбцом. */
.num {
  font-variant-numeric: tabular-nums;
}


/* ═══ 3. КИРПИЧИ ════════════════════════════════════════════════════ */

/* ── Раскладка: три приёма на весь продукт ──────────────────────────
   Стопка — друг под другом, ряд — друг за другом с переносом, пара —
   по краям. Зазор берётся из шага модификатором, руками не пишется.  */

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

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap, var(--sp-2));
  min-width: 0;
}

.split {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap, var(--sp-4));
  min-width: 0;
}

.gap-1 { --gap: var(--sp-1); }
.gap-2 { --gap: var(--sp-2); }
.gap-3 { --gap: var(--sp-3); }
.gap-4 { --gap: var(--sp-4); }
.gap-6 { --gap: var(--sp-6); }
.gap-8 { --gap: var(--sp-8); }

.grow     { flex: 1 1 0%; min-width: 0; }
.push     { margin-left: auto; }
.nowrap   { white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.muted    { color: var(--ink-muted); }
.mono     { font-family: var(--font-mono); font-size: 0.93em; }

/* Подпись капсом: над группой в панели, над разделом в карточке. */
.caps {
  font-size: var(--text-2xs);
  font-weight: var(--fw-semi);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--ink-muted);
}


/* ── Значок ───────────────────────────────────────────────────────── */

.icon {
  flex: none;
  width: var(--icon);
  height: var(--icon);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: square;
  stroke-linejoin: miter;
  /* Значок — не цель щелчка: цель — кнопка вокруг него. */
  pointer-events: none;
}

.icon--sm { width: var(--icon-sm); height: var(--icon-sm); }
.icon--lg { width: var(--icon-lg); height: var(--icon-lg); }

/* Залитые части значка: точки, квадраты, половина круга. */
.sprite .icon__fill {
  fill: currentColor;
  stroke: none;
}


/* ── Логотип ──────────────────────────────────────────────────────── */

.brand {
  display: inline-flex;
  align-items: flex-end;
  gap: 0.32em;
  font-size: 15px;
  font-weight: var(--fw-semi);
  letter-spacing: -0.03em;
  line-height: 1;
  color: var(--ink);
}

/* Знак — «M-конверт» (templates/brand_mark.html, рисует scripts/brand.py):
   стенки и клапан конверта складываются в M, под ней через зазор —
   полоска. Цвет — как у слова; рост — до верха «l» и «t», низ полоски —
   на линии букв. */
.brand__mark {
  flex: none;
  width: auto;
  height: 0.86em;
  margin-bottom: 0.02em;
}


/* ── КНОПКА ───────────────────────────────────────────────────────── *
   Одна на продукт. Три независимые оси:
     тон     — primary · outline · soft · (без тона — тихая) · danger
     размер  — sm · (обычная) · lg
     форма   — icon · block
   Высота — из шкалы и не зависит от содержимого: две кнопки с разным
   текстом стоят на одной линии.                                       */

.btn {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: var(--h-md);
  padding: 0 var(--sp-3);
  border: var(--hair) solid transparent;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}

.btn:hover  { background: var(--bg-control); }
.btn:active { background: var(--bg-active); }

.btn.is-on {
  background: var(--bg-active);
}

.btn:disabled,
.btn.is-off {
  color: var(--ink-faint);
  pointer-events: none;
}

/* Тон */
.btn--primary {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--bg-page);
  font-weight: var(--fw-semi);
}

.btn--primary:hover,
.btn--primary:active {
  background: var(--ink-2);
  border-color: var(--ink-2);
}

.btn--outline {
  border-color: var(--line-strong);
}

.btn--outline:hover {
  border-color: var(--ink-faint);
}

.btn--soft {
  background: var(--bg-control);
}

.btn--soft:hover {
  background: var(--bg-active);
}

/* Опасное действие — цветом знака и слова, без заливки: красная
   плашка в ряду кнопок кричит громче, чем нужно. */
.btn--danger {
  color: var(--danger);
}

.btn--danger:hover {
  background: var(--danger-bg);
}

/* Размер */
.btn--sm {
  height: var(--h-sm);
  padding: 0 var(--sp-2);
  gap: var(--sp-1h);
  font-size: var(--text-sm);
}

.btn--lg {
  height: var(--h-lg);
  padding: 0 var(--sp-5);
}

/* Форма */
.btn--icon {
  width: var(--h-md);
  padding: 0;
}

.btn--icon.btn--sm { width: var(--h-sm); }
.btn--icon.btn--lg { width: var(--h-lg); }

.btn--block {
  width: 100%;
}

/* Текстовая ссылка внутри фразы. */
.link {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-underline-offset: 3px;
  transition: text-decoration-color var(--t-fast);
}

.link:hover {
  text-decoration-color: var(--ink);
}


/* ── Клавиша ──────────────────────────────────────────────────────── */

.kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--sp-1);
  border: var(--hair) solid var(--line-strong);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--fw-medium);
  line-height: 1;
  color: var(--ink-muted);
}


/* ── ПОЛЕ ─────────────────────────────────────────────────────────── *
   Одно на продукт: строка, многострочное, число, дата. Родных
   выпадающих списков нет вовсе — см. «Выбор» ниже.                   */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1h);
  min-width: 0;
}

.field__label {
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  line-height: var(--sp-5);
  color: var(--ink-2);
}

.field__hint {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* Поле в меру строки: выпадающий список во всю ширину формы читается как
   заголовок раздела, а не как выбор из трёх. */
.field--measure {
  max-width: 72ch;
}

.input {
  display: block;
  width: 100%;
  height: var(--h-md);
  padding: 0 var(--sp-3);
  border: var(--hair) solid var(--line-strong);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-base);
  line-height: var(--lh-snug);
  appearance: none;
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}

.input::placeholder {
  color: var(--ink-faint);
  opacity: 1;
}

.input:hover {
  border-color: var(--ink-faint);
}

/* Фокус поля — рамка чернилами и вторая линия вплотную: обводка
   снаружи, как у кнопок, на полях читалась бы двойной рамкой. */
.input:focus,
.input:focus-visible {
  outline: none;
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

.input:disabled {
  color: var(--ink-faint);
  background: var(--bg-control);
}

.input--area {
  height: auto;
  min-height: 88px;
  padding: var(--sp-2) var(--sp-3);
  line-height: var(--lh-normal);
  resize: vertical;
}

.input--mono {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
}

/* Код из шести цифр: крупно и вразрядку. */
.input--code {
  width: 168px;
  height: var(--h-lg);
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  letter-spacing: 0.3em;
  text-align: center;
}

/* Довески браузера у чисел и поиска — долой: стрелки и крестик у
   каждого свои и ломают строй. */
.input[type="number"] {
  appearance: textfield;
}

.input[type="number"]::-webkit-inner-spin-button,
.input[type="number"]::-webkit-outer-spin-button,
.input[type="search"]::-webkit-search-cancel-button,
.input[type="search"]::-webkit-search-decoration {
  appearance: none;
  display: none;
}

.input[type="datetime-local"]::-webkit-calendar-picker-indicator,
.input[type="date"]::-webkit-calendar-picker-indicator {
  opacity: 0.6;
  cursor: pointer;
}

/* Автозаполнение не должно красить поле в жёлтое. */
.input:-webkit-autofill {
  -webkit-text-fill-color: var(--ink);
  box-shadow: 0 0 0 100px var(--bg-control) inset;
  caret-color: var(--ink);
}


/* ── Форма ────────────────────────────────────────────────────────── */

.form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  max-width: var(--w-form);
}

.form--wide {
  max-width: none;
}

/* Поля в ряд делят ширину поровну; узкое — под порт и число. Ряд
   выровнен по верху: подсказка под одним полем не должна сдвигать
   соседнее. Кнопка в ряду опускается на высоту подписи и встаёт на одну
   линию с полями. */
.form__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--sp-3);
}

.form__row > .btn {
  margin-top: calc(var(--sp-5) + var(--sp-1h));
}

/* Ряд без подписей (поле и кнопка) — кнопка на месте. */
.form__row--bare > .btn {
  margin-top: 0;
}

.form__row > .field,
.form__row > .input,
.form__row > .pick {
  flex: 1 1 180px;
}

.form__row > .field--narrow {
  flex: 0 0 104px;
}

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


/* ── ВЫБОР ────────────────────────────────────────────────────────── *
   Вместо родного select: его меню рисует операционная система, и
   посреди тёмного интерфейса открывается белая полоса с синей
   подсветкой. Здесь это details с радиокнопками внутри: значение
   уходит обычной формой, работает с клавиатуры.                      */

.pick {
  position: relative;
  min-width: 0;
}

.pick__value {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--h-md);
  padding: 0 var(--sp-2) 0 var(--sp-3);
  border: var(--hair) solid var(--line-strong);
  color: var(--ink);
  font-size: var(--text-base);
  transition: border-color var(--t-fast);
}

.pick__value:hover {
  border-color: var(--ink-faint);
}

.pick[open] > .pick__value {
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

.pick__label {
  flex: 1 1 0%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pick__value > .icon {
  color: var(--ink-muted);
  transition: rotate var(--t-fast);
}

.pick[open] > .pick__value > .icon {
  rotate: 180deg;
}

/* Выбор внутри панели раскрывается на месте, а не поверх неё: панель
   обрезает всё, что выходит за её край, и список ушёл бы под обрез. */
.pop .pick > .pop {
  position: static;
  width: auto;
  max-width: none;
  max-height: none;
  margin-top: var(--sp-1);
  box-shadow: none;
}

/* Тихий выбор — без рамки, для шапок и строк, где рамка лишняя. */
.pick--quiet > .pick__value {
  border-color: transparent;
  padding-left: var(--sp-2);
}

.pick--quiet > .pick__value:hover {
  background: var(--bg-control);
  border-color: transparent;
}


/* ── ВСПЛЫВАЮЩАЯ ПАНЕЛЬ ───────────────────────────────────────────── *
   Одна на всё, что раскрывается поверх: список выбора, меню действий,
   подсказки адресов, панель поиска, «отправить позже».               */

.pop {
  position: absolute;
  z-index: var(--z-pop);
  top: calc(100% + var(--sp-1));
  left: 0;
  min-width: 100%;
  width: max-content;
  max-width: min(360px, calc(100vw - var(--sp-8)));
  /* Высота — своя мера (--cap), но не больше места под кнопкой (--room,
     его считает скрипт при открытии): панель у неподвижной полосы за
     нижний край экрана не уходит, а листается сама. */
  --cap: min(440px, 70vh);
  max-height: min(var(--cap), var(--room, 100vh));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-1);
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-raised);
  box-shadow: var(--shadow-pop);
}

.pop--right { left: auto; right: 0; }
.pop--up,
.pop.is-up  { top: auto; bottom: calc(100% + var(--sp-1)); }

/* Панель, где над списком пунктов стоит поле: ей нужно больше места,
   иначе последний пункт режется пополам. */
.pop--tall  { --cap: min(560px, 70vh); }

/* Место считано для самой панели; вложенной оно не указ. */
.pop .pop   { --room: initial; }

/* Панель с формой: поля, а не список пунктов. Ей нужна вся её высота —
   обрезанная форма прячет собственную кнопку. */
.pop--pad {
  --cap: calc(100vh - var(--h-bar) - var(--sp-6));
  max-width: none;
  padding: var(--sp-4);
}

/* Пункт панели: строка меню, вариант выбора, подсказка адреса. */
.pop__item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  min-height: var(--h-md);
  padding: var(--sp-1) var(--sp-3);
  color: var(--ink-2);
  font-size: var(--text-base);
  text-align: left;
  white-space: nowrap;
  cursor: pointer;
}

.pop__item:hover,
.pop__item:focus-visible,
.pop__item:has(input:focus-visible) {
  background: var(--bg-control);
  color: var(--ink);
  outline: none;
}

.pop__item > .icon {
  color: var(--ink-muted);
}

.pop__item.is-on,
.pop__item:has(input:checked) {
  color: var(--ink);
}

/* Отметка выбранного — справа, место под неё держится всегда. Расстояние
   до подписи даёт зазор самого пункта: внутренний отступ съел бы значок. */
.pop__tick {
  margin-left: auto;
  visibility: hidden;
}

.pop__item.is-on > .pop__tick,
.pop__item:has(input:checked) > .pop__tick {
  visibility: visible;
  color: var(--ink);
}

.pop__item > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.pop__note {
  margin-left: auto;
  padding-left: var(--sp-4);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* Пункт, после которого что-то исчезает или запрещается. */
.pop__item--danger,
.pop__item--danger > .icon {
  color: var(--danger);
}

.pop__sep {
  height: var(--hair);
  margin: var(--sp-1) 0;
  background: var(--line);
}

.pop__caption {
  padding: var(--sp-2) var(--sp-3) var(--sp-1);
}

/* Меню — это кнопка и панель под ней. */
.menu {
  position: relative;
}

/* Меню по правому щелчку: та же панель, но у курсора — место называет
   скрипт. */
.ctx {
  position: fixed;
  z-index: var(--z-pop);
  top: var(--y, 0);
  left: var(--x, 0);
  min-width: 232px;
  max-height: calc(100vh - var(--sp-4));
}

/* Пункт со своим списком под ним: отложить до…, метка, папка. */
.ctx__group > summary {
  list-style: none;
}

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

.ctx__arrow {
  margin-left: auto;
  color: var(--ink-muted);
  transition: rotate var(--t-fast);
}

.ctx__group[open] > summary > .ctx__arrow {
  rotate: 90deg;
}

.ctx__group > .pop__item:not(summary) {
  padding-left: calc(var(--sp-3) + var(--icon) + var(--sp-2));
}

/* Строка, чьё меню открыто, — под рукой, как под курсором. */
.row.is-ctx {
  background: var(--bg-hover);
}


/* ── ДАТА И ВРЕМЯ ─────────────────────────────────────────────────── *
   Свой календарь вместо системного окна браузера: месяц сеткой, время
   двумя числами. Оболочка — тот же выбор и та же панель.             */

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

/* Панель, внутри которой раскрыт календарь, получает всю высоту экрана:
   в обычные триста шестьдесят пикселей месяц с часами не помещается, и
   кнопка «готово» оказывалась под обрезом. */
.pop:has(.when[open]) {
  --cap: calc(100vh - var(--h-bar) - var(--sp-6));
}

/* Значок календаря не переворачивается, в отличие от стрелки списка. */
.when[open] > .pick__value > .icon {
  rotate: none;
}

.when .pick__label.is-empty {
  color: var(--ink-muted);
}

.when__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}

.when__month {
  font-size: var(--text-sm);
  font-weight: var(--fw-semi);
  color: var(--ink);
}

.when__days {
  display: grid;
  grid-template-columns: repeat(7, var(--h-md));
  justify-content: space-between;
  row-gap: var(--sp-0h);
}

.when__dow {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--h-xs);
  font-size: var(--text-2xs);
  color: var(--ink-muted);
}

.when__day {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--h-md);
  color: var(--ink-2);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color var(--t-fast), color var(--t-fast);
}

.when__day:hover {
  background: var(--bg-control);
  color: var(--ink);
}

/* Сегодня — рамкой, выбранное — заливкой: видно оба сразу. */
.when__day.is-today {
  box-shadow: inset 0 0 0 var(--hair) var(--line-strong);
  color: var(--ink);
}

.when__day.is-on {
  background: var(--ink);
  color: var(--bg-page);
  font-weight: var(--fw-semi);
}

.when__day:disabled {
  background: none;
  color: var(--ink-faint);
  cursor: default;
}

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

.when__time {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin-right: auto;
  color: var(--ink-muted);
}

.when__num {
  width: var(--h-lg);
  padding: 0;
  text-align: center;
  font-variant-numeric: tabular-nums;
}


/* ── ГАЛОЧКА ──────────────────────────────────────────────────────── *
   Своя: родная в каждом браузере другая. Настоящее поле лежит под
   квадратом в один пиксель — оно ловит клавиатуру и уходит формой.   */

.tick {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--h-xs);
  color: var(--ink-2);
  font-size: var(--text-base);
  cursor: pointer;
  user-select: none;
}

.tick > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.tick__box {
  position: relative;
  flex: none;
  width: 16px;
  height: 16px;
  border: var(--hair) solid var(--ink-faint);
  background: transparent;
  transition: background-color var(--t-fast), border-color var(--t-fast);
}

.tick:hover .tick__box {
  border-color: var(--ink);
}

.tick > input:checked + .tick__box,
.tick > input:indeterminate + .tick__box {
  background: var(--ink);
  border-color: var(--ink);
}

/* Птичка — два штриха рамкой, повёрнутые на 45°. */
.tick > input:checked + .tick__box::after {
  content: "";
  position: absolute;
  left: 4.5px;
  top: 1.5px;
  width: 4px;
  height: 8px;
  border: solid var(--bg-page);
  border-width: 0 1.5px 1.5px 0;
  rotate: 45deg;
}

.tick > input:indeterminate + .tick__box::after {
  content: "";
  position: absolute;
  left: 3px;
  right: 3px;
  top: 6.25px;
  height: 1.5px;
  background: var(--bg-page);
}

.tick > input:focus-visible + .tick__box {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.tick > input:checked ~ .tick__label {
  color: var(--ink);
}


/* ── Тумблер ──────────────────────────────────────────────────────── *
   Для «включено / выключено», которое действует сразу или целиком
   включает раздел: автоответ, прогрев.                               */

.switch {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--h-xs);
  color: var(--ink);
  font-weight: var(--fw-medium);
  cursor: pointer;
  user-select: none;
}

.switch > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.switch__track {
  position: relative;
  flex: none;
  width: 32px;
  height: 18px;
  border: var(--hair) solid var(--ink-faint);
  transition: background-color var(--t-fast), border-color var(--t-fast);
}

.switch__track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 12px;
  height: 12px;
  background: var(--ink-muted);
  transition: translate var(--t-fast) var(--ease), background-color var(--t-fast);
}

.switch > input:checked + .switch__track {
  background: var(--ink);
  border-color: var(--ink);
}

.switch > input:checked + .switch__track::after {
  translate: 14px 0;
  background: var(--bg-page);
}

.switch > input:focus-visible + .switch__track {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}


/* ── Переключатель ────────────────────────────────────────────────── *
   Один из нескольких на виду: тема, плотность, язык, кампании.       */

.seg {
  display: inline-flex;
  border: var(--hair) solid var(--line-strong);
}

.seg__item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1h);
  height: calc(var(--h-md) - 2px);
  padding: 0 var(--sp-3);
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--t-fast), color var(--t-fast);
}

.seg__item + .seg__item {
  border-left: var(--hair) solid var(--line-strong);
}

.seg__item:hover {
  color: var(--ink);
  background: var(--bg-control);
}

.seg__item.is-on {
  background: var(--ink);
  color: var(--bg-page);
}


/* ── Выбор из плиток ──────────────────────────────────────────────── *
   Когда вариантов больше, чем влезает в переключатель, и у каждого есть
   что сказать о себе: службы помощника — «ключ есть», «используется».  */

.services {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(168px, 1fr));
  gap: var(--sp-2);
}

.service {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-0h);
  min-width: 0;
  min-height: var(--sp-12);
  padding: var(--sp-2) var(--sp-3);
  border: var(--hair) solid var(--line-strong);
  color: var(--ink-2);
  transition: background-color var(--t-fast), border-color var(--t-fast);
}

.service:hover {
  background: var(--bg-hover);
  color: var(--ink);
}

.service.is-on {
  border-color: var(--ink);
  background: var(--bg-control);
  color: var(--ink);
}

.service__name {
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
}

.service__mark {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* Кто взял письмо: имя целиком — у плашки-метки предел уже. */
.chip[data-assignee] {
  max-width: 280px;
}

/* Плашка «назначено мне» — залита, как своя отметка в строке списка. */
.chip.chip--mine {
  background: var(--ink);
  color: var(--bg-page);
}

/* Плашка-кнопка: значение, которое встаёт в поле по щелчку. Двойной
   класс — чтобы рост не перебило общее правило `.chip`, стоящее ниже:
   плашка-кнопка оставалась двадцати пикселей, мельче пальца. */
.chip.chip--pick {
  height: var(--h-xs);
  max-width: 100%;
  padding: 0 var(--sp-2);
  font-family: var(--font-mono);
  cursor: pointer;
  transition: background-color var(--t-fast), color var(--t-fast);
}

.chip--pick:hover {
  background: var(--bg-active);
  color: var(--ink);
}

.chip--pick.is-on {
  background: var(--ink);
  color: var(--bg-page);
}


/* ── Место на экране ──────────────────────────────────────────────── *
   Экран в миниатюре: шесть мест, где может стоять всплывающая строка.
   Показать вернее, чем назвать: «справа снизу» — это вот здесь.       */

.spot {
  display: inline-grid;
  grid-template-columns: repeat(3, var(--sp-12));
  grid-template-rows: repeat(2, var(--sp-10));
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-sunken);
}

.spot__cell {
  display: flex;
  padding: var(--sp-1h);
  cursor: pointer;
}

/* Сама строка в миниатюре. */
.spot__cell::before {
  content: "";
  width: var(--sp-6);
  height: var(--sp-2);
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-raised);
  transition: background-color var(--t-fast), border-color var(--t-fast);
}

.spot__cell:hover::before {
  border-color: var(--ink-muted);
}

.spot__cell.is-on::before {
  border-color: var(--ink);
  background: var(--ink);
}

.spot__cell--top-left     { align-items: flex-start; justify-content: flex-start; }
.spot__cell--top          { align-items: flex-start; justify-content: center; }
.spot__cell--top-right    { align-items: flex-start; justify-content: flex-end; }
.spot__cell--bottom-left  { align-items: flex-end;   justify-content: flex-start; }
.spot__cell--bottom       { align-items: flex-end;   justify-content: center; }
.spot__cell--bottom-right { align-items: flex-end;   justify-content: flex-end; }


/* ── Выбор файла ──────────────────────────────────────────────────── *
   Родное поле «Обзор…» спрятано под свою кнопку: у него в каждой
   системе свой вид и свой язык.                                      */

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

.filepick > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.filepick > input:focus-visible + .btn {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.filepick__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}


/* ── Плашка и бейдж ───────────────────────────────────────────────── */

/* Метка на письме: имя словами, цвет — квадратом. Узнавать метку только
   по цвету значило бы держать в голове таблицу соответствий. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1h);
  height: 20px;
  max-width: 160px;
  padding: 0 var(--sp-1h);
  background: var(--bg-control);
  color: var(--ink-2);
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
}

.chip > span:last-child {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Цветной квадрат тона — у метки, ящика, кампании. */
.dot {
  flex: none;
  width: 8px;
  height: 8px;
  background: var(--tone, var(--ink-faint));
}

.dot--ok   { background: var(--ok); }
.dot--warn { background: var(--warn); }
.dot--bad  { background: var(--danger); }
.dot--off  { background: var(--ink-faint); }

/* Бейдж состояния: «SPF pass», «включено», «админ». */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  height: 20px;
  padding: 0 var(--sp-1h);
  border: var(--hair) solid var(--line-strong);
  color: var(--ink-2);
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  line-height: 1;
  white-space: nowrap;
}

.badge--ok   { border-color: transparent; background: var(--ok-bg);     color: var(--ok); }
.badge--bad  { border-color: transparent; background: var(--danger-bg); color: var(--danger); }
.badge--warn { border-color: transparent; background: var(--warn-bg);   color: var(--warn); }

/* Видимость по ширине: слово, которому на телефоне нет места, и замена
   ему. Порог тот же, что у остальных правил для узкого экрана. */
.narrow-only {
  display: none;
}

/* Счётчик. Лаймовый — только непрочитанное. */
.count {
  flex: none;
  min-width: 20px;
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  text-align: right;
  color: var(--ink-muted);
}

.count--unread {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 18px;
  padding: 0 var(--sp-1h);
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: var(--fw-semi);
  text-align: center;
}


/* ── Аватар ───────────────────────────────────────────────────────── */

.avatar {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--h-md);
  height: var(--h-md);
  overflow: hidden;
  background: color-mix(in srgb, var(--tone, var(--ink-faint)) 18%, var(--bg-page));
  color: var(--tone, var(--ink));
  font-size: var(--text-sm);
  font-weight: var(--fw-semi);
  line-height: 1;
  text-transform: uppercase;
}

.avatar--sm { width: var(--h-xs); height: var(--h-xs); font-size: var(--text-2xs); }
.avatar--lg { width: var(--h-lg); height: var(--h-lg); font-size: var(--text-base); }

.avatar > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}


/* ── Сообщение в полосе ───────────────────────────────────────────── */

.notice {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--h-lg);
  padding: var(--sp-2) var(--sp-3);
  background: var(--bg-control);
  color: var(--ink-2);
  font-size: var(--text-sm);
}

.notice > .icon {
  color: var(--ink-muted);
}

.notice__text {
  flex: 1 1 0%;
  min-width: 0;
}

.notice--ok   { background: var(--ok-bg);     color: var(--ok); }
.notice--bad  { background: var(--danger-bg); color: var(--danger); }
.notice--warn { background: var(--warn-bg);   color: var(--warn); }

.notice--ok > .icon,
.notice--bad > .icon,
.notice--warn > .icon {
  color: inherit;
}


/* ── Слово помощника ──────────────────────────────────────────────── *
   Пересказ письма и ответ на вопрос к почте. Текст написала машина —
   поэтому он стоит отдельной плашкой, подписан и не выдаёт себя за
   письмо или за интерфейс.                                            */

.brief {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-sunken);
}

.brief[hidden] {
  display: none;
}

.brief__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--ink-muted);
}

.brief__close {
  margin: calc(var(--sp-1) * -1) calc(var(--sp-2) * -1) calc(var(--sp-1) * -1) auto;
}

.brief__text {
  color: var(--ink);
  font-size: var(--text-base);
  line-height: var(--lh-normal);
  white-space: pre-line;
}

/* Помощник ещё думает — текст на втором плане. */
.brief.is-busy > .brief__text {
  color: var(--ink-muted);
}

.brief.is-bad > .brief__text {
  color: var(--danger);
}

.brief__list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-0h);
}

/* Варианты ответа: каждый — кнопкой во всю ширину, текст целиком. */
.brief__picks {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1h);
}

.brief__picks:empty {
  display: none;
}

.brief__pick {
  padding: var(--sp-2) var(--sp-3);
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-page);
  color: var(--ink);
  font-size: var(--text-base);
  line-height: var(--lh-snug);
  text-align: left;
  transition: background-color var(--t-fast), border-color var(--t-fast);
}

.brief__pick:hover {
  border-color: var(--ink);
  background: var(--bg-hover);
}

/* Вычитка: правки помощника под текстом письма. */
.proof {
  display: flex;
  flex: none;
  flex-direction: column;
  gap: var(--sp-2);
  max-height: min(280px, 40vh);
  padding: var(--sp-3) var(--sp-6);
  border-top: var(--hair) solid var(--line);
  background: var(--bg-sunken);
}

.proof[hidden] {
  display: none;
}

.composer--inline > .proof {
  padding-right: var(--sp-4);
  padding-left: var(--sp-4);
  /* Под ответом прилипли кнопки отправки: когда страница подводит к
     правкам, они должны встать над кнопками, а не под ними. Запас —
     поле области прокрутки, от которого кнопки и отсчитывают низ, плюс
     сами кнопки. */
  scroll-margin-bottom: calc(var(--sp-10) + var(--sp-12) + var(--sp-2));
}

.proof__state {
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

.proof.is-bad > .proof__state {
  color: var(--danger);
}

.proof__list {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.proof__list:empty {
  display: none;
}

.proof__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1) var(--sp-3);
  min-height: var(--sp-10);
  padding: var(--sp-1h) 0;
  font-size: var(--text-sm);
}

.proof__item + .proof__item {
  border-top: var(--hair) solid var(--line);
}

.proof__change {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  font-size: var(--text-base);
}

.proof__change > .icon {
  flex: none;
  color: var(--ink-faint);
}

.proof__from {
  color: var(--ink-muted);
  text-decoration: line-through;
}

.proof__to {
  color: var(--ink);
  font-weight: var(--fw-medium);
  text-decoration: none;
}

.proof__why {
  flex: 1 1 0%;
  min-width: 0;
  color: var(--ink-muted);
}

.proof__acts {
  display: inline-flex;
  flex: none;
  gap: var(--sp-1);
}

/* Дела дня от помощника: что сделать, к какому сроку, по какому письму. */
.todo {
  margin-bottom: var(--sp-3);
}

.todo__list {
  display: flex;
  flex-direction: column;
}

.todo__list:empty {
  display: none;
}

.todo__item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-0h) var(--sp-3);
  padding: var(--sp-2) 0;
  font-size: var(--text-sm);
}

li + li > .todo__item {
  border-top: var(--hair) solid var(--line);
}

.todo__what {
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: var(--fw-medium);
}

.todo__due {
  color: var(--warn);
  font-weight: var(--fw-medium);
  white-space: nowrap;
}

.todo__from {
  grid-column: 1;
  overflow: hidden;
  color: var(--ink-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.todo__when {
  grid-column: 2;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.todo__item:hover > .todo__what {
  text-decoration: underline;
  text-decoration-color: var(--ink-faint);
  text-underline-offset: 3px;
}

.brief__list:empty {
  display: none;
}

/* Письмо-источник: номер, тема, от кого и когда. */
.brief__item {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  min-height: var(--h-xs);
  color: var(--ink-2);
  font-size: var(--text-sm);
}

.brief__item:hover {
  color: var(--ink);
}

.brief__item > .brief__n {
  flex: none;
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.brief__item > .brief__what {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--fw-medium);
}

.brief__item > .brief__who {
  flex: none;
  color: var(--ink-muted);
}

/* Ответ на вопрос к почте стоит над списком писем. Длинный ответ список
   не выдавливает: плашка растёт до трети экрана, дальше листается сама. */
.brief--answer {
  max-height: min(320px, 40vh);
  margin: var(--sp-3) var(--pad);
}

.brief__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}


/* ── Подсказка ────────────────────────────────────────────────────── *
   Слово к кнопке-значку. Появляется с задержкой — на беглом проходе
   мышью не мелькает.                                                 */

[data-tip] {
  position: relative;
}

[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  z-index: var(--z-toast);
  top: calc(100% + var(--sp-1h));
  left: 50%;
  translate: -50% 0;
  padding: var(--sp-1) var(--sp-2);
  background: var(--ink);
  color: var(--bg-page);
  font-family: var(--font-sans);
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--t-fast);
}

[data-tip]:hover::after,
[data-tip]:focus-visible::after {
  opacity: 1;
  transition-delay: 400ms;
}

[data-tip][data-tip-side="right"]::after { left: auto; right: 0; translate: 0 0; }
[data-tip][data-tip-side="left"]::after  { left: 0; translate: 0 0; }
[data-tip][data-tip-side="top"]::after   { top: auto; bottom: calc(100% + var(--sp-1h)); }

/* Раскрытое меню подсказку не показывает: она легла бы поверх пунктов. */
details[open] > [data-tip]::after {
  display: none;
}


/* ── Раскрывашка ──────────────────────────────────────────────────── */

.fold {
  min-width: 0;
}

.fold__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--h-md);
  color: var(--ink-2);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  user-select: none;
}

.fold__head:hover {
  color: var(--ink);
}

.fold__head > .icon:first-child {
  color: var(--ink-muted);
  transition: rotate var(--t-fast) var(--ease);
}

.fold[open] > .fold__head > .icon:first-child {
  rotate: 90deg;
}

/* Справа в заголовке складного раздела — когда и сколько: мелко, серым.
   Название слева сжимается первым — длинное обрежется, а не столкнёт. */
.fold__head > .truncate {
  min-width: 0;
}

.fold__meta {
  margin-left: auto;
  padding-left: var(--sp-3);
  color: var(--ink-muted);
  font-weight: var(--fw-normal);
}

/* Отозванный агент — серым: он есть в списке, но не работает. */
.fold.is-off > .fold__head {
  color: var(--ink-muted);
}

/* Текст письма агента перед отправкой читают целиком. */
.agentmail__text {
  max-height: 360px;
}

.fold__body {
  padding: var(--sp-3) 0 var(--sp-4) var(--sp-6);
}


/* ── Вкладки ──────────────────────────────────────────────────────── */

.tabs {
  display: flex;
  align-items: stretch;
  gap: var(--sp-4);
  min-width: 0;
}

.tab {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1h);
  height: var(--h-md);
  border-bottom: 2px solid transparent;
  color: var(--ink-muted);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  white-space: nowrap;
  transition: color var(--t-fast), border-color var(--t-fast);
}

.tab:hover {
  color: var(--ink);
}

.tab.is-on {
  color: var(--ink);
  border-bottom-color: var(--ink);
}

/* Вкладки рода писем: четыре слова и числа. На узком экране в полосу
   они не входят — ряд листается пальцем, а не ломается на две строки. */
.tabs--kinds {
  overflow-x: auto;
  scrollbar-width: none;
}

.tabs--kinds::-webkit-scrollbar {
  display: none;
}

.tabs--kinds > .tab {
  flex: none;
}

/* Край, за которым есть ещё вкладки, тает (сторону называет скрипт). */
.tabs--kinds[data-more="end"] {
  mask-image: linear-gradient(to left, transparent, #000 var(--sp-8));
}

.tabs--kinds[data-more="start"] {
  mask-image: linear-gradient(to right, transparent, #000 var(--sp-8));
}

.tabs--kinds[data-more="start end"] {
  mask-image: linear-gradient(to right, transparent, #000 var(--sp-8), #000 calc(100% - var(--sp-8)), transparent);
}

/* Число стоит вплотную к своему слову: с обычной шириной счётчика оно
   висело посередине между двумя вкладками, и было не понять, чьё оно. */
.tab > .count {
  min-width: 0;
}


/* ── Демо ──────────────────────────────────────────────────────────
   Напоминание в панели: демо общее и сбрасывается каждую ночь. */
.rail__demo {
  margin: 0 var(--sp-3) var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  border: var(--hair) solid var(--line);
  font-size: var(--text-xs);
  line-height: 1.45;
  color: var(--ink-muted);
}


/* ── Пустое место ─────────────────────────────────────────────────── */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-16) var(--sp-6);
  text-align: center;
}

.empty > .icon {
  width: var(--icon-lg);
  height: var(--icon-lg);
  margin-bottom: var(--sp-2);
  color: var(--ink-faint);
}

.empty__title {
  font-size: var(--text-base);
  font-weight: var(--fw-medium);
  color: var(--ink-2);
}

.empty__hint {
  max-width: 44ch;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.empty--inline {
  align-items: flex-start;
  padding: var(--sp-4) 0;
  text-align: left;
}

/* Действия под пустым местом — по его оси, а не по левому краю. */
.empty > .form__foot {
  justify-content: center;
  margin-top: var(--sp-2);
}


/* ── Таблица ──────────────────────────────────────────────────────── *
   Любой список со столбцами: сеансы, копии, правила, доноры. Столбцы
   объявляет экран одной строкой; строки берут их у таблицы, поэтому
   ячейки стоят друг под другом, какой бы длины ни был текст.         */

.table {
  display: grid;
  grid-template-columns: var(--cols, minmax(0, 1fr) auto);
  column-gap: var(--sp-4);
  min-width: 0;
}

.table__row {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  align-items: center;
  min-height: var(--h-lg);
  padding: var(--sp-1) 0;
  border-bottom: var(--hair) solid var(--line);
}

.table__row:last-child {
  border-bottom: 0;
}

.table__row--head {
  min-height: var(--h-md);
  border-bottom-color: var(--line-strong);
}

.table__cell {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--text-base);
  color: var(--ink-2);
}

.table__cell--main {
  color: var(--ink);
  font-weight: var(--fw-medium);
}

.table__cell--meta {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.table__cell--num {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.table__cell--acts {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-1);
  overflow: visible;
}

.table__row.is-off .table__cell {
  color: var(--ink-faint);
}

/* Раскрытая под строкой форма занимает всю ширину таблицы. */
.table__wide {
  grid-column: 1 / -1;
  min-width: 0;
}


/* ── Блок ─────────────────────────────────────────────────────────── *
   Карточка: рамка, заголовок, содержимое. Одна на «Сегодня», аутрич
   и календарь.                                                       */

.card {
  /* Поле названо: полосам внутри блока (воронка) нужно знать его, чтобы
     дойти до рамки. */
  --card-pad: var(--sp-5);

  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-width: 0;
  padding: var(--card-pad);
  border: var(--hair) solid var(--line);
  background: var(--bg-raised);
}

.card__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-3);
  min-height: var(--h-xs);
}

/* Название сжимается, кнопки справа — нет: на узком экране длинное имя
   уходит в многоточие, а не выталкивает кнопки друг под друга. */
.card__head > .card__title {
  flex: 1 1 0%;
  min-width: 0;
}

.card__head > .cluster {
  flex: none;
  flex-wrap: nowrap;
}

.card__title > .badge,
.card__title > .dot,
.card__title > .icon {
  flex: none;
}

.card__title {
  font-size: var(--text-base);
  font-weight: var(--fw-semi);
  color: var(--ink);
}

/* Заголовок со значком: значок стоит рядом с текстом, а длинный текст
   переносится сам — не сбрасывая значок на отдельную строку над собой. */
.card__title.cluster {
  flex-wrap: nowrap;
}

.card__title.cluster > span {
  min-width: 0;
}

.card__more {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.card__more:hover {
  color: var(--ink);
}

.card__hint {
  max-width: 72ch;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

/* Число с подписью. */
.stat {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.stat__value {
  font-size: var(--text-2xl);
  font-weight: var(--fw-semi);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ink);
}

.stat__label {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.stat--lead .stat__value {
  font-size: var(--text-3xl);
}

/* Ноль — тихо: подсвеченный ноль тянет взгляд туда, где ничего нет. */
.stat.is-zero .stat__value {
  color: var(--ink-faint);
}

.stat--accent:not(.is-zero) .stat__value {
  color: var(--accent-line);
}


/* ── Окно поверх ──────────────────────────────────────────────────── *
   Свой вопрос и своё поле вместо системных confirm и prompt.         */

.dialog {
  width: min(420px, calc(100vw - var(--sp-8)));
  margin: auto;
  padding: var(--sp-6);
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-raised);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
}

.dialog::backdrop {
  background: var(--scrim);
}

.dialog--wide {
  width: min(480px, calc(100vw - var(--sp-8)));
  max-height: calc(100vh - var(--sp-8));
  overflow-y: auto;
}

/* Справка по клавишам: клавиша — что делает, группами. */
.keys {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.keys > dt {
  display: flex;
  gap: var(--sp-1);
}

.keys__group {
  grid-column: 1 / -1;
  margin-top: var(--sp-2);
  color: var(--ink-muted);
}

.keys__group:first-child {
  margin-top: 0;
}

.dialog__title {
  font-size: var(--text-lg);
  font-weight: var(--fw-semi);
}

.dialog__text {
  color: var(--ink-2);
}

.dialog__foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
}


/* ── Всплывающие строки ───────────────────────────────────────────── *
   Итог действия и — пока не поздно — кнопка «отменить»: убрал письмо,
   отправил, удалил контакт. Вопроса «точно?» перед такими действиями
   нет: вместо него несколько секунд на то, чтобы передумать.

   Строки стоят стопкой в углу, который выбрал человек (`data-corner`
   на корне, настройки → интерфейс); по умолчанию — справа снизу.
   Стопка лежит над рабочей частью экрана, а не над боковой панелью:
   сообщение относится к тому, что сделано в списке или в письме.

   Срок строки виден: полоска по нижнему краю убывает вместе с ним.
   Отказ срока не имеет и ждёт, пока его закроют.                      */

.toasts {
  position: fixed;
  z-index: var(--z-toast);
  inset: auto 0 var(--sp-10) 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--sp-2);
  padding: 0 var(--pad);
  /* Тень — здесь, а не на строке: у контрастной строки краски другой
     темы, и своя тень вышла бы чёрной на белой странице. */
  filter: drop-shadow(var(--shadow-lift) var(--shadow-ink));
  /* Пустая стопка и её поля щелчков не ловят — под ними список. */
  pointer-events: none;
}

/* Рядом боковая панель — стопка начинается за ней. */
.app ~ .toasts {
  left: var(--w-rail);
}

/* Строка не закрывает то, чем управляют. Внизу она стоит над строкой
   состояния, а при открытом письме — над его нижней полосой: «ответить»
   и «отправить» остаются под рукой. Вверху — под шапкой и полосой
   списка: поверх шапки она прятала бы заголовок экрана и поиск. */
.app.is-reading ~ .toasts {
  bottom: calc(var(--sp-16) + var(--sp-3));
}

:root[data-corner^="top"] .toasts {
  inset-block: calc(var(--h-bar) + var(--h-strip) + var(--sp-3)) auto;
  /* Свежая строка — ближе к краю, как и внизу. */
  flex-direction: column-reverse;
}

:root[data-corner$="left"] .toasts {
  align-items: flex-start;
}

:root[data-corner="top"] .toasts,
:root[data-corner="bottom"] .toasts {
  align-items: center;
}

.toast {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: min(var(--w-toast), 100%);
  min-height: var(--sp-12);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4);
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-raised);
  color: var(--ink);
  font-size: var(--text-sm);
  line-height: var(--lh-snug);
  pointer-events: auto;
}

/* Контрастная строка — в красках противоположной темы: тёмная на
   светлой странице, светлая на тёмной. Меняется не цвет, а сама тема
   внутри строки, поэтому кнопка, знак и счётчик перекрашиваются сами
   и читаются не хуже, чем на своей странице. */
:root[data-plate="bold"] .toast {
  color-scheme: dark;
}

:root[data-plate="bold"][data-theme="dark"] .toast {
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root[data-plate="bold"]:not([data-theme="light"]) .toast {
    color-scheme: light;
  }
}

.toast__icon {
  flex: none;
  margin-right: var(--sp-1);
  color: var(--ink-muted);
}

.toast__text {
  flex: 1 1 0%;
  min-width: 0;
  overflow-wrap: anywhere;
}

.toast__count {
  margin-left: var(--sp-1);
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}

.toast__act,
.toast__close {
  flex: none;
}

.toast__close {
  color: var(--ink-muted);
}

.toast__close:hover {
  color: var(--ink);
}

/* Срок строки. Убывает слева направо за `--life` — его ставит скрипт
   вместе с классом `is-live`; без скрипта строка просто стоит. */
.toast__bar {
  position: absolute;
  inset: auto 0 0 0;
  height: var(--sp-0h);
  background: var(--ink-muted);
  transform-origin: 0 50%;
  scale: 0 1;
}

.toast.is-live > .toast__bar {
  animation: toast-life var(--life, 0s) linear both;
}

/* Курсор над строкой — срок стоит: человек читает или целится в кнопку. */
.toast.is-held > .toast__bar {
  animation-play-state: paused;
}

@keyframes toast-life {
  from { scale: 1 1; }
  to   { scale: 0 1; }
}

/* Беда — красным знаком и рамкой; текст остаётся чернилами: его читают. */
.toast--bad {
  border-color: var(--danger);
}

.toast--bad > .toast__icon {
  color: var(--danger);
}


/* ── Страницы ─────────────────────────────────────────────────────── */

.pager {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
}

.pager__where {
  padding: 0 var(--sp-2);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
  white-space: nowrap;
}


/* ── Полоса заполнения ────────────────────────────────────────────── */

.meter {
  display: block;
  width: 100%;
  height: 6px;
  border: 0;
  background: var(--bg-control);
  appearance: none;
}

.meter::-webkit-progress-bar   { background: var(--bg-control); }
.meter::-webkit-progress-value { background: var(--ink-2); }
.meter::-moz-progress-bar      { background: var(--ink-2); }


/* ═══ 4. ОБОЛОЧКА ═══════════════════════════════════════════════════ *
   Панель слева и рабочая область справа — одни и те же на всех экранах.
   Вертикаль у них общая: знак логотипа, значки пунктов, заголовок
   экрана и первая колонка любого списка стоят на одном отступе
   `--pad` от своей границы.                                          */

.app {
  position: relative;
  display: grid;
  grid-template-columns: var(--w-rail) minmax(0, 1fr);
  /* Строка сетки обязана быть «не больше экрана»: автоматическая
     растягивается содержимым, и колонки перестают прокручиваться сами. */
  grid-template-rows: minmax(0, 1fr);
  height: 100%;
  overflow: clip;
  background: var(--bg-page);
}


/* ── Панель ───────────────────────────────────────────────────────── */

.rail {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg-rail);
  border-right: var(--hair) solid var(--line);
}

.rail__head {
  display: flex;
  flex: none;
  align-items: center;
  height: var(--h-bar);
  padding: 0 var(--pad);
}

/* «Написать» — команда с клавишей на виду. Подпись слева, клавиша
   справа: кнопка читается как строка меню, а не как кирпич. */
.rail__compose {
  flex: none;
  justify-content: flex-start;
  margin: 0 var(--sp-2) var(--sp-3);
  width: auto;
}

.rail__compose > .kbd {
  margin-left: auto;
}

.rail__scroll {
  flex: 1 1 0%;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 var(--sp-2) var(--sp-4);
}

/* Свёрнутые письма — над подвалом панели, всегда на виду: до них не
   нужно листать список папок. Больше четырёх — листаются сами. */
.dock {
  flex: none;
  max-height: calc(var(--h-nav) * 4 + var(--sp-10));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 var(--sp-2) var(--sp-2);
  border-top: var(--hair) solid var(--line);
}

.dock > .nav__caption {
  padding-top: var(--sp-3);
}

.dock__item {
  display: flex;
  align-items: center;
}

.dock__open {
  flex: 1 1 0%;
  min-width: 0;
}

.dock__drop {
  flex: none;
  color: var(--ink-faint);
}

.rail__foot {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--sp-1);
  height: var(--h-bar);
  padding: 0 var(--sp-2) 0 var(--sp-3);
  border-top: var(--hair) solid var(--line);
}

.rail__user {
  display: flex;
  flex: 1 1 0%;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
  color: var(--ink-2);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
}

.rail__user:hover {
  color: var(--ink);
}


/* ── Пункт панели ─────────────────────────────────────────────────── *
   Один на всё: папки, метки, свои папки, поиски, ящики, разделы.     */

.nav {
  display: flex;
  flex-direction: column;
}

.nav__caption {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--sp-5) var(--sp-3) var(--sp-1h);
}

.nav__item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  height: var(--h-nav);
  padding: 0 var(--sp-3);
  color: var(--ink-2);
  font-size: var(--text-base);
  transition: background-color var(--t-fast), color var(--t-fast);
}

.nav__item > .icon {
  color: var(--ink-faint);
  transition: color var(--t-fast);
}

.nav__item:hover {
  background: var(--bg-hover);
  color: var(--ink);
}

.nav__item:hover > .icon {
  color: var(--ink-2);
}

.nav__item.is-on {
  background: var(--bg-active);
  color: var(--ink);
  font-weight: var(--fw-medium);
}

.nav__item.is-on > .icon {
  color: var(--ink);
}

/* Письмо несут мышью: пункт или вкладка под ним, куда его можно бросить,
   встаёт в полную силу — чернилами, как главная кнопка. */
.nav__item.is-drop,
.tab.is-drop {
  background: var(--ink);
  color: var(--bg-page);
}

.nav__item.is-drop > .icon,
.nav__item.is-drop .count {
  color: inherit;
}

.tab.is-drop {
  border-bottom-color: var(--ink);
}

/* То, что едет за курсором вместо снимка строки: «Писем: 3». Стоит за
   краем экрана — браузеру нужен настоящий элемент, чтобы снять с него
   картинку. */
.dragghost {
  position: fixed;
  top: -100px;
  left: 0;
  max-width: 280px;
  padding: var(--sp-1h) var(--sp-3);
  overflow: hidden;
  background: var(--ink);
  color: var(--bg-page);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Вместо значка — квадрат тона: у ящика и метки. Он стоит в том же
   гнезде шириной со значок, чтобы подписи шли по одной вертикали. */
.nav__mark {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--icon);
  height: var(--icon);
}

.nav__label {
  flex: 1 1 0%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


/* ── Рабочая область ──────────────────────────────────────────────── */

.main {
  position: relative;
  display: grid;
  /* Столбец объявлен явно: неявный растягивается по самому широкому
     содержимому, и длинная шапка уводила бы всю страницу за край. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  min-width: 0;
  min-height: 0;
}

/* Почта: шапка, полоса списка, список, строка состояния. */
.main--mail {
  grid-template-rows: auto auto minmax(0, 1fr) auto;
}

/* Полосы над списком нет (очередь, ожидания) — её ряд из сетки уходит
   вместе с ней, а список остаётся тянущимся: иначе строка состояния
   всплывала под последнее письмо. */
.main--mail:has(> .strip[hidden]) {
  grid-template-rows: auto minmax(0, 1fr) auto;
}

/* Ответ помощника встаёт своим рядом между полосой и списком: без ряда
   он занял бы место списка, а список съехал бы под него. */
.main--mail:has(> .brief--answer:not([hidden])) {
  grid-template-rows: auto auto auto minmax(0, 1fr) auto;
}

.main--mail:has(> .strip[hidden]):has(> .brief--answer:not([hidden])) {
  grid-template-rows: auto auto minmax(0, 1fr) auto;
}

.topbar {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  height: var(--h-bar);
  padding: 0 var(--pad);
  border-bottom: var(--hair) solid var(--line);
}

/* Вызов панели — только на узком экране. */
.topbar__nav {
  display: none;
  margin-left: calc(var(--sp-2) * -1);
}

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

.topbar__name {
  overflow: hidden;
  font-size: var(--text-lg);
  font-weight: var(--fw-semi);
  letter-spacing: -0.01em;
  line-height: var(--lh-snug);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.topbar__meta {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  white-space: nowrap;
}

.topbar__tools {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
  min-width: 0;
}

/* Рядом с поиском заголовок экрана не сжимается: уступает строка поиска —
   она резиновая, а «Конт…» вместо «Контакты» читается как поломка.
   Половина шапки — предел и для самого длинного названия папки. */
.topbar:has(.search) > .topbar__title {
  flex-shrink: 0;
  max-width: 50%;
}

.topbar:has(.search) > .topbar__tools {
  flex: 1 1 0%;
  justify-content: flex-end;
}

/* Прокручиваемая страница — у всех экранов, кроме почты. */
.page {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-6) var(--pad) var(--sp-16);
}

/* Между карточками — один шаг на всех экранах. Прежде «Сегодня» держало
   16, а аутрич 24: рядом это читалось как два разных продукта. */
.page__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  max-width: var(--w-page);
}

/* Затемнение под панелью на узком экране — оно же способ её закрыть. */
.scrim {
  display: none;
}


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

.strip {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  height: var(--h-strip);
  padding: 0 var(--pad);
  border-bottom: var(--hair) solid var(--line);
}

.strip__all {
  flex: none;
}

.strip__idle,
.strip__acts {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
}

.strip__acts {
  display: none;
  gap: var(--sp-1);
}

.strip__count {
  margin-right: var(--sp-2);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  white-space: nowrap;
}

.strip__sep {
  flex: none;
  width: var(--hair);
  height: var(--sp-4);
  margin: 0 var(--sp-1);
  background: var(--line-strong);
}

.strip__tail {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
}

/* Отмечено хоть одно письмо — уточнения уступают место действиям. С ними
   уходят и действия над всем списком: рядом встают такие же кнопки для
   отмеченного. */
.main--mail:has([data-row-check]:checked) .strip__idle,
.main--mail:has([data-row-check]:checked) .strip__whole { display: none; }
.main--mail:has([data-row-check]:checked) .strip__acts { display: flex; }


/* ── Строка состояния ─────────────────────────────────────────────── */

.status {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  height: var(--h-status);
  padding: 0 var(--pad);
  border-top: var(--hair) solid var(--line);
  font-size: var(--text-xs);
  color: var(--ink-muted);
  white-space: nowrap;
}

.status__cell {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1h);
}

.status__keys {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  margin-left: auto;
}

.status__key {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1h);
}

/* «Все клавиши» — единственное в строке состояния, что нажимается. */
.status__more {
  color: inherit;
  font: inherit;
  cursor: pointer;
  transition: color var(--t-fast);
}

.status__more:hover {
  color: var(--ink);
}


/* ── Поиск ────────────────────────────────────────────────────────── */

/* Нижний предел ширины — ноль: иначе строка упирается в «родную»
   ширину поля ввода и на узком экране вылезает из шапки. */
.search {
  position: relative;
  width: 420px;
  min-width: 0;
  max-width: 100%;
}

.search__bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: var(--h-md);
  padding: 0 var(--sp-1) 0 var(--sp-3);
  border: var(--hair) solid var(--line-strong);
  transition: border-color var(--t-fast), box-shadow var(--t-fast);
}

.search__bar:hover {
  border-color: var(--ink-faint);
}

.search__bar:focus-within {
  border-color: var(--ink);
  box-shadow: 0 0 0 1px var(--ink);
}

.search__bar > .icon {
  color: var(--ink-muted);
}

.search__input {
  flex: 1 1 0%;
  min-width: 0;
  height: 100%;
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-base);
  appearance: none;
}

.search__input:focus {
  outline: none;
}

.search__input::placeholder {
  color: var(--ink-faint);
  opacity: 1;
}

.search__input::-webkit-search-cancel-button,
.search__input::-webkit-search-decoration {
  appearance: none;
  display: none;
}

.search__bar > .kbd {
  margin-right: var(--sp-1);
}

/* Подсказки под строкой поиска — во всю её ширину. */
.search__hints {
  right: 0;
  width: auto;
  max-width: none;
}

.search__hints .pop__item {
  justify-content: space-between;
}

/* Поля письма — панелью под строкой: её адрес можно скопировать и
   вернуться к тому же запросу. */
.search__panel {
  width: 100%;
  max-width: none;
  max-height: none;
}

.search__grid {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-3) var(--sp-4);
}

.search__grid > .field__label {
  white-space: nowrap;
}

.search__foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}


/* ═══ 5. ЭКРАНЫ ═════════════════════════════════════════════════════ */

/* ── Список писем ─────────────────────────────────────────────────── *
   Столбцы объявлены один раз у списка, строки берут их у него —
   поэтому отправители, темы и время стоят друг под другом, какой бы
   длины ни был текст, а метки и ящик занимают ровно столько, сколько
   нужно самой длинной из них.

   Края: первый и последний столбцы вместе с зазором дают поле `--pad`.
   В первом живёт засечка непрочитанного.                              */

.list {
  --edge: calc(var(--pad) - var(--sp-3));

  display: grid;
  grid-template-columns:
    var(--edge) 16px 16px minmax(96px, 208px) minmax(0, 1fr) auto 56px var(--edge);
  column-gap: var(--sp-3);
  align-content: start;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Ящиков несколько — у строки появляется столбец «куда пришло». */
.list--multi {
  grid-template-columns:
    var(--edge) 16px 16px minmax(96px, 208px) minmax(0, 1fr) auto minmax(0, 168px) 56px var(--edge);
}

/* Заголовок дня. Прилипает к верху списка при прокрутке. */
.day {
  position: sticky;
  top: 0;
  z-index: var(--z-stick);
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  height: var(--h-md);
  padding: 0 var(--pad);
  border-bottom: var(--hair) solid var(--line);
  background: var(--bg-page);
  font-size: var(--text-xs);
  font-weight: var(--fw-semi);
  color: var(--ink-muted);
}

.row {
  position: relative;
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  height: var(--row-h);
  border-bottom: var(--hair) solid var(--line);
  color: var(--ink-2);
  transition: background-color var(--t-fast);
}

/* Жест пальцем по строке письма. По вертикали список листает браузер,
   вбок строку ведёт палец: содержимое едет за ним, а сама строка стоит
   на месте — её фон и есть подложка, на которой написано, что случится,
   если отпустить. До порога подпись спокойная; за порогом строка встаёт
   в полную силу — отпустишь, и действие сделано. */
.row[data-letter] {
  touch-action: pan-y;
}

.row.is-swiping {
  background: var(--bg-control);
  transition: none;
}

.row.is-swiping > *,
.row.is-swiping::before {
  translate: var(--dx, 0px) 0;
}

.row.is-settling > *,
.row.is-settling::before {
  transition: translate var(--t-norm) var(--ease);
}

.row.is-swiping::after {
  content: attr(data-swipe-label);
  position: absolute;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  padding: 0 var(--pad);
  color: var(--ink-2);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
}

.row.is-swiping[data-swipe-side="right"]::after { left: 0; }
.row.is-swiping[data-swipe-side="left"]::after  { right: 0; }

.row.is-swiping.is-armed {
  background: var(--ink);
}

.row.is-swiping.is-armed[data-swipe-tone="danger"] {
  background: var(--danger);
}

.row.is-swiping.is-armed::after {
  color: var(--bg-page);
}

/* За порогом письмо уже «не здесь»: его строка гаснет, остаётся подпись. */
.row.is-swiping.is-armed > *,
.row.is-swiping.is-armed::before {
  opacity: 0.2;
}

/* Засечка непрочитанного — в краевом столбце, во всю высоту строки.
   Место под неё есть у каждой строки, цвет — только у непрочитанной. */
.row::before {
  content: "";
  align-self: stretch;
  width: 3px;
}

.row.is-unread::before {
  background: var(--accent-line);
}

.row:hover {
  background: var(--bg-hover);
}

.row.is-open {
  background: var(--bg-active);
}

.row:has([data-row-check]:checked) {
  background: var(--bg-picked);
}

/* Галочка и флаг лежат поверх ссылки-строки, иначе щелчок по ним
   открывал бы письмо. */
.row__pick,
.row__flag {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
}

.row__flag {
  color: var(--ink-faint);
  transition: color var(--t-fast);
}

.row__flag:hover {
  color: var(--ink);
}

/* Помечено — флаг залит чернилами. */
.row.is-flagged .row__flag {
  color: var(--ink);
}

.row.is-flagged .row__flag > .icon {
  fill: currentColor;
}

/* У черновика флага нет — место под него остаётся, чтобы столбцы строки
   не съехали. */
.row__flag--none {
  pointer-events: none;
}

.row__sender {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Тема и начало текста одной строкой: тема занимает своё, превью —
   всё, что осталось. Ссылка накрывает строку целиком. */
.row__main {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  min-width: 0;
  white-space: nowrap;
}

.row__main::after {
  content: "";
  position: absolute;
  inset: 0;
}

.row__main:focus-visible {
  outline: none;
}

.row__main:focus-visible::after {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.row__subject {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.row__preview {
  flex: 1 1 0%;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.row.is-unread .row__sender,
.row.is-unread .row__subject {
  color: var(--ink);
  font-weight: var(--fw-semi);
}

.row__marks {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-2);
  color: var(--ink-muted);
}

.row__mark {
  display: inline-flex;
}

/* Общий ящик: кто взял переписку. Имя в рамке — как счётчик писем
   переписки рядом; своё залито: «это на мне» видно, не читая. */
.row__mate {
  display: inline-block;
  max-width: 96px;
  height: 18px;
  padding: 0 var(--sp-1);
  border: var(--hair) solid var(--line-strong);
  font-size: var(--text-2xs);
  font-weight: var(--fw-medium);
  line-height: 16px;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.row__mate.is-mine {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg-page);
}

/* Сколько писем в переписке. */
.row__thread {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 var(--sp-1);
  border: var(--hair) solid var(--line-strong);
  font-size: var(--text-2xs);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--ink-2);
}

/* В какой ящик пришло. */
.row__box {
  display: flex;
  align-items: center;
  gap: var(--sp-1h);
  min-width: 0;
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.list:not(.list--multi) .row__box {
  display: none;
}

.row__time {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
  color: var(--ink-muted);
}

.row.is-unread .row__time {
  color: var(--ink);
}

/* Частые действия — под курсором, поверх хвоста строки. Постоянный
   столбец под них держал бы сотню пикселей из каждой строки ради того,
   что видно несколько процентов времени. */
.row__quick {
  position: absolute;
  z-index: 2;
  top: 0;
  right: calc(var(--pad) - var(--sp-2));
  bottom: 0;
  display: none;
  align-items: center;
  gap: var(--sp-0h);
  padding-left: var(--sp-8);
  background: linear-gradient(to right, transparent, var(--bg-hover) var(--sp-6));
}

.row:hover .row__quick,
.row:focus-within .row__quick {
  display: flex;
}

.row.is-open .row__quick {
  background: linear-gradient(to right, transparent, var(--bg-active) var(--sp-6));
}

.row:has([data-row-check]:checked) .row__quick {
  background: linear-gradient(to right, transparent, var(--bg-picked) var(--sp-6));
}

/* Файлы письма — плашками под темой: вторая полка строки. Строка с
   файлами выше обычной; первая её полка той же высоты, что у всех,
   поэтому темы и время стоят на одной линии у всего списка. */
.row--files {
  grid-template-rows: var(--row-h) auto;
  height: auto;
}

.row--files::before {
  grid-row: 1 / span 2;
}

.row--files > .row__quick {
  bottom: auto;
  height: var(--row-h);
}

.row__files {
  position: relative;
  z-index: 1;
  grid-row: 2;
  grid-column: 5 / -2;
  display: flex;
  gap: var(--sp-2);
  min-width: 0;
  margin-top: calc(var(--sp-1) * -1);
  padding-bottom: var(--sp-2);
}

.chip--file {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 220px;
  height: var(--h-xs);
  padding: 0 var(--sp-2);
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-raised);
}

.chip--file:is(a, button):hover {
  border-color: var(--ink);
  color: var(--ink);
}

/* Опасный файл в строке списка: значок вместо скрепки — и только он. */
.chip--risk > .icon {
  color: var(--warn);
}

/* Есть плашки — скрепка в хвосте строки лишняя. */
.row--files .row__clip {
  display: none;
}

/* В плотном списке строка остаётся в одну полку: плашки уступают место
   числу писем на экране, файлы показывает скрепка. */
:root[data-density="compact"] .row--files {
  grid-template-rows: none;
  height: var(--row-h);
}

:root[data-density="compact"] .row__files {
  display: none;
}

:root[data-density="compact"] .row--files .row__clip {
  display: inline-flex;
}

/* Всё, что не строка письма, занимает ширину списка целиком. */
.list__wide {
  grid-column: 1 / -1;
  min-width: 0;
}

.list__note {
  grid-column: 1 / -1;
  margin: var(--sp-3) var(--pad) 0;
}

/* Страницы в конце списка — там, где кончилось чтение. */
.list__foot,
.book__foot {
  display: flex;
  justify-content: center;
  padding: var(--sp-4) var(--pad);
}


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

.book {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.book__item {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr);
  column-gap: var(--sp-3);
  align-items: start;
  padding: 0 var(--pad);
  border-bottom: var(--hair) solid var(--line);
  transition: background-color var(--t-fast);
}

.book__item:hover {
  background: var(--bg-hover);
}

.book__item:has(> .book__fold[open]) {
  background: var(--bg-active);
}

.book__item:has([data-row-check]:checked) {
  background: var(--bg-picked);
}

/* Галочка — по высоте строки, а не всей раскрытой записи. */
.book__item > .tick {
  height: var(--row-h);
}

/* Запись стоит во втором столбце и без галочки: в общем справочнике её
   нет у чужих записей, а имена должны стоять друг под другом у всех. */
.book__item > .book__fold {
  grid-column: 2;
  min-width: 0;
}

.book__head {
  display: grid;
  grid-template-columns:
    var(--h-xs) minmax(0, 3fr) minmax(0, 4fr) minmax(0, 3fr) minmax(0, 3fr) 72px auto;
  align-items: center;
  column-gap: var(--sp-3);
  height: var(--row-h);
  color: var(--ink-2);
  font-size: var(--text-base);
  user-select: none;
}

.book__name,
.book__addr,
.book__org,
.book__meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.book__name {
  color: var(--ink);
  font-weight: var(--fw-medium);
}

.book__meta,
.book__last {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.book__last {
  text-align: right;
}

.book__acts {
  display: flex;
  gap: var(--sp-0h);
}

/* Форма правки встаёт под именем: тело записи повторяет первый столбец
   строки, и левая граница у имени и у полей одна. */
.book__body {
  display: grid;
  grid-template-columns: var(--h-xs) minmax(0, var(--w-form));
  column-gap: var(--sp-3);
  padding: var(--sp-2) 0 var(--sp-5);
}

.book__body > .form,
.book__body > .book__facts {
  grid-column: 2;
}

/* Чужая запись общего справочника: заметка и кто её ведёт. */
.book__facts {
  display: grid;
  gap: var(--sp-2);
  font-size: var(--text-sm);
}

.book__text {
  color: var(--ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.book__note {
  padding: var(--sp-3) var(--pad) 0;
}

/* ── Задачи ───────────────────────────────────────────────────────── *
   Тот же каркас, что у контактов: строка той же высоты, раскрывается в
   правку на месте. Слева вместо галочки выбора — отметка «сделано».   */

.book__head--task {
  grid-template-columns: minmax(0, 5fr) minmax(0, 5fr) minmax(0, auto) auto;
}

.book--tasks .book__last {
  min-width: 96px;
}

/* Просроченное — жёлтым сроком: строку целиком не красим. */
.book__item.is-late .book__last {
  color: var(--warn);
}

.book__item.is-done .book__name {
  color: var(--ink-muted);
  text-decoration: line-through;
  text-decoration-color: var(--ink-faint);
}

/* Отметка «сделано»: квадрат на месте галочки выбора. Пустой — дело
   впереди; с птичкой — сделано. Наведение показывает, что будет.

   Нажимается не сам квадрат, а кнопка вокруг него: в шестнадцать точек
   пальцем не попасть. Кнопка шире своего столбца и заходит в поля по
   бокам, поэтому строка стоит как стояла. */
.taskcheck {
  display: flex;
  align-items: center;
  justify-content: center;
  height: var(--row-h);
}

.taskcheck__hit {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--h-md);
  height: 100%;
}

.taskcheck__box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border: var(--hair) solid var(--line-strong);
  color: transparent;
  transition: border-color var(--t-fast), background-color var(--t-fast), color var(--t-fast);
}

.taskcheck__hit:hover > .taskcheck__box {
  border-color: var(--ink);
  color: var(--ink-muted);
}

.is-done > .taskcheck > .taskcheck__hit > .taskcheck__box {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg-page);
}

/* Сделанное — вложенным списком в своём сворачиваемом блоке. */
.tasks__done {
  margin: var(--sp-4) var(--pad) var(--sp-8);
}

.book--inner {
  overflow: visible;
  margin-bottom: var(--sp-3);
}

.book--inner > .book__item {
  padding: 0;
}

/* Задача на плашке письма: птичка, слова, срок. */
.chip--task {
  gap: var(--sp-1h);
  max-width: 320px;
}

.chip--task > a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* И здесь нажимается кнопка вокруг птички: она выше самой плашки и шире
   квадрата, а в строке занимает столько же места. */
.chip__hit {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--h-xs);
  height: var(--h-xs);
  margin: 0 calc(var(--sp-1) * -1);
}

.chip__check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  border: var(--hair) solid var(--line-strong);
  color: transparent;
  transition: border-color var(--t-fast), color var(--t-fast), background-color var(--t-fast);
}

.chip__hit:hover > .chip__check {
  border-color: var(--ink);
  color: var(--ink-muted);
}

.chip--task.is-done > .chip__hit > .chip__check {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg-page);
}

.chip--task.is-done > a {
  color: var(--ink-muted);
  text-decoration: line-through;
  text-decoration-color: var(--ink-faint);
}

.chip__due {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.chip--task.is-late > .chip__due {
  color: var(--warn);
}

.book__wide {
  min-width: 0;
}

/* ── Подписки ─────────────────────────────────────────────────────── *
   Рассылки по отправителям — в том же каркасе, что и книга: строки той
   же высоты, столбцы долями. Справа — что с рассылкой уже сделано и что
   можно сделать.                                                      */

/* Столбцы задаёт сам список, строки их только наследуют: кнопки справа
   у строк разной ширины, и со своей сеткой у каждой строки адреса и
   числа стояли бы вразнобой. */
.subs {
  /* Поля строки — крайними столбцами, как у списка писем: с отступами
     самой строки унаследованная сетка съедала бы первый столбец. */
  --edge: calc(var(--pad) - var(--sp-3));
  display: grid;
  grid-template-columns:
    var(--edge) var(--h-xs) minmax(0, 3fr) minmax(0, 4fr) minmax(0, 4fr) auto auto var(--edge);
  align-content: start;
  column-gap: var(--sp-3);
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.subs__item {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  min-height: var(--row-h);
  border-bottom: var(--hair) solid var(--line);
  color: var(--ink-2);
  transition: background-color var(--t-fast);
}

.subs__item > .avatar {
  grid-column: 2;
}

.subs__item:hover {
  background: var(--bg-hover);
}

.subs__name {
  color: var(--ink);
  font-weight: var(--fw-medium);
}

/* От этой рассылки уже отписались: она остаётся в списке, но уходит на
   второй план. */
.subs__item.is-off > .subs__name {
  color: var(--ink-muted);
  font-weight: var(--fw-normal);
}

.subs__addr,
.subs__meta {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.subs__meta {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.subs__state {
  display: flex;
  justify-content: flex-end;
  min-width: 0;
}

.subs__acts {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--sp-0h);
}

.subs__wide {
  grid-column: 1 / -1;
  min-width: 0;
}

/* Очередь отправки и ожидания: те же строки, свои столбцы. */
.list--queue {
  grid-template-columns:
    var(--edge) minmax(0, 2fr) minmax(0, 2fr) minmax(0, 1fr) auto var(--edge);
}

.queue {
  position: relative;
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  min-height: var(--row-h);
  border-bottom: var(--hair) solid var(--line);
  color: var(--ink-2);
}

.queue::before {
  content: "";
  align-self: stretch;
  width: 3px;
}

.queue.is-bad::before {
  background: var(--danger);
}

.queue.is-late::before {
  background: var(--warn);
}

.queue__main {
  overflow: hidden;
  color: var(--ink);
  font-weight: var(--fw-medium);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.queue__cell {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.queue__meta {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  white-space: nowrap;
}

.queue.is-bad .queue__meta  { color: var(--danger); }
.queue.is-late .queue__meta { color: var(--warn); }

.queue__acts {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-1);
}


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

.reader {
  position: absolute;
  z-index: var(--z-panel);
  top: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  /* Ширина — «всё, кроме боковой панели», а предел её сужает. Меняется
     при развороте только предел: от пикселей к процентам браузер ведёт
     его плавно. */
  width: calc(100% - var(--w-rail));
  max-width: var(--w-reader);
  min-width: 0;
  border-left: var(--hair) solid var(--line-strong);
  background: var(--bg-raised);
  box-shadow: var(--shadow-pop);
  container: reader / inline-size;
}

:root[data-reader="wide"] .reader {
  max-width: calc(100% - var(--w-rail));
}

.letter,
.composer {
  position: relative;
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  min-height: 0;
}

/* Полоса действий над письмом и над редактором. */
.letter__bar {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--sp-0h);
  height: var(--h-bar);
  padding: 0 var(--sp-3);
  border-bottom: var(--hair) solid var(--line);
}

.letter__bar-tail {
  display: flex;
  align-items: center;
  gap: var(--sp-0h);
  margin-left: auto;
}

.letter__scroll {
  flex: 1 1 0%;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-6) var(--sp-6) var(--sp-10);
}

/* Всё содержимое письма держит одну меру: строка длиннее 80 знаков
   читается хуже, какой бы широкой ни была панель. */
.letter__scroll > * {
  max-width: var(--w-read);
}

.letter__scroll > * + * {
  margin-top: var(--sp-5);
}

.letter__head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.letter__subject {
  font-size: var(--text-xl);
  font-weight: var(--fw-semi);
  letter-spacing: -0.015em;
  line-height: var(--lh-tight);
  overflow-wrap: anywhere;
}

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

.letter__who {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  gap: var(--sp-0h);
  min-width: 0;
}

.letter__names {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  min-width: 0;
}

.letter__sender {
  overflow: hidden;
  font-weight: var(--fw-semi);
  color: var(--ink);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.letter__addr {
  overflow: hidden;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Письмо в узкой панели: адрес отправителя уходит в «Подробности» —
   имя важнее, а вдвоём они обрезали бы друг друга. Мерим саму панель,
   а не экран: узкой она бывает и на широком. */
@container reader (max-width: 520px) {
  .letter__addr {
    display: none;
  }
}

.letter__seal {
  display: inline-flex;
  align-self: center;
  color: var(--ok);
}

.letter__to,
.letter__time {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.letter__time {
  flex: none;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

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

/* Пустой блок заметок места не занимает — иначе под шапкой письма
   получался двойной отступ. `:empty` тут не годится: внутри остаются
   переводы строк из шаблона. */
.letter__notes:not(:has(*)) {
  display: none;
}

.letter__foot {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--sp-2);
  height: var(--sp-16);
  padding: 0 var(--sp-6);
  border-top: var(--hair) solid var(--line);
  background: var(--bg-raised);
}

/* Крестик у метки в шапке письма. */
.chip__drop {
  display: inline-flex;
  margin-right: calc(var(--sp-1) * -1);
  color: var(--ink-faint);
}

.chip__drop:hover {
  color: var(--ink);
}

/* Пары «что — значение»: паспорт письма, приглашение, записи домена. */
.facts {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--sp-2) var(--sp-5);
  font-size: var(--text-sm);
}

.facts > dt {
  color: var(--ink-muted);
}

.facts > dd {
  min-width: 0;
  color: var(--ink-2);
  overflow-wrap: anywhere;
}

/* Отпечаток сертификата: две строки по шестнадцать пар, одна под другой.
   Его сверяют глазами знак в знак, поэтому он ярче соседнего текста и
   рвётся только там, где пары кончились, а не посреди пары. */
.print {
  display: grid;
  grid-template-columns: repeat(2, max-content);
  gap: var(--sp-1) var(--sp-3);
  font-size: var(--text-sm);
  color: var(--ink);
}

.print > span {
  white-space: nowrap;
}


/* ── Текст ────────────────────────────────────────────────────────── *
   Письмо без своей вёрстки и то, что набирают в редакторе: один шрифт,
   одна мера, одни отступы.                                            */

.prose {
  font-size: var(--text-md);
  line-height: var(--lh-read);
  color: var(--ink);
  overflow-wrap: anywhere;
}

.prose > * + * {
  margin-top: 0.8em;
}

.prose a {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--ink-faint);
  text-underline-offset: 3px;
}

.prose a:hover {
  text-decoration-color: var(--ink);
}

.prose h1, .prose h2, .prose h3 {
  margin-top: 1.4em;
  font-size: var(--text-lg);
}

.prose ul, .prose ol {
  padding-left: 1.4em;
}

.prose ul { list-style: square; }
.prose ol { list-style: decimal; }

.prose li + li {
  margin-top: 0.3em;
}

.prose blockquote {
  padding-left: var(--sp-4);
  border-left: 2px solid var(--line-strong);
  color: var(--ink-2);
}

/* Абзацы внутри цитаты и блоков держат тот же шаг, что и снаружи. */
.prose blockquote > * + *,
.prose div > * + *,
.prose li > * + * {
  margin-top: 0.8em;
}

/* Блок подписи: строки подряд, без шага между ними. */
.prose [data-signature] {
  color: var(--ink-2);
}

.prose pre,
.prose code {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

/* Письмо, пришедшее голым текстом: переносы — как набрал отправитель,
   шрифт — наш. */
.prose pre {
  white-space: pre-wrap;
  font-family: inherit;
  font-size: inherit;
}

.prose img {
  height: auto;
}

.prose hr {
  height: var(--hair);
  border: 0;
  background: var(--line);
}

.prose table {
  width: 100%;
  font-size: var(--text-base);
}

.prose td, .prose th {
  padding: var(--sp-2) var(--sp-3);
  border: var(--hair) solid var(--line);
  text-align: left;
  vertical-align: top;
}

/* Свёрстанное письмо — в своём окне, во всю ширину панели. Высоту
   подгоняет скрипт по содержимому. */
.letter__body:has(.letter__frame) {
  max-width: none;
}

.letter__frame {
  width: 100%;
  min-height: 160px;
  border: 0;
  background: #ffffff;
  color-scheme: light;
}


/* ── Приглашение на встречу ───────────────────────────────────────── */

.invite {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-5);
  border: var(--hair) solid var(--line-strong);
}

.invite__head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.invite__head > .icon {
  color: var(--ink-muted);
}

.invite__title {
  flex: 1 1 0%;
  min-width: 0;
  font-size: var(--text-base);
}

.invite__answer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  padding-top: var(--sp-4);
  border-top: var(--hair) solid var(--line);
}

.invite__answer > .muted {
  margin-right: auto;
  font-size: var(--text-sm);
}

.invite.is-off .invite__title {
  color: var(--ink-muted);
  text-decoration: line-through;
}


/* ── Вложения ─────────────────────────────────────────────────────── */

.files {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.files__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(216px, 1fr));
  gap: var(--sp-2);
}

.file {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-width: 0;
  height: var(--sp-12);
  padding: 0 var(--sp-1) 0 var(--sp-2);
  border: var(--hair) solid var(--line);
  transition: border-color var(--t-fast), background-color var(--t-fast);
}

.file:hover {
  border-color: var(--line-strong);
  background: var(--bg-control);
}

.file__thumb,
.file__kind {
  flex: none;
  width: var(--h-md);
  height: var(--h-md);
}

.file__thumb {
  object-fit: cover;
  background: var(--bg-control);
}

.file__kind {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-control);
  font-family: var(--font-mono);
  /* Самый мелкий кегль шкалы: четыре знака («DOCX», «HTML») в плитку
     входят, а своего размера мимо шкалы у метки больше нет. */
  font-size: var(--text-2xs);
  font-weight: var(--fw-semi);
  color: var(--ink-2);
}

.file__text {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  min-width: 0;
  line-height: var(--lh-snug);
}

.file__name {
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  color: var(--ink);
}

.file__size {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* Что о файле надо знать: «программа», «проверен антивирусом», «вирус».
   Той же строкой, что и вес, — плитка не растёт. Беда красным, то, о чём
   стоит подумать, — жёлтым. */
.file__note--warn {
  color: var(--warn);
}

.file__note--bad {
  color: var(--danger);
}

/* Пояснение к пометке — подсказкой браузера: строка плитки обрезается, и
   своя подсказка в ней не поместилась бы. Пометка стоит поверх плитки —
   та целиком одна цель, и до пометки курсор иначе не дошёл бы. */
.file__note[title] {
  position: relative;
  z-index: 1;
}

/* Файл, который скачать нельзя: ни вирус, ни запрещённую программу. */
.file--shut {
  border-style: dashed;
}

.file--shut:hover {
  border-color: var(--line);
  background: none;
}

.file--shut .file__name {
  color: var(--ink-2);
}

/* Плитка целиком — одна цель: посмотреть или сохранить. */
.file__open {
  position: absolute;
  inset: 0;
}

.file__save {
  position: relative;
  z-index: 1;
}


/* ── Лента переписки ──────────────────────────────────────────────── *
   Письма одного разговора подряд, старые сверху — как в Gmail. Между
   письмами волосяная линия. Свёрнутое письмо — строка «кто, начало,
   когда»; развёрнутое — со своей шапкой и телом. Одно письмо без
   переписки стоит как раньше: без линий и без сворачивания.           */

.talk {
  display: flex;
  flex-direction: column;
}

.talk__item,
.talk__stack {
  border-top: var(--hair) solid var(--line);
}

.talk__item:last-child {
  border-bottom: var(--hair) solid var(--line);
}

.talk--alone > .talk__item {
  border: 0;
}

.talk__item[hidden],
.talk__stack[hidden] {
  display: none;
}

/* Свёрнутое: кто, начало, когда — одной строкой во всю ширину. */
.talk__row {
  display: grid;
  grid-template-columns: auto minmax(0, 168px) minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--h-lg);
  color: var(--ink-2);
  font-size: var(--text-sm);
  text-align: left;
}

.talk__row:hover {
  background: var(--bg-hover);
}

.talk__item.is-open > .talk__row,
.talk__item:not(.is-open) > .talk__body {
  display: none;
}

.talk__who {
  color: var(--ink);
  font-weight: var(--fw-medium);
}

.talk__item.is-unread .talk__who {
  font-weight: var(--fw-semi);
}

.talk__text,
.talk__when {
  color: var(--ink-muted);
}

.talk__when {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Развёрнутое письмо: шапка, пометки, тело, файлы — с тем же шагом,
   что был у письма, когда оно стояло в панели одно. */
.talk__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  padding: var(--sp-5) 0;
}

.talk--alone .talk__body {
  padding: 0;
}

/* По шапке развёрнутого письма его сворачивают. */
.letter__from[data-talk-fold] {
  cursor: pointer;
}

/* Кнопки письма из середины переписки: ответить на него, открыть его. */
.talk__acts {
  display: flex;
  flex: none;
  gap: var(--sp-0h);
}

.letter__assist:not(:has(*)) {
  display: none;
}

/* Стопка: середина длинной переписки под одной строкой. */
.talk__more {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-height: var(--h-md);
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

.talk__more:hover {
  color: var(--ink);
}


/* ── Ответ под письмом ────────────────────────────────────────────── *
   Редактор ответа стоит под перепиской, в той же колонке: письмо, на
   которое отвечают, остаётся перед глазами. Он легче полного: шапка в
   одну строку, из полей на виду только «Кому», цитата свёрнута.       */

.letter__reply:not(:has(*)) {
  display: none;
}

.composer--inline {
  flex: none;
  border: var(--hair) solid var(--line-strong);
  background: var(--bg-page);
}

.composer--inline > .letter__bar {
  height: var(--h-strip);
  padding: 0 var(--sp-1) 0 var(--sp-3);
}

.composer__mode {
  display: inline-flex;
  color: var(--ink-muted);
}

.composer--inline .composer__title {
  margin-left: var(--sp-2);
  font-size: var(--text-sm);
}

.composer--inline .composer__lines,
.composer--inline .composer__notes {
  padding-right: var(--sp-4);
  padding-left: var(--sp-4);
}

/* «От кого» и «Тема» у ответа известны заранее — они под кнопкой «Ещё». */
.composer--inline:not(.is-full) .composer__line--extra {
  display: none;
}

.composer--inline .editor {
  flex: none;
}

.composer--inline .editor__tools {
  padding: 0 var(--sp-2);
}

/* Растёт вместе с текстом: прокручивается панель письма, а не поле в
   поле. */
.composer--inline .editor__text {
  flex: none;
  min-height: 112px;
  overflow: visible;
  padding: var(--sp-4);
}

.composer--inline .composer__files {
  padding-right: var(--sp-4);
  padding-left: var(--sp-4);
}

/* Кнопки отправки держатся у низа панели, пока ответ на экране: до них
   не нужно листать через длинную цитату. */
.composer--inline > .letter__foot {
  position: sticky;
  z-index: var(--z-stick);
  bottom: 0;
  height: var(--sp-12);
  padding: 0 var(--sp-4);
  background: var(--bg-page);
}

/* Свёрнутая цитата: письмо стоит выше целиком, повторять его незачем.
   Вступление «такого-то числа такой-то написал» — вместе с ней. */
.editor.is-quote-folded [data-editor] > blockquote,
.editor.is-quote-folded [data-editor] > [data-signature] + p:has(+ blockquote) {
  display: none;
}

.editor__quote {
  padding: 0 var(--sp-4) var(--sp-3);
}

.editor:not(.is-quote-folded) > .editor__quote > .btn {
  background: var(--bg-active);
}

/* Картинка в тексте письма: не шире текста, какой бы ни была сама. */
.editor__text img {
  max-width: 100%;
  height: auto;
}

/* Ещё грузится — видно, что она пока не на месте. */
.editor__text img[data-pending] {
  opacity: 0.5;
}

/* Реакции под письмом: значки плашками и кнопка «поставить свою». */
.reacts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1h);
  margin-top: var(--sp-4);
}

.chip--react {
  height: var(--h-sm);
  padding: 0 var(--sp-2);
  gap: var(--sp-1);
  color: var(--ink);
  font-size: var(--text-sm);
}

.reacts__emoji {
  font-size: var(--text-md);
  line-height: 1;
}

/* Своя — обведена чернилами: видно, что уже поставил. */
.chip--react.is-mine {
  box-shadow: inset 0 0 0 var(--hair) var(--ink);
}

.reacts__add {
  color: var(--ink-muted);
}

/* Панель эмодзи: вкладки групп и сетка значков. Высота сетки своя —
   панель не прыгает, когда группы разной длины. */
.emoji {
  width: calc(var(--h-md) * 8);
}

.emoji__tabs {
  display: flex;
  border-bottom: var(--hair) solid var(--line);
}

.emoji__tab {
  display: inline-flex;
  flex: 1 1 0%;
  align-items: center;
  justify-content: center;
  height: var(--h-md);
  color: var(--ink-muted);
  font-size: var(--text-md);
}

.emoji__tab:hover {
  background: var(--bg-hover);
}

.emoji__tab.is-on {
  background: var(--bg-active);
  color: var(--ink);
}

.emoji__grid {
  display: grid;
  grid-template-columns: repeat(8, var(--h-md));
  grid-auto-rows: var(--h-md);
  height: calc(var(--h-md) * 6);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.emoji__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-lg);
  line-height: 1;
}

.emoji__item:hover {
  background: var(--bg-active);
}

/* Кнопка «картинка в текст»: поле выбора файла спрятано, как у скрепки. */
.editor__picture > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}


/* ── Редактор письма ──────────────────────────────────────────────── */

.composer__title {
  margin-left: var(--sp-2);
  font-size: var(--text-base);
  font-weight: var(--fw-semi);
}

.composer__saved {
  margin-right: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--ink-muted);
  white-space: nowrap;
}

.composer__notes {
  flex: none;
  padding: var(--sp-3) var(--sp-6) 0;
}

.composer__lines {
  flex: none;
  padding: 0 var(--sp-6);
}

/* Строка шапки письма: подпись слева, поле без рамки, линия снизу. */
.composer__line {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--sp-10);
  border-bottom: var(--hair) solid var(--line);
}

.composer__label {
  flex: none;
  width: 72px;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.composer__input {
  flex: 1 1 0%;
  min-width: 0;
  height: var(--sp-10);
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-base);
}

.composer__input:focus {
  outline: none;
}

/* Адресаты плашками. Вся строка — одно поле: плашки, за ними место, где
   набирают следующего; не помещаются — переносятся на вторую строку. */
.addr {
  display: flex;
  flex: 1 1 0%;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1);
  min-width: 0;
  min-height: var(--sp-10);
  padding: var(--sp-1h) 0;
  cursor: text;
}

.addr__input {
  flex: 1 1 var(--sp-16);
  min-width: var(--sp-16);
  height: var(--h-sm);
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--text-base);
}

.addr__input:focus {
  outline: none;
}

/* Подпись строки и её кнопка остаются у первой строки плашек. */
.composer__line:has(> .addr) {
  align-items: flex-start;
}

.composer__line:has(> .addr) > .composer__label {
  display: inline-flex;
  align-items: center;
  height: var(--sp-10);
}

.composer__line:has(> .addr) > .composer__more {
  margin-top: var(--sp-1h);
}

.composer__line.is-drop {
  background: var(--bg-hover);
}

.chip--addr {
  align-items: stretch;
  height: var(--h-xs);
  max-width: 100%;
  padding: 0 0 0 var(--sp-2);
  gap: 0;
  color: var(--ink);
  font-size: var(--text-sm);
  cursor: grab;
}

/* Имя и крестик — кнопки во всю высоту плашки: попасть в них пальцем
   должно быть не труднее, чем в саму плашку. */
.chip__text {
  display: block;
  min-width: 0;
  overflow: hidden;
  color: inherit;
  font-weight: inherit;
  line-height: var(--h-xs);
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: text;
}

.chip--addr > .chip__drop {
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--h-xs);
  height: auto;
  margin: 0;
}

/* Не адрес: видно до отправки, а не из ответа почтового сервера. */
.chip--addr.is-bad {
  background: var(--danger-bg);
  color: var(--danger);
}

.chip--addr.is-bad > .chip__drop {
  color: inherit;
}

/* Его сотрёт следующее нажатие. */
.chip--addr.is-picked {
  background: var(--ink);
  color: var(--bg-page);
}

.chip--addr.is-picked > .chip__drop {
  color: inherit;
}

.composer__input--subject {
  font-weight: var(--fw-medium);
}

/* Линия под строкой, в которой сейчас печатают, — чернилами. */
.composer__line:focus-within {
  border-bottom-color: var(--ink);
}

.composer__line > .pick {
  flex: 1 1 0%;
  margin-left: calc(var(--sp-2) * -1);
}

.composer__line > .pick > .pick__value {
  display: inline-flex;
  max-width: 100%;
}

.composer__more {
  color: var(--ink-muted);
}

.composer__hints {
  left: calc(72px + var(--sp-3));
  min-width: 280px;
  /* Строка подсказки — имя, адрес и откуда он: в обычные 360 точек она
     не входила, и адрес обрывался на полуслове. Шире строки адресатов
     подсказки не бывают. */
  max-width: calc(100% - 72px - var(--sp-3));
}

.composer__hints .pop__item {
  justify-content: space-between;
}

/* Не вошло и так — имя и адрес уступают поровну и кончаются
   многоточием, а не обрезом. */
.composer__hints .pop__item > span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Поле текста. */
.editor {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  min-height: 0;
}

.editor__tools {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--sp-0h);
  height: var(--h-strip);
  padding: 0 var(--sp-5);
  border-bottom: var(--hair) solid var(--line);
}

.editor__text {
  flex: 1 1 0%;
  min-height: 160px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-5) var(--sp-6);
}

.editor__text:focus {
  outline: none;
}

/* Подсказка продолжения: бледные слова за курсором и клавиша, которой
   их принять. Лежит поверх редактора, а не в тексте письма: в текст слова
   попадают, только когда человек их принял. Место и кегль ставит скрипт —
   по курсору. */
.ghost {
  position: fixed;
  z-index: var(--z-pop);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  overflow: hidden;
  color: var(--ink-muted);
  white-space: pre;
  cursor: pointer;
  user-select: none;
}

.ghost > .kbd {
  flex: none;
}

/* Без клавиатуры подсказку принимают касанием — клавишу рисовать незачем. */
@media (hover: none) {
  .ghost > .kbd {
    display: none;
  }
}

/* Что прикреплено. Пусто — места не занимает. */
.composer__files {
  display: flex;
  flex: none;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-6);
  border-top: var(--hair) solid var(--line);
}

.composer__files:not(:has(*)) {
  display: none;
}

/* Плашка файла шире плашки метки, и сжимается в ней только имя: размер и
   крестик видны всегда. С общей шириной длинное имя выталкивало их за
   край — и приложенный файл было не убрать. */
.composer__files > .chip {
  max-width: min(100%, 320px);
}

.composer__files > .chip > span:first-of-type {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.composer__files > .chip > .muted,
.composer__files > .chip > .chip__drop {
  flex: none;
}

.composer__attach > input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Меню параметров отмечено точкой, когда в нём что-то включено:
   спрятанная настройка не должна быть сюрпризом при отправке. */
.menu:has(.pop input[type="checkbox"]:checked) > .composer__opts::before {
  content: "";
  position: absolute;
  top: 5px;
  right: 5px;
  width: 6px;
  height: 6px;
  background: var(--accent-line);
}

/* Форма внутри всплывающей панели. */
.pop__form {
  width: 264px;
  padding: var(--sp-3);
}

.pop__field {
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
}

/* Подсказка «отпусти файлы» — поверх редактора, пока над ним несут
   файл. */
.composer__drop {
  position: absolute;
  z-index: var(--z-pop);
  inset: var(--sp-3);
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  border: var(--hair) dashed var(--ink);
  background: color-mix(in srgb, var(--bg-raised) 92%, transparent);
  color: var(--ink);
  font-weight: var(--fw-medium);
  pointer-events: none;
}

.composer.is-dropping .composer__drop {
  display: flex;
}


/* ── Просмотр вложения ────────────────────────────────────────────── */

.peek {
  position: fixed;
  z-index: var(--z-peek);
  inset: 0;
  display: flex;
  flex-direction: column;
  background: var(--scrim);
}

.peek__bar {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--sp-3);
  height: var(--h-bar);
  padding: 0 var(--sp-3) 0 var(--pad);
  border-bottom: var(--hair) solid var(--line);
  background: var(--bg-raised);
}

.peek__name {
  flex: 1 1 0%;
  font-weight: var(--fw-medium);
}

.peek__stage {
  display: flex;
  flex: 1 1 0%;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: var(--sp-6);
}

.peek__image {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  background: var(--bg-raised);
}

.peek__frame {
  width: min(100%, 1040px);
  height: 100%;
  border: 0;
  background: #ffffff;
}

.peek__text {
  width: min(100%, 880px);
  max-height: 100%;
  overflow: auto;
  padding: var(--sp-6);
  background: var(--bg-raised);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  white-space: pre-wrap;
}

.status__cell--bad {
  color: var(--danger);
}



/* Раскрытая кнопка подсказку не показывает: та легла бы поверх панели,
   которую сама же и открыла. */
[data-tip][aria-expanded="true"]::after {
  display: none;
}


/* ── Обсуждение письма между своими ───────────────────────────────── *
   Записки на полях: кто, когда, что. Черта слева отличает их от самого
   письма — это разговор о нём, а не его часть.                         */

.letter__presence {
  margin-bottom: var(--sp-3);
}

.notes {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.notes__item {
  padding-left: var(--sp-3);
  border-left: var(--hair) solid var(--line-strong);
}

.notes__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--h-xs);
  font-size: var(--text-sm);
}

.notes__who {
  font-weight: var(--fw-medium);
  color: var(--ink);
}

.notes__head > form {
  margin-left: auto;
}

.notes__text {
  margin: 0;
  color: var(--ink-2);
  white-space: pre-line;
  overflow-wrap: anywhere;
}


/* ── Настройки ────────────────────────────────────────────────────── *
   Оглавление слева, разделы справа. Разделы — не карточки: заголовок,
   пояснение и содержимое на одной вертикали, между разделами — линия.  */

.page--split {
  display: grid;
  grid-template-columns: 184px minmax(0, 1fr);
  align-items: start;
  gap: var(--sp-10);
}

/* Плавно страница едет только по щелчку в оглавлении. Приход на экран —
   после сохранения, по ссылке с якорем — встаёт на место сразу: шесть
   тысяч точек страницы ехали больше секунды после каждого «сохранить», и
   щелчок по ещё едущему приходился мимо. Отметку ставит скрипт, когда
   экран уже стоит на своём якоре. */
.page--split.is-settled {
  scroll-behavior: smooth;
}

.toc {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
}

.toc__item {
  display: flex;
  align-items: center;
  height: var(--h-nav);
  padding: 0 var(--sp-3);
  border-left: 2px solid var(--line);
  color: var(--ink-muted);
  font-size: var(--text-sm);
  transition: color var(--t-fast), border-color var(--t-fast);
}

.toc__item:hover {
  color: var(--ink);
}

.toc__item.is-on {
  border-left-color: var(--ink);
  color: var(--ink);
  font-weight: var(--fw-medium);
}

/* Мера страницы с формами: шире строка читается хуже, а поля
   растягиваются в полосы. */
.page__body--form {
  gap: 0;
  max-width: 760px;
}

.page__body--form > .notice {
  margin-bottom: var(--sp-6);
}

.section {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  padding: var(--sp-8) 0;
  border-top: var(--hair) solid var(--line);
  /* Якорь из оглавления не должен прятать заголовок под край. */
  scroll-margin-top: var(--sp-2);
}

.section:first-of-type {
  padding-top: 0;
  border-top: 0;
}

.section__head {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1h);
}

.section__title {
  font-size: var(--text-lg);
  font-weight: var(--fw-semi);
  letter-spacing: -0.01em;
}

.section__hint {
  max-width: 68ch;
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
  color: var(--ink-muted);
}

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

/* Подзаголовок внутри раздела. */
.section__sub {
  margin-top: var(--sp-4);
  font-size: var(--text-base);
  font-weight: var(--fw-semi);
}

.section__body > .section__sub:first-child {
  margin-top: 0;
}

/* Пары «настройка — значение» в две колонки. */
.options {
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-4) var(--sp-5);
}

.options__name {
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  color: var(--ink-2);
}

/* Значение занимает столько, сколько ему нужно, а не всю колонку. */
.options > :not(.options__name) {
  justify-self: start;
}

/* Ящик: строка-заголовок и всё его хозяйство под ней. */
.mbox {
  border: var(--hair) solid var(--line);
  scroll-margin-top: var(--sp-2);
}

/* Подзаголовок, к которому ведёт свой якорь (ключи доступа внутри
   «Безопасности»): после сохранения страница встаёт на него. */
.section__sub[id] {
  scroll-margin-top: var(--sp-4);
}

.mbox[open] {
  border-color: var(--line-strong);
}

.mbox__head {
  min-height: var(--sp-12);
  padding: 0 var(--sp-4);
  gap: var(--sp-3);
  font-size: var(--text-base);
}

.mbox__name {
  color: var(--ink);
  font-weight: var(--fw-semi);
}

.mbox__marks {
  display: flex;
  flex: none;
  align-items: center;
  gap: var(--sp-2);
  margin-left: auto;
}

.mbox > .fold__body {
  padding: var(--sp-2) var(--sp-4) var(--sp-5) var(--sp-4);
  border-top: var(--hair) solid var(--line);
}

.mbox__tight {
  color: var(--danger);
}

/* Выключенное: человек, правило. */
.fold.is-off > .fold__head {
  color: var(--ink-faint);
}

/* Таблицы настроек — каждая объявляет только свои столбцы. */
.table--pairs    { --cols: minmax(0, 1fr) minmax(0, 1fr) auto; }
.table--edit     { --cols: auto minmax(0, 1fr) auto; }
.table--rules    { --cols: minmax(0, 3fr) minmax(0, 2fr) auto; }
.table--sessions { --cols: minmax(0, 1fr) 168px 168px; }
.table--access   { --cols: minmax(0, 1fr) auto auto; }

.table--edit .input {
  flex: 1 1 0%;
  min-width: 0;
  max-width: 320px;
}

.table--edit .cluster {
  flex-wrap: nowrap;
}

/* «Название — короткая справка — действие»: копии базы, папки. */
.table--list { --cols: minmax(0, 1fr) auto auto; }
/* Ключи доступа: название с «сохранить», когда добавлен и когда им
   входили — и убрать. */
.table--passkeys { --cols: minmax(0, 1fr) auto auto; }
/* Ключи сайтов: имя, начало ключа, ящик, счёт за сегодня — и отозвать. */
.table--keys { --cols: minmax(0, 2fr) auto minmax(0, 2fr) auto auto; }
/* Письма сайтов: кому, тема, чем кончилось и когда — судьбы и даты
   стоят каждая в своём столбце, а не гуляют за словом разной длины. */
.table--sitemail { --cols: minmax(0, 2fr) minmax(0, 3fr) auto auto; }
/* Консоль администратора. Что и сколько: название и значение. */
.table--facts { --cols: minmax(0, 1fr) auto; }
/* Ящики установки: адрес, чей, сколько почты, когда сверялся. */
.table--adminboxes { --cols: minmax(0, 3fr) minmax(0, 2fr) auto auto; }
/* Люди: имя, отметки, последний вход, сеансы. */
.table--adminpeople { --cols: minmax(0, 2fr) auto minmax(0, 2fr) auto; }
/* Журнал действий: когда, кто, что, над чем и откуда. */
.table--audit { --cols: 96px minmax(0, 1fr) auto minmax(0, 3fr) auto; }

/* Строка под всей шириной таблицы: что сказал сервер ящика. Целиком,
   с переносом: обрезанная ошибка — не объяснение. */
.table__cell.table__cell--wide {
  grid-column: 1 / -1;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Над чем действие — целиком: адрес ящика с подробностями обрезать
   нельзя, по ним запись и ищут. */
.table__cell.audit__what {
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Название числа в обзоре — тоже целиком: на телефоне оно длиннее строки. */
.table--facts .table__cell--main {
  white-space: normal;
}

/* Числа обзора — те же, что в отчёте выпуска, но не в карточке: полей
   карточки у раздела нет, и отрицательным отступам не из чего браться. */
.funnel.funnel--plain {
  --card-pad: var(--sp-4);
  margin: 0;
  border-left: var(--hair) solid var(--line);
}

/* Журнал вебхука: событие, чем кончилось, что ответил адрес и когда. */
.table--hooklog { --cols: minmax(0, 2fr) auto minmax(0, 3fr) auto; }

/* Адрес вебхука — целиком: его сверяют глазами с тем, что в своей
   программе, и обрезанный хвост тут хуже переноса. */
.hook__url {
  display: block;
  color: var(--ink-2);
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}

.rules__cond {
  white-space: normal;
  line-height: var(--lh-snug);
}

.rules__cond > em {
  font-style: normal;
  color: var(--ink-muted);
}

/* Условия правила: три столбца, три строки, одна шапка. */
.rulegrid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 2fr);
  gap: var(--sp-2) var(--sp-3);
  max-width: var(--w-form);
}

/* Запасные коды второго фактора. */
.codes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  gap: var(--sp-2);
  max-width: var(--w-form);
}

.codes > li {
  padding: var(--sp-2) var(--sp-3);
  border: var(--hair) solid var(--line-strong);
  font-size: var(--text-base);
  text-align: center;
}

.totp {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--sp-6);
}

/* QR читается камерой только на белом — в любой теме. */
.totp__qr {
  flex: none;
  width: 184px;
  padding: var(--sp-3);
  background: #ffffff;
}

.totp__qr > svg {
  display: block;
  width: 100%;
  height: auto;
}

.totp__secret,
.pgp__print {
  font-size: var(--text-base);
  letter-spacing: 0.04em;
  color: var(--ink);
  overflow-wrap: anywhere;
}


/* Раскрывашки списком: линия между строками вместо пустоты. Так шесть
   настроек одного ящика читаются как меню, а не как шесть абзацев. */
.folds {
  display: flex;
  flex-direction: column;
  border-top: var(--hair) solid var(--line);
}

.folds > .fold {
  border-bottom: var(--hair) solid var(--line);
}

.folds > .fold > .fold__head {
  min-height: var(--h-lg);
}


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

.board {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
}

.board__stat { grid-column: span 3; }
.board__wide { grid-column: span 8; }
.board__side { grid-column: span 4; }
.board__full { grid-column: 1 / -1; }

.board__mail  { --cols: minmax(0, 200px) minmax(0, 1fr) auto; }
.board__pairs { --cols: minmax(0, 1fr) auto; }
.board__boxes { --cols: minmax(0, 240px) minmax(0, 1fr) auto minmax(0, auto); }

/* Строка-ссылка внутри блока. */
.board__row {
  transition: background-color var(--t-fast);
}

.board__row:hover .table__cell--main {
  text-decoration: underline;
  text-decoration-color: var(--ink-faint);
  text-underline-offset: 3px;
}

.board__row .table__cell--main {
  font-weight: var(--fw-normal);
  color: var(--ink-2);
}

.board__row.is-unread .table__cell--main {
  font-weight: var(--fw-semi);
  color: var(--ink);
}

.board__late {
  color: var(--warn);
}

.board__bad {
  color: var(--danger);
  font-size: var(--text-sm);
}

/* График недели. Столбцы — рисунок: высота здесь данные, а не
   оформление, и в стили она не попадает. */
.chart {
  display: block;
  width: 100%;
  height: 120px;
}

.chart__bar          { fill: var(--bg-active); }
.chart__bar--today   { fill: var(--ink-faint); }
.chart__bar--unread  { fill: var(--accent-line); }

.chart__key {
  background: var(--accent-line);
}

.chart__axis {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  padding-top: var(--sp-2);
  border-top: var(--hair) solid var(--line-strong);
}

.chart__tick {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-0h);
  font-size: var(--text-xs);
  color: var(--ink-muted);
  white-space: nowrap;
}

.chart__count {
  font-size: var(--text-sm);
  font-weight: var(--fw-semi);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

.chart__tick.is-today,
.chart__tick.is-today > .chart__count {
  color: var(--ink);
}


/* ── Календарь ────────────────────────────────────────────────────── *
   Неделя занимает всю высоту экрана: семь равных столбцов таблицей —
   общая рамка, линии между днями, а не семь отдельных карточек.       */

.page--fill {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-bottom: var(--pad);
}

.week {
  display: grid;
  flex: 1 1 0%;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  min-height: 360px;
  border: var(--hair) solid var(--line);
}

.week__day {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.week__day + .week__day {
  border-left: var(--hair) solid var(--line);
}

.week__head {
  display: flex;
  flex: none;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-2);
  height: var(--sp-12);
  padding: 0 var(--sp-3);
  border-bottom: var(--hair) solid var(--line);
  line-height: var(--sp-12);
}

.week__name {
  overflow: hidden;
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  color: var(--ink-muted);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.week__num {
  font-size: var(--text-lg);
  font-weight: var(--fw-semi);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* Сегодня — чертой чернилами над днём и полной яркостью числа. */
.week__day.is-today > .week__head {
  box-shadow: inset 0 2px 0 var(--ink);
}

.week__day.is-today .week__name,
.week__day.is-today .week__num {
  color: var(--ink);
}

/* Прошедшие дни гасим: они не про планирование. */
.week__day.is-past .week__num {
  color: var(--ink-faint);
}

.week__list {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  gap: var(--sp-2);
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-2);
}

/* Встреча. Слева — черта нашего ответа: без ответа серая, «иду»
   зелёная, «возможно» жёлтая, «не иду» красная. */
.meet {
  display: flex;
  flex-direction: column;
  gap: var(--sp-0h);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-3);
  border-left: 2px solid var(--ink-faint);
  background: var(--bg-control);
}

.meet--yes   { border-left-color: var(--ok); }
.meet--maybe { border-left-color: var(--warn); }
.meet--no    { border-left-color: var(--danger); }

.meet__time {
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}

.meet__name {
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  color: var(--ink);
  overflow-wrap: anywhere;
}

a.meet__name:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.meet__where {
  font-size: var(--text-xs);
  color: var(--ink-muted);
  overflow-wrap: anywhere;
}

.meet__marks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-1h);
  margin-top: var(--sp-1);
}

.meet__repeat {
  display: inline-flex;
  color: var(--ink-muted);
}

.meet.is-off .meet__name {
  color: var(--ink-muted);
  text-decoration: line-through;
}

.week__day.is-past .meet {
  opacity: 0.6;
}

/* Действие над своей встречей — в правом верхнем углу карточки, под
   курсором: постоянная кнопка на каждой встрече спорила бы с её названием. */
.meet {
  position: relative;
}

.meet__act {
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-1);
  display: none;
  background: var(--bg-control);
}

.meet:hover .meet__act,
.meet:focus-within .meet__act {
  display: flex;
}

/* Пальцем навести нельзя — на таком экране кнопка видна всегда. */
@media (hover: none) {
  .meet__act {
    display: flex;
  }
}

.week__empty {
  flex: none;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}


/* ── Месяц ────────────────────────────────────────────────────────── *
   Семь столбцов, недели строками. Линии между клетками — это фон сетки
   в зазорах: так у крайних клеток не выходит двойной рамки. Клетка —
   ссылка в неделю своего дня.                                         */

.month {
  display: grid;
  flex: 1 1 0%;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  grid-template-rows: var(--h-md);
  grid-auto-rows: minmax(calc(var(--sp-12) * 2), 1fr);
  gap: var(--hair);
  min-height: 0;
  border: var(--hair) solid var(--line);
  background: var(--line);
}

.month__dow,
.month__day {
  min-width: 0;
  background: var(--bg-page);
}

.month__dow {
  display: flex;
  align-items: center;
  padding: 0 var(--sp-3);
}

.month__day {
  display: flex;
  flex-direction: column;
  gap: var(--sp-0h);
  padding: var(--sp-2) var(--sp-3);
  transition: background-color var(--t-fast);
}

.month__day:hover {
  background: var(--bg-hover);
}

.month__num {
  margin-bottom: var(--sp-1);
  font-size: var(--text-sm);
  font-weight: var(--fw-semi);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* Чужой месяц и прошедшие дни гасим: они не про планирование. */
.month__day.is-out .month__num,
.month__day.is-past .month__num {
  color: var(--ink-faint);
}

/* Сегодня — той же чертой чернилами, что и в неделе. */
.month__day.is-today {
  box-shadow: inset 0 2px 0 var(--ink);
}

.month__day.is-today .month__num {
  color: var(--ink);
}

.month__event,
.month__more {
  overflow: hidden;
  font-size: var(--text-xs);
  line-height: var(--lh-snug);
  color: var(--ink-2);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.month__event.is-off {
  color: var(--ink-faint);
  text-decoration: line-through;
}

.month__time,
.month__more {
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* Метки по числу встреч — вместо слов на узком экране. */
.month__dots {
  display: none;
  gap: var(--sp-0h);
}

/* Форма «новая встреча» в панели под кнопкой. */
.meetform,
.feedpop {
  width: 320px;
}

/* Только что выданный адрес подписки: над сеткой, во всю её ширину.
   Поля по бокам даёт сама страница — свои сдвинули бы блок с её оси. */
.calfeed {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding-bottom: var(--sp-4);
  border-bottom: var(--hair) solid var(--line);
}


/* ── Аутрич ───────────────────────────────────────────────────────── */

/* Воронка: числа таблицей во всю ширину блока, между ними линии.
   Линию справа и снизу рисует каждая клетка, а полоса обрезает крайние —
   так сетка остаётся целой, во сколько бы рядов ни легли числа. */
.funnel {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  margin: 0 calc(var(--card-pad) * -1);
  overflow: hidden;
  border-top: var(--hair) solid var(--line);
  border-bottom: var(--hair) solid var(--line);
}

.funnel > .stat {
  margin: 0 calc(var(--hair) * -1) calc(var(--hair) * -1) 0;
  padding: var(--sp-4) var(--card-pad);
  border-right: var(--hair) solid var(--line);
  border-bottom: var(--hair) solid var(--line);
}

/* Какое письмо работает. */
.steps {
  --cols: minmax(0, 168px) minmax(0, 1fr) 80px 80px 104px;
}

.steps__num {
  text-align: right;
}

/* Сравнение двух вариантов письма: строки под письмом, тише его. */
.steps__variant > .table__cell--meta {
  padding-left: var(--sp-4);
}

/* Доноры: строка-заголовок и раскрывашки с теми же столбцами. */
.leads {
  display: flex;
  flex-direction: column;
}

.lead {
  display: grid;
  grid-template-columns: var(--icon) minmax(0, 3fr) minmax(0, 3fr) minmax(0, 4fr) minmax(0, 2fr);
  align-items: center;
  gap: var(--sp-3);
  min-height: var(--h-lg);
  border-bottom: var(--hair) solid var(--line);
  font-size: var(--text-base);
  font-weight: var(--fw-normal);
  color: var(--ink-2);
}

.lead--head {
  min-height: var(--h-md);
  border-bottom-color: var(--line-strong);
}

.lead__site {
  color: var(--ink);
  font-weight: var(--fw-medium);
}

.lead__live {
  color: var(--ok);
}

/* Состояние и его причина — одной строкой: причина бывает длинной и
   обрезается, а не роняет строку списка в два этажа. */
.lead__state {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}

.lead__state > .badge {
  flex: 0 0 auto;
}

.lead--lost,
.lead--lost .lead__site {
  color: var(--ink-faint);
}

.leads__item > .fold__body {
  border-bottom: var(--hair) solid var(--line);
}

/* Цепочка: три письма в ряд. */
.sequence {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--sp-4);
}

.sequence__step {
  gap: var(--sp-3);
  padding: var(--sp-4);
  border: var(--hair) solid var(--line);
}

.sequence__no {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--h-xs);
  height: var(--h-xs);
  background: var(--ink);
  color: var(--bg-page);
  font-size: var(--text-sm);
  font-weight: var(--fw-semi);
}

.sequence__days {
  width: var(--sp-16);
  text-align: center;
}

/* «Посмотреть» и «себе» в шапке письма — значками, справа от номера. */
.sequence__tools {
  display: flex;
  flex: 0 0 auto;
  gap: var(--sp-1);
}

.sequence__body {
  min-height: 176px;
  font-size: var(--text-sm);
}

/* Ящики отправки: галочки сеткой. */
.boxpick {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(264px, 1fr));
  gap: var(--sp-1) var(--sp-5);
}

.boxpick > .tick > .count {
  margin-left: auto;
}

/* Отбор адресатов: вкладки состояния и поиск — одной строкой. Вкладок
   шесть, и на узком экране их полоса листается, а не ломается на две. */
.leadbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
}

.leadbar > .seg {
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}

.leadbar > .seg::-webkit-scrollbar {
  display: none;
}

.leadbar > .seg > .seg__item {
  flex: 0 0 auto;
}

.leadbar__find {
  flex: 0 1 280px;
  min-width: 0;
}

.leadbar__find > .input {
  width: 100%;
}

/* Шаг цепочки — письмо или дело руками. Что из формы к делу руками не
   относится, прячется по выбранному роду — сразу, ещё до сохранения. */
.sequence__step:has(input[name="kind"]:not([value=""]):checked) .sequence__mail,
.sequence__step:not(:has(input[name="kind"]:not([value=""]):checked)) .sequence__hand {
  display: none;
}

/* Проверка перед запуском: замечание — метка рода и слова в одну строку;
   длинное замечание переносится под метку ровным краем. */
.precheck {
  display: grid;
  gap: var(--sp-2);
}

.precheck__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: baseline;
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
}

/* Условие письма смотрит на открытия, а кампания их не считает —
   предупреждение, а не подсказка: без счёта развилка не работает. */
.sequence__blind {
  color: var(--warn);
}

/* Сделка в карточке адресата: этапы кнопками в ряд, под ними — сумма и
   «проиграно» с причиной. Этапов бывает восемь, и на телефоне ряд
   листается, а не ломается. */
.deal__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  min-width: 0;
}

.deal__stages {
  max-width: 100%;
  overflow-x: auto;
  scrollbar-width: none;
}

.deal__stages::-webkit-scrollbar {
  display: none;
}

.deal__stages > .seg__item {
  flex: 0 0 auto;
  background: transparent;
}

.deal__stages > .seg__item.is-on {
  background: var(--ink);
}

.deal__form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}

.deal__sum {
  width: 14ch;
}

/* Что ответил адресат и ссылки на само письмо. */
.lead__said {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-4);
}

.lead__reply {
  color: var(--ink);
}

/* Заметка шага, который делает человек: её набирали абзацами — абзацами
   и показываем. */
.lead__note {
  color: var(--ink);
  white-space: pre-line;
}

.lead__acts {
  flex-wrap: wrap;
}

/* Журнал адресата: когда — что. Слова сервера бывают длинными и без
   пробелов, поэтому переносятся где придётся. */
.journal {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--sp-1) var(--sp-4);
  font-size: var(--text-sm);
  color: var(--ink-2);
}

.journal__row {
  display: contents;
}

.journal__when {
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.journal__what {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Второй вариант письма — внутри шага и в одну линию с первым: отступ
   раскрывашки сдвинул бы его поля вправо. */
.sequence__b > .fold__body {
  padding-left: 0;
}

/* Стоп-лист: кто, почему, когда — и убрать. */
.table--stops {
  --cols: minmax(0, 2fr) auto minmax(0, 2fr) auto;
}

/* Низ формы, где слева одно действие, справа другое. */
.form__foot--split {
  justify-content: space-between;
}


/* ── Доставляемость ───────────────────────────────────────────────── */

/* Что домену надо сделать: одним блоком, строка на замечание. */
.gaps {
  align-items: flex-start;
  padding-block: var(--sp-3);
}

.gaps > .icon {
  margin-top: var(--sp-0h);
}

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

/* Записи домена: имя, сама запись и оценка. Запись бывает длинной и
   переносится — её читают и копируют целиком. */
.table--records {
  --cols: 96px minmax(0, 1fr) auto;
}

.table--records .table__cell.mono {
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Чёрные списки: имя и итог. */
.table--lists {
  --cols: minmax(0, 1fr) auto;
}

/* Источники писем, не прошедших проверку. */
.table--sources {
  --cols: minmax(0, 1fr) 96px 168px;
}

/* Проверки доставки: откуда, куда, где легло, как оценено, когда. */
.table--probes {
  --cols: minmax(0, 2fr) minmax(0, 2fr) auto minmax(0, 3fr) 120px;
}

.table--probes .table__cell.cluster {
  overflow: visible;
}

/* Кнопки «проверить доставку»: по одной на ящик домена. */
.probe__start > form {
  min-width: 0;
  max-width: 100%;
}

.probe__start .btn {
  max-width: 100%;
}


/* ── Рассылки ─────────────────────────────────────────────────────── */

/* Выпуски: тема, состояние и числа. Вся строка — ссылка на выпуск. */
.table--issues {
  --cols: minmax(0, 1fr) auto 96px 72px 72px 112px;
}

.issues__num {
  text-align: right;
}

.issues__row {
  transition: background-color var(--t-fast);
}

.issues__row:hover {
  background: var(--bg-hover);
}

/* Цепочка писем: номер, тема, срок и счёт. Строка — ссылка на письмо. */
.table--series {
  --cols: var(--h-xs) minmax(0, 3fr) minmax(0, 2fr) minmax(88px, auto);
}

/* Подписчики: те же раскрывашки, что у адресатов кампании, со своими
   столбцами — адрес, имя с метками, состояние, с какого дня. */
.lead--subscriber {
  grid-template-columns: var(--icon) minmax(0, 4fr) minmax(0, 4fr) 104px minmax(0, 2fr);
}

/* Метки списка — плашками в ряд: отбор в один щелчок. */
.tagbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1h);
}

.tagbar > .chip > .count {
  min-width: 0;
}

.chip--pick.is-on > .count {
  color: inherit;
}

/* Адрес и кнопка «скопировать» — одной строкой. */
.copyline {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-width: 0;
}

.copyline > .btn {
  flex: none;
}

/* Разметка для вставки на свой сайт: её читают и копируют целиком. */
.codeblock {
  max-height: 240px;
  overflow: auto;
  padding: var(--sp-3) var(--sp-4);
  border: var(--hair) solid var(--line);
  background: var(--bg-sunken);
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* Переключатель на радиокнопках: сама кнопка не видна, отмечен пункт,
   чья выбрана. */
.seg__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.seg__item:has(> .seg__radio:checked) {
  background: var(--ink);
  color: var(--bg-page);
}

.seg__item:has(> .seg__radio:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Выпуск: слева письмо и его настройки, справа — каким оно придёт.
   Предпросмотр стоит на месте, пока прокручивается редактор. */
.issue {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 664px);
  align-items: start;
  max-width: none;
}

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

.issue__view {
  position: sticky;
  top: 0;
  max-height: calc(100dvh - var(--h-bar) - var(--sp-6) * 2);
}

/* Тема и получатель — как строка письма в почте. */
.issue__envelope {
  display: flex;
  flex-direction: column;
  gap: var(--sp-0h);
  min-width: 0;
  font-size: var(--text-sm);
}

.issue__subject {
  overflow: hidden;
  color: var(--ink);
  font-size: var(--text-base);
  font-weight: var(--fw-semi);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.issue__stage {
  min-height: 0;
  overflow-y: auto;
  border: var(--hair) solid var(--line);
  background: var(--bg-sunken);
}

.issue__frame {
  display: block;
  margin: 0 auto;
}

/* Ширина телефона: письмо обязано читаться и в ней. */
.issue__view:has([value="phone"]:checked) .issue__frame {
  max-width: 375px;
}

/* Из чего письмо — видно то, что выбрано; второе остаётся при выпуске. */
.issue__main:has([name="mode"][value="html"]:checked) .issue__blocks,
.issue__main:has([name="mode"][value="blocks"]:checked) .issue__html {
  display: none;
}

.issue__acts {
  padding-top: var(--sp-2);
}

/* Шапка выпуска: стрелка назад, тема и состояние — по одной линии.
   Тема бывает длинной: уступает она, а не кнопки справа — иначе те
   наезжали на неё. */
.topbar__title:has(> .btn) {
  flex: 1 1 0%;
  align-items: center;
  gap: var(--sp-2);
}

.topbar__title:has(> .btn) > .badge {
  flex: none;
}

.topbar:has(> .topbar__title > .btn) > .topbar__tools {
  flex: 0 0 auto;
}

/* Блоки письма: каждый — рамка с названием, полями и тремя кнопками. */
.blocks {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

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

.blocks__list:empty {
  display: none;
}

.block {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border: var(--hair) solid var(--line);
}

.block:focus-within {
  border-color: var(--line-strong);
}

.block__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--h-xs);
  color: var(--ink-muted);
}

.block__tools {
  display: flex;
  gap: var(--sp-0h);
}

/* Первый блок выше не поднять, последний ниже не опустить. */
.block:first-child [data-block-up],
.block:last-child [data-block-down] {
  visibility: hidden;
}

.block__text {
  min-height: 120px;
}

.block__rule {
  margin: var(--sp-2) 0;
  border-top: var(--hair) solid var(--line-strong);
}

.blocks__add {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}

/* Ход выпуска: полоса и «ушло из стольких». */
.progressline {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
}

.progressline > .meter {
  flex: 1 1 0%;
}

/* Ссылки выпуска: адрес с долей перешедших под ним, люди и переходы.
   Адрес бывает длинным и переносится — его читают целиком. */
.table--links {
  --cols: minmax(0, 1fr) 64px 96px;
}

.table--links > .table__row {
  padding: var(--sp-2) 0;
}

.links__url {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1h);
  white-space: normal;
  overflow-wrap: anywhere;
}

.links__url > .meter {
  max-width: 240px;
}

/* Форма подписки — на странице, которую видит подписчик. */
.joinform {
  width: 100%;
  max-width: 360px;
}

/* Поле-ловушка: человеку его не видно, заполняет его только робот. */
.joinform__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.lone__note {
  font-size: var(--text-sm);
  color: var(--ink-muted);
}


/* ── Аналитика ────────────────────────────────────────────────────── *
   Та же доска, что на «Сегодня», и три вида блоков: плитки с числами,
   график по времени, таблица. Цвета серий — не украшение: серое —
   объём, акцент — то, ради чего смотрят, красное — только беда.       */

.board__half { grid-column: span 6; }

/* Блок знает свою ширину: таблица перестраивается по ней, а не по
   ширине экрана, — половина доски бывает узкой и на большом мониторе. */
.stats {
  container: stats / inline-size;
}

/* Шапка итога. «За 30 дней» — три слова, сжимать их некуда; приписка о
   сравнении длиннее и в узком блоке переносится, не тесня заголовок. */
.stats > .card__head.stats__head > .card__title {
  flex: none;
}

.stats__vs {
  flex: 1 1 24ch;
  font-size: var(--text-sm);
  color: var(--ink-muted);
  text-align: right;
}

/* Форма недельного отчёта в меню: пояснению нужна мера, иначе меню
   вытянется в одну длинную строку. */
.report {
  width: min(320px, calc(100vw - var(--sp-8)));
}

/* Плитки стоят ровными рядами — по два, по три-четыре или все в один,
   смотря по ширине блока: одинокая плитка во втором ряду читается как
   забытая. Полоса плиток — последнее в блоке и доходит до его рамки. */
.funnel--flush {
  margin-bottom: calc(var(--card-pad) * -1);
  border-bottom: 0;
}

.funnel--4,
.funnel--6,
.funnel--8 {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@container stats (min-width: 560px) {
  .funnel--4,
  .funnel--8 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .funnel--6 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@container stats (min-width: 960px) {
  .funnel--6 {
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

@container stats (min-width: 1200px) {
  .funnel--8 {
    grid-template-columns: repeat(8, minmax(0, 1fr));
  }
}

/* Число плитки не рвётся на две строки; длинное пишется мельче, а
   строку занимает ту же — подписи под соседними плитками стоят вровень. */
.funnel--flush .stat__value {
  white-space: nowrap;
}

.funnel--flush .stat--long .stat__value {
  font-size: var(--text-xl);
  line-height: var(--text-2xl);
}

/* Под числом плитки — мелкой строкой: на сколько оно изменилось и от
   чего считалась доля. */
.stat__more {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-0h) var(--sp-2);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}

.stat__delta {
  font-weight: var(--fw-semi);
  color: var(--ink-2);
  white-space: nowrap;
}

/* Приписка бывает длиннее плитки («из них спят 310: не открывали 90
   дней») — ей переноситься можно, числу изменения рядом — нет. */
.stat__note {
  min-width: 0;
}

/* График. Рисунок тянется на всю ширину блока; деления одной ширины —
   и под рисунком им отвечают равные доли оси. */
.plot {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.plot__art {
  display: block;
  width: 100%;
  height: 168px;
}

.plot__bar--base { fill: var(--ink-faint); }
.plot__bar--mark { fill: var(--accent-line); }
.plot__bar--ink  { fill: var(--ink); }
.plot__bar--bad  { fill: var(--danger); }

/* Подписи серий. Трём подписям рядом с названием тесно — они уходят
   под него целиком, а не сжимают название в столбик. */
.stats > .card__head > .card__title {
  flex: 1 1 14ch;
}

.plot__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-4);
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.plot__key--base { background: var(--ink-faint); }
.plot__key--mark { background: var(--accent-line); }
.plot__key--ink  { background: var(--ink); }
.plot__key--bad  { background: var(--danger); }

/* Мишень деления — во всю высоту рисунка: она же подсветка выбранного. */
.plot__hit {
  fill: transparent;
}

.plot__slot.is-on > .plot__hit {
  fill: var(--bg-active);
}

.plot__axis {
  display: flex;
  height: var(--h-xs);
  padding-top: var(--sp-1h);
  border-top: var(--hair) solid var(--line-strong);
}

/* Подпись стоит по середине своего деления и шире его: делений бывает
   тридцать, и на каждое приходится по десятку пикселей. Крайние
   прижаты к своему краю, чтобы не вылезать из блока. */
.plot__tick {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
}

.plot__tick > span {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
  white-space: nowrap;
}

.plot__tick:first-child > span {
  left: 0;
  transform: none;
}

.plot__tick:last-child > span {
  left: auto;
  right: 0;
  transform: none;
}

/* Строка под графиком: числа выбранного деления, а пока не выбрано —
   пик. Высота занята всегда: блок под графиком не прыгает. */
.plot__read {
  min-height: var(--h-xs);
  padding-top: var(--sp-1);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}

/* Таблица чисел: название и столько числовых столбцов, сколько назвал
   экран. */
.nums {
  --n: 2;
  --cols: minmax(0, 1fr) repeat(var(--n), minmax(var(--sp-12), auto));
}

.nums--1 { --n: 1; }
.nums--3 { --n: 3; }
.nums--4 { --n: 4; }
.nums--5 { --n: 5; }
.nums--6 { --n: 6; }

.nums__name {
  display: flex;
  flex-direction: column;
  gap: var(--sp-0h);
}

.nums__note {
  font-size: var(--text-xs);
  font-weight: var(--fw-normal);
  color: var(--ink-muted);
}

/* Ноль и прочерк — тихо, как на плитке. */
.nums__quiet {
  color: var(--ink-faint);
}

/* Полоска доли под названием: длина — данные, поэтому рисунком. */
.meter {
  display: block;
  width: 100%;
  height: var(--sp-0h);
  margin-top: var(--sp-0h);
  background: var(--line);
}

.meter__fill {
  fill: var(--ink-faint);
}

/* В узком блоке числа встают под названием, а подписи столбцов — к
   самим числам: шапка таблицы над пятью столбцами там уже не читается. */
@container stats (max-width: 600px) {
  .nums--many {
    --cols: repeat(var(--n), minmax(0, 1fr));
  }

  .nums--many > .table__row--head {
    display: none;
  }

  .nums--many > .nums__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .nums--many > .nums__row > .nums__name {
    grid-column: 1 / -1;
  }

  .nums--many > .nums__row > .table__cell--num {
    text-align: left;
  }

  .nums--many > .nums__row > .table__cell--num::before {
    content: attr(data-label);
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: var(--text-xs);
    color: var(--ink-muted);
  }
}

@container stats (max-width: 400px) {
  .nums--some {
    --cols: repeat(var(--n), minmax(0, 1fr));
  }

  .nums--some > .table__row--head {
    display: none;
  }

  .nums--some > .nums__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .nums--some > .nums__row > .nums__name {
    grid-column: 1 / -1;
  }

  .nums--some > .nums__row > .table__cell--num {
    text-align: left;
  }

  .nums--some > .nums__row > .table__cell--num::before {
    content: attr(data-label);
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: var(--text-xs);
    color: var(--ink-muted);
  }
}


/* ── Вход ─────────────────────────────────────────────────────────── *
   Слева — что это за место, справа — форма. На узком экране остаётся
   одна форма.                                                         */

.gate {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 440px;
  height: 100%;
  background: var(--bg-rail);
}

.gate__pitch {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
  padding: var(--sp-10) var(--sp-12) var(--sp-12);
  overflow: hidden;
}

/* Линии — под словами; слова читаются поверх. */
.gate__flow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  opacity: 0.55;
}

.gate__pitch > .brand,
.gate__words {
  position: relative;
}

.gate__words {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}

.gate__title {
  font-size: clamp(40px, 5vw, 72px);
  font-weight: var(--fw-semi);
  letter-spacing: -0.035em;
  line-height: 1.02;
}

.gate__caption {
  max-width: 40ch;
  font-size: var(--text-md);
  line-height: var(--lh-normal);
  color: var(--ink-muted);
}

.gate__panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 0;
  padding: var(--sp-10) var(--sp-12);
  border-left: var(--hair) solid var(--line);
  background: var(--bg-page);
}

.gate__box {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  justify-content: center;
  gap: var(--sp-6);
}

.gate__head {
  font-size: var(--text-xl);
  letter-spacing: -0.015em;
}

.gate__input {
  height: var(--h-lg);
}

.gate__code {
  width: 100%;
}

.gate__foot {
  display: flex;
  flex: none;
}

/* Согласие агента: форма прав длиннее формы входа — панель шире и
   прокручивается сама; слева остаётся, кто просит доступ. Выбор языка —
   внизу, а форма длиннее окна — после неё, с отступом. */
.gate--wide {
  grid-template-columns: minmax(0, 1fr) 560px;
}

.gate--wide .gate__panel {
  justify-content: flex-start;
  gap: var(--sp-8);
  overflow-y: auto;
}

.gate--wide .gate__box {
  flex: 1 0 auto;
  justify-content: flex-start;
}


/* ── Заглушка на входе ────────────────────────────────────────────── */

.home {
  position: relative;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  height: 100%;
  overflow: hidden;
  background: var(--bg-rail);
}

.home__flow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
}

.home__bar,
.home__foot {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-8);
}

.home__foot {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.home__center {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-5);
  padding: 0 var(--sp-6);
  text-align: center;
}

.home__word {
  font-size: clamp(56px, 11vw, 168px);
  font-weight: var(--fw-semi);
  letter-spacing: -0.05em;
  line-height: 0.9;
}

.home__line {
  max-width: 46ch;
  font-size: var(--text-md);
  line-height: var(--lh-normal);
  color: var(--ink-2);
}

.home__marks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-2) var(--sp-6);
  margin-top: var(--sp-2);
}

.home__mark {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.home__mark > .dot {
  background: var(--accent-line);
}


/* ── Страница отказа ──────────────────────────────────────────────── */

.lone {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: var(--sp-5) var(--sp-8);
  background: var(--bg-rail);
}

.lone__body {
  display: flex;
  flex: 1 1 0%;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: var(--sp-3);
  max-width: 560px;
  margin: 0 auto;
  width: 100%;
}

.lone__code {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.lone__title {
  font-size: var(--text-2xl);
  letter-spacing: -0.02em;
}

.lone__text {
  margin-bottom: var(--sp-3);
  line-height: var(--lh-normal);
  color: var(--ink-2);
}

/* Запись на встречу: дни и окна — кнопками в несколько рядов. Листать
   вбок на телефоне неудобно, а дней на экране немного. */
.slotpick__days,
.slotpick__slots {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--sp-2);
  width: 100%;
}

.slotpick__slots {
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  margin-bottom: var(--sp-3);
}

.slotpick__days > .btn,
.slotpick__slots > .btn {
  justify-content: center;
}

/* Слова хозяина о встрече — абзацами, как он их набрал. */
.slotpick__note {
  white-space: pre-line;
}


/* ── Лист печати ──────────────────────────────────────────────────── */

.paper {
  height: auto;
  overflow: visible;
  background: #ffffff;
}

/* На листе страница прокручивается как обычная: это бумага, а не экран
   с колонками. */
html:has(> .paper) {
  height: auto;
  overflow: visible;
}

.sheet {
  max-width: 760px;
  margin: 0 auto;
  padding: var(--sp-10) var(--sp-8);
}

.sheet__subject {
  font-size: var(--text-xl);
  letter-spacing: -0.015em;
}

.sheet__head {
  margin: var(--sp-5) 0;
  padding: var(--sp-4) 0;
  border-top: var(--hair) solid var(--line-strong);
  border-bottom: var(--hair) solid var(--line-strong);
}

/* Адрес ссылки печатается рядом с текстом: на бумаге по ней не щёлкнуть. */
.sheet__body a[href^="http"]::after {
  content: " (" attr(href) ")";
  font-size: 0.85em;
  color: var(--ink-muted);
  overflow-wrap: anywhere;
}

@media print {
  .sheet {
    max-width: none;
    padding: 0;
  }
}


/* ═══ 6. ДВИЖЕНИЕ ═══════════════════════════════════════════════════ *
   Движется только то, что появляется и уходит: панель письма, боковая
   панель на узком экране, всплывающие панели, окна. Остальное меняется
   сразу: в почте любое лишнее движение умножается на сотню писем в
   день.                                                               */

/* Панель письма выезжает справа поверх списка и уезжает туда же.
   Разворот — тем же ходом: меняется только предел ширины. */
.reader {
  transition:
    translate var(--t-norm) var(--ease),
    max-width var(--t-norm) var(--ease);
}

.reader.is-entering,
.reader.is-leaving {
  translate: 100% 0;
}

/* Уезжающая панель щелчков не ловит: под ней уже список. */
.reader.is-leaving {
  pointer-events: none;
}

/* Всё, что раскрывается поверх, проявляется коротким ходом от своей
   кнопки. Начальное положение названо правилом ниже — движение
   случается только в момент появления, а закрытие мгновенное: закрыв
   меню, ждать его незачем. */
.pop,
.dialog,
.peek {
  transition:
    opacity var(--t-fast) var(--ease),
    translate var(--t-fast) var(--ease);
}

/* Письмо или человек, которых убрали: строка исчезает сразу, не
   дожидаясь ответа сервера. Следом приходит экран с сервера — и если
   убрать не вышло, строка в нём стоит на месте. */
.row.is-going,
.book__item.is-going {
  display: none;
}

/* Переход на другой экран занял заметное время — под верхним краем идёт
   полоска: нажатие принято, ответ в пути. Первую десятую долю секунды
   её нет: быстрый переход она бы только пачкала. */
.app.is-going::after {
  content: "";
  position: fixed;
  z-index: var(--z-toast);
  top: 0;
  right: 0;
  left: 0;
  height: var(--sp-0h);
  background: var(--ink);
  transform-origin: 0 50%;
  animation: going var(--t-slow) var(--ease) var(--t-fast) infinite both;
}

@keyframes going {
  from { scale: 0 1; opacity: 1; }
  70%  { scale: 0.8 1; opacity: 1; }
  to   { scale: 1 1; opacity: 0; }
}

/* Всплывающая строка выезжает от своего края экрана и уходит туда же. */
.toast {
  transition:
    opacity var(--t-norm) var(--ease),
    translate var(--t-norm) var(--ease);
}

.toast.is-leaving {
  opacity: 0;
  translate: 0 var(--sp-2);
  pointer-events: none;
}

:root[data-corner^="top"] .toast.is-leaving {
  translate: 0 calc(-1 * var(--sp-2));
}

@starting-style {
  .pop          { opacity: 0; translate: 0 -4px; }
  .pop--up      { translate: 0 4px; }
  .dialog[open] { opacity: 0; translate: 0 8px; }
  .peek         { opacity: 0; }
  .toast        { opacity: 0; translate: 0 var(--sp-2); }

  :root[data-corner^="top"] .toast { translate: 0 calc(-1 * var(--sp-2)); }
}

/* Кто отключил анимации в системе — получает всё сразу. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0s !important;
    animation-duration: 0s !important;
    scroll-behavior: auto !important;
  }
}


/* ═══ 7. УЗКИЕ ЭКРАНЫ ═══════════════════════════════════════════════ *
   Пороги общие для всех экранов:
     1440 — панель письма уже;
     1180 — панель письма занимает всё, кроме боковой панели;
      900 — боковая панель уезжает за край и вызывается кнопкой;
      620 — телефон: одна колонка, строка письма в две линии.
   Правила здесь только переставляют то, что объявлено выше, — новых
   кирпичей для узкого экрана нет.                                     */

@media (max-width: 1440px) {
  :root {
    --w-reader: 680px;
  }
}

/* Сбоку от письма остаётся обрубок списка, в котором видно одни
   галочки. Честнее отдать письму всё место. */
@media (max-width: 1180px) {
  .reader,
  :root[data-reader="wide"] .reader {
    max-width: calc(100% - var(--w-rail));
  }

  .reader__mode {
    display: none;
  }

  .board__stat { grid-column: span 6; }
  .board__wide,
  .board__side,
  .board__half { grid-column: 1 / -1; }

  /* Выпуск: рядом редактору и письму тесно — письмо встаёт под ним. */
  .issue {
    grid-template-columns: minmax(0, 1fr);
  }

  .issue__view {
    position: static;
    max-height: none;
  }

  .issue__stage {
    overflow-y: visible;
  }
}

@media (max-width: 900px) {
  .app {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Адресная книга: место работы и счёт писем уступают имени и адресу. */
  .book__head {
    grid-template-columns: var(--h-xs) minmax(0, 3fr) minmax(0, 4fr) 72px auto;
  }

  .book__org,
  .book__meta {
    display: none;
  }

  /* Боковая панель — за левым краем. Спрятанная, она не видна и
     клавиатуре: иначе Tab уходил бы в пустоту. */
  .rail {
    position: absolute;
    z-index: var(--z-rail);
    top: 0;
    bottom: 0;
    left: 0;
    width: min(var(--w-rail), calc(100% - var(--sp-12)));
    translate: -100% 0;
    visibility: hidden;
    transition:
      translate var(--t-norm) var(--ease),
      visibility 0s linear var(--t-norm);
  }

  .app.is-nav .rail {
    translate: 0 0;
    visibility: visible;
    box-shadow: var(--shadow-pop);
    transition-delay: 0s;
  }

  .scrim {
    position: absolute;
    z-index: calc(var(--z-rail) - 1);
    inset: 0;
    display: block;
    background: var(--scrim);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--t-norm) var(--ease);
  }

  .app.is-nav .scrim {
    opacity: 1;
    pointer-events: auto;
  }

  .topbar__nav {
    display: inline-flex;
  }

  /* Письмо — на весь экран. */
  .reader,
  :root[data-reader="wide"] .reader {
    width: 100%;
    max-width: none;
    border-left: 0;
  }

  /* Клавиш на таком экране, скорее всего, нет. */
  .status__keys,
  .status__more,
  .kbd {
    display: none;
  }

  /* Ящик в строке письма — одним квадратом тона: подпись съела бы
     место темы. */
  .list,
  .list--multi {
    grid-template-columns:
      var(--edge) 16px 16px minmax(96px, 168px) minmax(0, 1fr) auto 56px var(--edge);
  }

  .list--multi {
    grid-template-columns:
      var(--edge) 16px 16px minmax(96px, 168px) minmax(0, 1fr) auto auto 56px var(--edge);
  }

  .row__box > .truncate {
    display: none;
  }

  /* Настройки: оглавление — полосой над разделами.

     Полоса прилипает к верху, поэтому поле сверху убрано у самой
     страницы, а не съедено отрицательным отступом полосы: прилипший блок
     не выходит за пределы своего родителя, и вытянутая вверх полоса
     вставала обратно — на первые строки раздела, закрывая его заголовок. */
  .page--split {
    grid-template-columns: minmax(0, 1fr);
    /* Высота ряда полосы названа явно. Полоса прокручивается вбок, а ряд
       под прокручиваемый блок сетка вправе сжать до нуля — и сжимала:
       разделы начинались прямо под её верхним краем. */
    grid-template-rows: max-content auto;
    gap: var(--sp-6);
    padding-top: 0;
  }

  /* Раздел, к которому перешли по оглавлению, встаёт под полосой, а не
     за ней. */
  .section,
  .mbox,
  .section__sub[id],
  #trust {
    scroll-margin-top: calc(var(--h-lg) + var(--sp-4));
  }

  .toc {
    z-index: var(--z-stick);
    flex-direction: row;
    margin: 0 calc(var(--pad) * -1);
    padding: 0 calc(var(--pad) - var(--sp-3));
    overflow-x: auto;
    border-bottom: var(--hair) solid var(--line);
    background: var(--bg-page);
    scrollbar-width: none;
  }

  .toc__item {
    flex: none;
    height: var(--h-lg);
    border-left: 0;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
  }

  .toc__item.is-on {
    border-bottom-color: var(--ink);
  }

  /* Месяц на узком экране: высота клеток — по содержимому, страница
     прокручивается целиком, как и неделя. */
  .month {
    flex: none;
  }

  /* Календарь: дни — строками, число слева, встречи справа. Страница
     прокручивается целиком. */
  .week {
    display: flex;
    flex: none;
    flex-direction: column;
    min-height: 0;
  }

  .week__day {
    flex-direction: row;
  }

  .week__day + .week__day {
    border-top: var(--hair) solid var(--line);
    border-left: 0;
  }

  .week__head {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0;
    width: 104px;
    height: auto;
    padding: var(--sp-3);
    border-right: var(--hair) solid var(--line);
    border-bottom: 0;
    line-height: var(--lh-snug);
  }

  .week__day.is-today > .week__head {
    box-shadow: inset 2px 0 0 var(--ink);
  }

  .week__name {
    max-width: 100%;
  }

  .week__list {
    overflow: visible;
    min-height: var(--sp-12);
  }

  /* Вход: остаётся форма, от левой половины — только знак. */
  .gate {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    background: var(--bg-page);
  }

  .gate__pitch {
    padding: var(--sp-5) var(--pad);
  }

  .gate__words,
  .gate__flow {
    display: none;
  }

  .gate__panel {
    padding: var(--sp-6) var(--pad) var(--sp-5);
    border-left: 0;
  }

  .gate__box {
    width: 100%;
    max-width: 400px;
    margin: 0 auto;
  }

  .gate__foot {
    justify-content: center;
  }
}

/* Палец толще курсора: пунктам панели и мелким кнопкам — рост. */
@media (pointer: coarse) {
  :root {
    --h-nav: 40px;
    --h-sm: 32px;
  }

  /* Короткое слово вкладки («Все») — узкая цель: даём ей ширину. */
  .tab {
    min-width: var(--h-sm);
    justify-content: center;
  }

  /* Галочка и флаг в строке письма остаются мелкими на вид, а область
     нажатия у них — с палец: невидимая подложка шире самого значка. */
  .row__pick::after,
  .row__flag::after {
    content: "";
    position: absolute;
    inset: calc(var(--sp-2) * -1);
  }

  /* Крестик на метке письма: четырнадцать пикселей пальцем не поймать.
     Кнопка вырастает до плашки, а сама метка остаётся прежней высоты —
     лишнее уходит в отрицательные поля. */
  .chip__drop {
    align-items: center;
    justify-content: center;
    width: var(--h-xs);
    height: var(--h-xs);
    margin: calc(var(--sp-0h) * -1) calc(var(--sp-1h) * -1) calc(var(--sp-0h) * -1) calc(var(--sp-1) * -1);
  }
}

/* Навести палец нельзя, а после касания «наведение» залипает — подсказка
   повисла бы над кнопкой до следующего касания. */
@media (hover: none) {
  [data-tip]::after {
    display: none;
  }

  /* То же с действиями под курсором в строке письма: залипнув, они
     закрыли бы время и метки. */
  .row:hover .row__quick,
  .row:focus-within .row__quick {
    display: none;
  }
}

@media (max-width: 620px) {
  :root {
    --pad: 16px;
  }

  /* Шапка: счёт уходит под заголовок, действия — значками. */
  .topbar {
    gap: var(--sp-2);
  }

  .topbar__title {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
  }

  .topbar__name {
    max-width: 100%;
    font-size: var(--text-md);
    line-height: var(--lh-tight);
  }

  .topbar__meta {
    max-width: 100%;
    overflow: hidden;
    font-size: var(--text-2xs);
    line-height: var(--lh-snug);
    text-overflow: ellipsis;
  }

  .topbar__tools {
    flex: 1 1 0%;
    justify-content: flex-end;
  }

  .topbar__tools > .menu > .btn {
    width: var(--h-md);
    padding: 0;
  }

  .topbar__tools > .menu > .btn > span {
    display: none;
  }

  .topbar__tools > .menu {
    position: static;
  }

  .topbar__tools > .menu > .pop {
    top: 100%;
    right: var(--sp-2);
    left: var(--sp-2);
    width: auto;
    min-width: 0;
    max-width: none;
  }

  /* Формы в панелях — во всю ширину панели: сама панель на телефоне
     растянута от края до края, и узкая форма оставляла в ней пустоту. */
  .meetform,
  .pop__form {
    width: auto;
  }

  .search {
    flex: 1 1 0%;
    width: auto;
    max-width: 420px;
  }

  /* Панель поиска и меню над списком и над письмом раскрываются на всю
     ширину экрана: от своей кнопки они ушли бы за край. */
  .search,
  .strip .menu,
  .letter__bar .menu {
    position: static;
  }

  .topbar,
  .strip,
  .letter__bar {
    position: relative;
  }

  .search__panel,
  .strip .pop,
  .letter__bar .pop {
    top: 100%;
    right: var(--sp-2);
    left: var(--sp-2);
    width: auto;
    min-width: 0;
    max-width: none;
  }

  /* Полоса над списком: порядок — одним значком. */
  .strip {
    gap: var(--sp-2);
  }

  .strip__idle,
  .strip__acts {
    gap: var(--sp-1);
  }

  /* Страницы на телефоне — только в конце списка: в полосе им нет места. */
  .strip__tail .menu > .btn > span,
  .strip__whole > span,
  .strip__tail > .pager,
  .strip__acts > .btn > span,
  .strip__sep {
    display: none;
  }

  /* Значком становятся действия со значком. Кнопка-слово в хвосте
     («эта неделя» в календаре) остаётся словом: значка у неё нет. */
  .strip__whole,
  .strip__acts > .btn {
    width: var(--h-sm);
    padding: 0;
  }

  /* Строка письма — в две линии: кто и когда, ниже тема с началом
     текста. Столбцы у каждой строки свои: общие заставили бы одну
     длинную метку сжать имена во всём списке. */
  .list,
  .list--multi {
    grid-template-columns: minmax(0, 1fr);
    column-gap: 0;
  }

  /* Первый столбец — поле экрана, галочка и зазор: галочка строки стоит
     ровно под «выделить всё» из полосы, а имя — под первой вкладкой.
     Прежде столбец был 36 пикселей с галочкой по центру, и она съезжала
     на шесть пикселей влево от той, что над ней. */
  .row {
    grid-template-columns: calc(var(--pad) + 16px + var(--sp-2)) minmax(0, 1fr) auto auto;
    grid-template-rows: auto auto;
    align-content: center;
    row-gap: var(--sp-0h);
    height: auto;
    min-height: calc(var(--row-h) + var(--sp-6));
    padding-right: var(--pad);
  }

  /* Засечка — по левому краю во всю высоту, вне столбцов. */
  .row::before {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
  }

  .row__pick {
    grid-area: 1 / 1 / 3 / 2;
    justify-self: start;
    margin-left: var(--pad);
  }

  .row__sender { grid-area: 1 / 2 / 2 / 3; }
  .row__marks  { grid-area: 1 / 3 / 2 / 4; margin-left: var(--sp-2); }
  .row__time   { grid-area: 1 / 4 / 2 / 5; margin-left: var(--sp-2); }
  .row__main   { grid-area: 2 / 2 / 3 / 4; }
  .row__box    { grid-area: 2 / 4 / 3 / 5; justify-self: end; }

  /* Файлы — третьей линией под темой. */
  .row--files,
  :root[data-density="compact"] .row--files {
    grid-template-rows: auto auto auto;
    height: auto;
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-2);
  }

  .row__files,
  :root[data-density="compact"] .row__files {
    grid-area: 3 / 2 / 4 / 5;
    display: flex;
    margin-top: var(--sp-1);
    padding-bottom: 0;
  }

  .chip--file {
    max-width: 160px;
  }

  /* Флаг — только у помеченных, рядом со временем нижней строкой. */
  .row__flag {
    display: none;
  }

  /* Метки — квадратами тона. */
  .row__marks > .chip {
    padding: 0;
    border: 0;
    background: none;
  }

  .row__marks > .chip > :not(.dot) {
    display: none;
  }

  /* Действия под курсором — не для пальца. */
  .row .row__quick,
  .row:hover .row__quick,
  .row:focus-within .row__quick {
    display: none;
  }

  .queue,
  .list--queue {
    grid-template-columns: minmax(0, 1fr);
  }

  .queue {
    row-gap: var(--sp-1);
    padding: var(--sp-3) var(--pad);
  }

  .queue::before {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
  }

  .queue__acts {
    justify-content: flex-start;
  }

  /* Месяц: слова в клетку шириной в палец не помещаются — остаются число
     и метки по числу встреч. Подробности — в неделе, куда ведёт клетка. */
  .month {
    grid-auto-rows: minmax(var(--sp-12), auto);
  }

  .month__dow {
    justify-content: center;
    padding: 0;
  }

  .month__day {
    align-items: center;
    gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .month__num {
    margin-bottom: 0;
  }

  .month__event,
  .month__more {
    display: none;
  }

  .month__dots {
    display: flex;
  }

  /* Шапка шага цепочки — одной строкой: номер и «через N дн.» не
     переносятся, кнопки справа — значками на любой ширине. */
  .sequence__step > .split > .cluster {
    flex-wrap: nowrap;
  }

  /* Адресная книга — в две линии, как письмо: имя, под ним адрес.
     Галочка стоит под «выделить всё» из полосы, имя — под вкладками. */
  .book__item {
    column-gap: var(--sp-2);
  }

  .book__item > .tick {
    height: calc(var(--row-h) + var(--sp-4));
  }

  .book__head {
    grid-template-columns: var(--h-xs) minmax(0, 1fr) auto;
    grid-template-rows: auto auto;
    align-content: center;
    row-gap: var(--sp-0h);
    height: auto;
    min-height: calc(var(--row-h) + var(--sp-4));
  }

  /* Задача: слова — первой линией, письмо и срок — второй; столбца под
     аватар у неё нет. */
  .book__head--task {
    grid-template-columns: minmax(0, 1fr) auto auto;
  }

  .book__head--task > .book__name { grid-area: 1 / 1 / 2 / 2; }
  .book__head--task > .book__addr { grid-area: 2 / 1 / 3 / 2; }
  .book__head--task > .book__last { display: block; grid-area: 1 / 2 / 3 / 3; }
  .book__head--task > .book__acts { grid-area: 1 / 3 / 3 / 4; }

  .taskcheck {
    height: calc(var(--row-h) + var(--sp-4));
  }

  .book__head > .avatar { grid-area: 1 / 1 / 3 / 2; }
  .book__name { grid-area: 1 / 2 / 2 / 3; }
  .book__addr { grid-area: 2 / 2 / 3 / 3; font-size: var(--text-sm); color: var(--ink-muted); }
  .book__acts { grid-area: 1 / 3 / 3 / 4; }

  /* Без имени вторая линия пуста — имя встаёт по центру строки. */
  .book__addr:empty {
    display: none;
  }

  .book__head:has(> .book__addr:empty) > .book__name {
    grid-row: 1 / 3;
  }

  .book__last {
    display: none;
  }

  .book__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .book__body > .form,
  .book__body > .book__facts {
    grid-column: 1;
  }

  /* Подписки: имя и кнопки — первой линией, адрес и числа — второй. */
  .subs {
    grid-template-columns: minmax(0, 1fr);
  }

  .subs__item {
    grid-template-columns: var(--h-xs) minmax(0, 1fr) auto;
    column-gap: var(--sp-3);
    padding-right: var(--pad);
    padding-left: var(--pad);
    grid-template-rows: auto auto;
    align-content: center;
    row-gap: var(--sp-0h);
    min-height: calc(var(--row-h) + var(--sp-5));
    padding-top: var(--sp-2);
    padding-bottom: var(--sp-2);
  }

  .subs__item > .avatar { grid-area: 1 / 1 / 3 / 2; }
  .subs__name { grid-area: 1 / 2 / 2 / 3; }
  .subs__acts { grid-area: 1 / 3 / 2 / 4; }
  .subs__meta { grid-area: 2 / 2 / 3 / 4; }

  .subs__addr {
    display: none;
  }

  .subs__state {
    grid-area: 3 / 2 / 4 / 4;
    justify-content: flex-start;
  }

  .subs__state:empty {
    display: none;
  }

  /* Кнопка отписки — значком: слово в строку с именем не помещается. */
  .subs__acts .btn--outline > span {
    display: none;
  }

  /* Письмо. */
  .letter__bar {
    padding: 0 var(--sp-2);
  }

  .letter__bar > .strip__sep {
    display: none;
  }

  .letter__scroll {
    padding: var(--sp-5) var(--pad) var(--sp-8);
  }

  .letter__subject {
    font-size: var(--text-lg);
  }

  .letter__foot {
    position: relative;
    padding: 0 var(--pad);
  }

  /* Под письмом словами — только «Ответить»: три кнопки с подписями в
     ширину телефона не входят, и третья уезжала за край. У остальных
     остаётся значок; что он делает, сказано в подписи для читалки. */
  .letter__foot > .btn:not(.btn--primary) {
    width: var(--h-md);
    padding: 0;
  }

  .letter__foot > .btn:not(.btn--primary) > span {
    display: none;
  }

  /* Меню в подвале редактора («позже», параметры) раскрываются на всю
     ширину экрана: от своей кнопки они уходили за правый край. */
  .letter__foot .menu {
    position: static;
  }

  .letter__foot .pop {
    right: var(--sp-2);
    bottom: calc(100% + var(--sp-1));
    left: var(--sp-2);
    width: auto;
    min-width: 0;
    max-width: none;
  }

  .wide-only {
    display: none;
  }

  .narrow-only {
    display: revert;
  }

  /* Отмечено — в полосе остаются только действия: порядок и страницы на
     это время уходят, иначе действиям не хватает ширины. Спам из пачки
     на телефоне убран: он есть в самом письме. */
  .main--mail:has([data-row-check]:checked) .strip__tail,
  .strip__acts > .btn[value="spam"],
  .strip__acts > .btn[value="not-spam"] {
    display: none;
  }

  .strip__count {
    margin-right: 0;
  }

  /* Таблицы настроек. В три столбца на телефоне первому не остаётся
     места — у списка устройств он сжимался до нуля, и строка состояла из
     одной даты. Главное встаёт своей строкой, остальное — под ним. */
  .table {
    column-gap: var(--sp-3);
  }

  .table--stack {
    --cols: minmax(0, 1fr) auto;
  }

  .table--stack > .table__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .table--stack > .table__row > :first-child {
    grid-column: 1 / -1;
  }

  .table--stack > .table__row > .table__cell {
    white-space: normal;
  }

  /* Письма сайтов: дата на телефоне не показывается, а судьба письма
     встаёт к правому краю — ровным столбцом. */
  .table--sitemail > .table__row > :nth-child(3) {
    justify-self: end;
  }

  /* Консоль: строка ящика, человека и записи журнала — в два ряда. */
  .table--adminboxes,
  .table--adminpeople {
    --cols: minmax(0, 1fr) auto;
  }

  .table--audit {
    --cols: auto minmax(0, 1fr) auto;
  }

  .table--audit > .table__row > :nth-child(4) {
    grid-column: 1 / -1;
  }

  /* Журнал вебхука: событие и исход — строкой, ответ адреса — под ними. */
  .table--hooklog {
    --cols: minmax(0, 1fr) auto;
  }

  .table--hooklog > .table__row > :nth-child(3) {
    grid-column: 1 / -1;
  }

  /* Сохранённый поиск: сам запрос на телефоне не показываем, и столбец
     под него не держим. */
  .table--pairs:has(.wide-only) {
    --cols: minmax(0, 1fr) auto;
  }

  .thread__item {
    grid-template-columns: 96px minmax(0, 1fr) auto;
  }

  /* Редактор. */
  .composer__lines,
  .composer__notes {
    padding-right: var(--pad);
    padding-left: var(--pad);
  }

  /* Список «От кого» раскрывается во всю строку: длинный адрес от своей
     кнопки уходил за правый край. */
  .composer__line > .pick {
    position: static;
  }

  .composer__line > .pick > .pop {
    right: 0;
    left: 0;
    width: auto;
    min-width: 0;
    max-width: none;
  }

  .composer__label {
    width: var(--sp-12);
  }

  .composer__hints {
    right: 0;
    left: 0;
    min-width: 0;
    max-width: 100%;
  }

  .editor__tools {
    position: relative;
    padding: 0 var(--sp-2);
  }

  /* Помощник и заготовки — значками: со словами полоса инструментов в
     экран не помещалась. Их панели раскрываются на всю ширину. */
  .editor__tools .menu > .btn > span {
    display: none;
  }

  .editor__tools .menu {
    position: static;
  }

  .editor__tools .menu > .pop {
    top: 100%;
    right: var(--sp-2);
    left: var(--sp-2);
    width: auto;
    min-width: 0;
    max-width: none;
  }

  .editor__tools .menu > .pop.is-up {
    top: auto;
    bottom: 100%;
  }

  /* Редкие кнопки оформления на телефоне уступают место нужным:
     картинке, эмодзи, помощнику. Нумерованный список, цитату и «убрать
     оформление» с телефона почти не ставят. */
  .editor__rare {
    display: none;
  }

  /* Плашка с кнопкой: слова во всю ширину, кнопка — под ними. В одну
     строку словам оставался столбик в три слова шириной. */
  .notice:has(> .btn) {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    row-gap: var(--sp-2);
    padding-top: var(--sp-3);
    padding-bottom: var(--sp-3);
  }

  .notice:has(> .btn) > .btn {
    grid-column: 2;
    justify-self: start;
  }

  .editor__text,
  .composer__files {
    padding-right: var(--pad);
    padding-left: var(--pad);
  }

  /* Отпечаток: по одной группе в строке — две рядом на телефон не влезают. */
  .print {
    grid-template-columns: max-content;
  }

  /* Страницы. У настроек поля сверху нет вовсе: там полоса оглавления. */
  .page:not(.page--split) {
    padding-top: var(--sp-5);
  }

  .options {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-2);
  }

  .options > :not(.options__name) {
    margin-bottom: var(--sp-3);
  }

  .page__body:not(.page__body--form) {
    gap: var(--sp-3);
  }

  .card {
    --card-pad: var(--sp-4);
  }

  .board__mail {
    --cols: minmax(0, 2fr) minmax(0, 3fr) auto;
  }

  /* Условие правила: «где» и «как» в ряд, значение — под ними. Шапка
     столбцов уходит: в две строки она подписывала бы не то. */
  .rulegrid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }

  .rulegrid > .field__label {
    display: none;
  }

  .rulegrid > .input {
    grid-column: 1 / -1;
    margin-bottom: var(--sp-2);
  }

  /* Список у правого выбора («как») раскрывается от правого края: он
     шире своей кнопки и от левого уходил за край экрана. */
  .rulegrid > details:nth-of-type(even) > .pop {
    right: 0;
    left: auto;
  }

  /* Донор: сайт и состояние, под ними адрес и ссылка. Причина состояния
     и срок следующего письма стоят в нижней строке (см. разметку): рядом
     со значком состояния они забирали всю ширину, и от имени сайта не
     оставалось ничего. */
  .lead {
    grid-template-columns: var(--icon) minmax(0, 1fr) auto;
    row-gap: var(--sp-0h);
    padding: var(--sp-2) 0;
  }

  .lead--head {
    display: none;
  }

  .lead > :nth-child(1) { grid-area: 1 / 1 / 3 / 2; }
  .lead > :nth-child(2) { grid-area: 1 / 2; }
  .lead > :nth-child(4) { grid-area: 1 / 3; justify-self: end; }

  .lead > :nth-child(3),
  .lead > :nth-child(5) {
    font-size: var(--text-sm);
    color: var(--ink-muted);
  }

  .lead > :nth-child(3) { grid-area: 2 / 2; }
  .lead > :nth-child(5) { grid-area: 2 / 3; justify-self: end; }

  /* Поиск по адресатам — во всю ширину, под вкладками. */
  .leadbar__find {
    flex-basis: 100%;
  }

  /* Отчёт по письмам: полоска доли и столбец возвратов уступают место
     главному — сколько ушло и сколько ответили. Возвраты целиком стоят
     числом выше, в сводке. */
  .steps {
    --cols: minmax(0, 1fr) 88px 96px;
  }

  .steps > .table__row > :nth-child(2),
  .steps > .table__row > :nth-child(4) {
    display: none;
  }

  /* Записи домена: имя и оценка в строку, сама запись — под ними. */
  .table--records {
    --cols: minmax(0, 1fr) auto;
  }

  .table--records > .table__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .table--records > .table__row > :nth-child(2) {
    grid-area: 2 / 1 / 3 / -1;
  }

  /* Проверки доставки: откуда и куда — строкой, под ними итог и оценки. */
  .table--probes {
    --cols: minmax(0, 1fr) minmax(0, 1fr);
  }

  .table--probes > .table__row--head {
    display: none;
  }

  .table--probes > .table__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .table--probes > .table__row > :nth-child(4) {
    grid-column: 1 / -1;
  }

  .table--probes > .table__row > :nth-child(5) {
    text-align: left;
  }

  .table--sources {
    --cols: minmax(0, 1fr) 56px 104px;
  }

  /* Стоп-лист: адрес своей строкой, под ним причина и когда. */
  .table--stops {
    --cols: auto minmax(0, 1fr) auto;
  }

  .table--stops > .table__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .table--stops > .table__row > :first-child {
    grid-column: 1 / -1;
  }

  /* Выпуски: тема — своей строкой, целиком; под ней состояние, сколько
     ушло и сколько открыли. Переходы и дата уступают место — они есть
     на экране выпуска. */
  .table--issues {
    --cols: minmax(0, 1fr) 64px 72px;
  }

  .table--issues > .table__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .table--issues > .table__row > :nth-child(5),
  .table--issues > .table__row > :nth-child(6),
  .table--issues > .table__row--head > :nth-child(2) {
    display: none;
  }

  .table--issues > .issues__row > :nth-child(1) { grid-area: 1 / 1 / 2 / -1; }
  .table--issues > .issues__row > :nth-child(2) { grid-area: 2 / 1; }
  .table--issues > .issues__row > :nth-child(3) { grid-area: 2 / 2; }
  .table--issues > .issues__row > :nth-child(4) { grid-area: 2 / 3; }

  /* Цепочка: тема своей строкой, под ней срок и счёт. */
  .table--series {
    --cols: var(--h-xs) minmax(0, 1fr) auto;
  }

  .table--series > .table__row {
    row-gap: var(--sp-1);
    padding: var(--sp-2) 0;
  }

  .table--series > .table__row > :nth-child(1) { grid-area: 1 / 1 / 3 / 2; }
  .table--series > .table__row > :nth-child(2) { grid-area: 1 / 2 / 2 / -1; }
  .table--series > .table__row > :nth-child(3) { grid-area: 2 / 2; }
  .table--series > .table__row > :nth-child(4) { grid-area: 2 / 3; }

  /* Шапка выпуска: стрелка и тема — в строку; состояние стоит ниже, в
     самом экране, и в шапке ему на телефоне нет места. */
  .topbar__title:has(> .btn) {
    flex-direction: row;
    align-items: center;
    gap: var(--sp-1);
  }

  .topbar__title:has(> .btn) > .badge {
    display: none;
  }

  /* Ссылки выпуска: числам хватает меньшего. */
  .table--links {
    --cols: minmax(0, 1fr) 48px 88px;
  }

  /* Адрес формы — строкой, кнопка под ним. */
  .copyline {
    flex-wrap: wrap;
  }

  .copyline > .link {
    flex: 1 1 100%;
  }

  /* Кнопки выпуска: два ряда, каждый во всю ширину. */
  .issue__acts > .cluster {
    flex: 1 1 100%;
  }

  .peek__stage {
    padding: var(--sp-3);
  }

  /* Боковой панели на экране нет — стопка строк от края до края. */
  .app ~ .toasts {
    left: 0;
  }

  .home__bar,
  .home__foot,
  .lone {
    padding-right: var(--pad);
    padding-left: var(--pad);
  }
}

@media (max-width: 620px) {
  /* Всплывающая строка — во всю ширину у своего края, слева и справа
     ей на телефоне стоять негде. */
  .toasts {
    bottom: calc(var(--sp-4) + env(safe-area-inset-bottom, 0px));
    align-items: stretch;
  }

  :root[data-corner] .toasts {
    align-items: stretch;
  }

  .toast {
    width: auto;
  }
}


/* ═══ ВИТРИНА ═══════════════════════════════════════════════════════ *
   Страница /styleguide: кирпичи во всех состояниях. Стили ниже — только
   её собственная раскладка; сами кирпичи описаны выше.               */

.guide {
  height: 100%;
  overflow-y: auto;
  padding: var(--sp-10) var(--sp-8) var(--sp-16);
}

.guide__head,
.guide__part {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  max-width: var(--w-page);
  margin: 0 auto;
}

.guide__part {
  margin-top: var(--sp-10);
  padding-top: var(--sp-8);
  border-top: var(--hair) solid var(--line);
}

.guide__title {
  font-size: var(--text-2xl);
  letter-spacing: -0.02em;
}

.guide__swatches {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
  gap: var(--sp-3);
}

.guide__swatch {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1h);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.guide__chip {
  height: var(--sp-12);
  border: var(--hair) solid var(--line-strong);
}

.guide__chip--bg-rail     { background: var(--bg-rail); }
.guide__chip--bg-page     { background: var(--bg-page); }
.guide__chip--bg-raised   { background: var(--bg-raised); }
.guide__chip--bg-sunken   { background: var(--bg-sunken); }
.guide__chip--bg-control  { background: var(--bg-control); }
.guide__chip--bg-hover    { background: var(--bg-hover); }
.guide__chip--bg-active   { background: var(--bg-active); }
.guide__chip--bg-picked   { background: var(--bg-picked); }
.guide__chip--line        { background: var(--line); }
.guide__chip--line-strong { background: var(--line-strong); }
.guide__chip--ink         { background: var(--ink); }
.guide__chip--ink-2       { background: var(--ink-2); }
.guide__chip--ink-muted   { background: var(--ink-muted); }
.guide__chip--ink-faint   { background: var(--ink-faint); }
.guide__chip--accent      { background: var(--accent); }
.guide__chip--accent-line { background: var(--accent-line); }
.guide__chip--danger      { background: var(--danger); }
.guide__chip--warn        { background: var(--warn); }
.guide__chip--ok          { background: var(--ok); }

.guide__t        { line-height: var(--lh-snug); }
.guide__t--3xl   { font-size: var(--text-3xl); font-weight: var(--fw-semi); letter-spacing: -0.02em; }
.guide__t--2xl   { font-size: var(--text-2xl); font-weight: var(--fw-semi); letter-spacing: -0.02em; }
.guide__t--xl    { font-size: var(--text-xl);  font-weight: var(--fw-semi); letter-spacing: -0.01em; }
.guide__t--lg    { font-size: var(--text-lg);  font-weight: var(--fw-semi); }
.guide__t--md    { font-size: var(--text-md); }
.guide__t--base  { font-size: var(--text-base); }
.guide__t--sm    { font-size: var(--text-sm); color: var(--ink-2); }
.guide__t--xs    { font-size: var(--text-xs); color: var(--ink-muted); }

.guide__icons {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: var(--sp-3) var(--sp-2);
}

.guide__icon {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

.guide__icon > .icon {
  color: var(--ink);
}

/* Раскрытому меню нужно место под панель. */
.guide__open {
  min-height: 264px;
  align-items: flex-start;
}

.guide__table {
  --cols: minmax(0, 1fr) 160px 160px auto;
}

.guide__cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-4);
}

/* На витрине строки стоят на месте, а не висят над экраном. */
.guide__toasts {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-2);
}
