/* Компоненты и экраны. Порядок: оболочка → примитивы → экраны. */

/* ── Оболочка ─────────────────────────────────────────────────── */

.app {
  position: relative;
  width: 100%;
  max-width: var(--column);
  min-height: 100dvh;
  margin-inline: auto;
  background: var(--bg);
  isolation: isolate;
}

@media (min-width: 481px) {
  .app {
    box-shadow: 0 0 0 1px var(--line), 0 12px 48px rgba(43, 48, 42, 0.1);
  }
}

/* Отступ сверху обязателен: на домашнем экране приложение запускается без
   адресной строки и с viewport-fit=cover страница уходит под часы и вырез.
   В браузере inset равен нулю, поэтому там ничего не меняется. */
.appbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: var(--tap) 1fr var(--tap);
  align-items: center;
  min-height: calc(var(--appbar-h) + env(safe-area-inset-top));
  padding: calc(6px + env(safe-area-inset-top)) var(--pad) 6px;
  background: var(--bg);
}

.appbar__title {
  min-width: 0;
  text-align: center;
}

.appbar__title h1 {
  font-size: var(--t-20);
  font-weight: 700;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.appbar__subtitle {
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--t-12);
}

/* Кнопки шапки — 44px тач-цель, иконка визуально меньше. */
.iconbtn {
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  border-radius: var(--radius-btn);
  color: var(--ink);
}

.iconbtn:active {
  background: var(--card-2);
}

.iconbtn--end {
  justify-self: end;
}

.iconbtn__dot {
  position: absolute;
  margin: -14px 0 0 14px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--red);
  box-shadow: 0 0 0 2px var(--bg);
}

.view {
  padding: 4px var(--pad) calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 24px);
}

.view--flush {
  padding-inline: 0;
}

/* Экран без вкладок: место под нижнюю панель резервировать не надо. */
.view--bare {
  padding-bottom: 0;
}

.tabbar {
  position: fixed;
  bottom: 0;
  left: 50%;
  z-index: 30;
  display: flex;
  width: min(100%, var(--column));
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid var(--line);
  background: var(--card);
  transform: translateX(-50%);
}

/* До входа вкладок нет: полоса без содержимого только отъедала бы низ экрана. */
.tabbar:empty {
  display: none;
}

/* Кнопка «+» приподнята над панелью. Панель не обрезает её по верху, потому
   что overflow не задан, — но запас сверху нужен, иначе кружок налезал бы
   на содержимое экрана. */
.tabbar__item--fab {
  position: relative;
  color: var(--green-dk);
  font-weight: 600;
}

.fab {
  display: grid;
  width: 46px;
  height: 46px;
  margin-top: -20px;
  border: 3px solid var(--bg);
  border-radius: 50%;
  background: var(--green-dk);
  color: var(--on-green);
  place-items: center;
  transition: background var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.fab svg {
  width: 22px;
  height: 22px;
  stroke-width: 2.4;
}

.tabbar__item--fab:active .fab {
  background: var(--green-press);
  transform: scale(0.94);
}

.tabbar__item {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 3px;
  align-items: center;
  justify-content: center;
  min-height: var(--tabbar-h);
  padding: 6px 2px;
  color: var(--muted);
  font-size: 11px;
  text-decoration: none;
}

.tabbar__item[aria-current='page'] {
  color: var(--green-dk);
  font-weight: 700;
}

.tabbar__item svg {
  width: 22px;
  height: 22px;
}

/* ── Примитивы ────────────────────────────────────────────────── */

.section {
  margin-top: var(--section);
}

/* Первая секция экрана: полный отступ оторвал бы её от шапки. */
.section--first {
  margin-top: 8px;
}

.section__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
  padding-inline: 2px;
}

.section__title {
  font-size: var(--t-16);
  font-weight: 700;
}

.section__aside {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  color: var(--muted);
  font-size: var(--t-13);
}

/* Иконка в подписи секции («Все ›», «+ Добавить») — маленькая и в строке, а не
   блоком во всю ширину: глобальное svg{display:block} без размера растянуло бы её. */
.section__aside svg {
  width: 15px;
  height: 15px;
  flex: none;
}

.card {
  position: relative;
  padding: var(--pad);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--card);
  box-shadow: var(--shadow);
  overflow: hidden;
  /* Обязательно: без своего контекста наложения листья с z-index:-1 уходят в
     отрицательный слой .app и закрашиваются фоном самой карточки. Изоляция
     оставляет их внутри — над фоном, под содержимым. */
  isolation: isolate;
}

.card--flat {
  padding: 0;
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.btn {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  padding: 0 18px;
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  font-size: var(--t-15);
  font-weight: 700;
  transition: background var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.btn:active {
  transform: scale(0.985);
}

/* Фон здесь --green-dk, а не --green: белый текст на --green даёт 3.81:1 —
   значку хватило бы, надписи нет. Это та самая «провальная» пара с макета. */
.btn--primary {
  background: var(--green-dk);
  color: var(--on-green);
}

.btn--primary:hover {
  background: var(--green-press);
}

.btn--ghost {
  border-color: var(--line);
  background: var(--card);
  color: var(--ink);
}

.btn--ghost:hover {
  background: var(--card-2);
}

/* Приглушённая: стоит в форме и всего лишь ОТКРЫВАЕТ вопрос. Сплошной красный
   здесь кричал бы на человека, который просто правит план. */
.btn--danger {
  border-color: var(--line);
  background: var(--card);
  color: var(--red-ink);
}

/* Сплошная: стоит в подтверждении и действительно ДЕЛАЕТ. Это последняя кнопка
   перед необратимым, и она обязана выглядеть иначе, чем та, что задала вопрос. */
.btn--danger-fill {
  border-color: transparent;
  background: var(--red-btn);
  color: var(--on-red);
  font-weight: 700;
}

.btn--danger-fill:hover {
  background: var(--red-btn-press);
}

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

.btn svg {
  width: 18px;
  height: 18px;
}

/* Чипы-фильтры. Активный — зелёная заливка. */
.chips {
  display: flex;
  gap: 8px;
  margin: 4px 0 2px;
  padding: 2px var(--pad) 6px;
  margin-inline: calc(var(--pad) * -1);
  overflow-x: auto;
  scrollbar-width: none;
}

.chips::-webkit-scrollbar {
  display: none;
}

.chip {
  flex: none;
  min-height: 34px;
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--card);
  color: var(--muted);
  font-size: var(--t-13);
  font-weight: 600;
  white-space: nowrap;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.chip[aria-pressed='true'],
.chip[aria-selected='true'] {
  border-color: var(--green-dk);
  background: var(--green-dk);
  color: var(--on-green);
}

/* ── Переходы экранов и вкладок ────────────────────────────────────
   Смену вкладки, фильтра и экрана оборачивает document.startViewTransition
   в app.js. Здесь — только длительность и плавность, привязанные к тем же
   токенам, что и вся остальная анимация. Подсветку активной вкладки браузер
   сам «перевозит» на новую кнопку (общая view-transition-name из app.js),
   содержимое мягко сменяется кроссфейдом по умолчанию.

   Всё под prefers-reduced-motion: no-preference. При «меньше движения» переход
   в app.js вообще не запускается — но правила тоже молчат, чтобы поведение не
   зависело от того, дошло ли дело до вида-перехода. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-group(*) {
    animation-duration: var(--slow);
    animation-timing-function: var(--ease);
  }

  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: var(--slow);
    animation-timing-function: var(--ease);
  }

  /* «Обновить» в интеграциях: пока идёт проверка — стрелка крутится, и кнопка
     явно отвечает даже когда по итогу ничего не изменилось. */
  .dhead__btn.is-spinning svg {
    animation: spin360 0.7s linear infinite;
  }
}

@keyframes spin360 {
  to {
    transform: rotate(360deg);
  }
}

/* Бейдж-иконка слева в строке списка. */
.badge {
  display: grid;
  flex: none;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background: var(--card-2);
  color: var(--muted);
}

.badge svg {
  width: 17px;
  height: 17px;
}

.badge--fire {
  background: var(--red-soft);
  color: var(--red);
}

.badge--strategy {
  background: var(--green-soft);
  color: var(--green-dk);
}

.badge--others {
  background: var(--amber-soft);
  color: var(--on-amber-soft);
}

.badge--dust {
  background: var(--card-2);
  color: var(--muted);
}

.badge--tint {
  color: var(--on-green);
}

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

/* Метка квадранта / категории. */
/* Название категории задаёт человек — оно может быть любой длины. Тег держим
   в пределах колонки, лишнее уводим в многоточие. */
.tag {
  display: inline-flex;
  max-width: 100%;
  gap: 6px;
  align-items: center;
  height: 26px;
  padding: 0 10px;
  border-radius: var(--radius-pill);
  background: var(--card-2);
  color: var(--muted);
  font-size: var(--t-12);
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tag svg {
  width: 13px;
  height: 13px;
}

.tag--fire {
  background: var(--red-soft);
  color: var(--on-red-soft);
}

.tag--strategy {
  background: var(--green-soft);
  color: var(--green-dk);
}

.tag--others {
  background: var(--amber-soft);
  color: var(--on-amber-soft);
}

.tag--dust {
  background: var(--card-2);
  color: var(--muted);
}

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

/* ── Строки списка ────────────────────────────────────────────── */

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

.row {
  display: flex;
  gap: 12px;
  align-items: center;
  width: 100%;
  min-height: 60px;
  padding: 10px var(--pad);
  border-bottom: 1px solid var(--line);
  color: inherit;
  text-align: left;
  text-decoration: none;
  transition: background var(--fast) var(--ease);
}

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

.row:active {
  background: var(--card-2);
}

/* Строка целиком не кликабельна: ссылка ведёт в карточку,
   а чекбокс справа остаётся отдельной целью. */
.row__link {
  display: flex;
  flex: 1;
  gap: 12px;
  align-items: center;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

.row__body {
  flex: 1;
  min-width: 0;
}

/* display: block обязателен и не для красоты: это <span>, а на строчных
   элементах overflow и text-overflow не работают вовсе — браузер их молча
   игнорирует, и многоточия не будет, сколько свойств ни пиши. */
.row__title {
  display: block;
  overflow: hidden;
  font-size: var(--t-15);
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Подстрочник строки — ровно одна строка: длинное уезжает в многоточие, а не
   разносит карточку. display: block обязателен — это <span>, а на строчных
   overflow и text-overflow не работают. Обрезка отсчитывается от min-width: 0
   на .row__body. */
.row__sub {
  display: block;
  margin-top: 2px;
  overflow: hidden;
  color: var(--muted);
  font-size: var(--t-12);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Кроме тех мест, где в подстрочнике намеренно лежит проза, а не подпись. */
.row__sub--wrap {
  overflow: visible;
  text-overflow: clip;
  white-space: normal;
}

.row__sub--alert {
  color: var(--red-ink);
  font-weight: 600;
}

.row__end {
  display: flex;
  flex: none;
  gap: 8px;
  align-items: center;
  color: var(--muted);
  font-size: var(--t-13);
}

.row__chev {
  width: 18px;
  height: 18px;
  color: var(--muted);
}

.row--done .row__title {
  color: var(--muted);
  text-decoration: line-through;
}

/* Чекбокс: сам квадрат 22px, тач-цель вокруг — 44px. */
.check {
  display: grid;
  flex: none;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  margin-right: -10px;
  color: var(--green-dk);
}

.check__box {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1.5px solid var(--line);
  border-radius: 6px;
  background: var(--card);
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.check__box svg {
  width: 14px;
  height: 14px;
  color: var(--on-green);
  opacity: 0;
}

.check[aria-pressed='true'] .check__box {
  border-color: var(--green);
  background: var(--green);
}

.check[aria-pressed='true'] .check__box svg {
  opacity: 1;
}

.frog {
  display: grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  color: var(--line);
}

.frog svg {
  width: 20px;
  height: 20px;
}

.frog[aria-pressed='true'] {
  color: var(--amber-ink);
}

/* Группы задач. */
.group__head {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: var(--section) 2px 8px;
}

.group__name {
  font-size: var(--t-13);
  font-weight: 700;
}

.group__hint {
  color: var(--muted);
  font-size: var(--t-12);
}

.group__count {
  margin-left: auto;
  color: var(--muted);
  font-size: var(--t-12);
}

.group:first-child .group__head {
  margin-top: 4px;
}

/* ── Главная ──────────────────────────────────────────────────── */

.quads {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
}

.quad {
  display: flex;
  flex-direction: column;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  color: inherit;
  text-align: left;
  text-decoration: none;
  transition: transform var(--fast) var(--ease);
}

/* Тон отделяет важное от неважного — верхний ряд от нижнего. Это единственная
   ось, которую видно, не читая подписей. */
.quad--fire,
.quad--strategy {
  background: var(--green-soft);
}

.quad--others,
.quad--dust {
  background: var(--card-2);
}

.quad:active {
  transform: scale(0.98);
}

.quad__head {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-bottom: 10px;
}

.quad__icon {
  display: grid;
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 50%;
  background: var(--card);
  place-items: center;
}

.quad__icon svg {
  width: 17px;
  height: 17px;
}

.quad--fire .quad__icon {
  color: var(--red-ink);
}

.quad--strategy .quad__icon {
  color: var(--green-dk);
}

.quad--others .quad__icon {
  color: var(--amber-ink);
}

.quad--dust .quad__icon {
  color: var(--muted);
}

.quad__n {
  font-size: var(--t-28);
  font-weight: 700;
  line-height: 1;
}

.quad__axis {
  font-size: var(--t-12);
  font-weight: 600;
}

.quad__unit {
  margin-top: 2px;
  color: var(--muted);
  font-size: 11px;
}

/* ── Быстрый доступ ───────────────────────────────────────────── */

.quick {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.quick__item {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
  padding: 12px 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--card);
  color: var(--ink);
  font-size: var(--t-12);
  text-decoration: none;
  text-align: center;
}

.quick__ic {
  display: grid;
  width: 38px;
  height: 38px;
  border-radius: 12px;
  background: var(--card-2);
  color: var(--green-dk);
  place-items: center;
}

.quick__ic svg {
  width: 20px;
  height: 20px;
}

.quick__ic--fin {
  background: var(--green-soft);
}

/* ── Финансы ──────────────────────────────────────────────────── */

.fin__balance {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fin__label {
  color: var(--muted);
  font-size: var(--t-13);
}

.fin__big {
  font-size: var(--t-28);
  font-weight: 700;
  line-height: 1.1;
}

.fin__row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 8px;
}

.fin__chip {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  background: var(--card-2);
  font-size: var(--t-12);
  font-weight: 600;
}

.fin__chip svg {
  width: 14px;
  height: 14px;
}

.fin__chip--in {
  color: var(--green-dk);
  background: var(--green-soft);
}

.fin__chip--out {
  color: var(--red-ink);
  background: var(--red-soft);
}

.fin__net {
  margin-top: 8px;
  font-size: var(--t-13);
  color: var(--muted);
}

.fin__net--up {
  color: var(--green-dk);
}

.fin__net--down {
  color: var(--red-ink);
}

.fin__amount {
  flex: none;
  color: var(--red-ink);
  font-size: var(--t-15);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.fin__amount--in {
  color: var(--green-dk);
}

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

.finbar {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 10px;
}

.finbar__head {
  display: contents;
}

.finbar__name {
  display: flex;
  gap: 8px;
  align-items: center;
  font-size: var(--t-13);
  font-weight: 600;
}

.finbar__name svg {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--muted);
}

.finbar__pct {
  font-size: var(--t-13);
  font-weight: 700;
}

.finbar__track {
  grid-column: 1 / -1;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--line);
  overflow: hidden;
}

.finbar__track span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--green-dk);
}

.finbar__sum {
  grid-column: 1 / -1;
  color: var(--muted);
  font-size: var(--t-12);
}

/* ── Динамика доход/расход ────────────────────────────────────── */

.fintrend {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  height: 116px;
  margin-top: 4px;
}

.fintrend__col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  height: 100%;
}

.fintrend__bars {
  flex: 1;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 3px;
  width: 100%;
  min-height: 0;
}

.fintrend__bar {
  width: 10px;
  min-height: 2px;
  border-radius: 3px 3px 0 0;
}

.fintrend__bar--in {
  background: var(--green-dk);
}

.fintrend__bar--out {
  background: var(--red-ink);
}

.fintrend__lbl {
  font-size: var(--t-12);
  color: var(--muted);
}

.fintrend__legend {
  display: flex;
  gap: 16px;
  margin-top: 10px;
  font-size: var(--t-13);
  color: var(--muted);
}

.fintrend__key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* ── Копилки ──────────────────────────────────────────────────── */

.pot__head {
  display: flex;
  gap: 12px;
  align-items: center;
  width: 100%;
  text-align: left;
}

.pot__pct {
  flex: none;
  font-weight: 800;
  color: var(--green-dk);
}

/* Полоску прогресса переиспользуем у .finbar__track, но там она — элемент
   грида; здесь, в карточке, ей нужно самой стать блоком во всю ширину. */
.pot__track {
  display: block;
  width: 100%;
  margin-top: 12px;
}

.pot__topup {
  margin-top: 12px;
}

/* ── Ближайшие задачи ─────────────────────────────────────────── */

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

.up {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
}

.up__link {
  display: flex;
  flex: 1;
  gap: 10px;
  align-items: center;
  min-width: 0;
  min-height: var(--tap);
  color: inherit;
  text-decoration: none;
}

.up__title {
  flex: 1;
  overflow: hidden;
  font-size: var(--t-15);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.up__time {
  flex: none;
  color: var(--muted);
  font-size: var(--t-13);
  font-variant-numeric: tabular-nums;
}

.up__time--late {
  color: var(--red-ink);
  font-weight: 600;
}

.dot--fire {
  background: var(--red);
}

.dot--strategy {
  background: var(--green);
}

.dot--others {
  background: var(--amber);
}

.dot--dust {
  background: var(--line);
}

.quads__sum {
  margin-top: 12px;
  color: var(--muted);
  font-size: var(--t-12);
  text-align: center;
}

.focus {
  display: flex;
  gap: 12px;
  align-items: center;
}

.focus__body {
  flex: 1;
  min-width: 0;
  color: inherit;
  text-decoration: none;
}

.focus__label {
  display: block;
  color: var(--muted);
  font-size: var(--t-12);
}

/* display: block обязателен — это <span>, а overflow/text-overflow на строчных
   не действуют: без него длинное слово вылезает за карточку, а не обрезается. */
.focus__title {
  display: block;
  margin: 2px 0 6px;
  overflow: hidden;
  font-size: var(--t-16);
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.focus__meta {
  display: flex;
  gap: 6px;
  align-items: center;
  color: var(--muted);
  font-size: var(--t-12);
}

.focus__meta svg {
  width: 14px;
  height: 14px;
}

/* Куда ведёт задача дня. Зелёным, а не серым, как срок рядом: срок — это
   обстоятельство, а цель — смысл, и различать их цветом дешевле, чем словами. */
.focus__chain {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 4px;
  overflow: hidden;
  color: var(--green-dk);
  font-size: var(--t-12);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.focus__chain svg {
  width: 14px;
  height: 14px;
  flex: none;
}

.play {
  display: grid;
  flex: none;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  border-radius: 50%;
  background: var(--green);
  color: var(--on-green);
  transition: background var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.play:hover {
  background: var(--green-dk);
}

.play:active {
  transform: scale(0.94);
}

.play svg {
  width: 20px;
  height: 20px;
}

/* ── Карточка задачи ──────────────────────────────────────────── */

/* Заголовок задачи на её собственном экране обрезать многоточием нельзя:
   человек пришёл сюда именно узнать, как задача называется. Поэтому здесь
   перенос, в том числе посреди слова, если слово длиннее строки. */
.detail__title {
  margin: 2px 0 10px;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.detail__note {
  margin: 14px 2px 0;
  color: var(--muted);
  font-size: var(--t-15);
  overflow-wrap: anywhere;
}

.drow {
  display: flex;
  gap: 12px;
  align-items: center;
  width: 100%;
  min-height: 58px;
  padding: 8px var(--pad);
  border-bottom: 1px solid var(--line);
  color: inherit;
  text-align: left;
}

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

.drow:active {
  background: var(--card-2);
}

.drow__icon {
  flex: none;
  width: 20px;
  height: 20px;
  color: var(--muted);
}

.drow__body {
  flex: 1;
  min-width: 0;
}

.drow__label {
  color: var(--muted);
  font-size: var(--t-12);
}

/* Строка из одного заголовка (как на экране «О приложении»): подписи под ним
   нет, поэтому заголовок и есть текст строки — набирается как основной, а не
   как мелкая надпись над пустотой. */
.drow--solo {
  min-height: 62px;
}

.drow--solo .drow__label {
  color: var(--ink);
  font-size: var(--t-16);
  font-weight: 600;
}

.drow--solo .drow__icon {
  width: 22px;
  height: 22px;
}

.drow__value {
  display: block;
  margin-top: 1px;
  overflow: hidden;
  font-size: var(--t-15);
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Многоточие рассчитано на короткие значения. Проза в одну строку не влезает
   и превращается в обрезок — ей нужен перенос. */
.drow__value--wrap {
  overflow: visible;
  font-weight: 400;
  text-overflow: clip;
  white-space: normal;
}

.drow__value--empty {
  color: var(--muted);
  font-weight: 400;
}

/* Панель таймера — липнет над таббаром. */
.timerbar {
  position: sticky;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 10px);
  z-index: 10;
  display: flex;
  gap: 12px;
  align-items: center;
  margin-top: var(--section);
  padding: 12px 14px;
  border-radius: var(--radius-card);
  background: var(--green-dk);
  color: var(--on-green);
  box-shadow: var(--shadow-lift);
}

.timerbar__icon {
  flex: none;
  width: 22px;
  height: 22px;
  opacity: 0.85;
}

.timerbar__body {
  flex: 1;
}

.timerbar__time {
  font-size: 19px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.timerbar__label {
  font-size: var(--t-12);
  opacity: 0.8;
}

.timerbar__btn {
  display: grid;
  flex: none;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
  color: var(--on-green);
}

.timerbar__btn--main {
  background: var(--card);
  color: var(--green-dk);
}

.timerbar__btn svg {
  width: 18px;
  height: 18px;
}

.timerbar__btn:active {
  transform: scale(0.94);
}

/* ── Категории ────────────────────────────────────────────────── */

.cat__swatch {
  display: grid;
  flex: none;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  color: #fff;
}

.cat__swatch svg {
  width: 19px;
  height: 19px;
}

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

.swatch {
  width: 34px;
  height: 34px;
  border: 2px solid transparent;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(43, 48, 42, 0.1);
}

.swatch[aria-pressed='true'] {
  border-color: var(--ink);
}

.iconpick {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: 8px;
}

.iconpick__item {
  display: grid;
  place-items: center;
  height: var(--tap);
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
  color: var(--muted);
}

.iconpick__item[aria-pressed='true'] {
  border-color: var(--green);
  background: var(--green-soft);
  color: var(--green-dk);
}

/* ── Формы ────────────────────────────────────────────────────── */

.field {
  display: block;
}

.field__label {
  display: block;
  margin: 0 2px 6px;
  color: var(--muted);
  font-size: var(--t-12);
  font-weight: 600;
}

.input,
.textarea,
.select {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
  font-size: var(--t-15);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

.input::placeholder,
.textarea::placeholder {
  color: var(--muted);
  opacity: 0.75;
}

.input:focus-visible,
.textarea:focus-visible,
.select:focus-visible {
  border-color: var(--green);
  outline: none;
  box-shadow: var(--ring);
}

.textarea {
  min-height: 84px;
  resize: vertical;
}

.select {
  appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235F6559' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 16px;
}

.segment {
  display: flex;
  gap: 8px;
}

.segment .chip {
  flex: 1;
  text-align: center;
}

.switch {
  display: flex;
  gap: 12px;
  align-items: center;
  width: 100%;
  min-height: var(--tap);
  text-align: left;
}

/* Переключатель.

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

   Два вида, и разница не косметическая:

   • обычный — выбор между двумя равноправными ответами («Важно» / «Не важно»
     в форме задачи). Здесь выключенное красным было бы враньём: «не важно» —
     это нормальный ответ, на котором держатся квадранты. Покрасить его в цвет
     ошибки значит подтолкнуть человека помечать важным всё подряд;
   • `--power` — включено или отключено («о чём напоминать»). Вот здесь
     выключенное действительно значит «не работает», и красный уместен. */
.switch__track {
  flex: none;
  width: 46px;
  height: 27px;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--line);
  transition: background var(--slow) var(--ease);
}

.switch__knob {
  width: 21px;
  height: 21px;
  border-radius: 50%;
  background: var(--card);
  box-shadow: var(--shadow);
  /* Едет и перекрашивается одновременно: цвет, меняющийся рывком в конце пути,
     читается как перерисовка, а не как переход. */
  transition:
    transform var(--slow) var(--ease),
    background var(--slow) var(--ease),
    width var(--fast) var(--ease);
}

.switch[aria-pressed='true'] .switch__track {
  background: var(--green);
}

.switch[aria-pressed='true'] .switch__knob {
  transform: translateX(19px);
}

/* Включено / отключено. Дорожка берёт бледный оттенок, кружок — насыщенный:
   цвет несёт то, что движется, поэтому переход виден, а не только заметен. */
.switch--power .switch__track {
  background: var(--red-soft);
}

.switch--power .switch__knob {
  background: var(--red);
}

.switch--power[aria-pressed='true'] .switch__track {
  background: var(--green-soft);
}

.switch--power[aria-pressed='true'] .switch__knob {
  background: var(--green-dk);
}

/* Нажатие вытягивает кружок в сторону движения — как настоящий тумблер под
   пальцем. Только на живом переключателе: у выключенного нажимать нечего. */
.switch:not([disabled]):active .switch__knob {
  width: 25px;
  border-radius: var(--radius-pill);
}

.switch[aria-pressed='true']:not([disabled]):active .switch__knob {
  transform: translateX(15px);
}

/* Недоступный переключатель приглушён целиком: пока уведомления не разрешены,
   эти тумблеры ничего не изменят, и обещать обратное цветом нельзя. */
.switch[disabled] .switch__track {
  background: var(--line);
}

.switch[disabled] .switch__knob {
  background: var(--card);
}

/* ── Лист снизу ───────────────────────────────────────────────── */

.sheet-root:empty {
  display: none;
}

.sheet__scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(43, 48, 42, 0.4);
  animation: fade var(--slow) var(--ease);
}

.sheet {
  position: fixed;
  bottom: 0;
  left: 50%;
  z-index: 41;
  display: flex;
  flex-direction: column;
  width: min(100%, var(--column));
  max-height: 92dvh;
  border-radius: 18px 18px 0 0;
  background: var(--bg);
  box-shadow: var(--shadow-lift);
  transform: translateX(-50%);
  animation: rise var(--slow) var(--ease);
}

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

@keyframes rise {
  from {
    transform: translate(-50%, 100%);
  }
}

.sheet__head {
  display: grid;
  grid-template-columns: var(--tap) 1fr var(--tap);
  align-items: center;
  padding: 4px var(--pad);
  border-bottom: 1px solid var(--line);
}

.sheet__grip {
  width: 36px;
  height: 4px;
  margin: 8px auto 2px;
  border-radius: var(--radius-pill);
  background: var(--line);
}

.sheet__title {
  font-size: var(--t-16);
  font-weight: 700;
  text-align: center;
}

.sheet__body {
  flex: 1;
  padding: var(--pad);
  overflow-y: auto;
}

.sheet__foot {
  padding: 12px var(--pad) calc(12px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line);
  background: var(--card);
}

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

   Поэтому здесь лист становится тем же, чем на этом экране уже является
   подтверждение (.confirm): диалогом по центру. Разметка и поведение не
   меняются ни на строку — ловушка фокуса, Escape и вопрос «сбросить
   заполнение?» общие (ui.js). Меняется только то, где лист стоит и как
   появляется, поэтому все три десятка мест, зовущих sheet(), переезжают разом.

   Слои не трогаем: подтверждение (60/61) и поповеры (75) и так выше листа (41),
   а значит вопрос о сбросе и датапикер по-прежнему открываются поверх него. */
@media (min-width: 1100px) {
  .sheet {
    top: 50%;
    bottom: auto;
    /* 560, а не телефонные 430: в листах лежат формы, и колонка уже той, что
       помещается на мониторе, заставляет прокручивать вмещающееся целиком. */
    width: 560px;
    /* Ниже телефонных 92dvh: диалог во всю высоту монитора перестаёт читаться
       как диалог — видно, что за ним что-то есть, только по узкой кромке. */
    max-height: 80dvh;
    border-radius: 18px;
    transform: translate(-50%, -50%);
    /* Тот же pop, что у .confirm, — одно движение на оба диалога. Выезд снизу
       здесь означал бы направление, которого на этом экране нет: лист приходит
       не с края, а из середины. */
    animation: pop var(--slow) var(--ease);
  }

  /* Полоска-ручка обещает «потяни вниз, чтобы закрыть». Мышью тянуть нечего, и
     обещание, за которым ничего нет, хуже, чем его отсутствие. */
  .sheet__grip {
    display: none;
  }

  /* Ручки больше нет, а её поля (8px сверху, 2px снизу) отделяли заголовок от
     края листа. Возвращаем этот воздух самой шапке. */
  .sheet__head {
    padding: 8px var(--pad);
  }

  /* Вырез под жест «домой» — телефонное понятие. На мониторе env() и так ноль,
     но держать в правиле слагаемое, которое здесь никогда не сработает, значит
     оставлять читателю загадку. */
  .sheet__foot {
    padding: 12px var(--pad);
  }
}

/* ── Пустые состояния ─────────────────────────────────────────── */

.empty {
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: center;
  padding: 36px 20px 32px;
  text-align: center;
}

.empty__art {
  width: 84px;
  height: 84px;
  margin-bottom: 6px;
  color: var(--green);
  opacity: 0.5;
}

.empty__title {
  font-size: var(--t-16);
  font-weight: 700;
}

.empty__text {
  max-width: 30ch;
  color: var(--muted);
  font-size: var(--t-13);
}

.empty .btn {
  margin-top: 12px;
}

/* Заглушка первого запуска — просторнее и с крупной иллюстрацией, как на макете. */
.taskboard {
  padding: 44px 20px 40px;
}

.taskboard .empty__art {
  width: 104px;
  height: 104px;
  opacity: 0.55;
}

/* ── Планы ────────────────────────────────────────────────────── */

/* Карточка плана обычная, с отступами: в ней есть заголовок, счётчик и кнопка,
   которым отступы нужны. А вот список задач из них вырывается — у .row свои
   горизонтальные отступы, чтобы подсветка строки доходила до краёв карточки.
   Иначе отступ удвоился бы. */
.plan {
  margin-top: 12px;
}

/* Архивный план приглушён — видно, что он в стороне от активных, но не «сломан». */
.plan--archived {
  opacity: 0.72;
}

.plan .rows {
  margin-inline: calc(var(--pad) * -1);
}

.plan__head {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
}

/* flex и min-width обязательны вместе с многоточием: без них строка не знает,
   от чего отсчитывать «слишком длинно», и просто раздвигает шапку плана. */
.plan__title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-size: var(--t-16);
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Привычки, поддерживающие цель, и цель, которую поддерживает привычка, — одна
   и та же связь с двух сторон, поэтому и выглядят одинаково. Приглушённо и
   мелко: это спутник прогресса, а не он сам — в процент цели привычки не
   входят (см. goalPromises в core.js). */
.goal__habits,
.promise__goal {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  margin-top: 6px;
  color: var(--muted);
  font-size: var(--t-12);
  text-decoration: none;
}

.goal__habits svg,
.promise__goal svg {
  width: 14px;
  height: 14px;
  flex: none;
  color: var(--green-dk);
}

/* Цель, к которой ведёт план. Строкой над счётчиком задач, а не тегом сбоку:
   это ответ на «зачем этот план», и он важнее, чем «сколько закрыто». */
.plan__goal {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  margin-bottom: 6px;
  color: var(--green-dk);
  font-size: var(--t-13);
  font-weight: 600;
  text-decoration: none;
}

.plan__goal svg {
  width: 15px;
  height: 15px;
  flex: none;
}

.plan__count {
  margin-bottom: 8px;
  color: var(--muted);
  font-size: var(--t-13);
}

/* ── Цели ─────────────────────────────────────────────────────── */

.goals {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  margin-top: 12px;
}

.goal {
  padding: 14px var(--pad);
}

.goal__main {
  display: flex;
  gap: 12px;
  align-items: center;
  color: inherit;
  text-decoration: none;
}

.goal__body {
  flex: 1;
  min-width: 0;
}

.goal__title {
  display: block;
  overflow: hidden;
  font-size: var(--t-15);
  font-weight: 700;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.goal__sub {
  display: block;
  color: var(--muted);
  font-size: var(--t-12);
}

.goal__percent {
  flex: none;
  font-size: var(--t-16);
  font-weight: 700;
}

.goal__bar {
  display: block;
  height: 6px;
  margin-top: 12px;
  border-radius: var(--radius-pill);
  background: var(--line);
  overflow: hidden;
}

.goal__bar span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--green-dk);
  transition: width var(--slow) var(--ease);
}

.goal__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 8px;
}

.goal__count {
  color: var(--muted);
  font-size: var(--t-12);
}

.goal__edit {
  min-height: var(--tap);
  padding: 0 4px;
  color: var(--green-dk);
  font-size: var(--t-13);
  font-weight: 600;
}

/* Из чего собран процент цели: строка на план. Стоит под полосой и набрано
   мельче её подписей — это расшифровка процента, а не второй процент. */
.goal__chain {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
}

.goal__chain-cap {
  display: block;
  color: var(--muted);
  font-size: var(--t-12);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.goal__chain-list {
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}

.goal__chain-row {
  display: flex;
  gap: 10px;
  align-items: baseline;
  justify-content: space-between;
  padding: 2px 0;
  font-size: var(--t-12);
}

.goal__chain-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Числа не должны прыгать по вертикали от длины названия слева, поэтому им
   запрещён перенос: строка «3 из 8 · 12% цели» либо стоит целиком, либо её нет. */
.goal__chain-num {
  flex: none;
  color: var(--muted);
  white-space: nowrap;
}

.goal__chain-more {
  padding-top: 2px;
  color: var(--muted);
  font-size: var(--t-12);
}

/* ── Обещания ─────────────────────────────────────────────────── */

.promises {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  margin-top: 12px;
}

.promise {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 12px var(--pad);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--card);
}

.promise--today {
  border-color: var(--green);
  background: var(--green-soft);
}

.promise__mark {
  display: grid;
  flex: none;
  width: var(--tap);
  height: var(--tap);
  margin: -6px 0 -6px -8px;
  border-radius: 50%;
  color: var(--line);
  place-items: center;
}

.promise__mark svg {
  width: 26px;
  height: 26px;
  padding: 4px;
  border: 2px solid currentColor;
  border-radius: 50%;
}

.promise--today .promise__mark {
  color: var(--green-dk);
}

.promise__body {
  flex: 1;
  min-width: 0;
}

.promise__text {
  display: block;
  overflow: hidden;
  font-size: var(--t-15);
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.promise__sub {
  display: block;
  color: var(--muted);
  font-size: var(--t-12);
}

/* ── Паутина ──────────────────────────────────────────────────── */

.web {
  display: block;
  width: 100%;
  height: auto;
}

.web__edge {
  stroke: var(--green);
  opacity: 0.4;
}

.web__hub {
  fill: var(--green-dk);
}

.web__hubicon {
  color: var(--on-green);
}

.web__hubpercent {
  fill: var(--on-green);
  font-size: 15px;
  font-weight: 700;
  text-anchor: middle;
}

/* Узел плана. Ровный, без цвета: цвет в этой паутине означает область жизни, и
   у плана его нет — область есть у задачи, а не у набора задач. */
.web__node circle {
  fill: var(--card);
  stroke: var(--line);
  stroke-width: 2;
}

.web__node svg {
  color: var(--green-dk);
}

.web__node--full circle {
  fill: var(--green-soft);
}

/* Ветвь «Без плана» — не сущность, а то, что не попало ни в одну. Пунктир и
   говорит: узел нарисован, но за ним ничего не заведено. */
.web__node--loose circle {
  stroke-dasharray: 3 3;
}

.web__node--loose svg {
  color: var(--muted);
}

/* Кольцо привычек. Пунктиром и бледно: они держатся рядом с целью, но в её
   устройство не входят — сплошная линия ставила бы их наравне с лучами. */
.web__orbit {
  fill: none;
  stroke: var(--line);
  stroke-dasharray: 4 5;
}

.web__promise {
  fill: var(--card);
  stroke: var(--green);
  stroke-width: 2;
}

.web__promise.is-today {
  fill: var(--green);
}

.web__count {
  fill: var(--ink);
  font-size: 10px;
  font-weight: 700;
  text-anchor: middle;
}

.web__label {
  fill: var(--muted);
  font-size: 11px;
  text-anchor: middle;
}

.web__caption {
  margin-top: 4px;
  color: var(--muted);
  font-size: var(--t-13);
  text-align: center;
}

.web__caption b {
  color: var(--ink);
  font-size: var(--t-16);
}

.web__foot {
  display: flex;
  gap: var(--gap);
  margin-top: 16px;
}

.web__foot .btn {
  flex: 1;
}

.web__fact {
  color: var(--ink);
  font-size: var(--t-13);
  line-height: 1.5;
}

/* ── Статистика ───────────────────────────────────────────────── */

.stat__row {
  display: flex;
  gap: 10px;
  align-items: baseline;
  margin: 10px 0 2px;
  flex-wrap: wrap;
}

.stat__big {
  font-size: var(--t-28);
  font-weight: 700;
  line-height: 1;
}

/* Тот же смысл, что и график, но словами — график для озвучки скрыт. */
.stat__sr {
  margin-bottom: 10px;
  color: var(--muted);
  font-size: var(--t-13);
}

.delta {
  display: inline-flex;
  gap: 6px;
  align-items: baseline;
  font-size: var(--t-15);
  font-weight: 700;
}

.delta--up {
  color: var(--green-dk);
}

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

.delta--none {
  color: var(--muted);
  font-size: var(--t-13);
  font-weight: 400;
}

.delta__note {
  color: var(--muted);
  font-size: var(--t-13);
  font-weight: 400;
}

/* Карточка-итог: тёплая зелёная плашка с одной честной мыслью (сравнение с
   собой же в прошлом периоде, а не с выдуманными «82% пользователей»). */
.hl {
  display: flex;
  gap: 12px;
  align-items: center;
  background: var(--green-soft);
  border-color: transparent;
}

.hl__badge {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: var(--radius-pill);
  background: var(--card);
  color: var(--green-dk);
}

.hl__badge svg {
  width: 20px;
  height: 20px;
}

.hl__text {
  color: var(--ink);
  font-size: var(--t-15);
  line-height: 1.45;
}

/* Ряд Выполнено / Серия / Фокус — три равные колонки с разделителями. */
.statrow {
  display: flex;
  margin-top: 12px;
  padding-block: 18px;
}

.statrow__cell {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
  padding-inline: 6px;
}

.statrow__cell + .statrow__cell {
  border-left: 1px solid var(--line);
}

.statrow__num {
  font-size: var(--t-28);
  font-weight: 800;
  line-height: 1;
  color: var(--green-dk);
}

.statrow__cap {
  font-size: var(--t-12);
  color: var(--muted);
}

/* Кольцо по категориям + легенда рядом. */
.donut {
  display: flex;
  gap: 18px;
  align-items: center;
  margin-top: 12px;
}

.donut__svg {
  flex: none;
  width: 120px;
  height: 120px;
}

.donut__num {
  text-anchor: middle;
  dominant-baseline: central;
  font-size: 24px;
  font-weight: 800;
  fill: var(--ink);
}

.donut__cap {
  text-anchor: middle;
  dominant-baseline: central;
  font-size: 9px;
  fill: var(--muted);
  letter-spacing: 0.06em;
}

.legend {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

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

.legend__dot {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
}

.legend__name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-13);
}

.legend__pct {
  flex: none;
  font-weight: 700;
  font-size: var(--t-13);
  color: var(--muted);
}

/* Время по категориям — из реально засечённого таймером времени. */
.timelist {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-top: 12px;
}

.timerow {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
}

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

.timerow__dur {
  flex: none;
  font-weight: 700;
  color: var(--green-dk);
  font-variant-numeric: tabular-nums;
}

.chart {
  display: block;
  width: 100%;
  height: auto;
}

.chart__line {
  fill: none;
  stroke: var(--green);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.chart__area {
  fill: var(--green);
  opacity: 0.12;
}

.chart__dot {
  fill: var(--card);
  stroke: var(--green);
  stroke-width: 1.6;
}

.chart__dot[data-peak] {
  fill: var(--green);
}

.chart__axis {
  display: flex;
  margin-top: 4px;
}

.chart__tick {
  flex: 1;
  color: var(--muted);
  font-size: var(--t-12);
  text-align: center;
}

.hours {
  display: flex;
  gap: 2px;
  align-items: flex-end;
  height: 88px;
  margin: 12px 0 4px;
}

.hours__bar {
  flex: 1;
  min-height: 2px;
  height: max(2px, var(--v));
  border-radius: 2px;
  background: var(--green);
  opacity: 0.35;
}

.hours__bar--peak {
  opacity: 1;
}

.hours__axis {
  display: flex;
  justify-content: space-between;
  color: var(--muted);
  font-size: var(--t-12);
}

.stat__peak {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 10px;
  color: var(--muted);
  font-size: var(--t-13);
}

.stat__peak b {
  color: var(--ink);
}

.stat__peak svg {
  width: 16px;
  height: 16px;
  flex: none;
}

/* ── Награды ──────────────────────────────────────────────────── */

.medals {
  display: grid;
  gap: var(--gap);
  grid-template-columns: 1fr 1fr;
  margin-top: 12px;
}

.medal {
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: center;
  padding: 18px 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--card);
  color: inherit;
  text-align: center;
  text-decoration: none;
}

.medal__coin {
  position: relative;
  display: grid;
  width: 58px;
  height: 58px;
  margin-bottom: 8px;
  border: 2px solid currentColor;
  border-radius: 50%;
  background: var(--card-2);
  place-items: center;
}

.medal__coin svg {
  width: 26px;
  height: 26px;
}

/* Металл держим в переменной, а не только в color: значку степени нужен этот
   цвет фоном, а собственный color у него — цвет карточки. */
.medal--gold {
  --metal: var(--gold);
}

.medal--green {
  --metal: var(--green-dk);
}

.medal--silver {
  --metal: var(--silver);
}

.medal--bronze {
  --metal: var(--bronze);
}

.medal--locked {
  --metal: var(--muted);
}

.medal__coin,
.medal__bar span,
.medal__state {
  color: var(--metal);
}

.medal--locked .medal__coin {
  border-style: dashed;
  opacity: 0.7;
}

/* Степень римской цифрой — как значок на монете.
   Единственная надпись мельче двенадцати пикселей, оставленная нарочно. Это
   клеймо на значке в двадцать пикселей, а не сведение: та же степень стоит
   словом прямо под медалью — «Бронза», «Серебро», «Золото». Поэтому же
   в разметке оно aria-hidden: скринридеру незачем читать «III» перед
   «Бронзой». Увеличить нельзя: в кружок двенадцать пикселей не встанут. */
.medal__degree {
  position: absolute;
  right: -4px;
  bottom: -4px;
  display: grid;
  min-width: 20px;
  height: 20px;
  padding: 0 4px;
  border: 1.5px solid var(--card);
  border-radius: var(--radius-pill);
  background: var(--metal);
  color: var(--card);
  font-size: 10px;
  font-weight: 700;
  place-items: center;
}

.medal__name {
  color: var(--ink);
  font-size: var(--t-13);
  font-weight: 700;
}

.medal__hint {
  color: var(--muted);
  font-size: var(--t-12);
}

.medal__state {
  margin-top: 6px;
  font-size: var(--t-12);
  font-weight: 700;
}

.medal--locked .medal__state {
  font-weight: 400;
}

.medal__bar {
  display: block;
  width: 100%;
  height: 4px;
  margin-top: 8px;
  border-radius: var(--radius-pill);
  background: var(--line);
  overflow: hidden;
}

.medal__bar span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--metal);
}

.medal__next {
  margin-top: 6px;
  color: var(--muted);
  font-size: var(--t-12);
}

/* ── Глубокая работа ──────────────────────────────────────────── */

.focusmode {
  position: relative;
  display: flex;
  flex-direction: column;
  /* Шапка выше своей базовой высоты на вырез — вычитаем и его, иначе на
     домашнем экране экран фокуса вылезал бы за низ ровно на эту разницу. */
  min-height: calc(100dvh - var(--appbar-h) - env(safe-area-inset-top) - 24px);
  padding: 8px var(--pad) calc(env(safe-area-inset-bottom) + 20px);
}

.scene {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: -1;
  height: 46%;
  pointer-events: none;
}

.scene svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* Глубина — слоями полупрозрачной зелени, как на макете, а не тенями. */
.scene__sun {
  fill: var(--amber);
  opacity: 0.5;
}

.scene__far {
  fill: var(--green);
  opacity: 0.16;
}

.scene__mid {
  fill: var(--green);
  opacity: 0.26;
}

.scene__near {
  fill: var(--green-dk);
  opacity: 0.22;
}

.focusmode__top {
  padding: 20px 0 18px;
  text-align: center;
}

.focusmode__head {
  font-size: var(--t-20);
  font-weight: 700;
}

.focusmode__sub {
  margin-top: 4px;
  color: var(--muted);
  font-size: var(--t-13);
}

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

.focusmode__label {
  color: var(--muted);
  font-size: var(--t-12);
}

.focusmode__title {
  font-size: var(--t-16);
  font-weight: 700;
}

.focusmode__meta {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 4px;
  color: var(--muted);
  font-size: var(--t-13);
}

.focusmode__meta svg {
  width: 15px;
  height: 15px;
}

.focusmode__clock {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 2px;
  align-items: center;
  justify-content: center;
  padding: 24px 0;
}

.focusmode__time {
  font-size: 44px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.focusmode__state {
  color: var(--muted);
  font-size: var(--t-13);
}

.focusmode__foot {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  align-items: center;
}

.focusmode__foot .btn--ghost {
  background: transparent;
}

/* ── Глубокая работа на компьютере (отдельное окно) ───────────── */

/* Раскладка из макета doc/ref/focus desktop.png, но только с настоящими
   данными: пульс/сон, плеер, «ИИ рекомендует», очки и обратный отсчёт с
   макета сюда не попали — их неоткуда взять (см. focus.js). По умолчанию
   спрятана; включается только в широком виде, где `.focusmode` наоборот
   уходит. */
.fw {
  display: none;
}

@media (min-width: 1100px) {
  .focusmode {
    display: none;
  }

  .fw {
    position: relative;
    display: grid;
    grid-template-columns: minmax(230px, 1fr) minmax(360px, 1.5fr) minmax(230px, 1fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      'head head head'
      'left center right';
    gap: var(--gap);
    min-height: 100%;
    padding: 8px 4px 0;
  }

  .fw__head {
    grid-area: head;
    text-align: center;
    padding: 4px 0 6px;
  }

  /* Токены --t-24/--t-18/--t-14 не существуют: шкала в tokens.css состоит из
     12·13·15·16·20·28. Здесь стояли именно они, и var() без запасного значения
     недействителен на этапе вычисления — размер откатывался к унаследованному,
     то есть к 13px. Заголовок режима и название задачи набирались размером
     подписи, а весь смысл экрана в том, что задача одна и она крупная.

     Ссылаемся на существующие токены, а не заводим новые: весь блок .fw живёт
     внутри @media (min-width: 1100px), а на широком экране --t-28, --t-20 и
     --t-16 равны ровно 24, 18 и 14 пикселям — тем числам, что стояли здесь. */
  .fw__title {
    font-size: var(--t-28);
    font-weight: 700;
  }

  .fw__sub {
    margin-top: 4px;
    color: var(--muted);
    font-size: var(--t-16);
  }

  .fw__left {
    grid-area: left;
  }

  .fw__center {
    grid-area: center;
  }

  .fw__right {
    grid-area: right;
  }

  .fw__left,
  .fw__right {
    display: flex;
    flex-direction: column;
    gap: var(--gap);
    min-height: 0;
  }

  .fw__center {
    display: flex;
    flex-direction: column;
    gap: 18px;
    align-items: center;
    justify-content: center;
  }

  /* Часы — таймер вперёд, а не отсчёт: кольцо ровное, без «прогресса»,
     которого у нас нет. */
  .fw__clock {
    position: relative;
    display: grid;
    place-items: center;
    width: 232px;
    height: 232px;
  }

  .fw__ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 12px solid var(--green-soft);
    background: var(--card);
    box-shadow:
      inset 0 0 0 1px var(--line),
      0 8px 24px rgba(0, 0, 0, 0.05);
  }

  .fw__clockin {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: center;
    text-align: center;
  }

  .fw__clocklabel {
    color: var(--muted);
    font-size: var(--t-13);
  }

  .fw__time {
    font-size: 40px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
  }

  .fw__state {
    color: var(--green-dk);
    font-size: var(--t-13);
    font-weight: 600;
  }

  .fw__chips {
    display: flex;
    gap: 10px;
    justify-content: center;
    flex-wrap: wrap;
  }

  .fw__chip {
    display: inline-flex;
    gap: 8px;
    align-items: center;
    padding: 8px 14px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--card);
    font-size: var(--t-13);
    color: var(--muted);
  }

  .fw__chip svg {
    width: 16px;
    height: 16px;
    color: var(--green-dk);
  }

  .fw__chip b {
    font-size: var(--t-15);
    color: var(--ink);
  }

  .fw__task {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }

  .fw__tasklabel {
    display: flex;
    gap: 6px;
    align-items: center;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .fw__tasklabel svg {
    width: 15px;
    height: 15px;
  }

  .fw__tasktitle {
    font-size: var(--t-20);
    font-weight: 700;
  }

  .fw__taskmeta {
    display: flex;
    gap: 6px;
    align-items: center;
    color: var(--muted);
    font-size: var(--t-13);
  }

  .fw__taskmeta svg {
    width: 15px;
    height: 15px;
  }

  .fw__foot {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 10px;
  }

  /* Четыре кнопки укладываются 2×2: в столбце фокуса на один ряд они слишком
     узкие, а длинные подписи («Сбросить таймер», «Завершить фокус») ломались. */
  .fw__foot .btn {
    flex: 1 1 calc(50% - 4px);
    white-space: nowrap;
  }

  .fw__foot .btn--ghost {
    background: transparent;
  }

  .fw__cardhead {
    font-size: var(--t-16);
    font-weight: 700;
    margin-bottom: 8px;
  }

  .fw__cardempty {
    color: var(--muted);
    font-size: var(--t-13);
    line-height: 1.5;
  }

  /* Очередь за текущей задачей. */
  .fw__qlist {
    display: flex;
    flex-direction: column;
    gap: 12px;
    list-style: none;
  }

  .fw__qrow {
    display: flex;
    gap: 10px;
    align-items: flex-start;
  }

  .fw__qdot {
    flex: none;
    width: 9px;
    height: 9px;
    margin-top: 5px;
    border-radius: 50%;
    background: var(--dot);
  }

  .fw__qtext {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
  }

  .fw__qtitle {
    font-size: var(--t-16);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .fw__qmeta {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .fw__quote {
    display: flex;
    gap: 10px;
    align-items: flex-start;
  }

  .fw__quote p {
    font-size: var(--t-16);
    font-style: italic;
    color: var(--ink);
    line-height: 1.5;
  }

  .fw__quotemark,
  .fw__quieticon {
    flex: none;
    color: var(--green-dk);
  }

  .fw__quotemark svg,
  .fw__quieticon svg {
    width: 20px;
    height: 20px;
  }

  .fw__quiet {
    display: flex;
    gap: 10px;
    align-items: flex-start;
  }
}

/* ── Подтверждение ────────────────────────────────────────────── */

/* Поверх листа: z-index выше, чем у .sheet, — вопрос «сбросить заполнение?»
   обязан быть виден над той самой формой. */
.confirm-root:empty {
  display: none;
}

.confirm__scrim {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(43, 48, 42, 0.4);
  animation: fade var(--fast) var(--ease);
}

.confirm {
  position: fixed;
  top: 50%;
  left: 50%;
  z-index: 61;
  width: min(calc(100% - 40px), 340px);
  padding: 20px;
  border-radius: var(--radius-card);
  background: var(--card);
  box-shadow: var(--shadow-lift);
  transform: translate(-50%, -50%);
  animation: pop var(--fast) var(--ease);
}

.confirm__title {
  font-size: var(--t-16);
  font-weight: 700;
}

.confirm__text {
  margin-top: 6px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.5;
}

.confirm__actions {
  display: flex;
  gap: 8px;
  margin-top: 18px;
}

@keyframes pop {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.96);
  }
}

/* ── Интеграции ───────────────────────────────────────────────── */

.intgs {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  margin-top: 12px;
}

/* Список интеграций: строка на сервис, подробности — по нажатию. Так экран
   читается одним взглядом, а не листается через четыре развёрнутых карточки. */
.intgrows {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 12px;
}

.intgrow {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--card);
  box-shadow: var(--shadow);
  color: inherit;
  text-decoration: none;
}

/* Строка целиком — цель нажатия, поэтому отклик тоже на всю строку. */
.intgrow:active {
  transform: scale(0.99);
}

.intgrow .intg__logo {
  width: 44px;
  height: 44px;
  border-radius: 12px;
}

.intgrow .intg__logo svg {
  width: 25px;
  height: 25px;
}

.intgrow__body {
  min-width: 0;
  flex: 1;
}

.intgrow__name {
  display: block;
  font-size: var(--t-16);
  font-weight: 700;
}

.intgrow__status {
  display: block;
  margin-top: 2px;
  font-size: var(--t-12);
}

.intgrow__status--on {
  color: var(--green-dk);
}

.intgrow__status--off {
  color: var(--muted);
}

.intgrow__status--partial {
  color: var(--amber-text);
}

.intgrow__mark {
  display: grid;
  flex: none;
  color: var(--muted);
  place-items: center;
}

.intgrow__mark svg {
  width: 20px;
  height: 20px;
}

/* Зелёный кружок с галочкой — только у по-настоящему подключённого. */
.intgrow__mark--on {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--green);
  color: var(--on-green);
}

.intgrow__mark--on svg {
  width: 15px;
  height: 15px;
}

.intg {
  padding: 16px;
}

.intg__head {
  display: flex;
  gap: 12px;
  align-items: center;
}

/* Плитка логотипа — скруглённый квадрат с фирменным цветом сервиса, как на
   макете. Внутри либо белый значок, либо готовый разноцветный логотип. */
.intg__logo {
  display: grid;
  width: 48px;
  height: 48px;
  flex: none;
  border-radius: 13px;
  place-items: center;
  overflow: hidden;
}

.intg__logo svg {
  width: 28px;
  height: 28px;
}

.intg__logo--tg {
  background: var(--tg-blue);
}

.intg__logo--red {
  background: var(--red);
  color: var(--on-green);
}

/* Готовый разноцветный логотип (Google) на светлой подложке. */
.intg__logo--plain {
  border: 1px solid var(--line);
  background: var(--card);
}

.intg__logo--plain svg {
  width: 26px;
  height: 26px;
}

.intg__title {
  min-width: 0;
}

.intg__name {
  display: block;
  font-size: var(--t-16);
  font-weight: 700;
}

.intg__status {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  margin-top: 2px;
  font-size: var(--t-12);
  font-weight: 600;
}

.intg__status svg {
  width: 14px;
  height: 14px;
}

.intg__status--on {
  color: var(--green-dk);
}

.intg__status--off {
  color: var(--muted);
}

.intg__status--partial {
  color: var(--amber-text);
}

.intg__desc {
  margin-top: 12px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.5;
}

.intg__label {
  margin-top: 14px;
  font-size: var(--t-12);
  font-weight: 700;
}

.intg__abilities {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}

.intg__abilities li {
  display: flex;
  gap: 8px;
  align-items: center;
  font-size: var(--t-13);
}

.intg__abilities svg {
  width: 16px;
  height: 16px;
  flex: none;
  color: var(--green-dk);
}

.intg__actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 16px;
}

/* ── Уведомления ──────────────────────────────────────────────── */

.notif__head {
  display: flex;
  gap: 14px;
  align-items: center;
}

/* Значок перекрашивается переходом, а не подменой: включение уведомлений —
   единственное действие на экране, и оно обязано быть видно как движение, иначе
   человек не уверен, что нажатие сработало. Тот же приём, что у переключателя:
   выключено — красным, включено — зелёным. */
.notif__bell {
  display: grid;
  width: 46px;
  height: 46px;
  flex: none;
  border-radius: 50%;
  background: var(--red-soft);
  color: var(--on-red-soft);
  place-items: center;
  transition:
    background var(--slow) var(--ease),
    color var(--slow) var(--ease);
}

.notif__bell--on {
  background: var(--green-soft);
  color: var(--green-dk);
}

.notif__bell svg {
  width: 22px;
  height: 22px;
}

.notif__state {
  min-width: 0;
}

.notif__title {
  font-size: var(--t-16);
  font-weight: 700;
}

.notif__text {
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.45;
}

/* Переключатель строкой: подпись слева, тумблер справа. В форме задачи
   .switch устроен наоборот — там он идёт в потоке текста. */
.switches {
  display: flex;
  flex-direction: column;
}

.switch--row {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: var(--tap);
  padding: 12px var(--pad);
  border-bottom: 1px solid var(--line);
  text-align: left;
}

.switch--row:last-child {
  border-bottom: 0;
}

.switch--row:disabled {
  opacity: 0.45;
}

.switch__body {
  flex: 1;
  min-width: 0;
}

.switch__name {
  display: block;
  font-size: var(--t-15);
  font-weight: 600;
}

.switch__hint {
  display: block;
  margin-top: 1px;
  color: var(--muted);
  font-size: var(--t-12);
}

/* ── Вход и регистрация ───────────────────────────────────────── */

/* Экран без карточки: поля лежат прямо на фоне, как на макете. Горы внизу и
   листья по углам — часть экрана, поэтому нужен свой контекст наложения. */
.auth {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 100dvh;
  padding: calc(env(safe-area-inset-top) + 24px) var(--pad) calc(env(safe-area-inset-bottom) + 24px);
  isolation: isolate;
  overflow: hidden;
}

/* На регистрации полей четыре и есть шапка — центрировать нечего. */
.auth--form {
  justify-content: flex-start;
  min-height: calc(100dvh - var(--appbar-h) - env(safe-area-inset-top));
  padding-top: 8px;
}

.auth .scene {
  height: 32%;
}

.auth__box {
  position: relative;
  width: 100%;
  text-align: center;
}

.auth__logo {
  display: block;
  width: 112px;
  height: 112px;
  margin: 0 auto 10px;
}

.auth__brand {
  color: var(--green-dk);
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
}

.auth__tagline {
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--t-15);
}

.auth__sub {
  margin: 0 auto 4px;
  max-width: 32ch;
  color: var(--muted);
  font-size: var(--t-15);
  line-height: 1.45;
}

.auth__form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 20px;
  text-align: left;
}

/* Рамка на обёртке, а у input своей нет — иначе рамок было бы две. */
.auth__field {
  display: flex;
  gap: 10px;
  align-items: center;
  min-height: 54px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

.auth__field:focus-within {
  border-color: var(--green);
  box-shadow: 0 0 0 3px var(--green-soft);
}

.auth__icon {
  display: grid;
  flex: none;
  color: var(--muted);
  place-items: center;
}

.auth__icon svg {
  width: 20px;
  height: 20px;
}

.auth__input {
  flex: 1;
  min-width: 0;
  min-height: 52px;
  border: 0;
  background: none;
  font-size: var(--t-15);
}

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

.auth__eye {
  display: grid;
  width: var(--tap);
  height: var(--tap);
  flex: none;
  margin-right: -10px;
  color: var(--muted);
  place-items: center;
}

.auth__eye svg {
  width: 20px;
  height: 20px;
}

.auth__eye--on {
  color: var(--green-dk);
}

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

.auth__remember {
  display: flex;
  gap: 8px;
  align-items: center;
  min-height: var(--tap);
  font-size: var(--t-13);
  cursor: pointer;
}

/* Свой квадратик вместо системного: тот не красится и выглядит чужеродно.
   Настоящий input рядом — он несёт состояние и доступность. */
.auth__remember input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.auth__box-check {
  display: grid;
  width: 20px;
  height: 20px;
  flex: none;
  border: 1.5px solid var(--line);
  border-radius: 6px;
  background: var(--card);
  color: transparent;
  place-items: center;
}

.auth__box-check svg {
  width: 14px;
  height: 14px;
}

.auth__remember input:checked + .auth__box-check {
  border-color: var(--green-dk);
  background: var(--green-dk);
  color: var(--on-green);
}

.auth__remember input:focus-visible + .auth__box-check {
  outline: var(--ring);
  outline-offset: 2px;
}

.auth__link {
  color: var(--green-dk);
  font-size: var(--t-13);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.auth__hint {
  color: var(--muted);
  font-size: var(--t-12);
  line-height: 1.45;
}

.auth__error {
  padding: 9px 12px;
  border-radius: var(--radius-btn);
  background: var(--red-soft);
  color: var(--red-ink);
  font-size: var(--t-13);
  line-height: 1.4;
}

.auth__or {
  position: relative;
  margin: 18px 0;
  color: var(--muted);
  font-size: var(--t-13);
  text-align: center;
}

.auth__or::before {
  position: absolute;
  top: 50%;
  right: 0;
  left: 0;
  border-top: 1px solid var(--line);
  content: '';
}

.auth__or span {
  position: relative;
  padding: 0 12px;
  background: var(--bg);
}

.auth__google {
  background: var(--card);
}

.glogo {
  width: 20px;
  height: 20px;
  flex: none;
}

.auth__foot {
  margin-top: 16px;
  color: var(--muted);
  font-size: var(--t-13);
  text-align: center;
}

.auth__foot--muted {
  font-size: var(--t-12);
}

.auth__tg {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 16px;
  text-align: center;
}

/* Объяснение на экранах входа через Telegram и Google. Не .auth__sub: тот на
   широком экране прячется (на регистрации тот же текст дублируется в
   .auth__welcome), а здесь это единственное объяснение того, что сейчас
   произойдёт — и в оболочке, где экран всегда широкий, оно исчезало совсем. */
.auth__lead {
  margin: 0 auto;
  max-width: 40ch;
  color: var(--muted);
  font-size: var(--t-15);
  line-height: 1.45;
}

/* Заголовок в карточке. До входа шапка приложения на широком экране
   скрыта, и без этой строки карточка начиналась сразу с кнопки. */
.auth__step {
  font-size: var(--t-20);
  font-weight: 700;
}

/* .btn на ссылке не снимает подчёркивание браузера — снимаем явно. */
.auth__tglink {
  gap: 8px;
  text-decoration: none;
}

.auth__tglink svg {
  width: 18px;
  height: 18px;
}

.auth__tglink svg {
  color: var(--on-green);
}

.auth__wait {
  display: flex;
  gap: 6px;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: var(--t-13);
}

.auth__wait svg {
  width: 16px;
  height: 16px;
}

.about__mark {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 12px;
}

.about__mark img {
  width: 48px;
  height: 48px;
}

.about__mark span {
  font-size: var(--t-16);
  font-weight: 700;
}

.about {
  text-align: center;
}

.about .about__mark {
  justify-content: center;
  margin-bottom: 8px;
}

.about__version {
  color: var(--muted);
  font-size: var(--t-13);
}

.about__motto {
  margin-top: 10px;
  font-size: var(--t-16);
  font-weight: 600;
}

.about__copy {
  margin-top: 22px;
  color: var(--muted);
  font-size: var(--t-12);
  line-height: 1.6;
  text-align: center;
}

/* ── Оценка ───────────────────────────────────────────────────── */

.rating {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.rating__stars {
  display: flex;
  gap: 4px;
  justify-content: center;
  color: var(--amber-ink);
}

.rating__value {
  margin-top: 6px;
  font-size: var(--t-20);
  font-weight: 700;
}

.rating__count {
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--t-13);
}

/* Выбор оценки: звёзды крупные, потому что по ним попадают пальцем. */
.ratepick {
  display: flex;
  gap: 4px;
  justify-content: center;
}

.ratepick__star {
  display: grid;
  min-width: var(--tap);
  min-height: var(--tap);
  color: var(--muted);
  place-items: center;
  transition: color var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.ratepick__star--on {
  color: var(--amber-ink);
}

.ratepick__star:active {
  transform: scale(0.92);
}

/* Диагностика для письма — моноширинным и с прокруткой: это технический текст,
   его читают глазами по строкам, а перенос слов сделал бы его нечитаемым. */
.diag {
  max-height: 180px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card-2);
  color: var(--muted);
  font-family: ui-monospace, 'Cascadia Mono', Consolas, monospace;
  font-size: var(--t-12);
  line-height: 1.5;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ── Ряд вложений в форме ─────────────────────────────────────── */

/* Четыре кнопки в строку, как на макете. Ширина делится поровну, поэтому на
   узком экране они сжимаются, а не переносятся уродливым столбиком. */
.attachbar {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.attachbar__btn {
  display: flex;
  flex-direction: column;
  gap: 5px;
  align-items: center;
  justify-content: center;
  min-height: 62px;
  padding: 8px 4px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.attachbar__btn svg {
  width: 20px;
  height: 20px;
}

.attachbar__btn:active {
  background: var(--card-2);
}

/* Идёт запись голоса. Красный — единственное место, где он означает не ошибку,
   а «включено и пишет»: без явного признака человек не поймёт, что микрофон жив. */
.attachbar__btn--rec {
  border-color: var(--red);
  background: var(--red-soft);
  color: var(--on-red-soft);
}

.attachlist {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.attachlist:empty {
  display: none;
}

.chipfile {
  display: inline-flex;
  max-width: 100%;
  gap: 6px;
  align-items: center;
  padding: 6px 6px 6px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--card-2);
  font-size: var(--t-13);
}

.chipfile svg {
  width: 15px;
  height: 15px;
  flex: none;
  color: var(--muted);
}

/* Имя файла может быть длинным — режем многоточием, а не ломаем строку. */
.chipfile__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chipfile__x {
  display: grid;
  width: 22px;
  height: 22px;
  flex: none;
  border-radius: 50%;
  color: var(--muted);
  font-size: 12px;
  place-items: center;
}

.chipfile__x:active {
  background: var(--line);
}

/* ── Форма задачи ─────────────────────────────────────────────────
   Одна разметка на лист (телефон) и на страницу (компьютер). На телефоне —
   одна колонка: .tf__main, затем .tf__side. На широком экране CSS-грид ставит
   их рядом (см. медиазапрос ниже). Поля внутри каждой колонки — свой вертикальный
   стек, поэтому .stack на самой форме отвечает только за зазор между колонками. */
.tf__main,
.tf__side {
  display: flex;
  flex-direction: column;
  /* Поджато с --gap (12px) до 10px: полей в форме много, и на общей высоте
     лишние два пикселя между каждым складываются в заметную «лесенку». */
  gap: 10px;
  min-width: 0;
}

/* Подсказки в форме прижаты к своему полю плотнее обычных 8px — иначе каждая
   добавляла к высоте заметный зазор. */
.tf .hint {
  margin-top: 4px;
}

.tf__count {
  display: block;
  margin-top: 4px;
  text-align: right;
  color: var(--muted);
  font-size: var(--t-12);
}

.tf__desc {
  min-height: 92px;
}

/* Матрица: четыре кнопки на два независимых бита (важно/срочно). */
.tf__matrix {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}

.tf__quad {
  min-height: 38px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
  color: var(--ink);
  font-size: var(--t-13);
  font-weight: 600;
  transition:
    background var(--fast) var(--ease),
    color var(--fast) var(--ease),
    border-color var(--fast) var(--ease);
}

.tf__quad:hover {
  background: var(--card-2);
}

.tf__quad[aria-pressed='true'] {
  border-color: var(--green-dk);
  background: var(--green-dk);
  color: var(--on-green);
}

/* Приоритет: пустые звёзды бледные, заполненные — зелёные. */
.tf__stars {
  display: inline-flex;
  gap: 4px;
}

.tf__star {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  color: var(--muted);
  opacity: 0.35;
  transition: color var(--fast) var(--ease), opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.tf__star svg {
  width: 21px;
  height: 21px;
}

.tf__star.is-on {
  color: var(--green-dk);
  opacity: 1;
}

.tf__star:active {
  transform: scale(0.88);
}

/* Теги: чипы и встроенное поле ввода в одной рамке. */
.tf__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  min-height: var(--tap);
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
}

.tf__tags:focus-within {
  border-color: var(--green);
  box-shadow: var(--ring);
}

.chipfile--tag svg {
  color: var(--green-dk);
}

.tf__taginput {
  flex: 1;
  min-width: 90px;
  min-height: 28px;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--t-15);
  outline: none;
}

/* Подзадачи: строки с отметкой и поле «добавить». */
/* Рамка-«окно» вокруг подзадач: список и строка добавления в одной карточке.
   Строки внутри — без собственных плашек, разделены тонкой линией, чтобы блок
   читался как единое поле, а не стопка отдельных кнопок. */
.tf__subsbox {
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
  padding: 2px 12px;
}

.tf__subs {
  display: flex;
  flex-direction: column;
  /* Больше пяти подзадач — список прокручивается внутри «окна», а не толкает
     всю форму вниз. Строка «Добавить» лежит вне этого блока и остаётся на
     месте. ~5 строк по ~42px; шестая выглядывает краем, подсказывая прокрутку. */
  max-height: 220px;
  overflow-y: auto;
  scrollbar-width: thin;
}

.tf__subs:empty {
  display: none;
}

.tf__strow {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 10px 0;
}

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

/* Линия между списком и строкой добавления — только когда список не пуст. */
.tf__subs:not(:empty) + .tf__subadd {
  border-top: 1px solid var(--line);
}

.tf__stcheck {
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  flex: none;
  border: 1.5px solid var(--line);
  border-radius: 50%;
  color: transparent;
  transition:
    background var(--fast) var(--ease),
    border-color var(--fast) var(--ease),
    color var(--fast) var(--ease);
}

.tf__stcheck svg {
  width: 14px;
  height: 14px;
}

.tf__stcheck[aria-pressed='true'] {
  border-color: var(--green-dk);
  background: var(--green-dk);
  color: var(--on-green);
}

.tf__sttext {
  flex: 1;
  min-width: 0;
}

.tf__sttext.is-done {
  color: var(--muted);
  text-decoration: line-through;
}

.tf__subadd {
  display: flex;
  gap: 8px;
  align-items: center;
  color: var(--muted);
}

.tf__subadd svg {
  width: 18px;
  height: 18px;
  flex: none;
}

/* Строка добавления — без своей рамки: окно вокруг уже её обрамляет. */
.tf__subinput {
  flex: 1;
  min-height: var(--tap);
  padding: 8px 0;
  border: 0;
  border-radius: 0;
  background: none;
  font: inherit;
  font-size: var(--t-15);
  outline: none;
}

/* Страница задачи: форма и нижняя панель с кнопками. */
.tfpage {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.tfpage__foot {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

.tfpage__foot .btn {
  flex: 1 1 auto;
}

/* Широкий экран: две колонки, как в макете re-task.png. Только на отдельной
   странице (.tfpage) — в узком модальном листе форма всегда в одну колонку,
   иначе боковая колонка 360px не помещается и всё сминается. */
@media (min-width: 1100px) {
  .tfpage .tf {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 24px;
    align-items: start;
  }

  /* На странице кнопки нормального размера, а не во всю ширину: «Отмена»
     уходит вправо, «Сохранить» и «…создать ещё» остаются слева. */
  .tfpage__foot .btn {
    flex: 0 0 auto;
    min-width: 150px;
  }

  .tfpage__foot a.btn:last-child {
    margin-left: auto;
  }
}

/* ── Детали задачи (dat-task.png) ─────────────────────────────────
   Одна разметка на телефон и на компьютер: на узком — один столбец, на
   широком — две колонки (грид в медиазапросе ниже). */
.tdetail {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.tdetail__main,
.tdetail__side {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  min-width: 0;
}

.tdetail__headrow {
  display: flex;
  gap: 12px;
  align-items: center;
}

.tdetail__check {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border: 2px solid var(--line);
  border-radius: 50%;
  color: transparent;
}

.tdetail__check svg {
  width: 18px;
  height: 18px;
}

.tdetail__check.is-done {
  border-color: var(--green-dk);
  background: var(--green-dk);
  color: var(--on-green);
}

.tdetail__title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: var(--t-20);
  font-weight: 800;
}

.tdetail__star {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  flex: none;
  border-radius: 10px;
  color: var(--muted);
  opacity: 0.4;
  transition: color var(--fast) var(--ease), opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.tdetail__star svg {
  width: 22px;
  height: 22px;
}

.tdetail__star.is-on {
  color: var(--amber);
  opacity: 1;
}

.tdetail__star:active {
  transform: scale(0.9);
}

.tdetail__meta {
  margin-top: 12px;
}

.statuschip {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: var(--radius-pill);
  font-size: var(--t-12);
  font-weight: 700;
}

.statuschip--todo {
  background: var(--card-2);
  color: var(--muted);
}

.statuschip--doing {
  background: var(--green-soft);
  color: var(--green-dk);
}

.statuschip--done {
  background: var(--amber-soft);
  color: var(--on-amber-soft);
}

.tdetail__cardhead {
  margin: 0;
  font-size: var(--t-15);
  font-weight: 700;
}

.tdetail__subhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.tdetail__subcount {
  color: var(--muted);
  font-size: var(--t-12);
}

.tdetail__empty {
  margin: 0;
  color: var(--muted);
  font-size: var(--t-13);
}

.tdetail__notebody {
  margin: 0;
  white-space: pre-wrap;
  line-height: 1.6;
}

/* Цепочка вверх: цель → план → задача. Вложенность показываем отступом, а не
   стрелками: стрелка между целью и планом означала бы «план ведёт к этой цели»,
   а это верно не всегда (см. chainSection в task.js) — у разорванной цепочки
   звенья стоят в один отступ и никакой связи не изображают. */
.chain {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

.chain__step {
  display: flex;
  gap: 10px;
  align-items: center;
}

.chain__step--in {
  padding-left: 20px;
}

.chain__step--in2 {
  padding-left: 40px;
}

.chain__ic {
  display: grid;
  flex: none;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-btn);
  background: var(--green-soft);
  color: var(--green-dk);
}

.chain__ic svg {
  width: 16px;
  height: 16px;
}

/* Последнее звено — там, где человек и стоит. Приглушено: это не место, куда
   можно перейти, а отметка «вы здесь». */
.chain__step--now .chain__ic {
  background: var(--line);
  color: var(--muted);
}

.chain__body {
  min-width: 0;
}

.chain__name {
  display: block;
  overflow: hidden;
  color: inherit;
  font-size: var(--t-13);
  font-weight: 600;
  text-decoration: none;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chain__sub {
  display: block;
  color: var(--muted);
  font-size: var(--t-12);
}

.tdetail__chain .dlink {
  margin-top: 10px;
}

.tdetail__bar {
  height: 6px;
  margin-bottom: 12px;
  border-radius: 999px;
  background: var(--card-2);
  overflow: hidden;
}

.tdetail__bar span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--green-dk);
  transition: width var(--slow) var(--ease);
}

.tdetail__stlist {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tdetail__strow {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 8px 4px;
}

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

.tdetail__stcheck {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  flex: none;
  border: 1.5px solid var(--line);
  border-radius: 50%;
  color: transparent;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease), color var(--fast) var(--ease);
}

.tdetail__stcheck svg {
  width: 15px;
  height: 15px;
}

.tdetail__stcheck[aria-pressed='true'] {
  border-color: var(--green-dk);
  background: var(--green-dk);
  color: var(--on-green);
}

.tdetail__sttext {
  flex: 1;
  min-width: 0;
}

.tdetail__sttext.is-done {
  color: var(--muted);
  text-decoration: line-through;
}

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

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

.tdetail__del {
  color: var(--red-ink);
}

.starsread {
  display: inline-flex;
  gap: 2px;
}

.starsread__s {
  color: var(--muted);
  opacity: 0.35;
}

.starsread__s svg {
  width: 15px;
  height: 15px;
}

.starsread__s.is-on {
  color: var(--green-dk);
  opacity: 1;
}

@media (min-width: 1100px) {
  .tdetail {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 24px;
    align-items: start;
  }
}

/* ── Вложения задачи ──────────────────────────────────────────── */

.filerow {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card-2);
}

.filerow__icon {
  display: grid;
  flex: none;
  width: 22px;
  height: 22px;
  color: var(--muted);
  place-items: center;
}

.filerow__body {
  flex: 1;
  min-width: 0;
}

/* Имя файла может быть длинным и без пробелов — многоточие вместо разрыва
   карточки. */
.filerow__name {
  display: block;
  overflow: hidden;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.filerow__sub {
  display: block;
  color: var(--muted);
  font-size: var(--t-12);
}

/* Кнопки строки файла мельче обычных: их две, и вместе с именем они должны
   помещаться в ширину телефона. */
.filerow .iconbtn {
  width: 36px;
  height: 36px;
  flex: none;
}

.filerow .iconbtn svg {
  width: 18px;
  height: 18px;
}

/* Полоса загрузки. Показывает долю отправленного — на файле в несколько
   мегабайт это разница между «работает» и «зависло». */
.upload__track {
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--card-2);
  overflow: hidden;
}

.upload__bar {
  width: 0;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--green);
  transition: width var(--fast) linear;
}

.upload__label {
  margin-top: 6px;
  color: var(--muted);
  font-size: var(--t-12);
  text-align: center;
}

/* ── Правовые документы ───────────────────────────────────────── */

.legal {
  margin-top: 12px;
  padding-bottom: 8px;
}

.legal__lead {
  color: var(--muted);
  font-size: var(--t-13);
}

/* Оговорка про черновик — заметная, но не тревожная: это предупреждение,
   а не ошибка. */
.legal__note {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  margin-top: 12px;
  padding: 12px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--amber-soft);
  color: var(--on-amber-soft);
  font-size: var(--t-13);
}

.legal__note svg {
  width: 18px;
  height: 18px;
  flex: none;
  margin-top: 1px;
}

.legal__h {
  margin-top: 22px;
  font-size: var(--t-16);
  font-weight: 700;
}

.legal__p {
  margin-top: 8px;
  line-height: 1.55;
}

.legal__list {
  margin-top: 8px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.legal__list li {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  line-height: 1.5;
}

.legal__list svg {
  width: 16px;
  height: 16px;
  flex: none;
  margin-top: 3px;
  color: var(--green);
}

.legal__date {
  margin-top: 24px;
  color: var(--muted);
  font-size: var(--t-12);
}

/* ── Тема ─────────────────────────────────────────────────────── */

.themes {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
  margin-top: 12px;
}

/* Плитка — образец самой палитры: два её цвета мягким переходом. Показывать
   тему названием, а не цветом, значит просить выбрать вслепую. */
.themetile {
  position: relative;
  display: flex;
  gap: 12px;
  align-items: center;
  width: 100%;
  min-height: 92px;
  padding: 14px 16px;
  border: 2px solid var(--line);
  border-radius: var(--radius-card);
  background: linear-gradient(135deg, var(--tone) 0%, var(--tone2) 100%);
  text-align: left;
  transition: border-color var(--fast) var(--ease), transform var(--fast) var(--ease);
}

.themetile:active {
  transform: scale(0.99);
}

.themetile--on {
  border-color: var(--green-dk);
}

/* Плитка красится своей палитрой, а не текущей темой, поэтому буквы на ней
   задаются здесь же: иначе тёмная плитка в светлой теме получила бы тёмный
   текст на тёмном фоне. */
.themetile__name {
  display: block;
  color: #2B302A;
  font-size: var(--t-16);
  font-weight: 700;
}

.themetile__hint {
  display: block;
  margin-top: 2px;
  color: #5F6559;
  font-size: var(--t-13);
}

.themetile--dark .themetile__name {
  color: #E9EFE4;
}

.themetile--dark .themetile__hint {
  color: #A2B29A;
}

.themetile__art {
  display: grid;
  flex: none;
  width: 34px;
  height: 34px;
  color: #6E8B5B;
  place-items: center;
}

.themetile--dark .themetile__art {
  color: #8FB27A;
}

.themetile__art svg {
  width: 24px;
  height: 24px;
}

.themetile__body {
  flex: 1;
  min-width: 0;
}

.themetile__check {
  display: grid;
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--green);
  color: #fff;
  place-items: center;
}

.themetile__check svg {
  width: 16px;
  height: 16px;
}

/* ── Резервное копирование ────────────────────────────────────── */

/* Знак «под защитой» — облако со щитом. Своими путями, а не картинкой:
   файл пришлось бы держать в четырёх вариантах под четыре темы. */
.bart {
  display: block;
  flex: none;
  width: 96px;
  height: 72px;
}

.bart svg {
  width: 100%;
  height: 100%;
}

.bart__cloud {
  fill: var(--green-soft);
}

.bart__shield {
  fill: var(--green-dk);
}

.bart__tick {
  stroke: var(--on-green);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Последняя копия и кнопка рядом. */
.bmake {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin-top: 14px;
}

.bmake__label {
  display: block;
  color: var(--muted);
  font-size: var(--t-13);
}

.bmake__value {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-top: 2px;
  font-size: var(--t-16);
  font-weight: 700;
}

/* «Успешно» — не украшение: появляется, только когда копия вправду лежит на
   Диске, то есть пришла в списке оттуда. */
.btag {
  flex: none;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  background: var(--green-soft);
  color: var(--green-dk);
  font-size: var(--t-12);
  font-weight: 700;
}

.bsub {
  margin-top: 14px;
  margin-bottom: 8px;
  color: var(--muted);
  font-size: var(--t-13);
}

/* Список копий. Выбор и восстановление разведены: нажатие на строку ничего не
   заменяет, а только помечает. Необратимое действие не должно начинаться от
   попадания пальцем в строку списка. */
.bcopies {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.bcopy {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px 4px 4px;
  border: 1px solid var(--line);
  border-radius: var(--radius-btn);
  background: var(--card);
}

.bcopy.is-on {
  border-color: var(--green);
  background: var(--green-soft);
}

.bcopy__pick {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  min-height: var(--tap);
  padding: 6px;
  text-align: left;
}

.bcopy__mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1.5px solid var(--line);
  border-radius: 50%;
  background: var(--card);
  color: var(--on-green);
}

.bcopy__mark svg {
  width: 13px;
  height: 13px;
  opacity: 0;
}

.bcopy.is-on .bcopy__mark {
  border-color: var(--green);
  background: var(--green);
}

.bcopy.is-on .bcopy__mark svg {
  opacity: 1;
}

.bcopy__body {
  min-width: 0;
}

.bcopy__when {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-15);
}

.bcopy__sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: var(--t-12);
}

.bcopy__del {
  flex: none;
  color: var(--muted);
}

.bcopy__del:hover {
  color: var(--red);
}

.brestore {
  margin-top: 14px;
}

.brestore[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Пояснение со значком. Значок не сжимается и равняется по первой строке:
   текст часто в две. */
.bnote {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  color: var(--muted);
  font-size: var(--t-12);
  line-height: 1.45;
}

.bnote svg {
  flex: none;
  width: 15px;
  height: 15px;
  margin-top: 1px;
}

/* Что входит в копию. */
.bwhat {
  display: grid;
  gap: 10px;
}

.bwhat li {
  display: flex;
  gap: 10px;
  align-items: center;
  font-size: var(--t-15);
}

.bwhat svg {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--green-dk);
}

/* Заслон — на месте экрана, а не поверх него (почему — в backup.js). */
.bgate {
  display: grid;
  place-items: center;
  padding-top: 12px;
}

.bgate__card {
  width: 100%;
  max-width: 420px;
  padding: 26px 22px 18px;
  text-align: center;
}

.bgate__logo {
  display: inline-grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--card-2);
}

.bgate__logo svg {
  width: 28px;
  height: 28px;
}

.bgate__title {
  margin-top: 12px;
  font-size: var(--t-20);
  font-weight: 700;
}

.bgate__text {
  margin-top: 6px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.5;
}

.bgate__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 18px 0;
  text-align: left;
}

.bgate__list li {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.bgate__list li > span:last-child {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.bgate__list strong {
  font-size: var(--t-15);
}

.bgate__list li > span:last-child > span {
  color: var(--muted);
  font-size: var(--t-12);
  line-height: 1.45;
}

.bgate__ic {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-btn);
  background: var(--green-soft);
  color: var(--green-dk);
}

.bgate__ic svg {
  width: 17px;
  height: 17px;
}

.bgate__go {
  gap: 8px;
}

.bgate__go svg {
  width: 18px;
  height: 18px;
}

.bgate__foot {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-top: 12px;
  color: var(--muted);
  font-size: var(--t-12);
}

.bgate__foot svg {
  flex: none;
  width: 14px;
  height: 14px;
}

/* Телефонная шапка экрана. */
.bmob {
  margin-top: 12px;
  text-align: center;
}

.bmob .bart {
  margin: 0 auto;
}

.bmob__title {
  margin-top: 8px;
  font-size: var(--t-16);
  font-weight: 700;
}

.bmob__text {
  margin-top: 4px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.5;
}

.bmob__last {
  margin-top: 14px;
  padding: 12px;
  border-radius: var(--radius-btn);
  background: var(--card-2);
  text-align: left;
}

.bmob__last .bmake__value {
  justify-content: flex-start;
}

/* Широкий экран. */
.bdash {
  display: none;
}

@media (min-width: 1100px) {
  .bdash {
    display: block;
  }

  /* flex-direction обязательно: у .dcard оно column, и одного display: flex
     мало — знак вставал над текстом, а не слева от него. */
  /* Через .bdash, а не просто .bhero: у .dcard тоже есть flex-direction: column,
     и оно объявлено ниже по файлу — при равной весомости побеждало оно,
     и знак вставал над текстом вместо того, чтобы стоять слева. */
  .bdash .bhero {
    display: flex;
    flex-direction: row;
    gap: 20px;
    align-items: center;
  }

  .bdash .bhero__body {
    flex: 1;
    min-width: 0;
  }

  .bhero__body h2 {
    font-size: var(--t-20);
    font-weight: 700;
  }

  .bhero__body p {
    margin-top: 6px;
    max-width: 60ch;
    color: var(--muted);
    font-size: var(--t-13);
    line-height: 1.5;
  }

  .bhero__list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 12px;
  }

  .bhero__list li {
    display: flex;
    gap: 8px;
    align-items: center;
    font-size: var(--t-13);
  }

  .bhero__list svg {
    flex: none;
    width: 16px;
    height: 16px;
    color: var(--green-dk);
  }

  /* Две колонки в боковой карточке тесны — оставляем одну, как у остальных
     списков справа. */
  .bdash .bwhat {
    grid-template-columns: 1fr;
  }
}

/* ── Декор и мелочи ───────────────────────────────────────────── */

/* Листья только на спокойных экранах. В плотных списках их нет. */
.leaves {
  position: absolute;
  z-index: -1;
  color: var(--green);
  opacity: 0.14;
  pointer-events: none;
}

.leaves--tr {
  top: -14px;
  right: -18px;
  width: 150px;
  transform: scaleX(-1);
}

.leaves--bl {
  bottom: -20px;
  left: -22px;
  width: 130px;
}

.leaves--tl {
  top: -10px;
  left: -26px;
  width: 140px;
}

.toast {
  position: fixed;
  bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 16px);
  left: 50%;
  /* Выше подтверждения (61) и листа (41): всплывашка сообщает о том, что
     произошло, и не должна оказаться под чем-либо. */
  z-index: 70;
  max-width: calc(var(--column) - 32px);
  padding: 11px 16px;
  border-radius: var(--radius-btn);
  background: var(--ink);
  color: var(--bg);
  font-size: var(--t-13);
  box-shadow: var(--shadow-lift);
  transform: translateX(-50%);
  animation: fade var(--fast) var(--ease);
}

.toast--error {
  background: var(--red);
  color: #fff;
}

.hint {
  margin: 8px 2px 0;
  color: var(--muted);
  font-size: var(--t-12);
}

/* ── Финансы: редизайн и общий бюджет ─────────────────────────── */

.fin__hero {
  margin: 2px 2px 12px;
  color: var(--muted);
  font-size: var(--t-13);
}

.fin__balhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.fin__eye svg {
  width: 20px;
  height: 20px;
  color: var(--muted);
}

.fin__week {
  margin-top: 6px;
  font-size: var(--t-13);
  font-weight: 600;
}

.fin__week--up {
  color: var(--green-dk);
}

.fin__week--down {
  color: var(--red-ink);
}

/* Парные карточки Доходы/Расходы */
.fin__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 12px;
}

.fin__io {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fin__iolabel {
  color: var(--muted);
  font-size: var(--t-12);
}

.fin__ioval {
  font-size: var(--t-20, 20px);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.fin__io--in .fin__ioval {
  color: var(--green-dk);
}

.fin__io--out .fin__ioval {
  color: var(--red-ink);
}

/* Бюджет на месяц */
.budget {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 12px;
}

.budget__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}

.budget__title {
  font-weight: 600;
}

.budget__pct {
  font-size: var(--t-13);
  font-weight: 700;
  color: var(--muted);
}

.budget__pct--over {
  color: var(--red-ink);
}

.budget__track {
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--line);
  overflow: hidden;
}

.budget__track span {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--green);
}

.budget__track span.budget__fill--over {
  background: var(--red-ink);
}

.budget__nums {
  font-size: var(--t-13);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.budget--empty {
  gap: 10px;
}

/* Приглашение к созданию общего бюджета */
.fin__cta {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
  padding: 24px 18px;
}

.fin__cta .badge {
  width: 52px;
  height: 52px;
}

.fin__cta .badge svg {
  width: 26px;
  height: 26px;
}

.fin__ctatitle {
  font-size: var(--t-18, 18px);
  font-weight: 700;
}

.fin__ctatext {
  color: var(--muted);
  font-size: var(--t-13);
  max-width: 32ch;
}

.fin__cta .btn {
  margin-top: 4px;
}

/* Шапка вкладки общего бюджета */
.fin__hhbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 12px 2px 10px;
}

.fin__hhname {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  font-weight: 700;
}

.fin__hhname svg {
  width: 20px;
  height: 20px;
  color: var(--green-dk);
}

.linkbtn {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  color: var(--muted);
  font-size: var(--t-13);
  font-weight: 600;
}

.linkbtn svg {
  width: 16px;
  height: 16px;
}

/* Аватар-инициалы участника */
.avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--green-soft);
  color: var(--green-dk);
  font-size: var(--t-13);
  font-weight: 700;
}

.crown {
  width: 15px;
  height: 15px;
  color: var(--amber-ink);
  vertical-align: -2px;
}

/* Сумма + тег в строке транзакции */
.fin__cell {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
}

.fin__tag {
  font-size: var(--t-11, 11px);
  color: var(--muted);
}

.fin__amount--tr {
  color: var(--muted);
}

/* Группы по дням на экране транзакций */
.txday {
  margin-top: 16px;
}

.txday__head {
  margin: 0 2px 8px;
  font-size: var(--t-12);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

/* Экран приглашения */
.invite {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  text-align: center;
  padding: 16px 6px;
}

.invite__art {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--green-soft);
  color: var(--green-dk);
}

.invite__art svg {
  width: 30px;
  height: 30px;
}

.invite__title {
  font-size: var(--t-18, 18px);
  font-weight: 700;
}

.invite__text {
  color: var(--muted);
  font-size: var(--t-13);
  max-width: 34ch;
}

.invite__code {
  margin: 6px 0;
  padding: 14px 22px;
  border: 1px dashed var(--line);
  border-radius: var(--radius-card);
  background: var(--card-2);
  font-size: var(--t-28);
  font-weight: 700;
  letter-spacing: 0.22em;
  font-variant-numeric: tabular-nums;
}

.invite__row {
  display: flex;
  gap: 10px;
}

.invite__note {
  max-width: 36ch;
}

/* Права участника — переключатели */
.permlist {
  display: flex;
  flex-direction: column;
}

.permrow {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: var(--tap);
  padding: 10px 0;
  text-align: left;
}

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

.permrow__name {
  font-size: var(--t-15);
}

.permrow[disabled] {
  opacity: 0.55;
}

/* Переключатель (свой, компактный) */
.toggle {
  flex: none;
  width: 44px;
  height: 26px;
  padding: 3px;
  border-radius: var(--radius-pill);
  background: var(--line);
  transition: background var(--fast) var(--ease);
}

.toggle__dot {
  display: block;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--card);
  box-shadow: var(--shadow);
  transition: transform var(--slow) var(--ease);
}

.toggle--on,
[aria-pressed='true'] > .toggle {
  background: var(--green);
}

.toggle--on .toggle__dot,
[aria-pressed='true'] > .toggle .toggle__dot {
  transform: translateX(18px);
}

/* Заголовок группы настроек */
.settings__group {
  margin: 22px 2px 8px;
  font-size: var(--t-13);
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* ── Широкий экран ────────────────────────────────────────────── */

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

/* На узком экране бокового меню нет вовсе. Не «спрятано прозрачностью», а
   именно нет: скринридер не должен читать десять ссылок, которых не видно. */
.side {
  display: none;
}

@media (min-width: 1100px) {
  /* Страница не прокручивается вовсе: приложение занимает окно, листается
     только колонка содержимого. Без этого оставалась щель в несколько десятков
     пикселей, и всё приложение слегка ездило вверх-вниз колесом мыши —
     раскладка переставала быть неподвижной. */
  html,
  body {
    height: 100%;
    overflow: hidden;
  }

  /* До входа меню пустое — экран входа не раздел приложения. Колонку под него
     в этот момент держать нельзя: получилась бы мёртвая полоса слева. */
  .side:empty {
    display: none;
  }

  .app:has(.side:empty) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      'bar'
      'view';
  }

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

     Это же и есть «фиксированная раскладка»: при изменении размера окна
     меняется только высота прокручиваемой колонки, а меню, шапка и профиль
     стоят на своих местах. */
  .app {
    display: grid;
    grid-template-columns: var(--side-w) minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      'side bar'
      'side view';
    max-width: var(--desk-max);
    /* Воздух вокруг вычитаем из высоты: иначе страница всегда прокручивалась бы
       на эти 32px, даже когда содержимое умещается целиком. */
    height: calc(100dvh - var(--desk-gap) * 2);
    /* Обязательно: телефонное правило выше задаёт min-height: 100dvh, а
       min-height всегда сильнее height — без сброса приложение оставалось бы
       ровно в высоту окна и уезжало бы вниз вместе с отступами. */
    min-height: 0;
    margin: var(--desk-gap) auto;
    border: 1px solid var(--line);
    border-radius: 24px;
    /* Режет углы: содержимое, доехавшее до низа, иначе вылезало бы за
       скругление прямым краем. */
    overflow: hidden;
    box-shadow: var(--shadow-lift);
  }

  /* Прокручивается только эта колонка. min-height: 0 обязателен — без него
     элемент сетки отказывается быть ниже своего содержимого, и прокрутка
     снова уезжает на всю страницу. */
  .view {
    min-height: 0;
    overflow-y: auto;
  }

  /* Меню стоит на месте, пока листается содержимое: уходить наверх ради
     перехода в другой раздел — лишняя работа для человека. Прилипание больше
     не нужно — колонка и так во всю высоту приложения, её растягивает сетка.
     Отступа снизу нет: карточка профиля стоит вплотную к нижнему краю окна,
     свой воздух она держит внутри себя. */
  .side {
    grid-area: side;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding: 20px 12px 0;
    border-right: 1px solid var(--line);
  }

  .side__brand {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 4px 8px 20px;
  }

  .side__brand img {
    border-radius: 10px;
  }

  .side__brand strong {
    display: block;
    font-size: var(--t-16);
    font-weight: 700;
  }

  .side__brand span {
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* flex: 1 — чтобы свободное место забирал список разделов, а не отступы
     нижних кнопок. Раньше вниз её толкал margin-top: auto у карточки
     профиля, но теперь над ней есть вторая кнопка, и два auto разорвали
     бы их по разным концам свободного места. */
  .side__nav {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    overflow-y: auto;
  }

  /* Не пункт меню и не карточка профиля, а что-то между: ведёт не на
     экран, а к действию с этим компьютером. Поэтому рисуется как пункт,
     но без подсветки «вы здесь» — в нём нельзя находиться. */
  .side__install {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--tap);
    margin-top: 6px;
    padding: 0 12px;
    border-radius: var(--radius-btn);
    color: var(--muted);
    font-size: var(--t-15);
    text-align: left;
  }

  .side__install:hover {
    background: var(--card-2);
    color: var(--ink);
  }

  .side__install svg {
    flex: none;
    width: 20px;
    height: 20px;
  }

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

  /* Подпись группы. Мелкая и приглушённая намеренно: она делит список, но не
     соперничает с самими разделами — читать её каждый раз не нужно, нужна она
     ровно один раз, чтобы понять устройство. */
  .side__cap {
    margin: 14px 12px 4px;
    color: var(--muted);
    font-size: var(--t-12);
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
  }

  /* Первая группа идёт сразу под логотипом — лишний отступ сверху ей не нужен. */
  .side__group:first-child + .side__cap {
    margin-top: 10px;
  }

  .side__item {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: var(--tap);
    padding: 0 12px;
    border-radius: var(--radius-btn);
    color: var(--ink);
    text-decoration: none;
  }

  .side__item:hover {
    background: var(--card-2);
  }

  .side__item[aria-current='page'] {
    background: var(--green-soft);
    color: var(--green-dk);
    font-weight: 700;
  }

  /* Размер обязателен: иконки — инлайновый SVG без атрибутов width/height,
     и без правила они разворачиваются во всю доступную ширину. */
  .side__item svg {
    flex: none;
    width: 20px;
    height: 20px;
  }

  .side__badge {
    margin-left: auto;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    background: var(--card-2);
    color: var(--muted);
    font-size: var(--t-12);
    font-weight: 700;
  }

  .side__item[aria-current='page'] .side__badge {
    background: var(--card);
  }

  /* Профиль прижат к низу — он не раздел, а «кто я здесь».
     Теперь это кнопка, а не ссылка: она открывает меню, а не ведёт на экран.
     width: 100% обязателен — кнопка, в отличие от блочной ссылки, шириной по
     содержимому, и подпись перестала бы ужиматься многоточием. */
  .side__me {
    display: flex;
    align-items: center;
    gap: 10px;
    width: calc(100% + 24px);
    /* Вылезаем на боковые отступы меню: карточка идёт от края до края, как
       полоса, а не как ещё один пункт списка. */
    margin: auto -12px 0;
    padding: 12px 20px 14px;
    border-top: 1px solid var(--line);
    /* Скругление повторяет нижний левый угол приложения — иначе подсветка при
       наведении вылезала бы за него прямым углом. Радиус на пиксель меньше:
       у окна есть рамка в 1px. */
    border-bottom-left-radius: 23px;
    color: var(--ink);
    text-align: left;
    text-decoration: none;
  }

  .side__me:hover {
    background: var(--card-2);
  }

  /* Галочка вниз — обещание, что откроется меню, а не переход на экран. */
  .side__me > svg {
    flex: none;
    width: 18px;
    height: 18px;
    color: var(--muted);
  }

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

  .side__me-body strong {
    display: block;
    font-size: var(--t-15);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .side__me-body span {
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* Шапка: заголовок уезжает влево. По центру он держался потому, что рядом
     стояли две кнопки по 44px, — на широком экране этой рамки нет. */
  .appbar {
    grid-area: bar;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 8px;
    padding: 20px 28px 8px;
  }

  .appbar__title {
    text-align: left;
  }

  /* «Гамбургер» открывал разделы на телефоне. Здесь они все на виду слева —
     кнопка означала бы действие, которого нет. */
  .appbar [data-action='menu'] {
    display: none;
  }

  .appbar__title h1 {
    font-size: var(--t-28);
  }

  .view {
    grid-area: view;
    padding: 8px 28px 32px;
  }

  /* Нижняя панель — навигация для большого пальца. На десктопе её роль
     полностью забирает меню слева. */
  .tabbar {
    display: none;
  }

  /* Экраны свёрстаны в одну колонку под телефон. На широком экране такая
     колонка растянулась бы на весь монитор, и строка списка стала бы
     нечитаемой лентой. Ограничиваем ширину содержимого, а не окна. */
  .view > * {
    max-width: var(--read-max);
  }

  /* Сводный экран (Главная) занимает всю ширину: свою сетку карточек он строит
     сам, здесь нужно только снять ограничение читаемой строки. */
  .view--wide > * {
    max-width: none;
  }

  /* Вход — исключение: поля во всю ширину монитора выглядят нелепо, и глазу
     негде зацепиться. Держим прежнюю узкую колонку по центру. */
  .auth {
    max-width: none;
  }

  .auth > * {
    width: 100%;
    max-width: var(--column);
    margin-inline: auto;
  }
}

/* ── Быстрая панель (окно оболочки) ───────────────────────────── */

/* Отдельная страница в своём окне без рамки. Живёт вне медиазапроса широкого
   экрана: размер окна задаёт оболочка, и от ширины монитора он не зависит. */

/* Окно панели прозрачное: карточка не занимает его целиком — слева от неё
   висит круглая ручка, а вокруг нужен воздух, чтобы читалась тень. */
.quick-body {
  height: 100dvh;
  overflow: hidden;
  background: transparent;
}

.qdrawer {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 100dvh;
  padding: 10px 12px 10px 0;
}

/* Ручка с плюсом из макета. Прижата к вертикальной середине — там же, где
   курсор пересёк край экрана, и глазу не нужно её искать. */
.qdrawer__grip {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border: 0;
  border-radius: 50%;
  background: var(--green-dk);
  color: var(--on-green);
  cursor: pointer;
  box-shadow: var(--shadow-lift);
}

.qdrawer__grip:hover {
  background: var(--green-press);
}

.qdrawer__grip svg {
  width: 20px;
  height: 20px;
}

/* Обязательно внутри .quick-body: голый `.quick` уже занят сеткой «Быстрого
   доступа» на Главной, и это правило (оно ниже по файлу) её перебивало —
   четыре плитки вытягивались в столбик на всю высоту окна. Одно имя на два
   разных блока; привязка к странице панели разводит их обратно. */
.quick-body .quick {
  flex: 1;
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 14px 16px 16px;
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--bg);
  box-shadow: var(--shadow-lift);
}

/* Затемнение под вопросом «закрыть и потерять набранное?» гасит только карточку.
   Обычный `inset: 0` залил бы всё окно, а оно у панели прозрачное и заметно
   больше карточки: слева колонка под ручку с плюсом, по краям — запас под тень.
   Тёмный полупрозрачный прямоугольник по этому запасу лёг бы прямо на рабочий
   стол. Отступы повторяют раскладку .qdrawer: 36px ручка + 10px зазор слева,
   его padding — с остальных сторон. */
.quick-body .confirm__scrim {
  inset: 10px 12px 10px 46px;
  border-radius: 16px;
}

/* Всплывашка о вложениях. Базовое правило отсчитывает низ от нижней панели
   вкладок, а в панели её нет — сообщение висело бы в пустоте. Растягиваем по
   ширине карточки вместо центрирования по окну: окно шире карточки на колонку
   под ручку с плюсом, и «по центру окна» оказалось бы левее центра карточки. */
.quick-body .toast {
  bottom: 26px;
  left: 46px;
  right: 12px;
  max-width: none;
  transform: none;
  text-align: center;
}

/* Окно без рамки не двигается мышью само: перетаскивание задаём заголовку.
   Кнопку закрытия из этой области исключаем, иначе клик по ней превращался бы
   в попытку потащить окно. */
.quick__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-bottom: 10px;
  -webkit-app-region: drag;
}

.quick__head h1 {
  font-size: var(--t-16);
  font-weight: 700;
}

.quick__head .iconbtn {
  -webkit-app-region: no-drag;
  width: 32px;
  height: 32px;
}

.quick__form {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  overflow-y: auto;
}

.quick__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}

.quick__error {
  color: var(--on-red-soft);
  background: var(--red-soft);
  padding: 8px 10px;
  border-radius: var(--radius-btn);
  font-size: var(--t-13);
}

.quick__hint {
  color: var(--muted);
  font-size: var(--t-12);
  text-align: center;
}

/* ── Вход на широком экране ───────────────────────────────────── */

/* Промо-панель и заголовок карточки есть в разметке всегда, но на телефоне
   они не нужны: место дорогое, а человек уже решил войти. */
.auth__promo,
.auth__welcome {
  display: none;
}

@media (min-width: 1100px) {
  /* Две половины: слева рассказ, справа форма. Промо намеренно шире — в нём
     картинка и три пункта текста, форме такая ширина только вредила бы. */
  .auth {
    display: grid;
    grid-template-columns: 1.15fr 1fr;
    align-items: center;
    gap: 32px;
    padding: 32px;
  }

  .auth__promo {
    display: block;
    padding: 0 32px;
    text-align: center;
  }

  .auth__promo .auth__logo {
    margin-inline: auto;
  }

  .auth__promo .auth__brand {
    font-size: var(--t-28);
  }

  .auth__facts {
    display: flex;
    flex-direction: column;
    gap: 18px;
    max-width: 380px;
    margin: 32px auto 0;
    text-align: left;
  }

  .auth__fact {
    display: flex;
    align-items: flex-start;
    gap: 14px;
  }

  /* Кружок светлее фона, а не зеленее его: промо стоит прямо на фоне страницы,
     и --green-soft на нём почти неразличим — иконки висели бы в воздухе. */
  .auth__fact-icon {
    flex: none;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--card);
    color: var(--green-dk);
  }

  .auth__fact-icon svg {
    width: 22px;
    height: 22px;
  }

  .auth__fact strong {
    display: block;
    font-weight: 700;
  }

  .auth__fact strong + span {
    color: var(--muted);
    font-size: var(--t-13);
  }

  /* Форма становится карточкой: на пустом фоне ей нужны границы, иначе поля
     висят в воздухе посреди окна. */
  .auth__box {
    padding: 36px 32px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow-lift);
  }

  /* Логотип, название и слоган переехали в промо-панель слева. Оставлять их и
     в карточке значило бы показать одно и то же дважды. */
  .auth__box .auth__logo,
  .auth__box .auth__brand,
  .auth__box .auth__tagline {
    display: none;
  }

  .auth__welcome {
    display: block;
    margin-bottom: 24px;
    text-align: center;
  }

  /* Подзаголовок регистрации на телефоне живёт в .auth__sub, а здесь тот же
     текст стоит внутри .auth__welcome. Показывать оба — написать одно и то же
     дважды подряд. */
  .auth__sub {
    display: none;
  }

  /* Шапка приложения до входа лишняя: заголовок уже есть в карточке, а возврат
     ко входу даёт ссылка под формой. */
  .app:has(.side:empty) .appbar {
    display: none;
  }

  .auth__welcome h1 {
    font-size: var(--t-28);
    font-weight: 700;
  }

  .auth__welcome p {
    margin-top: 4px;
    color: var(--muted);
  }

  /* Фоновая сцена нарисована под узкую колонку: горы и солнце складываются там
     в одну картинку. На широком окне она разъезжается — солнце повисает
     отдельным кружком, горы съёживаются холмом по центру. Декора хватает и без
     неё: листья по верхним углам остаются. */
  .auth .scene {
    display: none;
  }

  /* Подпись внизу окна, под обеими колонками. */
  .auth__legal {
    grid-column: 1 / -1;
    color: var(--muted);
    font-size: var(--t-12);
    text-align: center;
  }

  .auth__legal span {
    display: block;
  }
}

/* На телефоне подпись остаётся, но скромной строкой под формой. */
.auth__legal {
  margin-top: 20px;
  color: var(--muted);
  font-size: var(--t-12);
  text-align: center;
}

/* Две строки, а не одна: рядом инлайном «© 2026 Феникс-Планер» и «Все права
   защищены» читаются как одно слипшееся предложение без разделителя. */
.auth__legal span {
  display: block;
}

/* Согласие с условиями. Галочка переиспользует вид «Запомнить меня» с экрана
   входа — это один и тот же элемент, и выглядеть он обязан одинаково. */
.auth__agree {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: var(--t-13);
  text-align: left;
  cursor: pointer;
}

.auth__agree input {
  position: absolute;
  opacity: 0;
}

/* Подсказка под полем пароля, а не общей строкой внизу формы: она относится
   к конкретному полю, и стоять должна рядом с ним. */
.auth__hint--under {
  margin-top: -4px;
  text-align: left;
  font-size: var(--t-12);
}

/* ── Сводка Главной (широкий экран) ───────────────────────────── */

/* Сводка и мобильные секции Главной меняются местами по ширине: до 1100px
   работает прежняя Главная, после — раскладка с макета. Обе живут в одной
   разметке, второй сборки нет. */
.dash {
  display: none;
}

@media (min-width: 1100px) {
  .dash {
    display: block;
  }

  /* Прежние секции Главной. На широком экране их место занимают карточки
     сводки, и показывать оба набора значило бы удвоить одно и то же. */
  .section.mob {
    display: none;
  }

  /* Шапка: приветствие слева, инструменты справа. */
  .dhead {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 18px;
  }

  .dhead h1 {
    font-size: var(--t-28);
    font-weight: 700;
  }

  .dhead p {
    margin-top: 2px;
    color: var(--muted);
  }

  /* Перенос: в узком окне шесть элементов в строку не помещаются, а шапка,
     вылезающая за край, — та же ошибка, что была в карточках. */
  .dhead__tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 10px;
  }

  /* Общий выбор периода. Стоит в шапке экрана, а не в карточке: он правит и
     «Продуктивность», и «Аналитику», и обещать обратное нельзя. Вид тот же, что
     был у карточных кнопок, — человек его уже знает. */
  .dperiod {
    display: flex;
    gap: 2px;
    padding: 2px;
    border-radius: var(--radius-pill);
    background: var(--card-2);
  }

  .dperiod button {
    padding: 5px 12px;
    border: 0;
    border-radius: var(--radius-pill);
    background: none;
    color: var(--muted);
    font: inherit;
    font-size: var(--t-12);
    cursor: pointer;
    transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
  }

  .dperiod button[aria-pressed='true'] {
    background: var(--card);
    color: var(--ink);
    font-weight: 700;
  }

  .dhead__date,
  .dhead__btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--card);
    color: var(--ink);
    font-size: var(--t-13);
    white-space: nowrap;
  }

  .dhead__btn {
    cursor: pointer;
  }

  .dhead__btn:hover {
    background: var(--card-2);
  }

  .dhead__date svg,
  .dhead__btn svg {
    width: 18px;
    height: 18px;
    color: var(--green-dk);
  }

  .dhead__add {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--green-dk);
    color: var(--on-green);
  }

  .dhead__add:hover {
    background: var(--green-press);
  }

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

     Высоты внутри ряда равные (без align-items: start). Сводка читается
     построчно, и карточки разной высоты ломают эту линию — глазу приходится
     искать, где начинается следующая. */
  .dash__grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--gap);
  }

  .dash__grid > .dcard {
    grid-column: span 4;
  }

  /* Нижний ряд. До 1400px четырём карточкам в ряд тесно — там их две. */
  .dash__grid > .dcard:nth-child(n + 7) {
    grid-column: span 6;
  }

  /* В узкой колонке нижнего ряда на строку остаётся около 230px, и «8 из 12
     задач» съедает их так, что от названия цели остаётся «Прочитать 12…».
     Название важнее: сколько задач закрыто, видно на самом экране целей, а
     нечитаемое название не говорит ничего. На макете подписи здесь тоже нет. */
  .dash__grid > .dcard:nth-child(n + 7) .drows__sub {
    display: none;
  }

  .dcard {
    display: flex;
    flex-direction: column;
    padding: var(--pad);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow);
  }

  .dcard__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 14px;
  }

  /* Название обязано ужиматься многоточием, а не толкать подпись за край
     карточки. Без min-width:0 flex-элемент отказывается сжиматься ниже своего
     содержимого — и «Финансы (Общий баланс)» выдавливало «Все ›» наружу. */
  .dcard__head h2 {
    min-width: 0;
    overflow: hidden;
    font-size: var(--t-16);
    font-weight: 700;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* «Все», «Подробнее», «Весь список» в шапках карточек. Это не ссылка
     внутри фразы, а отдельно стоящая команда, и по ней целятся мышью.
     Семнадцать пикселей высоты — тоньше двадцати четырёх, ниже которых
     цель считается мелкой. Растит её отступ, а не шрифт: надпись вторичная
     и крупнеть не должна, а попадать по ней — должна. Отрицательный
     маржин снимает прибавку с раскладки: шапка карточки не разъезжается. */
  .dcard__aside {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    min-height: 24px;
    margin: -4px 0;
    padding: 4px 6px;
    margin-right: -6px;
    border-radius: var(--radius-btn);
    color: var(--muted);
    font-size: var(--t-13);
    text-decoration: none;
    white-space: nowrap;
  }

  .dcard__aside:hover {
    background: var(--card-2);
    color: var(--ink);
  }

  .dcard__aside svg {
    width: 16px;
    height: 16px;
  }

  .dcard__pick {
    display: flex;
    gap: 2px;
    padding: 2px;
    border-radius: var(--radius-pill);
    background: var(--card-2);
  }

  .dcard__pick button {
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    color: var(--muted);
    font-size: var(--t-12);
    transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
  }

  .dcard__pick button[aria-pressed='true'] {
    background: var(--card);
    color: var(--ink);
    font-weight: 700;
  }

  .dcard__body {
    flex: 1;
  }

  .dcard__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: var(--t-13);
  }

  .dcard__foot strong {
    color: var(--green-dk);
    font-weight: 700;
  }

  /* Потолок ширины для связного текста в карточках. Сама карточка бывает
     шириной в тысячу пикселей — и пояснение разгонялось до двух сотен
     символов в строке при читаемых шестидесяти — семидесяти пяти. Глаз на
     такой длине теряет начало следующей строки. В ch, а не в пикселях:
     мера тут — символы, а не ширина экрана. */
  .dcard__empty,
  .dcard__hint,
  .dcard > .hint,
  .dcard > p.prof__note {
    max-width: 72ch;
  }

  .dcard__empty,
  .dcard__hint {
    color: var(--muted);
    font-size: var(--t-13);
  }

  .dcard__hint {
    margin-top: 12px;
  }

  /* Та же правка, что у .dcard__aside: отдельно стоящая команда обязана
     быть не тоньше двадцати четырёх пикселей по высоте. */
  .dlink {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 24px;
    margin: -4px -6px;
    padding: 4px 6px;
    border-radius: var(--radius-btn);
    color: var(--green-dk);
    font-size: var(--t-13);
    font-weight: 700;
    text-decoration: none;
  }

  .dlink:hover {
    background: var(--green-soft);
  }

  .dlink svg {
    width: 16px;
    height: 16px;
  }

  /* Кольцо процента — conic-gradient, как в Аналитике и Финансах.
     Перенос обязателен: в узком окне кольцо и три числа в строку не помещались,
     и числа уезжали за край карточки. Когда места мало, числа встают под
     кольцом и раскладываются по ширине — это по-прежнему читается. */
  .dtoday {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px 16px;
  }

  .dring {
    flex: none;
    display: grid;
    place-items: center;
    width: 112px;
    height: 112px;
    border-radius: 50%;
    background: conic-gradient(var(--green) calc(var(--p) * 1%), var(--card-2) 0);
  }

  /* Дырка должна вмещать слово «Выполнено» целиком: вылезая на кольцо, оно
     читается как обрезанное, а не как подпись. */
  .dring__hole {
    display: grid;
    place-items: center;
    width: 92px;
    height: 92px;
    border-radius: 50%;
    background: var(--card);
    text-align: center;
  }

  .dring__hole strong {
    font-size: var(--t-20);
    font-weight: 700;
  }

  .dring__hole span {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .dtoday__nums {
    /* 150px — порог переноса: ниже этого три подписи («Выполнено», «Осталось»)
       начали бы наезжать друг на друга. */
    flex: 1 1 150px;
    display: flex;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
  }

  .dtoday__nums strong {
    display: block;
    font-size: var(--t-20);
    font-weight: 700;
  }

  .dtoday__nums span {
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* График: шкала слева, поле справа. */
  .dchart {
    display: flex;
    gap: 10px;
    height: 128px;
  }

  .dchart__y {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    color: var(--muted);
    font-size: var(--t-12);
    text-align: right;
  }

  .dchart__plot {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
  }

  .dchart__plot svg {
    flex: 1;
    width: 100%;
    border-bottom: 1px solid var(--line);
  }

  /* Линия рисуется в координатах 0–100 и растягивается по ширине. Без
     non-scaling-stroke растяжение раздавило бы обводку в нитку. */
  .dchart__plot polyline {
    fill: none;
    stroke: var(--green);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
  }

  .dchart__x {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .dfin__big {
    font-size: var(--t-28);
    font-weight: 700;
  }

  .dfin__delta {
    margin-top: 2px;
    color: var(--muted);
    font-size: var(--t-13);
  }

  .dfin__delta.is-up { color: var(--green-dk); }
  .dfin__delta.is-down { color: var(--red-ink); }

  .dbar {
    display: block;
    height: 8px;
    margin-top: 14px;
    border-radius: var(--radius-pill);
    background: var(--card-2);
    overflow: hidden;
  }

  .dbar i {
    display: block;
    height: 100%;
    border-radius: var(--radius-pill);
    background: var(--green);
  }

  /* Перерасход красным: полоса, упёршаяся в конец зелёным, читается как успех. */
  .dbar i.is-over {
    background: var(--red);
  }

  .dbar__foot {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .dfin__pair {
    display: flex;
    gap: 10px;
    margin-top: 14px;
  }

  .dfin__pair > div {
    flex: 1;
    padding: 10px 12px;
    border-radius: var(--radius-btn);
    background: var(--card-2);
  }

  .dfin__pair span {
    display: block;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .dfin__pair strong {
    font-weight: 700;
  }

  .dfin__pair .is-down { color: var(--red-ink); }

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

  .drows a {
    display: flex;
    align-items: center;
    gap: 10px;
    text-decoration: none;
  }

  .drows__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .drows__ic svg {
    width: 16px;
    height: 16px;
  }

  .drows__body {
    flex: 1;
    min-width: 0;
  }

  .drows__top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
  }

  /* Название и «3 из 4 задач» — одной строкой. Отдельной строкой подпись
     добавляла к каждому ряду ещё двадцать пикселей, и карточка из пяти планов
     вырастала вдвое против макета. Сама подпись нужна: процент не говорит,
     из скольких задач он посчитан. */
  .drows__name {
    display: flex;
    align-items: baseline;
    gap: 6px;
    min-width: 0;
  }

  .drows__name > span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .drows__sub {
    flex: none;
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* В строке полоса идёт вплотную под названием: общий отступ .dbar рассчитан
     на карточку финансов, где она отделяет один блок от другого. */
  .drows .dbar {
    height: 5px;
    margin-top: 5px;
  }

  .dmedals {
    display: flex;
    gap: 8px;
  }

  .dmedals li {
    flex: 1;
    min-width: 0;
    text-align: center;
  }

  /* Внутри сводки медаль — только кружок с подписью. Своя карточка с рамкой
     здесь лишняя (карточка уже есть — сама «Награды»), а в узкой колонке
     нижнего ряда три такие карточки просто не помещались и обрезались. */
  .dmedals .medal {
    padding: 0;
    border: 0;
    background: none;
  }

  .dmedals .medal__coin {
    width: 44px;
    height: 44px;
    margin-bottom: 0;
  }

  .dmedals .medal__coin svg {
    width: 20px;
    height: 20px;
  }

  .dmedals strong {
    display: block;
    margin-top: 6px;
    font-size: var(--t-12);
    font-weight: 700;
  }

  .dmedals li > span:last-child {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .dmetrics {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
  }

  .dmetrics > div {
    padding: 10px;
    border-radius: var(--radius-btn);
    background: var(--card-2);
    text-align: center;
  }

  .dmetrics strong {
    display: block;
    margin: 2px 0;
    font-size: var(--t-20);
    font-weight: 700;
  }

  .dmetrics__k,
  .dmetrics__v {
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* Плитка без данных приглушена: она обязана отличаться от посчитанной,
     иначе прочерк читается как ноль. */
  .dmetrics > div.is-empty {
    background: transparent;
    border: 1px dashed var(--line);
  }

  .dweb svg {
    width: 100%;
    height: 140px;
  }

  .dweb line {
    stroke: var(--line);
    stroke-width: 1.5;
  }

  .dweb__node {
    fill: var(--green-soft);
    stroke: var(--line);
  }

  .dweb__core {
    fill: var(--green-dk);
  }

  .dweb text {
    fill: var(--muted);
    font-size: 9px;
    text-anchor: middle;
  }

  .dweb__goal {
    margin-top: -8px;
    color: var(--ink);
    font-size: var(--t-13);
    font-weight: 700;
    text-align: center;
  }

  /* Задача внутри сводки — строка списка, а не карточка. Своя рамка и фон у
     каждой строки внутри карточки дают рамку в рамке: на макете их разделяет
     тонкая черта, и в неё же помещается вдвое больше строк. */
  .dcard .ups {
    gap: 0;
  }

  .dcard .up {
    padding: 0;
    border: 0;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
    background: none;
  }

  .dcard .up:last-child {
    border-bottom: 0;
  }

  .dcard .up__link {
    min-height: 36px;
  }

  .dstatus {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: var(--t-12);
  }

  .dstatus__leaf svg {
    width: 18px;
    height: 18px;
    color: var(--green);
  }
}

@media (min-width: 1100px) {
  /* На Главной шапки приложения нет: её роль играет приветствие внутри самой
     сводки, а колокольчик и «плюс» переехали туда же. Две шапки подряд
     («Главная» и «Добро пожаловать») читались бы как ошибка вёрстки. */
  .app:has(.view--wide) .appbar {
    display: none;
  }

  .app:has(.view--wide) .view {
    padding-top: 24px;
  }
}

@media (min-width: 1100px) {
  /* Инструменты уезжают на свою строку, когда приветствию не хватает места.
     Иначе «Добро пожаловать, Алексей!» ломается, и эмодзи остаётся на строке
     один — выглядит как сбой вёрстки, а не как приветствие. */
  .dhead {
    flex-wrap: wrap;
  }

  .dhead h1 {
    text-wrap: balance;
  }
}

/* ── Планы на широком экране ──────────────────────────────────── */

/* До 1100px работает прежний мобильный экран, после — раскладка с макета.
   Обе живут в одной разметке. */
.pdash {
  display: none;
}

@media (min-width: 1100px) {
  .pdash {
    display: block;
  }

  /* Мобильный экран Планов: на широком его место занимает .pdash. */
  .view > .mob {
    display: none;
  }

  /* Четыре сводных показателя в ряд. */
  .pstats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--gap);
    margin-bottom: var(--gap);
  }

  .pstat {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow);
  }

  .pstat__label {
    display: block;
    color: var(--muted);
    font-size: var(--t-13);
  }

  .pstat__value {
    display: block;
    margin: 2px 0;
    font-size: var(--t-28);
    font-weight: 700;
  }

  .pstat__sub {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .pstat__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .pstat__ic svg {
    width: 22px;
    height: 22px;
  }

  /* Маленькое кольцо в карточке прогресса. */
  .dring--sm {
    width: 56px;
    height: 56px;
  }

  .dring--sm .dring__hole {
    width: 40px;
    height: 40px;
  }

  /* Список слева, сводки справа. Правая колонка фиксированной ширины: список
     планов должен получать весь остаток, а не делиться поровну. */
  .pmain {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: var(--gap);
    align-items: start;
  }

  .pside {
    display: flex;
    flex-direction: column;
    gap: var(--gap);
  }

  .ptabs {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 14px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--line);
  }

  /* Шесть фильтров в строку в узком окне не помещаются и выталкивали карточку
     за собственную рамку. Переносим на вторую строку, а не режем: спрятанный
     фильтр — это фильтр, которого для человека нет. */
  .ptabs__row {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    min-width: 0;
  }

  .ptabs__row button {
    padding: 6px 12px;
    border-radius: var(--radius-pill);
    color: var(--muted);
    font-size: var(--t-15);
    transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
  }

  .ptabs__row button[aria-pressed='true'] {
    background: var(--green-soft);
    color: var(--green-dk);
    font-weight: 700;
  }

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

  /* Покрытие ссылкой: нажатие в любое место строки открывает план.
     Обёрнуть строку в <a> нельзя — внутри есть кнопка правки, а кнопка
     внутри ссылки ведёт себя непредсказуемо. Поэтому ссылка остаётся
     на названии, а площадь ей добавляет псевдоэлемент. Кнопка правки
     поднята над покрытием ниже, иначе она бы перестала нажиматься. */
  .prow {
    position: relative;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card-2);
  }

  .prow__title::after,
  .arow__title::after {
    content: '';
    position: absolute;
    inset: 0;
  }

  .prow > .iconbtn {
    position: relative;
    z-index: 1;
  }

  .prow__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    border-radius: var(--radius-btn);
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .prow__ic svg {
    width: 24px;
    height: 24px;
  }

  .prow__body {
    flex: 1;
    min-width: 0;
  }

  /* Блок, а не строчная ссылка: целью было только само название —
     девяносто шесть пикселей на строку шириной в семьсот пятьдесят
     восемь. Обёртывать в ссылку всю строку нельзя: в ней свои кнопки,
     а ссылка внутри ссылки — сломанная разметка. */
  .prow__title {
    display: block;
    padding: 3px 0;
    font-size: var(--t-16);
    font-weight: 700;
    text-decoration: none;
  }

  .prow__note {
    margin-top: 2px;
    color: var(--muted);
    font-size: var(--t-13);
    /* Описание в одну строку: список планов должен листаться взглядом, а не
       читаться абзацами. Полный текст — в карточке плана. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .prow__tags {
    display: flex;
    gap: 6px;
    margin-top: 6px;
  }

  .prow__tag {
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    background: var(--card);
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* Цель выделена среди тегов: период и «в архиве» говорят, как план устроен, а
     цель — зачем он вообще. Это разные вопросы, и одинаково серыми они читались
     бы как один список свойств. */
  .prow__tag--goal {
    display: inline-flex;
    gap: 5px;
    align-items: center;
    background: var(--green-soft);
    color: var(--green-dk);
    font-weight: 600;
  }

  .prow__tag--goal svg {
    width: 13px;
    height: 13px;
    flex: none;
  }

  .prow__right {
    flex: none;
    width: 190px;
  }

  .prow__prog {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .prow__prog > span:first-child {
    width: 42px;
    font-size: var(--t-13);
    font-weight: 700;
    text-align: right;
  }

  .prow__prog .dbar {
    flex: 1;
    margin-top: 0;
  }

  .prow__meta {
    margin-top: 6px;
    color: var(--muted);
    font-size: var(--t-12);
    text-align: right;
  }

  /* Кольцо состояний с легендой. */
  .pdonut {
    display: flex;
    align-items: center;
    gap: 14px;
  }

  .pdonut svg {
    flex: none;
    width: 96px;
    height: 96px;
  }

  .pdonut__legend {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
    font-size: var(--t-13);
  }

  .pdonut__legend li {
    display: flex;
    align-items: center;
    gap: 8px;
  }

  .pdonut__legend strong {
    margin-left: auto;
    font-weight: 700;
  }

  .pdonut__dot {
    flex: none;
    width: 10px;
    height: 10px;
    border-radius: 50%;
  }

  /* Ближайшие планы — вертикальная лента с точками. */
  .ptime {
    display: flex;
    flex-direction: column;
    gap: 14px;
  }

  .ptime li {
    position: relative;
    padding-left: 18px;
  }

  .ptime__dot {
    position: absolute;
    top: 6px;
    left: 0;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--green);
  }

  .ptime a {
    display: block;
    font-size: var(--t-15);
    text-decoration: none;
  }

  .ptime li > span:last-child {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .pquote {
    padding: 4px 8px;
    color: var(--muted);
    font-size: var(--t-15);
    font-style: italic;
    text-align: center;
  }
}

@media (min-width: 1100px) {
  /* Общее правило переносит длинные слова где угодно — иначе они вылезают за
     карточку. Названию плана это вредит: «независимость» рвётся пополам.
     Здесь места хватает, поэтому переносим только по словам. */
  .prow__title {
    overflow-wrap: normal;
  }
}

/* ── Финансы на широком экране ────────────────────────────────── */

.fdash {
  display: none;
}

@media (min-width: 1100px) {
  .fdash {
    display: block;
  }

  /* Переключатель Личные/Совместные — две кнопки, а не список: режимов ровно
     два, и выбор виден целиком. */
  .fscope {
    display: flex;
    gap: 2px;
    padding: 3px;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--card);
  }

  /* Переход, а не подмена. Экран перерисовывается целиком, и «поехавшей»
     подложке между кнопками взяться неоткуда — но цвет и фон обязаны меняться
     плавно, иначе нажатие читается как мигание, а не как ответ. */
  .fscope button {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    border-radius: var(--radius-pill);
    color: var(--muted);
    font-size: var(--t-13);
    transition:
      background var(--slow) var(--ease),
      color var(--slow) var(--ease);
  }

  /* Подсветка под курсором — только у невыбранной: у выбранной она уже есть. */
  .fscope button[aria-pressed='false']:hover {
    background: var(--card-2);
    color: var(--ink);
  }

  .fscope button svg {
    width: 18px;
    height: 18px;
  }

  .fscope button[aria-pressed='true'] {
    background: var(--green-dk);
    color: var(--on-green);
    font-weight: 700;
  }

  .fstats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--gap);
    margin-bottom: var(--gap);
  }

  .fstat {
    padding: 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow);
  }

  .fstat__label {
    color: var(--muted);
    font-size: var(--t-13);
  }

  .fstat__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin: 4px 0 2px;
  }

  .fstat__value {
    font-size: var(--t-28);
    font-weight: 700;
  }

  .fstat__sub {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .fstat__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    border-radius: var(--radius-card);
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .fstat__ic svg {
    width: 24px;
    height: 24px;
  }

  /* Доход зелёным, расход красным — и у суммы, и у подписи с процентом. */
  .fstat .is-in,
  .ftx__sum.is-in,
  .drows .is-in {
    color: var(--green-dk);
  }

  .fstat .is-out,
  .ftx__sum.is-out,
  .drows .is-out {
    color: var(--red-ink);
  }

  .fspark {
    flex: none;
    width: 92px;
    height: 40px;
  }

  .fspark polyline {
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
  }

  .fspark--in polyline { stroke: var(--green); }
  .fspark--out polyline { stroke: var(--red); }

  .fmain {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: var(--gap);
    align-items: start;
  }

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

  .fpair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--gap);
  }

  /* Таблица операций. Именно таблица, а не список: колонки Сумма, Автор и Дата
     обязаны выстраиваться друг под другом, иначе взглядом их не сравнить. */
  .ftable {
    width: 100%;
    border-collapse: collapse;
  }

  .ftable th {
    padding: 0 8px 10px;
    border-bottom: 1px solid var(--line);
    color: var(--muted);
    font-size: var(--t-12);
    font-weight: 400;
    text-align: left;
  }

  .ftable td {
    padding: 12px 8px;
    border-bottom: 1px solid var(--line);
    vertical-align: middle;
  }

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

  .ftx {
    display: flex;
    align-items: center;
    gap: 12px;
  }

  .ftx__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-btn);
    background: var(--card-2);
    color: var(--muted);
  }

  .ftx__ic svg {
    width: 20px;
    height: 20px;
  }

  .ftx__ic.is-in { background: var(--green-soft); color: var(--green-dk); }
  .ftx__ic.is-out { background: var(--red-soft); color: var(--on-red-soft); }

  .ftx__title {
    display: block;
    font-weight: 700;
  }

  .ftx__sub {
    display: block;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .ftx__sum {
    font-weight: 700;
    white-space: nowrap;
  }

  .ftx__author {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
  }

  .ftx__date {
    color: var(--muted);
    font-size: var(--t-13);
    white-space: nowrap;
  }

  .avatar--sm {
    width: 28px;
    height: 28px;
    font-size: var(--t-12);
  }

  .fmembers {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 12px;
  }

  .fmembers li {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .fmembers strong {
    display: block;
    font-size: var(--t-15);
  }

  .fmembers li > span:last-child > span {
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* Лента действий. Отдельного журнала в приложении нет — строки собираются из
     самих операций и вступлений в бюджет. */
  .fact {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .fact li {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: var(--t-13);
  }

  .fact__dot {
    flex: none;
    margin-top: 6px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--muted);
  }

  .fact__dot.is-in { background: var(--green); }
  .fact__dot.is-out { background: var(--red); }

  .fact__body {
    flex: 1;
    min-width: 0;
  }

  .fact__time {
    flex: none;
    color: var(--muted);
    font-size: var(--t-12);
  }
}

/* ── Задачи на широком экране ─────────────────────────────────── */

.tdash {
  display: none;
}

@media (min-width: 1100px) {
  .tdash {
    display: block;
  }

  .tstats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: var(--gap);
    margin-bottom: var(--gap);
  }

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

  .tstat__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 44px;
    height: 44px;
    border-radius: var(--radius-btn);
  }

  .tstat__ic svg {
    width: 22px;
    height: 22px;
  }

  .tstat__ic--green { background: var(--green-soft); color: var(--green-dk); }
  .tstat__ic--red { background: var(--red-soft); color: var(--on-red-soft); }
  .tstat__ic--amber { background: var(--amber-soft); color: var(--on-amber-soft); }
  .tstat__ic--blue { background: var(--card-2); color: var(--muted); }

  .tstat__label {
    display: block;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .tstat__body strong {
    display: block;
    font-size: var(--t-28);
    font-weight: 700;
    line-height: 1.1;
  }

  .tstat__sub {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .tgroup + .tgroup {
    margin-top: 18px;
  }

  .tgroup__head {
    margin-bottom: 8px;
    color: var(--muted);
    font-size: var(--t-13);
  }

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

  .trow {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 8px;
    border-bottom: 1px solid var(--line);
  }

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

  .trow--done .trow__title {
    color: var(--muted);
    text-decoration: line-through;
  }

  /* align-self: stretch — чтобы ссылка занимала всю высоту строки, а не
     высоту своей строки текста. Строка шестьдесят пикселей высотой,
     кликабельных из них было восемнадцать: выше и ниже текста нажатие
     не попадало никуда. Размер шрифта при этом не меняется. */
  .trow__main {
    flex: 1;
    align-self: stretch;
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    text-decoration: none;
  }

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

  .trow__cat {
    flex: none;
    padding: 2px 10px;
    border-radius: var(--radius-pill);
    background: var(--card-2);
    color: var(--muted);
    font-size: var(--t-12);
  }

  .trow__due {
    flex: none;
    width: 120px;
    color: var(--muted);
    font-size: var(--t-13);
    text-align: right;
  }

  .trow__due.is-late {
    color: var(--red-ink);
  }

  /* Квадрант вместо «высокий/средний/низкий»: приоритет в приложении задаётся
     матрицей Эйзенхауэра, и три уровня потеряли бы её смысл. */
  .trow__quad {
    flex: none;
    display: flex;
    align-items: center;
    gap: 8px;
    width: 120px;
    color: var(--muted);
    font-size: var(--t-13);
  }

  /* Календарь месяца. Подсвечены только дни, на которые что-то назначено:
     точка на каждом числе не значила бы ничего. */
  .tcal__head {
    margin-bottom: 10px;
    font-weight: 700;
    text-transform: capitalize;
  }

  .tcal__grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 4px;
    text-align: center;
  }

  .tcal__wd {
    padding-bottom: 4px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .tcal__day {
    display: grid;
    place-items: center;
    height: 30px;
    border-radius: 50%;
    font-size: var(--t-13);
  }

  .tcal__day.is-due { background: var(--green-soft); color: var(--green-dk); font-weight: 700; }
  .tcal__day.is-late { background: var(--red-soft); color: var(--on-red-soft); font-weight: 700; }
  .tcal__day.is-today { outline: 2px solid var(--green-dk); }

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

  .tcats a {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Столько же, сколько у .tcats button ниже: в боковой карточке строка
       целиком и есть цель, и разной высоты у ссылки и кнопки быть не должно. */
    min-height: var(--tap);
    padding: 4px 0;
    font-size: var(--t-15);
    text-decoration: none;
  }

  .tcats__dot {
    flex: none;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--green);
  }

  .tcats strong {
    margin-left: auto;
    color: var(--muted);
    font-weight: 400;
  }
}

/* ── Архив ────────────────────────────────────────────────────── */

/* Экран десктопный: на телефоне архивом служат «Выполненные» в Задачах и
   вкладка «Архив» в Планах — там же, где человек их закрывал. */
.adash {
  display: none;
}

@media (min-width: 1100px) {
  .adash {
    display: block;
  }

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

  /* То же покрытие, что у строки плана. Здесь оно проще: других
     нажимаемых элементов в строке архива нет. */
  .arow {
    position: relative;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 8px;
    border-bottom: 1px solid var(--line);
  }

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

  .arow__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border-radius: var(--radius-btn);
  }

  .arow__ic svg {
    width: 20px;
    height: 20px;
  }

  .arow__ic--sm {
    width: 26px;
    height: 26px;
  }

  .arow__ic--sm svg {
    width: 14px;
    height: 14px;
  }

  /* Цвет типа — один и тот же у значка и у метки справа, чтобы строку можно
     было опознать не читая. */
  .arow__ic--task { background: var(--green-soft); color: var(--green-dk); }
  .arow__ic--plan { background: var(--card-2); color: var(--muted); }
  .arow__ic--award { background: var(--amber-soft); color: var(--on-amber-soft); }
  .arow__ic--file { background: var(--red-soft); color: var(--on-red-soft); }

  .arow__body {
    flex: 1;
    min-width: 0;
  }

  .arow__title {
    display: block;
    padding: 3px 0;
    font-weight: 700;
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .arow__sub {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .arow__date {
    flex: none;
    width: 150px;
    color: var(--muted);
    font-size: var(--t-13);
    text-align: right;
  }

  .arow__tag {
    flex: none;
    width: 110px;
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    font-size: var(--t-12);
    text-align: center;
  }

  .arow__tag--task { background: var(--green-soft); color: var(--green-dk); }
  .arow__tag--plan { background: var(--card-2); color: var(--muted); }
  .arow__tag--award { background: var(--amber-soft); color: var(--on-amber-soft); }
  .arow__tag--file { background: var(--red-soft); color: var(--on-red-soft); }

  /* Кнопка типа в правой колонке ведёт себя как строка списка. */
  .tcats button {
    display: flex;
    align-items: center;
    gap: 10px;
    /* Вся строка, а не текстовая полоска в двадцать пикселей: в боковой
       карточке это единственная цель, и мельчить её незачем. */
    min-height: var(--tap);
    padding: 4px 0;
    font-size: var(--t-15);
    text-align: left;
  }

  .tstat__ic--task { background: var(--green-soft); color: var(--green-dk); }
  .tstat__ic--plan { background: var(--card-2); color: var(--muted); }
  .tstat__ic--award { background: var(--amber-soft); color: var(--on-amber-soft); }
  .tstat__ic--file { background: var(--red-soft); color: var(--on-red-soft); }
}

/* ── Паутина на широком экране ────────────────────────────────── */

.wdash {
  display: none;
}

@media (min-width: 1100px) {
  .wdash {
    display: block;
  }

  /* Выбор цели: паутина плетётся вокруг одной, и переключение между целями —
     главное действие на этом экране. */
  .wgoals {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: var(--gap);
  }

  .wgoals button {
    padding: 8px 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: var(--card);
    color: var(--muted);
    font-size: var(--t-13);
  }

  .wgoals button[aria-pressed='true'] {
    background: var(--green-dk);
    border-color: var(--green-dk);
    color: var(--on-green);
    font-weight: 700;
  }

  .wgraph {
    display: block;
    width: 100%;
    height: auto;
  }

  .wedge {
    stroke: var(--line);
  }

  .whub {
    fill: var(--green-dk);
  }

  .whub__title,
  .whub__pct {
    fill: var(--on-green);
    text-anchor: middle;
  }

  .whub__title {
    font-size: 13px;
    font-weight: 700;
  }

  .whub__pct {
    font-size: 12px;
    opacity: 0.85;
  }

  .wnode__bg {
    fill: var(--card-2);
    stroke: var(--line);
  }

  .wnode svg,
  .wgraph [data-icon] {
    color: var(--green-dk);
  }

  /* Ветвь без плана — пунктиром, как и на телефоне: узел есть, сущности за ним
     нет. */
  .wnode--loose .wnode__bg {
    stroke-dasharray: 4 4;
  }

  .wnode--loose svg {
    color: var(--muted);
  }

  .wnode__count {
    fill: var(--ink);
    font-size: 12px;
    font-weight: 700;
    text-anchor: middle;
  }

  /* Обводка цветом карточки под самим текстом (paint-order: stroke — сначала
     обводка, потом заливка) — подписи стоят поверх колец с задачами, и без
     подложки название плана читалось бы сквозь точки. Двигать подписи вместо
     этого некуда: у каждой ветви занят и свой сектор, и оба соседних. */
  .wnode__label,
  .wnode__more,
  .worbit__node text {
    paint-order: stroke;
    stroke: var(--card);
    stroke-width: 3px;
    stroke-linejoin: round;
  }

  .wnode__label {
    fill: var(--muted);
    font-size: 12px;
    text-anchor: middle;
  }

  /* Пометка о задачах, которым не хватило места на дуге. Мельче подписи ветви:
     это оговорка к картинке, а не её часть. */
  .wnode__more {
    fill: var(--muted);
    font-size: 10px;
    text-anchor: middle;
    opacity: 0.8;
  }

  /* Задачи — точки на дуге своего плана. Цвет — область жизни задачи (--dot),
     закрытая залита им же, открытая пустая: разница видна, а подписи на каждую
     не нужно. Без категории точка серая — цвета у неё нет. */
  .wdot {
    fill: var(--card);
    stroke: var(--dot, var(--green));
    stroke-width: 2;
  }

  .wdot.is-done {
    fill: var(--dot, var(--green));
  }

  /* Веточка от плана к задаче. Тоньше и бледнее луча цели: связь та же по
     природе, но уровнем ниже, и спорить с лучами за внимание ей незачем. */
  .wedge--leaf {
    stroke: var(--line);
    stroke-width: 1;
    opacity: 0.7;
  }

  .worbit__path {
    fill: none;
    stroke: var(--line);
    stroke-dasharray: 5 6;
  }

  .worbit__node circle {
    fill: var(--card);
    stroke: var(--green);
    stroke-width: 2;
  }

  .worbit__node.is-today circle {
    fill: var(--green);
  }

  .worbit__node text {
    fill: var(--muted);
    font-size: 11px;
    text-anchor: middle;
  }

  .wlegend {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-top: 10px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
    color: var(--muted);
    font-size: var(--t-12);
  }

  .wlegend span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }

  .wlegend i {
    display: inline-block;
    width: 12px;
    height: 12px;
    border-radius: 50%;
  }

  .wlegend__hub { background: var(--green-dk); }
  .wlegend__cat { background: var(--card-2); border: 1px solid var(--line); }
  .wlegend__task { background: var(--card); border: 2px solid var(--green); }
  .wlegend__done { background: var(--green); }
  .wlegend__edge { width: 18px; height: 3px; border-radius: 2px; background: var(--line); }
  .wlegend__promise { background: var(--card); border: 2px dashed var(--green); }
}

/* ── Аналитика на широком экране ──────────────────────────────── */

.sdash {
  display: none;
}

@media (min-width: 1100px) {
  .sdash {
    display: block;
  }

  .sstats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--gap);
    margin-bottom: var(--gap);
  }

  .sstat {
    padding: 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow);
  }

  .sstat .tstat__ic {
    margin-bottom: 10px;
  }

  .sstat__label {
    display: block;
    color: var(--muted);
    font-size: var(--t-13);
  }

  .sstat__value {
    display: block;
    margin: 2px 0 4px;
    font-size: var(--t-28);
    font-weight: 700;
  }

  .sdelta {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .sdelta.is-up { color: var(--green-dk); }
  .sdelta.is-down { color: var(--red-ink); }

  /* График с заливкой под линией. */
  .schart {
    display: flex;
    gap: 10px;
    height: 260px;
  }

  .schart__y {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    color: var(--muted);
    font-size: var(--t-12);
    text-align: right;
  }

  .schart__plot {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
  }

  .schart__plot svg {
    flex: 1;
    width: 100%;
    border-bottom: 1px solid var(--line);
  }

  .schart__area {
    fill: var(--green-soft);
    opacity: 0.7;
  }

  /* Без non-scaling-stroke растяжение по ширине раздавило бы линию в нитку. */
  .schart__line {
    fill: none;
    stroke: var(--green);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    vector-effect: non-scaling-stroke;
  }

  .schart__x {
    display: flex;
    justify-content: space-between;
    margin-top: 6px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* Кольцо с числом в середине. */
  .sdonut {
    position: relative;
    flex: none;
    width: 130px;
    height: 130px;
  }

  .sdonut svg {
    width: 100%;
    height: 100%;
  }

  .sdonut__mid {
    position: absolute;
    inset: 0;
    display: grid;
    place-content: center;
    text-align: center;
  }

  .sdonut__mid strong {
    display: block;
    font-size: var(--t-15);
    font-weight: 700;
  }

  .sdonut__mid span {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .sfacts {
    display: flex;
    flex-direction: column;
    gap: 10px;
    font-size: var(--t-13);
  }

  .sfacts li {
    position: relative;
    padding-left: 16px;
    color: var(--ink);
  }

  .sfacts li::before {
    content: '';
    position: absolute;
    top: 7px;
    left: 0;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--green);
  }
}

/* ── Награды на широком экране ────────────────────────────────── */

.awdash {
  display: none;
}

@media (min-width: 1100px) {
  .awdash {
    display: block;
  }

  .awtotal {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 18px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
  }

  .awtotal__ic {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-btn);
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .awtotal span span {
    display: block;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .awtotal strong {
    font-size: var(--t-20);
    font-weight: 700;
  }

  .achs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--gap);
  }

  .ach {
    position: relative;
    padding: 18px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card-2);
    text-align: center;
  }

  /* Полученное — цветное, неполученное приглушено. Разница обязана читаться
     мгновенно, иначе список наград превращается в список обещаний. */
  .ach:not(.is-done) .ach__badge {
    background: var(--card);
    color: var(--muted);
    opacity: 0.75;
  }

  .ach__badge {
    display: grid;
    place-items: center;
    width: 64px;
    height: 64px;
    margin: 0 auto 10px;
    border-radius: 18px;
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .ach__badge svg {
    width: 28px;
    height: 28px;
  }

  .ach__badge--sm {
    width: 38px;
    height: 38px;
    margin: 0;
    border-radius: 12px;
  }

  .ach__badge--sm svg {
    width: 18px;
    height: 18px;
  }

  .ach__check {
    position: absolute;
    top: 10px;
    right: 10px;
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--green-dk);
    color: var(--on-green);
  }

  .ach__check svg {
    width: 14px;
    height: 14px;
  }

  .ach__name {
    display: block;
    font-size: var(--t-15);
    font-weight: 700;
  }

  .ach__hint {
    display: block;
    margin-top: 2px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .ach__date {
    display: block;
    margin-top: 10px;
    color: var(--green-dk);
    font-size: var(--t-12);
    font-weight: 700;
  }

  .ach__prog {
    display: block;
    margin-top: 10px;
  }

  .ach__num {
    display: block;
    margin-bottom: 4px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .awprog + .awprog {
    margin-top: 16px;
  }

  .awrecent {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .awrecent li {
    display: flex;
    align-items: center;
    gap: 10px;
  }

  .awrecent strong {
    display: block;
    font-size: var(--t-15);
  }

  .awrecent li > span:last-child > span {
    color: var(--muted);
    font-size: var(--t-12);
  }
}

/* ── Интеграции на широком экране ─────────────────────────────── */

/* До 1100px работает прежний список строк, после — сетка карточек с макета.
   Обе живут в одной разметке. */
.idash {
  display: none;
}

@media (min-width: 1100px) {
  .idash {
    display: block;
  }

  /* Сетка карточек. Ряды по содержимому не годятся: карточки в ряду обязаны
     совпадать по нижнему краю, иначе кнопки «Подключить» встают лесенкой. */
  .igrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(165px, 1fr));
    gap: var(--gap);
  }

  .icard {
    display: flex;
    flex-direction: column;
    padding: 18px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card-2);
  }

  .icard .intg__logo {
    width: 52px;
    height: 52px;
    margin-bottom: 14px;
  }

  .icard__name {
    font-size: var(--t-16);
    font-weight: 700;
  }

  /* Статус в две строки («Записываются вручную») — не редкость на узкой
     карточке, поэтому точка равняется по первой строке, а не по середине. */
  .icard__state {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin-top: 4px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .icard__state i {
    flex: none;
    margin-top: 5px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: currentcolor;
  }

  .icard__state--on {
    color: var(--green-dk);
  }

  .icard__state--partial {
    color: var(--amber-text);
  }

  /* Описания у сервисов разной длины. Обрезаем на трёх строках: подробности
     всё равно на своём экране, а ровный низ карточки важнее полного текста. */
  .icard__desc {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    overflow: hidden;
    margin-top: 12px;
    color: var(--muted);
    font-size: var(--t-13);
    line-height: 1.5;
  }

  /* Кнопка прижата к низу: у карточек разной высоты она обязана стоять на
     одном уровне. */
  .icard__go {
    align-self: flex-start;
    margin-top: auto;
    padding: 9px 18px;
    border-radius: var(--radius-pill);
    background: var(--green-soft);
    color: var(--green-dk);
    font-size: var(--t-13);
    font-weight: 700;
    text-decoration: none;
  }

  .icard__go:hover {
    background: var(--green);
    color: var(--on-green);
  }

  /* Сводка состояния справа. */
  .isync {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 10px 12px;
    border-radius: var(--radius-btn);
    font-size: var(--t-13);
    line-height: 1.4;
  }

  .isync svg {
    flex: none;
    width: 18px;
    height: 18px;
    margin-top: 1px;
  }

  .isync--ok {
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .isync--warn {
    background: var(--amber-soft);
    color: var(--on-amber-soft);
  }

  .irows {
    display: flex;
    flex-direction: column;
    margin-top: 6px;
  }

  .irows li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 2px;
    border-bottom: 1px solid var(--line);
    color: var(--muted);
    font-size: var(--t-13);
  }

  .irows li:last-child {
    border-bottom: 0;
    padding-bottom: 0;
  }

  .irows strong {
    color: var(--ink);
    font-weight: 700;
  }

  .iquote {
    position: relative;
    overflow: hidden;
    background: var(--green-soft);
    border-color: transparent;
    box-shadow: none;
  }

  /* Здесь лист лежит внутри карточки, а не выглядывает из-за её края, как на
     спокойных экранах. Поэтому и место, и слой задаём заново: базовый
     z-index: -1 увёл бы его под собственный фон карточки. */
  .iquote .leaves {
    z-index: 0;
    inset: auto -10px -18px auto;
    width: 120px;
    opacity: 0.22;
  }

  .iquote p {
    position: relative;
    z-index: 1;
    max-width: 210px;
    color: var(--green-dk);
    font-size: var(--t-15);
    line-height: 1.5;
  }
}

/* ── Цели на широком экране ───────────────────────────────────── */

/* До 1100px работает прежний мобильный экран с чипами и карточками,
   после — раскладка с макета. Обе живут в одной разметке. */
.gdash {
  display: none;
}

@media (min-width: 1100px) {
  .gdash {
    display: block;
  }

  /* Цвета состояний цели. Заведены переменными, потому что одни и те же четыре
     цвета нужны и кольцу (в conic-gradient), и точкам легенды. */
  .gdash {
    --g-done: var(--green);
    --g-doing: #7c9cd8;
    --g-planned: #c9b6e4;
    --g-overdue: var(--red);
  }

  .gstats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: var(--gap);
    margin-bottom: var(--gap);
  }

  .gstat {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 16px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card);
    box-shadow: var(--shadow);
  }

  .gstat__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    border-radius: 50%;
  }

  .gstat__ic svg {
    width: 22px;
    height: 22px;
  }

  .gstat__ic--green { background: var(--green-soft); color: var(--green-dk); }
  .gstat__ic--done { background: var(--green-soft); color: var(--green-dk); }
  .gstat__ic--doing { background: var(--card-2); color: #5a7ec0; }
  .gstat__ic--amber { background: var(--amber-soft); color: var(--on-amber-soft); }

  .gstat__label {
    display: block;
    color: var(--muted);
    font-size: var(--t-13);
  }

  .gstat__body strong {
    display: block;
    margin: 2px 0;
    font-size: var(--t-28);
    font-weight: 700;
  }

  .gstat__sub {
    display: block;
    color: var(--muted);
    font-size: var(--t-12);
  }

  /* Список целей. */
  .grows {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .grow {
    display: flex;
    align-items: center;
    gap: 6px;
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--card-2);
    /* Перенос — ради разбивки процента: она стоит отдельным блоком во всю
       ширину строки, а не третьей колонкой рядом с кнопкой правки. */
    flex-wrap: wrap;
  }

  /* Разбивка внутри <li>, а не внутри ссылки на задачи цели: вложенная ссылка
     разорвала бы внешнюю, и половина строки перестала бы нажиматься (см.
     chainLines в goals.js). Отступы повторяют padding ссылки, чтобы блок стоял
     по одной линии с названием цели, а не съезжал к рамке. */
  .grow > .goal__chain {
    width: 100%;
    margin-top: 0;
    padding: 8px 14px 12px;
  }

  .grow__main {
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 1;
    min-width: 0;
    padding: 14px;
    color: inherit;
    text-decoration: none;
  }

  .grow__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 52px;
    height: 52px;
    border-radius: var(--radius-btn);
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .grow__ic svg {
    width: 24px;
    height: 24px;
  }

  .grow__body {
    flex: 1;
    min-width: 0;
  }

  /* Многоточие, а не перенос: строка цели — одна строка с полосой под ней, и
     длинное название иначе вылезает за карточку. Прежний overflow-wrap: normal
     запрещал рвать слово, но ничего не делал с тем, что оно не помещается. */
  .grow__title {
    display: block;
    overflow: hidden;
    font-size: var(--t-16);
    font-weight: 700;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .grow__money {
    display: block;
    margin: 2px 0 8px;
    color: var(--muted);
    font-size: var(--t-13);
  }

  .grow__money b {
    color: var(--ink);
    font-weight: 700;
  }

  .grow__bar {
    display: block;
    height: 6px;
    border-radius: 3px;
    background: var(--line);
    overflow: hidden;
  }

  .grow__bar i {
    display: block;
    height: 100%;
    border-radius: 3px;
    background: var(--green);
  }

  /* Правый столбец ужимается вместе с окном. Жёсткие 170px в узком окне
     съедали всю строку: на название цели оставалось около пятидесяти пикселей,
     и «Финсвобода» не помещалась в собственную ячейку. */
  .grow__side {
    flex: 0 1 170px;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    min-width: 0;
  }

  .grow__date {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--muted);
    font-size: var(--t-13);
    white-space: nowrap;
  }

  .grow__date svg {
    width: 16px;
    height: 16px;
  }

  .grow__date.is-overdue {
    color: var(--red-ink);
  }

  .grow__date.is-done {
    color: var(--green-dk);
    font-weight: 700;
  }

  .grow__cat {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: var(--radius-pill);
    background: var(--card);
    font-size: var(--t-12);
  }

  .grow__cat i {
    width: 8px;
    height: 8px;
    border-radius: 50%;
  }

  .grow__percent {
    flex: none;
    width: 52px;
    text-align: right;
    font-size: var(--t-15);
    font-weight: 700;
  }

  .grow__edit {
    flex: none;
    display: grid;
    place-items: center;
    width: 36px;
    height: 36px;
    margin-right: 8px;
    border-radius: 50%;
    color: var(--muted);
  }

  .grow__edit:hover {
    background: var(--card);
    color: var(--ink);
  }

  /* Кольцо состояний и легенда. */
  .gring {
    display: flex;
    align-items: center;
    gap: 18px;
  }

  .gring__disc {
    flex: none;
    display: grid;
    place-items: center;
    width: 116px;
    height: 116px;
    border-radius: 50%;
  }

  .gring__hole {
    display: grid;
    place-items: center;
    width: 82px;
    height: 82px;
    border-radius: 50%;
    background: var(--card);
    text-align: center;
  }

  .gring__hole strong {
    font-size: var(--t-20);
    font-weight: 700;
  }

  .gring__hole span {
    color: var(--muted);
    font-size: var(--t-12);
  }

  .glegend {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 9px;
    min-width: 0;
  }

  .glegend li {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--t-13);
  }

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

  .glegend__dot--done { background: var(--g-done); }
  .glegend__dot--doing { background: var(--g-doing); }
  .glegend__dot--planned { background: var(--g-planned); }
  .glegend__dot--overdue { background: var(--g-overdue); }

  .glegend strong {
    margin-left: auto;
    color: var(--muted);
    font-weight: 400;
  }

  /* Ближайшие задачи. */
  .gsoon {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .gsoon li {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: var(--t-13);
  }

  .gsoon__dot {
    flex: none;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--green);
  }

  .gsoon a {
    min-width: 0;
    overflow: hidden;
    color: inherit;
    text-decoration: none;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .gsoon a:hover {
    color: var(--green-dk);
  }

  .gsoon li > span {
    margin-left: auto;
    flex: none;
    color: var(--muted);
    font-size: var(--t-12);
    white-space: nowrap;
  }

  .gquote {
    position: relative;
    overflow: hidden;
    background: var(--green-soft);
    border-color: transparent;
    box-shadow: none;
  }

  .gquote .leaves {
    z-index: 0;
    inset: auto -10px -18px auto;
    width: 120px;
    opacity: 0.22;
  }

  .gquote p {
    position: relative;
    z-index: 1;
    max-width: 210px;
    color: var(--green-dk);
    font-size: var(--t-15);
    line-height: 1.5;
  }

  /* Цели по сферам жизни. */
  .gcats {
    display: flex;
    flex-direction: column;
    gap: 11px;
  }

  .gcats li {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: var(--t-13);
  }

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

  .gcats strong {
    margin-left: auto;
    color: var(--muted);
    font-weight: 400;
  }

  .gcats__total {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
    font-weight: 700;
  }

  /* Зелёная кнопка в шапке — здесь она главное действие экрана. */
  .dhead__btn--go {
    border-color: transparent;
    background: var(--green-dk);
    color: var(--on-green);
    font-weight: 700;
  }

  .dhead__btn--go:hover {
    background: var(--green-press);
  }

  .dhead__btn--go svg {
    color: currentcolor;
  }
}

/* ── Настройки на широком экране ──────────────────────────────── */

/* До 1100px работает прежний список строк, после — раскладка с макета.
   Обе живут в одной разметке. */
.sdash {
  display: none;
}

/* Кружок профиля с картинкой. Живёт вне медиазапроса: аватар показывается и
   на телефоне — в шапке профиля и в боковом меню на планшете. */
.avatar--img {
  padding: 0;
  overflow: hidden;
  background: var(--card-2);
}

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

@media (min-width: 1100px) {
  .sdash {
    display: block;
  }

  .avatar--lg {
    flex: none;
    width: 72px;
    height: 72px;
    font-size: var(--t-20);
  }

  /* Шапка карточки: иконка, заголовок и пояснение под ним. */
  .scard__head {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    margin-bottom: 16px;
  }

  .scard__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-btn);
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .scard__ic svg {
    width: 20px;
    height: 20px;
  }

  .scard__head h2 {
    font-size: var(--t-16);
    font-weight: 700;
  }

  .scard__head p {
    margin-top: 2px;
    color: var(--muted);
    font-size: var(--t-13);
  }

  /* Аватар и кнопки рядом с ним. */
  .sprofile {
    display: flex;
    align-items: center;
    gap: 16px;
    margin-bottom: 18px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--line);
  }

  .sprofile__act {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }

  .dlink--muted {
    color: var(--muted);
    font-weight: 400;
  }

  .dlink--muted:hover {
    color: var(--red-ink);
  }

  /* Имя и почта — в две колонки, кнопка под ними справа. */
  .sgrid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px;
  }

  .sgrid__foot {
    grid-column: 1 / -1;
    display: flex;
    justify-content: flex-end;
  }

  /* Пары карточек в ряд: Уведомления + Внешний вид, Безопасность + Данные. */
  /* Ряды по содержимому: у «Уведомлений» строк меньше, чем у «Внешнего вида»,
     и растягивать их до одной высоты значило бы оставить внутри пустоту. */
  .spair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: var(--gap);
    align-items: start;
  }

  /* Строка-ссылка внутри карточки настроек. */
  .srow {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 13px 2px;
    border-bottom: 1px solid var(--line);
    font-size: var(--t-15);
    text-align: left;
  }

  .srow:last-child {
    border-bottom: 0;
    padding-bottom: 0;
  }

  .srow:hover {
    color: var(--green-dk);
  }

  .srow__val {
    margin-left: auto;
    color: var(--muted);
    font-size: var(--t-13);
    white-space: nowrap;
  }

  .srow__chev {
    display: grid;
    place-items: center;
    color: var(--muted);
  }

  .srow__val + .srow__chev {
    margin-left: 0;
  }

  .srow:not(:has(.srow__val)) .srow__chev {
    margin-left: auto;
  }

  .srow__chev svg {
    width: 18px;
    height: 18px;
  }

  .srow.is-danger {
    color: var(--red-ink);
  }

  /* Выбор темы: четыре карточки с превью палитры. */
  .tsets {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 10px;
  }

  .tset {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    padding: 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-btn);
    text-align: left;
  }

  .tset.is-on {
    border-color: var(--green);
    background: var(--green-soft);
  }

  /* Превью: две полоски на фоне карточки — намёк на список, а не скриншот. */
  .tset__art {
    position: relative;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    gap: 5px;
    height: 62px;
    padding: 10px;
    border: 1px solid;
    border-radius: 8px;
  }

  .tset__art i {
    display: block;
    height: 6px;
    border-radius: 3px;
    opacity: 0.75;
  }

  .tset__art i:last-child {
    width: 60%;
  }

  .tset__on {
    position: absolute;
    top: 6px;
    right: 6px;
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--green);
    color: var(--on-green);
  }

  .tset__on svg {
    width: 13px;
    height: 13px;
  }

  .tset strong {
    margin-top: 4px;
    font-size: var(--t-13);
    font-weight: 700;
  }

  .tset > span:last-child {
    color: var(--muted);
    font-size: var(--t-12);
  }
}

/* ── Напоминания карточкой в углу окна ────────────────────────── */

/* Карточка с макета `dectop & mobile 2.png`. Показывается только на широком
   экране: на телефоне за напоминания отвечает пуш — он приходит и когда
   вкладка закрыта, а карточка внутри страницы этого не умеет и вдобавок легла
   бы поверх нижней панели. */
.rtoasts {
  display: none;
}

@media (min-width: 1100px) {
  .rtoasts {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 70;
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 340px;
    /* Клики проходят мимо пустого места стопки — под ней живой экран. */
    pointer-events: none;
  }

  .rtoast {
    display: flex;
    gap: 12px;
    padding: 16px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--card);
    box-shadow: 0 10px 30px rgb(0 0 0 / 18%);
    pointer-events: auto;
    opacity: 0;
    transform: translateX(16px);
    transition: opacity 0.22s ease, transform 0.22s ease;
  }

  .rtoast.is-in {
    opacity: 1;
    transform: none;
  }

  .rtoast.is-out {
    opacity: 0;
    transform: translateX(16px);
  }

  .rtoast__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--green-soft);
    color: var(--green-dk);
  }

  .rtoast__ic svg {
    width: 20px;
    height: 20px;
  }

  .rtoast__body {
    flex: 1;
    min-width: 0;
  }

  .rtoast__kicker {
    display: block;
    font-size: var(--t-13);
    font-weight: 700;
  }

  /* Название задачи бывает длинным — две строки и многоточие. */
  .rtoast__title {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
    margin-top: 2px;
    color: var(--muted);
    font-size: var(--t-13);
  }

  .rtoast__when {
    display: block;
    margin-top: 2px;
    color: var(--muted);
    font-size: var(--t-12);
  }

  .rtoast__go {
    display: inline-block;
    margin-top: 10px;
    padding: 8px 18px;
    border-radius: 8px;
    background: var(--green-dk);
    color: var(--on-green);
    font-size: var(--t-13);
    font-weight: 700;
    text-decoration: none;
  }

  .rtoast__go:hover {
    background: var(--green-press);
  }

  .rtoast__close {
    flex: none;
    align-self: flex-start;
    display: grid;
    place-items: center;
    color: var(--muted);
  }

  .rtoast__close svg {
    width: 18px;
    height: 18px;
  }

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

/* Уважаем системную просьбу не двигать: карточка появляется сразу и без
   съезжания. Убирает её крестик или переход к задаче, а не анимация. */
@media (prefers-reduced-motion: reduce) {
  .rtoast {
    transition: none;
    opacity: 1;
    transform: none;
  }
}

/* ── Главная на телефоне ──────────────────────────────────────── */

/* Приветствие и карточка дня по макету `doc/ref/new-design.png` (экран 03).
   Полосу прогресса берём готовую (.goal__bar) — вторая копия того же оформления
   разошлась бы с первой при первой же правке. */

.hello {
  margin-top: 10px;
  padding-inline: 2px;
}

.hello__title {
  font-size: var(--t-20);
  font-weight: 800;
}

.hello__sub {
  margin-top: 4px;
  color: var(--muted);
  font-size: var(--t-13);
}

.mtoday {
  position: relative;
  padding: 16px var(--pad);
}

.mtoday__nums {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  text-align: center;
}

.mtoday__nums strong {
  display: block;
  font-size: var(--t-28);
  font-weight: 800;
  line-height: 1.1;
}

.mtoday__nums span {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: var(--t-12);
}

.mtoday__prog {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-top: 18px;
  font-size: var(--t-13);
}

.mtoday__prog strong {
  color: var(--green-dk);
  font-size: var(--t-15);
  font-weight: 800;
}

/* Полоса идёт сразу под строкой «Прогресс дня», а не через её собственный
   отступ: это одна пара «подпись — полоса», а не два отдельных блока. */
.mtoday .goal__bar {
  margin-top: 8px;
}

/* ── Сводка: нижний ряд на широком мониторе ───────────────────── */

/* Четыре карточки в ряд, как на макете. Ниже 1400px они не помещаются: на
   «Награды» приходилось бы меньше 230px, а там три медали в строку. */
@media (min-width: 1400px) {
  .dash__grid > .dcard:nth-child(n + 7) {
    grid-column: span 3;
  }
}

/* ── Своя строка заголовка (только в оболочке) ────────────────── */

/* Класс is-shell ставит titlebar.js, и только внутри приложения. Во вкладке
   браузера этих правил не существует: там рамку рисует браузер. */

/* Выше всего остального, включая листы, подтверждения и напоминания (z 70):
   закрыть окно человек обязан мочь всегда, а не только когда ничего не открыто. */
.wbar {
  position: fixed;
  z-index: 80;
  top: 0;
  right: 0;
  left: 0;
  display: flex;
  align-items: center;
  height: 38px;
  /* Ни фона-полосы, ни черты снизу: полоса сливается с приложением, видны только
     кнопки в правом верхнем углу — как на макете doc/ref/primer.png. Прежде здесь
     были непрозрачный фон и border-bottom, и это читалось как отдельное окно
     системы поверх приложения. Высоту (38px) оставляем — под ней ничего не
     рисуется, поэтому кнопки не налезают на колокольчик и «+» в шапке. */
  background: transparent;
  /* Окно без рамки не двигается само: тащить его можно за всю полосу, кроме
     кнопок — они исключены ниже, иначе нажатие превращалось бы в перетаскивание. */
  -webkit-app-region: drag;
}

.wbar__drag {
  flex: 1;
  align-self: stretch;
}

.wbar__btns {
  display: flex;
  align-self: stretch;
  -webkit-app-region: no-drag;
}

/* Ширина 46px — как у системных кнопок Windows. Рука тянется в угол по
   мышечной памяти, и кнопка уже другого размера промахивается. */
.wbar__btn {
  display: grid;
  place-items: center;
  width: 46px;
  border: 0;
  background: none;
  color: var(--muted);
  cursor: pointer;
}

.wbar__btn svg {
  width: 18px;
  height: 18px;
}

.wbar__btn:hover {
  background: var(--card-2);
  color: var(--ink);
}

/* Красная — только «Закрыть», и только под курсором: постоянно красная кнопка
   тревожит на пустом месте. */
.wbar__btn--close:hover {
  background: var(--red, #B4483F);
  color: #FFFFFF;
}

/* Освобождаем место под полосу. Приложение прижималось к самому верху окна —
   теперь верх занят заголовком. */
.is-shell body {
  padding-top: 38px;
}

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

@media (min-width: 1100px) {
  /* Окно оболочки прозрачное (main.js). Значит «страницы» вокруг приложения
     нет — есть только само приложение, и оно должно заполнять окно целиком, а
     за скруглёнными углами виден рабочий стол.

     Раньше на широком экране .app был карточкой по центру: отступ --desk-gap
     вокруг, макс. ширина, рамка. В браузере это воздух вокруг сайта, но в
     прозрачном окне оболочки тот отступ показывал более тёмный --bg-desk и
     упирался в квадратные углы окна — те самые «тёмные границы до квадрата».
     Поэтому в оболочке заливаем окно фоном приложения, а скругление и обрезку
     даём body: за его углами окно прозрачно и виден рабочий стол. */
  .is-shell {
    background: transparent;
  }

  .is-shell body {
    background: var(--bg);
    border-radius: 14px;
    overflow: hidden;
  }

  /* Полоса заголовка — position: fixed, и её содержащий блок окно, а не body.
     Значит ни `overflow: hidden`, ни скругление выше её НЕ обрезают: body не
     создаёт для fixed-потомков содержащий блок (нет ни transform, ни filter, ни
     contain). Красная заливка «Закрыть» при наведении ложилась поэтому и в те
     14px угла, где окно прозрачно и виден рабочий стол, — квадратным выступом
     из скруглённого угла приложения. Повторяем скругление на самой кнопке;
     радиус обязан совпадать с радиусом body над ним. */
  .is-shell:not(.is-max) .wbar__btn--close {
    border-top-right-radius: 14px;
  }

  .is-shell .app {
    max-width: none;
    margin: 0;
    height: calc(100dvh - 38px);
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }

  /* Убираем лишний воздух сверху: 38px под кнопками (body padding-top) — это уже
     вся строка заголовка, и добавлять к ним ещё собственные верхние отступы
     меню и колонки незачем — иначе содержимое висит слишком низко. Оставляем
     совсем немного, чтобы аватар и заголовок не липли к кнопкам. Только в
     оболочке: в браузере полосы нет и отступы там свои. */
  .is-shell .side {
    padding-top: 6px;
  }

  /* Специфичность под стать правилу `.app:has(.view--wide) .view{padding-top:24px}`
     (0,3,0) — иначе оно перебивает и воздух сверху остаётся. */
  .is-shell .view,
  .is-shell .app:has(.view--wide) .view {
    padding-top: 6px;
  }

  /* Развёрнутое окно занимает весь экран — скругление у краёв экрана читается
     как ошибка. Класс ставит titlebar.js по событию window-state. */
  .is-shell.is-max body {
    border-radius: 0;
  }
}

/* ── Панель уведомлений у колокольчика ────────────────────────── */

/* Живёт вне #view и позиционируется из JS, поэтому здесь только вид.
   Ниже 1100px её не существует: там открывается целый экран, и решает это
   сам bellpop.js, а не CSS — прятать уже открытую панель поздно. */
.bellpop {
  position: fixed;
  z-index: 75;
  width: 340px;
  max-width: calc(100vw - 24px);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg);
  box-shadow: var(--shadow-lift);
  opacity: 0;
  transform: translateY(-6px);
  transition:
    opacity var(--fast) var(--ease),
    transform var(--fast) var(--ease);
}

.bellpop.is-in {
  opacity: 1;
  transform: none;
}

.bellpop__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 8px 10px 14px;
  border-bottom: 1px solid var(--line);
}

.bellpop__head strong {
  font-size: var(--t-15);
}

/* Счётчик занимает остаток строки, отталкивая шестерёнку вправо. */
.bellpop__count {
  flex: 1;
  color: var(--muted);
  font-size: var(--t-12);
  font-weight: 700;
}

.bellpop__gear {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--muted);
  cursor: pointer;
}

.bellpop__gear:hover {
  background: var(--card-2);
  color: var(--ink);
}

.bellpop__gear svg {
  width: 18px;
  height: 18px;
}

/* Высоту ограничиваем окном, а не числом строк: панель у края экрана не должна
   уезжать за его нижнюю границу. */
.bellpop__body {
  max-height: min(52vh, 420px);
  padding: 6px;
  overflow-y: auto;
}

/* «Анализ» в Паутине — та же панель, но внутри не строки задач, а факты. */
.analysispop {
  width: 340px;
}

.analysispop__fact {
  padding: 8px 10px;
  font-size: var(--t-13);
  line-height: 1.5;
  color: var(--ink);
}

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

.bellpop__group + .bellpop__group {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid var(--line);
}

.bellpop__cap {
  display: flex;
  justify-content: space-between;
  padding: 6px 8px 4px;
  color: var(--muted);
  font-size: var(--t-12);
  font-weight: 700;
}

.bellpop__row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
}

.bellpop__row:hover {
  background: var(--card-2);
}

.bellpop__title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  font-size: var(--t-13);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bellpop__time {
  flex: none;
  color: var(--muted);
  font-size: var(--t-12);
  font-variant-numeric: tabular-nums;
}

.bellpop__time--late {
  color: var(--red-ink);
  font-weight: 700;
}

.bellpop__empty {
  padding: 16px 10px;
  color: var(--muted);
  font-size: var(--t-13);
  text-align: center;
}

.bellpop__foot {
  padding: 6px;
  border-top: 1px solid var(--line);
}

.bellpop__foot button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  width: 100%;
  padding: 9px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--green-dk);
  font: inherit;
  font-size: var(--t-13);
  font-weight: 700;
  cursor: pointer;
}

.bellpop__foot button:hover {
  background: var(--card-2);
}

.bellpop__foot svg {
  width: 16px;
  height: 16px;
}

/* ── Книга контактов ──────────────────────────────────────────────
   Окно того же вида, что уведомления (класс bellpop), плюс строка поиска
   сверху и строки контактов с иконкой способа связи. */
.ctpop__search {
  padding: 8px 8px 4px;
}

.ctpop__search .input {
  min-height: 38px;
}

.ctpop__body {
  max-height: min(48vh, 360px);
  overflow-y: auto;
}

.ctrow {
  display: flex;
  align-items: center;
  gap: 2px;
}

.ctrow__link {
  display: flex;
  flex: 1;
  min-width: 0;
  align-items: center;
  gap: 10px;
  padding: 7px 8px;
  border-radius: 8px;
  color: inherit;
  text-decoration: none;
  /* Строка выбора — это <button>, а у него текст по центру: короткое имя
     уезжало в середину над своим меню. Держим весь текст строки слева. */
  text-align: left;
}

.ctrow__link:hover {
  background: var(--card-2);
}

.ctrow__ic {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 10px;
}

.ctrow__ic svg {
  width: 18px;
  height: 18px;
}

/* Способ связи — цветом иконки. WhatsApp зелёный (совпадает с темой), Telegram
   синий (свой акцент, темы не касается), звонок — тёплый нейтральный. */
.ctrow__ic--whatsapp {
  background: var(--green-soft);
  color: var(--green-dk);
}

.ctrow__ic--telegram {
  background: rgba(42, 171, 226, 0.16);
  color: #1E88C7;
}

.ctrow__ic--phone {
  background: var(--amber-soft);
  color: var(--on-amber-soft);
}

.ctrow__body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.ctrow__name {
  overflow: hidden;
  font-size: var(--t-15);
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ctrow__meta {
  overflow: hidden;
  color: var(--muted);
  font-size: var(--t-12);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ctrow__edit {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 8px;
  color: var(--muted);
}

.ctrow__edit:hover {
  background: var(--card-2);
  color: var(--ink);
}

/* Корзина: на ней самой — красный намёк при наведении, а «взведённая» (ждёт
   второго тапа для удаления) заливается красным целиком, чтобы отличаться от
   соседней «⋯» и не удалить контакт случайным касанием. */
.ctrow__edit--del:hover {
  background: var(--red-soft);
  color: var(--red-ink);
}

.ctrow__edit--arm,
.ctrow__edit--arm:hover {
  background: var(--red-btn);
  color: var(--on-red);
}

.ctrow__edit svg {
  width: 18px;
  height: 18px;
}

/* Встроенная форма добавления и правки контакта — прямо в окне, вместо списка.
   display:flex перебивает служебное [hidden] (правило автора сильнее UA), поэтому
   спрятанное состояние возвращаем явно — иначе форма висела бы открытой всегда. */
.ctpop__new {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px;
}

.ctpop__new[hidden] {
  display: none;
}

.ctpop__newtitle {
  color: var(--muted);
  font-size: var(--t-12);
  font-weight: 700;
}

.ctpop__newrow {
  display: flex;
  gap: 8px;
}

/* Маленькая иконка способа связи — в чипах формы задачи и строках карточки. */
.ctchip__ic {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 7px;
}

.ctchip__ic svg {
  width: 15px;
  height: 15px;
  color: inherit;
}

.ctchip__ic--whatsapp {
  background: var(--green-soft);
  color: var(--green-dk);
}

.ctchip__ic--telegram {
  background: rgba(42, 171, 226, 0.16);
  color: #1E88C7;
}

.ctchip__ic--phone {
  background: var(--amber-soft);
  color: var(--on-amber-soft);
}

/* Кнопка «Добавить контакт» в форме задачи — на всю ширину, иконка в строку. */
.tf__ctadd {
  flex-direction: row;
  gap: 8px;
  width: 100%;
  min-height: 44px;
  margin-top: 8px;
  font-size: var(--t-13);
}

.tf__ctadd svg {
  width: 18px;
  height: 18px;
}

/* Контакт на карточке задачи — строка-ссылка к разговору. */
.ctlink {
  text-decoration: none;
  color: inherit;
}

.ctlink:hover {
  background: var(--card);
}

.ctlink > svg:last-child {
  flex: none;
  width: 18px;
  height: 18px;
  color: var(--muted);
}

/* ── Меню профиля в боковом меню ──────────────────────────────── */

/* Позиционирует popover.js — здесь только вид. Всплывает над карточкой
   профиля: она прижата к низу окна, и снизу места нет. */
.umenu {
  position: fixed;
  z-index: 75;
  width: 248px;
  max-width: calc(100vw - 24px);
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--bg);
  box-shadow: var(--shadow-lift);
  opacity: 0;
  /* Всплывает над карточкой профиля (она прижата к низу): растём из своего
     нижнего края, будто разворачиваемся от кнопки, а не просто проявляемся. */
  transform-origin: bottom left;
  transform: translateY(8px) scale(0.96);
  transition:
    opacity var(--slow) var(--ease),
    transform var(--slow) var(--ease);
}

.umenu.is-in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .umenu {
    transform: none;
    transition: opacity var(--fast) var(--ease);
  }
}

.umenu__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 8px 10px;
  border-bottom: 1px solid var(--line);
}

.umenu__who {
  min-width: 0;
}

.umenu__who strong {
  display: block;
  overflow: hidden;
  font-size: var(--t-13);
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Почта длиннее имени и обязана ужиматься, а не растягивать меню. */
.umenu__who span {
  display: block;
  overflow: hidden;
  color: var(--muted);
  font-size: var(--t-12);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.umenu__items {
  display: flex;
  flex-direction: column;
  padding-top: 6px;
}

.umenu__items button {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 8px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: var(--t-13);
  text-align: left;
  cursor: pointer;
}

.umenu__items button:hover {
  background: var(--card-2);
}

.umenu__items svg {
  width: 18px;
  height: 18px;
  flex: none;
  color: var(--muted);
}

/* Выход выделен цветом, но не фоном: красная строка в меню читается как
   предупреждение о том, что уже произошло. Красный фон — на кнопке в
   подтверждении, там он к месту. */
.umenu__out,
.umenu__out svg {
  color: var(--red-ink);
}

.umenu__out:hover {
  background: var(--red-soft);
}

/* ── Экран во всю высоту, список листается внутри ─────────────── */

/* Две беды лечатся одним приёмом.

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

   Поэтому высота не задаётся числом, а берётся вся, что есть: экран занимает
   колонку целиком, карточка со списком — весь остаток по высоте, а список
   листается внутри себя. Сколько строк видно, решает размер окна: на обычном
   как раз те пять-шесть, на большом больше, и нигде не остаётся дыры.

   Нижняя граница нужна, чтобы на низком окне список не сжался до двух строк. */
@media (min-width: 1100px) {
  /* Именно height, а не min-height. Минимум задаёт только пол: контейнер всё
     равно растёт под содержимое, свободного места не остаётся, и flex: 1 ниже
     нечего распределять — карточка не ужимается, список не листается, а экран
     вылезает за колонку. Определённая высота заставляет содержимое уместиться. */
  .tdash,
  .pdash,
  .gdash,
  .adash,
  .awdash,
  .prdash,
  .catdash {
    display: flex;
    flex-direction: column;
    height: 100%;
  }

  /* align-items: start выше не даёт колонкам растянуться — здесь это как раз
     то, что нужно отменить. */
  .pmain {
    flex: 1;
    align-items: stretch;
    min-height: 0;
  }

  .pmain > .dcard,
  .pmain > .fcol,
  .pmain > .fcol > .dcard:first-child {
    min-height: 0;
  }

  /* Правая колонка листается своей прокруткой. Её карточки (календарь,
     категории, статистика) не умеют ужиматься, и на низком окне именно она
     распирала строку сетки — из-за неё главная карточка вылезала за нижний
     край. Пусть лучше листается второстепенная колонка, чем теряется то, что
     обрезано за краем. */
  .pmain > .pside,
  .fmain > .pside {
    min-height: 0;
    overflow-y: auto;
    padding-right: 4px;
  }

  /* Карточки в ней НЕ ужимаются. Колонка — flex, а у flex-детей сжатие включено
     по умолчанию: как только у колонки появилась ограниченная высота, карточки
     начали сдавливаться и резать себе текст (цитата на «Целях» теряла две
     строки). Пусть лучше колонка листается. */
  .pmain > .pside > *,
  .fmain > .pside > * {
    flex: none;
  }

  .pmain > .fcol > .dcard:first-child {
    flex: 1;
  }

  /* Карточка без графика свободное место не занимает. Растягиваться
     на всю колонку имеет смысл линии — ей высота нужна, чтобы было видно
     перепады. Одной строке «за этот период ничего не закрыто» — нет: под ней
     оставалось сто шестьдесят пикселей пустоты, и экран выглядел сломанным,
     а не пустым. Место под график резервирует .schart со своей высотой,
     так что прыгать вёрстка при появлении данных не будет. */
  .pmain > .fcol > .dcard--nodata:first-child {
    flex: none;
  }

  .prows,
  .grows,
  .arows,
  .achs,
  .tlist,
  .promises--desk,
  .catrows {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    /* Место под полосу прокрутки, чтобы она не легла на текст строки. */
    padding-right: 4px;
  }

  /* Страховка на всё семейство: если у карточки во всю высоту содержимое
     окажется без своей прокрутки, оно не вывалится наружу — карточка обрежет
     его по своей рамке. Это не замена прокрутке, а предохранитель: именно так
     список задач однажды и полез за нижний край окна. */
  .pmain > .dcard,
  .pmain > .fcol > .dcard {
    overflow: hidden;
  }

  /* Пол: три строки списка и один ряд карточек достижений. Ниже этого список
     перестаёт быть списком. Числа — та же арифметика, что и высота строки:
     3 × строка + 2 × промежуток. Промежутка в архиве нет, там строки разделяет
     черта. */
  .prows { min-height: 254px; }  /* 3 × 78 + 2 × 10 */
  .promises--desk { min-height: 216px; } /* 3 × 64 + 2 × 12 */
  .catrows { min-height: 180px; } /* 3 × 60, строки разделяет черта */
  .grows { min-height: 266px; }  /* 3 × 82 + 2 × 10 */
  .arows { min-height: 201px; }  /* 3 × 67 */
  .achs { min-height: 210px; }   /* один ряд карточек */
}

/* ── Финансы: экран во всю высоту ─────────────────────────────── */

@media (min-width: 1100px) {
  /* Тот же приём, что на Задачах и Планах: экран занимает колонку, список
     операций листается внутри своей карточки. Смысл здесь ещё и в том, что
     «Расходы по категориям» и «Копилки» стоят ПОД карточкой операций — пока
     та росла под число строк, они уезжали за нижний край экрана. */
  .fdash {
    display: flex;
    flex-direction: column;
    height: 100%;
  }

  .fmain {
    flex: 1;
    align-items: stretch;
    min-height: 0;
  }

  .fmain > .fcol,
  .fmain > .pside {
    min-height: 0;
  }

  /* Тянется только карточка операций. Нижняя пара — по содержимому: она и есть
     то, что должно оставаться на виду. */
  .fcol > .dcard:first-child {
    flex: 1;
    min-height: 150px;
    overflow: hidden;
  }

  .fcol > .fpair {
    flex: none;
  }

  .flist {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: 4px;
  }

  /* Пустой общий бюджет: не абзац с отсылкой к телефону, а два настоящих
     действия. Раньше здесь было написано «на мобильном экране есть обе
     кнопки» — то есть экран честно признавался, что не умеет то, что умеет
     телефон. */
  .hhempty {
    align-items: center;
    text-align: center;
  }

  .hhempty h2 {
    margin-top: 12px;
    font-size: var(--t-16);
  }

  .hhempty .dcard__empty {
    max-width: 460px;
    margin-top: 6px;
  }

  .hhempty__act {
    display: flex;
    gap: 10px;
    margin-top: 16px;
  }
}

/* ── Поле срока и свой календарь ────────────────────────────────────
   Поле «Дата и время» — это кнопка вида .input: показывает выбранный срок и
   открывает свой календарь (datepicker.js) вместо браузерного datetime-local. */
.dtfield {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  text-align: left;
  cursor: pointer;
}

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

.dtfield--empty .dtfield__text {
  color: var(--muted);
}

.dtfield__ic {
  display: grid;
  place-items: center;
  flex: none;
  color: var(--muted);
}

.dtfield__ic svg {
  width: 18px;
  height: 18px;
}

/* Календарь: та же карточка-окно, что уведомления (.bellpop), но уже и с сеткой. */
.dppop {
  width: 300px;
  padding: 12px;
}

.dp__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.dp__month {
  font-size: var(--t-15);
  font-weight: 700;
}

.dp__nav {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  color: var(--muted);
}

.dp__nav:hover {
  background: var(--card-2);
  color: var(--ink);
}

.dp__nav svg {
  width: 18px;
  height: 18px;
}

.dp__nav--prev svg {
  transform: rotate(180deg);
}

.dp__week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  margin-bottom: 4px;
}

.dp__week span {
  text-align: center;
  color: var(--muted);
  font-size: var(--t-12);
  font-weight: 700;
}

.dp__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}

.dp__day {
  height: 36px;
  border-radius: 8px;
  color: var(--ink);
  font-size: var(--t-13);
  font-variant-numeric: tabular-nums;
  transition: background var(--fast) var(--ease);
}

.dp__day:hover {
  background: var(--card-2);
}

/* Дни соседних месяцев видны, но приглушены: сетка не должна обрываться пустотой. */
.dp__day--out {
  color: var(--muted);
  opacity: 0.55;
}

.dp__day--today {
  box-shadow: inset 0 0 0 1px var(--green-dk);
  font-weight: 700;
}

.dp__day--sel,
.dp__day--sel:hover {
  background: var(--green-dk);
  color: var(--on-green);
  font-weight: 700;
}

.dp__time {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}

.dp__time-label {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: var(--t-12);
  font-weight: 600;
}

.dp__time-label svg {
  width: 16px;
  height: 16px;
}

.dp__time-controls {
  display: flex;
  align-items: center;
  gap: 6px;
}

.dp__sel {
  width: 76px;
  min-height: 38px;
  font-variant-numeric: tabular-nums;
}

.dp__colon {
  font-weight: 700;
}

.dp__foot {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}

.dp__foot .btn {
  flex: 1;
  min-height: 38px;
}

/* ── Разгребатель бесхозных задач ─────────────────────────────── */

/* Одна разметка на обе ширины: панель не рисует ничего, чего нет на телефоне,
   поэтому второй раскладки для неё не нужно. Отличие только в рамке — на
   широком экране панель уже лежит в карточке списка (.trg--flat). */

.trg {
  margin-top: 12px;
  /* .card прячет переполнение ради листьев в углах — здесь листьев нет, зато
     overflow: hidden отменил бы sticky у панели действий: липкий элемент
     цепляется за ближайшего предка с прокруткой, а им стала бы сама карточка,
     которая не прокручивается никогда. */
  overflow: visible;
}

.trg--flat {
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}

.trg__head {
  margin-bottom: 12px;
}

.trg__title-h {
  font-size: var(--t-16);
  font-weight: 700;
}

.trg__text {
  margin-top: 4px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.5;
}

/* Панель действий липнет к верху, а не к низу экрана. Внизу телефона уже стоит
   панель вкладок с безопасной зоной под ней, и вторая плавающая полоса поверх
   неё встала бы либо на вкладки, либо под жест «домой». Сверху она к тому же
   рядом с «Выбрать все», к которому и относится. */
.trg__bar {
  position: sticky;
  top: calc(var(--appbar-h) + env(safe-area-inset-top));
  z-index: 3;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 -4px 4px;
  padding: 8px 4px;
  background: var(--card);
}

.trg--flat .trg__bar {
  top: 0;
  background: var(--card);
}

.trg__all {
  flex: none;
  min-height: var(--tap);
  padding: 0 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--card);
  color: var(--ink);
  font-size: var(--t-13);
  font-weight: 600;
}

.trg__all:hover {
  background: var(--card-2);
}

.trg__count {
  flex: 1;
  min-width: 0;
  color: var(--muted);
  font-size: var(--t-13);
  font-variant-numeric: tabular-nums;
}

.trg__go {
  flex: none;
  min-height: var(--tap);
  padding: 0 16px;
  font-size: var(--t-13);
}

/* Кнопка гаснет, а не исчезает: пока ничего не выбрано, она всё равно говорит,
   что произойдёт после выбора. Исчезающая кнопка оставила бы список без
   единого намёка на то, зачем эти галочки. */
.trg__go[disabled] {
  opacity: 0.45;
  cursor: not-allowed;
}

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

.trg__row {
  display: flex;
  align-items: center;
  /* Восемь пикселей, а не четыре: рядом стоят две разные цели — «выбрать» и
     «открыть», — и промах между ними означает не ту команду, а не просто
     неточность. */
  gap: 8px;
  border-bottom: 1px solid var(--line);
}

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

.trg__row.is-picked {
  background: var(--green-soft);
}

/* Вся строка — один переключатель: у него есть имя (название задачи), и
   попасть по нему можно любым местом строки, а не квадратиком в 22 пикселя. */
.trg__main {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  min-height: var(--tap);
  padding: 8px 6px;
  text-align: left;
}

.trg__main .check__box {
  flex: none;
}

.trg__main[aria-pressed='true'] .check__box {
  border-color: var(--green);
  background: var(--green);
}

.trg__main[aria-pressed='true'] .check__box svg {
  opacity: 1;
}

.trg__body {
  min-width: 0;
}

.trg__title {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-15);
}

.trg__sub {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: var(--t-12);
}

.trg__sub--alert {
  color: var(--red);
}

.trg__row--done .trg__title {
  color: var(--muted);
  text-decoration: line-through;
}

.trg__row .iconbtn {
  flex: none;
  color: var(--muted);
}

.trg__form {
  padding: 14px;
}

.trg__note {
  margin-top: 12px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.5;
}

/* ── Обещания, Профиль и Категории на широком экране ──────────── */

/* Три экрана до этого широкой раскладки не имели вовсе: телефонная вёрстка
   растягивалась во всю колонку вместе с мобильной шапкой и стрелкой «назад» из
   раздела, который стоит в боковом меню. Правило то же, что у Архива: разметка
   широкая по умолчанию скрыта, мобильная скрывается на широком экране. */
.prdash,
.profdash,
.catdash {
  display: none;
}

@media (min-width: 1100px) {
  .prdash,
  .profdash,
  .catdash {
    display: block;
  }

  /* Карточки обещаний уже лежат внутри .dcard — свой отступ сверху им там ни к
     чему, его задаёт заголовок карточки. */
  .promises--desk {
    margin-top: 0;
  }

  /* Профиль в семью экранов «во всю высоту» не входит: содержимое у него
     постоянное и короткое, а .pmain выше растягивает колонки под самую высокую.
     Карточка учётной записи вытягивалась бы до правого столбца и держала под
     текстом три сотни пикселей пустоты. Здесь колонки жмутся к содержимому. */
  .profdash .pmain {
    align-items: start;
  }

  .prside__dot {
    flex: none;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--green);
  }

  /* Правила и пояснения. Узкая колонка здесь не только про вид: это она держит
     строку в читаемой длине, а на всю ширину карточки текст разгонялся до двух
     сотен символов. */
  .prside__rules {
    display: flex;
    flex-direction: column;
    gap: 10px;
    color: var(--muted);
    font-size: var(--t-13);
    line-height: 1.5;
  }

  .prside__rules li {
    position: relative;
    padding-left: 14px;
  }

  .prside__rules li::before {
    content: '';
    position: absolute;
    top: 7px;
    left: 0;
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--green);
  }

  /* ── Профиль ───────────────────────────────────────────────── */

  .prof__me {
    display: flex;
    align-items: center;
    gap: 16px;
  }

  .prof__avatar {
    flex: none;
    width: 64px;
    height: 64px;
    font-size: var(--t-20);
  }

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

  .prof__who strong {
    font-size: var(--t-20);
  }

  .prof__who span {
    color: var(--muted);
    font-size: var(--t-13);
  }

  .prof__counts {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--gap);
  }

  .prof__counts li {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 12px 14px;
    border-radius: var(--radius-btn);
    background: var(--card-2);
  }

  .prof__counts strong {
    font-size: var(--t-20);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
  }

  .prof__counts span {
    color: var(--muted);
    font-size: var(--t-13);
  }

  .prof__note {
    margin-top: 14px;
    color: var(--muted);
    font-size: var(--t-13);
    line-height: 1.5;
  }

  .prof__links button {
    width: 100%;
    /* Строка целиком, а не одна текстовая: в боковой карточке это единственная
       цель, и мельчить её незачем. */
    min-height: var(--tap);
    padding: 6px 0;
  }

  .prof__ic {
    flex: none;
    display: grid;
    place-items: center;
    width: 32px;
    height: 32px;
    border-radius: var(--radius-btn);
    background: var(--card-2);
    color: var(--green-dk);
  }

  .prof__ic svg {
    width: 17px;
    height: 17px;
  }

  .prof__link-body {
    display: flex;
    flex-direction: column;
    min-width: 0;
  }

  .prof__link-sub {
    color: var(--muted);
    font-size: var(--t-13);
  }

  .prof__links svg:last-child {
    margin-left: auto;
    flex: none;
    width: 16px;
    height: 16px;
    color: var(--muted);
  }

  /* ── Категории ─────────────────────────────────────────────── */

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

  .catrow {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 200px 96px 48px;
    align-items: center;
    gap: 14px;
    border-bottom: 1px solid var(--line);
  }

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

  .catrow__main {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    /* Вся ячейка, а не одна строка текста: в списках приложения кликабельной
       часто оказывалась только надпись в восемнадцать пикселей посреди
       шестидесятипиксельной строки. */
    min-height: var(--tap);
    padding: 8px 0;
    text-align: left;
  }

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

  /* Полоса — вторая запись того же числа, что стоит рядом словами. Поэтому
     aria-hidden в разметке: скринридеру она повторила бы «12 задач · 34%». */
  .catrow__bar {
    display: block;
    height: 8px;
    border-radius: var(--radius-pill);
    background: var(--card-2);
    overflow: hidden;
  }

  .catrow__bar span {
    display: block;
    height: 100%;
    border-radius: var(--radius-pill);
  }

  .catrow__num {
    color: var(--muted);
    font-size: var(--t-13);
    text-align: right;
  }

  .catrow__share {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: right;
  }
}

/* ── Приглашение поставить оболочку ───────────────────────────── */

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

   z-index 75 — между листом (40/41) и подтверждением (60/61) с одной стороны и
   строкой заголовка оболочки (80) с другой. Внутри самой оболочки приглашение
   не показывается вовсе, но порядок держим осмысленным, а не «побольше». */
.inst__scrim {
  position: fixed;
  inset: 0;
  z-index: 74;
  background: rgba(20, 26, 20, 0.55);
  animation: fade var(--slow) var(--ease);
}

.inst {
  position: fixed;
  inset: 0;
  z-index: 75;
  display: grid;
  place-items: center;
  padding: 24px;
  overflow-y: auto;
  /* Полупрозрачное стекло поверх формы входа: за ним видно, куда человек шёл, и
     ясно, что приглашение — поверх, а не вместо. */
  /* Сквозь стекло должна читаться форма входа — иначе приглашение читается
     как отдельная страница, и непонятно, куда ведёт «Продолжить в браузере».
     Сама карточка ниже непрозрачная: текст читается на своём фоне, а не
     на просвечивающей форме. */
  background: color-mix(in srgb, var(--bg) 55%, transparent);
  backdrop-filter: blur(7px);
  opacity: 0;
  transition: opacity var(--slow) var(--ease);
}

.inst.is-in {
  opacity: 1;
}

/* Зерно. SVG-шум в data-URI, а не картинкой: файл в несколько килобайт ради
   слоя, который целиком описывается одной строкой фильтра, — лишний запрос и
   лишний файл в сборке. baseFrequency подобрана так, чтобы зерно читалось как
   плёночное, а не как рябь на экране.

   pointer-events: none обязательны: слой лежит поверх содержимого и без этого
   съедал бы нажатия по кнопкам под собой. */
.inst__grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0.5;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Зерно — украшение. При включённом «меньше движения» оно остаётся (оно
   неподвижно), но на слабых машинах размытие фона дорого, поэтому его снимаем:
   стекло превращается в плотную заливку, читаемость от этого только растёт. */
@media (prefers-reduced-motion: reduce) {
  .inst {
    backdrop-filter: none;
    background: var(--bg);
  }
}

.inst__body {
  position: relative;
  width: 100%;
  max-width: 440px;
  padding: 28px 24px 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--card);
  box-shadow: var(--shadow-lift);
  text-align: center;
}

.inst__logo {
  width: 72px;
  height: 72px;
}

.inst__title {
  margin-top: 10px;
  font-size: var(--t-20);
  font-weight: 700;
}

.inst__lead {
  margin-top: 6px;
  color: var(--muted);
  font-size: var(--t-13);
  line-height: 1.5;
}

.inst__list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin: 18px 0;
  text-align: left;
}

.inst__list li {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.inst__ic {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: var(--radius-btn);
  background: var(--green-soft);
  color: var(--green-dk);
}

.inst__ic svg {
  width: 18px;
  height: 18px;
}

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

.inst__what strong {
  font-size: var(--t-15);
}

.inst__what span {
  color: var(--muted);
  font-size: var(--t-12);
  line-height: 1.45;
}

/* text-decoration снимаем явно: это ссылка на файл, а не кнопка, и подчёркивание
   браузера пробивалось сквозь .btn. Ссылка, а не кнопка — нарочно: средним
   щелчком её можно открыть в новой вкладке, и адрес файла виден в строке состояния
   до нажатия — перед загрузкой в восемьдесят мегабайт это честно. */
.inst__get {
  gap: 8px;
  text-decoration: none;
}

.inst__get svg {
  width: 18px;
  height: 18px;
}

.inst__meta {
  margin-top: 10px;
  color: var(--muted);
  font-size: var(--t-12);
  line-height: 1.45;
}

/* Про SmartScreen говорим ДО скачивания, а не после. Человек, увидевший
   красное окно Windows впервые и без предупреждения, решает, что подхватил
   вирус, — и он прав, что настораживается: подписи у сборки правда нет. */
.inst__warn {
  margin-top: 8px;
  padding: 8px 10px;
  border-radius: var(--radius-btn);
  background: var(--amber-soft);
  color: var(--on-amber-soft);
  font-size: var(--t-12);
  line-height: 1.45;
  text-align: left;
}

.inst__skip {
  width: 100%;
  min-height: var(--tap);
  margin-top: 14px;
  border-radius: var(--radius-btn);
  color: var(--muted);
  font-size: var(--t-15);
}

.inst__skip:hover {
  background: var(--card-2);
  color: var(--ink);
}

/* Низкое окно: панель листается вместе с приглашением, а не обрезается по
   краю. place-items: center выше на прокрутку не влияет — сетка сама уводит
   содержимое к началу, когда оно выше контейнера. */
@media (max-height: 700px) {
  .inst {
    place-items: start center;
  }
}

/* ── Конструктор КП на карточке задачи ────────────────────────────
   Дорожка этапов: что уже отмечено конструктором, а что ещё впереди.
   Отметки ставит не человек, поэтому строки не кликабельны — это
   состояние, а не список действий, и выглядеть оно должно иначе. */
.tdetail__kp .hint { margin: 0 0 12px; }

.kpsteps {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: grid;
  gap: 2px;
}

.kpstep {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 8px 0;
  position: relative;
}

/* Нить между отметками: видно, что это один путь, а не четыре пункта. */
.kpstep + .kpstep::before {
  content: '';
  position: absolute;
  left: 11px;
  top: -6px;
  width: 2px;
  height: 12px;
  background: var(--line);
  border-radius: 2px;
}
.kpstep--done + .kpstep::before { background: var(--green); }

.kpstep__mark {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--card-2);
  color: var(--muted);
}
.kpstep__mark svg { width: 14px; height: 14px; }
.kpstep--done .kpstep__mark { background: var(--green); color: var(--on-green); }

.kpstep__body { min-width: 0; }
.kpstep__name {
  display: block;
  font-size: 14px;
  color: var(--muted);
}
.kpstep--done .kpstep__name { color: var(--ink); font-weight: 600; }
.kpstep__hint {
  display: block;
  font-size: 12.5px;
  color: var(--muted);
  margin-top: 1px;
}
