/* Палитра v3 (docs/superpowers/specs/2026-07-30-v3-foundations-design.md,
   источник — handoff Design/New/tokens). Цвета свои, у Telegram
   спрашиваем только светлая/тёмная — см. applyColorScheme() в app.js. */
:root {
  /* Нейтрали */
  --n-0: oklch(99% 0.003 260);
  --n-50: oklch(96% 0.006 260);
  --n-100: oklch(92% 0.008 260);
  --n-300: oklch(80% 0.012 260);
  --n-500: oklch(54% 0.018 260); /* 58% давал 3.8:1 подписям на --bg */
  --n-700: oklch(38% 0.02 260);
  --n-900: oklch(22% 0.02 260);

  /* Бренд */
  --brand-500: oklch(64% 0.17 258);
  --brand-600: oklch(58% 0.17 258);
  --brand-700: oklch(50% 0.16 258);

  /* Конвейер статусов: очередь → эфир → проверка → готово */
  --stage-todo: oklch(70% 0.025 260);
  --stage-doing: oklch(62% 0.17 258);
  --stage-review: oklch(76% 0.15 70);
  --stage-done: oklch(65% 0.14 150);
  --danger: oklch(60% 0.19 25);

  /* Стадийные цвета — заливочные: как ТЕКСТ они дают 2-3:1. Для подписей
     нужны более тёмные «чернила» (в тёмной теме, наоборот, годятся сами
     заливочные — там фон тёмный). */
  --stage-review-ink: oklch(54% 0.13 70);
  --stage-done-ink: oklch(52% 0.13 150);
  /* --danger как подпись даёт 4.2:1 — ниже нормы для мелкого текста */
  --danger-ink: oklch(56% 0.19 25);
  /* Зелёная кнопка: на --stage-done белая подпись давала 3.0:1 */
  --success-bg: oklch(55% 0.14 150);

  /* Заливки диаграмм. Стадийные цвета против дорожки полосы дают 1.7-2.9:1 —
     тонкая полоса и точка легенды на этом теряются. Логика та же, что у -ink:
     в светлой теме темнее, в тёмной совпадают со стадийными. */
  --chart-todo: var(--n-500);
  --chart-doing: var(--brand-600);
  --chart-review: var(--stage-review-ink);

  /* Семантические */
  --bg: var(--n-50);
  --surface: var(--n-0);
  --surface-sunken: var(--n-100);
  --text: var(--n-900);
  --text-hint: var(--n-500);
  --border-soft: color-mix(in oklch, var(--n-500) 16%, transparent);
  /* Обводка самостоятельного контрола: поле ввода, бейдж, чекбокс. Норма для
     границы — 3:1, а не 4.5:1 как у текста: сплошной --n-500 давал 4.5 в
     светлой теме и 7.8 в тёмной, то есть обводку в вес самой подписи. */
  --border-strong: color-mix(in oklch, var(--n-500) 80%, transparent);
  --btn-bg: var(--brand-700); /* brand-600 давал подписи 4.2:1 */
  --btn-text: oklch(99% 0 0);

  /* Геометрия */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-pill: 999px;
  --shadow-fab: 0 4px 14px oklch(20% 0.02 260 / 0.18);

  /* Отступы из handoff */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-12: 48px;

  /* Типографика из handoff. Семейство внутри
     шорткатов обязательно: font сбрасывает font-family. */
  --font-ui: 'Onest', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --text-display: 800 26px/1.15 var(--font-ui);
  --text-title: 800 22px/1.2 var(--font-ui);
  --text-heading: 800 17px/1.3 var(--font-ui);
  --text-body-strong: 600 15px/1.35 var(--font-ui);
  --text-body: 500 15px/1.4 var(--font-ui);
  --text-meta: 600 12.5px/1.3 var(--font-ui);
  --text-micro: 700 11.5px/1.2 var(--font-ui);
  --letter-tight: -0.02em;

  /* Псевдонимы прежних имён: ~1500 строк CSS продолжают работать без
     переименования, фазы 3-5 переезжают на словарь макета по мере
     переделки блоков. */
  --card: var(--surface);
  --hint: var(--text-hint);
  --btn: var(--btn-bg);
  /* Заливка кнопки и «акцентная краска» — разные роли: заливке нужен
     контраст со СВЕТЛОЙ подписью, тексту и обводкам — с фоном страницы.
     Один токен на обе роли означал, что улучшение одной портит другую. */
  --accent-ink: var(--brand-700); /* brand-600 давал 4.2:1 подписям на карточке */
  --radius: var(--radius-md);

  /* Наш «контур тенью» вместо рамки — перевыведен из палитры */
  --shadow-border:
    0 0 0 1px var(--border-soft),
    0 1px 2px -1px color-mix(in oklch, var(--n-900) 8%, transparent),
    0 2px 4px 0 color-mix(in oklch, var(--n-900) 5%, transparent);

  /* Нативные контролы (select, input[type=date]) рисуются UA по этому
     свойству — без него их выпадашки и календарь остаются светлыми на
     тёмной теме. */
  color-scheme: light;
}

/* Тёмная тема (в макете её нет — выведена в той же системе: hue 260,
   бренд и стадии те же, нейтрали инвертированы). Одна копия значений:
   атрибут data-theme ставит JS и из Telegram, и из системной темы —
   см. бутстрап в index.html и applyColorScheme() в app.js. */
:root[data-theme='dark'] {
  --n-0: oklch(21% 0.014 260);
  --n-50: oklch(16% 0.012 260);
  --n-100: oklch(26% 0.014 260);
  --n-300: oklch(38% 0.016 260);
  --n-500: oklch(72% 0.02 260);
  --n-700: oklch(85% 0.01 260);
  --n-900: oklch(96% 0.006 260);

  --brand-500: oklch(70% 0.17 258);
  --brand-600: oklch(64% 0.17 258);
  --brand-700: oklch(54% 0.17 258); /* единственный потребитель — --btn-bg */

  --stage-todo: oklch(74% 0.03 260);
  --stage-doing: oklch(68% 0.17 258);
  --stage-review: oklch(80% 0.15 70);
  --stage-done: oklch(70% 0.14 150);
  --danger: oklch(66% 0.19 25);

  /* На тёмном фоне сами стадийные цвета читаются как текст (5.8-6.8:1) */
  --stage-review-ink: var(--stage-review);
  --stage-done-ink: var(--stage-done);
  --danger-ink: var(--danger);

  --chart-todo: var(--stage-todo);
  --chart-doing: var(--stage-doing);
  --chart-review: var(--stage-review);

  --btn-bg: var(--brand-700);
  --accent-ink: var(--brand-500);
  --border-soft: color-mix(in oklch, var(--n-500) 20%, transparent);
  /* В тёмной теме та же доля дала бы 5.3:1 — нейтраль там светлее фона */
  --border-strong: color-mix(in oklch, var(--n-500) 60%, transparent);
  --shadow-border: 0 0 0 1px var(--border-soft);
  color-scheme: dark;
}

@font-face {
  font-family: 'Onest';
  src: url('https://fonts.gstatic.com/s/onest/v9/gNMEW2NoNyIAQNGJd6IdVdF9wjEnA5o6.woff2') format('woff2');
  font-weight: 400 800;
  font-style: normal;
  font-display: swap;
}

* { box-sizing: border-box; margin: 0; }

body {
  font-family: var(--font-ui);
  background: var(--bg);
  color: var(--text);
  /* Место под зафиксированное нижнее меню (высота ~54px) снизу экрана */
  padding-bottom: calc(54px + env(safe-area-inset-bottom));
  -webkit-tap-highlight-color: transparent;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* --- Шапка --- */

.topbar {
  position: relative; /* якорь для дропдауна «Ещё» */
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px 10px;
}

.topbar .title {
  font: var(--text-title);
  letter-spacing: var(--letter-tight);
}

/* Вордмарк только на desktop, название страницы — только на мобильном
   (показ/скрытие в @media ниже, как у #topbarNav / #bottomNav) */
.wordmark {
  font: var(--text-title);
  letter-spacing: var(--letter-tight);
  flex: none;
  display: none;
}

.nav-count {
  margin-left: 5px;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-hint);
}

.seg {
  display: flex;
  background: var(--card);
  border-radius: var(--radius-md);
  padding: 3px;
}

.seg-btn {
  border: 0;
  background: transparent;
  color: var(--hint);
  font: var(--text-meta);
  font-size: 14px;
  padding: 5px 14px;
  border-radius: 8px;
  cursor: pointer;
}

.seg-btn.active {
  background: var(--btn);
  color: var(--btn-text);
}

/* В радиогруппе по Tab доступна только выбранная кнопка, а между вариантами
   ходят стрелками — без видимого фокуса непонятно, где ты находишься. */
.seg-btn:focus-visible,
.status-btn:focus-visible,
.view-status-btn:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}

/* По Tab фокус попадает именно на выбранную кнопку — а её заливка тот же
   --accent-ink, и кольцо на ней читалось бы как «кнопка стала толще». */
.seg-btn.active:focus-visible {
  outline-color: var(--text);
}

/* --- Список карточек --- */

.list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 0 16px;
}

.card {
  display: flex;
  align-items: stretch;
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
  box-shadow: var(--shadow-border);
  overflow: hidden;
  cursor: pointer;
  transition-property: scale, box-shadow;
  transition-duration: 150ms;
  transition-timing-function: ease-out;
}
.card:active { scale: 0.98; }

.card-rail {
  width: 4px;
  flex: none;
  background: var(--col-color, var(--hint));
}

.card-main {
  flex: 1;
  padding: 12px 13px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.card-title {
  font: var(--text-body-strong);
  overflow-wrap: break-word;
  text-wrap: pretty;
}

/* Строка «исполнители ↔ срок» */
.card-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
}

.card-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  font: var(--text-meta);
  color: var(--hint);
  flex-wrap: wrap;
}

.card-no-assignee,
.card-comments {
  font-size: 11.5px;
  color: var(--hint);
}

.card-comments {
  font-weight: 600;
}

.card-free {
  font: var(--text-micro);
  color: var(--accent-ink);
}

.due { font-weight: 600; font-variant-numeric: tabular-nums; }
.due.today { color: var(--stage-review); }
.due.overdue { color: var(--danger); }

.advance {
  flex: none;
  border: 0;
  background: transparent;
  color: var(--hint);
  font-size: 20px;
  padding: 0 14px;
  cursor: pointer;
  align-self: stretch;
}
.advance:active { color: var(--text); }

/* Пустая страница или колонка */
.empty {
  text-align: center;
  color: var(--text-hint);
  font-size: 14px;
  padding: 48px 24px;
  line-height: 1.5;
}

/* В desktop-колонке 48px сверху выглядели дырой */
.empty.tight {
  font-size: 12.5px;
  padding: 20px 4px;
}

/* Подпись внутри секции или виджета — не по центру и мельче */
.empty-inline {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-hint);
  padding: 6px 0;
}

/* --- Кнопка добавления --- */

.fab {
  position: fixed;
  right: 16px;
  bottom: calc(70px + env(safe-area-inset-bottom));
  width: 54px;
  height: 54px;
  border-radius: 50%;
  border: 0;
  padding: 0;
  background: var(--btn);
  color: var(--btn-text);
  /* Плюс рисуется двумя полосками ниже, а текстовый глиф «+» из разметки
     скрывается: его положение зависело от метрик шрифта (Onest мог не
     догрузиться) и от кнопочных UA-паддингов, из-за чего на разных
     телефонах он съезжал от центра. Геометрии съезжать нечем.
     Доступное имя кнопки берётся из её aria-label. */
  font-size: 0;
  cursor: pointer;
  box-shadow: var(--shadow-fab);
  z-index: 10; /* выше .avatar-ready, которая всплывает над стопкой */
  transition-property: scale;
  transition-duration: 150ms;
  transition-timing-function: ease-out;
}

.fab::before,
.fab::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: currentColor;
  border-radius: 1px;
}
.fab::before { width: 20px; height: 2px; }
.fab::after { width: 2px; height: 20px; }

.fab:active { scale: 0.96; }

/* --- Шторка задачи --- */

.sheet { position: fixed; inset: 0; z-index: 20; }
.sheet.hidden, .hidden { display: none; }

.sheet-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
}

.sheet-body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--card);
  border-radius: 16px 16px 0 0;
  padding: 8px 16px calc(16px + env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 88vh;
  overflow-y: auto;
  transition: transform 0.2s ease;
}

/* Во время свайпа вниз шторка следует за пальцем без задержки —
   транзишн включается обратно только при отпускании (см. app.js). */
.sheet-body.dragging {
  transition: none;
}

.sheet-grip {
  width: 36px;
  height: 4px;
  border-radius: 2px;
  background: var(--hint);
  opacity: 0.4;
  margin: 4px auto 2px;
}

.inp {
  width: 100%;
  border: 1px solid var(--border-strong);
  background: var(--bg);
  color: var(--text);
  border-radius: var(--radius-md);
  padding: 10px 12px;
  font: inherit;
  /* 16px и выше — иначе iOS Safari/WebView зумит страницу при фокусе на поле
     (правило действует для любого поля ввода с font-size < 16px), из-за чего
     форма визуально "сужается" при открытии клавиатуры. */
  font-size: 16px;
}
.inp:focus { outline: 2px solid var(--accent-ink); outline-offset: -1px; }

textarea.inp { resize: vertical; }

/* iOS/WebKit рисует date-инпут собственным виджетом с внутренней шириной:
   поле игнорировало width:100% и вылезало за правый край экрана (видно
   только на устройстве). appearance:none возвращает его в обычную коробку
   .inp; высоту держим явно — пустое поле без нативного виджета иначе
   схлопывается до одних паддингов. */
input[type='date'].inp {
  -webkit-appearance: none;
  appearance: none;
  min-width: 0;
  max-width: 100%;
  min-height: 42px; /* высота текстового .inp: 16px шрифт + 10px паддинги */
}

/* Значение iOS центрирует — остальные поля у нас левосторонние */
input[type='date'].inp::-webkit-date-and-time-value {
  text-align: left;
}

/* «Исполнитель» и «Срок» — друг под другом: бок о бок они слипались и на
   телефоне, и в desktop-панели той же ширины (440px) */
.row {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.row .lbl { min-width: 0; }

.lbl {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--hint);
}
/* .lbl задаёт display:flex и объявлен позже общего .hidden{display:none} —
   при равной специфичности класс, идущий позже в файле, побеждает, так что
   без этого компаунд-правила элемент с classList "lbl hidden" (например,
   #statusBlock при создании задачи) оставался бы видимым. */
.lbl.hidden { display: none; }

.status-pick { display: flex; gap: 6px; }

.status-btn {
  flex: 1;
  border: 0;
  background: var(--bg);
  color: var(--hint);
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  padding: 9px 4px;
  border-radius: 9px;
  cursor: pointer;
  border-top: 3px solid transparent;
}

.status-btn.active {
  color: var(--text);
  border-top-color: var(--sb-color);
}

.sheet-actions {
  display: flex;
  gap: 10px;
  margin-top: 4px;
}
/* display:flex объявлен позже общего .hidden{display:none} и победил бы его
   (футер детали прячется у архивной задачи) */
.sheet-actions.hidden {
  display: none;
}

.btn {
  border: 0;
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font: var(--text-body-strong);
  cursor: pointer;
  transition-property: scale;
  transition-duration: 150ms;
  transition-timing-function: ease-out;
}
.btn:active { scale: 0.96; }

.btn:disabled {
  opacity: 0.55;
  cursor: default;
}
.btn:disabled:active { scale: 1; }

.btn.primary {
  flex: 1;
  background: var(--btn);
  color: var(--btn-text);
}

/* В макете Button variant="success" — «Я готов» */
.btn.success {
  background: var(--success-bg);
  color: #fff;
}

.btn.danger {
  background: color-mix(in srgb, var(--danger) 14%, transparent);
  color: var(--danger);
}

/* --- Тост --- */

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(70px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  background: var(--text);
  color: var(--card);
  font-size: 13.5px;
  padding: 9px 14px;
  border-radius: var(--radius-md);
  max-width: 86vw;
  z-index: 30;
}

@media (prefers-reduced-motion: no-preference) {
  .sheet-body { animation: rise 0.18s ease-out; }
  @keyframes rise {
    from { transform: translateY(24px); opacity: 0.6; }
    to { transform: translateY(0); opacity: 1; }
  }

  /* Въезд списка при свайпе между стадиями (мобильная доска) */
  .list.slide-in-left { animation: slideInLeft 0.2s ease-out; }
  .list.slide-in-right { animation: slideInRight 0.2s ease-out; }
  @keyframes slideInLeft {
    from { transform: translateX(-16px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
  }
  @keyframes slideInRight {
    from { transform: translateX(16px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
  }
}

/* --- Экран «Люди» --- */

/* Используется и заголовком модалки «Добавить участника» (#assigneePickerSheet) */
.people-title {
  font: var(--text-heading);
  margin: 4px 0 6px;
}

.people-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

@media (min-width: 768px) {
  .people-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
  }
}

.people-card {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
  box-shadow: var(--shadow-border);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.people-card-head {
  display: flex;
  align-items: center;
  gap: 10px;
}

.people-card-id {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.people-card-id .name {
  font-weight: 600;
  font-size: 14.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.people-level {
  font: var(--text-meta);
  color: var(--text-hint);
}

.people-hint {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-hint);
  margin-top: 4px;
}

.people-level-select {
  width: auto;
  flex: none;
  padding: 4px 8px;
}

.comment-edit {
  position: relative;
  border: 0;
  background: none;
  color: var(--hint);
  font: inherit;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}

.comment-edit-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 6px;
}

.mention {
  color: var(--accent-ink);
  font-weight: 600;
}

/* --- Реакции на комментарии --- */

.reaction-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
}

.reaction {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  /* 32px — та же норма для целей в ряду, что у .check-del:
     пилюли стоят плотно, и невидимая накладка перехватывала бы соседей. */
  min-height: 32px;
  padding: 2px 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--bg);
  color: var(--text);
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}

.reaction.mine {
  background: var(--btn-bg);
  border-color: var(--btn-bg);
  color: var(--btn-text);
}

/* Полупрозрачная, пока к комментарию не притронулись: иначе под каждой
   строкой обсуждения висит лишний значок. */
.reaction-add {
  min-height: 32px;
  padding: 2px 9px;
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--text-hint);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  /* Полностью прячем, а не приглушаем: приглушённая кнопка давала с фоном
     2:1 — ниже нормы для управляющего элемента, — и всё равно висела под
     каждой строкой обсуждения. */
  opacity: 0;
  transition: opacity 120ms ease;
}

.comment-row:hover .reaction-add,
.reaction-add.open,
.reaction-add:focus-visible {
  opacity: 1;
}

/* На тач-экране наведения нет — там кнопка видна всегда */
@media (hover: none) {
  .reaction-add {
    opacity: 1;
  }
}

.reaction-palette {
  display: inline-flex;
  gap: 4px;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--border-soft);
}

.reaction-choice {
  border: 0;
  background: none;
  font: inherit;
  font-size: 17px;
  line-height: 1;
  /* Главный способ поставить реакцию — у него и должна быть зона побольше */
  min-width: 32px;
  min-height: 32px;
  padding: 4px 6px;
  border-radius: var(--radius-pill);
  cursor: pointer;
}

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

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

.attach-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* Подсказка о лимитах и Диске — строкой под плитками, на всю ширину ряда */
.attach-hint {
  flex: 1 1 100%;
  font-size: 11px;
  line-height: 1.45;
  color: var(--text-hint);
}

/* Ширина по плитке: подпись под ней обязана обрезаться, а не растягивать ряд */
.attach-tile-wrap {
  position: relative;
  width: 52px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.attach-tile {
  width: 52px;
  height: 52px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  box-shadow: inset 0 0 0 1px var(--border-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  font-size: 22px;
  cursor: pointer;
}

.attach-tile:disabled {
  cursor: default;
}

.attach-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.attach-tile.uploading {
  opacity: 0.6;
}

.attach-tile.failed {
  box-shadow: inset 0 0 0 1px var(--danger);
  opacity: 1;
}

.attach-name {
  font-size: 11.5px;
  line-height: 1.2;
  color: var(--text-hint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Крестик на самой плитке: они лежат плотным рядом, и невидимая накладка
   в 44px перехватывала бы соседние плитки (см. Фазу 6). */
.attach-del {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 0;
  background: var(--text);
  color: var(--surface);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.attach-add {
  width: 52px;
  height: 52px;
  flex: none;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  background: none;
  color: var(--text-hint);
  font: inherit;
  font-size: 20px;
  cursor: pointer;
}

/* --- Архив --- */

.archive-list {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.archive-month-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font: var(--text-meta);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  /* Не --text-hint: у него на этом фоне ровно 4.50:1, без запаса, а это
     12.5px капсом с разрядкой — первый же сдвиг палитры сломал бы. */
  color: var(--n-700);
  /* Липкий: пролистывая год назад, легко потерять, какой месяц смотришь */
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg);
  padding: 6px 0;
}

.archive-month {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.archive-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface);
  box-shadow: var(--shadow-border);
  border-radius: var(--radius);
  padding: 12px 14px;
  cursor: pointer;
}

.archive-date {
  flex: none;
  font: var(--text-micro);
  color: var(--text-hint);
  font-variant-numeric: tabular-nums;
}

.archive-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: flex-start;
}

.archive-row-title {
  font: var(--text-body-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}

.archive-hint {
  border: 0;
  background: none;
  color: var(--accent-ink);
  font: var(--text-meta);
  cursor: pointer;
  padding: 10px 4px;
  text-align: left;
  align-self: flex-start;
}

/* Архивная задача: блок «принята и уехала» с кнопкой возврата (макет v4) */
.view-archived {
  background: var(--bg);
  border-radius: var(--radius-md);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
/* display:flex объявлен позже общего .hidden{display:none} и победил бы его */
.view-archived.hidden {
  display: none;
}

.view-archived-text {
  font-size: 13.5px;
}

/* Пунктирная кнопка на всю ширину — как в макете детали */
#viewAddAssignee {
  width: 100%;
}

/* --- Приоритет --- */

/* Метка приоритета (макет v4): ▲/▲▲ + подпись. Ink-цвета, не заливочные:
   заливка как текст даёт 2-3:1 в светлой теме (см. комментарий у токенов). */
.priority-mark {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex: none;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: -0.5px;
}

.priority-mark .priority-mark-label {
  letter-spacing: 0;
}

.priority-mark.urgent {
  color: var(--danger-ink);
}

.priority-mark.important {
  color: var(--stage-review-ink);
}

/* Верхний ряд карточки: тег проекта слева, метка приоритета справа */
.card-top {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}

.card-top-spacer {
  flex: 1;
}

/* --- Корзина --- */

.trash-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Корзина теперь страница, а не шторка: на странице --bg — это фон body,
   и строки сливались бы с ним. Поверхность как у карточек. */
.trash-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
  box-shadow: var(--shadow-border);
  border-radius: var(--radius);
  padding: 14px;
}

.trash-row-main {
  flex: 1;
  min-width: 0;
}

.trash-row-title {
  font: var(--text-body-strong);
  color: var(--text-hint);
  text-decoration: line-through;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.trash-row-meta {
  font-size: 11.5px;
  color: var(--hint);
  margin-top: 2px;
}

/* --- Комментарии к задаче --- */

.comments-block {
  border-top: 1px solid var(--border-soft);
  padding-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Общий вид заголовка секции в панели задачи: капс слева, счётчик справа */
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.section-head.hidden { display: none; }

.section-title {
  font: var(--text-meta);
  font-weight: 700;
  color: var(--hint);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.section-count {
  font: var(--text-meta);
  color: var(--hint);
  font-variant-numeric: tabular-nums;
}

.view-section {
  border-top: 1px solid var(--border-soft);
  padding-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* .hidden объявлен раньше — без компаунда display:flex победил бы */
.view-section.hidden { display: none; }

.comments-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.comment-row {
  display: flex;
  gap: 8px;
  align-items: flex-start;
}

.comment-body {
  flex: 1;
  min-width: 0;
}

.comment-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
}

.comment-author {
  font-weight: 700;
}

.comment-time {
  color: var(--hint);
}

.comment-del {
  position: relative;
  margin-left: auto;
  border: 0;
  background: none;
  color: var(--hint);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
}
/* Вширь накладке расти можно (слева только имя и время), а ввысь нельзя:
   строки комментариев разделяет 10px, и квадрат 44px залез бы в соседний
   комментарий и в первую строку своего собственного текста. */
.comment-del::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 26px;
  transform: translate(-50%, -50%);
}

.comment-text {
  font-size: 13.5px;
  white-space: pre-wrap;
  overflow-wrap: break-word;
  margin-top: 2px;
}

.comment-form {
  display: flex;
  gap: 8px;
  align-items: flex-end;
}

.comment-form textarea {
  flex: 1;
  resize: none;
}

.comment-form .btn {
  flex: none;
  padding: 10px 14px;
}

/* --- Чек-лист задачи --- */

.checklist-block {
  border-top: 1px solid var(--border-soft);
  padding-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.checklist-items {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.check-item {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
}

.check-box {
  flex: none;
  width: 18px;
  height: 18px;
  border: 1px solid var(--border-strong);
  border-radius: 5px;
}

.check-item.done .check-box {
  background: var(--stage-done);
  border-color: var(--stage-done);
}

.check-item.done .check-box::after {
  content: '✓';
  display: block;
  color: #fff;
  font-size: 13px;
  line-height: 18px;
  text-align: center;
}

.check-text {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  overflow-wrap: break-word;
}

.check-item.done .check-text {
  color: var(--hint);
  text-decoration: line-through;
}

/* Зона нажатия — сама кнопка, а не ::after-накладка как у .comment-del:
   там иконка одна в строке, здесь их две рядом с зазором 8px, и накладка
   любого разумного размера перекрыла бы соседа — тап в промежуток между ✎
   и × попадал бы на удаление (кнопка идёт позже в DOM и оказывается
   сверху). Поэтому растёт сама кнопка: 32px — норма для целей в ряду. */
.check-edit,
.check-del {
  flex: none;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  color: var(--hint);
  font: inherit;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.check-edit-input {
  flex: 1;
}

.checklist-form {
  display: flex;
  gap: 8px;
}
.checklist-form.hidden { display: none; }

.checklist-form input {
  flex: 1;
}

.checklist-form .btn {
  flex: none;
  padding: 10px 14px;
}

/* --- Фильтр по проекту --- */

.project-filter-row {
  padding: 0 16px 10px;
  display: flex;
  flex-wrap: wrap; /* на 320px три контрола в одну строку не встают */
  gap: 8px;
}

.project-filter-row input[type='search'] {
  flex: 1 1 100%;
  border: 0;
  background: var(--card);
  border-radius: var(--radius-md);
  padding: 9px 12px;
}

.project-filter-row select {
  flex: 1 1 40%;
  width: 100%;
  border: 0;
  background: var(--card);
  color: var(--text);
  border-radius: var(--radius-md);
  padding: 9px 12px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
}

/* --- Чипы выбранных исполнителей (в шторке задачи) --- */

.assignee-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.assignee-badges.hidden { display: none; }

.assignee-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  border: 1px solid color-mix(in srgb, var(--accent-ink) 45%, transparent);
  background: color-mix(in srgb, var(--accent-ink) 12%, transparent);
  color: var(--text);
  font-size: 12px;
  font-weight: 600;
  padding: 4px 6px 4px 9px;
  border-radius: 999px;
}

.chip-remove {
  position: relative;
  border: 0;
  background: none;
  color: var(--hint);
  font-size: 14px;
  line-height: 1;
  padding: 2px;
  cursor: pointer;
}
/* Видимая иконка крестика маленькая — расширяем зону нажатия до ~28px,
   не увеличивая сам чип визуально. Не берём полные 44px — чипы стоят
   плотно (gap 6px), риск задеть соседний чип с коротким именем. */
.chip-remove::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 28px;
  height: 28px;
  transform: translate(-50%, -50%);
}

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

/* Плашка готовности в «Проверке»: янтарная, пока готовы не все */
.ready-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  align-self: flex-start;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--stage-review-ink);
  background: color-mix(in oklch, var(--stage-review) 16%, transparent);
  padding: 2px 8px;
  border-radius: var(--radius-pill);
}

.ready-pill.all {
  color: var(--stage-done-ink);
  background: color-mix(in oklch, var(--stage-done) 12%, transparent);
}

/* Прогресс чек-листа: «☑ 2/5» + мини-полоска */
.check-progress {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--hint);
}

/* Одна полоска на всё приложение: чек-лист карточки, прогресс проекта в
   дэшборде и на экране «Проекты». Раньше это были три копии с разным фоном. */
.progress {
  height: 6px;
  border-radius: 3px;
  background: var(--surface-sunken);
  overflow: hidden;
}

/* Дорожка отличается от подложки на 1.2:1 — при нулевом прогрессе полоски
   просто не видно. У .mini на 4px высоты обводка съела бы половину. */
.progress:not(.mini) {
  box-shadow: inset 0 0 0 1px var(--border-soft);
}

.progress > span {
  display: block;
  height: 100%;
  background: var(--stage-done);
}

/* Вариант в мета-строке карточки: полоска стоит в ряд с текстом */
.progress.mini {
  width: 34px;
  height: 4px;
  border-radius: 2px;
}

/* Инлайн-кнопки действий внизу карточки */
.card-actions {
  display: flex;
  gap: 6px;
  padding-top: 2px;
  /* Иначе строка растягивается на всю ширину карточки, и справа от кнопок
     появляется полоса, где тап не открывает задачу (data-stop-card). */
  align-self: flex-start;
}

/* --- Дэшборд --- */

.dash-section {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
  box-shadow: var(--shadow-border);
  padding: 16px;
}

#dashWidgets {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* display по ID сильнее, чем .hidden по классу: без этой строки спрятанные
   замком виджеты продолжат занимать место. */
#dashWidgets.hidden {
  display: none;
}

@media (min-width: 768px) {
  #dashWidgets {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
    gap: 14px;
    align-items: start;
  }

  /* График — на всю ширину сетки (макет v4). На мобильном #dashWidgets —
     flex-колонка, и правило просто не действует. */
  .dash-chart {
    grid-column: 1 / -1;
  }
}

.dash-lock {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow-border);
  padding: 22px 16px;
  text-align: center;
  font: var(--text-body);
  color: var(--text-hint);
}

/* Ряд управления: период слева, выгрузка справа (макет v4) */
.dash-controls {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap; /* на узком экране кнопка уходит под переключатель */
  margin-bottom: 10px;
}

/* display:flex объявлен позже общего .hidden{display:none} и победил бы его
   (ряд прячется замком дэшборда) */
.dash-controls.hidden {
  display: none;
}

.dash-export {
  margin-left: auto;
  white-space: nowrap;
}

.export-hint {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-hint);
  margin-bottom: 10px;
}

/* Шапка графика: заголовок периода слева, итог с подписью справа */
.dash-chart-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
}

.dash-chart-head .dash-heading {
  margin-bottom: 0;
}

.dash-chart-spacer {
  flex: 1;
}

/* Сравнение с прошлым периодом и средний срок — строкой под шапкой */
.dash-chart-sub {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
  margin: 2px 0 10px;
}

.dash-chart-sub .dash-avg {
  margin: 0;
}

.dash-total-n {
  font: var(--text-title);
  font-variant-numeric: tabular-nums;
}

.dash-total-note {
  font: var(--text-meta);
  color: var(--text-hint);
}

.dash-delta {
  font: var(--text-meta);
  font-weight: 700;
  color: var(--text-hint);
  font-variant-numeric: tabular-nums;
}

.dash-delta.up {
  color: var(--stage-done-ink);
}

.dash-delta.down {
  color: var(--danger-ink);
}

.dash-avg {
  font: var(--text-meta);
  color: var(--text-hint);
  margin: -4px 0 8px;
}

.dash-avg:empty {
  display: none;
}

.dash-heading {
  font: var(--text-meta);
  font-weight: 700;
  color: var(--hint);
  text-transform: uppercase;
  letter-spacing: 0.02em;
  margin-bottom: 6px;
}

/* :not — чтобы правило строки не перебивало подпись «здесь пусто»:
   .dash-list > div специфичнее одиночного .empty-inline. */
.dash-list > div:not(.empty-inline) {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border-soft);
  font-size: 13.5px;
}

.dash-list > div:last-child {
  border-bottom: 0;
}

.dash-counts {
  color: var(--hint);
  font-size: 12.5px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.dash-list .title {
  font: var(--text-body-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  font: var(--text-micro);
  color: var(--text-hint);
  margin-bottom: 8px;
}

.dash-legend span {
  display: flex;
  align-items: center;
  gap: 4px;
}

.dash-legend i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex: none;
}

.dash-legend:empty {
  display: none;
}

/* Селектор с родителем, а не просто класс: общее правило .dash-list > div
   (padding, gap, разделитель) специфичнее одиночного класса и перебило бы его. */
.dash-list > .dash-workload-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 0;
  /* Полосы сами по себе разделяют строки — линейки между ними были бы шумом */
  border-bottom: 0;
}

.dash-workload-name {
  flex: none;
  width: 100px;
  font: var(--text-meta);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Соседние сегменты различаются почти только тоном (1.2-1.7:1) — при
   дальтонизме шов между ними пропадает. Светлая линия делает его яркостным. */
.dash-workload-bar i + i {
  box-shadow: -1px 0 0 var(--card);
}

.dash-workload-bar {
  flex: 1;
  display: flex;
  height: 8px;
  border-radius: 4px;
  overflow: hidden;
  background: var(--surface-sunken);
  /* Стадийные цвета светлые: у «Очереди» с дорожкой всего 2.1:1, и без обводки
     непонятно, где полоса кончается. Раскладку дублируют легенда и aria-label. */
  box-shadow: inset 0 0 0 1px var(--border-soft);
}

.dash-workload-total {
  flex: none;
  min-width: 16px;
  text-align: right;
  font: var(--text-micro);
  color: var(--text-hint);
  font-variant-numeric: tabular-nums;
}

.dash-list .due {
  font-size: 12px;
  white-space: nowrap;
  color: var(--danger);
  font-weight: 600;
}

.dash-project-row {
  padding: 7px 0;
}

.dash-project-top {
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  margin-bottom: 4px;
}

.dash-project-top .name {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-project-top .percent {
  color: var(--hint);
  white-space: nowrap;
  margin-left: 8px;
  font-variant-numeric: tabular-nums;
}

.dash-velocity {
  display: flex;
  align-items: flex-end;
  gap: 4px;
  /* Столбиков теперь до тринадцати: на узком экране подписи «н19» слипались
     бы, поэтому даём им минимум ширины и прокрутку. */
  overflow-x: auto;
  /* 60px было при одной подписи; теперь их две — иначе столбики сожмутся */
  height: 76px;
}

.dash-velocity-col {
  flex: 1;
  min-width: 18px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  height: 100%;
}

/* Столбик живёт в собственной дорожке: без неё height в процентах считался от
   всей колонки вместе с двумя подписями, и всё выше ~60% максимума упиралось в
   один потолок — неделя с 6 закрытыми выглядела как неделя с 10. */
.dash-velocity-track {
  position: relative;
  flex: 1;
  width: 100%;
  min-height: 0;
}

.dash-velocity-bar {
  position: absolute;
  bottom: 0;
  width: 100%;
  background: var(--btn);
  border-radius: 3px 3px 0 0;
  min-height: 2px;
}

.dash-free-n {
  font: var(--text-meta);
  font-weight: 700;
  color: var(--accent-ink);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* Несрочный срок свободной задачи: тот же ряд, но не акцент — счётчик один */
.dash-free-due {
  font: var(--text-meta);
  color: var(--hint);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.dash-velocity-n,
.dash-velocity-week {
  font: var(--text-micro);
  font-size: 9.5px;
  color: var(--text-hint);
  font-variant-numeric: tabular-nums;
}

/* --- Мастер создания задачи (2 шага) --- */

.step-1,
.step-2 {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

#sheet.wizard-mode .step-1,
#sheet.wizard-mode .step-2 {
  display: none;
}
#sheet.wizard-mode[data-active-step="1"] .step-1,
#sheet.wizard-mode[data-active-step="2"] .step-2 {
  display: flex;
  /* Одинаковая высота на обоих шагах — иначе шторка визуально "прыгает"
     при переходе Далее/Назад, так как на шаге 2 полей меньше. */
  min-height: 240px;
}

@media (prefers-reduced-motion: no-preference) {
  #sheet.wizard-mode .step-1,
  #sheet.wizard-mode .step-2 {
    animation: stepIn 0.2s ease-out;
  }
  @keyframes stepIn {
    from { transform: translateX(16px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
  }
}

.step-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin: 2px 0 4px;
}
.step-dots.hidden { display: none; }

.step-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--hint);
  opacity: 0.3;
}

.step-dot.active {
  opacity: 1;
  background: var(--btn);
}

.btn.secondary {
  flex: 1;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--border-strong);
}

.btn-outline {
  border: 1px dashed var(--border-strong);
  background: transparent;
  color: var(--hint);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  cursor: pointer;
  margin-top: 6px;
  width: fit-content;
}

/* --- Модалка выбора участника --- */

.picker-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 50vh;
  overflow-y: auto;
}

.picker-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 9px 4px;
  border-bottom: 1px solid var(--border-soft);
  cursor: pointer;
}

.picker-row-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.picker-row-name {
  font-size: 14.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.picker-row-level {
  font-size: 11.5px;
  color: var(--hint);
}

#assigneePickerDone {
  font-variant-numeric: tabular-nums;
}

.picker-check {
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
}

.picker-row.checked .picker-check {
  background: var(--btn);
  border-color: var(--btn);
}

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

.stage-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 16px 8px;
}

.pager-arrow {
  border: 0;
  background: transparent;
  color: var(--hint);
  font-size: 20px;
  padding: 4px 10px;
  cursor: pointer;
}

.pager-arrow:disabled {
  opacity: 0.3;
  cursor: default;
}

.pager-label {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 15px;
  font-weight: 600;
}

.pager-stage-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--hint);
}

.pager-count {
  font-size: 12.5px;
  color: var(--hint);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.pager-dots {
  display: flex;
  justify-content: center;
  /* 14px, а не 10: накладка 24px выступает на 9px от обычной точки и на 4px
     от активной (она шире) — при зазоре 10px их зоны нажатия перекрывались,
     и тап в трёхпиксельную полоску выбирал соседнюю стадию. */
  gap: 14px;
  padding-bottom: 10px;
}

.pager-nav-dot {
  position: relative;
  /* Сброс кнопочных умолчаний: точка была span, пока не понадобилась
     клавиатура и роль */
  border: 0;
  padding: 0;
  /* Префикс ради WKWebView до Safari 15.4 — проект ещё живёт на старых iOS */
  -webkit-appearance: none;
  appearance: none;
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 3px;
  /* --n-300 давал с фоном 1.7:1 в светлой и 1.9:1 в тёмной, а точка
     кликабельна — значит нужна видимая граница состояния. */
  background: var(--border-strong);
  cursor: pointer;
  transition: width 150ms ease;
}

/* Сама точка 6px — самая мелкая цель в приложении. Накладка 24x32 умещается
   в зазор между точками (см. .pager-dots), поэтому соседей не перехватывает. */
.pager-nav-dot::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 24px;
  height: 32px;
  transform: translate(-50%, -50%);
}

/* Кольцо на 6px точке слилось бы с ней самой — отодвигаем на зазор */
.pager-nav-dot:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

/* У активной точки заливка стадийная, и на «В работе» кольцо совпало бы с
   ней по цвету (1.1:1 в тёмной теме) — та же причина, что у .seg-btn.active */
.pager-nav-dot.active:focus-visible {
  outline-color: var(--text);
}

.pager-nav-dot.active {
  width: 16px;
  background: var(--pager-color, var(--btn));
}

/* --- Нижняя навигация --- */

.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  background: var(--card);
  border-top: 1px solid var(--border-soft);
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 15;
}

.nav-tab {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  border: 0;
  background: none;
  padding: 9px 0 8px;
  cursor: pointer;
  color: var(--hint);
}

.nav-tab.active {
  color: var(--accent-ink);
}

.nav-icon {
  font-size: 19px;
}

.nav-label {
  font: var(--text-micro);
  font-weight: 600;
}

.nav-tab.active .nav-label {
  font-weight: 700;
}

/* --- Полноэкранные страницы (Люди / Дэшборд) --- */

.page {
  padding: 12px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.page.hidden {
  display: none;
}

/* --- Аватар --- */

.avatar {
  position: relative;
  flex: none;
  border-radius: 50%;
  color: #fff;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--card);
}

/* Растянута на весь кружок поверх инициалов: те остаются под ней и
   проступают, если картинка не загрузилась и удалила себя. */
.avatar-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

/* Отметка «я свою часть сделал» прямо на аватаре */
.avatar-ready {
  position: absolute;
  right: -2px;
  bottom: -2px;
  /* В стопке аватары наезжают друг на друга, и следующий
     аватар закрывал бы галочку предыдущего: z-index поднимает её над
     соседями — иначе готовность видна только у последнего в стопке. */
  z-index: 1;
  border-radius: 50%;
  background: var(--success-bg);
  color: #fff;
  font-weight: 700;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1.5px solid var(--surface);
}

.avatar-stack {
  display: flex;
}

.avatar-stack .avatar:not(:first-child) {
  /* Треть диаметра: при 24px это было 8px, при нынешних 30px — 10px. Меньше —
     и стопка читается как ряд отдельных кружков, а не как группа. */
  margin-left: -10px;
}

.avatar-extra {
  margin-left: -10px;
  border-radius: 50%;
  background: var(--n-300);
  color: var(--text);
  font-size: 10px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--card);
}

/* --- Тег проекта на карточке --- */

.project-tag {
  display: flex;
  align-items: center;
  gap: 5px;
  font: var(--text-micro);
  color: var(--hint);
  margin-bottom: 4px;
}

/* В ряду .card-top ритм держит gap ряда: собственный отступ тега ломал бы
   выравнивание с меткой приоритета (в шторке просмотра он по-прежнему нужен) */
.card-top .project-tag {
  margin-bottom: 0;
}

.project-tag-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: none;
}

/* --- Ссылка «Назад» из редактирования к просмотру --- */

/* Кнопка — ссылка без рамки; здесь
   кнопка — прямой потомок .sheet-body (flex-column, align-items не
   переопределён => stretch по умолчанию), без этого правила растянулась
   бы на всю ширину шторки вместо маленькой ссылки у грипа. */
#editBackBtn {
  align-self: flex-start;
  border: 0;
  background: none;
  color: var(--accent-ink);
  font: inherit;
  font-size: 11.5px;
  font-weight: 700;
  cursor: pointer;
  padding: 0;
}

/* --- Просмотр задачи (детали) --- */

.view-top {
  display: flex;
  align-items: center;
  gap: 8px;
}

.view-top-spacer {
  flex: 1;
}

/* Кнопок в шапке две (✎ и ×), и невидимые 44px-накладки перекрывали бы
   друг друга — вместо накладки зона нажатия настоящая: 44×44 сам бокс. */
.view-close {
  flex: none;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: none;
  color: var(--hint);
  font: inherit;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 0;
}

.view-title {
  font-size: 19px;
  font-weight: 800;
  line-height: 1.3;
  overflow-wrap: break-word;
}

.claim-block {
  background: var(--bg);
  border-radius: var(--radius-md);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.claim-block.hidden { display: none; }

.claim-text {
  font-size: 13.5px;
}

.field-hint {
  font-size: 12.5px;
  color: var(--hint);
  font-weight: 400;
  margin-top: 6px;
}

.view-status-pick {
  display: flex;
  gap: 6px;
}
/* display:flex объявлен позже общего .hidden{display:none} и победил бы его
   (у архивной задачи степпер заменяется блоком «Вернуть на доску») */
.view-status-pick.hidden {
  display: none;
}

.view-status-btn {
  flex: 1;
  border: 0;
  background: var(--bg);
  color: var(--hint);
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  padding: 9px 4px;
  border-radius: 9px;
  cursor: pointer;
}

/* Как у .status-btn.active: белая подпись на стадийной заливке давала
   1.9–3.0:1 (в тёмной теме хуже всего) — активный шаг помечаем кромкой. */
.view-status-btn.active {
  color: var(--text);
  border-top: 3px solid var(--sb-color);
  padding-top: 6px;
}

.view-due {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--hint);
}

.view-due.today { color: var(--stage-review); }
.view-due.overdue { color: var(--danger); }

.view-desc {
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--text);
  white-space: pre-wrap;
}

.assignee-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.assignee-row {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--bg);
  border-radius: var(--radius-md);
  padding: 7px 10px;
}

.assignee-name {
  flex: 1;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.assignee-state {
  flex: none;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--hint);
}

.assignee-state.ready {
  color: var(--stage-done-ink);
}

/* Контейнер остаётся в DOM всегда: пустым он съедал бы gap секции */
#viewReadyAction:empty {
  display: none;
}

.ready-action {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: 8px;
}

.ready-action .btn {
  width: 100%;
}

.ready-note {
  font-size: 11.5px;
  color: var(--hint);
  text-align: center;
}

/* --- Desktop-раскладка (≥768px) --- */

.topbar-nav {
  display: none;
  gap: 4px;
}

.topbar-nav-tab {
  border: 0;
  background: none;
  color: var(--hint);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  padding: 8px 14px;
  border-radius: var(--radius-md);
  cursor: pointer;
}

.topbar-nav-tab.active {
  background: var(--bg);
  color: var(--text);
}

.topbar-nav-tab.hidden {
  display: none;
}

/* Дропдаун «Ещё» (desktop): позиционируется под своей кнопкой — left ставит
   JS от кнопки, потому что перед ней вордмарк и вкладки переменной ширины */
.more-dropdown {
  position: absolute;
  top: calc(100% - 4px);
  left: 216px;
  z-index: 30;
  background: var(--surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md);
  padding: 5px;
  min-width: 190px;
  box-shadow: 0 8px 24px oklch(20% 0.02 260 / 0.16);
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.more-dropdown.hidden {
  display: none;
}

.more-dropdown-item {
  display: flex;
  align-items: center;
  gap: 9px;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  padding: 9px 10px;
  border-radius: 8px;
  cursor: pointer;
  text-align: left;
}

.more-dropdown-item.active {
  background: var(--bg);
}

.more-dropdown-item .more-link-label {
  flex: 1;
}

#addBtnDesktop {
  display: none;
}

#topbarAvatar {
  display: none;
}

.desktop-columns {
  display: none;
}

/* --- Узкая колонка страниц «Проекты» и «Корзина» --- */

.narrow-col {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 640px;
  width: 100%;
}
/* display:flex объявлен позже общего .hidden{display:none} и побеждал бы его —
   а контент Корзины/Повторов прячется именно классом (замок для участника) */
.narrow-col.hidden {
  display: none;
}

/* --- Экран «Проекты» --- */

.project-create {
  display: flex;
  gap: 8px;
}
/* Как и .lbl.hidden: .hidden объявлен раньше, при равной специфичности
   победил бы display:flex — и участник видел бы строку создания проекта. */
.project-create.hidden { display: none; }

.project-create input {
  flex: 1;
}

.project-create .btn {
  flex: none;
}

.projects-list,
.project-group {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.projects-list {
  gap: 18px;
}

.project-group-title {
  font: var(--text-micro);
  color: var(--text-hint);
  text-transform: uppercase;
}

/* Рельса свайпа: корзина лежит ПОД строкой, строка сдвигается влево и
   открывает её (стандартный жест iOS/Android). Класс .swiped ставит JS. */
.project-row-wrap {
  position: relative;
}

.project-row-delete {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 72px;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--danger);
  color: #fff;
  font-size: 20px;
  cursor: pointer;
}

/* На desktop свайпа нет — та же корзина маленькой кнопкой в ряду */
.project-del-desktop {
  display: none;
}

@media (min-width: 768px) {
  .project-del-desktop {
    display: inline-flex;
  }
}

/* display в @media объявлен позже общего .hidden{display:none} и при равной
   специфичности победил бы его — конвенция проекта, см. .lbl.hidden */
.project-del-desktop.hidden {
  display: none;
}

.project-row {
  position: relative; /* поверх корзины, пока строка не сдвинута */
  background: var(--surface);
  border-radius: var(--radius-md);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08);
  box-shadow: var(--shadow-border);
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 9px;
  transition: transform 0.15s ease-out;
}

.project-row.swiped {
  transform: translateX(-72px); /* вровень с шириной корзины — без просвета */
}

/* Прозрачность — на содержимом, не на строке: полупрозрачная строка
   просвечивала бы красную корзину, лежащую под ней в рельсе свайпа */
.project-row.archived > * {
  opacity: 0.65;
}

.project-row-top {
  display: flex;
  align-items: center;
  gap: 8px;
}

.project-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
}

.project-name {
  flex: 1;
  min-width: 0;
  font: var(--text-body-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Компактная кнопка в строке (в макете — Button small variant="secondary").
   Базовый .btn.secondary тянется flex:1 под футер шторки — здесь не нужно. */
.btn.small {
  flex: none;
  padding: 8px 12px;
  font: var(--text-meta);
  font-size: 13px;
}

.project-progress-top {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-hint);
  margin-bottom: 4px;
  font-variant-numeric: tabular-nums;
}

/* --- Экран «Корзина» --- */

.trash-hint {
  font-size: 12.5px;
  color: var(--text-hint);
}

/* --- Экран «Повторы» (макет v4) --- */

.rec-row {
  background: var(--card);
  border-radius: var(--radius);
  box-shadow: var(--shadow-border);
  padding: 14px;
  display: flex;
  align-items: center;
  gap: 12px;
}

.rec-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.rec-row-title {
  font: var(--text-body-strong);
  overflow-wrap: break-word;
}

.rec-row-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  color: var(--text-hint);
  flex-wrap: wrap;
}

.rec-schedule {
  font-weight: 700;
  color: var(--accent-ink);
}

.rec-assignee {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.rec-day-note {
  font-size: 11.5px;
  color: var(--text-hint);
}

/* --- Шторка «Ещё» --- */

.more-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.more-link {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
  border: 0;
  background: var(--bg);
  border-radius: var(--radius-md);
  padding: 0 14px;
  font: var(--text-body-strong);
  color: var(--text);
  cursor: pointer;
  text-align: left;
}

.more-link-icon {
  font-size: 20px;
}

.more-link-label {
  flex: 1;
}

.more-link-count {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-hint);
  font-variant-numeric: tabular-nums;
}

.more-link-chevron {
  color: var(--text-hint);
}

.more-profile {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-top: 6px;
}

.more-profile-name {
  font: var(--text-body-strong);
}

.more-profile-level {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-hint);
}

@media (min-width: 768px) {
  .stage-pager,
  .pager-dots,
  .list,
  .bottom-nav,
  .fab {
    display: none;
  }

  /* На desktop в шапке постоянный вордмарк, название страницы не нужно */
  .wordmark {
    display: block;
  }

  /* ID-селекторы ниже сильнее .hidden (0,1,0), поэтому скрытие через класс
     без этих компаундов не работало: кнопка «+ Задача» оставалась на всех
     страницах, а сетка дэшборда — под ними. */
  #addBtnDesktop.hidden,
  #dashboardPage.hidden {
    display: none;
  }

  .narrow-col {
    margin: 0 auto;
  }

  .topbar .title {
    display: none;
  }

  /* Вкладок шесть — при нехватке ширины ряд скроллится, а не переносится */
  .topbar-nav {
    overflow-x: auto;
    flex-shrink: 1;
    min-width: 0;
  }

  .topbar-nav-tab {
    flex: none;
    white-space: nowrap;
  }

  .topbar {
    justify-content: flex-start;
    gap: 20px;
  }

  .topbar-nav {
    display: flex;
  }

  .seg {
    margin-left: auto;
  }

  #addBtnDesktop {
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
  }

  #topbarAvatar {
    display: inline-flex;
  }

  .desktop-columns {
    display: flex;
    gap: 16px;
    padding: 20px;
    overflow-x: auto;
    align-items: flex-start;
  }

  .desktop-col {
    flex: none;
    width: 288px; /* макет v4: фиксированные 288px */
    display: flex;
    flex-direction: column;
    gap: 10px;
    /* Скругление под подсветку dragover — без него box-shadow рисует
       прямые углы поверх скруглённых карточек */
    border-radius: var(--radius);
  }

  .card[draggable] {
    cursor: grab;
  }

  .card.dragging {
    opacity: 0.5;
  }

  .desktop-col.dragover {
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-ink) 55%, transparent);
    background: color-mix(in srgb, var(--accent-ink) 8%, transparent);
  }

  .desktop-col-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 2px;
  }

  .desktop-col-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex: none;
  }

  .desktop-col-label {
    font-size: 14px;
    font-weight: 700;
  }

  .desktop-col-count {
    font-size: 12.5px;
    color: var(--hint);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  .desktop-col-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
  }

  .sheet-body {
    left: auto;
    top: 0;
    width: 440px; /* макет v4: SidePanel 440px */
    max-width: 92vw;
    max-height: none;
    border-radius: 0;
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.12);
    /* Тень слева — вместо анимации "наезжания снизу", которая уместна
       только для шторки на мобильном. */
    animation: none;
  }

  .sheet-grip {
    display: none;
  }
}
