/* База: reset, каркас, таб-бар, форма шита. Логики нет — только вид. */

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

html, body { height: 100%; }

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  -webkit-font-smoothing: antialiased;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Часы и любые числа — моноширинными цифрами (ТЗ, раздел 8). */
.tabular-nums { font-variant-numeric: tabular-nums; }

/* Контент — узкая колонка по центру; на десктопе ничего не «адаптируется». */
#view {
  max-width: 480px;
  min-height: 100%;
  margin: 0 auto;
  padding: 16px 16px calc(72px + env(safe-area-inset-bottom));
}

.panel { display: grid; gap: 16px; }

/* ── Таб-бар ─────────────────────────────────────────────────────────── */

.tabbar {
  position: fixed;
  inset: auto 0 0 0;
  display: flex;
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border-top: 1px solid var(--glass-border);
}

.tabbar button {
  flex: 1;
  min-height: 44px; /* тап-зона ≥ 44 px (ТЗ, раздел 10.11) */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 8px 0;
  color: var(--fg-dim);
  transition: color 150ms var(--ease);
}

.tabbar button.is-active { color: var(--fg); }
.tabbar svg { width: 24px; height: 24px; }
.tabbar span { font-size: 11px; }

/* ── Нижний шит (форма; подъём и логика — в sheet.js) ────────────────── */

.sheet {
  position: fixed;
  inset: auto 0 0 0;
  padding: 8px 16px calc(16px + env(safe-area-inset-bottom));
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  border-bottom: 0;
  border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  transform: translateY(100%);
  transition: transform var(--dur-sheet) var(--ease);
}

.sheet.is-open { transform: none; }

.sheet__handle {
  width: 40px;
  height: 4px;
  margin: 0 auto 12px;
  border-radius: var(--r-pill);
  background: var(--glass-border);
}

/* Волны и наклон глушим — движение остаётся только там, где оно несёт смысл. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ── Колба (ТЗ, раздел 7) ─────────────────────────────────────────────── */

/* Сетка «Сегодня» (design-today.md): кластер 16 + шкала 44 + 6 + капсула 136 + поле сносок.
   Капсула скользит по двум позициям (.flask--place-*, вешает flask.js; класс позиции панели
   .today--place-* вешает today.js — от него зависит полоса окошка и места «+»); часы и дата —
   в верхней полосе справа (.today__head), возврат дня — там же слева (.daybar).
   Аура (.flask::before) растекается за края и расширяет документ; clip режет её, не
   создавая скролл-контейнер, поэтому вертикальные тени капсулы целы. */
.today {
  --edge: max(16px, calc(50vw - 224px));
  /* Ширина кластера колбы (286 / 256 при <390). Боковая полоса — остаток колонки против неё:
     по ней встают окошко и «+» (design-final, b). */
  --col-flask: 286px;
  /* Резерв под вертикаль (design-final, a): центрирование колбы требует нижнего зазора
     (Z − fh)/2 ≥ 28 ⇒ fh ≤ 100dvh − 160 − env, отсюда 160. env() обязателен: без него на
     телефоне с индикатором возвращается вертикальный скролл. */
  --reserve: calc(160px + env(safe-area-inset-bottom, 0px));
  /* Колба центрирована в зоне Z (между верхней полосой и таб-баром): 44 + (Z − fh)/2 =
     72 + (100dvh − reserve − fh)/2. Обе переменные стоят тут, а не на .flask: своя
     декларация там перекрыла бы наследование. */
  --flask-h: min(74vh, calc(100vh - var(--reserve)));
  --flask-top: calc(72px + (100vh - var(--reserve) - var(--flask-h)) / 2);
  position: relative;
  overflow-x: clip;
}
@supports (height: 100dvh) {
  .today {
    --flask-h: min(74dvh, calc(100dvh - var(--reserve)));
    --flask-top: calc(72px + (100dvh - var(--reserve) - var(--flask-h)) / 2);
  }
}

/* Верхняя полоса справа: короткая дата (только прошлый день) и часы. z-index — над аурой:
   при позиции «право» она заходит в эту полосу (design-layout, «Сверка» п.3). */
.today__head {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 1;
  width: 66px;
  display: grid;
  /* Колонка ровно в ширину зоны: auto-колонка раздувалась бы по max-content и вынесла
     часы за экран. */
  grid-template-columns: minmax(0, 1fr);
  gap: 2px;
  justify-items: end;
  text-align: right;
}
.today__date { font-size: 12px; color: var(--fg-dim); font-variant-numeric: tabular-nums; }
.today__date[hidden] { display: none; }
.today__clock {
  font-size: 22px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}

/* Окошко дневной статистики (ТЗ, 4.1): в боковой полосе напротив колбы (вне потока).
   Верх — середина верхней зоны ⅔ полосы: --flask-top + fh/12 + 22, то есть ниже верха
   колбы на ≥ 22 px при любом fh (design-final, b). Высота fh/2 − 44, как в #5; список
   занятий прокручивается внутри, габарит держится. z-index — над аурой: её «юбка»
   заходит на верх окошка. */
.today__stats {
  position: absolute;
  z-index: 1;
  top: calc(var(--flask-top) + var(--flask-h) / 12 + 22px);
  left: var(--col-flask);
  right: 0;
  height: calc(var(--flask-h) / 2 - 44px);
  display: grid;
  /* Строка списка — в остатке высоты: minmax(0, 1fr), иначе грид-трек не даст ей сжаться
     и вместо внутренней прокрутки окошко вырастет. */
  grid-template-rows: auto minmax(0, 1fr);
  gap: 4px;
  padding: 8px 4px; /* полоса 72: контент 62 = 72 − 2·4 − 2·1 (рамка) */
  border-radius: var(--r-card);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
}
.today--place-right .today__stats { left: 0; right: var(--col-flask); }
/* Заголовок — две строки в весе лейбла сноски (12/500/--fg, R5): число, ниже «из 24 ч»
   или «не учтено X». Вторая строка занимает всю ширину и переносится, не режется. */
.today__stats-head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 2px 0;
  font-size: 12px;
  line-height: 1;
  font-weight: 500;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.today__stats-dim { flex-basis: 100%; color: var(--fg); white-space: normal; }
/* Разделитель « · » — псевдоэлемент: в полосе он не нужен (число и вторая строка и так
   врозь), а текстовым узлом его из разметки не спрятать. */
.today__stats-dim::before { content: ' · '; }
.today--place-left .today__stats-dim::before,
.today--place-right .today__stats-dim::before { content: ''; }
.today__stats-list { display: grid; gap: 2px; align-content: start; overflow-y: auto; }

/* Строка занятия: три яруса 12/6/12 (имя, тянущаяся полоса, время) и gap 4 — 38 px,
   питч с gap 2 списка — 40. Имя и время — 12/500/--fg, как лейбл сноски (R5); полоса
   тянется на весь контент 62. */
.dayrow {
  display: grid;
  grid-template-rows: 12px 6px 12px;
  gap: 4px;
  height: 38px;
  font-size: 12px;
  line-height: 1; /* строка 12 px = ярус: иначе line box 14.4 режет низ глифов */
  font-weight: 500;
  color: var(--fg);
}
.dayrow__name {
  min-width: 0;
  text-transform: lowercase;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.dayrow__bar {
  width: 100%;
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--glass-hi);
  overflow: hidden;
}
.dayrow__fill { height: 100%; border-radius: inherit; min-width: 4px; }
.dayrow__ms {
  color: var(--fg);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-align: right;
}

.flask {
  /* --tt-tilt (угол тела жидкости) и --tt-shift (смещение блика) пишет src/tilt.js на общем
     предке: и большая колба, и 31 мини-колба наследуют их. Своей декларации здесь нет —
     она перекрыла бы значение с предка. Ровная колба без датчиков — фолбэк в var(). */
  --flask-pivot: 50%;   /* точка поворота — середина залитого диапазона; пишет flask.js */
  --flask-w: 136px;     /* ширина капсулы: по ней считаются бокс и маска ауры (design-glow, 1) */
  --glow-x: 48px;       /* горизонталь ауры: симметрично в обе стороны от стенок капсулы */
  --glow-y: 64px;       /* нижний вылет ауры — «юбка»: из неё выводятся стопы масок и pos()/хвост */
  --capsule-x: 50px;    /* левый край .flask → левая стенка капсулы: шкала 44 + зазор 6 */
  /* --flask-top и --flask-h ставит раскладка «Сегодня» (.today), мини-колбам они не нужны:
     своя декларация здесь перекрыла бы их наследование. */
  position: relative;
  display: flex;
  align-items: stretch;
  gap: 6px; /* зазор шкала ↔ капсула */
  /* Ширина до правого края поля сносок: 44 + 6 + 136 + 100 (design-today.md). */
  width: 286px;
  height: var(--flask-h);
  margin-top: var(--flask-top, 0px);
}

/* Аура: колба подсвечивает комнату цветом каждого своего уровня (ТЗ, 8). Стопы слоёв
   собирает flask.js в --flask-levels. Бокс расходится от стенок капсулы на --glow-x/-y, а
   сверху — на 16px + --flask-top: при любом смещении колбы он достаёт ровно до y = 0. Гаснет
   свечение по двум маскам в пересечении: по горизонтали и по вертикали нормированным профилем
   «тело + хвост» — непрозрачно у стенок капсулы, к краям бокса сходит на нет. Полосы над
   капсулой и под ней красит крайний слой (flask.js), так что свечение в них есть, а неучтённое
   время внутри капсулы остаётся прозрачным. Без blur и цветного box-shadow: 35 мини-колб
   грели бы телефон. */
.flask::before {
  content: "";
  position: absolute;
  z-index: 0;
  pointer-events: none;
  top: calc(-16px - var(--flask-top, 0px));
  bottom: calc(0px - var(--glow-y));
  left: calc(var(--capsule-x, 50px) - var(--glow-x));
  width: calc(var(--flask-w) + 2 * var(--glow-x));
  right: auto;
  background: var(--flask-levels, none);
  /* intersect (он же -webkit-source-in), а не сложение: в углах бокса, где одна маска
     гасит, а другая нет, свечения быть не должно. Стопы обеих масок — в долях
     --glow-x/--glow-y от стенок капсулы; шапка maskV — косинус над S = min(24px,
     16px + --flask-top). Те же --flask-w/--glow-x/
     --glow-y/--flask-h/--flask-top живут в pos() и хвосте flask.js (доли .85/.65/.40/
     .15/.05 · --glow-y): правишь --glow-y — маски, стопы и бокс едут вместе. */
  -webkit-mask-image:
    linear-gradient(90deg, transparent 0, rgba(0, 0, 0, .038) calc(.125 * var(--glow-x)), rgba(0, 0, 0, .146) calc(.25 * var(--glow-x)), rgba(0, 0, 0, .309) calc(.375 * var(--glow-x)), rgba(0, 0, 0, .5) calc(.5 * var(--glow-x)), rgba(0, 0, 0, .691) calc(.625 * var(--glow-x)), rgba(0, 0, 0, .854) calc(.75 * var(--glow-x)), rgba(0, 0, 0, .962) calc(.875 * var(--glow-x)), #000 var(--glow-x), #000 calc(var(--glow-x) + var(--flask-w)), rgba(0, 0, 0, .962) calc(var(--glow-x) + var(--flask-w) + .125 * var(--glow-x)), rgba(0, 0, 0, .854) calc(var(--glow-x) + var(--flask-w) + .25 * var(--glow-x)), rgba(0, 0, 0, .691) calc(var(--glow-x) + var(--flask-w) + .375 * var(--glow-x)), rgba(0, 0, 0, .5) calc(var(--glow-x) + var(--flask-w) + .5 * var(--glow-x)), rgba(0, 0, 0, .309) calc(var(--glow-x) + var(--flask-w) + .625 * var(--glow-x)), rgba(0, 0, 0, .146) calc(var(--glow-x) + var(--flask-w) + .75 * var(--glow-x)), rgba(0, 0, 0, .038) calc(var(--glow-x) + var(--flask-w) + .875 * var(--glow-x)), transparent 100%),
    linear-gradient(to top, transparent 0, rgba(0, 0, 0, .038) calc(.125 * var(--glow-y)), rgba(0, 0, 0, .146) calc(.25 * var(--glow-y)), rgba(0, 0, 0, .309) calc(.375 * var(--glow-y)), rgba(0, 0, 0, .5) calc(.5 * var(--glow-y)), rgba(0, 0, 0, .691) calc(.625 * var(--glow-y)), rgba(0, 0, 0, .854) calc(.75 * var(--glow-y)), rgba(0, 0, 0, .962) calc(.875 * var(--glow-y)), #000 var(--glow-y), #000 calc(var(--flask-h) + var(--glow-y)), #000 calc(100% - min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .962) calc(100% - .875 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .854) calc(100% - .75 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .691) calc(100% - .625 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .5) calc(100% - .5 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .309) calc(100% - .375 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .146) calc(100% - .25 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .038) calc(100% - .125 * min(24px, 16px + var(--flask-top, 0px))), transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(90deg, transparent 0, rgba(0, 0, 0, .038) calc(.125 * var(--glow-x)), rgba(0, 0, 0, .146) calc(.25 * var(--glow-x)), rgba(0, 0, 0, .309) calc(.375 * var(--glow-x)), rgba(0, 0, 0, .5) calc(.5 * var(--glow-x)), rgba(0, 0, 0, .691) calc(.625 * var(--glow-x)), rgba(0, 0, 0, .854) calc(.75 * var(--glow-x)), rgba(0, 0, 0, .962) calc(.875 * var(--glow-x)), #000 var(--glow-x), #000 calc(var(--glow-x) + var(--flask-w)), rgba(0, 0, 0, .962) calc(var(--glow-x) + var(--flask-w) + .125 * var(--glow-x)), rgba(0, 0, 0, .854) calc(var(--glow-x) + var(--flask-w) + .25 * var(--glow-x)), rgba(0, 0, 0, .691) calc(var(--glow-x) + var(--flask-w) + .375 * var(--glow-x)), rgba(0, 0, 0, .5) calc(var(--glow-x) + var(--flask-w) + .5 * var(--glow-x)), rgba(0, 0, 0, .309) calc(var(--glow-x) + var(--flask-w) + .625 * var(--glow-x)), rgba(0, 0, 0, .146) calc(var(--glow-x) + var(--flask-w) + .75 * var(--glow-x)), rgba(0, 0, 0, .038) calc(var(--glow-x) + var(--flask-w) + .875 * var(--glow-x)), transparent 100%),
    linear-gradient(to top, transparent 0, rgba(0, 0, 0, .038) calc(.125 * var(--glow-y)), rgba(0, 0, 0, .146) calc(.25 * var(--glow-y)), rgba(0, 0, 0, .309) calc(.375 * var(--glow-y)), rgba(0, 0, 0, .5) calc(.5 * var(--glow-y)), rgba(0, 0, 0, .691) calc(.625 * var(--glow-y)), rgba(0, 0, 0, .854) calc(.75 * var(--glow-y)), rgba(0, 0, 0, .962) calc(.875 * var(--glow-y)), #000 var(--glow-y), #000 calc(var(--flask-h) + var(--glow-y)), #000 calc(100% - min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .962) calc(100% - .875 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .854) calc(100% - .75 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .691) calc(100% - .625 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .5) calc(100% - .5 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .309) calc(100% - .375 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .146) calc(100% - .25 * min(24px, 16px + var(--flask-top, 0px))), rgba(0, 0, 0, .038) calc(100% - .125 * min(24px, 16px + var(--flask-top, 0px))), transparent 100%);
  mask-composite: intersect;
  opacity: var(--glow-op);
  transition: opacity var(--dur-layer) var(--ease);
}
.flask--mini::before { display: none; }

/* Шкала 0–24ч слева. Не уже 44 px: колба и шкала согласованы по массе (ТЗ, 7). */
.flask__scale {
  position: relative;
  width: 44px;
  flex: none;
  font-size: 10px;
  color: var(--fg-dim);
}
.flask__tick {
  position: absolute;
  right: 0;
  width: 6px;
  height: 1px;
  background: currentColor;
  opacity: .3;
}
.flask__tick.is-label { width: 11px; opacity: .6; }
.flask__tick.is-label::after {
  content: attr(data-label);
  position: absolute;
  right: 15px;
  top: 50%;
  transform: translateY(-50%);
  font-variant-numeric: tabular-nums;
}

/* Маркер реального времени на шкале: полоска с подписью часов устройства, а не точка
   (ТЗ, 7). Переход линейный и секундный: с var(--ease) маркер отставал бы от тика. */
.flask__marker {
  position: absolute;
  right: 0;
  transform: translateY(50%);
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 1px 6px;
  border-radius: var(--r-pill);
  background: var(--bg); /* непрозрачный: цифра подписи часа просвечивала сквозь пилюлю */
  border: 1px solid var(--glass-border);
  color: var(--fg);
  font-size: 10px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  transition: bottom 1s linear;
  pointer-events: none;
}
.flask__marker::before {
  content: "";
  width: 12px;
  height: 2px;
  border-radius: var(--r-pill);
  background: var(--fg);
}
.flask__marker[hidden] { display: none; }

/* ── Сноски названий (ТЗ, 4.1; геометрия — design-today.md) ──────────── */

/* Поле сносок: справа от капсулы, во всю высоту колбы. Смещение — 44 (шкала) + 6 + 136.
   Клики пропускает: тапается только табличка (ТЗ, 10.11). */
.flask__notes {
  position: absolute;
  top: 0;
  left: 186px;
  width: 100px;
  height: 100%;
  pointer-events: none;
}
/* Линия из вертикальной середины слоя к табличке; угол и длина — из flask.js. */
.flask__leader {
  position: absolute;
  left: 0;
  height: 1px;
  background: var(--fg-dim);
  transform-origin: 0 50%;
}
/* Табличка = кнопка правки занятия: слот 82×44, от левой стенки поля на 18 px (проекция
   линии). Кнопка — прозрачный flex-контейнер: тап-зона 44 и шаг 46 те же, вид ушёл в пилюлю. */
.flask__note {
  position: absolute;
  left: 18px;
  width: 82px;
  height: 44px;
  padding: 0;
  display: flex;
  align-items: center;
  background: none;
  border: 0;
  pointer-events: auto;
}
/* Видимая пилюля — 32 в слоте 44 (margin 6px 0: 32 коробки + 12 полей = 44 ровно): 12 текста +
   7 сверху / 11 снизу. Коробка 32, а не 30: план считал без двух рамок 1 px. Асимметрия паддингов
   и есть оптический центр: при line-height 1 глифы Segoe UI массой сидят в строке ниже её
   геометрической середины, поэтому центроид чернил ложится на центр пилюли при сплите 7/11
   (замер пиксельной пробой по контентному боксу: 7/11 → Δ −0,8 px, 6/12 → −1,8, 9/9 → +1,2,
   порог M1 — 1). Сплит делегирован implementer'у (CURRENT, п.3). Ширина по содержимому
   (max-content), но не шире слота: длинное имя режет ellipsis, короткое даёт узкую пилюлю.
   Центр текста держит text-align: у flex-контейнера нет строчного содержимого и text-overflow
   не рисует многоточие, а align-content работает лишь с Chromium 123 / Safari 17.4. Строчные —
   только вид: aria-label и шит хранят исходное имя. */
.flask__note-name {
  display: block;
  width: max-content;
  max-width: 100%;
  margin: 6px 0;
  padding: 7px 12px 11px;
  border-radius: var(--r-pill);
  background: var(--glass); /* фолбэк: на iOS 15 без color-mix пилюля осталась бы без фона */
  background: color-mix(in oklab, var(--bg) 85%, transparent);
  border: 1px solid var(--glass-border);
  color: var(--fg);
  font-size: 12px;
  font-weight: 500;
  line-height: 1;
  text-align: center;
  text-transform: lowercase;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ── Позиция колбы (ТЗ, 7; design-layout п.1) ───────────────────────────
   Класс вешает flask.js по state.settings.flaskPlace. Скользит только кластер колбы: часы и
   дата не двигаются ни в одной позиции; окошко и «+» меняют сторону по классу .today--place-*
   (его вешает today.js). «Лево» — правило не нужно (margin-left по умолчанию 0). */
/* «Право»: поле сносок уходит за ЛЕВУЮ стенку капсулы (табличка 0–82, линия 82–100), но текст
   читается слева направо, и линия крепится к левой стенке капсулы (origin 100% 50%, угол —
   flask.js). Шкала — зеркало левой: order: 1 ставит её за капсулу, в свободную полосу справа
   (330–374 на 390 px), риски у её левой стенки, подпись — справа от риски, у маркера текст
   перед чертой (row-reverse). Пилюля прижата к правому краю слота (margin-left: auto):
   ближний к линии край неподвижен, рост — наружу, к левой стенке капсулы.
   --capsule-x = ширина поля сносок: свечение едет за капсулой (--glow-x симметричен). */
.flask--place-right { --capsule-x: 100px; margin-left: calc(100% - 286px); }
.flask--place-right .flask__capsule { margin-left: var(--capsule-x); }
.flask--place-right .flask__scale { order: 1; }
.flask--place-right .flask__tick { left: 0; right: auto; }
.flask--place-right .flask__tick.is-label::after { left: 15px; right: auto; }
.flask--place-right .flask__marker { left: 0; right: auto; flex-direction: row-reverse; }
.flask--place-right .flask__note-name { margin-left: auto; }
.flask--place-right .flask__notes { left: 0; width: var(--capsule-x); }
.flask--place-right .flask__note { left: 0; }
.flask--place-right .flask__leader { left: auto; right: 0; transform-origin: 100% 50%; }

/* Вьюпорт < 390: сетка 16+44+6+136+18+52+6+66+16 ужимается только в табличке сноски —
   82 → 52 — и тогда сходится ровно в 360 (design-today.md). Шкалу, капсулу, часы и отступы
   не трогаем: минус 30 px взяты у подписи, у неё всё равно ellipsis. */
@media (max-width: 389px) {
  .today { --col-flask: 256px; }  /* боковая полоса та же — 72 px */
  .flask { width: 256px; }        /* 44 + 6 + 136 + 70 (поле сносок) */
  .flask__notes { width: 70px; }  /* линия 18 + табличка 52 */
  .flask__note { width: 52px; }
  /* «Право»: поле сносок — 70, по нему же встают капсула и свечение (design-layout, 360). */
  .flask--place-right { --capsule-x: 70px; margin-left: calc(100% - 256px); }
}

/* Капсула: стенка из двух бликов поверх стекла, торец сверху, тёмное дно и внешняя
   тень вниз — без этого пустая зона читается плоским чёрным овалом. Здесь — 36 px и
   фолбэк мини-колбы; у большой профиль задаёт форма (три блока ниже). Не --r-pill:
   «999px» давало эффект «яйцо рядом с линейкой» (ТЗ, 7). */
.flask__capsule {
  position: relative;
  z-index: 1; /* поверх ауры .flask::before */
  width: var(--flask-w);
  flex: none;
  height: 100%;
  overflow: hidden;
  border-radius: 36px;
  border: 1px solid var(--glass-border);
  background-color: var(--glass);
  background-image:
    linear-gradient(100deg, rgba(255, 255, 255, .10) 0 14%, transparent 28%),
    linear-gradient(255deg, rgba(255, 255, 255, .05) 0 7%, transparent 18%);
  box-shadow:
    inset calc(3px + var(--tt-shift, 0px)) 0 18px -8px rgba(255, 255, 255, .55),
    inset 0 1px 0 rgba(255, 255, 255, .16),
    inset 0 -26px 34px -26px rgba(0, 0, 0, .6),
    0 26px 60px -24px rgba(0, 0, 0, .7);
}

/* Форма большой колбы (ТЗ, 7; таблица — design-glow §4): одна «Мягкая» —
   .flask--shape-soft. Прежние drop/pebble удалены (заказчик 2026-10-17), нормализатор
   state.js гасит их старые значения в soft. Габарит 136 × --flask-h не меняется. */
.flask--shape-soft .flask__capsule {
  border-radius: 48px 48px 41px 41px;
  background-image:
    linear-gradient(104deg, rgba(255, 255, 255, .10) 0 16%, transparent 32%),
    linear-gradient(256deg, rgba(255, 255, 255, .05) 0 9%, transparent 22%);
  box-shadow:
    inset calc(4px + var(--tt-shift, 0px)) 0 22px -9px rgba(255, 255, 255, .55),
    inset 0 1px 0 rgba(255, 255, 255, .14),
    inset 0 -30px 38px -28px rgba(0, 0, 0, .6),
    0 26px 60px -24px rgba(0, 0, 0, .7);
}

/* Поворотный контейнер: наклон крутит тело жидкости целиком (ТЗ, 7) — и слои, и
   поверхность. Оверсайз — худший случай F·sin 6° ≈ 0.105·F (F = --flask-h, pivot не по
   центру): адаптивно, а не литералом из 624 px — высота колбы теперь произвольная (min()).
   Иначе у стенок капсулы от поворота вылезал бы клин фона (капсула с overflow: hidden
   режет — это легально, дыр внутри быть не должно). Угол пишет src/tilt.js одной переменной
   на предке, точку поворота — flask.js (середина залитого диапазона). Мини оверсайзится
   своей высотой 104 px и pivot'ом ровно по центру — там хватает половинного случая (±6 px). */
.flask__body {
  position: absolute;
  inset: 0 calc(-1 * var(--flask-h, 624px) * 0.105);
  transform: rotate(var(--tt-tilt, 0deg));
  transform-origin: 50% var(--flask-pivot, 50%);
}

.flask__layers { position: absolute; inset: 0; }

/* Затемнение — одно на весь столб жидкости (ТЗ, 7): от 00:00 темнее, к верху и левому
   верхнему углу светлее. Маска — те же стопы занятий (--flask-levels), поэтому дыры
   (их transparent-стопы) остаются пустыми, а светлая кромка слоёв не затирается:
   поперёк неё α оверлея меняется на доли процента. Чёрный — корректен в обе темы. */
.flask:not(.flask--mini) .flask__layers::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none; /* тап должен доставаться слоям под оверлеем */
  background:
    linear-gradient(to top, rgba(0, 0, 0, .34), rgba(0, 0, 0, .16) 45%, rgba(0, 0, 0, .06) 100%),
    linear-gradient(to bottom right, transparent 45%, rgba(0, 0, 0, .12) 100%);
  -webkit-mask-image: var(--flask-levels, none);
  /* Маска оверлея — в координатах бокса ауры, а не собственного бокса: иначе стопы уровней
     поднимались бы на 64 px и затемнение съезжало бы с границ слоёв (design-glow, 3). */
  -webkit-mask-size: 100% calc(var(--flask-h) + 16px + var(--glow-y) + var(--flask-top, 0px));
  -webkit-mask-position: 0 calc(100% + var(--glow-y));
  -webkit-mask-repeat: no-repeat;
  mask-image: var(--flask-levels, none);
  mask-size: 100% calc(var(--flask-h) + 16px + var(--glow-y) + var(--flask-top, 0px));
  mask-position: 0 calc(100% + var(--glow-y));
  mask-repeat: no-repeat;
}
.flask.is-empty .flask__layers::after { display: none; } /* пустому столбу затемнять нечего */

.flask__layer,
.flask__hole {
  position: absolute;
  left: 0;
  right: 0;
}

/* Слой жидкости: цвет приходит переменной --liq, вид целиком здесь (ТЗ, 7, 8).
   Слой ровный, без собственного градиента: затемнение одно на весь столб
   (.flask__layers::after), по-layer градиент наложился бы на него дважды. Белой кромки
   между слоями нет (заказчик 2026-10-16): 1 px полоска поверх цвета читалась швом, а не
   жидкостью. Откат — border-top 1px rgba(255,255,255,.25) + inset 0 1px 0 rgba(255,255,255,.28). */
.flask__layer {
  background-color: var(--liq, #94A3B8);
  /* откат: залить этот блок — слой снова растёт вверх */
  /* transition: height var(--dur-layer) var(--ease), bottom var(--dur-layer) var(--ease); */
}

/* Заливка сверху: новый слой проявляется от кромки вниз (класс вешает flask.js по образцу
   splash). clip-path на одном слое, не в сетке мини-колб — производительность (ТЗ, 10.12). */
.flask__layer.is-fill { animation: flask-fill 600ms var(--ease); }
@keyframes flask-fill {
  from { clip-path: inset(0 0 100% 0); }
  to { clip-path: inset(0); }
}

/* Поверхность-мениск: почти белая кромка → цветной переход → прозрачно вниз, плюс
   свечение цветом верхнего слоя (--liq пишет flask.js). translateY(100%) ставит верх
   кромки на верх заливки; scaleX(1.6) — волна из двух эллипсов. Поворот — не здесь,
   его несёт .flask__body: собственный rotate дал бы двойной угол (ТЗ, 7). */
.flask__surface {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 11px;
  border-radius: 50%;
  /* Фолбэк без color-mix: мениск не должен исчезать там, где его нет. */
  background: linear-gradient(180deg, rgba(255, 255, 255, .95), var(--liq, #94A3B8) 40%, transparent);
  background: linear-gradient(180deg,
    rgba(255, 255, 255, .95),
    color-mix(in oklab, var(--liq, #94A3B8) 65%, white) 40%,
    transparent);
  filter: drop-shadow(0 0 7px color-mix(in oklab, var(--liq, #94A3B8) 75%, transparent));
  /* Сдвиг на свою высоту: верх кромки совпадает с верхом последнего слоя, а не висит над ним. */
  transform: translateY(100%) scaleX(1.6);
  transform-origin: 50% 100%;
  transition: bottom var(--dur-layer) var(--ease);
  pointer-events: none; /* тап должен доставаться слою под поверхностью */
}
.flask__surface[hidden] { display: none; }
/* Колба, залитая до 24:00: мениска нет — он висел бы полоской 11 px у самой крышки капсулы
   и «трясся» бы от наклона без смысла (ТЗ, 7). Класс вешает flask.js по верх заливки. */
.flask.is-full .flask__surface { display: none; }

.flask__surface::before,
.flask__surface::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  width: 110%;
  height: 5px;
  border-radius: 50%;
  background: color-mix(in oklab, var(--liq, #94A3B8) 45%, white);
  transform: translateX(-50%);
  animation: flask-wave 3.6s var(--ease) infinite;
}
.flask__surface::after { animation-duration: 4.4s; animation-direction: reverse; opacity: .55; }

@keyframes flask-wave {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50% { transform: translateX(-50%) translateY(-2px); }
}

.flask__surface.is-splash { animation: flask-splash 1.2s var(--ease); }
/* translateY(100%) — тот же сдвиг мениска на кромку: keyframes перезаписывают transform целиком. */
@keyframes flask-splash {
  0% { transform: translateY(100%) scaleX(1.6) translateY(0); }
  35% { transform: translateY(100%) scaleX(1.6) translateY(-6px); }
  100% { transform: translateY(100%) scaleX(1.6) translateY(0); }
}

/* ── «+» и пилюля «не учтено» (ТЗ, раздел 4.1) ───────────────────────── */

/* «+» — центр нижней зоны ⅓ полосы (design-final, b): 2fh/3 + fh/6 = 5fh/6 от верха
   колбы. translateY(-50 %) держит центр и у круга, и у выросшей пилюли. При хвосте > 1 ч
   тот же узел превращается в пилюлю «не учтено X»: тап → шит заполнения, а не создания. */
.fab {
  position: absolute;
  /* Центр нижней зоны ⅓: сдвиг колбы от верха панели (--flask-top) + 5/6 её высоты.
     top у absolute — от верха .today; translateY(-50 %) ставит центр на это значение. */
  top: calc(var(--flask-top) + var(--flask-h) * 5 / 6);
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: var(--glass);
  backdrop-filter: var(--glass-blur);
  -webkit-backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-border);
  color: var(--fg);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .35);
  transition: transform 150ms var(--ease);
}
.today--place-left .fab { left: calc(50% + var(--col-flask) / 2 - 28px); }
.today--place-right .fab { left: calc(50% - var(--col-flask) / 2 - 28px); }
.fab:active { transform: translateY(-50%) scale(.97); }
.fab svg { width: 26px; height: 26px; }
/* Пилюля: ширина = боковая полоса (лево/право). */
.fab.is-tail {
  left: var(--col-flask);
  right: 0;
  width: auto;
  height: auto;
  min-height: 44px;
  padding: 6px 8px;
  font-size: 11px;
  line-height: 1.2;
  text-align: center;
}
.today--place-right .fab.is-tail { left: 0; right: var(--col-flask); }

/* Шапка прошлого дня: только возврат «Сегодня», в верхней полосе слева. */
.daybar {
  position: fixed;
  top: 16px;
  left: var(--edge);
  z-index: 1; /* выше ауры колбы */
  display: flex;
  min-height: 44px;
}
.daybar[hidden] { display: none; }
.daybar__back {
  min-height: 44px;
  padding: 0 16px;
  border-radius: var(--r-pill);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  color: var(--fg);
  transition: transform 150ms var(--ease);
}
.daybar__back:active { transform: scale(.97); }

/* ── Нижний шит и шит «Занятие» (ТЗ, 4.5, 8) ─────────────────────────── */

.flask__hole { cursor: pointer; }

.scrim {
  position: fixed;
  inset: 0;
  z-index: 1;
  background: rgba(0, 0, 0, .5);
  opacity: 0;
  transition: opacity var(--dur-sheet) var(--ease);
}
.scrim.is-open { opacity: 1; }

.sheet { z-index: 2; max-width: 480px; margin-inline: auto; max-height: 88vh; overflow-y: auto; }

.sheet__title { margin-bottom: 12px; font-size: 17px; font-weight: 600; }
.sheet__body { display: grid; gap: 12px; }

.sheet__name,
.sheet__note,
.times__input {
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  border-radius: var(--r-card);
  background: rgba(255, 255, 255, .06);
  border: 1px solid var(--glass-border);
  color: var(--fg);
  font: inherit;
}
.sheet__name { font-size: 16px; }
.sheet__name::placeholder { color: var(--fg-dim); }
.times__input:disabled { opacity: .7; }

/* Чипы пресетов: 2–3 ряда с переносом и вертикальной прокруткой. Горизонтальная
   лента прятала часть пресетов за краем; 148 px = три ряда по 44 px (ТЗ, 4.5). */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-height: 148px;
  overflow-y: auto;
  padding-bottom: 2px;
}
.chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  border-radius: var(--r-pill);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  color: var(--fg);
  white-space: nowrap;
}
.chip__dot { width: 10px; height: 10px; border-radius: 50%; background: var(--chip, var(--liq-12)); }
.chip--new { justify-self: start; }
.chip--new[hidden] { display: none; }

.palette { display: flex; flex-wrap: wrap; gap: 8px; }
.palette__dot {
  width: 44px;
  height: 44px;
  padding: 6px;
  background-clip: content-box;
  border-radius: 50%;
  border: 2px solid transparent;
}
.palette__dot.is-active { border-color: var(--fg); }

.times { display: flex; gap: 12px; }
.times__field { display: grid; gap: 4px; font-size: 12px; color: var(--fg-dim); }

.sheet__caption { font-size: 13px; color: var(--fg-dim); }
.sheet__error { font-size: 13px; color: var(--liq-4); }
.sheet__error[hidden] { display: none; }

.btn {
  min-height: 48px;
  padding: 0 16px;
  border-radius: var(--r-card); /* ≤ 24 px: --r-pill на короткой надписи читался «яйцом» */
  font: inherit;
  font-weight: 600;
  transition: transform 150ms var(--ease);
}
.btn:active { transform: scale(.97); }
.btn--primary { background: var(--liq-1); color: #fff; }
.btn--danger { border: 1px solid var(--glass-border); color: var(--liq-4); }

/* ── Настройки (ТЗ, 4.4) ─────────────────────────────────────────────── */

.settings__title { font-size: 20px; font-weight: 600; }
.settings__row { display: grid; gap: 8px; }

.settings__control {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 44px; /* тап-зона ≥ 44 px (ТЗ, 10.11) */
}
.settings__label { font-size: 15px; }
.settings__hint { font-size: 13px; line-height: 1.4; color: var(--fg-dim); }
.settings__hint[hidden] { display: none; }
.settings__hint.is-error { color: var(--liq-4); }

.settings__file { display: none; }
.settings__actions { display: flex; gap: 12px; }
.settings__actions .btn { flex: 1; }

.btn--ghost { border: 1px solid var(--glass-border); }

/* Переключатель: галочку рисуем сами, доступность остаётся нативной. */
.switch {
  flex: none;
  position: relative;
  width: 48px;
  height: 28px;
  appearance: none;
  -webkit-appearance: none;
  border-radius: var(--r-pill);
  background: var(--glass-hi);
  border: 1px solid var(--glass-border);
  transition: background 150ms var(--ease);
}
.switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--fg);
  transition: transform 150ms var(--ease);
}
.switch:checked { background: var(--liq-1); border-color: var(--liq-1); }
.switch:checked::after { transform: translateX(20px); background: #fff; }
.switch:disabled { opacity: .5; }

/* ── Пресеты (ТЗ, 4.3) ────────────────────────────────────────────────── */

.presets__head { display: flex; align-items: center; justify-content: space-between; }
.presets__title { font-size: 20px; font-weight: 600; }

.presets__add {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  color: var(--fg);
  transition: transform 150ms var(--ease);
}
.presets__add:active { transform: scale(.97); }
.presets__add svg { width: 22px; height: 22px; }

.presets { display: grid; gap: 8px; }

.preset {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px; /* тап-зона ≥ 44 px (ТЗ, раздел 10.11) */
  padding: 6px 12px 6px 2px;
  border-radius: var(--r-card);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  text-align: left;
  transition: transform 150ms var(--ease);
}
.preset:active { transform: scale(.97); }

/* Жест с ручки принадлежит перетаскиванию, а не прокрутке списка. */
.drag-handle {
  flex: none;
  width: 40px;
  min-height: 44px;
  display: grid;
  place-items: center;
  color: var(--fg-dim);
  touch-action: none;
  cursor: grab;
}
.drag-handle svg { width: 20px; height: 20px; }

.preset__dot { flex: none; width: 12px; height: 12px; border-radius: 50%; }
.preset__text { display: grid; gap: 2px; min-width: 0; }
.preset__name { font-size: 16px; }
.preset__note {
  font-size: 12px;
  color: var(--fg-dim);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Строка едет за пальцем через transform, поэтому переход на время перетаскивания
   выключен — иначе она догоняла бы палец с задержкой. Поднята над соседями. */
.preset.is-dragging {
  position: relative;
  z-index: 5;
  transition: none;
  box-shadow: 0 12px 28px rgba(0, 0, 0, .35);
  will-change: transform;
}

.presets__empty { display: grid; gap: 12px; justify-items: start; }
.presets__hint { font-size: 14px; line-height: 1.45; color: var(--fg-dim); }

/* ── Статистика (ТЗ, 4.2) ─────────────────────────────────────────────── */

/* Мини-колба: тот же рендер, размер задаём самой колбе явно. В клетке с
   justify-items: center она иначе схлопнулась бы по содержимому в линию.
   Вытянутая (ТЗ, 4.2): 30 мин обязаны читаться полосой, а не волосяной линией. */
.flask--mini { display: block; width: 28px; height: 104px; margin-inline: auto; }
/* Без свечения вокруг: 35 размытий радиусом 56 px — это то, что греет телефон. */
.flask--mini .flask__capsule {
  width: 100%;
  box-shadow: inset 2px 0 8px -4px rgba(255, 255, 255, .45);
}
/* Слой в 104 px: 30 мин = 2.2 px. Дотягиваем до 3 px ради читаемости — искажение
   пропорции осознанное и только здесь: в большой колбе шкала 0–24 обязана сходиться. */
.flask--mini .flask__layer { min-height: 3px; }
/* Грань-мениск в мини-колбе не рисуется вовсе — вместе со своим drop-shadow: в клетке
   28 px она читалась полосой, а 31 тень грела телефон. Наклон границ занятия остаётся:
   он от поворотного контейнера, а не от поверхности. */
.flask--mini .flask__surface { display: none; }
/* Оверсайз контейнера мини под наклон: sin 6° × 104 ≈ 11 px (±6) — клина фона в клетке нет. */
.flask--mini .flask__body { inset: 0 -6px; }

.stats__seg {
  display: flex;
  gap: 4px;
  padding: 4px;
  border-radius: var(--r-pill);
  background: var(--glass);
  border: 1px solid var(--glass-border);
}
.stats__seg-btn {
  flex: 1;
  min-height: 44px; /* тап-зона ≥ 44 px (ТЗ, раздел 10.11) */
  border-radius: var(--r-pill);
  font-size: 14px;
  color: var(--fg-dim);
  transition: background 150ms var(--ease), color 150ms var(--ease);
}
.stats__seg-btn.is-active { background: var(--glass-hi); color: var(--fg); }

.stats__nav { display: flex; align-items: center; gap: 8px; }
.stats__period { flex: 1; text-align: center; font-size: 15px; }

.stats__arrow,
.stats__today {
  min-height: 44px;
  border-radius: var(--r-pill);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  color: var(--fg);
  transition: transform 150ms var(--ease);
}
.stats__arrow { width: 44px; display: grid; place-items: center; }
.stats__arrow svg { width: 20px; height: 20px; }
.stats__today { padding: 0 14px; font-size: 13px; }
.stats__arrow:active,
.stats__today:active { transform: scale(.97); }

.stats__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }

.stats__cell {
  display: grid;
  gap: 4px;
  justify-items: center;
  min-height: 44px;
  padding: 0;
  color: inherit;
  transition: transform 150ms var(--ease);
}
.stats__cell:disabled { opacity: .3; } /* будущее: видно масштаб, открывать нечего */
.stats__cell:not(:disabled):active { transform: scale(.97); }
.stats__cell.is-today .flask__capsule { border-color: var(--fg-dim); }

.stats__caption {
  font-size: 10px;
  color: var(--fg-dim);
  font-variant-numeric: tabular-nums;
}
.stats__cell.is-today .stats__caption { color: var(--fg); font-weight: 600; }

.stats__totals { display: grid; gap: 12px; }
.stats__empty { font-size: 14px; color: var(--fg-dim); }

.total { display: grid; gap: 6px; }
.total__head { display: flex; justify-content: space-between; gap: 8px; font-size: 14px; }
.total__ms { color: var(--fg-dim); font-variant-numeric: tabular-nums; }
.total__bar {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--glass-hi);
  overflow: hidden;
}
/* Дорожка — общий масштаб: полоса в долю самой длинной строки, а не от нуля шкалы. */
.total__fill { height: 100%; border-radius: inherit; min-width: 4px; }

