/*
  Из «Дедлайна» взята только СТРУКТУРА: нижний таб-бар, плотность вёрстки,
  компоновка карточек, спокойный тон. Внешний вид — синапсовский.

  Цвета не заданы здесь буквами: их считает app.js по палитрам из
  ios-prototype/TaskAIPrototype/App/AppTheme.swift (десять тем, те же формулы
  смешивания для panel, panelStrong и stroke) и подставляет в переменные ниже
  на <html>. Значения в этом блоке — только запасной вариант на случай, если
  скрипт не успел отработать: тема paper, светлая.

  Имена переменных повторяют имена из AppTheme: background, panel, panelStrong,
  stroke, textPrimary, textSecondary, accent, accentWarm, focusGreen, focusBlue.
*/

:root{
  --background:#F6F2E7;
  --panel:#EDE9DE;
  --panel-strong:#E4E0D5;
  --stroke:#DCD5C4;
  --text:#211F1A;
  --text-2:#615C50;
  --accent:#25503B;
  --accent-warm:#8A6E35;
  --focus-green:#3F6B52;
  --focus-blue:#2F5A72;
  --accent-soft:rgba(37,80,59,.10);
  --danger:#9C3B2E;

  /* Структурные псевдонимы: карточка — это panel, разделитель — stroke. */
  --bg:var(--background);
  --card:var(--panel);
  --soft:var(--panel-strong);
  --soft-2:var(--stroke);
  --fg:var(--text);
  --fg-2:var(--text-2);
  --fg-3:var(--text-2);
  --line:var(--stroke);
  --ok:var(--focus-green);
  --warn:var(--accent-warm);
  --crit:var(--danger);

  /* Одна колонка на всю страницу: шапку, контент и плашку об ошибке держит
     одна и та же мерка, иначе они разъезжаются между собой. */
  --col:820px;
  --pad:20px;
  /* Вертикальный ритм: карточки на расстоянии --gap, строки внутри списков
     на --gap-row. Раньше здесь было четыре разных значения вперемешку. */
  --gap:10px;
  --gap-row:8px;

  --shadow:0 1px 2px rgba(20,22,26,.04), 0 8px 24px rgba(20,22,26,.05);
  --shadow-lift:0 2px 4px rgba(20,22,26,.05), 0 14px 34px rgba(20,22,26,.09);
  --r-xl:26px; --r-lg:22px; --r-md:16px; --r-sm:12px;
  /* Приложение набрано скруглённым системным шрифтом — тот же и здесь. */
  --display:ui-rounded,"SF Pro Rounded",Manrope,-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
  --body:ui-rounded,"SF Pro Rounded",Manrope,-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
  --mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace;
}
:root[data-dark="1"]{
  --shadow:0 1px 2px rgba(0,0,0,.3), 0 8px 24px rgba(0,0,0,.28);
  --shadow-lift:0 2px 6px rgba(0,0,0,.35), 0 16px 40px rgba(0,0,0,.4);
}

*{box-sizing:border-box}

/* В приложении текст интерфейса не выделяется от касания.

   Для WebView нажатие по слову — это нажатие по тексту: андроид принимает
   касание заголовка «СЕГОДНЯ» или названия задачи за начало выделения и
   поднимает синюю подсветку с ручками и панелькой «Копировать». В браузере
   так и надо, там страница — документ. В приложении это выглядит поломкой:
   интерфейс не копируют, его нажимают.

   Заодно перестаёт спорить перетаскивание: задача берётся зажимом, а зажим —
   тот же жест, которым система начинает выделять слово, и они делили одно
   касание.

   Поля ввода исключены явно и не случайно: без выделения в них не поставить
   курсор в середину строки и не выбрать написанное, то есть текст можно было
   бы только дописывать и стирать с конца. Правило для них идёт следом и
   перебивает общее — у него специфичность выше. */
.in-app, .in-app *{
  -webkit-user-select:none;
  user-select:none;
  /* Серая вспышка во весь прямоугольник при касании — тоже привычка браузера.
     У кнопок есть собственное :active, и оно точнее. */
  -webkit-tap-highlight-color:transparent;
}
.in-app input, .in-app textarea{
  -webkit-user-select:text;
  user-select:text;
}
/* Размер шрифта — те же три ступени, что в приложении (0.88 / 1 / 1.16).
   Вёрстка набрана в пикселях, поэтому масштабируем корень целиком: иначе
   пришлось бы переписать каждое значение, а половину всё равно забыть.
   zoom, а не transform: он меняет раскладку, а не растягивает картинку, и
   фиксированные панели остаются на своих местах. */
html{zoom:var(--scale, 1)}
/* clip, а не hidden. `overflow-x:hidden` на body делает его прокручиваемым
   контейнером: из-за этого липкая шапка переставала липнуть (её скролл-портом
   становился body, который сам не прокручивается), а события scroll переставали
   доходить до window — колонка меню не знала, что страницу листают.
   `clip` режет то же самое по горизонтали, но контейнера прокрутки не создаёт. */
html,body{overflow-x:clip}
body{margin:0; background:var(--bg); color:var(--fg); font-family:var(--body); font-size:16px; line-height:1.5; -webkit-font-smoothing:antialiased}
h1,h2,h3{font-family:var(--display); font-weight:700; letter-spacing:-.035em; margin:0}
p{margin:0}
button{font:inherit; color:inherit; cursor:pointer; background:none; border:0; padding:0; text-align:left}
input,textarea,select{font:inherit; color:inherit; max-width:100%}
:focus-visible{outline:2px solid var(--fg); outline-offset:3px; border-radius:8px}
.mono{font-family:var(--mono); font-variant-numeric:tabular-nums}
.hidden{display:none !important}
/* Подпись для читалок с экрана: невидима глазом, но поле не остаётся безымянным. */
.visually-hidden{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap}

/* ============ ШАПКА ============ */
/* Шапка и колонка контента живут по одной мерке. Раньше шапка была зажата в
   820 px, а на широком экране колонка расширялась до 1000 — логотип уезжал
   внутрь на девяносто пикселей относительно карточек под ним. */
.top{position:sticky; top:0; z-index:30; background:var(--bg)}
/* Линия под шапкой раньше шла во всю ширину окна и на широком экране
   начиналась в пустоте слева от колонки. Теперь она принадлежит самой
   колонке: начинается ровно под логотипом и кончается под аватаркой. */
.top-in{max-width:var(--col); margin:0 auto; padding:14px var(--pad); display:flex; align-items:center; gap:12px; position:relative}
.top-in::after{content:''; position:absolute; left:var(--pad); right:var(--pad); bottom:0; height:1px; background:var(--line)}
/* Логотип теперь кнопка «домой»: убираем всё, что браузер добавляет кнопке
   от себя, и оставляем нажимаемость — курсор и лёгкое затемнение. */
.brand{display:flex; align-items:center; gap:12px; min-width:0;
  background:none; border:0; padding:0; margin:0; font:inherit; color:inherit;
  cursor:pointer; text-align:left; border-radius:12px}
.brand:hover{opacity:.78}
.brand:active{opacity:.6}
/* Знак — настоящий логотип, тот же файл, что иконкой приложения. Раньше
   здесь стояла буква S в квадрате: заглушка, которая пережила все остальные. */
/* Логотип и название крупнее. Шапка — единственное место, где написано, в
   чём человек вообще находится, и мельче остального текста ей быть незачем. */
.brand .mark{width:44px; height:44px; border-radius:13px; flex:none; display:block; object-fit:contain}
.brand .nm{font-family:var(--display); font-size:27px; font-weight:800; letter-spacing:-.05em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
/* Шапка на телефоне.

   Знак в 44 пикселя с отступами по 14 съедал 72 пикселя высоты — десятую
   часть экрана — и на нём не написано ничего, кроме названия, которое человек
   и так знает. Ужимаем всё разом: знак, шрифт названия, отступы и кнопки.
   Получается 52 вместо 72, и это ровно одна карточка задачи сверху. */
@media (max-width:759px){
  .top-in{padding:9px var(--pad)}
  .brand .mark{width:30px; height:30px; border-radius:9px}
  .brand .nm{font-size:20px}
  .brand{gap:9px}
  .top-acts{gap:6px}
  .iconbtn{width:34px; height:34px}
  .iconbtn .nav-ic{width:17px; height:17px}
  .whoami{padding:3px 10px 3px 3px; max-width:150px}
  .whoami .avatar{width:28px; height:28px; font-size:11px}
  .whoami .nm{font-size:13px}
}
@media (max-width:420px){
  .brand .mark{width:28px; height:28px; border-radius:8px}
  .brand .nm{font-size:18px}
  /* Имя рядом с аватаркой уходит: на 375 пикселях оно отжимает название
     сервиса, а сам кружок и так ведёт в профиль. */
  .whoami .nm{display:none}
  .whoami{padding:3px; max-width:none}
}
.top-acts{margin-left:auto; display:flex; align-items:center; gap:8px; flex:none; min-width:0}
/* Аватарка с именем рядом. Имя обрезается многоточием, а не выдавливает
   кнопку темы с экрана. */
.whoami{display:flex; align-items:center; gap:9px; padding:4px 12px 4px 4px; border-radius:999px; background:var(--card); border:1px solid var(--stroke); box-shadow:var(--shadow); min-width:0; max-width:220px}
.whoami:not(:has(.nm)){padding-right:4px}
.whoami .nm{font-size:14px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; min-width:0}
.whoami.on{background:var(--fg); color:var(--bg); border-color:var(--fg)}
.whoami.on .avatar{background:transparent; color:var(--bg)}
.iconbtn{width:38px; height:38px; border-radius:999px; background:var(--card); border:1px solid var(--stroke); box-shadow:var(--shadow); display:grid; place-items:center; font-size:15px; flex:none}
.iconbtn .nav-ic{width:19px; height:19px}
.iconbtn.on{background:var(--fg); color:var(--bg)}

/* Снизу оставлено место под таб-бар и строку ввода, иначе они накрывают
   последнюю карточку. */
/* На узких экранах навигация — плавающий таб-бар внизу, как в приложении.
   На широких он же разворачивается в боковую колонку: веб открывают с
   ноутбука, и растянутый на весь монитор телефон там читается как недоделка.
   Разметка при этом одна и та же — меняется только раскладка (см. --rail). */
.warnbar{max-width:var(--col); margin:0 auto; padding:10px var(--pad) 12px; display:flex; gap:12px; align-items:center; flex-wrap:wrap; font-size:13.5px; color:var(--danger)}
.warnbar span{flex:1; min-width:200px}

main{max-width:var(--col); margin:0 auto; padding:24px var(--pad) 230px}

/* ============ ОБЩЕЕ ============ */
.hi{font-size:14px; color:var(--fg-3)}
h1.page{font-size:clamp(28px,7vw,38px); margin:2px 0 20px}
.lbl{font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase; color:var(--fg-3); display:flex; justify-content:space-between; align-items:center; margin:26px 0 12px}
.card{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg); box-shadow:var(--shadow); padding:18px; margin-bottom:var(--gap)}
.card h3{font-size:19px}
.card .sub{font-size:13.5px; color:var(--fg-2); margin-top:5px}
.grid2{display:grid; grid-template-columns:1fr; gap:var(--gap)}
@media (min-width:900px){ .grid2{grid-template-columns:1fr 356px; align-items:start} }

/* Колонок столько, сколько плиток, а не всегда четыре.

   Жёсткие четыре колонки писались под помодоро, где плиток ровно четыре. В
   медитации их две — и они занимали первые две клетки из четырёх, оставляя
   полэкрана пустым слева направо. auto-fit растягивает любое число поровну. */
.counts{display:grid; grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));
  gap:var(--gap); margin-bottom:var(--gap)}
.cnt{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-md); box-shadow:var(--shadow); padding:15px 16px}
.cnt .v{font-family:var(--mono); font-size:25px; font-weight:600; letter-spacing:-.03em; line-height:1; display:block}
.cnt .l{font-size:12.5px; color:var(--fg-2); margin-top:6px; display:block}

.bar{height:12px; background:var(--soft); border-radius:999px; overflow:hidden}
.bar i{display:block; height:100%; border-radius:999px; background:var(--ok); transition:width .3s ease}
.bar.slim{height:8px}
.barline{display:flex; justify-content:space-between; align-items:baseline; margin-bottom:8px; font-size:12.5px; color:var(--fg-2); gap:12px}
.barline b{font-family:var(--mono); font-size:14px; font-weight:600; color:var(--fg)}

.chip{font-size:12px; padding:4px 10px; border-radius:999px; display:inline-flex; align-items:center; gap:6px; background:var(--soft); color:var(--fg-2); white-space:nowrap}
.chip.goal{background:var(--accent-soft); color:var(--accent)}
.chips{display:flex; gap:7px; flex-wrap:wrap}

.btn{background:var(--fg); color:var(--bg); border-radius:999px; padding:12px 22px; font-size:15px; font-weight:600; display:inline-flex; align-items:center; justify-content:center; gap:9px; text-align:center; transition:opacity .12s}
.btn:hover{opacity:.9}
.btn.soft{background:var(--card); color:var(--fg); border:1px solid var(--stroke); box-shadow:var(--shadow)}
.btn.full{display:flex; width:100%}
.btn.sm{padding:9px 16px; font-size:13.5px}
.acts{display:flex; gap:9px; flex-wrap:wrap; margin-top:16px}
/* Пара равных кнопок под главным действием: одинаковая ширина и высота, без
   переносов. Разнокалиберные кнопки в ряд читаются как собранные наспех. */
.acts.pair{display:grid; grid-template-columns:1fr 1fr; gap:10px}
.acts.pair .btn{width:100%; padding:11px 14px; font-size:14px}
.hint{font-size:13px; color:var(--fg-3); margin-top:12px; line-height:1.5}

/* пустые состояния */
.blank{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg); box-shadow:var(--shadow); text-align:center; padding:40px 22px; margin-bottom:var(--gap)}
.blank .ill{width:58px; height:58px; border-radius:20px; background:var(--soft); display:grid; place-items:center; margin:0 auto 16px; color:var(--fg-3)}
.blank .ill .nav-ic{width:26px; height:26px; stroke-width:1.7}
.blank h3{font-size:19px; margin-bottom:7px}
.blank p{font-size:14px; color:var(--fg-2); max-width:42ch; margin:0 auto}
.blank .btn{margin-top:18px}

/* ============ ФОРМЫ ============ */
.field{margin-bottom:16px}
.field label{font-family:var(--mono); font-size:10.5px; letter-spacing:.14em; text-transform:uppercase; color:var(--fg-3); display:block; margin-bottom:8px}
.inp{width:100%; border:0; background:var(--soft); border-radius:var(--r-md); padding:13px 15px; font-size:15.5px}
.inp:focus{outline:0; box-shadow:0 0 0 2px var(--fg) inset}
textarea.inp{resize:vertical; min-height:74px; line-height:1.45}
select.inp{appearance:none}
.row2{display:grid; grid-template-columns:1fr; gap:var(--gap)}
@media (min-width:560px){ .row2{grid-template-columns:1fr 1fr} }
.radios{display:flex; gap:8px; flex-wrap:wrap}
.radio{background:var(--soft); border-radius:999px; padding:9px 16px; font-size:13.5px; color:var(--fg-2)}
.radio[aria-pressed="true"]{background:var(--fg); color:var(--bg)}
.radios.sm .radio{padding:6px 12px; font-size:12.5px}
/* Палитра выбиралась вслепую: все десять чипов рисовались цветами текущей
   темы. Теперь каждый несёт свои — фон кружком и акцент точкой внутри. */
.radio.pal{display:inline-flex; align-items:center; gap:9px; padding-left:9px}
.radio.pal .sw{width:19px; height:19px; border-radius:999px; display:grid; place-items:center; border:1px solid rgba(128,128,128,.35); flex:none}
.radio.pal .sw i{width:8px; height:8px; border-radius:999px; display:block}
.rowadd{display:flex; gap:7px; align-items:center; margin-top:8px}
.rowadd .inp{flex:1; min-width:0; padding:8px 12px; font-size:14px; border-radius:var(--r-sm)}
.rowadd .btn{flex:none; padding:8px 15px; font-size:13.5px}

/* ============ ЗАДАЧИ ============ */
.group{margin-bottom:24px}
.group-h{display:flex; align-items:flex-end; gap:10px; margin-bottom:10px; width:100%; padding:2px 0}
.group-h h3{font-size:clamp(22px,6vw,34px); line-height:.86; text-transform:uppercase; font-weight:800; letter-spacing:-.045em; transform:scaleY(1.2); transform-origin:left bottom; margin-bottom:5px}
/* Стрелка, а не кнопка с кружком: круглая плашка спорила с самим заголовком.
   Размер средний — 20 пикселей, видно, но заголовок не перебивает. */
.group-h .car{color:var(--fg-2); margin-bottom:6px; font-size:20px; line-height:1; flex:none; transition:transform .18s ease}
.group-h:hover .car{color:var(--fg)}
.group-h.closed .car{transform:rotate(-90deg)}
.group-h .n{margin-left:auto; font-size:12.5px; color:var(--fg-3); margin-bottom:7px; flex:none; white-space:nowrap}

/* Шапка дня в приложении: значок слева, стрелка вплотную к слову.

   Стрелка стояла в десяти пикселях от заголовка и читалась как отдельный
   элемент строки, а не как признак этого блока — особенно теперь, когда дни
   свёрнуты и строк из них пять подряд. Пять пикселей ставят её при слове.

   Общий gap обнулён, а не уменьшен: значку, слову и стрелке нужны разные
   расстояния, одно число на всех даёт либо тесный значок, либо далёкую
   стрелку. Счётчик справа отодвинут margin-left:auto и от gap не зависит. */
.in-app .group-h{gap:0}
.in-app .group-h .group-ic{flex:none; display:block; margin:0 9px 6px 0; color:var(--fg-2)}
.in-app .group-h .group-ic svg{width:19px; height:19px; display:block; fill:none;
  stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.in-app .group-h .car{margin-left:5px}
/* Отступ под шапкой отделяет её от списка. У свёрнутого списка нет, и отступ
   превращается в пустую полосу между днями. */
.in-app .group.closed .group-h{margin-bottom:0}
/* Свёрнутый блок раньше просто исчезал через display:none — переход по такому
   не проигрывается. Теперь высоту ведёт та же обёртка, что у карточек. */
.tasklist-wrap{overflow:hidden; transition:height .24s ease, opacity .2s ease}
.group.closed .tasklist-wrap{height:0; opacity:0}
@media (prefers-reduced-motion:reduce){ .tasklist-wrap{transition:none} }
.group-sub{font-size:12.5px; color:var(--fg-3); margin:-6px 0 12px}
/* Колонка задаётся явно. Без неё трек берёт ширину по max-content самой
   широкой карточки, а не по контейнеру, и карточки вылезают за правый край
   экрана — на 375 px это было 387 px, то есть срезанное скругление и рамка.
   Скролла при этом не появлялось: его прячет overflow-x:hidden на html. */
.tasklist{display:grid; grid-template-columns:minmax(0,1fr); gap:var(--gap-row); min-height:12px}
.tasklist.over{outline:2px dashed var(--fg-3); outline-offset:5px; border-radius:var(--r-md)}
.dropnote{font-size:13px; color:var(--fg-3); background:var(--soft); border-radius:var(--r-md); padding:14px 16px; text-align:center}
/* Пустого блока дня в разметке нет вовсе. Полоса под приём появляется только
   пока задачу несут, и выглядит именно полосой — местом, а не разделом. */
.empty-drop{margin-bottom:var(--gap)}
.empty-drop .dropnote{border:1px dashed var(--stroke); background:transparent; padding:11px 16px; font-size:12.5px; letter-spacing:.02em; text-transform:lowercase}

/* Карточка ужата: 12/14 внутрь и 23-пиксельный кружок давали на телефоне три
   задачи на экран. Теперь помещается пять, при том же кегле названия. */
.item{position:relative; background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-md); box-shadow:var(--shadow);
  transition:transform .16s cubic-bezier(.2,.7,.3,1)}
/* Поле держит лицо, а не карточка.

   Пока поле было на карточке, лицо оказывалось уже её на ширину поля — и
   кнопки, прижатые к правому краю карточки, выглядывали из-под него даже у
   закрытой строки. Теперь лицо ровно во всю ширину и закрывает их целиком. */
.item.swipe > .swipe-face{padding:8px 10px 8px 11px}
/* Без свайпа поле держит сама карточка, как держало всегда.

   Сняв его ради подвижного лица, я оставил без отступов десктоп, где лица
   нет вовсе: текст лёг вплотную к рамке, а значки налезли на край. */
.item:not(.swipe){padding:8px 10px 8px 11px}
/* Свёрнутая часть не должна занимать высоту.

   Дал ей поле заодно с лицом — и свёрнутая карточка стала на восемь пикселей
   выше своего лица, из-под которого снизу выглянули кнопки. Поле только
   раскрытой. */
.item.swipe.open > .detail-wrap{padding:0 10px 8px 11px}
/* Карточка в руке едет за пальцем сама и без задержки: переход на ней
   превратил бы жест в вязкое перетягивание. */
/* Карточку под пальцем ведём без перехода, соседей — с переходом.

   Переход на всех сразу и давал ту дёрганость: карточка догоняла палец с
   задержкой в шестую долю секунды и постоянно промахивалась мимо него, а
   соседи, наоборот, перескакивали мгновенно, потому что их сдвиг шёл тем же
   правилом, что и рывок несомой. Теперь наоборот: несомая приклеена к пальцу,
   соседи расступаются плавно. */
.item.dragging{transition:none; cursor:grabbing; transform-origin:center}

/* В приложении карточку под пальцем видно, что подняли.

   Было почти незаметно: та же ширина, та же прозрачность, лёгкая тень — на
   ходу не отличить от лежащих рядом. Теперь она непрозрачная, с настоящей
   тенью и шире списка: выходит за его поля с обеих сторон, как лист, который
   вынули из стопки. Ширину даём отрицательными полями, а не масштабом — от
   scale текст мылится. */
.item.dragging.lifted{
  opacity:1; z-index:60;
  /* Несомая карточка не участвует в поиске «что под пальцем».

     Она едет прямо под ним, и elementFromPoint возвращал её саму — а через
     неё находился её РОДНОЙ список. Зона назначения залипала на исходном дне,
     и дни, над которыми проносили карточку, пропускались: система считала,
     что палец всё ещё в первом. */
  pointer-events:none;
  /* Вылет за поля списка задаёт скрипт при подъёме: у карточки вне потока
     отрицательные поля сдвигали бы её саму, а не расширяли. */
  background:var(--card);
  box-shadow:0 10px 26px rgba(20,22,26,.20), 0 2px 6px rgba(20,22,26,.10);
}
.item.dragging.lifted > .swipe-face{background:var(--card); padding-left:6px; padding-right:6px}

/* У раскрытой карточки свайпа нет.

   Панель правки растянута на всю высоту карточки, а раскрытая вдвое выше:
   кнопки оказывались посреди подпунктов и накрывали поле ввода. Закрывать её
   при раскрытии было мало — карточку раскрывали и свайпали снова. Пока
   карточка раскрыта, панели просто нет: правка и удаление доступны, когда её
   свернули обратно. */
.touch .item.swipe.open > .side,
.touch .item.swipe.folding > .side{display:none}
.touch .item.swipe.open > .swipe-face{left:0 !important}

/* Плашка места посадки. Не рамка и не пунктир: сплошная заливка отвечает
   «сюда попадёт», а не «здесь чего-то не хватает». */
.dragging-now .item:not(.dragging){transition:transform .18s cubic-bezier(.2,.8,.3,1)}
/* Первая расстановка щели при подъёме — без перехода, чтобы компенсация выноса
   совпала с ним в одном кадре и соседи не дёргались вверх-вниз. */
.no-drag-anim .item, .no-drag-anim [data-drop]{transition:none !important}
@media (prefers-reduced-motion:reduce){ .item{transition:none} }
.item-main{display:flex; gap:10px; align-items:flex-start}
/* ---- отметка выполнения ---- */
/* По умолчанию скруглённый квадрат, как в приложении. Форму задаёт data-box
   на корне; выбор в настройках рисует ту же кнопку через data-shape, поэтому
   правила ниже написаны один раз для обоих случаев. */
.box{width:20px; height:20px; border:2px solid var(--soft-2); border-radius:7px; flex:none; display:grid; place-items:center; font-size:10px; color:transparent; background:none; margin-top:1px; transition:background .14s ease, border-color .14s ease}
/* --mark задаётся, только когда человек выбрал свой цвет; иначе действует
   запасное значение и отметка красится темой, как раньше. */
.box.on{background:var(--mark, var(--ok)); border-color:var(--mark, var(--ok)); color:#fff}
/* Кружок «готово» рисуется на 20px, а пальцем в него попадают плохо: у Apple
   и Google минимум 44px, и это самая частая кнопка приложения. Растим ТОЛЬКО
   область попадания — прозрачным слоем поверх, — вид не меняется ни на пиксель.
   Вправо всего 6px: там начинается заголовок, который сам открывает задачу, и
   отнимать у него нажатия нельзя. */
.item .box{position:relative}
.item .box::after{content:''; position:absolute; inset:-12px -6px -12px -12px}

/* Галочка — линия, а не заливка.

   Правила у неё не было вовсе, и браузер применял своё умолчание: fill чёрным.
   Контур из трёх точек, залитый чёрным, превращается в кривую закорючку — её
   и было видно внутри каждой формы. Рисуем как задумано: белая линия по
   текущему цвету, без заливки. */
.box svg{width:11px; height:11px; display:block; fill:none; stroke:currentColor;
  stroke-width:2.2; stroke-linecap:round; stroke-linejoin:round}

:root[data-box="circle"] .box:not([data-shape]),
.box[data-shape="circle"]{border-radius:999px}
:root[data-box="sharp"] .box:not([data-shape]),
.box[data-shape="sharp"]{border-radius:3px}

/* Треугольник, звезда и сердце рамкой не рисуются — берём заливку и
   вырезаем форму. Пустое состояние остаётся видимым за счёт подложки. */
:root[data-box="triangle"] .box:not([data-shape]),
:root[data-box="star"] .box:not([data-shape]),
:root[data-box="heart"] .box:not([data-shape]),
.box[data-shape="triangle"], .box[data-shape="star"], .box[data-shape="heart"]{
  border:0; border-radius:0; background:var(--soft-2); color:transparent;
  width:22px; height:22px; font-size:9px;
}
:root[data-box="triangle"] .box.on:not([data-shape]),
:root[data-box="star"] .box.on:not([data-shape]),
:root[data-box="heart"] .box.on:not([data-shape]),
.box.on[data-shape="triangle"], .box.on[data-shape="star"], .box.on[data-shape="heart"]{
  /* Тот же выбранный цвет, что и у остальных форм. Здесь он красит саму
     фигуру, а не рамку с галочкой внутри — но выбирают-то один цвет на
     отметку, и три формы из шести не могли остаться при своём. */
  background:var(--mark, var(--ok)); color:transparent;
}
:root[data-box="triangle"] .box:not([data-shape]), .box[data-shape="triangle"]{
  clip-path:polygon(50% 4%, 96% 92%, 4% 92%);
}
:root[data-box="star"] .box:not([data-shape]), .box[data-shape="star"]{
  clip-path:polygon(50% 2%, 61% 36%, 97% 36%, 68% 58%, 79% 92%, 50% 71%, 21% 92%, 32% 58%, 3% 36%, 39% 36%);
}
:root[data-box="heart"] .box:not([data-shape]), .box[data-shape="heart"]{
  clip-path:path('M11 20 C 2 13, 1 7, 5 4 C 8 2, 11 4, 11 7 C 11 4, 14 2, 17 4 C 21 7, 20 13, 11 20 Z');
}
.radio.boxpick{display:inline-flex; align-items:center; gap:9px; padding-left:10px}
.radio.boxpick .box{margin-top:0}
.radio.markpick{display:inline-flex; align-items:center; gap:9px; padding-left:9px}
/* Кружок цвета того же размера, что кружок палитры рядом: два ряда кнопок
   подряд с разными по величине значками читаются как случайные. */
.radio.markpick .msw{width:19px; height:19px; border-radius:999px; flex:none;
  border:1px solid rgba(128,128,128,.35)}
.radio.markpick, .radio.markpick::after{justify-content:flex-start}
/* Название — кнопка: карточка раскрывается тапом целиком, но с клавиатуры
   нужна цель для табуляции. Выглядит как текст. */
.item .t{font-size:15px; font-weight:600; letter-spacing:-.015em; line-height:1.28; display:block; width:100%; overflow-wrap:anywhere; padding:0}
/* Выполненная задача выглядит выключенной.

   Раньше отличие сводилось к зачёркиванию цветом --soft-2 — то есть линией
   чуть темнее фона: на светлой теме её попросту не было видно, и закрытая
   задача читалась как открытая. Теперь линия того же цвета, что текст, сама
   карточка приглушена и стоит на утопленном фоне: сделанное не спорит за
   внимание с тем, что ещё предстоит. */
.item.done{background:var(--soft); border-color:transparent; box-shadow:none}
.item.done .t{
  color:var(--fg-3);
  text-decoration:line-through;
  text-decoration-color:currentColor;
  text-decoration-thickness:1.5px;
}
.item.done .expand, .item.done .side{opacity:.55}
.item.done .m span{color:var(--fg-3)}
.item-main{cursor:pointer}
.item .expand .car{display:inline-block; transition:transform .18s ease}
.item.open .expand .car{transform:rotate(180deg)}
.item .belongs{font-size:12.5px; color:var(--accent); margin-bottom:2px}
.item .m{font-size:12px; color:var(--fg-3); margin-top:3px; display:flex; gap:6px; flex-wrap:wrap; align-items:center}

/* Место вставки показывает щель между карточками, а не линия поверх них:
   соседи отъезжают ровно на высоту переносимой, и видно, куда она сядет.
   Сдвиг ставит скрипт (markDropSpot), здесь только его плавность — она уже
   задана на .item выше. */
.item .body{flex:1; min-width:0}
/* ---- свайп по карточке ----

   Кнопки лежат под карточкой справа, карточка съезжает влево и открывает их.
   Значки в каждой строке отъедали место у названия всегда, а нужны изредка. */
.swipe{position:relative; overflow:hidden}
.swipe > .side{position:absolute; right:0; top:0; bottom:0; z-index:0;
  display:flex; align-items:stretch; gap:0; margin:0}
.swipe > .side button{width:46px; height:auto; border-radius:0; display:grid;
  place-items:center; color:var(--fg-2); background:var(--soft-2)}
.swipe > .side button.kill{background:var(--danger); color:#fff}
.swipe > .side button svg{width:18px; height:18px; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}

/* Значки в строке задачи на десктопе — как были до свайпов, но по центру.

   Прижатые к верху, они держались за первую строку названия, а карточка с
   чипами вдвое выше — значки оказывались в её верхней трети и висели без
   опоры. По центру они привязаны к карточке целиком. */
.item:not(.swipe) .side{display:flex; gap:1px; flex:none; margin:0; align-self:center}
.item:not(.swipe) .side button{width:27px; height:27px; border-radius:999px;
  display:grid; place-items:center; color:var(--fg-3); font-size:13px}
.item:not(.swipe) .side button:hover{background:var(--soft); color:var(--fg)}

/* Лицо карточки едет поверх кнопок и обязано быть непрозрачным, иначе они
   просвечивают сквозь него в закрытом состоянии. */
/* Едем смещением, а не преобразованием.

   translateX на этом блоке молча не срабатывал — даже заданный вручную с
   !important. Разбираться, чем именно движок его глушит, дольше, чем обойти:
   у позиционированного блока left делает ровно то же и вопросов не вызывает. */
.swipe > .swipe-face{position:relative; left:0; z-index:1; background:var(--card)}
.swipe:not(.swiping) > .swipe-face{transition:left .2s cubic-bezier(.2,.8,.3,1)}
.swipe.swiped > .swipe-face{left:-92px}

/* Пока карточку ведут пальцем, браузер не должен листать страницу вбок. */
.swipe{touch-action:pan-y}

/* Пока карточку несут, пустые блоки становятся мишенью.

   У блока без задач список нулевой высоты: попасть в него пальцем нечем, и
   перенос в пустой день просто не срабатывал — палец опускался мимо, на сам
   заголовок блока. На время переноса даём каждому списку высоту строки. */
.dragging-now .tasklist{min-height:46px; border-radius:var(--r-md)}
/* Высота списка (щель снизу) меняется плавно, чтобы секции ниже съезжали
   мягко, а не скачком, когда карточка переходит между днями. При подъёме это
   гасится классом .no-drag-anim. */
.dragging-now [data-drop]{transition:padding-bottom .18s cubic-bezier(.2,.8,.3,1)}
/* Пунктирной рамки нет: она обводила список поверх карточек и читалась как
   поломка вёрстки. Куда упадёт карточка, и так видно по раскрывшейся щели —
   подсветки хватает мягкой заливки. */
.dragging-now .tasklist.over{background:var(--soft); outline:2px dashed var(--stroke); outline-offset:-2px}

/* В приложении вокруг списка не рисуется ничего.

   Пунктирная рамка с заливкой обводила весь блок дня и читалась как «сюда
   нельзя», хотя значила ровно обратное. Куда упадёт карточка, говорит плашка
   на месте посадки — второй указатель на том же экране только спорит с ней.

   Селектор составной, без пробела: и in-app, и dragging-now висят на одном и
   том же элементе — на корне страницы. С пробелом это читается как «потомок»,
   и правило не совпадало ни разу; рамку владелец так и видел. */
.dragging-now .tasklist.over{background:none; outline:none}
.dragging-now .tasklist{min-height:0}
/* Свёрнутый день подсвечиваем шапкой: списка там нет, а понимать, куда
   целишься, надо. */
.dragging-now .group.over > .group-h{background:var(--soft); border-radius:var(--r-sm)}

/* Финансовые строки — те же правила, но своё поле у лица.

   У них поле держит сама строка, и лицо оказалось бы уже её: те же кнопки,
   выглядывающие из-под закрытой строки, что уже ловили у задач. */
.finrow.swipe{padding:0}
.finrow.swipe > .swipe-face{display:flex; align-items:center; gap:10px; width:100%;
  padding:9px var(--fin-pad, 18px)}

/* У платежей строка — сетка из четырёх колонок, и обёртка стала одной её
   клеткой: лицо вышло на 88 пикселей уже строки, и кнопки торчали из-под
   него. Сетку теперь несёт само лицо, а строка становится простым блоком. */
.payrow.swipe{display:block; padding:0}
.payrow.swipe > .swipe-face{display:grid;
  grid-template-columns:minmax(0,1fr) 92px 100px auto;
  align-items:center; gap:10px; padding:10px var(--fin-pad, 18px)}
.debtrow.swipe{padding:0}
.debtrow.swipe > .swipe-face{padding:11px 13px}
/* Значки были символами шрифта (⇅ ✎ ✕): в разных браузерах разной толщины,
   а «перенести в блок» из стрелок не читалось вовсе. Теперь рисунок свой. */
.item .side button svg{width:16px; height:16px; display:block; fill:none; stroke:currentColor; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round}

/* ---- карточка списка и заметки ---- */
/* Была одна большая кнопка на всю карточку. Теперь внутри неё живут ещё две —
   правка и удаление, — а кнопку в кнопку класть нельзя, поэтому снаружи
   обычный article, а «открыть» осталось кнопкой на всю ширину. */
.row-card.swipe{display:block; padding:0}
.row-card.swipe > .main{display:block; width:100%; text-align:left; padding:14px 16px}
/* На десктопе карточка осталась такой, какой была: текст слева, кнопки
   справа в одном ряду. */
.row-card:not(.swipe){display:flex; align-items:flex-start; gap:8px}
.row-card:not(.swipe) > .main{flex:1; min-width:0; display:block; width:100%; text-align:left}
.row-card:not(.swipe) .side{display:flex; gap:1px; flex:none; margin:-4px -6px 0 0}
.row-card:not(.swipe) .side button{width:30px; height:30px; border-radius:999px;
  display:grid; place-items:center; color:var(--fg-3)}
.row-card:not(.swipe) .side button:hover{background:var(--soft); color:var(--fg)}

.row-card .side button svg{width:16px; height:16px; display:block; fill:none; stroke:currentColor; stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round}

/* Правка и удаление — по наведению.

   Нужны они раз в сотню взглядов на карточку, а висели на виду всегда и тянули
   глаз на себя вместо названия. Место под них остаётся занятым: убери его —
   и название на каждом наведении перекладывалось бы заново, строка бы прыгала.
   Там, где наведения не бывает (телефон, планшет), кнопки видны всегда — иначе
   до них попросту не добраться. */
/* Значки появляются под курсором.

   Там, где есть мышь, они не нужны постоянно: в списке из двадцати строк это
   шестьдесят значков, и глаз собирает их в столбцы вместо того, чтобы читать
   названия. Место под них остаётся занятым и в покое — иначе название на
   каждом наведении перекладывалось бы, и строка прыгала.

   На сенсоре этого правила нет вовсе: наводить там нечем, и там кнопки живут
   под карточкой, откуда их достаёт свайп. */
@media (hover:hover) and (pointer:fine){
  .item:not(.swipe) .side, .row-card:not(.swipe) .side{opacity:0; transition:opacity .14s ease}
  .item:not(.swipe) .side button, .row-card:not(.swipe) .side button{pointer-events:none}
  .item:not(.swipe):hover .side, .item:not(.swipe):focus-within .side,
  .row-card:not(.swipe):hover .side, .row-card:not(.swipe):focus-within .side{opacity:1}
  .item:not(.swipe):hover .side button, .item:not(.swipe):focus-within .side button,
  .row-card:not(.swipe):hover .side button,
  .row-card:not(.swipe):focus-within .side button{pointer-events:auto}
}
/* ---- плавное раскрытие ---- */
/* Высоту ведёт JS замером (foldOpen): приём с grid-template-rows от 0fr к 1fr
   короче, но в части движков нулевая fr-дорожка не схлопывается — карточка
   раскрывалась рывком. Замер работает везде.

   Свёрнутое состояние держит CSS, а во время перехода высоту задаёт inline —
   он перебивает правило ниже, а после перехода снимается. */
.detail-wrap,
.goalbody-wrap{overflow:hidden; transition:height .24s ease, opacity .2s ease}
.item:not(.open) .detail-wrap,
.goalcard:not(.open) .goalbody-wrap{height:0; opacity:0}
.item.open .detail-wrap,
.goalcard.open .goalbody-wrap{opacity:1}
@media (prefers-reduced-motion:reduce){
  .detail-wrap, .goalbody-wrap{transition:none}
}

/* Подпункты сдвинуты вправо под название задачи, а не стоят вровень с ней:
   вровень они читались как ещё несколько самостоятельных задач. Отступ равен
   кружку плюс зазор — ровно там, где начинается текст задачи. */
.item .detail{margin:7px 0 1px 30px; padding-top:8px; border-top:1px solid var(--line); display:grid; grid-template-columns:minmax(0,1fr); gap:6px}
.item .note{font-size:13px; color:var(--fg-2); background:var(--soft); border-radius:var(--r-sm); padding:8px 11px; overflow-wrap:anywhere}
.subline{display:flex; gap:10px; align-items:center; font-size:14px}
.subline .box{width:17px; height:17px; font-size:9px}
.subline.on span{color:var(--fg-3); text-decoration:line-through; text-decoration-color:var(--soft-2)}
.subline span{flex:1; min-width:0; overflow-wrap:anywhere}
.subline .kill{color:var(--fg-3); font-size:12px; flex:none}
.expand{font-size:12px; color:var(--fg-2); margin-top:4px; display:inline-flex; gap:6px; align-items:center}
.pct{font-family:var(--mono); font-size:12px; color:var(--fg-2)}

/* строка создания задачи */
/* Отступ снизу.

   Было 18 пикселей от края окна — и под панелью оставалась пустая полоса
   поверх системной панели телефона: два поля подряд, ни одно из которых
   ничего не показывает. Ужимаем до 8, но не меньше безопасной зоны: на
   айфонах там живёт полоска «домой», и панель под неё нельзя загонять.

   Строка создания стоит ровно на высоту панели выше: 73 плюс 9 зазора. */
:root{
  --dock: max(8px, env(safe-area-inset-bottom, 0px));
}
.composer{position:fixed; left:50%; transform:translateX(-50%); bottom:calc(var(--dock) + 82px + var(--vv-shift, 0px)); z-index:40; width:min(620px, calc(100% - 32px))}

/* Идёт ввод — нижней панели на экране нет вовсе.

   Мы перебрали все промежуточные варианты: двигать её вместе с клавиатурой,
   закреплять над клавиатурой. Оба раза она оставалась на экране и оба раза
   мешала, потому что во время ввода она не нужна ни в каком положении:
   человек печатает, а не переходит в другой раздел. display:none — это не
   «сдвинуть подальше», это убрать: элемента нет в раскладке, и появиться
   где-то сбоку или снизу ему нечем.

   Строка создания опускается на освободившееся место, иначе висела бы над
   пустотой в 82 пикселя — там, где панель была бы, если бы её не убрали. */
.kbd .tabbar{display:none !important}
.kbd .composer{bottom:calc(6px + var(--vv-shift, 0px))}
/* Строка ввода плавает над содержимым, а карточки под ней того же цвета —
   на светлых палитрах она в них растворялась. Поэтому фон здесь не card, а
   более плотный panelStrong, обводка в полный контраст текста и тень
   заметнее: панель должна читаться на любом фоне и в любой теме. */
.say{display:flex; gap:8px; align-items:center; background:var(--soft); border:1.5px solid var(--fg-3); border-radius:999px; padding:7px 7px 7px 18px; box-shadow:var(--shadow-lift), 0 0 0 5px var(--bg)}
.say input{flex:1; border:0; background:none; outline:0; font-size:15px; min-width:0}
.say input::placeholder{color:var(--fg-3); opacity:.85}
/* Кнопка ассистента слева от отправки: тише её, но заметнее обычной иконки.
   Фон — карточный, а не soft: сама панель уже soft, и кружок на ней пропадал. */
/* Искра одинаковая и в строке задач, и в строке финансов: правила были
   привязаны к .say, и в финансах кнопка выходила нулевой ширины — на экране
   её просто не было. */
.say .ai, .rowadd .ai{width:38px; height:38px; border-radius:999px; display:grid; place-items:center; flex:none; background:var(--card); border:1px solid var(--stroke); color:var(--accent)}
.say .ai:hover, .rowadd .ai:hover{background:var(--accent-soft); border-color:var(--accent)}
.say .ai svg, .rowadd .ai svg{width:19px; height:19px; fill:currentColor; stroke:none}
.say .send{width:38px; height:38px; border-radius:999px; background:var(--fg); color:var(--bg); display:grid; place-items:center; flex:none; font-size:17px}
.say .send .nav-ic{width:19px; height:19px; stroke-width:2}
.composer .hint{margin:8px auto 0; font-size:11.5px; background:var(--panel); border:1px solid var(--stroke); border-radius:14px; padding:8px 10px 8px 14px; max-width:520px; box-shadow:var(--shadow)}
.composer .hint.tip{display:flex; align-items:flex-start; gap:8px; text-align:left}
.composer .hint.tip span{flex:1; min-width:0}
.composer .hint.tip button{flex:none; width:20px; height:20px; border-radius:999px; display:grid; place-items:center; color:var(--fg-3); font-size:11px}
.composer .hint.tip button:hover{background:var(--soft); color:var(--fg)}

/* ============ МОЙ ФОКУС ============ */
/* Повторяет «Синапс» из приложения: заголовок с процентом справа, под ним
   строки брифинга «МЕТКА: текст», затем полоса дня и горизонт. */
.card.focus{position:relative; overflow:hidden}
.focus-h{display:flex; align-items:flex-start; gap:14px}
.focus-t{flex:1; min-width:0}
.focus-p{text-align:right; flex:none}
.focus-p b{font-family:var(--mono); font-size:31px; font-weight:700; letter-spacing:-.04em; line-height:1; display:block}
.focus-p span{font-size:10.5px; color:var(--fg-2); display:block; margin-top:3px}
.focus-lines{display:grid; gap:11px; margin-top:16px}
.fl{display:grid; gap:2px}
.fll{font-family:var(--mono); font-size:9.5px; font-weight:700; letter-spacing:.11em; color:var(--accent)}
.flt{font-size:13.5px; color:var(--fg); line-height:1.4}

.card.strips{padding:16px 18px}
.strip-split{height:1px; background:var(--line); margin:16px 0}
.strip-h{display:flex; align-items:center; gap:10px; flex-wrap:wrap}
.strip-h b{font-size:15px; font-weight:600}
.legend{margin-left:auto; display:flex; gap:12px; flex-wrap:wrap}
.lg{display:inline-flex; align-items:center; gap:4px; font-size:10.5px; color:var(--fg-2)}
.lg i{width:7px; height:7px; border-radius:999px; display:block; flex:none}
.lg b{font-family:var(--mono); font-size:12px; font-weight:600; color:var(--fg)}
.strip{display:flex; gap:3px; height:14px; margin-top:10px}
.strip i{flex:1; min-width:5px; border-radius:4px; background:var(--soft-2)}
.strip i.done{background:var(--ok)}
.strip i.late{background:var(--crit)}
.strip.empty{display:grid; place-items:center; background:var(--soft); border-radius:7px; font-size:10.5px; color:var(--fg-2)}
.strip-note{font-size:10.5px; color:var(--fg-3); margin-top:7px}

.horizon{display:flex; align-items:flex-end; gap:5px}
.hd{flex:1; min-width:0; display:grid; justify-items:center; gap:4px}
.hd .dot{width:5px; height:5px; border-radius:999px; background:var(--accent-warm); display:block}
.hd .bar{width:100%; border-radius:3px; background:var(--accent); opacity:.35; display:block}
.hd.now .bar{opacity:1}
.hd span{font-family:var(--mono); font-size:9px; color:var(--fg-3)}
.hd.now span{color:var(--fg); font-weight:700}

/* ============ ЦЕЛИ ============ */

/* Карточка цели ужата до трёх строк: название с процентом, полоска и одна
   строка подробностей. Всё остальное — смысл, этапы, задачи — раскрывается
   по нажатию прямо здесь, отдельной страницы у цели больше нет. */
.goalcard{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg); box-shadow:var(--shadow); margin-bottom:var(--gap)}
/* Поле теперь на обёртке: она и есть вся карточка. */
.goalcard.swipe > .gc-face{padding:14px 16px}
.goalcard:not(.swipe){padding:14px 16px}
.goalcard-h{display:flex; align-items:center; gap:10px; width:100%; padding:0}
.goalcard-h .gt{font-family:var(--display); font-size:16px; font-weight:700; letter-spacing:-.02em; flex:1; min-width:0; overflow-wrap:anywhere; line-height:1.25}
.goalcard-h .gp{font-size:13px; font-weight:600; color:var(--fg-2); flex:none}
.goalcard-h .car{color:var(--fg-2); font-size:14px; line-height:1; flex:none; width:24px; height:24px; border-radius:999px; background:var(--soft); display:grid; place-items:center; transition:transform .18s ease}
.goalcard-h[aria-expanded="false"] .car{transform:rotate(-90deg)}
.goalcard-h:hover .car{color:var(--fg); background:var(--panel-strong)}
.goalcard .bar{margin-top:9px}
.goalcard .gmeta{font-size:12px; color:var(--fg-3); margin-top:7px}
.goalcard .goalbody{margin-top:12px; padding-top:12px; border-top:1px solid var(--line)}
.goalcard .sub{font-size:13px; color:var(--fg-2); line-height:1.45}
.goalcard .gpurpose{margin:0 0 10px}
.goalcard .goalbody > .lbl{margin:16px 0 8px}
.goalcard .goalbody > .acts{margin-top:14px}

/* Этап — не коробка внутри коробки.
   Было три вложенных фона подряд: карточка цели, плашка этапа поверх неё и
   карточка задачи поверх плашки. Матрёшка: границ много, а какая из них
   что означает — на глаз не разобрать, и взгляд спотыкается о каждую.

   Иерархию держит вертикальная черта слева и отступ, а не заливка. Черта
   тянется вдоль всего этапа, поэтому видно, где он кончился, а фон остаётся
   один на всю цель. */
.stage{
  background:none; border-radius:0; margin-top:26px;
  padding:0 0 0 13px; border-left:2px solid var(--soft-2);
}
.stage:first-of-type{margin-top:14px}
/* Пройденный этап гасит черту: список сверху вниз читается как «эти позади». */
.stage.on{border-left-color:var(--ok)}

/* «Этап 2» — номер строкой над названием.

   Раскрытая цель читалась как один длинный список: заголовок этапа и название
   задачи различались кеглем на пункт, и глазу не за что было зацепиться, где
   кончается один уровень и начинается другой. Номер даёт и метку уровня, и
   место в очереди — этапы идут последовательно, и «сколько ещё» больше не
   надо считать строки. */
.st-num{
  font-family:var(--mono); font-size:9.5px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--fg-3); margin:0 0 5px;
}
.stage.on .st-num{color:var(--ok)}

/* Заголовок этапа — заголовок, а не строка списка. Кегль и начертание
   уводят его от названия задачи, которое идёт обычным текстом в 13.5. */
.stage-h{display:flex; gap:10px; align-items:center}
.stage-h .t{font-family:var(--display); font-size:15.5px; font-weight:700;
  letter-spacing:-.015em; flex:1; min-width:0; overflow-wrap:anywhere}
.stage-h .kill{color:var(--fg-3); font-size:12px; flex:none}
.stage.on .stage-h .t{color:var(--fg-3)}
.stage .detail{font-size:12.5px; color:var(--fg-3); margin-top:4px; padding-left:30px}

/* Задача внутри этапа — строка, а не карточка. Свой фон, рамка и тень у неё
   были ровно тем третьим слоем, который и путал; здесь её место в списке
   задано отступом и волосяной линией сверху. На экране «Задачи» карточка
   остаётся карточкой — там она сама себе контекст, и отнимать у неё вид
   незачем. */
/* Задачи сдвинуты под заголовок этапа, а не под его черту.

   Раньше они начинались от той же вертикали, что и сам этап, — то есть на
   картинке лежали рядом с ним, а не внутри. Отступ в тридцать пикселей ставит
   их под название этапа, за галочкой: теперь видно, что это его содержимое, а
   не следующий пункт того же уровня. Столько же у пояснения, у строки «нет
   задач» и у поля добавления — весь низ этапа выстроен по одной вертикали. */
.stage .tasks{margin-top:8px; margin-left:30px; display:grid; grid-template-columns:minmax(0,1fr); gap:0}
.stage .tasks .item{
  background:none; border:0; border-radius:0; box-shadow:none;
  padding:7px 0; border-top:1px solid var(--line);
}
/* Задача внутри этапа: поле опять на лице, иначе кусками торчат кнопки.

   Здесь у карточки своё поле — семь пикселей сверху и снизу, — и с ним она
   выше своего лица ровно на четырнадцать: под свайпом из-под лица выглядывали
   полоски кнопок сверху и снизу. Ровно та же ошибка, что у обычной задачи,
   только вылезла в другом месте, потому что правило здесь своё.

   Лицу нужен непрозрачный фон: внутри цели он тот же, что у карточки цели, —
   значит его не видно, а кнопки под ним не просвечивают. */
.stage .tasks .item.swipe{padding:0}
.stage .tasks .item.swipe > .swipe-face{padding:7px 0; background:var(--card)}
.stage .tasks .item:first-child{border-top:0}
.stage .tasks .item.drop-before::before{top:-1px}
.stage .none{font-size:12.5px; color:var(--fg-3); padding-left:30px; margin-top:6px}
/* Добавление задачи этапа — действие второго ряда, и выглядеть должно так же.
   С обычным полем и тёмной кнопкой оно оказывалось самым тяжёлым пятном в
   раскрытой цели и перебивало то, ради чего её открыли. */
.stage .rowadd{margin-top:8px; margin-left:30px; gap:6px}
.stage .rowadd .inp{
  background:none; border:0; border-bottom:1px solid var(--line);
  border-radius:0; padding:6px 2px; font-size:13.5px;
}
.stage .rowadd .inp:focus{box-shadow:none; border-bottom-color:var(--fg-3)}
.stage .rowadd .btn{
  background:none; color:var(--fg-3); border:1px solid var(--stroke);
  box-shadow:none; padding:6px 12px; font-size:13px; font-weight:500;
}
.stage .rowadd .btn:hover{color:var(--fg); border-color:var(--fg-3); opacity:1}

/* Черта этапа чуть плотнее фона: на бумажных палитрах stroke почти сливается
   с карточкой, а именно она здесь несёт всю иерархию. */
.stage{border-left-color:var(--panel-strong)}
:root[data-dark="1"] .stage{border-left-color:var(--soft-2)}
@media (min-width:560px){
  .stage .tasks{padding-left:30px}
}
.goalbody > .none{font-size:13px; color:var(--fg-3); margin:0 0 4px}
.status{font-family:var(--mono); font-size:10.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--fg-3); flex:none}

/* ============ MIND MAP ============ */
/* Холст шире экрана — крутится внутри своей рамки, страницу за собой не тянет
   (требование: горизонтальной прокрутки у страницы быть не должно). */
/* У рамки карты фиксированная высота. Раньше она подстраивалась под холст, и
   экран аналитики прыгал: одна цель — полоска, четыре — половина страницы. */
.mmwrap{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg); box-shadow:var(--shadow); padding:10px; margin-bottom:var(--gap); height:640px; overflow:auto; -webkit-overflow-scrolling:touch; display:grid; place-items:center}
/* На телефоне рамка ниже экрана, но заметно выше полоски: карта вписывается в
   неё целиком, и высота 640 пикселей там просто не нужна — она бы уехала под
   нижнюю панель. */
@media (max-width:759px){ .mmwrap{height:min(62vh, 460px)} }
.mmwrap svg{display:block; height:auto}

/* На телефоне в рамку помещался ствол и обрезанные края двух целей, а сверху
   и снизу оставалось пустое поле. Карта — это отдельный экран, а не врезка:
   по кнопке она разворачивается на всё окно и крутится в обе стороны. */
.mmfull{position:fixed; inset:0; z-index:80; background:var(--bg); display:flex; flex-direction:column}
.mmfull-bar{display:flex; align-items:center; gap:10px; padding:12px 16px; border-bottom:1px solid var(--line); flex:none}
.mmfull-bar .ttl{font-family:var(--mono); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase; color:var(--fg-3)}
.mmfull-bar .sp{margin-left:auto; display:flex; gap:7px}
.mmfull .mmwrap{flex:1; margin:0; border:0; border-radius:0; box-shadow:none; background:var(--bg); overflow:auto; display:grid; place-items:center; padding:16px}
.mmfull .mmlegend{padding:10px 16px 16px; margin:0; border-top:1px solid var(--line); flex:none}
body.mm-open{overflow:hidden}
.mm-link{fill:none; stroke:var(--stroke); stroke-width:1.4}
.mm-node{stroke-width:1}
.mm-label{font-family:var(--body); font-size:11px; fill:var(--text); dominant-baseline:middle}
.mm-label.sec{font-size:9.5px; fill:var(--text-2)}
.mm-core-label{font-family:var(--display); font-size:11px; font-weight:700; fill:var(--text); text-anchor:middle}
.mmlegend{display:flex; gap:14px; flex-wrap:wrap; font-size:12px; color:var(--fg-2); margin-top:10px}
.mmlegend i{width:10px; height:10px; border-radius:3px; display:inline-block; margin-right:6px; vertical-align:-1px; border:1px solid var(--stroke)}

.chip.late{background:transparent; color:var(--danger); border:1px solid var(--danger)}

/* ============ СПИСКИ / ЗАМЕТКИ / ПРОЧЕЕ ============ */
.lines{display:grid; grid-template-columns:minmax(0,1fr); gap:2px; margin-top:10px}
.line{display:flex; gap:11px; align-items:center; padding:9px 0; border-bottom:1px solid var(--line); font-size:15px}
.line:last-child{border-bottom:0}
.line span{flex:1; min-width:0; overflow-wrap:anywhere}
.line.on span{color:var(--fg-3); text-decoration:line-through; text-decoration-color:var(--soft-2)}
.line .kill{color:var(--fg-3); font-size:12px; flex:none}
.tilegrid{display:grid; grid-template-columns:repeat(2,1fr); gap:10px; margin-bottom:14px}
@media (min-width:700px){ .tilegrid{grid-template-columns:repeat(3,1fr)} }
.tilebtn{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg); box-shadow:var(--shadow); padding:18px; display:grid; gap:5px}
.tilebtn .ic{font-size:20px}
.tilebtn .tt{font-size:15.5px; font-weight:600}
.tilebtn .ss{font-size:12.5px; color:var(--fg-3)}
/* Заметка на весь экран: одна рамка, поле тянется до низа.

   min-height в 110 пикселей был рассчитан на поле внутри карточки. Теперь
   карточки нет, и поле должно занимать всё, что осталось от экрана: в заметку
   пишут длинный текст, и упираться в маленькое окошко посреди пустой
   страницы — худшее, что можно предложить. */
.note-field.solo{min-height:calc(100dvh - 260px); margin-top:0}
.note-field{width:100%; min-height:110px; border:0; background:var(--soft); border-radius:var(--r-md); padding:13px 15px; font-size:14.5px; line-height:1.5; margin-top:10px;
  /* Ни своей прокрутки, ни ручного размера: высоту ведёт содержимое, а
     прокручивается страница. Полоса внутри поля заставляла читать длинную
     запись через щель. */
  resize:none; overflow:hidden}
/* ============ МЕДИТАЦИЯ ============ */
/* Круг заполняется по ходу сеанса: conic-gradient по переменной --p, без
   единого кадра анимации в JS. Внутри круга — время и слово дыхания. */
.card.med{display:grid; justify-items:center; gap:22px; padding:30px 18px}
.med-dial{position:relative; width:min(248px, 62vw); aspect-ratio:1; display:grid; place-items:center}
.med-ring{
  position:absolute; inset:0; border-radius:999px;
  background:conic-gradient(var(--ok) calc(var(--p) * 360deg), var(--soft) 0);
  transition:background .9s linear;
  /* Кольцо, а не диск: середина вырезана маской, чтобы цифры не спорили с
     заливкой. */
  -webkit-mask:radial-gradient(circle, transparent 61%, #000 62%);
  mask:radial-gradient(circle, transparent 61%, #000 62%);
}
.med-dial::before{content:''; position:absolute; inset:14%; border-radius:999px; background:var(--soft); opacity:.4}
.med-face{position:relative; display:grid; justify-items:center; gap:4px}
.med-face b{font-family:var(--mono); font-size:clamp(34px,10vw,44px); font-weight:600; letter-spacing:-.045em; line-height:1}
.med-face span{font-size:13px; color:var(--fg-2)}
.card.med.on .med-face span{font-size:15px; color:var(--accent); font-weight:600}
.med-acts{display:flex; gap:9px; flex-wrap:wrap; justify-content:center}

/* Громкость — часть карточки с кругом, а не отдельный блок ниже: её крутят,
   слушая звук, и разносить их по разным местам незачем. */
.med-vol{display:flex; align-items:center; gap:12px; width:min(320px,100%); padding-top:4px}
.med-vol .ic{flex:none; display:grid; place-items:center}
.med-vol .ic svg{width:17px; height:17px; fill:none; stroke:var(--fg-3); stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round}
.med-vol .vv{font-size:13px; color:var(--fg-3); width:2.2em; text-align:right; flex:none}
.range{flex:1; min-width:0; appearance:none; height:6px; border-radius:999px; background:var(--soft); outline:none}
.range::-webkit-slider-thumb{appearance:none; width:18px; height:18px; border-radius:999px; background:var(--fg); cursor:pointer; border:0}
.range::-moz-range-thumb{width:18px; height:18px; border-radius:999px; background:var(--fg); cursor:pointer; border:0}

/* Шесть сред в ряд на широком экране, три на телефоне: двенадцать плиток
   должны читаться сеткой, а не лентой. */
.soundgrid{display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:var(--gap-row); margin-bottom:var(--gap)}
@media (min-width:560px){ .soundgrid{grid-template-columns:repeat(6,minmax(0,1fr))} }
.soundcard{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-md); box-shadow:var(--shadow); padding:11px 8px 10px; display:grid; gap:6px; justify-items:center; text-align:center}
.soundcard .sw{position:relative; width:32px; height:32px; border-radius:999px; background:var(--soft); display:grid; place-items:center}
.soundcard .sw svg{width:17px; height:17px; fill:none; stroke:var(--fg-2); stroke-width:1.5; stroke-linecap:round; stroke-linejoin:round}
.soundcard .tt{font-size:12.5px; font-weight:600; line-height:1.2}
.soundcard.on{border-color:var(--accent); background:var(--accent-soft)}
.soundcard.on .sw{background:var(--accent)}
.soundcard.on .sw svg{stroke:var(--bg)}
.soundcard.on .tt{color:var(--accent)}
/* Кольцо вокруг значка, пока среда звучит: видно, что именно играет. */
.soundcard .pulse{position:absolute; inset:-4px; border-radius:999px; border:2px solid var(--accent); animation:pulse 1.9s ease-out infinite}
@keyframes pulse{0%{transform:scale(.86); opacity:.9}100%{transform:scale(1.18); opacity:0}}
@media (prefers-reduced-motion:reduce){ .soundcard .pulse{animation:none; opacity:.7} }

.clock{font-family:var(--mono); font-size:clamp(46px,15vw,68px); font-weight:600; letter-spacing:-.045em; text-align:center; line-height:1}
.phase{text-align:center; color:var(--fg-2); font-size:13.5px; margin-top:6px}
.modes{display:grid; grid-template-columns:repeat(3,1fr); gap:8px; margin:16px 0}
.mode{background:var(--soft); border-radius:var(--r-md); padding:11px; text-align:center; display:grid; gap:2px}
.mode b{font-size:14px}
.mode span{font-family:var(--mono); font-size:11.5px; color:var(--fg-3)}
.mode[aria-pressed="true"]{background:var(--fg); color:var(--bg)}
.mode[aria-pressed="true"] span{color:var(--bg); opacity:.65}
.pomo-actions{display:flex; gap:9px; justify-content:center}
.setrow{display:flex; align-items:center; gap:12px; padding:15px 17px; border-radius:var(--r-md); background:var(--card); border:1px solid var(--stroke); box-shadow:var(--shadow); font-size:15.5px; width:100%; margin-bottom:var(--gap-row); text-decoration:none; color:inherit}
.setrow .arrow{margin-left:auto; color:var(--fg-3); display:grid; place-items:center}
.setrow .arrow .nav-ic{width:17px; height:17px}
.setrow .val{margin-left:auto; color:var(--fg-3); font-size:13.5px}
/* Пункт меню настроек: название и под ним то, что сейчас выбрано, — иначе
   в раздел приходится заходить, чтобы вспомнить. */
.setrow.tall{align-items:flex-start; padding:14px 17px}
.setrow .st{display:grid; gap:2px; min-width:0}
.setrow .st b{font-size:15.5px; font-weight:600}
.setrow .st i{font-style:normal; font-size:12.5px; color:var(--fg-3); overflow-wrap:anywhere}

/* ============ ПРОФИЛЬ ============ */
.avatar{width:34px; height:34px; border-radius:999px; background:var(--soft); background-size:cover; background-position:center; display:grid; place-items:center; font-family:var(--display); font-weight:700; font-size:14px; color:var(--fg-2); flex:none}
.avatar.lg{width:82px; height:82px; font-size:31px}
.iconbtn.av{padding:0; overflow:hidden}
.iconbtn.av .avatar{width:100%; height:100%; background-color:transparent}
.iconbtn.on .avatar{color:var(--bg)}
.avatar-row{display:flex; gap:16px; align-items:center}
.avatar-acts{display:flex; gap:8px; flex-wrap:wrap; min-width:0}
.preview .chip{font-size:calc(12px * var(--scale, 1))}

/* ============ ВХОД ============ */
/* Экран входа выстроен по одной оси: знак, заголовок, подпись, карточка,
   пояснение — всё по центру колонки и с одинаковыми интервалами. Раньше карточка
   центрировалась, а кнопки под ней разъезжались влево, и ось ломалась там, где
   её как раз ждут. */
.auth{max-width:420px; margin:0 auto; padding:16px 0 60px; display:flex; flex-direction:column; align-items:center; text-align:center}
.auth > *{width:100%}
.auth .mark{width:72px; height:72px; border-radius:20px; display:block; margin:0 auto 22px; object-fit:contain}
.auth h1{font-size:27px; text-align:center; margin-bottom:8px}
.auth .s{font-size:14.5px; color:var(--fg-2); text-align:center; margin-bottom:24px}
.auth .card{text-align:left}
.auth .stub{font-size:12.5px; color:var(--fg-3); text-align:center; margin-top:18px; line-height:1.5}
.auth .acts{justify-content:center; margin-top:14px}
.err{color:var(--crit); font-size:13px; margin-top:10px}

/* ============ НИЖНЯЯ НАВИГАЦИЯ ============ */
/* Низ отсчитывается от видимой части окна, а не от окна целиком: при открытой
   клавиатуре это разные вещи, и без --vv-shift панель уезжает вверх и там
   остаётся. Переменную ставит скрипт по visualViewport, по умолчанию она 0. */
.tabbar{position:fixed; left:50%; transform:translateX(-50%); bottom:calc(var(--dock) + var(--vv-shift, 0px)); z-index:50; background:var(--card); border:1px solid var(--stroke); border-radius:24px; padding:8px; box-shadow:var(--shadow-lift); width:min(560px, calc(100% - 24px))}
.tabs-main{display:grid; grid-template-columns:repeat(5,1fr); align-items:center}
.tab{display:grid; justify-items:center; gap:4px; font-size:10.5px; color:var(--fg-3); padding:6px 2px; border-radius:16px; text-align:center; line-height:1.2}
/* Пункт «Поддержка» — настоящая ссылка, а не кнопка: подчёркивание и
   наследуемый цвет ссылки в меню лишние. */
a.tab{text-decoration:none; color:var(--fg-3)}
/* Значок — рисунок, а не буква. Размер задаётся здесь, а не кеглем шрифта:
   раньше меню собирали символы Unicode, и в каждом браузере они выходили своей
   толщины и своего размера — на телефоне выглядели мелкими и бледными. */
.tab .ic{display:grid; place-items:center; width:26px; height:26px}
.nav-ic{width:24px; height:24px; display:block; fill:none; stroke:currentColor;
  stroke-width:1.8; stroke-linecap:round; stroke-linejoin:round}
/* У выбранного раздела штрих чуть плотнее: подсветки фоном на нижней панели
   нет, и вес — единственное, чем он отличается. */
.tab[aria-current="page"] .nav-ic{stroke-width:2.1}
.tab[aria-current="page"]{color:var(--fg); font-weight:600}
.tab.more.on{color:var(--fg)}

/* Разделы за «Ещё»: на телефоне выпадают над панелью, на широком экране это
   просто продолжение колонки. */
.tabs-rest{display:none}
.tabs-rest.open{display:grid; gap:2px; padding:8px 2px 4px; margin-top:6px; border-top:1px solid var(--line)}
/* Черта между смысловыми группами меню. На телефоне граница у .tabs-rest
   отделяет выпавший список от панели — это про устройство; а вот эта
   делит разделы по смыслу и рисуется там, где сказано в TABS. */
.tabs-sep{height:1px; background:var(--line); margin:7px 8px}
.tab.wide{grid-template-columns:22px 1fr; justify-items:start; align-items:center; gap:11px; font-size:14px; padding:10px 12px; text-align:left}
.tab.wide .ic{justify-self:center; width:24px; height:24px}
.tab.wide .nav-ic{width:21px; height:21px}
.tab.wide[aria-current="page"]{background:var(--soft)}

/* ============ ШИРОКИЙ ЭКРАН ============ */
/* Таб-бар переезжает влево и становится колонкой, страница сдвигается вправо
   на его ширину. Ни одного нового элемента в разметке: то же самое дерево,
   другая раскладка. */
@media (min-width:1040px){
  :root{
    --rail:232px;

    /* Три просвета — до колонки меню, между меню и текстом, справа от текста —
       считаются одной формулой, поэтому они одинаковые на любом окне. Раньше
       левый был жёстко 36px, а два других делили остаток: на ноутбуке 1728px
       получалось 36 / 250 / 250, и экран выглядел сдвинутым влево.

       Плюс 2×--pad в числителе — потому что у main своё внутреннее поле, и
       равнять надо видимые края текста, а не невидимые края блока. */
    --col: clamp(700px, calc(100vw - var(--rail) - 3 * 28px), 1180px);
    --gutter: max(28px, calc((100vw - var(--rail) - var(--col) + 2 * var(--pad)) / 3));
  }

  body{
    padding-left:calc(var(--rail) + var(--gutter) * 2 - var(--pad));
    padding-right:calc(var(--gutter) - var(--pad));
  }

  /* Верх колонки стоит на одной линии с первой строкой содержимого — с тем
     самым «СЕГОДНЯ». Раньше она центрировалась по окну и поднималась при
     прокрутке; выяснилось, что нужно не движение, а совпадение: две вертикали
     рядом обязаны начинаться с одной высоты, иначе экран выглядит собранным
     наспех. Раз она и так на месте, поднимать её больше не нужно — и всё
     слежение за прокруткой ушло вместе с этим.

     Высоту шапки считает скрипт (railTop): она зависит от шрифта и его
     размера, а их меняют в настройках.

     max-height — на случай низкого окна: колонка из двенадцати пунктов в него
     не влезает, и лучше прокрутка внутри неё, чем пункты, ушедшие под край. */
  .tabbar{
    left:var(--gutter);
    top:var(--rail-y, 96px);
    /* Низ на том же расстоянии от края, что и верх. Панель раньше кончалась
       там, где кончались пункты: сверху 96px, снизу 294px — та же кривизна,
       что и по бокам. Тянется фон, а не пункты: ни одна кнопка не сдвинулась
       с места, к которому привыкла рука. */
    bottom:var(--rail-y, 96px);
    transform:none;
    width:var(--rail);
    max-height:none;
    overflow-y:auto;
    border-radius:22px; padding:10px;
  }
  /* «Ещё» на широком экране не нужна: все десять пунктов помещаются. */
  .tabs-main{grid-template-columns:1fr; gap:2px}
  .tabs-main .tab.more{display:none}
  .tabs-rest{display:grid !important; gap:2px; padding:0; margin-top:2px; border-top:0}
  .tab{
    grid-template-columns:24px 1fr; justify-items:start; align-items:center;
    gap:12px; font-size:14.5px; padding:10px 13px; text-align:left;
  }
  .tab .ic{justify-self:center; width:24px; height:24px}
  .tab .nav-ic{width:21px; height:21px}
  .tab[aria-current="page"]{background:var(--soft)}

  /* Строка создания задачи прижимается к колонке текста, а не к центру окна. */
  .composer,
  .kbd .composer{
    left:calc(var(--rail) + var(--gutter) * 2 - var(--pad));
    right:calc(var(--gutter) - var(--pad));
    transform:none;
    width:min(620px, calc(100% - 40px)); margin:0 auto;
    bottom:calc(26px + var(--vv-shift, 0px));
  }
  /* Здесь панель — боковая колонка навигации слева, а не нижний таб. Она
     ничему не мешает и клавиатуры на таком экране обычно нет вовсе: прятать
     нечего и незачем. */
  .kbd .tabbar{display:block !important; bottom:auto}
  main{padding-bottom:170px}
  .toast{left:calc(50% + (var(--rail) + var(--gutter)) / 2)}
}

/* Экраны, где есть что положить рядом: карточки в две колонки вместо одной
   длинной ленты. Задачи и цели остаются в одну — там порядок несёт смысл. */
@media (min-width:1240px){
  /* Ширину колонки задаёт формула просветов выше — она растёт вместе с окном
     до 1180px, а не прыгает на фиксированную тысячу. */
  .twocol{display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:var(--gap); align-items:start}
}

/* ============ МОДАЛКА ============ */
/* Затемнение под окном закрывает экран целиком.

   inset:0 у зафиксированного слоя меряется по «малому» вьюпорту — тому, что
   с показанной адресной строкой. Стоит ей спрятаться при прокрутке, видимая
   часть становится выше, а слой остаётся прежним: снизу вылезает полоса
   несмазанного содержимого — ровно то, что видно на телефоне под окном.
   100dvh следит за настоящей высотой; inset:0 остаётся запасным для старых
   браузеров, где dvh нет. */
/* Высоту задаёт inset, а не 100dvh.

   Стояло и то и другое сразу, и на андроиде они расходились: при открытой
   клавиатуре вьюпорт сжимается, inset послушно сжимается с ним, а dvh
   продолжает считать по старой высоте. Затемнение оказывалось выше видимой
   области, и снизу оставалась полоса, которую ничем не закрыли. */
.modal{position:fixed; inset:0; background:rgba(10,11,13,.5); display:none; align-items:center; justify-content:center; z-index:70; padding:16px; backdrop-filter:blur(4px); -webkit-backdrop-filter:blur(4px)}
.modal.on{display:flex}
/* Высота окна тоже по живому вьюпорту, иначе на телефоне оно вырастает выше
   экрана и последняя кнопка оказывается под сгибом. */
.modal-in{background:var(--card); border-radius:var(--r-xl); width:100%; max-width:470px; max-height:min(86vh, calc(100dvh - 32px)); overflow-y:auto; overscroll-behavior:contain; padding:24px; animation:pop .18s ease}
@keyframes pop{from{opacity:0; transform:translateY(12px) scale(.98)}to{opacity:1; transform:none}}
@media (prefers-reduced-motion:reduce){ .modal-in{animation:none} }
/* Подвал прилипает ко дну окна, поля прокручиваются под ним.

   sticky, а не fixed: окно само по себе прокручиваемое, и прилипать кнопки
   должны к его дну, а не к дну экрана — иначе на большом окне они уедут в
   середину. Фон обязателен: без него поля просвечивают сквозь кнопки. */
.modal-in{display:flex; flex-direction:column}
.modal-foot{position:sticky; bottom:-24px; z-index:2; background:var(--card);
  padding:10px 0 0; margin-top:auto;
  /* Мягкая граница вместо линии: снизу под кнопками должно быть видно, что
     список продолжается, но линия поперёк окна выглядела бы швом. */
  box-shadow:0 -14px 16px -12px rgba(0,0,0,.16)}
.modal-foot .acts{margin-top:10px}

/* Цена в окне лимита: две строки, цифра крупно.

   Без неё окно предлагало «подключить» неизвестно за сколько, и первый вопрос
   человека — «а сколько это стоит» — оставался без ответа ровно в тот момент,
   когда он готов был решить. */
/* Закрытое подпиской — приглушено и с замком.

   Не спрятано и не выключено: человек должен видеть, что выбор есть и он
   больше двух тем. Спрятанное не продаёт, а выключенное выглядит поломкой. */
.radio.locked, .soundcard.locked, .mode.locked{position:relative; opacity:.55}
.radio.locked::after, .soundcard.locked::after, .mode.locked::after{
  content:'🔒'; position:absolute; top:2px; right:5px; font-size:9px; opacity:.75; line-height:1}
.radio.pal.locked::after, .radio.boxpick.locked::after, .radio.markpick.locked::after{
  top:1px; right:3px}

.paywall-price{display:grid; grid-template-columns:auto 1fr; gap:4px 10px;
  align-items:baseline; margin:14px 0 4px; padding:12px 14px;
  background:var(--soft); border-radius:var(--r-md)}
.paywall-price b{font-family:var(--mono); font-size:17px; letter-spacing:-.02em; white-space:nowrap}
.paywall-price span{font-size:13px; color:var(--fg-2)}

.modal-in h3{font-size:21px; margin-bottom:6px}
.modal-in .s{font-size:13.5px; color:var(--fg-2); margin-bottom:18px}
/* Всплывающее сообщение — выше строки ввода, а не поверх неё.

   Стояло на 96 пикселях от низа и ложилось прямо на поле: записал задачу, и
   следующую уже не набрать — сообщение закрывает и подсказку, и курсор. В
   приложении внизу и панель разделов, и композер, поэтому поднимаем заметно
   выше. */
.toast{position:fixed; left:50%; transform:translateX(-50%); bottom:96px; background:var(--fg); color:var(--bg); border-radius:999px; padding:11px 20px; font-size:14px; z-index:90; box-shadow:var(--shadow-lift); max-width:calc(100% - 32px)}

/* ============ ТАРИФЫ И ЗАМКИ ============ */

/* Таблица тарифа — три колонки: что, бесплатно, в подписке. На телефоне это
   всё равно таблица, а не карточки: сравнивают именно строки, и разбивать их
   по колонкам значит заставить человека держать сравнение в голове. */
.plan-table{display:grid; gap:2px}
.plan-row{display:grid; grid-template-columns:minmax(0,1.5fr) minmax(0,.9fr) minmax(0,.9fr); gap:10px;
  align-items:baseline; padding:9px 0; border-bottom:1px solid var(--line)}
.plan-row:last-child{border-bottom:0}
.plan-what{font-size:14px}
.plan-free,.plan-pro{font-size:12.5px; color:var(--fg-2); text-align:right}
.plan-free.off{color:var(--fg-3)}
.plan-pro{color:var(--accent); font-weight:600}

/* На телефоне три колонки в строку не помещаются: «без ограничений» обрезалось
   на середине слова. Название занимает свою строку целиком, а под ним два
   значения с подписями — сравнение остаётся построчным, но ничего не жмётся. */
@media (max-width:520px){
  .plan-row{grid-template-columns:1fr 1fr; gap:3px 12px; padding:11px 0}
  .plan-what{grid-column:1 / -1}
  .plan-free,.plan-pro{text-align:left; font-size:12px}
  .plan-free::before{content:'бесплатно: '; color:var(--fg-3)}
  .plan-pro::before{content:'Pro: '; color:var(--fg-3); font-weight:400}
}

.plan-price{display:flex; align-items:baseline; gap:8px; margin-bottom:6px}
.plan-price b{font-family:var(--display); font-size:30px; letter-spacing:-.04em}
.plan-price span{font-size:13px; color:var(--fg-3)}

.card.pro-on{border-color:var(--accent)}

/* Замок. Рисунок, а не эмодзи: замок из шрифта в разных системах то жирный,
   то цветной, и карточка каждый раз выглядит по-разному. */
.locked-card{text-align:center}
.locked-mark{display:inline-grid; place-items:center; width:52px; height:52px; border-radius:999px;
  background:var(--accent-soft); color:var(--accent); margin-bottom:12px}
.locked-mark svg{width:26px; height:26px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.locked-card .acts{justify-content:center}

/* Остаток запросов под кнопкой Syn: строка, а не значок, — число должно
   читаться до нажатия, а не объясняться после отказа. */
.syn-quota{margin-top:10px; text-align:center}
.q-link{color:var(--accent); text-decoration:none; border-bottom:1px solid transparent}
.q-link:hover{border-bottom-color:currentColor}

/* Крайний срок на карточке. Отличается от «просрочено» тем, что это ещё не
   беда, а условие: обводка тише, чем у красного. */
.chip.hard{border:1px solid var(--stroke); color:var(--fg-2)}

/* ============ РАЗГОВОР С SYN ============ */

/* Окно разговора устроено как мессенджер, потому что это и есть разговор:
   лента сверху, строка снизу, микрофон рядом со стрелкой. Высота ленты
   фиксирована и прокручивается сама — иначе длинный разговор растягивал бы
   окно на весь экран и кнопка отправки уезжала бы за край. */
.syn-win{display:flex; flex-direction:column; min-height:0}
.syn-top{display:flex; align-items:center; justify-content:space-between; gap:12px; margin-bottom:12px}
.syn-top h3{margin:0}

.syn-log{flex:1; min-height:120px; max-height:46vh; overflow-y:auto; overscroll-behavior:contain;
  display:flex; flex-direction:column; gap:8px; padding:2px 2px 4px; margin-bottom:12px}
.syn-empty{font-size:13.5px; color:var(--fg-2); line-height:1.5; padding:6px 2px}

.syn-msg{max-width:88%; font-size:14px; line-height:1.45; padding:9px 12px; border-radius:14px;
  background:var(--soft); color:var(--fg); align-self:flex-start}
.syn-msg.mine{align-self:flex-end; background:var(--accent-soft); color:var(--fg)}
.syn-msg.wait{color:var(--fg-3)}

/* Что изменилось — списком под ответом, а не отдельной карточкой: это часть
   реплики, а не второй экран. Не применилось — тем же списком, но тише. */
.syn-did{list-style:none; margin:0 0 2px; padding:0 2px; display:flex; flex-direction:column; gap:3px; align-self:flex-start; max-width:92%}
.syn-did li{font-size:12.5px; color:var(--fg-2); padding-left:14px; position:relative}
.syn-did li::before{content:''; position:absolute; left:3px; top:8px; width:5px; height:5px; border-radius:999px; background:var(--ok)}
.syn-did.off li{color:var(--fg-3)}
.syn-did.off li::before{background:var(--fg-3)}

.syn-bar{display:flex; align-items:flex-end; gap:8px}
.syn-bar textarea{flex:1; resize:none; min-height:44px; max-height:120px; padding:11px 12px}
.syn-mic,.syn-go{flex:none; width:44px; height:44px; border-radius:999px; display:grid; place-items:center}
.syn-mic{background:var(--soft); color:var(--fg-2)}
.syn-mic svg{width:20px; height:20px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.syn-mic:hover{color:var(--fg)}
/* Слушает — это состояние, которое должно быть видно через всю комнату:
   человек говорит, а не смотрит в экран. */
.syn-mic.on{background:var(--accent); color:#fff; animation:mic-pulse 1.4s ease-in-out infinite}
@keyframes mic-pulse{0%,100%{box-shadow:0 0 0 0 var(--accent-soft)} 50%{box-shadow:0 0 0 9px transparent}}
@media (prefers-reduced-motion:reduce){ .syn-mic.on{animation:none} }
.syn-go{background:var(--fg); color:var(--bg); font-size:18px}
.syn-go[disabled]{opacity:.5}
.syn-error{margin-bottom:10px}
.syn-voice-hint{margin-top:10px; text-align:center; color:var(--accent)}

/* ============ МОЯ ПОДПИСКА ============ */

.sub-state .sub-head{display:flex; gap:14px; align-items:flex-start}
.sub-state.on{border-color:var(--accent)}
.sub-mark{flex:none; display:grid; place-items:center; width:44px; height:44px; border-radius:999px;
  background:var(--soft); color:var(--fg-3)}
.sub-state.on .sub-mark{background:var(--accent-soft); color:var(--accent)}
.sub-mark svg{width:22px; height:22px; fill:none; stroke:currentColor; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
.sub-state.on .sub-mark svg{fill:currentColor; stroke:none}
.sub-code{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:14px; padding-top:14px; border-top:1px solid var(--line)}
.sub-code .lbl{margin:0}
.sub-code b{font-size:15px; letter-spacing:.06em}

/* Три тарифа рядом — так же, как на странице оплаты, чтобы человек, который
   уже видел их там, не сравнивал заново. */
.plancards{display:grid; gap:10px; margin-bottom:12px}
@media (min-width:560px){ .plancards{grid-template-columns:repeat(3,1fr)} }
.plancard{position:relative; display:flex; flex-direction:column; gap:3px; text-decoration:none; color:inherit;
  background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg); padding:16px; box-shadow:var(--shadow)}
.plancard.main{border-color:var(--accent)}
.plancard:hover{border-color:var(--accent)}
.planname{font-size:13px; color:var(--fg-3)}
.planprice{font-family:var(--display); font-size:24px; letter-spacing:-.04em}
.plannote{font-size:12.5px; color:var(--fg-2); margin-top:2px}
.planbuy{margin-top:10px; font-size:13px; color:var(--accent); font-weight:600}
.plantag{position:absolute; top:12px; right:12px; font-size:11px; padding:3px 8px; border-radius:999px;
  background:var(--accent-soft); color:var(--accent)}

/* Главное дело дня из брифинга: одна строка, которую Syn просит не потерять. */
.focus-main{margin-top:14px; padding:11px 13px; border-radius:var(--r-md); background:var(--accent-soft);
  color:var(--fg); font-size:13.5px; line-height:1.45}
.focus-main span{display:block; font-size:11px; letter-spacing:.08em; text-transform:uppercase; color:var(--accent); margin-bottom:3px}

/* Выход из веб-версии — последним пунктом меню и отделён чертой: это не
   раздел, а уход на сайт, и стоять он должен не в одном ряду с разделами. */
.tab.leave{margin-top:6px; padding-top:12px; border-top:1px solid var(--line); border-radius:0 0 14px 14px; color:var(--fg-3)}
.tab.leave:hover{color:var(--fg)}

/* «О сервисе»: знак рядом с первым абзацем, а не над ним — карточка читается
   как визитка, а не как ещё один заголовок. */
.about-lead{display:flex; gap:16px; align-items:flex-start}
.about-mark{width:56px; height:56px; border-radius:16px; flex:none; object-fit:contain}
/* Пояснение справа в строке: серое, мельче, и переносится, а не выдавливает
   название за край — на телефоне это было главной причиной кривых строк. */
.line-note{color:var(--fg-3); font-size:12.5px; text-align:right; margin-left:auto; max-width:58%}

/* Ответ ассистента, не сделавший ничего. Не красный и не тревожный — это не
   ошибка, а несовпадение слов и дела, и рядом сразу лежит выход. */
.syn-none{align-self:flex-start; max-width:92%; font-size:12.5px; color:var(--fg-2); line-height:1.45;
  background:var(--soft); border:1px dashed var(--stroke); border-radius:12px; padding:10px 12px}
.syn-none b{color:var(--fg)}
.syn-none-acts{display:flex; gap:8px; flex-wrap:wrap; margin-top:9px}
.syn-none-acts .btn{padding:7px 12px; font-size:12.5px}

/* ============ ПЕРВЫЕ ШАГИ ============ */

/* Обучение выглядит как карточка задач, а не как баннер поверх них: это часть
   работы, а не реклама самой себя. Раскрыт всегда один шаг — текущий. */
.card.tour{border-color:var(--accent)}
.tour-head{display:flex; align-items:flex-start; justify-content:space-between; gap:12px}
.tour-head h3{margin:0}
/* Заголовок подсказки и крестик — в одну строку, крестик у правого края. */
.finhint-head{display:flex; align-items:flex-start; justify-content:space-between; gap:10px}
.finhint-head h3{min-width:0}
.tour-hide{flex:none; width:28px; height:28px; border-radius:999px; color:var(--fg-3); display:grid; place-items:center; font-size:13px}
.tour-hide:hover{background:var(--soft); color:var(--fg)}

.tour-bar{height:4px; border-radius:999px; background:var(--soft); overflow:hidden; margin:14px 0 4px}
.tour-bar i{display:block; height:100%; border-radius:999px; background:var(--accent); transition:width .3s ease}

.tour-steps{display:flex; flex-direction:column}
.tour-step{display:flex; gap:12px; align-items:flex-start; padding:11px 0; border-bottom:1px solid var(--line)}
.tour-step:last-child{border-bottom:0; padding-bottom:0}
.tour-mark{flex:none; width:22px; height:22px; border-radius:999px; border:2px solid var(--soft-2); color:#fff;
  display:grid; place-items:center; font-size:11px; margin-top:1px}
.tour-step.on .tour-mark{background:var(--ok); border-color:var(--ok)}
.tour-step.on .tour-body b{color:var(--fg-3); text-decoration:line-through}
.tour-step.now .tour-mark{border-color:var(--accent)}
.tour-body{min-width:0}
.tour-body b{font-size:14.5px; display:block}
.tour-body p{font-size:13px; color:var(--fg-2); line-height:1.45; margin-top:4px}
.tour-body .btn{margin-top:10px}

/* ============ НАСТРОЙКИ ВИДА ============ */

/* Каждая настройка — карточка с названием и одной строкой объяснения. Плоский
   список «подпись — ряд кнопок — подпись — ряд» сливался в полотно: не было
   видно, где кончается одна настройка и начинается следующая. */
.setblock{padding:18px}
.setblock + .setblock{margin-top:12px}
.setblock-h{margin-bottom:14px}
.setblock-h h3{font-size:16.5px}
.setblock-h .sub{margin-top:4px}

/* Подряд идущие ряды внутри одной карточки — «Начертание» и «Размер». Разделены
   чертой, а не только отступом: иначе два ряда кнопок читаются как один
   длинный, перенесённый на вторую строку. */
.subrow + .subrow{margin-top:14px; padding-top:14px; border-top:1px solid var(--line)}
.subrow-l{display:block; font-size:12.5px; color:var(--fg-3); margin-bottom:9px}

/* Превью — отдельный сюжет. Показывает задачу целиком: отметка, название,
   подпись, чипы. Раньше показывало только текст, и выбранная форма отметки
   проверялась взглядом на кнопку, а не на результат. */
.card.preview{margin-top:0}
.preview-task{display:flex; gap:11px; align-items:flex-start}
.preview-task h3{font-size:16px}

/* Мета в строке раскрытия — там же, где «подпункты», сразу за ней.

   Чипами дата и время занимали отдельный ряд под названием, и карточка
   вырастала вдвое: пять задач на экране телефона вместо десяти. Справа от
   названия они отжимали название до двух слов. В нижней строке место уже есть,
   и она всё равно оставалась полупустой. */
/* Ряд чипов в карточке задачи.

   Чуть мельче, чем чипы в превью и в других разделах: тут их бывает пять
   подряд — дата, время, повтор, срок, цель, — и в полный размер они начинают
   спорить с названием за внимание. */
.item .chips{margin-top:7px; gap:6px}
.item .chips .chip{font-size:11.5px; padding:3px 9px; gap:5px}
.item .chips .chip.rep svg{width:11px; height:11px}
/* Срок и просрочка — единственное, что кричит. Остальное ровным серым. */
.item .chips .chip.hard{background:transparent; color:var(--fg-2); box-shadow:inset 0 0 0 1px var(--stroke)}
.item .chips .chip.late{background:transparent; color:var(--danger); box-shadow:inset 0 0 0 1px var(--danger)}
.item .chips .chip.carried{background:transparent; color:var(--fg-3); box-shadow:inset 0 0 0 1px var(--stroke)}
/* Чип подпунктов несёт стрелку раскрытия — она и говорит, что карточка
   открывается. У карточек без подпунктов и без описания её нет, и открывать
   там нечего. */
.item .chips .chip.sub .car{display:inline-block; font-size:13px; line-height:1;
  transition:transform .18s ease}
.item.open .chips .chip.sub .car{transform:rotate(180deg)}
/* Выполненная задача глушит и чипы: иначе цветная цель на зачёркнутой строке
   выглядит живее самой задачи. */
.item.done .chips{opacity:.55}
.item .expand .m .mt{font-variant-numeric:tabular-nums}
.item .expand .m .mr{display:inline-grid; place-items:center; color:var(--fg-3)}
.item .expand .m .mr .nav-ic{width:12px; height:12px; stroke-width:2}
.item .expand .m .pct{font-weight:600; color:var(--fg-2)}
/* Строка может не влезть на узком экране — тогда переносится целиком, а не
   разрывает дату посередине. */
.item .expand{display:flex; flex-wrap:wrap; align-items:baseline; row-gap:2px}

/* ============ ПЕРВЫЕ ШАГИ ============ */

/* Обучение выглядит как карточка задач, а не как баннер поверх них: это часть
   работы, а не реклама самой себя. Раскрыт всегда один шаг — текущий. */
.card.tour{border-color:var(--accent)}
.tour-head{display:flex; align-items:flex-start; justify-content:space-between; gap:12px}
.tour-head h3{margin:0}
.tour-hide{flex:none; width:28px; height:28px; border-radius:999px; color:var(--fg-3); display:grid; place-items:center; font-size:13px}
.tour-hide:hover{background:var(--soft); color:var(--fg)}

.tour-bar{height:4px; border-radius:999px; background:var(--soft); overflow:hidden; margin:14px 0 4px}
.tour-bar i{display:block; height:100%; border-radius:999px; background:var(--accent); transition:width .3s ease}

.tour-steps{display:flex; flex-direction:column}
.tour-step{display:flex; gap:12px; align-items:flex-start; padding:11px 0; border-bottom:1px solid var(--line)}
.tour-step:last-child{border-bottom:0; padding-bottom:0}
.tour-mark{flex:none; width:22px; height:22px; border-radius:999px; border:2px solid var(--soft-2); color:#fff;
  display:grid; place-items:center; font-size:11px; margin-top:1px}
.tour-step.on .tour-mark{background:var(--ok); border-color:var(--ok)}
.tour-step.on .tour-body b{color:var(--fg-3); text-decoration:line-through}
.tour-step.now .tour-mark{border-color:var(--accent)}
.tour-body{min-width:0}
.tour-body b{font-size:14.5px; display:block}
.tour-body p{font-size:13px; color:var(--fg-2); line-height:1.45; margin-top:4px}
.tour-body .btn{margin-top:10px}

/* ============ НАСТРОЙКИ ВИДА ============ */

/* Каждая настройка — карточка с названием и одной строкой объяснения. Плоский
   список «подпись — ряд кнопок — подпись — ряд» сливался в полотно: не было
   видно, где кончается одна настройка и начинается следующая. */
.setblock{padding:18px}
.setblock + .setblock{margin-top:12px}
.setblock-h{margin-bottom:14px}
.setblock-h h3{font-size:16.5px}
.setblock-h .sub{margin-top:4px}

/* Подряд идущие ряды внутри одной карточки — «Начертание» и «Размер». Разделены
   чертой, а не только отступом: иначе два ряда кнопок читаются как один
   длинный, перенесённый на вторую строку. */
.subrow + .subrow{margin-top:14px; padding-top:14px; border-top:1px solid var(--line)}
.subrow-l{display:block; font-size:12.5px; color:var(--fg-3); margin-bottom:9px}

/* Превью — отдельный сюжет. Показывает задачу целиком: отметка, название,
   подпись, чипы. Раньше показывало только текст, и выбранная форма отметки
   проверялась взглядом на кнопку, а не на результат. */
.card.preview{margin-top:0}
.preview-task{display:flex; gap:11px; align-items:flex-start}
.preview-task h3{font-size:16px}

/* Строка названия задачи и мета справа от него.

   Чипами дата и время занимали отдельный ряд под названием, и карточка
   вырастала вдвое: пять задач на экране телефона вместо десяти. Теперь это
   мелкая тихая строка справа — там, где есть пустое место, — и она не
   переносится: длинное название сжимается первым. */
.titleline{display:flex; align-items:baseline; gap:10px}
.titleline .t{flex:1; min-width:0}
.titleline .m{flex:none; margin-top:0; justify-content:flex-end; font-size:11.5px; gap:7px; white-space:nowrap}
.titleline .m .late{color:var(--danger); font-weight:600}
.titleline .m .hard{color:var(--fg-2)}
.titleline .m .mt{font-variant-numeric:tabular-nums}
.titleline .m .mr{display:inline-grid; place-items:center; color:var(--fg-3)}
.titleline .m .mr .nav-ic{width:13px; height:13px; stroke-width:2}
.titleline .m .pct{font-weight:600; color:var(--fg-2)}

/* На узком экране мета остаётся справа, пока название помещается в строку, и
   уходит под него, когда не помещается. Жёстко прибить её вправо нельзя:
   длинное название сжалось бы до двух слов, а оно здесь главное. */
@media (max-width:430px){
  .titleline{flex-wrap:wrap; gap:1px 10px}
  .titleline .t{flex:1 1 auto; min-width:55%}
  .titleline .m{justify-content:flex-start}
}

/* ============ КОРЗИНА ============ */

/* Полоса над списком вместо карточки: срок хранения — одна строка, а под неё
   уходил целый первый экран. Кнопки — справа, где их и ищут. */
.trashbar{display:flex; align-items:center; justify-content:space-between; gap:12px;
  flex-wrap:wrap; margin:0 0 12px}
.trashbar .sub{font-size:12.5px; margin:0}
.trashbar-a{display:flex; gap:7px; flex:none}

/* Записи — строками одного списка, а не стопкой карточек: в корзину приходят
   окинуть взглядом, а карточка на запись тратит три ряда вместо одного. */
.trashlist{display:flex; flex-direction:column;
  background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg);
  box-shadow:var(--shadow); overflow:hidden}
.trashrow{display:flex; align-items:center; gap:12px; padding:9px 14px; margin:0;
  border-top:1px solid var(--line)}
.trashlist .trashrow:first-child{border-top:0}
.trashrow-t{min-width:0; flex:1; display:flex; align-items:baseline; gap:9px}
.trashrow-t b{font-size:13.5px; font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.trashrow-t .sub{font-size:11.5px; margin:0; flex:none; white-space:nowrap}
.trashrow-a{display:flex; gap:1px; flex:none}
.trashrow-a button{width:28px; height:28px; border-radius:999px; display:grid; place-items:center;
  color:var(--fg-3)}
.trashrow-a button:hover{background:var(--soft); color:var(--fg)}
.trashrow-a button svg{width:15px; height:15px; display:block; fill:none; stroke:currentColor;
  stroke-width:1.6; stroke-linecap:round; stroke-linejoin:round}
/* На узком экране строка не ломается в столбец: теперь она и так в один ряд,
   а кнопки стали значками. Ужимается только название. */
@media (max-width:520px){
  .trashrow-t{flex-direction:column; align-items:flex-start; gap:1px}
  .trashbar{gap:8px}
  .trashbar .sub{flex:1 1 100%}
}

/* Дата цели и этапа: сама дата плюс сколько до неё осталось. Близкая
   подсвечивается, прошедшая — красным, но без паники: цель, у которой срок
   прошёл, не ошибка, а решение, которое надо принять. */
.gtarget{font-size:12.5px; color:var(--fg-2); margin:0 0 10px}
.gtarget.soon{color:var(--accent-warm); font-weight:600}
.gtarget.late{color:var(--danger); font-weight:600}
.stage-target{color:var(--fg-2)}
.stage-target.soon{color:var(--accent-warm)}
.stage-target.late{color:var(--danger)}
.field .opt{color:var(--fg-3); font-weight:400; text-transform:none; letter-spacing:0}
.item .expand .m .carried{color:var(--fg-2); font-weight:600}

/* Своё правило повтора: три поля, нужные одному человеку из десяти. Скрыто,
   пока его не выбрали в списке — иначе модалка задачи вырастает вдвое у всех. */
.ruleblock{display:none}
.ruleblock.on{display:block; margin-top:4px; padding-top:14px; border-top:1px solid var(--line)}

/* ============ МОИ ФИНАНСЫ ============ */

/* Горизонтальная мерка раздела. Совпадает с padding карточки: плитки, строки
   операций, заголовки дней и подписки выстраиваются по одной вертикали, а не
   каждый по своей. */
.fintabs, .finadd, .finrows, .sublist, .finday, .fintiles{--fin-pad:18px}

/* Ряд кнопок по центру: один вход в раздел, и он не должен прижиматься к
   левому краю, будто продолжает список. */
.acts.center{justify-content:center}

/* Вкладки внутри раздела — та же форма, что у активной вкладки в панели:
   текущая залита, остальные молчат. Полоска прокручивается вбок на телефоне,
   а не переносится в два ряда: пять слов в два этажа читаются как список. */
.fintabs{display:flex; gap:4px; padding:4px; margin:0 0 16px;
  background:var(--soft); border:1px solid var(--line); border-radius:14px;
  overflow-x:auto; -webkit-overflow-scrolling:touch}
.fintab{flex:none; border:0; background:none; border-radius:10px; padding:8px 14px;
  font-size:13.5px; color:var(--fg-2); cursor:pointer; white-space:nowrap}
.fintab:hover{color:var(--fg)}
.fintab.on{background:var(--card); color:var(--fg); font-weight:600; box-shadow:var(--shadow)}

/* Плитки сводки: подпись сверху мелко, число крупно. Колонка чисел читается
   сверху вниз, а не выискивается в предложении. */
.fintiles{display:grid; grid-template-columns:repeat(auto-fit,minmax(140px,1fr));
  gap:1px; background:var(--line); border:1px solid var(--line);
  border-radius:var(--r-lg); overflow:hidden; margin-bottom:var(--gap)}
/* Сводка — ровно четыре плитки: две колонки, чтобы не оставалось пустого
   слота в неполном третьем столбце (auto-fit его не растягивает). */
.fintiles.summary{grid-template-columns:repeat(2,1fr)}
/* Отступ тот же, что у карточки: раньше плитки были на 16, карточки на 18, и
   на стыке двух блоков подписи стояли ступенькой. Весь раздел живёт на одной
   мерке --fin-pad, и любая строка в нём начинается на одной вертикали. */
.fintile{background:var(--card); padding:14px var(--fin-pad)}
.fintile span{display:block; font-size:11px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--fg-3); font-weight:500}
.fintile b{display:block; margin-top:5px; font-size:20px; letter-spacing:-.02em;
  font-variant-numeric:tabular-nums}
.fintile.bad b{color:var(--crit)}
.fintile.warn b{color:var(--warn)}

.finhead{display:flex; align-items:baseline; justify-content:space-between; gap:12px;
  margin-bottom:12px}
.finhead h3{font-size:17px; margin:0}
.finhead .sub{margin:0; font-size:12.5px; flex:none}

/* Полосы по категориям: название, полоса, сумма — три колонки одной сетки,
   чтобы суммы стояли столбиком, а не в конце разной длины строк. */
.finbars{display:flex; flex-direction:column; gap:9px}
.finbar{display:grid; grid-template-columns:minmax(64px,1fr) 2.2fr auto; align-items:center; gap:10px}
.fb-t{font-size:13px; color:var(--fg-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.fb-r{height:7px; border-radius:999px; background:var(--soft-2); overflow:hidden}
.fb-r i{display:block; height:100%; border-radius:999px}
.fb-v{font-size:13px; font-variant-numeric:tabular-nums; text-align:right}

.finline{display:flex; align-items:baseline; justify-content:space-between; gap:12px;
  padding:7px 0; border-top:1px solid var(--line)}
.finline:first-of-type{border-top:0}
.finline span{font-size:13.5px; color:var(--fg-2)}
.finline b{font-size:13.5px; font-variant-numeric:tabular-nums; flex:none}

/* Ввод операции. Переключатель «трата/доход» стоит над строкой, а не рядом:
   он меняет смысл всего, что напишут, и должен читаться первым. */
.finadd{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg);
  box-shadow:var(--shadow); padding:14px var(--fin-pad); margin-bottom:var(--gap)}
.finswitch{display:inline-flex; gap:2px; padding:3px; margin-bottom:10px;
  background:var(--soft); border-radius:999px}
.finswitch button{border:0; background:none; border-radius:999px; padding:6px 14px;
  font-size:13px; color:var(--fg-2); cursor:pointer}
.finswitch button.on{background:var(--card); color:var(--fg); font-weight:600; box-shadow:var(--shadow)}

/* День — заголовок с итогом и список строк под ним. Ленту трат читают
   сверху вниз, поэтому день отбит, а строки внутри максимально тихие. */
.finday{margin-bottom:16px}
.finday-h{display:flex; align-items:baseline; justify-content:space-between; gap:10px;
  padding:0 var(--fin-pad) 7px}
.finday-h b{font-size:12.5px; font-weight:600; color:var(--fg-2)}
.finday-h span{font-size:12.5px; color:var(--fg-3); font-variant-numeric:tabular-nums}
.finrows{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg);
  box-shadow:var(--shadow); overflow:hidden}
.finrow{display:flex; align-items:center; gap:10px; padding:9px var(--fin-pad);
  border-top:1px solid var(--line)}
.finrows .finrow:first-child{border-top:0}
.fr-dot{width:8px; height:8px; border-radius:999px; flex:none}
.fr-t{flex:1; min-width:0; font-size:13.5px; display:flex; align-items:baseline; gap:8px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.fr-c{font-size:11.5px; color:var(--fg-3); flex:none}
.fr-v{font-size:13.5px; font-variant-numeric:tabular-nums; flex:none}
.fr-v.up{color:var(--ok)}
.fr-x{width:26px; height:26px; border-radius:999px; display:grid; place-items:center;
  color:var(--fg-3); flex:none; font-size:13px}
.fr-x:hover{background:var(--soft); color:var(--fg)}
.fr-x svg{width:14px; height:14px; display:block; fill:none; stroke:currentColor;
  stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round}
/* Крестик виден по наведению — как в задачах и списках. */
@media (hover:hover) and (pointer:fine){
  .finrow:hover .fr-x, .finrow:focus-within .fr-x{opacity:1}
}

/* Долг и копилка: крупная сумма — это ответ, всё остальное к ней пояснение. */
.debt-sum{display:flex; align-items:baseline; gap:10px; flex-wrap:wrap}
.debt-sum b{font-size:24px; letter-spacing:-.02em; font-variant-numeric:tabular-nums}
.debt-sum .sub{margin:0; font-size:12.5px}
.card.debt.done, .card.jar.full{opacity:.72}
.card.jar.full{border-color:var(--ok)}

/* Список конвертов. Раньше тут же лежали правила для .subrow — строки
   платежей, — и они доставались настройкам вида: там класс .subrow свой и
   означает совсем другое. Отсюда и брались полоски поперёк экрана настроек,
   которых никто не рисовал. Разметка платежей давно живёт на .payrow, а эти
   правила остались висеть. */
.sublist{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg);
  box-shadow:var(--shadow); overflow:hidden}

/* Переключатель стороны в окне долга: та же форма, что у «трата/доход», —
   в разделе не должно быть двух разных способов выбрать одно из двух. */
.sidepick{display:flex; gap:2px; padding:3px; margin:0 0 16px;
  background:var(--soft); border-radius:999px}
.sidepick button{flex:1; border:0; background:none; border-radius:999px; padding:9px 12px;
  font-size:13.5px; color:var(--fg-2); cursor:pointer}
.sidepick button.on{background:var(--card); color:var(--fg); font-weight:600; box-shadow:var(--shadow)}

/* Галочка с подписью в строку: квадратик и текст выровнены по первой строке
   текста, а не по центру блока — иначе при переносе на две строки квадратик
   уезжает в середину. */
.check{display:flex; align-items:flex-start; gap:10px; margin:0 0 16px; cursor:pointer}
.check input{width:18px; height:18px; margin:1px 0 0; flex:none; accent-color:var(--ok)}
.check span{font-size:13.5px; line-height:1.45; color:var(--fg-2)}

/* Шаблоны подписок — одна строка с прокруткой вбок, а не полотно на
   восемнадцать кнопок: в два ряда они поднимали окно выше экрана, и оно
   открывалось уже прокрученным — с обрезанным заголовком. */
.chips.tpl{flex-wrap:nowrap; overflow-x:auto; -webkit-overflow-scrolling:touch;
  margin:0 0 16px; padding:2px 0 8px; scrollbar-width:thin}
.chips.tpl .chip{flex:none}
.chip[data-act="fin-sub-tpl"]{border:1px solid var(--line); cursor:pointer; padding:6px 11px}
.chip[data-act="fin-sub-tpl"]:hover{background:var(--soft-2); color:var(--fg)}

/* Всё в окне — по одной оси. Кнопка действия во всю ширину, «Отмена» под ней
   по центру: прижатая влево, она выглядела остатком другой вёрстки. */
#modal .acts{justify-content:center; margin-top:12px}
/* «Отмена» той же ширины, что и действие над ней.

   Действие идёт кнопкой во всю ширину, а отмена оставалась по своему тексту —
   узкой таблеткой под широкой кнопкой. Пара разноразмерных кнопок читается
   как незаконченная вёрстка, а не как выбор из двух. */
#modal .acts:not(.pair){display:grid; grid-template-columns:1fr; gap:10px}
#modal .acts:not(.pair) .btn{width:100%}
#modal h3{text-align:center}
#modal .s{text-align:center}

/* ---- новое в финансах ---- */

/* Полоса выбора месяца. Стрелки по краям, название посередине — так же
   листают месяц в любом календаре, и объяснять это не нужно. */
.finmonth{display:flex; align-items:center; justify-content:center; gap:8px;
  margin:0 0 14px}
.finmonth b{font-size:14px; min-width:132px; text-align:center}
.finmonth button{width:30px; height:30px; border-radius:999px; display:grid; place-items:center;
  color:var(--fg-2); font-size:17px; line-height:1}
.finmonth button:hover:not(:disabled){background:var(--soft); color:var(--fg)}
.finmonth button:disabled{opacity:.3; cursor:default}
.finmonth .now{width:auto; padding:0 12px; font-size:12.5px; background:var(--soft)}

/* Дата и счёт под строкой ввода: подписи мелкие, поля узкие — это уточнение
   к строке, а не вторая форма. */
.finwhen{display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:10px}
.finwhen label{font-size:11px; text-transform:uppercase; letter-spacing:.05em; color:var(--fg-3)}
.finwhen .inp{width:auto; flex:0 1 auto; padding:7px 10px; font-size:13px}

/* Конверт: заголовок, полоса, остаток. Перерасход красным по всей строке —
   это то место, ради которого раздел и заведён. */
.envrow{padding:12px var(--fin-pad); border-top:1px solid var(--line)}
.sublist .envrow:first-child{border-top:0}
.env-h{display:flex; align-items:baseline; gap:8px; margin-bottom:8px}
.env-h b{font-size:14px; flex:1; min-width:0}
.env-h span{font-size:12px; color:var(--fg-3); font-variant-numeric:tabular-nums}
.env-f{margin-top:7px; font-size:12.5px; color:var(--fg-2)}
.envrow.over .env-f{color:var(--crit)}
.fb-r.over{background:color-mix(in srgb, var(--crit) 18%, transparent)}
.fb-v.bad{color:var(--crit)}
.sr-v.bad{color:var(--crit)}

/* Столбики полугодия. Высота — доля от самого дорогого месяца, подпись суммы
   сверху: колонка чисел под графиком читается хуже, чем над ним. */
.fincols{display:flex; align-items:flex-end; gap:6px; height:150px}
.fincol{flex:1; display:flex; flex-direction:column; align-items:center; gap:5px; height:100%}
.fc-v{font-size:10.5px; color:var(--fg-3); font-variant-numeric:tabular-nums; white-space:nowrap}
.fc-b{flex:1; width:100%; display:flex; align-items:flex-end}
.fc-b i{display:block; width:100%; border-radius:6px 6px 0 0; background:var(--soft-2)}
.fincol.on .fc-b i{background:var(--accent)}
.fc-t{font-size:11px; color:var(--fg-3)}
.finline b.up-bad{color:var(--crit)}
.finline b.down-ok{color:var(--ok)}

/* «Ещё N бесплатно» рядом с кнопкой создания: предел называется до того, как
   в него упрутся, а не окном после нажатия. */
.freeleft{font-size:12px; color:var(--fg-3); align-self:center}

.card.finhint{border-color:var(--accent)}

/* Карточка подтверждения в разговоре: что именно запишется и на сколько. */
.syn-fin{margin-top:10px; padding:12px 14px; border:1px solid var(--stroke);
  border-radius:14px; background:var(--soft)}
.syn-fin b{display:block; font-size:13.5px; margin-bottom:8px}
.syn-fin ul{margin:0 0 10px; padding-left:18px}
.syn-fin li{font-size:13px; line-height:1.5; color:var(--fg-2); font-variant-numeric:tabular-nums}

/* Отказ у самого поля. Красная рамка и строка причины под ней: плашка внизу
   экрана годится, чтобы сказать «сделано», но не «не сделано» — человек
   смотрит туда, куда писал, а на телефоне плашку вдобавок закрывает нижняя
   панель. Гаснет от первого нажатия клавиши. */
.inp.bad, input.bad, textarea.bad{
  border-color:var(--crit);
  box-shadow:0 0 0 3px color-mix(in srgb, var(--crit) 16%, transparent);
}
.field-err{
  margin:6px 0 0;
  font-size:12.5px;
  line-height:1.45;
  color:var(--crit);
}

/* Кнопка «Оплатить» в строке платежа: не значок, а слово — это действие
   месяца, и прятать его в иконку рядом с крестиком нельзя. Оплаченное
   становится галочкой и гаснет вместе со строкой. */
.fr-pay{flex:none; padding:6px 12px; border-radius:999px; font-size:12.5px; font-weight:600;
  background:var(--fg); color:var(--bg); white-space:nowrap}
.fr-pay:hover{opacity:.85}
.fr-pay.on{width:28px; padding:0; height:28px; display:grid; place-items:center;
  background:var(--ok); color:#fff; font-size:14px}

/* Шаблоны платежей по группам. Каждая — своя строка с прокруткой вбок; весь
   блок прокручивается вниз. Тридцать кнопок в одну ленту не просматриваются,
   а в четыре подписанные — да. */
.tpl-group{margin:10px 0 6px; font-size:10.5px; text-transform:uppercase;
  letter-spacing:.06em; color:var(--fg-3); font-weight:600}

/* ---- две таблицы платежей в одной вкладке ---- */

.paysec{margin-bottom:26px}
.paysec .fintiles{margin-bottom:12px}

/* Таблица: название тянется, две колонки сумм фиксированной ширины и
   выровнены по правому краю — цифры сравнивают взглядом сверху вниз, а не
   вычитывают из строки. Кнопки — последней колонкой, по наведению. */
.paytable{background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg);
  box-shadow:var(--shadow); overflow:hidden}
.payhead, .payrow{display:grid; grid-template-columns:minmax(0,1fr) 92px 100px auto;
  align-items:center; gap:10px; padding:10px var(--fin-pad, 18px)}
.payhead{font-size:10.5px; text-transform:uppercase; letter-spacing:.05em;
  color:var(--fg-3); font-weight:600; background:var(--soft); padding-top:8px; padding-bottom:8px}
.payhead span:nth-child(2), .payhead span:nth-child(3){text-align:right}
.payrow{border-top:1px solid var(--line)}
.payrow.off{opacity:.5}
.pr-main{min-width:0; display:flex; align-items:center; gap:10px}
.pr-t{min-width:0; display:flex; flex-direction:column; gap:1px; font-size:14px}
.pr-n{font-size:11.5px; color:var(--fg-3)}
.pr-v{text-align:right; font-size:13.5px; font-variant-numeric:tabular-nums; white-space:nowrap}
.payrow.paid .pr-v{color:var(--ok)}
.payrow.paid .pr-t{opacity:.7}
.pr-a{display:flex; align-items:center; gap:2px; justify-content:flex-end}
@media (hover:hover) and (pointer:fine){
  .payrow .fr-x{opacity:0; transition:opacity .14s ease}
  .payrow:hover .fr-x, .payrow:focus-within .fr-x{opacity:1}
}

/* На телефоне колонка «в год» уходит: 375 пикселей на четыре колонки не
   делятся, а годовая сумма стоит в плитке над таблицей. */
@media (max-width:560px){
  /* Прячем колонку по классу, а не по порядку: nth-of-type считает среди
     всех span подряд, и под нож попадала колонка «в месяц» — в шапке
     оставалась её подпись, а под ней стояли годовые суммы. */
  .payhead, .payrow{grid-template-columns:minmax(0,1fr) 84px auto; gap:8px}
  .payhead .year, .payrow .pr-v.year{display:none}
  .fr-pay{padding:5px 9px; font-size:11.5px}
  .pr-t{font-size:13.5px}
  .payhead, .payrow{padding-left:12px; padding-right:12px}
}

/* Буквы вместо звёздочек на кнопке ассистента. Кегль мелкий, разрядка
   заметная — так две буквы читаются знаком, а не обрывком слова. */
.ai-mark{font-size:12px; font-weight:800; letter-spacing:.04em; line-height:1;
  font-family:var(--display, inherit)}
.say .ai, .rowadd .ai{font-weight:800}

/* ---- долги строками ---- */

.debtlist{display:flex; flex-direction:column;
  background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg);
  box-shadow:var(--shadow); overflow:hidden}
.debtrow{padding:10px var(--fin-pad, 18px); border-top:1px solid var(--line)}
.debtlist .debtrow:first-child{border-top:0}
.debtrow.done{opacity:.55}
.dr-main{display:flex; align-items:center; gap:10px}
.dr-t{flex:1; min-width:0; display:flex; flex-direction:column; gap:1px; font-size:14px}
/* Подпись переносится, а не обрезается многоточием: «я должен · до 1
   сентября · отдано 5 000 из 15 000» — это и есть всё, что нужно знать о
   долге, и терять хвост нельзя. */
.dr-n{font-size:11.5px; color:var(--fg-3); line-height:1.35}
.dr-v{font-size:15px; font-weight:600; font-variant-numeric:tabular-nums; flex:none}
.dr-v.closed{font-size:12.5px; font-weight:400; color:var(--fg-3)}
.dr-a{display:flex; align-items:center; gap:2px; flex:none}
@media (hover:hover) and (pointer:fine){
  .debtrow .fr-x{opacity:0; transition:opacity .14s ease}
  .debtrow:hover .fr-x, .debtrow:focus-within .fr-x{opacity:1}
}


/* «Или своё» под шаблонами: два поля в строку и кнопка — всё, что нужно,
   чтобы завести платёж, которого нет в списке. */

/* Плитки на телефоне: три штуки в ряд вместо двух и пустой клетки. */
@media (max-width:560px){
  .fintiles{grid-template-columns:repeat(auto-fit, minmax(96px, 1fr))}
  .fintile{padding:11px 12px}
  .fintile b{font-size:16px}
  .fintile span{font-size:10px}
}

/* ---- поля ввода на телефоне ---- */

/* Safari на айфоне сам приближает страницу, когда фокус встаёт в поле мельче
   16 пикселей, — и обратно не отдаляет. Снаружи это выглядит так, будто
   экран прыгнул, а окно уехало за край: именно это и происходило при каждом
   открытии окна с полем.

   Лечится единственным способом — шрифт в полях не мельче 16. Запрещать
   масштаб через maximum-scale нельзя: тогда человек не сможет приблизить
   страницу сам, когда ему нужно. */
@media (max-width:759px){
  .inp, input, select, textarea,
  .rowadd .inp, .finwhen .inp, .say input, .inp-sum{
    font-size:16px;
  }
  .finwhen .inp{padding:8px 11px}
  .rowadd .inp{padding:9px 12px}
}

/* Знак сервиса: фирменный цвет и буква. Не эмодзи и не чужой логотип —
   узнаётся так же быстро, а принадлежит нам. */
.tplmark{width:20px; height:20px; border-radius:6px; flex:none;
  display:inline-grid; place-items:center; color:#fff;
  font-size:9px; font-weight:800; letter-spacing:-.02em; line-height:1}

/* Два поля в ряд: сумма и период — короткие, и разводить их на две строки
   значит растить окно вдвое ради воздуха. */
.pairfields{display:flex; gap:10px}
.pairfields .field{flex:1; min-width:0}

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


/* ---- поле даты ---- */

/* Safari на айфоне рисует input[type=date] по-своему: значение прижимается к
   середине, а само поле шире соседних — оно берёт ширину под формат
   «15 авг. 2026 г.» и не слушает width:100%. В ряду полей это видно сразу:
   одна строка выпирает и текст в ней стоит не как у всех. */
input[type="date"], input[type="time"], input[type="month"]{
  -webkit-appearance:none;
  appearance:none;
  text-align:left;
  min-width:0;
  max-width:100%;
  box-sizing:border-box;
}
input[type="date"]::-webkit-date-and-time-value{
  text-align:left;
  margin:0;
}
input[type="date"]::-webkit-calendar-picker-indicator{
  margin-left:auto;
  opacity:.55;
}
input[type="date"]::-webkit-datetime-edit{
  padding:0;
}

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

/* <details> вместо своего раскрывающегося блока: браузер сам держит
   состояние, ничего не ломается при перерисовке окна и работает без скрипта. */
.tplpick{margin:0 0 16px; border:1px solid var(--stroke); border-radius:var(--r-md);
  background:var(--soft); overflow:hidden}
.tplpick > summary{list-style:none; cursor:pointer; padding:12px 15px; font-size:14px;
  display:flex; align-items:center; justify-content:space-between; gap:10px}
.tplpick > summary::-webkit-details-marker{display:none}
.tplpick > summary::after{content:'⌄'; font-size:15px; color:var(--fg-3); line-height:1;
  transition:transform .16s ease}
.tplpick[open] > summary::after{transform:rotate(180deg)}
.tplpick[open] > summary{border-bottom:1px solid var(--line)}

.tpllist{max-height:236px; overflow-y:auto; overscroll-behavior:contain;
  background:var(--card)}
.tplrow{display:flex; align-items:center; gap:10px; width:100%; text-align:left;
  padding:9px 15px; border-top:1px solid var(--line); font-size:14px; cursor:pointer}
.tpllist .tplrow:first-child{border-top:0}
.tplrow:hover{background:var(--soft)}
.tplname{flex:1; min-width:0}
.tplsum{font-size:12.5px; color:var(--fg-3); font-variant-numeric:tabular-nums; flex:none}
.tpllist .tpl-group{margin:0; padding:9px 15px 5px; background:var(--soft);
  border-top:1px solid var(--line)}
.tpllist .tpl-group:first-child{border-top:0}

/* Логотип и плашка лежат друг на друге: не загрузился первый — видно вторую.
   Ни таймеров, ни подмены скриптом. */
.tpllogo{position:relative; width:20px; height:20px; flex:none; display:block}
.tpllogo img{position:absolute; inset:0; width:20px; height:20px; border-radius:5px;
  object-fit:contain; background:var(--card); z-index:1; opacity:0; transition:opacity .15s ease}
.tpllogo img.ok{opacity:1}
.tpllogo .tplmark{position:absolute; inset:0}
.tplmark.none{background:var(--soft-2)}

/* Подписки и платежи — двумя равными вкладками. Не главное и второстепенное,
   а выбор из двух: и ширина у кнопок поэтому одна. */
.paytabs{display:grid; grid-template-columns:1fr 1fr; gap:3px; padding:3px;
  margin:0 0 16px; background:var(--soft); border:1px solid var(--line); border-radius:14px}
/* Надпись по центру своей кнопки: кнопки одной ширины, и текст, прижатый
   влево, выдавал бы их за разные по весу. */
.paytab{border:0; background:none; border-radius:11px; padding:10px 12px;
  font-size:14px; color:var(--fg-2); cursor:pointer; white-space:nowrap;
  display:grid; place-items:center}
.paytab:hover{color:var(--fg)}
.paytab.on{background:var(--card); color:var(--fg); font-weight:600; box-shadow:var(--shadow)}

/* Плитка «Свободно» — кнопка: остаток правят там же, где на него смотрят. */
button.fintile{text-align:left; cursor:pointer; border:0; font:inherit; color:inherit; width:100%}
button.fintile:hover{background:var(--soft)}

/* Пустой блок дня ничем не отличается от остальных: тот же заголовок, тот же
   размер, тот же цвет. Приглушать его — значит снова делать из одного и того
   же дня две разные вещи. Единственное отличие — слово «пусто» вместо числа
   задач, и этого достаточно. */
.group.empty{margin-bottom:10px}

/* ---- настройки вида ---- */

/* Превью прибито к верху экрана и едет вместе с прокруткой.

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

   Длинное пояснение из карточки убрано: подпись «Как это выглядит» говорит
   то же самое, а высота у прибитого блока на счету. */
.preview-dock{
  position:sticky;
  top:0;
  z-index:20;
  padding:6px 0 12px;
  background:var(--bg);
  margin-bottom:4px;
}
.preview-dock .lbl{margin-top:0}
.preview-dock .card.preview{margin-bottom:0; padding:14px 16px}
.preview-dock .preview-task h3{margin:0}

/* Блоки настроек — сеткой, а не колонкой во всю ширину.

   У «Темы» две кнопки, а карточка занимала ту же строку, что и палитра из
   десяти: справа оставалось пустое поле в пол-экрана, а экран рос вниз.
   Теперь короткие блоки стоят парами, длинные занимают всю ширину. */
/* Три квадрата в ряд и выбор отметки полосой под ними.

   Колонки разной ширины намеренно: у «Темы» две кнопки, у «Палитры» —
   десять. Равные колонки означали бы либо пустое поле слева, либо палитру
   в пять рядов. Ширина по содержимому — и ряд получается ровным. */
.setgrid{display:grid; gap:var(--gap); align-items:stretch;
  grid-template-columns:repeat(auto-fit, minmax(240px, 1fr))}
.setgrid .setblock{margin-bottom:0}
.setgrid .setblock.wide{grid-column:1 / -1}

@media (min-width:880px){
  /* Доли подобраны по содержимому: «Светлая» и «Тёмная» должны встать в одну
     строку, три начертания — тоже, а палитре нужно место на десять кружков. */
  /* «Текст» шире соседей: в нём самое длинное слово во всём экране —
     «маленький», и в узкой колонке оно обрезалось многоточием. */
  .setgrid{grid-template-columns:minmax(0,.78fr) minmax(0,1.34fr) minmax(0,1.38fr)}
}

/* Кнопки прижаты к верху карточки, а не размазаны по её высоте: карточки в
   ряду одной высоты, и без этого содержимое каждой висело бы посередине. */
.setgrid .setblock{display:flex; flex-direction:column}
.setgrid .setblock .subrow:last-child{margin-bottom:auto}

@media (max-width:600px){
  .setgrid{grid-template-columns:1fr; align-items:start}
  /* На телефоне прибитая карточка съедала бы треть экрана: оставляем её
     наверху, но без прилипания — там и листать меньше. */
  .preview-dock{position:static}
}

/* Кнопки внутри квадратов настроек компактнее: в колонке 200 пикселей
   «Светлая» и «Тёмная» с обычными отступами не встают в строку, а перенос
   одной кнопки под другую превращает квадрат в столбик. */
.setgrid .radio{padding:8px 12px; font-size:13px; gap:7px}
.setgrid .radio.pal{padding:6px 11px 6px 6px}
.setgrid .radios{gap:6px}
.setgrid .setblock-h .sub{font-size:12.5px}

/* Кнопки в ряду настроек — сеткой, а не переносом по мере заполнения.

   При переносе ряд получался рваным: «Rounded» шире «Clean», «Треугольник»
   шире «Круга», и каждая строка кончалась в своём месте. Равные колонки
   делают кнопки одинаковыми, а число колонок задаётся под содержимое. */
.setgrid .radios{
  display:grid;
  grid-template-columns:repeat(var(--cols, 2), minmax(0, 1fr));
  gap:6px;
}
.setgrid .radio{
  display:flex;
  align-items:center;
  justify-content:center;
  gap:6px;
  padding:9px 8px;
  text-align:center;
  min-width:0;
}
/* Кружок слева, название по центру оставшегося места.

   Центрировать пару «кружок + название» целиком было мало: названия разной
   длины, и кружки в колонке вставали на разной высоте от края — ряд выглядел
   пляшущим. Теперь кружки на одной вертикали, а подписи по центру своих
   кнопок. */
.radio.pal, .radio.boxpick, .radio.markpick{justify-content:flex-start; padding-left:8px}
.radio .rl{flex:1; min-width:0; text-align:center;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
/* Пустышка справа шириной со значок: без неё «центр оставшегося места» и
   «центр кнопки» — разные точки, и подпись стоит правее середины ровно на
   половину кружка. */
.radio.pal::after, .radio.boxpick::after, .radio.markpick::after{
  content:''; flex:none;
}

/* Узкий экран: подписи не помещаются — значит их и не должно быть.

   Шесть кнопок в ряд на телефоне дают около сорока пикселей на кнопку, и
   название схлопывалось в ноль. Схлопнутое название всё равно остаётся
   растягивающимся блоком, и значок оставался прижатым влево — из-за этого
   галочки и стояли не по центру. Убираем подпись совсем и центрируем то, что
   осталось: форма и цвет читаются сами, а название повторено в подсказке. */
@media (max-width:640px){
  .radio.boxpick, .radio.markpick{
    justify-content:center; padding-left:10px; padding-right:10px; gap:0;
  }
  .radio.boxpick .rl, .radio.markpick .rl{display:none}
  .radio.boxpick::after, .radio.markpick::after{display:none}
}
.setgrid .radio.pal::after{width:14px}
.setgrid .radio.boxpick::after{width:18px}
.setgrid .radio .sw, .setgrid .radio .box{flex:none}
.setgrid .radio span:not(.sw):not(.box){overflow:hidden; text-overflow:ellipsis; white-space:nowrap}

/* Блоки каждый своей высоты: тянуть «Тему» с двумя кнопками до высоты
   «Палитры» с десятью — это полкарточки пустоты, только уже внутри. */
.setgrid{align-items:start}
.setgrid .setblock{margin:0}

/* Строка-ссылка в сводке: подпись, число и стрелка.

   Пришла на место списков, которые слово в слово повторяли содержимое
   соседних вкладок. Здесь важно одно число и путь к подробностям — а не
   пересказ восьми строк, из-за которого сводку и не читали. */
.finrow-link{
  display:flex; align-items:center; gap:12px; width:100%; text-align:left;
  padding:14px 16px; margin-bottom:var(--gap);
  background:var(--card); border:1px solid var(--stroke); border-radius:var(--r-lg);
  box-shadow:var(--shadow); cursor:pointer;
}
.finrow-link:hover{background:var(--soft)}
.frl-t{flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; font-size:14.5px}
.frl-n{font-size:11.5px; color:var(--fg-3)}
.finrow-link b{font-size:16px; font-variant-numeric:tabular-nums; flex:none}
.finrow-link b.bad{color:var(--crit)}
.frl-go{color:var(--fg-3); font-size:19px; line-height:1; flex:none}

/* Значки в кнопках финансов рисуются, а не набираются шрифтом: ✓, ⏻, ↺, ‹ и ›
   есть не в каждом системном шрифте, и на части андроидов вместо кнопки был
   пустой квадрат. */
.finmonth button svg, .frl-go svg, .fr-pay svg{
  width:15px; height:15px; display:block;
  fill:none; stroke:currentColor; stroke-width:1.8;
  stroke-linecap:round; stroke-linejoin:round;
}
.fr-pay.on svg{width:14px; height:14px}
.frl-go{display:grid; place-items:center}
.frl-go svg{width:17px; height:17px; stroke-width:1.7}
.finmonth button{display:grid; place-items:center}

/* Своя длительность рядом с готовыми: сорок минут или семь из списка не
   выбрать, а сеанс у каждого свой. */
.med-mins{align-items:center}
.medown{display:inline-flex; align-items:center; gap:6px; padding:2px 10px 2px 4px;
  background:var(--soft); border-radius:999px}
.medown.on{background:var(--fg)}
.medown input{width:52px; border:0; background:none; text-align:center;
  font-size:13.5px; color:var(--fg-2); padding:7px 0; -moz-appearance:textfield}
.medown.on input{color:var(--bg)}
.medown input::-webkit-outer-spin-button,
.medown input::-webkit-inner-spin-button{-webkit-appearance:none; margin:0}
.medown .mu{font-size:13.5px; color:var(--fg-3)}
.medown.on .mu{color:var(--bg); opacity:.75}


/* ---- строка с переключателем (настройки приложения) ---- */
/* Раньше в настройках были только наборы кнопок-радио: «включено/выключено»
   ими выражается плохо — две кнопки на два состояния занимают строку и всё
   равно требуют прочесть обе. */
.switchrow{
  display:flex; align-items:center; gap:14px; width:100%;
  background:none; border:0; padding:11px 0; text-align:left; color:var(--fg);
  border-top:1px solid var(--line); cursor:pointer;
}
.switchrow:first-child{border-top:0}
.sw-text{flex:1; min-width:0; display:flex; flex-direction:column; gap:2px}
.sw-text b{font-size:14.5px; font-weight:600}
.sw-text i{font-style:normal; font-size:12.5px; color:var(--fg-3); line-height:1.35}
.sw-knob{
  flex:none; width:44px; height:26px; border-radius:999px;
  background:var(--soft-2); position:relative; transition:background .16s ease;
}
.sw-knob::after{
  content:''; position:absolute; top:3px; left:3px; width:20px; height:20px;
  border-radius:999px; background:var(--card); box-shadow:var(--shadow);
  transition:transform .16s cubic-bezier(.2,.8,.3,1);
}
.switchrow[aria-pressed="true"] .sw-knob{background:var(--accent)}
.switchrow[aria-pressed="true"] .sw-knob::after{transform:translateX(18px)}
.switchrow:focus-visible{outline:2px solid var(--accent); outline-offset:2px; border-radius:8px}
@media (prefers-reduced-motion:reduce){ .sw-knob, .sw-knob::after{transition:none} }

.in-app .toast{bottom:188px}

/* Под курсором карточка не раздувается: мышью её не сдвигают вбок, и лишние
   двенадцать пикселей ширины только сбивают прицел. Тень и слой остаются —
   поднятой она должна выглядеть в любом случае. */
.item.dragging.мышью{cursor:grabbing}
.dragging-now, .dragging-now *{cursor:grabbing !important; user-select:none}

/* Код языка в шапке рядом с темой. Буквами, а не флагом: флаг обозначает
   страну, а не язык, и для английского пришлось бы выбирать между странами. */
.iconbtn.lang .lang-code{
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
}

/* Строка записи трат: тот же вид, что у строки создания задач, плюс
   переключатель «Трата / Доход» над ней. Переключатель именно НАД полем, а не
   внутри: внутри он съедал бы половину строки, а меняют его редко — обычно
   пишут траты подряд. */
.fincomposer .finswitch{
  display: flex;
  gap: 4px;
  margin: 0 auto 8px;
  width: max-content;
  background: var(--panel);
  border: 1px solid var(--stroke);
  border-radius: 999px;
  padding: 3px;
  box-shadow: var(--shadow);
}
.fincomposer .finswitch button{
  padding: 5px 14px;
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--fg-3);
}
.fincomposer .finswitch button.on{ background: var(--accent-soft); color: var(--accent); }

/* Микрофон во время слушания — заметно «включён»: человек говорит и должен
   видеть, что его слышат, не вглядываясь. */
.say .ai.on{ background: var(--accent); border-color: var(--accent); color: #fff; }

/* Место под плавающей строкой: без него последняя трата в списке оказывается
   под ней и её не прочитать. */
.finance-has-composer{ padding-bottom: 96px; }
