/* Движение и жесты. Переходы между экранами — View Transitions; где их нет, срабатывают короткие появления по data-enter.
   Всё короткое и мягкое, читать не мешает; при системной настройке «меньше движения» выключается целиком.
   Кривые — одно семейство: движение трогается быстро и плавно замедляется к концу, без рывков и дрожания.
     --ease       мелкое: отклик на нажатие, появление, цвет, сдвиг до полусотни точек;
     --ease-soft  крупное: окно, шторка, листание страницы, смена экрана, переезд строки. Трогается мягче, чем --ease:
                  большая поверхность в первом кадре не прыгает далеко вперёд;
     --ease-exit  уход за край (окно вниз, шторка вправо): разгоняется и уходит, а не ползёт у края экрана;
     --spring     маленькая «пружинка» с перелётом — только для значков.
   Длительность растёт с расстоянием: нажатие 0,14 с, цвет и угасание 0,18 с, небольшой сдвиг 0,24 с, смена экрана 0,28 с,
   страница 0,3 с, окно во весь рост 0,34 с; уход короче прихода. Двигаются только transform и opacity — раскладка страницы не пересчитывается. */
:root{--ease:cubic-bezier(.2,.8,.2,1);--ease-soft:cubic-bezier(.32,.72,0,1);--ease-exit:cubic-bezier(.3,0,1,1);--spring:cubic-bezier(.3,1.5,.5,1)}

/* Отклик на нажатие */
.btn,.chip,.tile,.tab,.nav,.icon-btn,.hb,.mod,.style-card,.pal-card,.swatch,.cd,.ym,.wd,.pb-pick,.wday,.idot,.cdot,button.rowi,button.card,.fab{transition:transform .14s var(--ease),background-color .18s var(--ease),color .18s var(--ease),box-shadow .18s var(--ease),opacity .18s var(--ease)}
.btn:active,.chip:active,.tile:active,.mod:active,.style-card:active,.pal-card:active,.cd:active,.ym:active,button.card:active,.wday:active{transform:scale(.965)}
.icon-btn:active,.hb:active,.tab:active,.nav:active,.wd:active,.fab:active,.idot:active,.cdot:active,.swatch:active{transform:scale(.9)}
.cell{transition:background-color .18s var(--ease)}
.sw::after{transition:transform .2s var(--ease)}
.cb{transition:background-color .15s var(--ease),border-color .15s var(--ease)}

/* Отметка, появление строки, кольцо привычки, полоски.
   «Пружинка» галочки: значок вырастает чуть больше себя, замирает в верхней точке и мягко садится на место — один перелёт,
   без второго подскока и без провала ниже своего размера (кривая задана на каждом отрезке, поэтому скорость нигде не скачет) */
@keyframes pop{0%{transform:scale(.6);animation-timing-function:cubic-bezier(.2,.8,.2,1)}55%{transform:scale(1.14);animation-timing-function:cubic-bezier(.45,0,.55,1)}100%{transform:none}}
@keyframes rise{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes grow-x{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.pop{animation:pop .38s}
.rise{animation:rise .28s var(--ease) both}
.ring .rp{transition:stroke-dashoffset .45s var(--ease-soft)}
.bar i{transform-origin:left center}
/* Полоски «вырастают» только при смене экрана или месяца; открытие, закрытие и смена окна (sheet-*, dim) графики не трогают */
.app:is([data-enter="forward"],[data-enter="back"],[data-enter="fade"],[data-enter="next"],[data-enter="prev"],[data-enter^="zoom"]) .bar i,
html:is([data-motion="forward"],[data-motion="back"],[data-motion="fade"],[data-motion="next"],[data-motion="prev"],[data-motion^="zoom"]) .bar i{animation:grow-x .42s var(--ease-soft) both}
/* После записи траты на том же экране полоски и суммы «Финансов» доезжают от прежнего значения к новому — это ведёт js/tween.js
   (здесь правил нет: при «меньше движения» app.js его просто не запускает) */

/* Окна: появление только в момент открытия, а не при каждой перерисовке */
.app .sheet,.app[data-device="desktop"] .sheet,.app .sheet.alert,.app[data-device="phone"] .sheet.drawer{animation:none}
/* Окно въезжает снизу целиком, от самого края, а не выпрыгивает полупрозрачным с середины экрана */
@keyframes sheet-rise{from{transform:translateY(100%)}}
.app[data-enter="sheet-in"] .sheet{animation:sheet-rise .34s var(--ease-soft)}
.app[data-enter="sheet-in"][data-device="desktop"] .sheet,.app[data-enter="sheet-in"] .sheet.alert{animation:sheet-pop .22s var(--ease)}
.app[data-enter="sheet-in"] .overlay,.app[data-enter="dim"] .overlay,.app[data-enter="drawer-in"] .overlay{animation:enter-fade .24s var(--ease)}
/* Шторка «Вид и календари» на телефоне въезжает справа — только когда её открыли (где нет View Transitions) */
.app[data-enter="drawer-in"][data-device="phone"] .sheet.drawer{animation:drawer-in .3s var(--ease-soft)}
/* Закрытое окно без View Transitions уходит так же плавно: его прежний узел ещё на миг лежит поверх экрана в своей рамке
   и уезжает вниз (шторка — вправо), затемнение гаснет. Рамку, движение и уборку ведёт js/flip.js (sheetGhost) */
.overlay.leaving{display:flex;pointer-events:none}
@keyframes enter-fade{from{opacity:0}}
@keyframes enter-right{from{opacity:0;transform:translateX(28px)}}
@keyframes enter-left{from{opacity:0;transform:translateX(-28px)}}
@keyframes enter-zoom{from{opacity:0;transform:scale(1.06)}}
.app[data-enter="forward"] #screen,.app[data-enter="next"] :is([data-page],[data-slide]){animation:enter-right .28s var(--ease-soft)}
.app[data-enter="back"] #screen,.app[data-enter="prev"] :is([data-page],[data-slide]){animation:enter-left .28s var(--ease-soft)}
.app[data-enter="fade"] #screen{animation:enter-fade .24s var(--ease)}
.app[data-enter^="zoom"] #screen{animation:enter-zoom .3s var(--ease-soft)}

/* View Transitions: имена раздаются только тем частям, которые участвуют в этом переходе */
::view-transition-group(*){animation-duration:.3s;animation-timing-function:var(--ease-soft)}
::view-transition-old(root),::view-transition-new(root){animation-duration:.22s}
/* Пока идёт переход, собственные переливания цвета у фона, вкладок, пунктов меню и клеток месяца выключены: новый снимок живой,
   и без этого цвет доезжал бы второй раз поверх общего перехода — анимация двоилась бы и кончалась позже самого перехода */
html[data-motion] :is(.app,.tab,.nav,.cell){transition:none}
::view-transition-group(screen),::view-transition-group(pane){overflow:clip}
::view-transition-old(screen),::view-transition-new(screen),::view-transition-old(pane),::view-transition-new(pane),::view-transition-old(sheet),::view-transition-new(sheet){mix-blend-mode:normal}
@keyframes vt-in{from{opacity:0}}
@keyframes vt-out{to{opacity:0}}
@keyframes vt-to-left{to{transform:translateX(-36px)}}
@keyframes vt-from-right{from{transform:translateX(44px)}}
@keyframes vt-to-right{to{transform:translateX(36px)}}
@keyframes vt-from-left{from{transform:translateX(-44px)}}
@keyframes vt-grow{from{transform:scale(.985)}}
/* Страница листается на 28 % своей ширины, но не дальше 150 точек: на широком экране она едет с той же скоростью, что на телефоне,
   а не пролетает пол-экрана за то же время */
@keyframes vt-page-to-left{to{transform:translateX(max(-28%,-150px))}}
@keyframes vt-page-from-right{from{transform:translateX(min(28%,150px))}}
@keyframes vt-page-to-right{to{transform:translateX(min(28%,150px))}}
@keyframes vt-page-from-left{from{transform:translateX(max(-28%,-150px))}}
@keyframes vt-sheet-up{from{transform:translateY(100%)}}
@keyframes vt-sheet-down{to{transform:translateY(100%)}}
@keyframes vt-pop{from{transform:scale(.96)}}
@keyframes vt-sink{to{transform:scale(.97)}}
@keyframes vt-from-big{from{transform:scale(1.35)}}
@keyframes vt-to-small{to{transform:scale(.8)}}
@keyframes vt-from-small{from{transform:scale(.8)}}
@keyframes vt-to-big{to{transform:scale(1.35)}}

/* Прежний экран гаснет быстрее, чем проявляется новый: два экрана почти не просвечивают друг сквозь друга */
html[data-motion="forward"] #screen,html[data-motion="back"] #screen,html[data-motion="fade"] #screen,html[data-motion^="zoom"] #screen{view-transition-name:screen}
html[data-motion="forward"]::view-transition-old(screen){animation:.16s var(--ease) both vt-out,.28s var(--ease-soft) both vt-to-left}
html[data-motion="forward"]::view-transition-new(screen){animation:.24s var(--ease) both vt-in,.28s var(--ease-soft) both vt-from-right}
html[data-motion="back"]::view-transition-old(screen){animation:.16s var(--ease) both vt-out,.28s var(--ease-soft) both vt-to-right}
html[data-motion="back"]::view-transition-new(screen){animation:.24s var(--ease) both vt-in,.28s var(--ease-soft) both vt-from-left}
html[data-motion="fade"]::view-transition-old(screen){animation:.12s var(--ease) both vt-out}
html[data-motion="fade"]::view-transition-new(screen){animation:.24s var(--ease) both vt-in,.28s var(--ease-soft) both vt-grow}

/* Листаемая область — [data-page] (стрелкой и пальцем) или [data-slide] (только стрелкой или выбором дня: список «Привычек») */
html[data-motion="next"] :is([data-page],[data-slide]),html[data-motion="prev"] :is([data-page],[data-slide]){view-transition-name:pane}
html[data-motion="next"]::view-transition-old(pane){animation:.18s var(--ease) both vt-out,.3s var(--ease-soft) both vt-page-to-left}
html[data-motion="next"]::view-transition-new(pane){animation:.26s var(--ease) both vt-in,.3s var(--ease-soft) both vt-page-from-right}
html[data-motion="prev"]::view-transition-old(pane){animation:.18s var(--ease) both vt-out,.3s var(--ease-soft) both vt-page-to-right}
html[data-motion="prev"]::view-transition-new(pane){animation:.26s var(--ease) both vt-in,.3s var(--ease-soft) both vt-page-from-left}

/* «месяц ↔ год»: сетка месяца превращается в маленький месяц года и обратно. Только текущая сетка (data-zoom): соседние месяцы
   ленты на телефоне (js/pager.js) имени не получают — два одинаковых имени сорвали бы переход */
html[data-motion^="zoom"] .month[data-zoom],html[data-motion^="zoom"] .ym.ym-cur .ym-grid{view-transition-name:zoomcell}
::view-transition-group(zoomcell){animation-duration:.36s}
::view-transition-old(zoomcell),::view-transition-new(zoomcell){width:100%;height:100%;object-fit:fill}
html[data-motion="zoom-out"]::view-transition-old(screen){animation:.2s var(--ease) both vt-out,.36s var(--ease-soft) both vt-to-small}
html[data-motion="zoom-out"]::view-transition-new(screen){animation:.3s var(--ease) both vt-in,.36s var(--ease-soft) both vt-from-big}
html[data-motion="zoom-in"]::view-transition-old(screen){animation:.2s var(--ease) both vt-out,.36s var(--ease-soft) both vt-to-big}
html[data-motion="zoom-in"]::view-transition-new(screen){animation:.3s var(--ease) both vt-in,.36s var(--ease-soft) both vt-from-small}

/* Окно въезжает мягкой кривой (без прыжка в первом кадре) и уходит разгоняясь — уход короче прихода */
html[data-motion^="sheet"] .overlay .sheet,html[data-motion^="drawer"] .overlay .sheet{view-transition-name:sheet}
html[data-motion="sheet-in"]::view-transition-new(sheet){animation:.34s var(--ease-soft) both vt-sheet-up}
html[data-motion="sheet-out"]::view-transition-old(sheet){animation:.24s var(--ease-exit) both vt-sheet-down}
/* Шторка справа и уезжает вправо — не снизу и не наискосок */
@keyframes vt-drawer-in{from{transform:translateX(100%)}}
@keyframes vt-drawer-out{to{transform:translateX(100%)}}
html[data-motion="drawer-in"]::view-transition-new(sheet){animation:.3s var(--ease-soft) both vt-drawer-in}
html[data-motion="drawer-out"]::view-transition-old(sheet){animation:.22s var(--ease-exit) both vt-drawer-out}
/* На компьютере окно посреди экрана: проявляется, чуть вырастая, и гаснет, чуть уменьшаясь, — в обе стороны одинаково */
html[data-device="desktop"][data-motion="sheet-in"]::view-transition-new(sheet){animation:.22s var(--ease) both vt-in,.24s var(--ease-soft) both vt-pop}
html[data-device="desktop"][data-motion="sheet-out"]::view-transition-old(sheet){animation:.16s var(--ease-exit) both vt-out,.16s var(--ease-exit) both vt-sink}

/* Плашка внизу выплывает мягко и уходит быстрее, чем пришла */
.toast{transition:opacity .18s var(--ease-exit),transform .18s var(--ease-exit)}
.toast.show{transition:opacity .2s var(--ease),transform .26s var(--ease)}

/* «Назад» движением вправо — текущий экран едет за пальцем (gestures.js, не дальше 96 точек) с тенью слева, открывшаяся полоса чуть темнее;
   прошлого экрана под ним нет — у края стрелка, она наливается цветом, когда отпускание уже вернёт назад */
#screen.back-drag{background:var(--bg);box-shadow:-14px 0 28px -12px rgba(0,0,0,.32);will-change:transform}
.main:has(>#screen.back-drag){background:color-mix(in srgb,var(--text) 6%,var(--bg))}
.back-peek{position:fixed;left:8px;top:50%;z-index:26;display:grid;place-items:center;width:38px;height:38px;margin-top:-19px;border-radius:50%;
  color:var(--text);background:var(--surface);box-shadow:var(--shadow);opacity:0;pointer-events:none;transition:opacity .16s var(--ease),transform .2s var(--ease),background-color .15s var(--ease),color .15s var(--ease)}
.back-peek svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.back-peek.armed{color:var(--on-accent);background:var(--accent)}

/* Свайп по строке: строка едет за пальцем, под ней — цвет и значок действия */
.swipe{position:relative;display:block !important;padding:0 !important;overflow:hidden;touch-action:pan-y}
.swipe>.swipe-fg{position:relative;display:flex;align-items:center;gap:12px;padding:11px 0;background:var(--bg)}
/* Свой слой видеокарты — только у строки, которую тянут прямо сейчас (класс swiping ставится в начале жеста, gestures.js),
   а не у каждой строки длинного списка: память слабого телефона не тратится на десятки слоёв */
.swipe.swiping>.swipe-fg{will-change:transform}
.rowi.swipe>.swipe-fg{min-height:58px;padding:9px 0}
.app[data-variant="b"] .lg .swipe-fg,.app[data-variant="b"] .group .swipe-fg{background:var(--surface)}
.swipe-under{position:absolute;inset:1px 0;display:none;align-items:center;justify-content:space-between;padding:0 20px;border-radius:14px;color:#fff;background:var(--sw-c,#35a66b)}
.swipe.swiping .swipe-under{display:flex}
.swipe-under svg.lucide{width:22px;height:22px;stroke-width:2.4;opacity:.75;transform:scale(.8);transition:transform .2s var(--spring),opacity .15s var(--ease)}
.swipe.armed .swipe-under svg.lucide{opacity:1;transform:scale(1.15)}
.swipe[data-dir="right"] .su-r,.swipe[data-dir="left"] .su-l{visibility:hidden}
.swipe[data-dir="right"]{--sw-c:#35a66b}
.swipe[data-dir="left"]{--sw-c:#527fe1}
.swipe[data-dir="left"][data-left="delete"]{--sw-c:#e5484d}

/* Год: двенадцать маленьких месяцев, дни со сменами подкрашены цветом смены */
.month,.year{touch-action:none}
.wk,.tl{touch-action:pan-y}
.year{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px 10px;padding:6px 14px 28px}
.app[data-device="desktop"] .year{grid-template-columns:repeat(4,minmax(0,1fr));gap:30px 36px;max-width:1120px;padding:10px 28px 36px}
.ym{display:block;align-self:start;min-width:0;padding:4px;border-radius:14px;text-align:left;color:var(--text)}
.ym>b{display:block;margin:0 0 5px 4px;font-size:17px;font-weight:var(--head-w);letter-spacing:var(--head-track)}
.ym.ym-now>b{color:var(--accent-ink)}
.ym-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px 1px}
.ym-grid i{display:grid;place-items:center;aspect-ratio:1;border-radius:32%;font-style:normal;font-size:10.5px;font-weight:600;font-variant-numeric:tabular-nums}
.app[data-variant="b"] .ym-grid i{border-radius:50%}
.app[data-device="desktop"] .ym-grid i{font-size:12.5px}
.ym-grid i[data-has]{background:color-mix(in srgb,var(--c) 30%,transparent)}
.app[data-palette="bright"] .ym-grid i[data-has]{background:var(--c);color:#fff}
.ym-grid i.today{background:var(--accent);color:var(--on-accent);font-weight:800}

@media (prefers-reduced-motion:reduce){
  ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none !important}
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important}
}
/* «Меньше движения» в «Оформлении». Переходы между экранами и выезд окон app.js уже не запускает (экраны меняются сразу);
   здесь гасим появления, которые идут сами: новая запись, свежее настроение друга, шторка, окна, полоски. Мелкие отклики на нажатие
   (кнопка чуть сжимается, кружок выключателя, кольцо привычки, «пружинка» галочки) остаются — в отличие от системной настройки */
.app[data-calm="on"] :is(.rise,.ava-bf.fresh,.sheet,.overlay,.bar i,[data-page],[data-slide],#screen){animation:none !important}

/* Панель вкладок, кнопка-карандаш, полоса разметки и плашки лежат ПОВЕРХ экрана. Снимок листаемого экрана (screen, pane) рисуется выше общего снимка
   страницы, поэтому без своего имени они на время перехода оказались бы под ним — панель на треть секунды «пропадала» бы при листании месяца и смене вкладок.
   Со своим именем они остаются сверху. Для окон (sheet) имён нет: там панель должна оставаться под затемнением вместе со всей страницей. */
html:is([data-motion="forward"],[data-motion="back"],[data-motion="fade"],[data-motion="next"],[data-motion="prev"],[data-motion^="zoom"]) #tabbar{view-transition-name:tabbar}
html:is([data-motion="forward"],[data-motion="back"],[data-motion="fade"],[data-motion="next"],[data-motion="prev"],[data-motion^="zoom"]) #fab{view-transition-name:fab}
html:is([data-motion="forward"],[data-motion="back"],[data-motion="fade"],[data-motion="next"],[data-motion="prev"],[data-motion^="zoom"]) #paintbar{view-transition-name:paintbar}
html:is([data-motion="forward"],[data-motion="back"],[data-motion="fade"],[data-motion="next"],[data-motion="prev"],[data-motion^="zoom"]) #netpill{view-transition-name:netpill}
html:is([data-motion="forward"],[data-motion="back"],[data-motion="fade"],[data-motion="next"],[data-motion="prev"],[data-motion^="zoom"]) #toast{view-transition-name:toast}
::view-transition-group(tabbar),::view-transition-group(fab),::view-transition-group(paintbar),::view-transition-group(netpill),::view-transition-group(toast){animation-duration:.2s}
/* «Мягкий» — «таблетка» выбранной вкладки плавно перетекает к новой вкладке. Размер и место (flex, display) браузер сам
   не анимирует, поэтому у «таблетки» своё имя в переходе: её ведут с прежнего места и ширины на новые примерно за 0,25 с,
   а остальная панель мягко сменяется целиком. Имя даётся только при тех же переходах, что и панели: при открытии
   окна «таблетка» остаётся под затемнением вместе со всей страницей. Собственное переливание цвета у вкладок на время перехода
   выключено (правило html[data-motion] выше) — иначе на старом месте на миг оставался бы второй, гаснущий след «таблетки». */
html:is([data-motion="forward"],[data-motion="back"],[data-motion="fade"],[data-motion="next"],[data-motion="prev"],[data-motion^="zoom"],[data-motion="next-v"],[data-motion="prev-v"]) .app[data-variant="b"] .tab.on{view-transition-name:tabpill}
::view-transition-group(tabpill){animation-duration:.26s;border-radius:18px;overflow:clip}
::view-transition-old(tabpill),::view-transition-new(tabpill){height:100%;object-fit:none}

/* Месяц листается вверх-вниз: уходящий месяц уезжает вверх, следующий приходит снизу (и наоборот) */
.app[data-enter="next-v"] [data-page]{animation:enter-up .28s var(--ease-soft)}.app[data-enter="prev-v"] [data-page]{animation:enter-down .28s var(--ease-soft)}
@keyframes enter-up{from{opacity:0;transform:translateY(28px)}}@keyframes enter-down{from{opacity:0;transform:translateY(-28px)}}
html[data-motion="next-v"] [data-page],html[data-motion="prev-v"] [data-page]{view-transition-name:pane}
html[data-motion="next-v"]::view-transition-old(pane){animation:.18s var(--ease) both vt-out,.3s var(--ease-soft) both vt-page-to-top}
html[data-motion="next-v"]::view-transition-new(pane){animation:.26s var(--ease) both vt-in,.3s var(--ease-soft) both vt-page-from-bottom}
html[data-motion="prev-v"]::view-transition-old(pane){animation:.18s var(--ease) both vt-out,.3s var(--ease-soft) both vt-page-to-bottom}
html[data-motion="prev-v"]::view-transition-new(pane){animation:.26s var(--ease) both vt-in,.3s var(--ease-soft) both vt-page-from-top}
@keyframes vt-page-to-top{to{transform:translateY(max(-22%,-150px))}}@keyframes vt-page-from-bottom{from{transform:translateY(min(22%,150px))}}@keyframes vt-page-to-bottom{to{transform:translateY(min(22%,150px))}}@keyframes vt-page-from-top{from{transform:translateY(max(-22%,-150px))}}
html:is([data-motion="next-v"],[data-motion="prev-v"]) #tabbar{view-transition-name:tabbar}html:is([data-motion="next-v"],[data-motion="prev-v"]) #fab{view-transition-name:fab}html:is([data-motion="next-v"],[data-motion="prev-v"]) #paintbar{view-transition-name:paintbar}
