
:root {
  color-scheme: light;

  /* поверхности */
  --bg:         #eaf2f4;   /* фон страницы */
  --surface:    #ffffff;   /* карточка */
  --surface-2:  #dfeaee;   /* подложка внутри карточки, поле задания */
  --border:     #cadbe1;   /* линии и рамки */

  /* текст */
  --text:       #0b2a33;
  --muted:      #3f5c66;   /* подписи; держит 4,5:1 даже на --surface-2 */

  /* действие */
  --primary:    #0a5f7a;
  --on-primary: #ffffff;

  /* смысл: норма / недобор / перебор */
  --ok:         #0b6e40;
  --low:        #a3151f;
  --high:       #8a5a00;
  --ok-soft:    #e0f2e8;   /* фон метки «в норме» */
  --low-soft:   #fbe7e8;
  --high-soft:  #faefd3;

  /* старые имена — чтобы нынешний app.css работал без правок */
  --accent: var(--ok);
  --danger: var(--low);
  --warn:   var(--high);

  /* не цвет — оставлены как были */
  --radius: 14px;
  --shadow: 0 1px 2px rgba(11,42,51,.06), 0 8px 24px rgba(11,42,51,.05);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg:         #06161c;
    --surface:    #0d222a;
    --surface-2:  #133039;
    --border:     #1f414c;
    --text:       #e6f3f6;
    --muted:      #93b3bd;
    --primary:    #5ccbe8;
    --on-primary: #04212a;
    --ok:         #4fd49b;
    --low:        #ff8585;
    --high:       #f5c250;
    --ok-soft:    #0f3024;
    --low-soft:   #3a1a1f;
    --high-soft:  #33290f;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.3);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --bg:         #06161c;
  --surface:    #0d222a;
  --surface-2:  #133039;
  --border:     #1f414c;
  --text:       #e6f3f6;
  --muted:      #93b3bd;
  --primary:    #5ccbe8;
  --on-primary: #04212a;
  --ok:         #4fd49b;
  --low:        #ff8585;
  --high:       #f5c250;
  --ok-soft:    #0f3024;
  --low-soft:   #3a1a1f;
  --high-soft:  #33290f;
  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.3);
}

/* Метка смысла: цвет + значок. Значок обязателен —
   красный и зелёный у части мужчин неразличимы. */
.chip       { display: inline-flex; align-items: center; gap: 4px;
              padding: 4px 10px; border-radius: 999px;
              font-size: 13px; font-weight: 600; }
.chip svg   { width: 14px; height: 14px; flex: none; }
.chip.ok    { background: var(--ok-soft);   color: var(--ok); }   /* значок ✓ */
.chip.low   { background: var(--low-soft);  color: var(--low); }  /* значок ↓ */
.chip.high  { background: var(--high-soft); color: var(--high); } /* значок ↑ */

/* Знак «Ритм»: кольцо недели, 7 сегментов, 4 закрыты. Цвет берёт от текста,
   поэтому одинаково живёт в обеих темах и в любом месте интерфейса. */
.ritm-mark { width: 28px; height: 28px; flex: none; }
.brand { display: inline-flex; align-items: center; gap: 9px; color: var(--primary); }
.brand strong { font-size: 18px; letter-spacing: -.01em; color: var(--text); }
.brand-lg { display: flex; justify-content: center; margin-bottom: 18px; }
.brand-lg .ritm-mark { width: 34px; height: 34px; }
.brand-lg strong { font-size: 22px; }

* { box-sizing: border-box; }
/* Оболочка приложения: прокручивается только .wrap, сам документ — нет.
   Когда страница скроллилась целиком, на айфоне нижняя панель и кнопка
   «Сохранить» гуляли вверх-вниз: position:fixed отрывается от края при
   упругом отскоке и при смене высоты панелей браузера. Внутренний скролл
   убирает отскок вместе с прыжками, а панель становится частью каркаса. */
/* --app-h держит JS по window.visualViewport — это единственная высота, которая
   на айфоне совпадает с тем, что человек реально видит. 100dvh пересчитывается
   с задержкой и не знает про клавиатуру: каркас оставался прежней высоты, а
   окно под ним уезжало — отсюда и нижняя панель посреди экрана. Без JS (или на
   десктопе) работает фоллбек 100dvh. */
/* --sab: сколько на самом деле нужно отступить снизу под домашнюю черту.
   Само env(safe-area-inset-bottom) доверия не заслуживает: в режиме «с
   домашнего экрана» айфон отдаёт окно НИЖЕ экрана (innerHeight 879 при
   экране 926 — замер с телефона Игоря 16.09), то есть вырез уже вычтен из
   окна, и env() поверх этого добавляет его второй раз. Отсюда пустая полоса
   под панелью на всю ладонь. Реальное число считает JS ниже; здесь — фоллбек
   для десктопа и для страницы без скриптов. */
:root { --app-h: 100dvh; --app-top: 0px;
        --sab: env(safe-area-inset-bottom);
        --sat: env(safe-area-inset-top); }
/* Значок связи: зелёный — всё отправлено, красный — сети нет (работа идёт в
   очередь на устройстве и уйдёт сама). Маленькая точка в шапке, не кнопка:
   нажимать её незачем. */
.net-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px;
           background: var(--accent); align-self: center; margin-left: auto;
           margin-right: 8px; transition: background .25s ease; }
.net-dot.off { background: var(--danger); }
/* overflow:hidden на самом html обязателен: без него документ остаётся выше
   окна и айфон прокручивает его ЦЕЛИКОМ вместе с каркасом — панель и кнопка
   «Сохранить» ходят вверх-вниз, хотя внутри всё липнет правильно. */
/* Без text-size-adjust айфон при повороте в альбом сам «подтягивает» кегль
   (text autosizing) и обратно в портрет его уже не возвращает: шрифты
   остаются раздутыми до перезагрузки страницы. 100% = запрет на эту
   самодеятельность, размеры всегда те, что заданы в CSS. */
/* Фон документа — цвет нижней панели. Полосу под окном (её оставляет сам
   айфон, разметкой туда не дотянуться) браузер красит фоном документа: с
   цветом панели она читается как продолжение панели, а не как дыра. */
html {
  /* height: 100% равен ОКНУ, а не экрану: на айфоне с домашнего экрана окно
     ниже экрана (замер Игоря: окно 879 при экране 926), и полоса 47px под
     окном оставалась незакрашенной — её и видно как отдельную планку под
     нижним меню. 100dvh берёт высоту экрана, включая эту зону. */
  height: 100dvh; min-height: 100dvh;
  overflow: hidden; overscroll-behavior: none;
  /* Зону под окном красим цветом нижней панели: она читается как продолжение
     меню, а не как чужая полоса. */
  background: var(--surface);
  -webkit-text-size-adjust: 100%; text-size-adjust: 100%;
}
/* Тело живёт в пределах окна: каркас прибит к обоим краям и не тянется
   на вырез — иначе нижняя панель уезжает в зону домашней черты. */
html > body {
  height: 100dvh;
}
/* Каркас прибит к документу (position: fixed), а не лежит в потоке. Когда на
   айфоне открывается клавиатура, Safari не может прокрутить документ (он у нас
   не прокручивается) и вместо этого сдвигает само видимое окно — visualViewport
   уезжает вниз на десятки-сотни пикселей. Каркас при этом остаётся на месте:
   человек видит его середину, нижняя панель и «Сохранить» оказываются посреди
   экрана, а под ними — пустота. --app-top возвращает каркас в видимое окно. */
body {
  margin: 0; color: var(--text);
  /* Фон документа = цвет нижней панели. На айфоне с домашнего экрана окно
     НИЖЕ экрана (замер Игоря: 879 при 926), и зону под окном красит фон
     документа. Был --bg (фон страницы) — под панелью читалась отдельная
     полоса 22px другого цвета (видно на скриншотах). Теперь она совпадает
     с панелью и не отличается от неё. */
  background: var(--surface);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  -webkit-font-smoothing: antialiased;
  padding: 0;
  position: fixed; top: 0; left: 0; right: 0; bottom: 0; width: 100%;
  display: flex; flex-direction: column; overflow: hidden;
}
/* Обычное состояние (без клавиатуры) высоту НЕ вычисляет: каркас растянут
   top:0 + bottom:0 по окну, и число ниоткуда взяться не может. Раньше высоту
   всегда задавал JS из visualViewport — стоило одному замеру залипнуть на
   заниженном значении (после сохранения, возврата «назад», запуска с домашнего
   экрана), и каркас навсегда оставался короче экрана: меню висело в воздухе,
   под ним пустая полоса. Теперь JS вмешивается только при открытой клавиатуре
   — единственный случай, когда окно реально уезжает. */
html.kb body { top: var(--app-top, 0px); bottom: auto; height: var(--app-h, 100dvh); }
.wrap {
  flex: 1 1 auto; min-height: 0; width: 100%;
  max-width: 780px; margin-inline: auto;
  overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-y: contain;
  /* Сверху — место под строку состояния iPhone (часы, батарея, Wi-Fi).
     env() в режиме «с домашнего экрана» равен нулю, поэтому берём надёжный
     минимум: 20px оставляли шапку под часами (замер 19.09 — 20px на всех
     одиннадцати экранах). */
  /* Отступ сверху адаптивный: clamp держит его в разумных рамках.
     Жёсткие 46px раздували шапку на моделях без выреза (iPhone SE)
     и на небольших окнах — шапка съедала десятую часть экрана. */
  /* Минимум 40px: --sat в режиме «с домашнего экрана» равен нулю, и
     clamp(10px, ...) оставлял шапку под часами (замер 19.09 — 18px на
     «Разборе дня» и «Отчётах»). Статус-бар iPhone — около 47px. */
  /* Низ: запас под фиксированную панель, иначе последние поля карточки
     остаются под ней (замер 19.09 — «мини-подход» был перекрыт). */
  padding: clamp(40px, var(--sat), 46px) 16px calc(76px + var(--sab));
}
header { display: flex; align-items: flex-start; justify-content: space-between;
         gap: 12px; margin: 8px 0 20px; }
/* Левая часть шапки занимает остаток ширины, но не выдавливает кнопку темы:
   без min-width:0 заголовок с подписью распирал строку и подзаголовок
   залезал на кнопку. */
header > div { min-width: 0; flex: 1 1 auto; }
h1 { font-size: 22px; line-height: 1.25; margin: 0; letter-spacing: -.01em; }
.sub { color: var(--muted); font-size: 14px; margin-top: 2px; }
.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: 0 0 44px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  cursor: pointer; transition: background .18s ease, transform .18s ease;
}
.icon-btn:hover { background: var(--surface-2); }
.icon-btn:active { transform: scale(.96); }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

/* Название тренировки с карандашом: нажал — открылось окно правки.
   Кнопка выглядит как текст, а не как кнопка: название читается заголовком. */
.name-edit {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; padding: 0; margin: 0; font: inherit;
  color: inherit; cursor: pointer; text-align: left;
}
.name-edit .pencil { display: inline-flex; opacity: .55; }
.name-edit .pencil svg { width: 15px; height: 15px; }
.name-edit:active .pencil { opacity: 1; }

/* Прогрессия по группам: группа раскрывается тапом, внутри — упражнения.
   summary без маркера: свой значок-стрелка понятнее системного треугольника. */
details.grp { border-bottom: 1px solid var(--border); }
details.grp > summary { list-style: none; cursor: pointer; align-items: center; }
details.grp > summary::-webkit-details-marker { display: none; }
details.grp > summary::after { content: "▸"; color: var(--muted); font-size: 13px;
  margin-left: 6px; transition: transform .15s ease; }
details.grp[open] > summary::after { content: "▾"; }
details.grp .sub-list { padding: 0 0 8px 12px; border-left: 2px solid var(--border);
  margin: 0 0 8px 4px; }
.row.sub { padding: 6px 0; border: 0; }
.row.sub .name { font-size: 13px; font-weight: 500; }
.row.sub .meta { font-size: 12px; }
.meta-ish { color: var(--muted); font-size: 12px; margin: -6px 0 8px; }
/* Свой диапазон дат: два поля и кнопка в одну строку, на узком экране перенос. */
.range-form { display: flex; gap: 8px; align-items: center; margin-bottom: 10px;
  flex-wrap: wrap; }
.range-form input[type=date] { flex: 1 1 130px; min-width: 0; padding: 8px 10px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface);
  color: var(--text); font-size: 13px; }
.range-form .dash { color: var(--muted); }
/* Шапка тренировки: имя с карандашом и подпись — в одной строке, но с переносом.
   Раньше карандаш стоял внутри подписи и наезжал на «упражнений в плане». */
.sub.name-line { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 8px; }
.name-text { font-weight: 600; }
.name-meta { opacity: .75; }
/* Дата: видимая подпись по-русски, сам календарь скрыт под ней. */
.date-view { position: relative; }
.date-btn {
  width: 100%; text-align: left; font: inherit; color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px 14px; cursor: pointer;
}
.date-btn:active { border-color: var(--primary); }
.date-hidden { position: absolute; left: 0; bottom: 0; width: 1px; height: 1px;
               opacity: 0; pointer-events: none; }
.key-note { font-size: 12px; opacity: .7; }
/* Окно правки: обычная карточка, а не модальное окно — на телефоне проще. */
.rename-panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 14px; margin: 12px 0 16px;
}
.rename-panel .row-actions { display: flex; gap: 8px; margin-top: 12px; }
.rename-panel .row-actions .btn { flex: 1; }

.cards { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
         gap: 10px; margin-bottom: 20px; }
/* minmax(0,1fr) вместо 1fr: иначе длинная цифра распирает колонку и текст
   уезжает за край экрана. */
@media (min-width: 560px) { .cards { grid-template-columns: repeat(4, 1fr); } }
.card {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px; box-shadow: var(--shadow);
}
.card .label { color: var(--muted); font-size: 13px; }
.card .value { font-size: 24px; font-weight: 650; letter-spacing: -.02em; margin-top: 4px;
               font-variant-numeric: tabular-nums; }
.card .delta { font-size: 13px; margin-top: 2px; font-variant-numeric: tabular-nums; }
/* Карточки веса и сна — во всю ширину: строк стало по семь, и в две колонки
   значения переносились посреди («30 дней назад 80,8 / кг»). */
.card.wide { grid-column: 1 / -1; }
.card.wide .delta { white-space: normal; line-height: 1.55; }
.card .hint-dim { color: var(--muted); opacity: .85; font-size: 11px; }
.dim0 { opacity: .55; }
/* Прогрессия: каждая группа — своя карточка, внутри строки упражнений.
   Две колонки справа: 7 и 30 дней. Сетка 1fr auto auto держит их ровно
   друг под другом. Блок компактный: мелкий шрифт, тонкие линии-разделители,
   названия переносятся на две строки и не обрезаются (Игорь, 19.09). */
.pt-head, .pt-group, .pt-ex {
  display: grid; grid-template-columns: minmax(0, 1fr) 60px 66px;
  align-items: center; gap: 8px; }
.pt-head { padding: 0 12px 4px; color: var(--muted); font-size: 10px;
           text-transform: uppercase; letter-spacing: .04em; }
.pt-head .pt-w, .pt-head .pt-m { text-align: right; }
.pt-table { display: flex; flex-direction: column; gap: 6px; }
.pt-group { background: var(--surface); border: 1px solid var(--border);
            border-radius: var(--radius) var(--radius) 0 0;
            border-bottom: 0; padding: 7px 12px;
            font-weight: 650; font-size: 13px; line-height: 1.2; }
.pt-ex { padding: 4px 12px; font-size: 12px; line-height: 1.25;
         background: var(--surface);
         border-left: 1px solid var(--border); border-right: 1px solid var(--border);
         border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }
.pt-table > .pt-ex:last-child,
.pt-ex:has(+ .pt-group) { border-bottom: 1px solid var(--border);
                          border-radius: 0 0 var(--radius) var(--radius);
                          margin-bottom: 1px; }
.pt-exname { color: var(--text); overflow: hidden;
             display: -webkit-box; -webkit-line-clamp: 2;
             -webkit-box-orient: vertical; }
.pt-w, .pt-m { text-align: right; font-variant-numeric: tabular-nums;
               font-size: 11px; white-space: nowrap; }
.pt-m { color: var(--text); }
.pt-w { color: var(--muted); }
.pt-ok   { color: var(--accent); }
.pt-high { color: var(--accent); font-weight: 650; }
.pt-low  { color: var(--muted); }
.pt-stall { color: var(--danger); }
.pt-down { color: var(--danger); font-weight: 650; }
.pt-group .pt-w, .pt-group .pt-m { font-weight: 650; font-size: 13px; }
.pt-group .pt-name { font-size: 13px; }
.more-link { display: inline-block; margin-top: 6px; font-size: 12px;
             color: var(--primary); text-decoration: none; }
.more-link:active { opacity: .7; }
/* Выбор показателей галочками: мелкая сетка, цветная точка-маркер. */
.chk-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 2px 8px; margin: 4px 0 8px; }
.chk { display: flex; align-items: baseline; gap: 4px; font-size: 12px;
       padding: 2px 0; min-width: 0; }
.chk input { width: 14px; height: 14px; flex: 0 0 14px; align-self: center; }
.chk .chk-name { min-width: 0; overflow: hidden; text-overflow: ellipsis;
                  white-space: nowrap; }
.chk .unit { margin-left: auto; padding-left: 4px; }
.chk .unit { color: var(--muted); font-size: 10px; flex: 0 0 auto; }
.dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px;
       display: inline-block; margin-right: 6px; }
.chk-actions { display: flex; gap: 8px; align-items: center; }
.chk-actions .btn { flex: 0 0 auto; padding: 8px 14px; }
.chk-form { margin-bottom: 4px; }
/* Поля настроек: числовые, время и выпадающие списки — единый вид.
   Раньше класс .unit не имел стилей, и числовые поля выглядели чёрными
   полосками без рамки и подписи (Игорь, 19.09). */
.cfg-row input.unit, .cfg-row select.unit,
.row input.unit, .row select.unit,
input.unit, select.unit {
  height: 42px; min-width: 96px; padding: 0 10px; font-size: 15px;
  font-family: inherit; color: var(--text); background: var(--surface);
  border: 1px solid var(--border); border-radius: 10px;
  -webkit-appearance: none; appearance: none;
  font-variant-numeric: tabular-nums; text-align: right; }
select.unit { min-width: 150px; text-align: left; padding-right: 30px;
              background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23888' stroke-width='1.6' stroke-linecap='round'/></svg>");
              background-repeat: no-repeat; background-position: right 10px center; }
input.unit:focus, select.unit:focus {
  outline: none; border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 15%, transparent); }
input.unit[type=time] { min-width: 120px; }
.row input.unit, .row select.unit { max-width: 62%; }
/* Галочки по блокам: видно, откуда показатель — тело, питание, сон, активность. */

/* Таблица по дням: числа под графиком. Прокрутка вбок — колонок может быть
   много, а экран узкий. */
.day-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch;
                  border: 1px solid var(--border); border-radius: var(--radius);
                  background: var(--surface); }
.day-table { border-collapse: collapse; width: 100%; font-size: 12px;
             font-variant-numeric: tabular-nums; }
.day-table th { text-align: right; padding: 8px 10px; color: var(--muted);
                font-weight: 500; white-space: nowrap;
                border-bottom: 1px solid var(--border); }
.day-table td { padding: 7px 10px; text-align: right; white-space: nowrap;
                border-bottom: 1px solid var(--border); }
.day-table tr:last-child td { border-bottom: 0; }
.day-table .d, .day-table th:first-child { text-align: left; color: var(--muted); }
.tabs.pager { margin-top: 10px; flex-wrap: wrap; justify-content: center; }
/* Галочки показателей: в строку друг за дружкой, с переносом — иначе
   список занимал пол-экрана (Игорь, 20.09). */
/* Все показатели одним потоком: заголовок блока идёт в строке с галочками,
   без переноса строки на каждый блок. При 31 галочке столбик занимал
   27 рядов (Игорь, 20.09). */
.chk-wrap { display: contents; }
.chk-blocks { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.chk-block { display: block; }
.chk-title { display: block; width: 100%; font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
            color: var(--muted); margin: 2px 0 2px; }
.chk-block .chk-title { display: inline-flex; align-items: center; width: auto;
                        margin: 0 0 0 6px; font-size: 11px; color: var(--muted);
                        text-transform: uppercase; white-space: nowrap; }
.chk-block:first-child .chk-title { margin-left: 0; }
.chk-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 2px 8px; }
.chk { display: inline-flex; align-items: center; gap: 5px; font-size: 13px;
       white-space: nowrap; }
.chk .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; }
.chk .unit { color: var(--muted); font-size: 11px; }
.chk-title { font-size: 11px; color: var(--muted); text-transform: uppercase;
             width: 100%; margin-top: 6px; }
/* Период и шестерёнка на страницах графиков: без отступа текст и иконка
   слипались в «6 месяцев⚙» (приёмка 20.09). */
.chart-tools { display: flex; align-items: center; gap: 12px; margin: 8px 0 10px; }
.period-note { font-size: 13px; color: var(--muted); text-transform: lowercase; }
.cfg-open { flex: 0 0 auto; }
.cfg-panel { margin: 5px 0 10px; }
/* Табы блоков: прокрутка вбок. При пяти табах на iPhone последний
   обрезался («Активн») — Игорь заметил на приёмке 20.09. */
/* Прокрутка только у ряда табов-блоков. Общее правило ломало раскладку:
   пагинация и контейнер таблицы сжимались до пары пикселей (приёмка 20.09). */
.tabs.block-tabs { flex-wrap: nowrap; overflow-x: auto;
                   -webkit-overflow-scrolling: touch; scrollbar-width: none; }
.tabs.block-tabs::-webkit-scrollbar { display: none; }
.tabs.block-tabs .tab { flex: 0 0 auto; }
/* Название показателя и единица — в одну строку, без переноса «ккал» на
   отдельную строку. */
.chk { white-space: nowrap; }
.chk .unit { margin-left: 4px; }
/* Показатели — в одну колонку: в две длинные названия («Активные калории»,
   «Минуты тренировок») обрезались правым краем (приёмка 20.09). */
.chk-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
@media (min-width: 560px) { .chk-grid { grid-template-columns: 1fr 1fr !important; } }
/* Подсказка, что табы листаются: тень у правого края. */
.tabs { position: relative; }
.chk-block .chk-title { font-size: 11px; text-transform: uppercase;
                        letter-spacing: .04em; color: var(--muted); margin-bottom: 2px; }
.chart-legend .lg-wrap { display: flex; flex-wrap: wrap; gap: 8px;
                         justify-content: center; }
.chart-live { position: relative; }
.chart-live svg { touch-action: none; }
.ch-guide { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 3 3; opacity: .7; }
.ch-tip { position: absolute; top: 6px; transform: translateX(-50%);
          background: var(--surface); border: 1px solid var(--border);
          border-radius: 8px; padding: 6px 9px; font-size: 11.5px; line-height: 1.5;
          box-shadow: 0 4px 14px rgba(0, 0, 0, .18); pointer-events: none;
          white-space: nowrap; z-index: 5; color: var(--text); }
.ch-tip .ct-date { font-weight: 650; margin-bottom: 2px; opacity: .75; font-size: 11px; }
.ch-tip .ct-days { font-weight: 400; opacity: .8; }
.ch-tip .ct-row { display: flex; align-items: center; gap: 4px; }
.ch-tip .ct-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; }
.chart-legend .lg { display: inline-flex; align-items: center; gap: 4px;
                    font-size: 11px; }
.delta.ok { color: var(--accent); }
.delta.bad { color: var(--danger); }
/* Цвета прогрессии: рост — зелёный, падение — красный. «Весовые»
   up/down сюда не годятся: там рост означал набор веса. */
.gain-up { color: var(--ok, #16a34a); }
.gain-down { color: var(--danger); }
.gain-flat { color: var(--muted); }
.grp-block { border-bottom: 1px solid var(--border); }
.grp-block:last-child { border-bottom: 0; }
.grp-block .grp { border-bottom: 0; }
.grp-block .grp-meta { margin: 0 0 10px; }
/* Компактная строка группы: название слева, прирост справа, «развернуть»
   подчёркнуто — видно, что нажимается. Данные идут строкой ниже. */
.grp { border-bottom: 1px solid var(--border); }
.grp:last-child { border-bottom: 0; }
.grp > summary.grp-head { display: flex; align-items: baseline; gap: 8px;
  padding: 12px 0; cursor: pointer; list-style: none; }
.grp > summary.grp-head::-webkit-details-marker { display: none; }
.grp-name { flex: 1 1 auto; font-weight: 600; font-size: 15px; }
.grp-gain { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 14px; }
.grp-more { color: var(--primary); font-size: 12px; text-decoration: underline;
  text-underline-offset: 3px; white-space: nowrap; }
.grp[open] .grp-more::after { content: ""; }
.grp[open] > summary.grp-head .grp-more { text-decoration: none; color: var(--muted); }
.grp[open] > summary.grp-head .grp-more { font-size: 0; }
.grp[open] > summary.grp-head .grp-more::before { content: "свернуть"; font-size: 12px; }
.grp-meta { color: var(--muted); font-size: 12px; margin: -6px 0 8px; }
.grp .sub-list { padding-bottom: 8px; }
/* Карточка в две колонки: слева большая цифра, справа список точек.
   Раньше строки шли во всю ширину, а правую половину оставляли пустой. */
.card-split { display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; }
.card-split .split-left { flex: 0 0 auto; }
.card-split .split-right { flex: 1 1 auto; text-align: right; font-size: 13px;
  line-height: 1.75; font-variant-numeric: tabular-nums; }
.up { color: var(--danger); } .down { color: var(--accent); } .flat { color: var(--muted); }
/* Прогрессия упражнений: рост — это хорошо, поэтому цвета обратные весу.
   Раньше использовали .up/.down от веса, и рост в упражнениях выходил красным. */
.grow { color: var(--accent); } .fall { color: var(--danger); } .even { color: var(--muted); }

.section-title { font-size: 13px; text-transform: uppercase; letter-spacing: .06em;
                 color: var(--muted); margin: 24px 0 10px; }
.list { display: flex; flex-direction: column; gap: 8px; }
.row {
  display: flex; align-items: center; gap: 12px; min-height: 52px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  color: inherit; text-decoration: none; transition: background .18s ease, transform .18s ease;
}
a.row:hover { background: var(--surface-2); }
a.row:active { transform: scale(.99); }
.row { flex-wrap: wrap; }
.row .grow { flex: 1 1 auto; min-width: 0; }
.row .name { font-weight: 550; }
.row .name, .row .meta { overflow-wrap: anywhere; }
/* Правая часть строки: дельты, чипы, кнопки. Без ограничения ширины длинный
   текст («+1 080 к прошлой неделе») распирал карточку и выезжал за экран;
   переносим его на свою строку, а не режем. */
/* Дельта («+1 080 к прошлой неделе») — длинный текст. Без max-width она
   распирала карточку и уезжала за правый край экрана: сжимаем её и разрешаем
   переносом занять своё место под цифрой. */
.row > .delta { flex: 0 1 auto; max-width: 52%; text-align: right;
                overflow-wrap: anywhere; }
.row > .chip, .row > .num, .row > .mini { flex: 0 0 auto; }
.report-body { background: var(--surface); border: 1px solid var(--border);
                border-radius: var(--radius); box-shadow: var(--shadow);
                padding: 16px; line-height: 1.65; font-size: 15px;
                /* Текст собран для Telegram: абзацы разделены переносами строки,
                   а не тегами. Без pre-wrap все пункты слипаются в один абзац. */
                white-space: pre-wrap; }
.report-body b { font-weight: 650; }
.report-body > b:first-child { display: block; font-size: 18px; margin-bottom: 6px; }
.report-body pre { white-space: pre; overflow-x: auto; background: var(--surface-2); border-radius: 10px;
                   padding: 12px; font-size: 13px; line-height: 1.5; margin: 2px 0;
                   font-variant-numeric: tabular-nums; }
.report-body i { color: var(--muted); font-size: 13px; font-style: normal; }
.card.wide-card .lead { font-size: 17px; font-weight: 650; margin-bottom: 10px; }
.card.wide-card p { margin: 0 0 8px; color: var(--muted); line-height: 1.6; }
/* Анализы: карточка показателя со шкалой референса. */
.lab-grid { display: grid; gap: 12px; }
@media (min-width: 900px) { .lab-grid { grid-template-columns: 1fr 1fr; } }
.lab-card { display: block; background: var(--surface); border: 1px solid var(--border);
            border-radius: var(--radius); box-shadow: var(--shadow); padding: 14px 16px;
            color: inherit; text-decoration: none; min-width: 0;
            transition: border-color .18s ease, transform .18s ease; }
.lab-card:hover { border-color: color-mix(in srgb, var(--primary) 45%, var(--border)); }
.lab-card:active { transform: scale(.995); }
.lab-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.lab-head b { font-size: 15px; line-height: 1.35; }
.lab-value { font-size: 26px; font-weight: 700; margin: 8px 0 10px;
             font-variant-numeric: tabular-nums; display: flex; align-items: baseline; gap: 8px; }
.lab-value .unit { font-size: 14px; font-weight: 500; color: var(--muted); }
.lab-value .when { margin-left: auto; font-size: 13px; font-weight: 500; color: var(--muted); }
.scale { position: relative; height: 8px; border-radius: 999px; background: var(--surface-2); }
.scale-band { position: absolute; top: 0; bottom: 0; border-radius: 999px;
              background: color-mix(in srgb, var(--accent) 32%, transparent); }
.scale-mark { position: absolute; top: -3px; width: 4px; height: 14px; border-radius: 2px;
              background: var(--text); transform: translateX(-2px); }
.scale-mark.ok { background: var(--accent); }
.scale-mark.warn { background: var(--warn); }
.scale-mark.fail { background: var(--danger); }
.lab-norm { margin-top: 8px; font-size: 13px; color: var(--muted); }
.lab-hist { margin-top: 6px; font-size: 13px; font-variant-numeric: tabular-nums; }
.lab-old { margin-top: 6px; font-size: 12px; color: var(--warn); }
.lab-hint { margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border);
            font-size: 13px; color: var(--muted); }
.lab-chart { width: 100%; max-width: 640px; height: auto; display: block; margin: 0 auto; }
.lab-chart text { fill: var(--muted); font-size: 13px; }
.lab-chart .lab-point { fill: var(--text); font-size: 14px; font-weight: 600; }
.notice.warn { border-color: color-mix(in srgb, var(--warn) 45%, var(--border));
               background: color-mix(in srgb, var(--warn) 10%, var(--surface)); }
/* Схема нового упражнения. Четыре поля стояли одной строкой (класс ex-row
   перебивал сетку своим display:flex) — подписи-плейсхолдеры обрезались до
   «повторь»/«подходь» и было непонятно, что вводить. Своя сетка 2×2 и
   подпись над каждым полем. */
.add-scheme { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 8px; }
.add-scheme .control { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
/* Четыре поля в ряд: диапазоны миорепса (первый подход и мини-подходы). На
   телефоне — по два в строку, иначе подписи обрезаются. */
.grid4 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 12px; margin: 12px 0 4px; }
@media (min-width: 560px) { .grid4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.grid4 .control { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.grid4 .cap { font-size: 11px; color: var(--muted); white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; }
/* Поля «от» и «до» идут парой: между ними узкий зазор, между парами — широкий. */
.grid4 .control + .control { margin-left: 0; }
.add-scheme .cap { font-size: 10px; line-height: 1.2; color: var(--muted, #888); opacity: .8;
    text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.add-scheme input, .add-scheme select,
.grid4 input, .grid4 select { height: 48px; padding: 0 12px; font-size: 17px;
    min-width: 0; width: 100%;
    background: var(--surface-2); color: var(--text);
    border: 1px solid var(--border); border-radius: 10px; }
.add-scheme input:focus, .add-scheme select:focus,
.grid4 input:focus, .grid4 select:focus {
    border-color: var(--primary); outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent); }
/* «от» и «до» — два отдельных поля: диапазон в таблице бывает и односторонним
   («до 16» у миорепса), а одним текстовым полем это не набрать с телефона. */
.rep-span { display: flex; align-items: center; gap: 6px; }
.rep-span input { text-align: center; padding: 0 4px; font-variant-numeric: tabular-nums; }
.rep-span .dash { flex: 0 0 auto; color: var(--muted, #888); font-size: 15px; }
.reps-label { margin: 10px 0 4px; color: var(--muted); font-size: 12px; }
/* Кнопка сохранения липнет к низу: в зале форма длинная, листать до конца
   ради одного нажатия неудобно и легко забыть сохранить. */
/* Кнопка сохранения — в обычном потоке, в конце формы (Игорь, 21.09).
   Была position: sticky, и при открытой клавиатуре вьюпорт сжимается:
   кнопка «прилипала» к новому низу видимой области и всплывала ПОВЕРХ
   задания с упражнением. Пусть лучше лишний раз пролистать, чем
   перекрывать то, что человек заполняет. */
/* Пороги данных: сетка узких полей вместо строк с длинными пояснениями —
   блок настроек был портянкой на весь экран (Игорь, 21.09). */
/* Зона записи отделена от настроек графика: кнопки «Записать вес» и «Замер»
   относятся к дневнику, а табы и период — к графику (Игорь, 21.09). */
.cfg-zone { padding-bottom: 12px; margin-bottom: 4px;
            border-bottom: 1px solid var(--border); }

.cfg-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
            gap: 6px 8px; margin: 8px 0 4px; }
.cfg-cell { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cfg-cell span { color: var(--muted); font-size: 11px; white-space: nowrap;
                 overflow: hidden; text-overflow: ellipsis; }
.cfg-cell input { width: 100%; padding: 7px 8px; font-size: 13px;
                  border: 1px solid var(--border); border-radius: 8px;
                  background: var(--surface); color: var(--text);
                  font-variant-numeric: tabular-nums; }
.cfg-hint { color: var(--muted); font-size: 11px; line-height: 1.35;
            margin-bottom: 10px; }

.save-bar { position: static; z-index: auto;
            padding: 10px 0 6px; margin-top: 18px;
            background: transparent;
            border-top: 1px solid var(--border); }
.wrap:has(.save-bar) { padding-bottom: calc(96px + var(--sab)); }
/* Заголовок сворачивающегося блока — тоже цель для пальца: 22px строки мало,
   добираем отступами до 44px. */
details.howto > summary { cursor: pointer; font-weight: 600; color: var(--text);
                          padding: 11px 0; margin: -11px 0; }
details.howto[open] > summary { margin-bottom: 8px; }
@media (min-width: 1024px) { .save-bar { bottom: 16px; } }
.row.accent { border-color: color-mix(in srgb, var(--primary) 40%, var(--border));
              background: color-mix(in srgb, var(--primary) 6%, var(--surface)); }
.row .meta { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
/* Сравнение с прошлой неделей в строке блока активности: то же, что в карточке,
   но справа от текста и не переносится на вторую строку. */
.row .delta { font-size: 13px; font-variant-numeric: tabular-nums; flex: 0 0 auto;
              text-align: right; max-width: 45%; }
.num { font-variant-numeric: tabular-nums; white-space: nowrap; }

.meal { margin: 22px 0 8px; display: flex; align-items: baseline; gap: 10px; }
.meal h2 { font-size: 17px; margin: 0; }
.meal .num { color: var(--muted); font-size: 14px; }
.macros { display: flex; gap: 10px; flex-wrap: wrap; color: var(--muted); font-size: 13px; }
.total { margin-top: 22px; padding: 16px; border-radius: var(--radius);
         background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow); }
.total .value { font-size: 26px; font-weight: 650; letter-spacing: -.02em; }

.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: var(--radius);
             /* Затемнение у правого края: без него таблица выглядит просто
                обрезанной, и не понять, что её можно листать вбок. */
             background:
               linear-gradient(to right, var(--surface) 30%, transparent) left / 24px 100% no-repeat,
               linear-gradient(to left, var(--surface) 30%, transparent) right / 24px 100% no-repeat,
               radial-gradient(farthest-side at 0 50%, rgba(0,0,0,.13), transparent) left / 12px 100% no-repeat,
               radial-gradient(farthest-side at 100% 50%, rgba(0,0,0,.13), transparent) right / 12px 100% no-repeat;
             background-attachment: local, local, scroll, scroll; }
table.data { width: 100%; border-collapse: collapse; background: var(--surface);
             border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.tbl-scroll { width: 100%; overflow-x: auto; -webkit-overflow-scrolling: touch;
   overscroll-behavior-x: contain; }
/* Кромка справа: видно, что таблицу можно сдвинуть пальцем. */
.tbl-scroll.scrollable { -webkit-mask-image: linear-gradient(to right, #000 88%, transparent);
   mask-image: linear-gradient(to right, #000 88%, transparent); }
table.data th, table.data td { padding: 10px 12px; text-align: right; white-space: nowrap;
                               font-variant-numeric: tabular-nums; font-size: 14px; }
table.data th { color: var(--muted); font-weight: 500; font-size: 12px; text-transform: uppercase;
                letter-spacing: .04em; border-bottom: 1px solid var(--border); }
table.data th .thm { display: block; }
table.data th .ths { display: block; font-size: 9px; font-weight: 400;
                     text-transform: none; letter-spacing: 0; opacity: .65;
                     white-space: normal; }
table.data td:first-child, table.data th:first-child { text-align: left; }
table.data tbody tr + tr td { border-top: 1px solid var(--border); }

.actions { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0 14px; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
       min-height: 44px; padding: 0 16px; border-radius: 12px; font-size: 15px; font-weight: 550;
       text-decoration: none; cursor: pointer; border: 1px solid var(--border);
       background: var(--surface); color: var(--text);
       transition: background .18s ease, transform .18s ease; }
.btn:hover { background: var(--surface-2); }
.btn.primary { background: var(--primary); color: var(--on-primary); border-color: transparent; }
.btn.primary:hover { opacity: .92; background: var(--primary); }

/* ---------------------------------------------------------------- нажатие
   Отклик на палец. Раньше его фактически не было, и это читалось как «приложение
   зависло»: нажал — ничего, ждёшь, потом страница перерисовалась.

   Три причины, все чинятся здесь:
   1. Сафари на айфоне вообще не применяет :active к ссылкам и кнопкам, пока на
      документе нет обработчика касаний. Поэтому состояние вешает JS классом
      .is-press, а :active оставлен только для мыши.
   2. Подсветка ехала через `transition: transform .18s` — то есть ВЪЕЗЖАЛА
      за 180 мс. Обычное нажатие короче, палец успевал уйти раньше, чем
      анимация доходила до середины. Теперь нажатие мгновенное (0s), плавно
      только отпускание.
   3. Один scale(.98) на глаз почти не виден. Добавлен сдвиг цвета — его видно
      и в зале, и на солнце.
   tap-highlight гасим: серый прямоугольник айфона приходит с задержкой 100+ мс
   и выглядит как чужой артефакт поверх собственной подсветки. */
.btn, .mini, .icon-btn, a.row, .lab-card, nav a, .menu a, button, summary {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;   /* убирает 300 мс ожидания двойного тапа */
}
.is-press { transition: none !important; transform: scale(.97) !important;
            filter: brightness(1.18); }
:root[data-theme="light"] .is-press { filter: brightness(.94); }
.btn.is-press, .mini.is-press, .icon-btn.is-press { background: var(--surface-2); }
.btn.primary.is-press { background: var(--primary); }
a.row.is-press, .lab-card.is-press { background: var(--surface-2); }
nav a.is-press { background: var(--surface-2); }

/* Кнопка, по которой уже нажали и чей запрос в пути. Кнопку НЕ отключаем:
   disabled выкидывает её name/value из формы, а у нас на них держится
   различение команд («переместить вверх» против «удалить»). Поэтому только
   вид + блокировка повторной отправки в JS. */
.is-busy { position: relative; color: transparent !important; pointer-events: none; }
.is-busy::after {
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 16px; height: 16px; margin: -8px 0 0 -8px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  color: var(--on-primary); animation: spin .6s linear infinite;
}
.btn:not(.primary).is-busy::after, .mini.is-busy::after { color: var(--text); }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .is-busy::after { animation-duration: 1.8s; }
  .is-press { transform: none !important; }
}
/* Тонкая полоска прогресса вверху на время перехода между страницами. Пока
   сервер думает, человек должен видеть, что нажатие принято. */
#navbar { position: fixed; left: 0; top: 0; height: 2px; width: 0; z-index: 90;
          background: var(--primary); opacity: 0;
          transition: width .25s ease, opacity .25s ease; }
#navbar.on { opacity: 1; }

/* Плашка-подтверждение. Появляется снизу, над нижней панелью, гаснет сама.
   Раньше после «Сохранить» человек видел только вернувшуюся страницу и не мог
   понять, записалось ли: Игорь жаловался ровно на это — «нажал, ничего не
   произошло». Плашку показывает TOAST_JS по параметру в адресе (?ok=/?err=). */
#toast { position: fixed; left: 50%; bottom: calc(78px + var(--sab));
  transform: translate(-50%, 10px); z-index: 120;
  max-width: min(92vw, 420px); padding: 12px 16px; border-radius: 12px;
  background: var(--surface-2); color: var(--text); border: 1px solid var(--border);
  box-shadow: 0 10px 28px rgba(0, 0, 0, .38); font-size: 15px; line-height: 1.35;
  opacity: 0; pointer-events: none; transition: opacity .2s ease, transform .2s ease; }
#toast.on { opacity: 1; transform: translate(-50%, 0); }
#toast.fail { border-color: color-mix(in srgb, var(--danger) 55%, var(--border)); }
#toast .tick { color: var(--accent); font-weight: 700; margin-right: 6px; }

/* Несколько кнопок-форм в ряд. Каждая кнопка — своя форма (иначе одна отправка
   не отличила бы «переименовать» от «удалить»), а формы блочные и вставали бы
   столбиком во всю ширину. */
form.inline { display: inline; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.btn-row:empty { margin-top: 0; }

/* Личный адрес приёма данных: длинная строка с токеном, которую переписывают в
   приложение на телефоне. Переносим по любому символу — иначе она вылезает за
   край экрана и половину адреса не видно. */
.code-line { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px;
             background: var(--surface-2); border: 1px solid var(--border);
             border-radius: 10px; padding: 10px; margin: 10px 0;
             overflow-wrap: anywhere; user-select: all; }

.chip { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px;
        border: 1px solid var(--border); }

/* Переключатель «Авто / Показывать / Скрыть» на странице настроек. Три
   положения в одну строку: на телефоне они уезжают под название раздела, иначе
   подпись раздела сжималась до «Трен…». */
.seg { display: inline-flex; flex: 1 1 100%; border: 1px solid var(--border);
       border-radius: 10px; overflow: hidden; margin-top: 2px; }
.seg label { flex: 1; display: flex; align-items: center; justify-content: center;
             min-height: 44px; cursor: pointer; font-size: 13px; color: var(--muted); }
.seg label + label { border-left: 1px solid var(--border); }
.seg input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.seg input:checked + span { color: var(--primary); font-weight: 600; }
.seg label:active { background: var(--surface-2); }
.sec-row { flex-wrap: wrap; }
.chip.ok { color: var(--accent); } .chip.warn { color: var(--warn); } .chip.fail { color: var(--danger); }

/* Цветные бейджи типа разбора в общем списке отчётов */
.badge { display: inline-block; flex: 0 0 auto; padding: 2px 9px; border-radius: 999px;
         font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
         border: 1px solid transparent; }
/* Периодичность — не оценка: зелёный и жёлтый здесь читались как «в норме»
   и «перебор». Различаем насыщенностью основного цвета, а не смыслом. */
.badge.daily   { color: var(--primary); background: color-mix(in srgb, var(--primary) 14%, transparent); border-color: color-mix(in srgb, var(--primary) 40%, transparent); }
.badge.weekly  { color: var(--muted);   background: color-mix(in srgb, var(--muted) 12%, transparent);   border-color: color-mix(in srgb, var(--muted) 32%, transparent); }
.badge.monthly { color: var(--muted);   background: transparent;                                          border-color: var(--border); }
.row .badge { margin-right: 2px; }

.tabs { display: flex; gap: 8px; margin-bottom: 12px; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.tab { flex: 0 0 auto; padding: 7px 14px; border-radius: 999px; font-size: 13px; font-weight: 600;
       border: 1px solid var(--border); color: var(--muted); background: transparent; text-decoration: none;
       transition: background .18s ease, color .18s ease; }
.tab.active { background: var(--primary); color: var(--on-primary); border-color: transparent; }
.tab .cnt { opacity: .75; font-weight: 400; margin-left: 4px; }

.daynav { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 16px; }
.daynav .row { justify-content: center; gap: 6px; font-size: 15px; color: var(--muted); }
.daynav .row:last-child { justify-content: center; }
.empty { text-align: center; color: var(--muted); padding: 48px 16px; }
.row.next { border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary) inset; }
.step { width: 26px; height: 26px; flex: 0 0 26px; border-radius: 50%; display: flex;
        align-items: center; justify-content: center; font-size: 13px; font-weight: 600;
        background: var(--surface-2); color: var(--muted); }
.note { color: var(--muted); font-size: 13px; margin: 8px 2px 0; }
.howto { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
         padding: 14px; font-size: 14px; line-height: 1.6; margin-bottom: 16px; }
/* Инструкция подключения: нумерованные шаги должны читаться, а не слипаться
   в абзац — раньше это был текст через <br>, и человек в нём тонул. */
.steps { margin: 0 0 12px; padding-left: 20px; display: flex; flex-direction: column; gap: 8px; }
.steps li { padding-left: 2px; }
.steps li b { font-weight: 600; }
.steps a { color: var(--primary); }
.cta-row { margin: 12px 0 16px; }
.cta-row .btn { display: inline-flex; align-items: center; justify-content: center;
                text-decoration: none; padding: 0 18px; height: 48px; }
.note b { color: var(--text); }
.plan { color: var(--muted); font-size: 13px; line-height: 1.4; }
.field .plan:first-of-type { margin: -2px 0 2px; }
.ex-grid { display: grid; gap: 12px; }
@media (min-width: 1024px) { .ex-grid { grid-template-columns: 1fr 1fr; } }
table.data.mini { font-size: 13px; }
table.data.mini th, table.data.mini td { padding: 6px 8px; }
table.data.mini td.reps-cell { font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.ex-card .btn { align-self: flex-start; min-height: 44px; font-size: 14px; }
.ex-card { min-width: 0; }
.ex-card .scroll-x { max-width: 100%; }
table.data.mini { min-width: 320px; }
.ex-card { background: var(--surface); border: 1px solid var(--border);
            border-radius: var(--radius); padding: 14px; display: flex;
            flex-direction: column; gap: 8px; }
.ex-card.just-saved { border-color: var(--accent);
            box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 24%, transparent); }
.ex-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.ex-row { display: flex; gap: 8px; }
.ex-row .control { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.ex-row .control.unit-wrap { flex: 0 0 120px; }
.ex-row .control[hidden] { display: none; }
.ex-row .cap { font-size: 10px; line-height: 1.2; color: var(--muted, #888); opacity: .8;
    text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ex-row input, .ex-row select { height: 48px; padding: 0 12px; font-size: 17px;
    min-width: 0; width: 100%;
    background: var(--surface-2); color: var(--text);
    border: 1px solid var(--border); border-radius: 10px; }
.ex-type-line { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ex-type-label { font-size: 13px; color: var(--muted, #888); }
.type-pick { min-height: 40px; padding: 0 10px; font-size: 15px;
    background: var(--surface-2); color: var(--text);
    border: 1px solid var(--border); border-radius: 10px; }
.ex-type-about { font-size: 13px; color: var(--muted, #888); flex: 1 1 auto; min-width: 0; }
.reps-row { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.reps-row .rep { height: 52px; text-align: center; font-size: 18px;
    font-variant-numeric: tabular-nums; background: var(--surface-2); color: var(--text);
    border: 1px solid var(--border); border-radius: 10px; padding: 0 2px; }
.reps-row .rep:focus, .ex-row input:focus, .ex-row select:focus {
    border-color: var(--primary); outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent); }
/* Задание и факт раньше шли одним серым текстом и слипались: план принимали
   за историю. Задание — выделенный блок с подписью, факт — строка мельче. */
.task { border-radius: 12px; padding: 10px 12px; margin-top: 2px;
        background: color-mix(in srgb, var(--primary) 7%, var(--surface-2));
        border: 1px solid color-mix(in srgb, var(--primary) 24%, var(--border)); }
.task-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.task-label { font-size: 12px; font-weight: 650; letter-spacing: .04em;
              text-transform: uppercase; color: var(--muted); }
.task-line { margin-top: 6px; font-size: 17px; font-weight: 650; line-height: 1.35;
             font-variant-numeric: tabular-nums; }
.task-why { margin-top: 4px; font-size: 12px; line-height: 1.4; color: var(--muted); }
.task-why:empty { display: none; }
/* Траектория: у тренера в таблице это колонки «План 4» и «План 5». Мелким —
   чтобы не спорить за внимание с заданием на сегодня, но на виду. */
.task-next { margin-top: 6px; font-size: 12px; line-height: 1.45; color: var(--muted);
             font-variant-numeric: tabular-nums; opacity: .85; }
.task-next:empty { display: none; }
.task-next b { font-weight: 600; color: var(--text); opacity: .8; }
.task-more { margin-top: 6px; border-top: 1px dashed var(--border); }
/* Ссылка на инструкцию к упражнению: внизу раскрывашки «Почему · как дальше».
   Отдельной строкой с отбивкой, чтобы читалась как действие. */
.task-link { display: block; margin-top: 10px; padding-top: 10px;
             border-top: 1px dashed var(--border); }
.task-link a { display: inline-block; font-size: 13px; font-weight: 600;
               color: var(--primary); text-decoration: none; }
.task-link a:active { opacity: .7; }
.task-more summary { cursor: pointer; font-weight: 500; font-size: 12.5px; color: var(--muted);
  padding: 7px 0 2px; list-style: none;
  text-decoration: underline dotted; text-underline-offset: 4px; }
.task-more summary::-webkit-details-marker { display: none; }
.task-more summary::after {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-left: 7px;
  border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
  transform: rotate(45deg); transform-origin: center; vertical-align: 1px;
  transition: transform .18s ease; opacity: .8; }
.task-more[open] summary::after { transform: rotate(-135deg); }
.task-more[open] summary { color: var(--text); padding-bottom: 4px; }
.task-more[open] .mode-about, .task-more[open] .task-why, .task-more[open] .task-next { opacity: 1; }

/* Совет по режиму: предложение, а не переключение. Поэтому отдельной плашкой
   с причиной — без причины советом никто не воспользуется. */
.task-advice { margin-top: 8px; padding: 8px 10px; border-radius: 10px; font-size: 12.5px;
               line-height: 1.45; color: var(--text);
               background: color-mix(in srgb, var(--warn) 12%, var(--surface));
               border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--border)); }
.task-advice:empty, .task-advice[hidden] { display: none; }
.task-advice b { color: var(--warn); }
.mode-pick { margin-left: auto; min-height: 44px; padding: 0 8px; border-radius: 10px;
             font-size: 13px; max-width: 100%;
             background: var(--surface); color: var(--text); border: 1px solid var(--border); }
.mode-pick:focus { border-color: var(--primary); outline: none;
                   box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent); }
/* Кнопка «Применить» нужна только без JS: со скриптом режим уезжает сам. */
.js .mode-apply { display: none; }
/* Что за режим и когда его брать. Четыре режима на память не держат, а без
   расшифровки «Силовая» и «Восстановление» читаются как одно и то же. */
.mode-about { margin-top: 6px; padding-top: 6px; font-size: 12px; line-height: 1.45;
              color: var(--muted);
              border-top: 1px dashed color-mix(in srgb, var(--primary) 25%, var(--border)); }
.mode-about:empty { display: none; }
.was { font-size: 13px; line-height: 1.4; color: var(--muted);
       font-variant-numeric: tabular-nums; }
.save-mark { flex: 0 0 auto; text-align: right; }
.save-mark .chip { white-space: nowrap; }
.howto code { background: var(--surface-2); padding: 2px 6px; border-radius: 6px;
              font-size: 13px; font-family: ui-monospace, SFMono-Regular, monospace; }
/* Правка состава тренировки: порядок и «убрать». Кнопки мелкие по смыслу, но
   не по площади — палец в зале попадает по 44px, а не по иконке. */
.ex-tools { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 2px; }
.mini { min-height: 44px; min-width: 44px; padding: 0 14px; border-radius: 10px;
        font-size: 13px; font-weight: 550; cursor: pointer; white-space: nowrap;
        background: var(--surface-2); color: var(--muted);
        border: 1px solid var(--border); transition: background .18s ease, color .18s ease; }
.mini.edit { width: 68px; display: inline-flex; align-items: center; justify-content: center; }
.mini:hover:not(:disabled) { background: var(--surface); color: var(--text); }
.mini:active:not(:disabled) { transform: scale(.96); }
.mini:disabled { opacity: .35; cursor: default; }
.row .mini { flex: 0 0 auto; }
/* Скрытая первая кнопка формы: Enter в поле должен сохранять тренировку,
   а не срабатывать на первую попавшуюся стрелку порядка. */
.hidden-submit { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
                 overflow: hidden; clip: rect(0 0 0 0); border: 0; }

.form { display: flex; flex-direction: column; gap: 14px; margin-top: 8px; }
.field { display: flex; flex-direction: column; gap: 6px; }
.field label { font-size: 14px; color: var(--muted); }
.field .hint { color: var(--muted); opacity: .75; font-size: 13px; }
.field input, .field select {
  height: 50px; padding: 0 14px; font-size: 17px; color: var(--text);
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  transition: border-color .18s ease;
}
.field input:focus, .field select:focus {
  border-color: var(--primary); outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent);
}
.btn.wide { width: 100%; margin-top: 8px; }
.notice { padding: 12px 14px; border-radius: 12px; margin-bottom: 12px;
          background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }
.notes { margin: 12px 0 0; padding-left: 20px; color: var(--muted); font-size: 14px; }
.notes li { margin-bottom: 6px; }
.chart { background: var(--surface); border: 1px solid var(--border);
         border-radius: var(--radius); padding: 14px; color: var(--primary); }
.chart svg { width: 100%; height: 160px; display: block; }
table.data tr.avg td { background: var(--surface-2); font-weight: 600;
                       border-bottom: 2px solid var(--border); }
table.data td.fit { color: var(--accent); }
table.data td.low { color: var(--danger); }
table.data td.high { color: var(--warn); }
table.data tr.today td { background: color-mix(in srgb, var(--primary) 10%, transparent); }
table.data td.note-cell { white-space: normal; min-width: 180px; color: var(--muted); font-size: 13px;
                          text-align: left; }
.dim { opacity: .35; }
.chart-values { display: flex; justify-content: space-between; margin-top: 4px;
                 font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; }
.chart-legend { display: flex; justify-content: space-between; margin-top: 8px;
                color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }


nav {
  flex: 0 0 auto; z-index: 40;
  display: flex; justify-content: center; gap: 4px;
  padding: 6px 12px calc(6px + var(--sab));
  background: var(--surface);
  border-top: 1px solid var(--border);
  /* Панель строго по ширине окна: без этого на айфоне она выезжала за края
     и выглядела тёмной полосой шире экрана. */
  width: 100%; max-width: 100vw; box-sizing: border-box;
}
nav a {
  flex: 1; max-width: 140px; min-height: 48px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 2px;
  color: var(--muted); text-decoration: none; font-size: 12px; border-radius: 12px;
  transition: color .18s ease, background .18s ease;
}
nav a[aria-current="page"] { color: var(--primary); background: var(--surface-2); }

/* Кнопка «Меню» в нижней панели: выглядит и ведёт себя как соседние вкладки.
   Высота и разметка те же — иначе она выбивалась бы из ряда. */
nav .nav-menu-btn {
  flex: 1; max-width: 140px; min-height: 48px; width: auto; height: auto;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; border: 0; border-radius: 12px; background: transparent;
  color: var(--muted); font-size: 12px; font-family: inherit;
  cursor: pointer; transition: color .18s ease, background .18s ease;
}
nav .nav-menu-btn:hover { background: var(--surface-2); }
nav .nav-menu-btn:active { transform: scale(.96); }
nav .nav-menu-btn[aria-expanded="true"] { color: var(--primary); background: var(--surface-2); }

/* Бургер: полный список разделов. Выезжает справа, поверх всего, с затемнением
   под ним — чтобы промах пальцем закрывал панель, а не жал ссылку под ней. */
.menu-back { position: fixed; inset: 0; z-index: 60; background: rgba(0,0,0,.45); }
.menu {
  position: fixed; z-index: 61; top: 0; right: 0; bottom: 0; width: min(88vw, 340px);
  background: var(--surface); border-left: 1px solid var(--border);
  /* Сверху — отступ под строку состояния телефона: без него заголовок «Все
     разделы» уходил под часы. Снизу панель Меню перекрывает контент, поэтому
     отступ под неё, иначе последний пункт не доскроллить. */
  /* Снизу — место под нижнюю панель и домашнюю черту: иначе последние
     пункты списка («Выйти») уходят под панель и не доскролливаются. */
  /* Сверху — место под строку состояния: меню начинается от top:0, и без
     отступа у контейнера шапка уезжала под часы и батарею. Минимум 48px —
     статус-бар iPhone с бровью (--sat в режиме с домашнего экрана равен 0). */
  padding: max(48px, calc(12px + var(--sat))) 12px calc(84px + var(--sab));
  overflow-y: auto; -webkit-overflow-scrolling: touch;
  transform: translateX(100%); transition: transform .2s ease;
  display: flex; flex-direction: column;
}
.menu.open { transform: translateX(0); }
.menu-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 17px; z-index: 2;
  background: var(--surface);
  /* Верхний отступ даёт контейнер .menu — здесь только боковые поля. */
  padding: 0 4px 12px;
}
.menu-group { border-top: 1px solid var(--border); padding: 8px 0; }
.menu-group:first-of-type { border-top: 0; }
.menu-title { padding: 6px 8px; font-size: 12px; text-transform: uppercase;
              letter-spacing: .04em; color: var(--muted); }
.menu-item {
  display: flex; align-items: center; gap: 12px; min-height: 48px; padding: 0 8px;
  border-radius: 12px; color: var(--text); text-decoration: none; font-size: 16px;
}
.menu-item svg { flex: 0 0 auto; color: var(--muted); }
.menu-item.on { background: var(--surface-2); color: var(--primary); }
.menu-item.on svg { color: var(--primary); }
body.menu-open { overflow: hidden; }
svg { width: 22px; height: 22px; fill: none; stroke: currentColor;
      stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* Десктоп: боковое меню вместо нижней панели. На телефоне одной рукой удобнее
   нижняя, на большом экране она выглядит инородно и крадёт высоту. */
@media (min-width: 1024px) {
  /* На большом экране меню — боковое и фиксированное, прокрутка возвращается
     документу: внутренний скроллер нужен только телефону. */
  html { height: auto; overflow: visible; }
  body, html.kb body { display: block; position: static; height: auto; overflow: visible;
         top: auto; bottom: auto; padding: 24px 24px 24px 248px; }
  .wrap { max-width: 1200px; overflow: visible; padding: 0; }
  nav {
    position: fixed; left: 0; top: 0; bottom: 0; right: auto; width: 224px; flex-direction: column;
    justify-content: flex-start; gap: 4px; padding: 24px 12px;
    border-top: 0; border-right: 1px solid var(--border); backdrop-filter: none;
    background: var(--surface);
  }
  nav::before {
    content: "Здоровье"; display: block; padding: 0 12px 16px;
    font-size: 17px; font-weight: 700; color: var(--text); letter-spacing: -.01em;
  }
  nav a { flex: 0 0 auto; max-width: none; width: 100%; min-height: 44px;
          flex-direction: row; justify-content: flex-start; gap: 12px;
          padding: 0 12px; font-size: 15px; }
  nav a span { font-size: 15px; }
  .cards { grid-template-columns: repeat(4, 1fr); gap: 14px; }
  .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
}

@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* Альбомная ориентация на телефоне. Веб не умеет запретить поворот: iOS
   игнорирует и manifest orientation, и screen.orientation.lock — работает
   только у Android в standalone. Поэтому в альбоме на низком экране каркас
   прячем и показываем просьбу повернуть: интерфейс не разъезжается, а
   человек возвращается в портрет. Порог 500px по высоте отсекает планшеты и
   десктоп — у айфона в альбоме высота 390-430. */
/* Телефон повернули — мы не просим повернуть обратно, а сами держим портрет:
   каркас разворачивается на 90°, и человек видит тот же вертикальный экран.
   Раньше здесь была заглушка «поверните телефон» — она останавливала работу
   посреди подхода из-за случайного поворота в зале.

   Класс html.rot ставит скрипт: он знает и про сенсор, и про размеры окна.
   Через чистый медиазапрос это не выразить — на компьютере маленькое окно
   тоже бывает низким, а разворачивать там нечего. */
html.rot { overflow: hidden; }
html.rot body, html.rot.kb body {
  position: fixed; top: 0; left: 100dvw; right: auto; bottom: auto;
  width: 100dvh; height: 100dvw;
  transform: rotate(90deg); transform-origin: 0 0;
}
/* Заглушка остаётся в разметке ради старых браузеров без поддержки поворота,
   но при работающем развороте не показывается никогда. */
/* Личная ссылка в настройках: длинный ключ переносится, а не растягивает
   страницу вбок. Моноширинный шрифт — чтобы его можно было сверить глазами. */
/* Строка поиска по списку. Держится сверху, пока листаешь: в справочнике
   почти сотня карточек, и возвращаться к строке прокруткой — лишняя работа. */
/* Не липкая: липкая полоса наезжала на заголовок карточки и читалась как
   поломка. Строка стоит над списком — этого достаточно. */
.find-box { margin: 10px 0 8px; }
.find-box .find { width: 100%; }
.find-box .hint { display: block; margin-top: 4px; min-height: 16px; }

.card > .hint { font-size: 13px; line-height: 1.5; color: var(--muted); opacity: .9; }

.link-box { margin: 6px 0 10px; padding: 8px 10px; border-radius: var(--r-s, 10px);
            background: var(--surface-2); border: 1px solid var(--border); }
.link-box code { font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace;
                 color: var(--text); overflow-wrap: anywhere; }

.rotate-lock { display: none; }
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  html:not(.rot) body > .wrap, html:not(.rot) body > nav,
  html:not(.rot) body > .menu, html:not(.rot) body > .menu-back { display: none !important; }
  html:not(.rot) .rotate-lock {
    display: flex; flex-direction: column; align-items: center;
    justify-content: center; gap: 14px; text-align: center;
    position: fixed; inset: 0; padding: 24px;
    background: var(--bg); color: var(--text); z-index: 9999;
  }
  .rotate-lock svg { width: 44px; height: 44px; stroke: var(--primary); }
  .rotate-lock strong { font-size: 18px; }
  .rotate-lock span { color: var(--muted); font-size: 14px; max-width: 320px; }
}


.auth { max-width: 400px; margin: 10vh auto 0; }
.auth h2 { font-size: 22px; margin: 0 0 6px; text-align: center; }
.auth p.sub { margin: 0 0 24px; text-align: center; color: var(--muted); font-size: 15px; }
.auth p.sub b { color: var(--text); }
.auth label { display: block; font-size: 14px; color: var(--text); margin-bottom: 8px;
              font-weight: 500; }
.auth input {
  width: 100%; height: 52px; padding: 0 14px; font-size: 17px; color: var(--text);
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  transition: border-color .18s ease;
}
.auth input:focus { border-color: var(--primary); outline: none;
                    box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 22%, transparent); }
/* Код одним полем, но с широкими промежутками — читается как ячейки. */
.auth input.code { text-align: center; letter-spacing: 12px; font-size: 26px;
                   font-variant-numeric: tabular-nums; padding-left: 12px; }
.auth button {
  width: 100%; height: 52px; margin-top: 16px; font-size: 17px; font-weight: 600;
  color: var(--on-primary); background: var(--primary); border: 0; border-radius: 12px;
  cursor: pointer; transition: opacity .18s ease, transform .18s ease;
}
.auth button:hover { opacity: .92; }
.auth button:active { transform: scale(.99); }
.auth button:disabled { opacity: .45; cursor: default; }
.auth .hint { color: var(--muted); font-size: 13px; margin-top: 16px; text-align: center;
              line-height: 1.5; }
.auth .error { color: var(--danger); font-size: 14px; margin-top: 12px; text-align: center; }
.auth a { color: var(--primary); }
/* Действия под формой кода: повтор с таймером и смена почты. */
.auth .actions { display: flex; flex-direction: column; gap: 6px; margin-top: 6px;
                 align-items: center; }
.auth .actions button.ghost {
  width: 100%; margin-top: 8px; font-size: 15px; font-weight: 500;
  padding: 14px; border-radius: 12px; border: 1px solid var(--border);
  background: transparent; color: var(--primary); cursor: pointer;
}
.auth .actions button.ghost:disabled { color: var(--muted); cursor: default; opacity: 1; }
.auth .actions a { font-size: 15px; text-decoration: none; padding: 8px; }
