:root {
  /* светлая тема — значения по умолчанию; ночные лежат ниже, слоем --night-* */
  color-scheme: light;

  --ground: #e9e5f1;
  --paper: #faf9fd;
  --ink: #221b2e;
  --muted: #6b6379;
  --thread: #c6bfd8;
  --berry: #a5325c;
  --sage: #5c8171;
  /* Ирис — маркер добавок в ленте дня. Ягодный, шалфейный и охристый уже
     заняты едой, активностью и фокусом, а пятый тип событий обязан читаться
     с одного взгляда; фиолетовый взят из той же семьи, что фон и чернила. */
  --iris: #5f4b8b;

  /* Зоны стресса — проверены на контраст и различимость при дальтонизме */
  --stress-low: #2b8a63;
  --stress-mid: #a8730c;
  --stress-high: #a5325c;

  /*
    Заливка полей ввода. Отдельный токен, а не «белый»: в светлой теме поле
    белее бумаги карточки и читается как пустое место, куда можно писать,
    а в тёмной этот же смысл даёт углубление — цвет темнее бумаги. Один
    захардкоженный #fff в трёх местах файла обеих логик не выдерживал.
  */
  --field: #ffffff;

  /*
    Чернила теней и затемнений. В светлой теме совпадают с --ink, и раньше
    тени брали прямо его. Но в тёмной --ink светлеет до почти белого, и тень
    под окном превратилась бы в свечение, а подложка модалки — в белую вуаль.
    Поэтому «тёмное ради темноты» вынесено в свой токен и остаётся тёмным
    всегда. Обводки и подсветки, которым положено светлеть вместе с текстом
    (кольцо «сегодня», пунктир цели, бледный столбик текущего дня), как
    брали --ink, так и берут.
  */
  --shade: #221b2e;

  --display: 'Bricolage Grotesque', 'Trebuchet MS', sans-serif;
  --body: 'IBM Plex Sans', system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, monospace;

  --gap: 20px;
  --radius: 14px;
}

/* ==================================================================== */
/* Тёмная тема                                                          */
/* ==================================================================== */

/*
  Три режима: системная (по умолчанию), светлая, тёмная. Выбор лежит в
  localStorage под ключом lifeos.theme, а на страницу приезжает атрибутом
  data-theme на <html> — его ставит инлайн-скрипт в шапке layouts/base
  ещё до этого файла, поэтому светлым при открытии не мигает. Нет
  атрибута — значит системная.

  Отсюда и два включателя ниже: явный выбор ловится селектором по атрибуту,
  системный — медиазапросом. Значения при этом записаны ОДИН раз, слоем
  --night-*: оба включателя только переклеивают на него рабочие токены и
  ни одного цвета в себе не держат. Разъехаться светлому с тёмным негде.

  Палитра — та же семья, что днём: фон не чёрный, а глубокий чернильно-
  фиолетовый, бумага карточек чуть светлее фона, чернила — тёплый светлый
  серый с лиловым подтоном. Акценты те же по тону, но осветлены и слегка
  приглушены: на тёмном дневные #a5325c и #5c8171 читались бы как пятна.
  Контраст основного текста к бумаге — 13,6:1, приглушённой подписи — 5,7:1,
  акцентов — от 5,8:1 (WCAG AA берётся с запасом).
*/

:root {
  --night-ground: #181326;
  --night-paper: #221b33;
  --night-ink: #ece7f2;
  --night-muted: #9d94ad;
  --night-thread: #453a5c;
  --night-berry: #e07b9e;
  --night-sage: #7fb99e;
  --night-iris: #a794d8;

  --night-stress-low: #4fbf8d;
  --night-stress-mid: #d9a13c;
  /* высокий стресс и ягодный совпадают — как и днём */
  --night-stress-high: #e07b9e;

  /* поле ввода — углубление в бумаге, а не белый лист */
  --night-field: #1c1630;
  /* тени ночью почти чёрные: на тёмной бумаге разбавленные не читаются */
  --night-shade: #05030d;
}

/* Выбрана тёмная. */
html[data-theme='dark'] {
  color-scheme: dark;

  --ground: var(--night-ground);
  --paper: var(--night-paper);
  --ink: var(--night-ink);
  --muted: var(--night-muted);
  --thread: var(--night-thread);
  --berry: var(--night-berry);
  --sage: var(--night-sage);
  --iris: var(--night-iris);
  --stress-low: var(--night-stress-low);
  --stress-mid: var(--night-stress-mid);
  --stress-high: var(--night-stress-high);
  --field: var(--night-field);
  --shade: var(--night-shade);
}

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

  Список тот же, что выше, слово в слово — иначе и нельзя: медиазапрос
  оборачивает правило целиком, в один селектор с атрибутным его не
  соберёшь. Но повторяются здесь только имена; цвета лежат в --night-*
  и правятся в одном месте.
*/
@media (prefers-color-scheme: dark) {
  html:not([data-theme='light']) {
    color-scheme: dark;

    --ground: var(--night-ground);
    --paper: var(--night-paper);
    --ink: var(--night-ink);
    --muted: var(--night-muted);
    --thread: var(--night-thread);
    --berry: var(--night-berry);
    --sage: var(--night-sage);
    --iris: var(--night-iris);
    --stress-low: var(--night-stress-low);
    --stress-mid: var(--night-stress-mid);
    --stress-high: var(--night-stress-high);
    --field: var(--night-field);
    --shade: var(--night-shade);
  }
}

* { box-sizing: border-box; }

body {
  margin: 0;
  padding: clamp(20px, 4vw, 48px);
  background: var(--ground);
  color: var(--ink);
  font-family: var(--body);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

main { max-width: 1080px; margin: 0 auto; }

h1, h2 { font-family: var(--display); font-weight: 600; margin: 0; letter-spacing: -0.02em; }

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 6px;
}

/* ---------------- Верхнее меню ---------------- */

.nav { max-width: 1080px; margin: 0 auto 26px; }

/* «таблетка» на бумажном фоне — та же форма, что у кнопок */
.nav__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  width: fit-content;
  max-width: 100%;
  background: var(--paper);
  border-radius: 999px;
  padding: 5px;
}
.nav__link {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  padding: 9px 16px;
  border-radius: 999px;
}
.nav__link:hover { color: var(--ink); }
/* текущий раздел — тёмная таблетка, как у .button--solid */
.nav__link[aria-current='page'] { background: var(--ink); color: var(--paper); }

/* ---------------- Экран подключения ---------------- */

.gate { min-height: 70vh; display: grid; place-items: center; }
.gate[hidden] { display: none; }
.gate__inner { max-width: 520px; }
.gate__title { font-size: clamp(30px, 5vw, 46px); line-height: 1.08; margin-bottom: 18px; }
.gate__text { color: var(--muted); margin: 0 0 26px; }

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

.head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--gap);
  flex-wrap: wrap;
  margin-bottom: 28px;
}
.head__title { font-size: clamp(34px, 6vw, 54px); line-height: 1; }
.head__date { font-family: var(--mono); font-size: 12px; color: var(--muted); margin: 8px 0 0; }

/* ---------------- Метрики ---------------- */

.metrics {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--gap);
  margin-bottom: var(--gap);
}
.metric { background: var(--paper); border-radius: var(--radius); padding: 18px 20px 20px; }
/* составное значение (съедено / сожжено) просит больше места — занимает две колонки */
.metric--wide { grid-column: span 2; }
.metric__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 10px;
}
.metric__value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(26px, 3.4vw, 34px);
  margin: 0;
  font-variant-numeric: tabular-nums;
}
.metric__unit { font-size: 13px; font-weight: 400; color: var(--muted); margin-left: 5px; white-space: nowrap; }
.metric__note { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 8px 0 0; }

/* ---------------- Стресс ---------------- */

.card--stress { margin-bottom: var(--gap); }

.stress__meta { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.stress__hint { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 0; }

.stress__now { display: inline-flex; align-items: baseline; gap: 9px; margin: 0; }
.stress__swatch {
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--thread);
  align-self: center;
  flex: none;
}
.stress__swatch[data-zone='low'] { background: var(--stress-low); }
.stress__swatch[data-zone='mid'] { background: var(--stress-mid); }
.stress__swatch[data-zone='high'] { background: var(--stress-high); }

.stress__value { font-family: var(--mono); font-weight: 600; font-size: 32px; line-height: 1; }
.stress__word { font-size: 13px; color: var(--muted); }

.stress { margin: 0; }
.stress__plot { position: relative; }
/* pan-y — сделка с браузером: вертикаль его (страница прокручивается прямо
   с графика), горизонталь наша — палец ведёт подсказку (scrub в public/ui.js) */
.stress__svg { display: block; width: 100%; touch-action: pan-y; }
.stress__svg text { font-family: var(--mono); font-size: 10px; fill: var(--muted); }

.stress__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
  /* поля совпадают с PLOT.left / PLOT.right из app.js — иначе часы уедут */
  margin: 6px 10px 0 28px;
}

.stress__key { display: flex; gap: 16px; flex-wrap: wrap; margin: 14px 0 0; font-size: 12px; color: var(--muted); }
.stress__legend { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 11px; }
.stress__legend i { width: 8px; height: 8px; border-radius: 2px; background: var(--thread); }
.stress__legend[data-zone='low'] i { background: var(--stress-low); }
.stress__legend[data-zone='mid'] i { background: var(--stress-mid); }
.stress__legend[data-zone='high'] i { background: var(--stress-high); }

/* Подсказка при наведении — общая для графиков стресса и MRR */
.stress__tip, .mrr__tip {
  position: absolute;
  top: 0;
  transform: translate(-50%, -4px);
  pointer-events: none;
  background: var(--ink);
  color: var(--paper);
  border-radius: 9px;
  padding: 7px 10px;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.45;
  white-space: nowrap;
  z-index: 2;
}
.stress__tip b, .mrr__tip b { font-weight: 600; }
.stress__tip span, .mrr__tip span { color: color-mix(in srgb, var(--paper) 62%, transparent); }

/* Таблица — тот же набор чисел, что и на графике */
.stress__table { margin-top: 16px; }
.stress__data { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 13px; }
.stress__data th, .stress__data td {
  text-align: left;
  padding: 6px 8px 6px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.stress__data th {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 400;
  border-top: 0;
}
.stress__data td:first-child, .stress__data td:nth-child(2) {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

/* ---------------- Карточки ---------------- */

.card { background: var(--paper); border-radius: var(--radius); padding: 22px 24px; }
.card__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.card__title { font-size: 19px; }
.card__sum { font-family: var(--mono); font-weight: 600; font-size: 17px; margin: 0; color: var(--berry); }

.sub { color: var(--muted); font-size: 13px; margin: 6px 0 0; }
.empty { color: var(--muted); font-size: 14px; margin: 4px 0 0; }

/* ---------------- Таймлайн дня ---------------- */

.tl { list-style: none; margin: 0; padding: 0; }

/* время слева, лента справа: «нить» дня — это левая граница .tl__body */
.tl__item { display: grid; grid-template-columns: 46px 1fr; gap: 12px; }
.tl__time {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  padding-top: 2px;
}
.tl__body {
  position: relative;
  border-left: 1px solid color-mix(in srgb, var(--thread) 55%, transparent);
  padding: 0 0 18px 16px;
}
/* последнее событие ленту дальше не тянет */
.tl__item:last-child .tl__body { border-left-color: transparent; padding-bottom: 0; }

.tl__dot {
  position: absolute;
  left: -4px;
  top: 3px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--thread);
}
/* маркеры типов — цвета только из палитры проекта */
.tl__item[data-type='meal'] .tl__dot { background: var(--berry); }
.tl__item[data-type='activity'] .tl__dot { background: var(--sage); }
.tl__item[data-type='focus'] .tl__dot { background: var(--stress-mid); }
.tl__item[data-type='sleep'] .tl__dot { background: var(--muted); }
.tl__item[data-type='supplement'] .tl__dot { background: var(--iris); }

.tl__kind {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 3px;
}
.tl__title { margin: 0; }
.tl__detail { font-size: 13px; color: var(--muted); margin: 3px 0 0; }

/* Форма добавления еды */

.add { margin-top: 18px; border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent); padding-top: 14px; }
.add__toggle { cursor: pointer; font-family: var(--mono); font-size: 12px; color: var(--berry); }
.add__form { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 16px; }

/* Сосудистые детали внутри формы еды: насыщенные, транс-жиры, добавленный
   сахар и холестерин. Свёрнуты по той же причине, что и состав у добавок:
   заполняют их по этикетке и далеко не каждый раз, а четыре лишних поля
   в каждой форме превратили бы быструю запись в анкету. Растягиваются на
   всю ширину сетки — иначе ссылка встала бы третьей колонкой к полям. */
.vasc { grid-column: 1 / -1; }
.vasc__toggle { cursor: pointer; font-family: var(--mono); font-size: 11px; color: var(--berry); }
.vasc__rows { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 12px; }
.field { display: grid; gap: 5px; }
.field--wide { grid-column: span 2; }
.field span { font-family: var(--mono); font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.field input, .field select {
  font-family: var(--body);
  font-size: 14px;
  padding: 9px 11px;
  border: 1px solid var(--thread);
  border-radius: 9px;
  background: var(--field);
  color: var(--ink);
}
.form-note { grid-column: 1 / -1; margin: 0; font-size: 13px; color: var(--muted); }

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

/* прирост к прошлому месяцу: рост — травяной, спад — ягодный */
.metric__delta { font-weight: 600; color: var(--muted); }
.metric__delta[data-dir='up'] { color: var(--sage); }
.metric__delta[data-dir='down'] { color: var(--berry); }

.card--mrr, .card--src { margin-bottom: var(--gap); }

.mrr__meta { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.mrr__hint { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 0; }

.mrr { margin: 0; }
.mrr__plot { position: relative; }
/* про touch-action: pan-y — у .stress__svg */
.mrr__svg { display: block; width: 100%; touch-action: pan-y; }
.mrr__svg text { font-family: var(--mono); font-size: 10px; fill: var(--muted); }
/* текущий месяц выделен: он ещё идёт */
.mrr__svg text.is-now { fill: var(--ink); font-weight: 600; }
.mrr__key { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 12px 0 0; }

/* Составная полоса: доли всех источников в общем MRR */
.split { display: flex; gap: 3px; height: 10px; margin: 2px 0 8px; }
.split span { display: block; height: 100%; min-width: 4px; border-radius: 999px; background: var(--thread); }

/* Список источников */
.src { list-style: none; margin: 0; padding: 0; }
.src__item {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 7px 14px;
  padding: 14px 0 16px;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.src__item:first-child { border-top: 0; }

.src__name { margin: 0; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.src__title { font-weight: 600; }
.src__note { font-size: 12px; color: var(--muted); }

.src__money { margin: 0; display: flex; align-items: baseline; justify-content: flex-end; gap: 8px; }
.src__sum { font-family: var(--mono); font-weight: 600; font-size: 17px; font-variant-numeric: tabular-nums; }
.src__delta { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.src__delta[data-dir='up'] { color: var(--sage); }
.src__delta[data-dir='down'] { color: var(--berry); }

.src__bar {
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--thread) 40%, transparent);
  overflow: hidden;
}
.src__bar i { display: block; height: 100%; border-radius: 999px; background: var(--thread); }
.src__share { margin: 0; font-family: var(--mono); font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* цвета долей — те же, что у маркеров таймлайна */
.src__item[data-tone='berry'] .src__bar i, .split span[data-tone='berry'] { background: var(--berry); }
.src__item[data-tone='sage'] .src__bar i, .split span[data-tone='sage'] { background: var(--sage); }
.src__item[data-tone='amber'] .src__bar i, .split span[data-tone='amber'] { background: var(--stress-mid); }
.src__item[data-tone='quiet'] .src__bar i, .split span[data-tone='quiet'] { background: var(--muted); }

/* Управление источниками: список, загрузка выгрузки, форма нового источника.
   Карточка серверная и видна всегда — в том числе на пустой базе, иначе
   первому файлу неоткуда было бы взяться. */
.card--srcs { margin-bottom: var(--gap); }

/* сообщение после отправки формы: сводка импорта или «источник добавлен» */
.flash {
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
  background: color-mix(in srgb, var(--thread) 28%, transparent);
  border-radius: 10px;
  padding: 10px 14px;
  margin: 0 0 14px;
}
.flash--ok { color: var(--ink); background: color-mix(in srgb, var(--sage) 16%, transparent); }

/*
  Подтверждение быстрой записи (partials/quick-add.blade.php). Окно к этому
  моменту закрыто, а страница под ним — любая: вставить строку в её поток
  некуда, поэтому она висит поверх у верхнего края и гаснет сама через
  четыре секунды. Слой 35 — выше самих окон (30): показывается она уже
  после закрытия, но и перекрывать её нечему.
*/
.flash--toast {
  position: fixed;
  top: calc(12px + env(safe-area-inset-top, 0px));
  /* центр берём автополями, а не translateX: появление и уход у флешей
     анимируют transform, и центровка на нём уехала бы вместе с ними */
  left: 0;
  right: 0;
  z-index: 35;
  width: max-content;
  max-width: calc(100% - 32px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
  margin: 0 auto;
  background: var(--paper);
  box-shadow: 0 10px 28px color-mix(in srgb, var(--shade) 20%, transparent);
}
.flash--toast.flash--ok { background: color-mix(in srgb, var(--sage) 22%, var(--paper)); }
.flash--toast[hidden] { display: none; }

.srcs { list-style: none; margin: 0; padding: 0; }
.srcs__item {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: start;
  gap: 14px 18px;
  padding: 16px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.srcs__item:first-child { border-top: 0; }

.srcs__meta { min-width: 0; }
.srcs__name { margin: 0; font-weight: 600; }
.srcs__note { margin: 4px 0 0; font-family: var(--mono); font-size: 11px; color: var(--muted); }

.srcs__mrr { margin: 0; display: grid; gap: 2px; justify-items: end; text-align: right; }
.srcs__sum { font-family: var(--mono); font-weight: 600; font-size: 17px; font-variant-numeric: tabular-nums; }
.srcs__unit {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.srcs__upload, .srcs__new { display: flex; align-items: end; gap: 12px; flex-wrap: wrap; }
.srcs__upload { grid-column: 1 / -1; }
.srcs__upload .field, .srcs__new .field { min-width: min(260px, 100%); }
.srcs__new {
  margin-top: 6px;
  padding-top: 18px;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.srcs__new .errors { flex-basis: 100%; margin: 0; }

/* Переименовать и удалить: две обычные формы в одну строку под загрузкой файла.
   Полем подтверждения удаление отличается от остальных действий не только
   цветом кнопки — вписать название придётся руками. */
.srcs__tools {
  grid-column: 1 / -1;
  display: flex;
  gap: 12px 26px;
  flex-wrap: wrap;
  align-items: end;
}
.srcs__tool { display: flex; align-items: end; gap: 12px; flex-wrap: wrap; }
.srcs__tool .field { min-width: min(220px, 100%); }
/* ошибка стоит у своего источника, а не в общей шапке карточки */
.srcs__error { grid-column: 1 / -1; margin: 0; }

.srcs__empty { font-size: 14px; color: var(--muted); padding: 2px 0 10px; }
.srcs__hint { margin: 18px 0 0; font-size: 12px; line-height: 1.6; color: var(--muted); }

/* выбор файла: кнопку браузера приводим к тёмной таблетке проекта */
.field input[type='file'] { padding: 7px 10px; font-family: var(--mono); font-size: 12px; }
.field input[type='file']::file-selector-button {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-right: 10px;
  padding: 7px 13px;
  border-radius: 999px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
}

/* ---------------- Фокус ---------------- */

.card--timer { margin-bottom: var(--gap); text-align: center; }
.card--today { margin-bottom: var(--gap); }
.card--all { margin-bottom: var(--gap); }

/* итоги за всё время: те же мини-плитки, что в «Питании», только их три */
.card--all .mini { grid-template-columns: repeat(3, 1fr); margin-bottom: 12px; }
/* «1 205 ч» и «14 дней подряд» не разрываем: число и подпись читаются вместе */
.card--all .mini__value { white-space: nowrap; }

/* переключатель режимов — та же таблетка, что и меню, только вывернутая:
   на бумажной карточке дорожка окрашена фоном страницы */
.timer__modes {
  display: inline-flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 4px;
  max-width: 100%;
  background: var(--ground);
  border-radius: 999px;
  padding: 6px;
}
.timer__mode {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  background: transparent;
  border: 0;
  border-radius: 999px;
  /* по ширине таблетка и на узком десктопе (561px) не упирается в края
     карточки, а вот по высоте буквы стояли впритык к скруглению — воздух
     добавлен там, где он ничего не ломает */
  padding: 11px 16px;
  white-space: nowrap;
  cursor: pointer;
}
.timer__mode:hover { color: var(--ink); }
.timer__mode[aria-pressed='true'] { background: var(--ink); color: var(--paper); }

.timer__round {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 24px 0 0;
}

/* главное число страницы — крупнее заголовка раздела */
.timer__clock {
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(56px, 15vw, 116px);
  line-height: 1;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  margin: 4px 0 0;
}

.timer__track {
  height: 5px;
  max-width: 320px;
  margin: 20px auto 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--thread) 40%, transparent);
  overflow: hidden;
}
.timer__track i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--berry);
  transition: width 0.25s linear;
}
/* перерыв — шалфейный: режим виден и без подписи.
   Имена режимов те же, что в API таймера: focus / short_break / long_break */
.card--timer[data-mode='short_break'] .timer__track i,
.card--timer[data-mode='long_break'] .timer__track i { background: var(--sage); }

.timer__controls { display: flex; justify-content: center; gap: 10px; flex-wrap: wrap; margin-top: 22px; }
.timer__start { min-width: 148px; font-weight: 600; }
.timer__skip { font-size: 12px; padding: 7px 12px; margin-top: 8px; }

.timer__hint { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 16px 0 0; }

/* Тег сессии — на месте бывшего поля «над чем работаю»: та же узкая колонка
   под таймером, отделённая нитью. Внутри — капсулы выбора и форма нового тега. */
.timer__tags {
  max-width: 460px;
  margin: 26px auto 0;
  text-align: left;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
  padding-top: 20px;
}
/* перерыв не тегируется: блок гаснет, но кликам не мешает —
   выбрать тег для следующего фокуса посреди перерыва вполне нормально */
.timer__tags[data-off='yes'] { opacity: 0.45; }

.timer__tags-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 9px;
}

/* капсулы тегов — та же таблетка, что у переключателя режимов, только с обводкой:
   это выбор, а не навигация. На узком экране просто переносятся */
.tagpick { display: flex; flex-wrap: wrap; gap: 6px; }
.tagpick__item {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--thread);
  border-radius: 999px;
  padding: 7px 13px;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.tagpick__item:hover { color: var(--ink); border-color: var(--ink); }
.tagpick__item[aria-pressed='true'] { background: var(--ink); border-color: var(--ink); color: var(--paper); }

/* форма нового тега: поле и кнопка в одну строку, поле тянется */
.tagnew { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.tagnew__input {
  flex: 1 1 170px;
  min-width: 0;
  font-family: var(--body);
  font-size: 14px;
  padding: 9px 11px;
  border: 1px solid var(--thread);
  border-radius: 9px;
  background: var(--field);
  color: var(--ink);
}
.tagnew__add { font-size: 13px; padding: 9px 16px; white-space: nowrap; }

.timer__tags-note { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 11px 0 0; }
.timer__tags-error { font-family: var(--mono); font-size: 11px; color: var(--berry); margin: 8px 0 0; }

/* Уведомления о завершении: тихая строка внизу карточки таймера — той же
   породы, что «отключить» у Google Health. Настройка, за которой ходят раз
   в жизни, не должна спорить со «Стартом» за внимание. */
.timer__push {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  margin: 14px 0 0;
}
.timer__push[hidden] { display: none; }
.timer__push-state[hidden] { display: none; }
.timer__push-act {
  font: inherit;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.timer__push-act:hover { color: var(--ink); }
/* пока браузер думает над разрешением, кнопка ждёт молча и не зовёт нажимать */
.timer__push-act[disabled] { opacity: 0.5; cursor: default; text-decoration: none; }
.timer__push-act[hidden] { display: none; }

/* Сегодня: по точке за каждую завершённую сессию */
.today__dots { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 0 12px; }
.today__dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--berry); }
.today__dots[hidden] { display: none; }

/* По тегам: строки-доли ровно того же устройства, что у источников дохода
   в «Финансах» — название слева, числа справа, полоса-доля под ними.
   Составная полоса сверху переиспользует .split из блока финансов. */
.card--tagrep { margin-bottom: var(--gap); }
.card--tagrep .split[hidden] { display: none; }

.tagrep { list-style: none; margin: 0; padding: 0; }
.tagrep__item {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-areas:
    'name share'
    'stats stats'
    'bar bar';
  align-items: center;
  gap: 10px 14px;
  padding: 14px 0 16px;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.tagrep__item:first-child { border-top: 0; }

/* имя тега пишет пользователь — длинное режем переносом, а не выездом за карточку */
.tagrep__name { grid-area: name; margin: 0; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }

/* четыре среза времени — отдельные мини-плитки на подложке (как БЖУ на «Здоровье»),
   иначе подписи и числа сливаются в одну строку и читаются слитно */
.tagrep__stats {
  grid-area: stats;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
}
.tagrep__cell {
  display: grid;
  gap: 4px;
  justify-items: start;
  background: var(--ground);
  border-radius: 10px;
  padding: 10px 12px;
}
.tagrep__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}
.tagrep__value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--muted);
}
/* «всего» — главное число строки, остальные три читаются как контекст */
.tagrep__cell--total .tagrep__value { font-size: 17px; color: var(--ink); }

.tagrep__bar {
  grid-area: bar;
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--thread) 40%, transparent);
  overflow: hidden;
}
.tagrep__bar i { display: block; height: 100%; border-radius: 999px; background: var(--thread); }
.tagrep__share { grid-area: share; margin: 0; font-family: var(--mono); font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* цвета долей — та же палитра, что у источников дохода и маркеров таймлайна */
.tagrep__item[data-tone='berry'] .tagrep__bar i { background: var(--berry); }
.tagrep__item[data-tone='sage'] .tagrep__bar i { background: var(--sage); }
.tagrep__item[data-tone='amber'] .tagrep__bar i { background: var(--stress-mid); }
.tagrep__item[data-tone='quiet'] .tagrep__bar i { background: var(--muted); }

@media (max-width: 560px) {
  /* на телефоне четыре плитки в ряд не встают — складываем в две колонки */
  .tagrep__stats { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .tagrep__value { font-size: 14px; }
  .tagrep__cell--total .tagrep__value { font-size: 15px; }

  /* форма тега: кнопка во всю ширину под полем, как в карточке источников */
  .timer__tags { margin-top: 22px; }
  .tagnew__add { width: 100%; }
}

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

.button {
  font-family: var(--body);
  font-size: 14px;
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
}
.button--solid { background: var(--ink); color: var(--paper); }
.button--quiet { border-color: transparent; color: var(--muted); }
/* разрушающее действие — ягодная кнопка: её не спутаешь с «Загрузить» рядом */
.button--danger { border-color: var(--berry); background: var(--berry); color: var(--paper); }
.button:hover { opacity: 0.86; }
:focus-visible { outline: 2px solid var(--berry); outline-offset: 3px; }

.foot { margin-top: 28px; }
.foot__row { display: flex; gap: 10px; flex-wrap: wrap; }
.errors {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--berry);
  background: color-mix(in srgb, var(--berry) 8%, transparent);
  border-radius: 10px;
  padding: 10px 14px;
  margin: 0 0 14px;
  white-space: pre-wrap;
}

/* ---------------- Адаптив ---------------- */

@media (max-width: 900px) {
  .metrics { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  /* меню сжимается, а если совсем узко — переносится на вторую строку внутри таблетки */
  .nav { margin-bottom: 20px; }
  /* пять разделов в ширину телефона не встают: таблетка не переносится
     на вторую строку, а прокручивается вбок — как вкладки в нативных
     приложениях; полосу прокрутки прячем, край подсказывает сам контент */
  .nav__inner {
    flex-wrap: nowrap;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    gap: 2px;
    padding: 4px;
  }
  .nav__inner::-webkit-scrollbar { display: none; }
  .nav__link { font-size: 10px; letter-spacing: 0.1em; padding: 8px 12px; }
  /* служебная пара уходит на свою строку и прижимается вправо, компактнее */
  .nav__side { margin-left: auto; }
  .nav__quit { font-size: 10px; letter-spacing: 0.1em; padding: 7px 12px; }

  .add__form { grid-template-columns: repeat(2, 1fr); }
  .field--wide { grid-column: span 2; }
  /* четыре сосудистых поля в ряд на телефоне не читаются — складываем по два */
  .vasc__rows { grid-template-columns: repeat(2, 1fr); }

  /* таймлайн: колонка времени уже, отступ ленты меньше — текст не сжимается в столбик */
  .tl__item { grid-template-columns: 38px 1fr; gap: 10px; }
  .tl__time { font-size: 10px; }
  .tl__body { padding: 0 0 16px 12px; }

  /* плитки сжимаются, чтобы длинные единицы не переносились на вторую строку */
  .metric { padding: 16px 16px 18px; }
  .metric__value { font-size: 24px; }
  .metric__unit { font-size: 12px; margin-left: 4px; }

  /* итог справа в шапке карточки не переносим — переносится заголовок слева */
  .card__sum { white-space: nowrap; }

  /* за всё время: в три колонки числа уже не помещаются, серия уходит на свою строку */
  .card--all .mini { grid-template-columns: repeat(2, 1fr); }
  .card--all .mini__cell:last-child { grid-column: span 2; }

  /* таблетка-переключатель вообще (её же берёт период в «Питании»): подписи
     мельче и разрядка уже — «Неделя» и «Месяц» должны влезать целиком */
  .timer__modes { gap: 2px; padding: 4px; }
  .timer__mode { font-size: 10px; letter-spacing: 0.1em; padding: 8px 12px; }

  /*
    Режимам таймера этого мало. «Короткий перерыв» и «Длинный перерыв» в
    inline-таблетку не вставали ни при какой разрядке: строка вылезала за
    скругление, а поля пришлось ужать до нечитаемых. Поэтому на телефоне
    переключатель разворачивается во всю ширину карточки тремя равными
    сегментами — ширина каждого известна заранее, подпись спокойно ложится
    в две строки («Короткий / перерыв», «Длинный / перерыв»), и внутри
    снова есть чем дышать. Смысл при этом целый: сокращать «перерыв» до
    одного слова не пришлось.

    Сегменты равны и по высоте (сетка тянет их до самого высокого), поэтому
    однострочный «Фокус» стоит по центру своей капсулы, а не выше соседей.
    Скругление 999px у дорожки и у сегмента даёт общий центр — зазор в 5px
    ровный по всему контуру.

    Классы и атрибуты кнопок не тронуты: focus.js ищет .timer__mode и
    читает data-mode, разметка ему та же самая.
  */
  .card--timer .timer__modes {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 3px;
    width: 100%;
    padding: 5px;
  }
  .card--timer .timer__mode {
    letter-spacing: 0.06em;
    line-height: 1.35;
    padding: 11px 6px;
    /* перенос — это и есть решение: слова длинные, колонка узкая */
    white-space: normal;
  }

  .timer__clock { font-size: clamp(52px, 16vw, 84px); }
  .timer__controls { margin-top: 20px; }
  .timer__start { min-width: 132px; }

  /* источники: описание уходит под название, суммы чуть мельче */
  .src__note { width: 100%; }
  .src__money { flex-wrap: wrap; gap: 2px 8px; }
  .src__sum { font-size: 15px; }

  /* карточка источников: MRR встаёт под название, формы — в одну колонку */
  .srcs__item { grid-template-columns: 1fr; }
  .srcs__mrr { justify-items: start; text-align: left; }
  .srcs__upload .button, .srcs__new .button { width: 100%; }
  /* переименование и удаление тоже встают в колонку, кнопки — во всю ширину */
  .srcs__tools { display: grid; gap: 14px; }
  .srcs__tool .button { width: 100%; }
}

/* ---------------- Здоровье ---------------- */

.card--hr, .card--sleep, .card--hours, .card--vo2, .card--food { margin-bottom: var(--gap); }

/* Состояние источника. Подключённый браслет — это норма, а не новость:
   строка тихая, как подпись, и рядом с ней маленькая кнопка отключения.
   Отсутствие подключения — наоборот, повод показать карточку с кнопкой. */
.card--conn { margin-bottom: var(--gap); }
.conn__act { margin: 16px 0 0; }

.conn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  margin: 0 0 var(--gap);
}
.conn__acts { display: flex; align-items: center; gap: 14px; }
.conn__quit {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.conn__quit:hover { color: var(--ink); }
/* синк — обычное действие, отключение — разрушающее. Одинаково тихими они
   читались как пара равных, и «синк сейчас» терялся рядом с «отключить»:
   основному действию отдаём полный цвет текста */
.conn__quit--go { color: var(--ink); }
/* пока синк идёт, кнопка ждёт молча: подчёркивание снимаем, чтобы не звала нажимать */
.conn__quit[disabled] { opacity: 0.5; cursor: default; text-decoration: none; }

/* причина неудачного синка: подпись под строкой состояния, а не тревога */
.conn__note {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  margin: -10px 0 var(--gap);
}
.conn__note[hidden] { display: none; }

/* разряженный браслет — единственное, о чём тихая строка состояния просит */
.conn__batt[data-low='yes'] { color: var(--berry); }

/* общие детали карточек раздела: заголовок с подписью, график, легенда */
.h__meta { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.h__hint { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 0; }
.h__key { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 12px 0 0; }

.h__figure { margin: 0; }
.h__figure[hidden] { display: none; }
.h__plot { position: relative; }
/* про touch-action: pan-y — у .stress__svg */
.h__svg { display: block; width: 100%; touch-action: pan-y; }
.h__svg text { font-family: var(--mono); font-size: 10px; fill: var(--muted); }

/* часы под кривой пульса: поля совпадают с PLOT.left / PLOT.right из health.js */
.h__scale {
  display: flex;
  justify-content: space-between;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
  margin: 6px 12px 0 32px;
}

/* подсказка при наведении — та же, что у графиков стресса и MRR */
.h__tip {
  position: absolute;
  top: 0;
  transform: translate(-50%, -4px);
  pointer-events: none;
  background: var(--ink);
  color: var(--paper);
  border-radius: 9px;
  padding: 7px 10px;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.45;
  white-space: nowrap;
  z-index: 2;
}
.h__tip b { font-weight: 600; }
.h__tip span { color: color-mix(in srgb, var(--paper) 62%, transparent); }

/* Пульс: сводка «сейчас / мин / макс» справа в шапке карточки */
.hr__stats { display: flex; gap: 20px; }
.hr__stat { display: grid; gap: 3px; margin: 0; text-align: right; }
.hr__stat-label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.hr__stat-value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 19px;
  font-variant-numeric: tabular-nums;
}
/* «сейчас» — главное число сводки, поэтому крупнее и акцентом */
.hr__stat:first-child .hr__stat-value { font-size: 26px; color: var(--berry); }

/* Сон: длительность крупно, подробности мелким моноширинным */
.sleep__lead { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin: 0 0 16px; }
.sleep__hours {
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(28px, 4vw, 36px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.sleep__note { font-family: var(--mono); font-size: 11px; color: var(--muted); }

/* составная полоса фаз и БЖУ — та же форма, что у долей дохода, только выше */
.split[hidden] { display: none; }
.split--tall { height: 14px; }
.split span[data-tone='thread'] { background: var(--thread); }

/* Легенда: фазы сна и доли БЖУ показываем одинаково */
.phases { list-style: none; margin: 14px 0 0; padding: 0; }
.phases__item {
  display: grid;
  grid-template-columns: 8px 1fr auto auto;
  align-items: center;
  gap: 12px;
  padding: 10px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.phases__item:first-child { border-top: 0; }
.phases__dot { width: 8px; height: 8px; border-radius: 2px; background: var(--thread); }
.phases__item[data-tone='berry'] .phases__dot { background: var(--berry); }
.phases__item[data-tone='sage'] .phases__dot { background: var(--sage); }
.phases__item[data-tone='amber'] .phases__dot { background: var(--stress-mid); }
.phases__item[data-tone='quiet'] .phases__dot { background: var(--muted); }
.phases__item[data-tone='thread'] .phases__dot { background: var(--thread); }

.phases__name { font-size: 14px; }
.phases__min { font-family: var(--mono); font-weight: 600; font-size: 14px; font-variant-numeric: tabular-nums; }
.phases__share {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 40px;
  text-align: right;
}

/* Шаги по часам: столбик на каждый час суток */
.bars { display: flex; align-items: flex-end; gap: 3px; height: 130px; margin: 4px 0 0; }
.bars__col { flex: 1 1 0; min-width: 0; height: 100%; display: flex; align-items: flex-end; }
.bars__col i {
  display: block;
  width: 100%;
  border-radius: 5px 5px 2px 2px;
  background: color-mix(in srgb, var(--berry) 45%, transparent);
}
/* самый активный час — насыщенный, чтобы пик читался сразу */
.bars__col[data-state='peak'] i { background: var(--berry); }
/* часы без шагов: сон и то, что ещё не наступило */
.bars__col[data-state='empty'] i { background: color-mix(in srgb, var(--thread) 60%, transparent); }

.bars__scale {
  display: flex;
  gap: 3px;
  margin: 6px 0 0;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
}
.bars__scale span { flex: 1 1 0; min-width: 0; text-align: center; }

/* VO2MAX: текущее значение крупно над кривой */
.vo2__now { display: flex; align-items: baseline; margin: 0 0 10px; }
.vo2__value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(34px, 5vw, 46px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

/* Питание: четыре мини-значения на фоне страницы внутри бумажной карточки */
.mini { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin: 0 0 18px; }
.mini__cell { display: grid; gap: 6px; margin: 0; background: var(--ground); border-radius: 10px; padding: 12px 14px; }
.mini__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.mini__value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 20px;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
  /* сводка пульса переносится под заголовок, если в строку уже не влезает */
  .card--hr .card__head { flex-wrap: wrap; }
  .hr__stats { gap: 14px; }
  .hr__stat-value { font-size: 17px; }
  .hr__stat:first-child .hr__stat-value { font-size: 22px; }

  /* столбики ниже и теснее — 24 часа должны помещаться в ширину экрана */
  .bars { height: 96px; gap: 2px; }
  .bars__scale { gap: 2px; font-size: 9px; }

  .phases__item { gap: 10px; padding: 9px 0; }
  .phases__name { font-size: 13px; }

  .mini { grid-template-columns: repeat(2, 1fr); gap: 10px; }
  .mini__value { font-size: 18px; }
}

/* ==================================================================== */
/* Life OS на Laravel: меню с выходом, лендинг и страница входа          */
/* ==================================================================== */

/* ---------------- Выход в верхнем меню ---------------- */

/* меню — слева, выход — справа; на узком экране просто переносится */
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.nav__exit { margin: 0; }

/* настройки и выход — служебная пара справа от таблетки разделов */
.nav__side { display: flex; align-items: center; gap: 8px; }
.nav__side .nav__quit[aria-current='page'] { color: var(--ink); border-color: var(--ink); }

/* та же таблетка, что у пунктов меню, но с обводкой — действие, а не раздел */
.nav__quit {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
  padding: 9px 16px;
  border: 1px solid var(--thread);
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  display: inline-block;
}
.nav__quit:hover { color: var(--ink); border-color: var(--ink); }

/* ---------------- Лендинг ---------------- */

.land { max-width: 760px; }

.land__hero { margin-bottom: 34px; }
.land__title {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -0.02em;
  font-size: clamp(38px, 7vw, 62px);
  line-height: 1;
  margin: 0 0 16px;
}
.land__lead {
  color: var(--muted);
  font-size: 17px;
  max-width: 46ch;
  margin: 0 0 26px;
}

.land__card { margin-bottom: var(--gap); }

.land__works {
  list-style: none;
  margin: 18px 0 0;
  padding: 0;
  display: grid;
  gap: 10px;
}
/* карточка в карточке: чуть темнее бумаги, чтобы читалась как отдельный блок */
.land__work {
  background: color-mix(in srgb, var(--ground) 55%, var(--paper));
  border-radius: 10px;
  padding: 14px 16px;
}
.land__work-name { margin: 0; font-weight: 600; }
.land__work-note {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--muted);
  margin: 4px 0 0;
}

.land__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 32px;
}
.land__foot-note {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

/* ---------------- Вход ---------------- */

.auth { min-height: 78vh; display: grid; place-items: center; }
.auth__card { width: min(400px, 100%); }
.auth__title { font-size: 30px; margin: 0 0 4px; }
.auth__sub { margin: 0 0 22px; }

.auth__form { display: grid; gap: 14px; }

.auth__remember {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  cursor: pointer;
}
.auth__remember input { accent-color: var(--ink); }

.auth__error { margin: 0; }
.auth__submit { justify-self: start; }

.auth__back { margin: 20px 0 0; font-size: 13px; }
.auth__back a { color: var(--muted); text-decoration: none; }
.auth__back a:hover { color: var(--ink); }

/* ==================================================================== */
/* Недели: семь столбиков и линия цели                                   */
/* ==================================================================== */

/* Один набор стилей на четыре карточки — сон, клетчатка и белок на
   «Здоровье», фокус на своей странице. Различаются они только данными:
   шкалу и подписи считает week.js, разметка и цвета здесь общие. */

.card--week { margin-bottom: var(--gap); }

/* «Клетчатка за неделю» с «1 из 6 дней ≥ 25» в строку помещается не всегда:
   пусть сводка уезжает под заголовок целиком, а не рвётся посреди «≥ 25» */
.card--week .card__head { flex-wrap: wrap; }
.card--week .card__sum { white-space: nowrap; margin-left: auto; }

.week {
  /* полоса справа под подпись цели: столбики в неё не заезжают,
     а сама линия тянется на всю ширину поля и уходит под подпись */
  --week-lane: 54px;
}
.week[hidden] { display: none; }

/* три ряда по одной сетке: числа, поле со столбиками, дни недели */
.week__scores,
.week__cols,
.week__days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  padding-right: var(--week-lane);
  text-align: center;
}

/* оценка стоит над своим столбиком: ряд общий, поэтому цифры выровнены */
.week__scores {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  margin: 4px 0 6px;
}
.week__score[data-state='hit'] { color: var(--sage); }
.week__score[data-today] { color: var(--ink); }

/* высота поля фиксированная: от неё health.js считает и столбики, и линию цели */
.week__plot { position: relative; height: 150px; }
.week__cols { height: 100%; }

.week__col { display: flex; align-items: flex-end; }
.week__col i {
  display: block;
  width: 100%;
  /* на широком экране семь столбиков иначе расплываются в плиты */
  max-width: 76px;
  margin: 0 auto;
  border-radius: 6px 6px 2px 2px;
  background: color-mix(in srgb, var(--berry) 45%, transparent);
}
/* цель взята — шалфейный, тот же цвет успеха, что у быстрого сна и VO2MAX */
.week__col[data-state='hit'] i { background: var(--sage); }
/* сегодняшний день обведён, как выделяют текущую точку остальные графики */
.week__col[data-today] i { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ink) 55%, transparent); }

/* День ещё идёт: клетчатка, белок и минуты фокуса копятся до вечера, поэтому
   к обеду столбик закономерно ниже цели. Такой день рисуется контурным и
   бледным — цифра неполная, сравнивать её с целью рано. Правила стоят после
   data-today: у сегодняшнего незавершённого дня выигрывает этот вид. */
.week__col[data-state='running'] i {
  background: color-mix(in srgb, var(--ink) 5%, transparent);
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ink) 26%, transparent);
}
.week__score[data-state='running'] { color: var(--muted); font-weight: 400; }

/* линия цели: пунктир поверх столбиков и подпись у правого края поля */
.week__goal {
  position: absolute;
  left: 0;
  right: 0;
  border-top: 1px dashed color-mix(in srgb, var(--ink) 45%, transparent);
  pointer-events: none;
}
.week__goal span {
  position: absolute;
  right: 0;
  top: -8px;
  padding: 0 4px;
  background: var(--paper);
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
}

.week__days {
  margin: 8px 0 0;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
}
.week__day[data-today] { color: var(--ink); font-weight: 600; }
/* вместо «вт» под незавершённым днём стоит «идёт» — тем же бледным тоном */
.week__day[data-running] { color: var(--muted); font-weight: 400; }

@media (max-width: 560px) {
  /* семь столбиков теснее и ниже — неделя должна помещаться в ширину экрана */
  .week { --week-lane: 44px; }
  .week__scores, .week__cols, .week__days { gap: 4px; }
  .week__scores { font-size: 12px; }
  .week__plot { height: 118px; }
  .week__days { font-size: 10px; }
  .week__goal span { font-size: 9px; }
}

/* ==================================================================== */
/* Год: тепловая карта в стиле GitHub                                    */
/* ==================================================================== */

/* Общий рисовальщик heatmap.js кладёт сюда «Сон за год» на «Здоровье» и
   «Фокус за год» на своей странице: пороги цвета у них разные, но сетка,
   палитра и разметка — общие, как у недельных шкал в week.js. */

.card--heatmap { margin-bottom: var(--gap); }
.card--heatmap .card__head { flex-wrap: wrap; }
.card--heatmap .card__sum { white-space: nowrap; margin-left: auto; }

.heatmap {
  /* Размер клетки и зазор — переменные: карта тянется во всю ширину карточки,
     и точные пиксели heatmap.js подставляет сюда инлайном, померив контейнер
     (см. fit() и ResizeObserver там же). Значения ниже — исходные, до первой
     отрисовки и на случай, если скрипт не доехал: та же плотность, что была
     у карты раньше. */
  --hm-cell: 11px;
  --hm-gap: 3px;
}
.heatmap[hidden] { display: none; }

/* на узком экране 53 недели не помещаются в карточку — карта крутится сама,
   а не ломает вёрстку; heatmap.js при загрузке прижимает прокрутку к сегодня */
.heatmap__scroll { overflow-x: auto; padding-bottom: 2px; }

.heatmap__inner {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 6px;
}

/* подписи месяцев сверху: своя сетка колонок, но той же ширины, что у поля —
   тогда «янв», «фев» встают точно над первой неделей своего месяца */
.heatmap__months {
  grid-column: 2;
  grid-row: 1;
  display: grid;
  grid-template-columns: repeat(var(--hm-cols, 53), var(--hm-cell));
  gap: var(--hm-gap);
  height: 14px;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
  text-transform: lowercase;
}
.heatmap__months span { grid-row: 1; white-space: nowrap; }

/* дни недели слева: подписаны только пн, ср и пт — как в GitHub */
.heatmap__weekdays {
  grid-column: 1;
  grid-row: 2;
  display: grid;
  grid-template-rows: repeat(7, var(--hm-cell));
  gap: var(--hm-gap);
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
}
.heatmap__weekdays span { display: flex; align-items: center; padding-right: 4px; }

/* поле карты: колонка — неделя, семь строк — дни; понедельник сверху */
.heatmap__grid {
  grid-column: 2;
  grid-row: 2;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--hm-cell);
  grid-template-rows: repeat(7, var(--hm-cell));
  gap: var(--hm-gap);
}

.heatmap__cell {
  width: var(--hm-cell);
  height: var(--hm-cell);
  border-radius: 2px;
  /* пусто по умолчанию — та же дорожка, что у незаполненных часовых столбиков */
  background: color-mix(in srgb, var(--thread) 30%, transparent);
}
/* дни за пределами окна: только распорка, чтобы сетка оставалась прямоугольной */
.heatmap__cell--pad { visibility: hidden; }

/* день есть, оценка ниже цели — серый, отдельно от «нет данных» */
.heatmap__cell[data-level='low'] { background: color-mix(in srgb, var(--muted) 40%, transparent); }
/* цель взята — четыре ступени шалфейного, темнее с ростом над целью */
.heatmap__cell[data-level='l1'] { background: color-mix(in srgb, var(--sage) 35%, var(--paper)); }
.heatmap__cell[data-level='l2'] { background: color-mix(in srgb, var(--sage) 60%, var(--paper)); }
.heatmap__cell[data-level='l3'] { background: color-mix(in srgb, var(--sage) 85%, var(--paper)); }
.heatmap__cell[data-level='l4'] { background: color-mix(in srgb, var(--sage) 85%, var(--ink) 15%); }

/* сегодняшняя клетка — тонкая тёмная обводка, как «сегодня» в недельных шкалах */
.heatmap__cell[data-today] { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--ink) 55%, transparent); }

/* легенда в подвале: «меньше» — дорожка и пять ступеней — «больше», цель справа */
.heatmap__legend {
  /* образцы легенды за клеткой карты не тянутся: она растёт с шириной экрана,
     а строка легенды должна остаться строкой. Размер у них свой и постоянный —
     и потому, что легенда лежит вне .heatmap и переменную карты не наследует */
  --hm-swatch: 11px;
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 12px 0 0;
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
}
.heatmap__swatch {
  width: var(--hm-swatch);
  height: var(--hm-swatch);
  border-radius: 2px;
  display: inline-block;
  background: color-mix(in srgb, var(--thread) 30%, transparent);
}
.heatmap__swatch[data-level='low'] { background: color-mix(in srgb, var(--muted) 40%, transparent); }
.heatmap__swatch[data-level='l1'] { background: color-mix(in srgb, var(--sage) 35%, var(--paper)); }
.heatmap__swatch[data-level='l2'] { background: color-mix(in srgb, var(--sage) 60%, var(--paper)); }
.heatmap__swatch[data-level='l3'] { background: color-mix(in srgb, var(--sage) 85%, var(--paper)); }
.heatmap__swatch[data-level='l4'] { background: color-mix(in srgb, var(--sage) 85%, var(--ink) 15%); }
.heatmap__legend-goal { margin-left: auto; }

@media (max-width: 560px) {
  /* мельче клетка и теснее зазор — тот же минимум, до которого доходит fit()
     в heatmap.js; здесь он нужен на случай, если скрипт ещё не отработал */
  .heatmap { --hm-cell: 10px; --hm-gap: 2px; }
  .heatmap__legend { font-size: 10px; --hm-swatch: 10px; }
}

/* ==================================================================== */
/* Питание: действия, столбики по дням, лог, диалог о еде                */
/* ==================================================================== */

/* Новых цветов и шрифтов раздел не заводит: всё ниже собрано из тех же
   переменных и тех же форм, что «Здоровье» и «Фокус». Отсюда и повторное
   использование .metric, .mini, .bars, .timer__modes и .add — новая
   страница должна читаться как давно существующая. */

.card--ndays, .card--navg, .card--nlog, .card--water { margin-bottom: var(--gap); }

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

.acts { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: var(--gap); }

/* «диалог не настроен» — не тревога, а сноска: она занимает свою строку
   целиком, чтобы не растаскивать кнопки по ширине экрана */
.acts__note {
  flex-basis: 100%;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
  margin: 0;
}

/* ---------------- Полоса воды ---------------- */

/* Та же дорожка, что у таймера на «Фокусе», но во всю ширину блока и
   шалфейная: вода — метрика цели, а не расхода, и шалфейный в проекте
   уже означает «цель взята». Класс общий: им живут и плитка «Вода» в
   «Питании», и карточка «Вода сегодня» на «Здоровье». */
.water__track {
  height: 6px;
  margin: 12px 0 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--thread) 40%, transparent);
  overflow: hidden;
}
.water__track i {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--sage);
  transition: width 0.25s ease;
}

/* карточка на «Здоровье»: миллилитры крупно, цель — мелкой подписью рядом */
.water__lead { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin: 0; }
.water__value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(28px, 4vw, 36px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.water__goal { font-family: var(--mono); font-size: 12px; color: var(--muted); }

/* ---------------- Переключатель периода ---------------- */

/* Таблетка режимов таймера стоит внутри бумажной карточки, и дорожка у неё
   цветом страницы. Здесь переключатель лежит прямо на фоне — красим дорожку
   бумагой, иначе на --ground её просто не видно. */
.n__range { background: var(--paper); margin-bottom: var(--gap); }

/* ---------------- Калории по дням ---------------- */

/* Столбики те же, что у «Активности по часам», но состояний больше: день
   выше цели и ниже цели различаются насыщенностью, а не цветом — так шкала
   остаётся читаемой и в чёрно-белом, и при дальтонизме. */
.bars__col[data-state='under'] i { background: color-mix(in srgb, var(--berry) 45%, transparent); }
.bars__col[data-state='over'] i { background: var(--berry); }
/* сегодняшний день обведён — тот же приём, что у недельных шкал */
.bars__col[data-today] i { box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ink) 55%, transparent); }

/* пустой период прячет и поле, и шкалу под ним. У .bars и .bars__scale
   свой display, а он сильнее браузерного правила для [hidden] — гасим руками */
.bars[hidden], .bars__scale[hidden] { display: none; }

/* на неделе столбиков всего семь: без ограничения ширины они расплываются
   в плиты — тот же предел, что у .week__col */
.bars--days { gap: 5px; }
.bars--days .bars__col i { max-width: 76px; margin: 0 auto; }
.bars--days + .bars__scale { gap: 5px; }

/* ---------------- Средние за период ---------------- */

/* Девять чисел: ккал, БЖУ, клетчатка, вода и сосудистая тройка. Базовая .mini
   рассчитана на четыре, а девять в жёсткую сетку не ложатся ни при каком
   делителе — поэтому auto-fit: на широком экране влезает шесть-семь, на
   планшете три, на телефоне два, и последний ряд нигде не остаётся рваным. */
.mini--nine { grid-template-columns: repeat(auto-fit, minmax(128px, 1fr)); }
.mini--nine .mini__value { font-size: 17px; }
/* сетка сильнее браузерного [hidden] — пустой период гасим правилом */
.mini[hidden] { display: none; }

/* ---------------- Лог записей ---------------- */

/* Строка лога устроена как событие таймлайна: время слева, суть в середине,
   числа справа. Вода идёт отдельными строками — так видно, когда её пили. */
.log { list-style: none; margin: 0; padding: 0; }
.log__item {
  display: grid;
  grid-template-columns: 46px 1fr auto auto;
  align-items: baseline;
  gap: 5px 14px;
  padding: 13px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.log__item:first-child { border-top: 0; }

.log__time {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* название пишет человек или модель — длинное переносим, а не выпускаем из карточки */
.log__name { margin: 0; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
.log__sum {
  margin: 0;
  font-family: var(--mono);
  font-weight: 600;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* вода — не еда: её объём читается спокойнее калорий */
.log__item[data-kind='water'] .log__sum { color: var(--muted); }

.log__note {
  grid-column: 2 / -1;
  margin: 0;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
}

/* удаление — тихая ссылка, как «отключить» в строке состояния на «Здоровье» */
.log__del {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.log__del:hover { color: var(--berry); }
.log__del[disabled] { opacity: 0.5; cursor: default; text-decoration: none; }

/* ==================================================================== */
/* Быстрая запись: окна еды и воды                                       */
/* ==================================================================== */

/*
  Общий слой приложения (resources/views/partials/quick-add.blade.php):
  диалог о еде и стакан воды открываются поверх любой страницы, не уводя
  человека с того, что он смотрел.

  Устройство одно на оба окна и на оба размера экрана: шапка, прокручиваемая
  середина и прижатый к низу ввод. На телефоне окно занимает экран целиком —
  так поле оказывается ровно над клавиатурой, а список блюд не жмётся в
  четверть экрана; на широком это крупная карточка по центру, не выше 85 %
  высоты окна.

  Слои: 30 — выше плавающей кнопки (20) и нижней панели разделов (12), под
  которыми окно и должно лежать. Индикатор жеста (40) остаётся сверху, но
  вместе они не встречаются: при открытом окне жест не заводится вовсе
  (body.is-modal, см. public/refresh.js).
*/

.modal {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: clamp(12px, 4vw, 44px) clamp(12px, 4vw, 24px);
}
.modal[hidden] { display: none; }

/* затемнение ловит клик мимо карточки — это второй способ закрыть окно */
.modal__back { position: fixed; inset: 0; background: color-mix(in srgb, var(--shade) 52%, transparent); }

.modal__card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: min(640px, 100%);
  max-height: min(85vh, 100%);
  background: var(--paper);
  border-radius: var(--radius);
  /* поля разнесены по шапке, середине и подвалу: только так середина может
     прокручиваться под неподвижной шапкой, а не вместе с ней */
  overflow: hidden;
  /* мягкий выезд снизу — тот же жест, что у любого мобильного листа */
  animation: lifeos-modal-in 240ms cubic-bezier(0.2, 0.9, 0.3, 1) both;
}

@keyframes lifeos-modal-in {
  from { opacity: 0; transform: translateY(18px) scale(0.985); }
  to { opacity: 1; transform: none; }
}

/* ---------------- Шапка, середина, подвал ---------------- */

.modal__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex: none;
  padding: 20px 24px 14px;
  border-bottom: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}

/* единственное, что прокручивается: переписка, оценка и ручная форма */
.modal__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 18px 24px 20px;
}

/* ввод прижат к низу и не уезжает с прокруткой: на телефоне он оказывается
   ровно над клавиатурой, и переписка не прыгает под пальцем */
.modal__foot {
  flex: none;
  padding: 14px 24px calc(16px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
  background: var(--paper);
}

.modal__close {
  font-family: var(--body);
  font-size: 24px;
  line-height: 1;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0 2px;
  cursor: pointer;
}
.modal__close:hover { color: var(--ink); }

/* пока окно открыто, страница под ним не едет ни от колеса, ни от пальца */
body.is-modal { overflow: hidden; }

/* ---------------- Телефон: во весь экран ---------------- */

@media (max-width: 560px) {
  /*
    Высоту берём у визуального вьюпорта: он один знает, сколько экрана
    осталось после клавиатуры. Переменные ставит quick-add.js, запасной
    100dvh — для браузеров без visualViewport.
  */
  .modal {
    top: var(--vv-top, 0px);
    bottom: auto;
    height: var(--vv-h, 100dvh);
    padding: 0;
    place-items: stretch;
  }

  .modal__card {
    width: 100%;
    max-height: none;
    height: 100%;
    border-radius: 0;
  }

  /* окно приезжает снизу целиком — обычное поведение мобильного листа */
  .modal__card { animation-name: lifeos-sheet-in; }

  .modal__head { padding: calc(16px + env(safe-area-inset-top, 0px)) 20px 12px; }
  .modal__body { padding: 16px 20px 20px; }
  .modal__foot { padding: 12px 20px calc(12px + env(safe-area-inset-bottom, 0px)); }
}

@keyframes lifeos-sheet-in {
  from { transform: translateY(100%); }
  to { transform: none; }
}

/* просьба «поменьше движения» касается и выезда: окно просто появляется */
@media (prefers-reduced-motion: reduce) {
  .modal__card { animation: none; }
}

/* ---------------- Переписка ---------------- */

/* Пузыри как в мессенджере: реплика человека прижата вправо и тёмная,
   ответ модели — слева на подложке страницы. Подпись роли моноширинная
   и мелкая, той же породы, что подписи мини-плиток.

   Своей прокрутки у переписки нет: она едет вместе с серединой окна
   (.modal__body). Два вложенных скролла на телефоне неразличимы пальцем —
   палец попадает то в один, то в другой. */
.chat { display: grid; gap: 14px; margin: 0; }
.chat:empty { display: none; }

.chat__row { display: grid; gap: 4px; justify-items: start; }
.chat__row[data-role='user'] { justify-items: end; }

.chat__role {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.chat__text {
  margin: 0;
  max-width: 88%;
  border-radius: 12px;
  padding: 10px 13px;
  background: var(--ground);
  /* модель отвечает абзацами и списками — переносы сохраняем как есть */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.chat__row[data-role='user'] .chat__text { background: var(--ink); color: var(--paper); }
/* реплика, которая ещё летит на сервер: видно, что она не подтверждена */
.chat__row[data-pending] .chat__text { opacity: 0.6; }

.chat__empty, .chat__off { font-size: 13px; line-height: 1.6; color: var(--muted); margin: 0; }
.chat__empty[hidden], .chat__off[hidden] { display: none; }

.chat__wait { font-family: var(--mono); font-size: 11px; color: var(--muted); margin: 12px 0 0; }
/* отказ Claude — мягкая строка, а не красный блок: переписка цела,
   человеку достаточно повторить или дописать вручную */
.chat__error { font-family: var(--mono); font-size: 11px; line-height: 1.6; color: var(--berry); margin: 12px 0 0; }

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

.est {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.est[hidden] { display: none; }

.est__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 8px;
}

.est__list { list-style: none; margin: 0; padding: 0; }
.est__item {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 3px 12px;
  padding: 9px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.est__item:first-child { border-top: 0; padding-top: 0; }
.est__name { margin: 0; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
.est__num {
  margin: 0;
  font-family: var(--mono);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.est__note {
  grid-column: 1 / -1;
  margin: 0;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
}

.est__totals {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  margin: 12px 0 0;
  padding-top: 12px;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.est__kcal { font-family: var(--mono); font-weight: 600; font-size: 19px; font-variant-numeric: tabular-nums; }
.est__macros { font-family: var(--mono); font-size: 12px; color: var(--muted); }
.est__share { font-family: var(--mono); font-size: 11px; line-height: 1.6; color: var(--muted); margin: 7px 0 0; }

/* ---------------- Ввод ---------------- */

/* Поля и границы приезжают из .modal__foot: ввод и есть подвал окна. */
.chat__form[hidden] { display: none; }

.chat__input {
  width: 100%;
  font-family: var(--body);
  font-size: 16px; /* меньше — и iOS зумит страницу при фокусе в поле */
  line-height: 1.5;
  padding: 10px 12px;
  border: 1px solid var(--thread);
  border-radius: 10px;
  background: var(--field);
  color: var(--ink);
  resize: none;
}

.chat__acts { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.chat__hint { font-family: var(--mono); font-size: 10px; line-height: 1.5; color: var(--muted); }

/* ---------------- Окно воды ---------------- */

/* Сегодняшний итог крупно, как в плитке «Вода» на «Питании»: прежде чем
   доливать, человек смотрит, сколько уже выпито. */
.wsum {
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(26px, 7vw, 34px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.wsum__note { font-family: var(--mono); font-size: 11px; line-height: 1.6; color: var(--muted); margin: 10px 0 0; }

/* Два пресета во всю ширину: попасть в них можно, не глядя. Это главное
   действие окна, поэтому они крупнее любой кнопки проекта. */
.wpick { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 22px; }

.wpick__item {
  display: grid;
  gap: 6px;
  justify-items: center;
  align-content: center;
  min-height: 96px;
  padding: 16px 10px;
  border: 1px solid var(--thread);
  border-radius: var(--radius);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
}
.wpick__item:hover { border-color: var(--ink); }
.wpick__item:active { background: var(--ground); }
.wpick__item[disabled] { opacity: 0.5; cursor: default; }

.wpick__num {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 24px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.wpick__unit { font-family: var(--mono); font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }

.wnote { font-family: var(--mono); font-size: 11px; line-height: 1.6; color: var(--muted); margin: 14px 0 0; }
.wnote[hidden] { display: none; }

/* «своё, мл» — редкий случай, поэтому строкой в подвале, а не карточкой */
.wform { display: flex; align-items: end; gap: 12px; }
.wform .field { flex: 1 1 auto; min-width: 0; }
/* меньше 16px — и iOS зумит страницу при фокусе в поле */
.wform .field input { font-size: 16px; }

/* ---------------- Адаптив раздела ---------------- */

@media (max-width: 900px) {
  /* на планшете колонка уже — числа не должны слипаться в столбик */
  .mini--nine { grid-template-columns: repeat(auto-fit, minmax(112px, 1fr)); }
}

@media (max-width: 560px) {
  .mini--nine { grid-template-columns: repeat(2, 1fr); }
  .mini--nine .mini__value { font-size: 16px; }

  /* столбиков за месяц тридцать — им нужен тот же тесный шаг, что у часов */
  .bars--days { gap: 3px; }
  .bars--days + .bars__scale { gap: 3px; }

  /* лог: колонка времени уже, числа мельче — четыре колонки должны влезть */
  .log__item { grid-template-columns: 38px 1fr auto auto; gap: 5px 9px; padding: 12px 0; }
  .log__time { font-size: 10px; }
  .log__sum { font-size: 14px; }

  /* окно во весь экран: пузыри шире, кнопки ввода делят строку пополам */
  .chat__text { max-width: 94%; }
  .chat__acts .button { flex: 1 1 auto; }
  .chat__hint { flex-basis: 100%; }

  /* ручная форма и правка шаблонов: три колонки на 375 пикселях — это три
     поля по 90, куда не влезает ни одна подпись */
  .modal__body .add__form { grid-template-columns: repeat(2, 1fr); }
}

/* ==================================================================== */
/* Настройки: профиль, цели и история измерений                          */
/* ==================================================================== */

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

.card--set { margin-bottom: var(--gap); }

/* строка формы: поля слева, кнопка в конце — как в карточке источников */
.set__form { display: flex; align-items: end; gap: 14px 16px; flex-wrap: wrap; }

/* поле вместе с подписью под ним: .field — только ярлык и ввод */
.set__cell { display: grid; gap: 5px; min-width: min(220px, 100%); }

/* подсказка под полем: «авто: 2 500 мл от веса 75 кг» */
.set__note {
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1.5;
  color: var(--muted);
  margin: 0;
}

/* сетка целей: семь полей в одну колонку читались бы как анкета */
.set__grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.set__acts { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 18px; }
.set__acts .errors { margin: 0; }

/* ошибка стоит в своей форме, а не в общей шапке страницы */
.set__error { flex-basis: 100%; margin: 0; }

/* блок измерений отделён от роста чертой: это уже не профиль, а история */
.set__block {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.set__legend {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 14px;
}

/* последние измерения: дата, вес, жир и тихая кнопка «удалить» */
.set__list { list-style: none; margin: 18px 0 0; padding: 0; }
.set__row {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: baseline;
  gap: 6px 14px;
  padding: 11px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.set__row:first-child { border-top: 0; }
.set__when { font-family: var(--mono); font-size: 11px; color: var(--muted); }
.set__kg { font-family: var(--mono); font-weight: 600; font-size: 16px; font-variant-numeric: tabular-nums; }
.set__fat { font-family: var(--mono); font-size: 11px; color: var(--muted); }

/* удаление — исправление опечатки, а не разрушительное действие:
   тихая ссылка-кнопка, как «отключить» в карточке Google */
.set__drop {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--muted);
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.set__drop:hover { color: var(--berry); }

/*
  «Оформление» — единственная карточка настроек без формы и без сервера:
  тема живёт в localStorage этого браузера, и жать «Сохранить» после выбора
  было бы враньём. Собственных цветов и форм у неё нет — переключатель тот
  же, что у режимов таймера и периода в «Питании» (.timer__modes).
*/
.theme__pick { margin-top: 4px; }
.theme__note { margin-top: 12px; }

@media (max-width: 900px) {
  .set__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .set__grid { grid-template-columns: 1fr; }
  .set__form .button { width: 100%; }
  /* дата уходит на свою строку, числа встают под ней — четыре колонки не влезают */
  .set__row { grid-template-columns: 1fr auto; }
  .set__when { grid-column: 1 / -1; }
}

/* ==================================================================== */
/* Тренды: три ночные метрики под общим переключателем периода            */
/* ==================================================================== */

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

  Своих графических форм раздел не заводит: поле, подсказка и подписи оси
  те же самые .h__plot / .h__svg / .h__tip, что у пульса и веса. Новое
  здесь только шапка подграфика — имя слева, текущее число справа.
*/

.card--trends { margin-bottom: var(--gap); }

/* переключатель стоит на бумажной карточке — дорожка цветом страницы,
   как у режимов таймера; во всю ширину, чтобы три периода делили её поровну */
.tr__range { display: flex; width: 100%; margin: 4px 0 6px; }
.tr__range .timer__mode { flex: 1; padding: 10px 8px; }

.tr__item { padding: 18px 0 4px; border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent); }
.tr__item:first-child { border-top: 0; padding-top: 8px; }

.tr__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: 0 0 10px; }
.tr__name { font-family: var(--display); font-size: 16px; font-weight: 600; margin: 0; }

/* текущее значение крупно, размах и среднее — мелким моноширинным под ним */
.tr__now { display: grid; justify-items: end; gap: 3px; margin: 0; text-align: right; }
.tr__value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: 26px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.tr__meta { font-family: var(--mono); font-size: 11px; color: var(--muted); }

/* поле держит высоту графика и без него: пустой ряд не должен сжимать
   карточку, иначе переключение периода дёргало бы всю страницу */
.tr__body { display: flex; flex-direction: column; justify-content: center; min-height: 170px; }
.tr__empty { text-align: center; margin: 0; }

/* легенда температуры: сплошная линия — измеренная ночь, пунктир — базовая */
.tr__legend { display: flex; gap: 16px; flex-wrap: wrap; margin: 10px 0 0; }
.tr__legend[hidden] { display: none; }
.tr__line { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 11px; color: var(--muted); }
.tr__line i { width: 12px; height: 0; border-top: 2px solid var(--stress-mid); }
.tr__line[data-line='base'] i { border-top: 2px dashed var(--muted); }

.tr__note { margin-top: 14px; }
.tr__note[hidden] { display: none; }

@media (max-width: 560px) {
  /* на телефоне имя метрики и число живут в одной строке только по верхнему
     краю: у «Ночной температуры» подпись переносится, и базовая линия
     выравнивания увела бы число вниз */
  .tr__head { align-items: flex-start; }
  .tr__value { font-size: 22px; }
  .tr__range .timer__mode { padding: 10px 4px; letter-spacing: 0.08em; }
}

/* ==================================================================== */
/* Вес и % жира: график на «Здоровье»                                    */
/* ==================================================================== */

/*
  Карточка живёт в том же рисовальщике, что пульс и VO2MAX (drawLine
  в health.js), поэтому у неё общие .h__figure, .h__plot и .h__svg.
  Своего здесь — только шапка с текущим весом и легенда двух линий:
  вес читается по левой шкале, процент жира — по правой.
*/

.card--weight { margin-bottom: var(--gap); }

.weight__now { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin: 0 0 10px; }
.weight__value {
  font-family: var(--mono);
  font-weight: 600;
  font-size: clamp(30px, 4.5vw, 40px);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.weight__fat { font-family: var(--mono); font-size: 12px; color: var(--muted); }

/* легенда: какая линия чем меряется — иначе две шкалы читаются наугад */
.weight__key { display: flex; gap: 16px; flex-wrap: wrap; margin: 12px 0 0; }
.weight__legend { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono); font-size: 11px; color: var(--muted); }
.weight__legend i { width: 8px; height: 8px; border-radius: 2px; background: var(--thread); }
.weight__legend[data-line='kg'] i { background: var(--berry); }
.weight__legend[data-line='fat'] i { background: var(--sage); }
.weight__legend[data-line='goal'] i { background: transparent; border-top: 2px dashed var(--muted); height: 0; border-radius: 0; }

/* ==================================================================== */
/* Шаблоны еды: капсулы быстрого добавления и карточка на «Питании»      */
/* ==================================================================== */

/*
  Шаблон — привычное с известными КБЖУ: протеин, коллаген, овсянка.
  Новых форм раздел не заводит: капсула — та же таблетка, что у тегов
  фокуса, строка карточки — та же сетка, что у лога записей, а форма
  правки переиспользует .add__form с полями .field. Так «Шаблоны»
  читаются как часть страницы, а не как приклеенный сбоку блок.
*/

.card--ntpl { margin-bottom: var(--gap); }

/* ---------------- Быстрое добавление в модале ---------------- */

/* Стоит первым делом в диалоге, до переписки: чаще всего модал открывают
   ради одного тапа по капсуле, и прокрутка до неё убила бы весь смысл. */
.quick {
  margin-bottom: 16px;
  padding-bottom: 14px;
  border-bottom: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.quick[hidden] { display: none; }

.quick__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 9px;
}

/* капсулы переносятся строками: их бывает восемь, и в одну строку
   на телефоне они всё равно не встали бы */
.quick__row { display: flex; flex-wrap: wrap; gap: 6px; }

.quick__chip {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  max-width: 100%;
  background: transparent;
  border: 1px solid var(--thread);
  border-radius: 999px;
  padding: 7px 13px;
  cursor: pointer;
  color: var(--ink);
}
.quick__chip:hover { border-color: var(--ink); }
.quick__chip[disabled] { opacity: 0.45; cursor: default; }

/* название пишет человек — длинное подрезаем многоточием, а не растягиваем
   капсулу на всю ширину диалога */
.quick__name {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* калории мельче имени: это подсказка, а не то, по чему выбирают */
.quick__kcal {
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.quick__note { font-family: var(--mono); font-size: 11px; line-height: 1.6; color: var(--muted); margin: 10px 0 0; }
.quick__note[hidden] { display: none; }

/* ---------------- Карточка «Шаблоны» ---------------- */

/* Строка устроена как строка лога, только без колонки времени: у заготовки
   времени нет. Подпись с КБЖУ и формой правки уходят под неё во всю ширину. */
.tpl { list-style: none; margin: 0; padding: 0; }
.tpl__item {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: baseline;
  gap: 5px 14px;
  padding: 13px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.tpl__item:first-child { border-top: 0; }

.tpl__name { margin: 0; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
.tpl__sum {
  margin: 0;
  font-family: var(--mono);
  font-weight: 600;
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tpl__note {
  grid-column: 1 / -1;
  margin: 0;
  font-family: var(--mono);
  font-size: 11px;
  line-height: 1.6;
  color: var(--muted);
}

/* правка и удаление — те же тихие ссылки-кнопки, что «убрать» в логе */
.tpl__acts, .log__acts { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }

/* форма правки свёрнута по умолчанию: семь полей у каждой строки
   превратили бы карточку в простыню. У .add__form свой display —
   браузерное правило для [hidden] его не перебивает, гасим руками */
.tpl__edit { grid-column: 1 / -1; margin-top: 4px; }
.tpl__edit[hidden] { display: none; }

@media (max-width: 560px) {
  /* название и калории остаются в строке, кнопки уходят под них:
     три колонки на телефоне уже не влезают */
  .tpl__item { grid-template-columns: 1fr auto; }
  .tpl__acts { grid-column: 1 / -1; justify-content: flex-start; }
  .log__acts { gap: 9px; }
}

/* ---------------- Добавки: капсулы, история, карточка ---------------- */

/*
  Капсула добавки — та же таблетка, что у шаблонов еды, только разрезанная
  надвое: слева «принял», справа «история». Две отдельные кнопки, а не одна
  с длинным нажатием: жест, о котором нигде не написано, не найдут.
*/
.supp__row { display: flex; flex-wrap: wrap; gap: 6px; }

.supp__item {
  display: inline-flex;
  align-items: stretch;
  max-width: 100%;
  border: 1px solid var(--thread);
  border-radius: 999px;
  overflow: hidden;
}
.supp__item:hover { border-color: var(--ink); }

.supp__take {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  min-width: 0;
  background: transparent;
  border: 0;
  padding: 7px 13px;
  cursor: pointer;
  color: var(--ink);
}
.supp__take[disabled] { opacity: 0.45; cursor: default; }

/* название пишет человек — длинное подрезаем многоточием, как у шаблонов */
.supp__name {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* доза мельче имени: это подсказка, а не то, по чему выбирают */
.supp__dose { font-family: var(--mono); font-size: 10px; color: var(--muted); white-space: nowrap; }

/*
  Состав второй строкой капсулы. Занимает всю ширину (flex-basis), поэтому имя
  и доза остаются на первой строке, а «Д3 5000 МЕ · К2 100 мкг» уходит под них:
  подпись, а не заголовок — капсулу выбирают по имени препарата.

  Пищевая ценность («120 ккал · Б 24») живёт там же и по тем же правилам:
  это вторая подпись того же рода, и заводить ей отдельную типографику значило
  бы сделать две мелкие строки под одним именем разными без причины.
*/
.supp__mix,
.supp__food {
  flex-basis: 100%;
  font-family: var(--mono);
  font-size: 10px;
  line-height: 1.45;
  color: var(--muted);
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* двухстрочная капсула круглой быть перестаёт: 999px раздул бы ей пустые бока */
.supp__item--mix { border-radius: var(--radius); }
.supp__item--mix .supp__take { flex-wrap: wrap; row-gap: 2px; }

/* капсула вещества — половина обычной: «принять» вещество нельзя, принимают
   препарат, поэтому второй кнопки у неё нет вовсе */
.supp__item--sub .supp__take { padding-right: 15px; }

/*
  Переключатель картин: препараты и вещества. Не вкладки с рамками — две
  тихие подписи на месте заголовка списка: переключаются они редко, а места
  в окне ровно столько же, сколько было под словом «Ваши добавки».
*/
.supp__tabs { display: flex; gap: 14px; margin: 0 0 9px; }

.supp__tab {
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}
.supp__tab:hover { color: var(--ink); }
/* открытая картина подчёркнута, а не залита: это подпись, а не кнопка */
.supp__tab[aria-pressed='true'] {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* принято сегодня: маленькая галочка вместо второй строки текста */
.supp__mark { font-size: 11px; color: var(--sage); }

/* «история» — тихая половина капсулы: по ней ходят реже, чем отмечают приём */
.supp__hist {
  border: 0;
  border-left: 1px solid var(--thread);
  background: transparent;
  padding: 0 11px;
  cursor: pointer;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.supp__hist:hover { color: var(--ink); }

/* история внутри окна: показывается вместо списка капсул */
.supp-hist[hidden] { display: none; }

.supp-days { list-style: none; margin: 14px 0 0; padding: 0; }
.supp-day {
  padding: 11px 0;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.supp-day:first-child { border-top: 0; }
.supp-day__date {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 6px;
}
/* приёмы одного дня — строкой таблеток: их редко больше трёх */
.supp-day__row { display: flex; flex-wrap: wrap; gap: 6px; }
.supp-day__time {
  font-family: var(--mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  border: 1px solid color-mix(in srgb, var(--thread) 55%, transparent);
  border-radius: 999px;
  padding: 3px 9px;
}
.supp-day__dose { color: var(--muted); }
/* из какого препарата пришёл вклад: в истории вещества без этого цифры
   из двух источников не различить */
.supp-day__from { color: var(--muted); font-size: 10px; }

/* суммы за периоды под сводкой истории — вторым этажом подписи */
.supp-hist__totals { margin-top: 3px; }
.supp-hist__totals[hidden] { display: none; }

/* состав препарата (или перечень источников вещества) — над сводкой: он
   объясняет цифры ниже, поэтому читается раньше них */
.supp-hist__mix { margin-bottom: 3px; }
.supp-hist__mix[hidden] { display: none; }

/* форма новой добавки в подвале окна: имя во всю ширину, ниже доза числом,
   единица и кнопка — одной строкой */
.supp-form { display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: end; }
/* сетка сильнее браузерного [hidden] — на время истории гасим правилом */
.supp-form[hidden] { display: none; }
.supp-form .field--wide { grid-column: 1 / -1; }
.supp-form .form-note { grid-column: 1 / -1; margin: 0; }
/* единица — короткий список из семи слов, растягивать его незачем */
.supp-form select { min-width: 82px; }

/*
  Узкий экран: три поля в строку превращают ввод дозы в щель шириной в два
  символа. Кнопка уходит вниз, доза и единица делят строку между собой.
*/
@media (max-width: 420px) {
  .supp-form { grid-template-columns: 1fr auto; }
  .supp-form .button { grid-column: 1 / -1; }
}

/*
  Состав в форме новой добавки. Спрятан за ссылкой, потому что у большинства
  добавок его нет: креатин сам себе вещество, и три лишних поля на каждом
  заведении превратили бы форму в анкету.
*/
.supp-mix { grid-column: 1 / -1; }
.supp-mix__toggle { cursor: pointer; font-family: var(--mono); font-size: 11px; color: var(--berry); }

.supp-mix__rows { display: grid; gap: 12px; margin-top: 12px; }

/* строка вещества: имя во всю ширину, под ним доза, единица и крестик */
.supp-mix__row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 10px;
  align-items: end;
}
.supp-mix__row .field--wide { grid-column: 1 / -1; }
.supp-mix__row select { min-width: 82px; }

/* крестик — тихий: убрать строку нужно редко, а спутать его с «Завести» нельзя */
.supp-mix__drop {
  background: transparent;
  border: 0;
  padding: 0 4px 6px;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  color: var(--muted);
}
.supp-mix__drop:hover { color: var(--berry); }

.supp-mix__acts { display: flex; align-items: center; gap: 12px; margin: 12px 0 0; flex-wrap: wrap; }
.supp-mix__hint { font-family: var(--mono); font-size: 10px; color: var(--muted); }

/*
  Пищевая ценность добавки — тот же свёрнутый блок, что состав и сосудистые
  детали еды: у креатина её нет вовсе, и пять полей в каждой форме превратили
  бы быстрое заведение в анкету. Колонки резиновые: пять чисел в ряд на
  телефоне не встают, а фиксированные пять колонок сжали бы поля в нечитаемые.
*/
.supp-food { grid-column: 1 / -1; }
.supp-food__toggle { cursor: pointer; font-family: var(--mono); font-size: 11px; color: var(--berry); }
.supp-food__rows {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: 12px;
  margin-top: 12px;
}
.supp-food__hint { font-family: var(--mono); font-size: 10px; color: var(--muted); margin: 10px 0 0; }

/* блок «По веществам» в карточке «Питания»: отделён нитью от списка
   препаратов — это другая картина тех же добавок, а не продолжение списка */
.supp-subs {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid color-mix(in srgb, var(--thread) 45%, transparent);
}
.supp-subs[hidden] { display: none; }

/* кнопка «+ Добавка» стоит в хвосте карточки — нижний отступ .acts тут лишний */
.acts--supp { margin: 18px 0 0; }

/* карточка «Добавки» на «Питании»: имя добавки открывает ту же историю */
.supp__link {
  font: inherit;
  font-weight: 600;
  text-align: left;
  background: transparent;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--thread);
  text-underline-offset: 3px;
}
.supp__link:hover { text-decoration-color: var(--ink); }

/* в карточке состав стоит под именем препарата: там не капсула, а строка
   списка, и подпись становится собственной строкой */
.tpl__name .supp__mix,
.tpl__name .supp__food { display: block; margin-top: 3px; white-space: normal; }

/* доза в логе приёмов читается спокойнее калорий — как объём воды */
.log__item[data-kind='supplement'] .log__sum { color: var(--muted); font-size: 13px; }

/* ==================================================================== */
/* Мягкость: скелетоны, проявление, состояния кнопок и сообщений         */
/* ==================================================================== */

/*
  Всё ниже обслуживает public/ui.js и public/refresh.js — два общих модуля,
  подключённых в layouts/app.blade.php до страничных скриптов.

  Новых цветов раздел не заводит: подложка плашки — фон страницы (--ground)
  на бумажной карточке, блик — та же бумага, спиннеры и стрелка берут
  currentColor. Формы тоже прежние: скругления .card, капсулы .button.
*/

:root {
  /* блик, который бежит по плашке: бумага, растворяющаяся к краям */
  --skel-glint: color-mix(in srgb, var(--paper) 82%, transparent);
}

/* ---------------- Скелетоны ---------------- */

@keyframes lifeos-shimmer {
  from { background-position: -60% 0; }
  to { background-position: 160% 0; }
}

/*
  Строчная плашка. Рисуется псевдоэлементом поверх элемента, а текст-заглушка
  («—» и мелкая единица рядом) прячется: высота строки остаётся ровно той же,
  что была, поэтому появление настоящего числа не двигает вёрстку ни на пиксель.

  Цвет текста гасим через !important нарочно: у части чисел он задан более
  цепким селектором (.hr__stat:first-child .hr__stat-value и подобные), и без
  этого прочерк проступал бы сквозь плашку.
*/
.skeleton {
  position: relative;
  color: transparent !important;
}
.skeleton > * { visibility: hidden; }

.skeleton::after {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: var(--skel-w, 100%);
  height: var(--skel-h, 0.74em);
  border-radius: 7px;
  background-color: var(--ground);
  background-image: linear-gradient(100deg, transparent 30%, var(--skel-glint) 50%, transparent 70%);
  background-size: 220% 100%;
  background-repeat: no-repeat;
  background-position: -60% 0;
  animation: lifeos-shimmer 1.5s linear infinite;
  pointer-events: none;
}

/* Ширины по назначению: число, дата, подпись, полная строка. Мера — ch, а не
   проценты: половина плашек висит на строчных span'ах, и процент считался бы
   от ширины самого «—», то есть в ничто. */
.skeleton--num { --skel-w: 4.5ch; }
.skeleton--date { --skel-w: 13ch; }
.skeleton--text { --skel-w: 18ch; }
.skeleton--wide { --skel-w: 100%; }

/* поле графика: плашка во всю площадь будущей кривой.
   min-height держит высоту, пока пустой svg внутри ещё ничего не занял */
.skeleton--plot {
  --skel-w: 100%;
  --skel-h: 100%;
  min-height: 170px;
}
/* у кривой дохода поле выше остальных: PLOT в finance.js — 16 + 190 + 26 */
.mrr__plot.skeleton--plot { min-height: 232px; }

/*
  Коробочные скелетоны. Здесь плашка — не одна: в пустой контейнер ui.js
  кладёт распорки нужной формы (строки лога, столбики, клетки года, капсулы),
  а бегущий блик идёт общим слоем поверх них.
*/
.skel-box { position: relative; }
.skel-box::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 10px;
  background-image: linear-gradient(100deg, transparent 30%, var(--skel-glint) 50%, transparent 70%);
  background-size: 220% 100%;
  background-repeat: no-repeat;
  background-position: -60% 0;
  animation: lifeos-shimmer 1.5s linear infinite;
  pointer-events: none;
}

/* строки списка: те же 44 пикселя высоты, что у строки лога и таймлайна */
.skel-box--rows { display: block; }
.skel-row {
  display: block;
  height: 14px;
  margin: 15px 0;
  border-radius: 7px;
  background: var(--ground);
}
.skel-row:first-child { margin-top: 6px; }
.skel-row:nth-child(2n) { width: 74%; }
.skel-row:nth-child(3n) { width: 88%; }

/* Столбики. Высоту не задаём: она уже своя и у .bars, и у .week__plot —
   поставив её здесь, мы бы схлопнули поле до нуля. */
.skel-box--bars { display: flex; align-items: flex-end; gap: 4px; }
.skel-bar {
  flex: 1 1 0;
  min-width: 0;
  border-radius: 5px 5px 2px 2px;
  background: var(--ground);
}
.skel-bar:nth-child(4n + 1) { height: 38%; }
.skel-bar:nth-child(4n + 2) { height: 66%; }
.skel-bar:nth-child(4n + 3) { height: 27%; }
.skel-bar:nth-child(4n + 4) { height: 54%; }

/* клетка года берёт размер у самой карты: распорке хватает своей заливки */
.skel-cell { background: var(--ground); }

/* капсулы шаблонов и тегов */
.skel-box--chips { display: flex; flex-wrap: wrap; gap: 6px; }
.skel-chip { display: inline-block; height: 31px; border-radius: 999px; background: var(--ground); }
.skel-chip:nth-child(3n + 1) { width: 96px; }
.skel-chip:nth-child(3n + 2) { width: 124px; }
.skel-chip:nth-child(3n + 3) { width: 78px; }

/* ---------------- Проявление данных ---------------- */

/* Короткий фейд при первом наполнении — и только при первом: обновление
   уже показанных чисел (поллинг таймера, синк, смена периода) проходит
   без анимации, иначе страница мигала бы раз в минуту сама по себе. */
@keyframes lifeos-fade {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}
.is-fresh { animation: lifeos-fade 180ms ease-out both; }

/* ---------------- Состояния кнопок ---------------- */

@keyframes lifeos-spin {
  to { transform: rotate(360deg); }
}

/*
  Мини-спиннер внутри кнопки: кольцо из currentColor, поэтому одинаково
  читается и на тёмной .button--solid, и на тихой ссылке-кнопке лога.
  Картинок и шрифтов не требует.
*/
.is-busy { position: relative; }
.is-busy::before {
  content: '';
  display: inline-block;
  vertical-align: -1px;
  width: 11px;
  height: 11px;
  margin-right: 7px;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, currentColor 30%, transparent);
  border-top-color: currentColor;
  animation: lifeos-spin 0.7s linear infinite;
}

/* Выключенная кнопка гаснет везде одинаково. Раньше такой вид был заведён
   точечно — в диалоге о еде и в окне воды; теперь он общий. */
.button[disabled],
.conn__quit[disabled],
.log__del[disabled],
.set__drop[disabled],
.tagpick__item[disabled],
.timer__mode[disabled],
.quick__chip[disabled],
.supp__take[disabled],
.supp__hist[disabled] {
  opacity: 0.5;
  cursor: default;
}

/* ---------------- Флеш-сообщения ---------------- */

/* Появляются мягко, гаснут сами через четыре секунды (ui.js). Остаются
   висеть только ошибки: их читают и по ним что-то делают. */
@keyframes lifeos-flash-in {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}
@keyframes lifeos-flash-out {
  from { opacity: 1; transform: none; }
  to { opacity: 0; transform: translateY(-6px); }
}
/* классы наши собственные, поэтому и селекторы общие: одинаково работают
   и для .flash, и для красной .errors, и для тихих подписей вроде .conn__note */
.is-in { animation: lifeos-flash-in 200ms ease-out both; }
.is-out { animation: lifeos-flash-out 220ms ease-in both; }

/* ==================================================================== */
/* Телефон: жест обновления, зоны нажатия и безопасные поля               */
/* ==================================================================== */

/* ---------------- Потянуть вниз, чтобы обновить ---------------- */

/*
  Индикатор жеста (public/refresh.js). Висит по центру под шапкой и выезжает
  ровно на столько, на сколько его вытянул палец: --pull ставит скрипт.

  Собственной резинки браузера при этом быть не должно — её отключает
  overscroll-behavior ниже, иначе поверх нашей стрелки поехала бы вторая.
*/
.pull {
  position: fixed;
  top: 0;
  left: 50%;
  z-index: 40;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-left: -17px;
  border-radius: 50%;
  background: var(--paper);
  box-shadow: 0 8px 20px color-mix(in srgb, var(--shade) 16%, transparent);
  transform: translateY(calc(var(--pull, 0px) + env(safe-area-inset-top, 0px) - 44px));
  opacity: 1;
  pointer-events: none;
  will-change: transform;
}
.pull[hidden] { display: none; }

/* пока палец ведёт, индикатор идёт след в след — плавность только на возврате
   и на доводке к точке вращения после отпускания.
   На возврате гасим ещё и прозрачность: на телефонах с большим вырезом
   (safe-area-inset-top ≥ 44px) «спрятанная» позиция геометрически остаётся
   в кадре — без opacity индикатор было видно после завершения жеста */
.pull[data-state='idle'] { transition: transform 220ms ease, opacity 180ms ease; opacity: 0; }
.pull[data-state='run'] { transition: transform 220ms ease; }

/* стрелка: уголок вниз, у порога разворачивается вверх и меняет цвет */
.pull__mark {
  width: 12px;
  height: 12px;
  margin-top: -4px;
  border: 2px solid var(--muted);
  border-top: 0;
  border-left: 0;
  transform: rotate(45deg);
  transition: transform 180ms ease, border-color 180ms ease;
}
.pull[data-state='ready'] .pull__mark { border-color: var(--berry); transform: rotate(225deg); }

/* данные пошли: стрелка уступает место отдельному кольцу-спиннеру.
   Именно отдельному: раньше кольцом становилась сама стрелка, и её
   transition докручивал transform из 225° обратно к нулю — глазом это
   читалось как вращение то в одну, то в другую сторону */
.pull__ring {
  display: none;
  width: 16px;
  height: 16px;
  border: 2px solid color-mix(in srgb, var(--thread) 70%, transparent);
  border-top-color: var(--ink);
  border-radius: 50%;
}
.pull[data-state='run'] .pull__mark { display: none; }
.pull[data-state='run'] .pull__ring {
  display: block;
  animation: lifeos-spin 0.7s linear infinite;
}

/* ---------------- Безопасные поля и прокрутка ---------------- */

/*
  В standalone страница занимает экран целиком, вместе с вырезом и полосой
  жестов: base.blade.php просит viewport-fit=cover. Значит поля обязаны
  учитывать env(safe-area-inset-*) — иначе заголовок уедет под чёлку.
  Базовые отступы те же, что у body выше, они просто складываются с вырезом.
*/
/*
  Ключевой нюанс: современный Chrome отключает свой pull-to-refresh только
  по overscroll-behavior на КОРНЕ (html) — с body свойство до вьюпорта не
  доезжает, и системный спиннер крутился поверх нашего индикатора.
*/
html { overscroll-behavior-y: none; }

body {
  padding-top: calc(clamp(20px, 4vw, 48px) + env(safe-area-inset-top, 0px));
  padding-right: calc(clamp(20px, 4vw, 48px) + env(safe-area-inset-right, 0px));
  padding-bottom: calc(clamp(20px, 4vw, 48px) + env(safe-area-inset-bottom, 0px));
  padding-left: calc(clamp(20px, 4vw, 48px) + env(safe-area-inset-left, 0px));
  /* жест обновления — свой, системная резинка поверх него не нужна */
  overscroll-behavior-y: contain;
}

/* ---------------- Зоны нажатия на телефоне ---------------- */

@media (max-width: 560px) {
  /*
    Палец — не курсор: всё, что нажимают, должно быть не меньше 44 пикселей
    по высоте. Капсулам и кнопкам хватает min-height с центровкой по вертикали.
  */
  .button,
  .timer__mode,
  .tagpick__item,
  .quick__chip,
  .supp__take,
  .supp__hist,
  .modal__close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
  }

  /* Меню — исключение. Разогнать пункты до 44 значит сделать таблетку разделов
     самой заметной вещью на экране, а она служебная. Вместо этого просто
     добавляем воздуха сверху и снизу: палец попадает, вид остаётся прежним. */
  .nav__link,
  .nav__quit { padding-top: 12px; padding-bottom: 12px; }

  /* капсула шаблона держит имя и калории на общей базовой линии */
  .quick__chip,
  .supp__take { align-items: baseline; }

  /*
    Тихие ссылки-кнопки («убрать», «в шаблон», «отключить», «удалить»)
    остаются мелкой подписью: раздувать их до кнопки значит превращать
    исправление опечатки в главное действие строки. Вместо этого им
    подкладывается невидимая площадка — она не занимает места в потоке
    и не двигает соседей.
  */
  .log__del,
  .conn__quit,
  .set__drop {
    position: relative;
  }
  .log__del::before,
  .conn__quit::before,
  .set__drop::before {
    content: '';
    position: absolute;
    inset: -14px -10px;
  }
  /* у занятой кнопки тот же псевдоэлемент занят спиннером: возвращаем его
     в поток, остальные свойства кольца приезжают из .is-busy::before */
  .log__del.is-busy::before,
  .conn__quit.is-busy::before,
  .set__drop.is-busy::before {
    position: static;
    inset: auto;
  }
}

/* ==================================================================== */
/* Меньше движения                                                       */
/* ==================================================================== */

/*
  Просьба системы «поменьше анимации» касается всего, что здесь заведено:
  мерцание скелетонов, проявление данных, спиннеры, стрелка жеста. Формы
  и состояния остаются на месте — исчезает только движение.
*/
@media (prefers-reduced-motion: reduce) {
  .skeleton::after,
  .skel-box::after,
  .is-fresh,
  .is-busy::before,
  .is-in,
  .is-out,
  .pull[data-state='run'] .pull__ring {
    animation: none;
  }

  /* без бегущего блика плашка остаётся ровной подложкой */
  .skeleton::after,
  .skel-box::after { background-image: none; }

  .is-fresh { opacity: 1; transform: none; }
  .is-in { opacity: 1; transform: none; }

  .pull,
  .pull__mark,
  .timer__track i,
  .water__track i { transition: none; }
}

/* ==================================================================== */
/* Нижняя панель разделов: телефон                                      */
/* ==================================================================== */

/*
  На телефоне пять разделов в верхнюю таблетку не встают: она прокручивалась
  вбок, половина пунктов жила за краем экрана, а попасть в 10-пиксельную
  подпись у самого верха можно было только второй рукой. Поэтому разделы
  переезжают вниз, под большой палец, а в шапке остаётся служебная пара
  «Настройки» и «Выйти».

  Над подписью — иконка раздела: контур в одну линию, той же тонкой породы,
  что и вся графика Life OS. Подпись при этом остаётся: пять рисунков без
  слов пришлось бы разгадывать, а моно-капс на девяти пикселях места почти
  не занимает. Сами иконки лежат в layouts/app.blade.php рядом с подписями —
  один список разделов на оба меню.

  Текущий раздел отмечен полным цветом (--ink против приглушённого) и чуть
  более плотной линией иконки — два признака вместо одного цвета. Ягодная
  точка над подписью, которой панель отмечала раздел, пока была текстовой,
  убрана: маркером стала сама иконка, а точка добавляла третий сигнал и
  лишнюю строку в и без того подросшую панель. Тёмная таблетка верхнего меню
  здесь по-прежнему не годится: на всю высоту нижней панели она читалась бы
  как большая кнопка.

  Разметка (layouts/app.blade.php) есть на любой ширине — на десктопе панель
  просто не показывается.
*/

.tabs { display: none; }

@media (max-width: 560px) {
  :root {
    /* высота панели без выреза: 1px границы + 7px + 53px кнопки + 7px */
    --tabs-h: 68px;
  }

  /* Верхнее меню на телефоне не нужно: разделы уехали вниз. Прокручиваемую
     таблетку убираем целиком, служебная пара прижимается вправо. */
  .nav__inner { display: none; }
  .nav { justify-content: flex-end; margin-bottom: 18px; }

  .tabs {
    display: block;
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    /*
      Ниже окон быстрой записи (30) и плавающей кнопки (20): панель —
      постоянный фон приложения, и перекрывать ею то, что человек только что
      открыл, нельзя. Индикатор жеста (40) тем более остаётся сверху.
    */
    z-index: 12;
    background: var(--paper);
    border-top: 1px solid var(--thread);
    /* мягкая тень вверх — граница между панелью и уезжающим под неё контентом */
    box-shadow: 0 -6px 20px color-mix(in srgb, var(--shade) 8%, transparent);
    /* полоса жестов Android и вырез iPhone: панель поднимается над ними,
       фон при этом продолжается до самого низа экрана */
    padding-right: env(safe-area-inset-right, 0px);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    padding-left: env(safe-area-inset-left, 0px);
  }

  .tabs__list {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 0;
    margin: 0;
    /* боковые поля маленькие намеренно: ширину съедают подписи, а воздух
       у панели вертикальный — им живут сами зоны нажатия */
    padding: 7px 4px;
    list-style: none;
  }

  .tabs__item { display: flex; }

  /* зона нажатия — вся высота панели и вся ширина колонки: целиться некуда,
     промахнуться мимо соседнего раздела нечем */
  .tabs__link {
    display: flex;
    flex: 1;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    min-height: 53px;
    padding: 5px 2px;
    border-radius: 12px;
    color: var(--muted);
    text-decoration: none;
  }

  /*
    Иконка. Толщина, цвет и заливка живут здесь, а не в атрибутах каждого
    рисунка: в разметке остаётся одна геометрия, и стиль всех пяти иконок
    правится в одной строке. Дети <svg> наследуют stroke и fill сами.
  */
  .tabs__icon {
    width: 22px;
    height: 22px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
  }

  .tabs__label {
    font-family: var(--mono);
    font-size: 9px;
    letter-spacing: 0.06em;
    line-height: 1;
    text-transform: uppercase;
    text-align: center;
    white-space: nowrap;
  }

  /* текущий раздел: полный цвет и линия чуть плотнее — один цвет как
     единственный признак читался бы хуже */
  .tabs__link[aria-current='page'] { color: var(--ink); }
  .tabs__link[aria-current='page'] .tabs__icon { stroke-width: 2.1; }

  /* отклик на палец: подложка цвета фона страницы, без своего цвета */
  .tabs__link:active { background: var(--ground); }

  /*
    Контент не должен прятаться под панелью: к нижнему полю страницы
    добавляется вся её высота вместе с вырезом. Правило перекрывает
    базовое padding-bottom для body из «Безопасных полей» выше.
  */
  body { padding-bottom: calc(var(--tabs-h) + 20px + env(safe-area-inset-bottom, 0px)); }
}

/* совсем узкий экран (iPhone SE и родня): у подписей сжимается разрядка,
   иначе «Здоровье» не помещается в колонку и панель ломается переносом */
@media (max-width: 359px) {
  .tabs__label { letter-spacing: 0.02em; }
}

/* ==================================================================== */
/* Воздух внутри карточек на телефоне                                   */
/* ==================================================================== */

/*
  Поля карточек и плиток на телефоне были ужаты ради ширины строки, и экран
  читался сплошной сеткой без пауз: цифра, граница, снова цифра. Возвращаем
  паузы — щедрее вертикальные поля и зазоры вложенных сеток. Боковые поля
  карточки при этом чуть уменьшены: ширина строки от этого не страдает, а
  двойное поле (страница плюс карточка) на 375 пикселях съедало почти
  четверть экрана.

  Всё внутри медиазапроса — десктопа правки не касаются.
*/

@media (max-width: 560px) {
  .card { padding: 24px 20px 26px; }
  .card__head { margin-bottom: 16px; }

  /*
    Плитки дашборда: воздух добавляем только сверху и снизу. Боковые 16px
    трогать нельзя — они выверены под длинные единицы («мл/кг/мин»), и
    лишняя пара пикселей поля унесла бы подпись на вторую строку.
  */
  .metric { padding: 18px 16px 20px; }

  /* вложенные плитки внутри карточек («за всё время», сводки разделов) */
  .mini { gap: 12px; }
  .mini__cell { padding: 13px 14px; }

  /* четыре числа отчёта по тегам стояли почти впритык друг к другу */
  .tagrep__stats { gap: 10px; }

  /* подвал с кнопками отделяется от последней карточки заметнее */
  .foot { margin-top: 32px; }
}

/* ==================================================================== */
/* Плавающая кнопка «+»                                                 */
/* ==================================================================== */

/*
  Еда и вода записываются по несколько раз в день — чаще, чем происходит
  всё остальное в Life OS. Раньше ради стакана воды приходилось сначала
  дойти до «Питания»; теперь тёмный кружок висит поверх любой страницы
  приложения и раскрывает вверх две капсулы.

  Кружок тёмный (--ink), как активный раздел в меню и как .button--solid:
  это главное действие экрана, и выглядеть оно должно так же, как остальные
  главные действия. Плюс нарисован псевдоэлементами — две полоски currentColor
  вместо шрифтового глифа: у «+» в Bricolage своя оптика, и центр креста в
  кружке не совпадал бы с центром круга. При раскрытии крест доворачивается
  на 45° и становится крестиком закрытия — отдельной кнопки «свернуть» не нужно.

  Слои: кнопка на 20 — выше нижней панели разделов (12), но ниже модала еды
  (30), под которым она вообще прячется. Скрим лежит внутри .fab с
  отрицательным z-index: он в её слое, поэтому затемняет всю страницу вместе
  с панелью, но не саму кнопку и не меню.

  Разметка — layouts/app.blade.php, раскрытие — public/fab.js.
*/

.fab {
  position: fixed;
  right: calc(28px + env(safe-area-inset-right, 0px));
  bottom: calc(28px + env(safe-area-inset-bottom, 0px));
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

/* модал еды занимает весь экран: кнопка под ним не нужна ни видимой, ни нажимаемой */
body.is-modal .fab { display: none; }

/* ---------------- Кружок ---------------- */

.fab__button {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
  /* тень вместо обводки: кнопка лежит над страницей, а не в потоке */
  box-shadow: 0 10px 26px color-mix(in srgb, var(--shade) 26%, transparent);
  transition: transform 0.16s ease;
}
.fab__button:hover { transform: translateY(-1px); }
.fab__button:active { transform: translateY(1px); }

/* крест: две полоски одной толщины, ровно по центру круга */
.fab__plus {
  position: relative;
  display: block;
  width: 22px;
  height: 22px;
  transition: transform 0.2s ease;
}
.fab__plus::before,
.fab__plus::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  background: currentColor;
  border-radius: 2px;
  transform: translate(-50%, -50%);
}
.fab__plus::before { width: 22px; height: 2px; }
.fab__plus::after { width: 2px; height: 22px; }

/* открытое меню — тот же крест, довёрнутый в крестик закрытия */
.fab[data-open='yes'] .fab__plus { transform: rotate(45deg); }

/* ---------------- Меню ---------------- */

.fab__menu {
  display: grid;
  justify-items: end;
  gap: 8px;
  margin: 0 0 12px;
}
.fab__menu[hidden] { display: none; }

/* капсула той же породы, что кнопки проекта, но бумажной заливки:
   меню лежит поверх карточек, и прозрачная кнопка на них не читалась бы */
.fab__item {
  /* палец, а не курсор: пункт держит высоту кнопки, а не подписи */
  display: flex;
  align-items: center;
  min-height: 46px;
  font-family: var(--body);
  font-size: 14px;
  line-height: 1;
  padding: 13px 20px;
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  box-shadow: 0 8px 22px color-mix(in srgb, var(--shade) 18%, transparent);

  /* закрытое состояние: капсулы «сложены» в кнопку и не ловят палец */
  opacity: 0;
  transform: translateY(10px) scale(0.94);
  transition: opacity 0.16s ease, transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1);
}
.fab[data-open='yes'] .fab__item {
  opacity: 1;
  transform: none;
}

/* Короткий каскад снизу вверх: капсулы выезжают из-под кнопки по очереди.
   Считаем с конца, а не с начала: ближняя к кнопке трогается первой, и
   порядок не сбивается, сколько бы пунктов в меню ни стало. */
.fab[data-open='yes'] .fab__item:nth-last-child(2) { transition-delay: 0.045s; }
.fab[data-open='yes'] .fab__item:nth-last-child(3) { transition-delay: 0.09s; }

/* ---------------- Скрим ---------------- */

.fab__scrim {
  position: fixed;
  inset: 0;
  /* минус первый: слой .fab, но позади её содержимого — кнопка и капсулы
     остаются поверх затемнения, всё остальное уходит под него */
  z-index: -1;
  background: color-mix(in srgb, var(--shade) 12%, transparent);
  opacity: 0;
  transition: opacity 0.18s ease;
}
.fab__scrim[hidden] { display: none; }
.fab[data-open='yes'] .fab__scrim { opacity: 1; }

/* ---------------- Место под кнопку ---------------- */

/*
  Подвал страницы не должен уезжать под кружок: нижнее поле body считается
  так, чтобы последняя кнопка «Синка» кончалась выше него.
*/

@media (min-width: 561px) {
  body { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }
}

@media (max-width: 560px) {
  /* на телефоне кнопка садится над панелью разделов, а не поверх неё */
  .fab {
    right: calc(16px + env(safe-area-inset-right, 0px));
    bottom: calc(var(--tabs-h, 68px) + 12px + env(safe-area-inset-bottom, 0px));
  }

  /* высота панели + зазор + сама кнопка + воздух под последней карточкой */
  body { padding-bottom: calc(var(--tabs-h, 68px) + 84px + env(safe-area-inset-bottom, 0px)); }
}

/* Плавность — украшение: кому она мешает, тот получает то же меню без движения */
@media (prefers-reduced-motion: reduce) {
  .fab__button,
  .fab__plus,
  .fab__item,
  .fab__scrim {
    transition-duration: 0.01ms;
    transition-delay: 0s;
  }
  .fab__button:hover,
  .fab__button:active { transform: none; }
  .fab__item { transform: none; }
}

/* ---------------- Ввод на сенсорном экране: без принудительного зума ---------------- */

/*
  Мобильный браузер принудительно приближает страницу, когда фокус попадает
  в поле со шрифтом мельче 16px, — и обратно сам не отъезжает. Поэтому на
  устройствах без курсора у всех полей ввода шрифт ровно 16px: браузеру
  незачем зумить. Компактные 14px остаются только там, где есть мышь.
*/
@media (hover: none) and (pointer: coarse) {
  /* !important осознанно: точечные селекторы форм (.field input, .wform
     .field input и т.п.) специфичнее голого input и молча возвращали бы
     свои 14px — а зум срабатывает от ЛЮБОГО поля мельче 16px. Это щит от
     поведения браузера, он обязан бить все локальные размеры полей разом. */
  input,
  select,
  textarea {
    font-size: 16px !important;
  }
}

/* ---------------- Питание: превышение сосудистых лимитов ---------------- */

/*
  Насыщенные и добавленный сахар выше нормы (AHA/ВОЗ), транс выше планки —
  значение и подпись плитки становятся ягодными. Холестерин сюда сознательно
  не входит: AHA 2026 не считает его первичной целью, у него только ориентир.
*/
.metric__value[data-state='over'],
.metric__note[data-state='over'] { color: var(--berry); }
