/* Токены — в tokens.css (подключается первым в index.html). Здесь остаётся
   только то, что не входит в общую систему. */
/* Глобальный guard «меньше движения» — пакет 5, п.6, 11.08. index.css грузят
   ВСЕ пять страниц, а анимации без причины (pulseGlow/mg-blink/spin/mg-slide/
   anchorFlash — все определены ниже в этом файле) раньше гасились только
   такой же копией правила в ai.css/fuelplan.css. Эти два листа подключены не
   везде (на /health и /profile их нет вовсе, хотя anchor-flash там реально
   срабатывает — переход по якорю сайдбара есть на всех пяти страницах через
   общий app.js), поэтому пять экранов без ai.css/fuelplan.css оставались без
   защиты. Правило то же самое, что и в ai.css (не переименовывалось). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration:0.01ms !important; animation-iteration-count:1 !important;
    transition-duration:0.01ms !important; scroll-behavior:auto !important;
  }
}
    * { box-sizing:border-box; }
    /* B1.3 → Д2 (ТЗ-typography-and-plan): измеренное — Onest с
       tabular-nums, не отдельная моноширинная гарнитура (решение
       ревьюера Open §1 = A). Метрики сессии, БЖУ/вода, веса, сезонная
       статистика, пилюли зон. */
    .chip b, .fcell b, td.num, .chips b,
    .heat-cell .hc-val, .hs-stats, .fs-cell > b,
    .trend-card .tc-big, .pc-stat b, .season-stats b,
    .sc-item .sc-val, .sc-form b, .z-w, .z-pct, .z-code {
      font-family:var(--font-num);
      font-variant-numeric:tabular-nums lining-nums;
      font-weight:inherit;
    }
    body { margin:0; font-size:var(--fs-md); line-height:1.55; font-family:var(--font-sans);
           background:var(--bg); color:var(--ink); -webkit-font-smoothing:antialiased;
           overflow-x:clip; }   /* страховка от горизонтального переполнения (не ломает sticky) */
    .chip b, .fcell b, td.num, .chips b { font-variant-numeric:tabular-nums lining-nums; }
    a { color:inherit; text-decoration:none; }

    /* прилипающая шапка */
    .sticky { position:sticky; top:0; z-index:30; background:var(--bg);
              padding:var(--sp-3) 0 var(--sp-3); margin-bottom:var(--sp-4); border-bottom:1px solid transparent;
              transition:border-color var(--transition-fast); }
    /* B1.4: было box-shadow (на тёмном читается как грязь, не как подъём) —
       границу «прилипшей» шапки теперь даёт линия, а не тень. */
    .sticky.stuck { border-bottom-color:var(--pl); }

    /* П5.4: ОДНО определение карточки на весь продукт. Раньше их было три —
       .card, .hero-card и .trend-card, причём два последних побайтно совпадали,
       а .card отличался только именем токена фона (--card и --panel дают один и
       тот же цвет). Разные имена одного и того же расходятся при первой же
       правке: чинишь отступ в одном месте, а на двух страницах он прежний. */
    .card, .hero-card, .trend-card {
            background:var(--card); border:1px solid var(--line); border-radius:var(--r-md);
            padding:var(--sp-4); }
    .card { margin-bottom:var(--sp-4); }
    .card.err { background:#3a1d1d; border-color:#5a2a2a; color:#ffd2c8; }
    /* Заголовки карточек — h3 (h2 — заголовки секций .sec-h/.hero-h/.pl-h).
       Аудит №13, ТЗ-4: раньше все они были div, и скринридер получал плоскую
       простыню из одного h1 без единого h2/h3. Тег сменился, ВИД — нет:
       font-size задан явно, иначе браузер применил бы дефолт h3. */
    .ttl { display:flex; align-items:center; gap:8px; font-weight:700; margin:0 0 var(--sp-1);
           font-size:var(--fs-base); }
    .ttl small { color:var(--mut); font-weight:500; font-size:var(--fs-xs); margin-left:auto; }
    .muted { color:var(--mut); font-size:var(--fs-sm); }

    label { display:block; font-weight:600; margin:0 0 var(--sp-2); font-size:var(--fs-sm); }
    input[type=date], input[type=text], input[type=number], select {
            width:100%; min-height:44px; padding:var(--sp-3) var(--sp-3); border-radius:var(--r-sm); border:1px solid var(--line);
            background:var(--card2); color:var(--ink); font-size:var(--fs-base); }
    /* select без кастомной обёртки (на случай, если JS не пришёл) — своя стрелка вместо браузерной */
    select { appearance:none; -webkit-appearance:none; background-image:none; padding-right:36px; }
    /* minmax(0,1fr), не просто 1fr: голый 1fr = minmax(auto,1fr) — трек не
       сжимается уже своего контента (input/label), и на узких телефонах
       колонка .col2 вылезала за экран (Б10, 06.10: camp-create 334px при
       вьюпорте 320). minmax(0,…) разрешает треку сжаться до нуля — внутренние
       input/label и так имеют width:100%, переносу/эллипсису ничего не мешает. */
    .grid { display:grid; gap:8px; grid-template-columns:repeat(4,minmax(0,1fr)); }
    .grid .col2 { grid-column:span 2; }

    /* ── КАСТОМНЫЙ ВИД <select> ("витрина" в стиле карточек) ──────────
       Сам <select> остаётся поверх и прозрачным — клавиатуру, чтение
       скринридером и мобильный тап-пикер обслуживает настоящий select
       (никакой самодельной ARIA-логики, ноль риска что-то сломать).
       Снизу — стилизованный «фасад», который просто отражает текущий
       выбор. Работает одинаково на десктопе и мобиле: на телефоне тап
       по прозрачному select всё равно открывает нативный ОС-пикер —
       то есть на мобиле поведение остаётся полностью нативным. */
    .csel { position:relative; display:block; }
    .csel select.csel-native { position:absolute; inset:0; width:100%; height:100%;
            min-height:0; margin:0; padding:0; opacity:0; cursor:pointer; z-index:2; }
    .csel-face { display:flex; align-items:center; justify-content:space-between; gap:8px;
            width:100%; min-height:44px; padding:var(--sp-3) var(--sp-3); border-radius:var(--r-sm);
            border:1px solid var(--line); background:var(--card2); color:var(--ink);
            font-size:var(--fs-base); font-weight:400; line-height:1.3; }
    /* Долг-находка TZ-redesign-sections-en.md: без min-width:0 на флекс-
       элементе и overflow:hidden текст длинного значения (напр. «Пояс
       старта» → часовой пояс "America/Los_Angeles") не ужимался — флекс-
       родитель .csel-face растягивался по высоте вместо того, чтобы обрезать
       строку (на 500px — до пяти строк). Один видимый ряд + эллипсис, сама
       опция внутри нативного select остаётся полной (это только витрина). */
    .csel-face-label { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0; flex:1 1 auto; }
    .csel-arrow { flex:0 0 auto; width:16px; height:16px; color:var(--mut); transition:transform var(--transition-fast), color var(--transition-fast); }
    .csel:hover .csel-face { border-color:var(--mut); }
    .csel select.csel-native:focus-visible ~ .csel-face,
    .csel:focus-within .csel-face { border-color:var(--acc); outline:2px solid var(--acc); outline-offset:2px; }
    .csel:focus-within .csel-arrow { color:var(--acc); transform:rotate(180deg); }
    /* внутри label-обёртки текст названия поля не должен слипаться с селектом */
    label > .csel { margin-top:var(--sp-2); }
    @media (max-width:480px){ .grid { grid-template-columns:repeat(2,minmax(0,1fr)); } }
    /* ⛔ Пункт 7 приёмки редизайна «Сегодня»: глобальный переход на Manrope
       (addendum 07.10) чуть шире Onest на тех же кеглях — на 500px «Максимальный
       пульс» переставал влезать в четверть сетки и наезжал на «Пол» (найдено
       скриншотом /profile). Минимальная правка: тот же откат на 2 колонки,
       только порог чуть выше (520 вместо 480) — самая длинная подпись решает. */
    @media (max-width:520px){ .grid { grid-template-columns:repeat(2,minmax(0,1fr)); } }

    /* ── ДОСТУПНОСТЬ: фокус с клавиатуры и тап-цели (аудит №13, ТЗ-4) ──────
       Было: два правила :focus на весь дашборд и НИ ОДНОГО на /passport —
       пройти страницу с клавиатуры вслепую. Обводка контуром (outline), а не
       тенью: не сдвигает вёрстку и видна на любом фоне карточек. */
    :where(button, .btn, a, input, select, textarea, summary, [tabindex]):focus-visible {
      outline:2px solid var(--acc); outline-offset:2px; border-radius:var(--r-sm); }
    /* Чекбокс — 20×20 в строке ≥44px: пальцем по 13×13 не попасть. */
    .opt-check { display:flex; align-items:center; gap:8px; font-weight:400; margin:0;
                 min-height:44px; cursor:pointer; }
    .opt-check input[type=checkbox] { width:24px; height:24px; min-height:0; flex:none;
                                      accent-color:var(--acc); cursor:pointer; }

    /* ── КНОПКИ: один primary + токены secondary/ai/ghost (без инлайн-хексов) ─ */
    /* Заливка первичной кнопки идёт через --btn-bg/--btn-fg, а не напрямую из
       --acc: так демо-режим гасит ВСЕ первичные кнопки разом, переопределив две
       переменные на <body>, и не воюет за специфичность с .btn-soft/.ghost/
       .btn-ai (у них своя заливка, они это переопределение не видят). */
    button, .btn { border:0; border-radius:var(--r-md); background:var(--btn-bg,var(--acc)); color:var(--btn-fg,var(--on-acc));
             font-weight:700; font-size:var(--fs-base); padding:var(--sp-3) var(--sp-4); cursor:pointer;
             display:inline-flex; align-items:center; justify-content:center; gap:8px; line-height:1.2; }
    button:hover, .btn:hover { filter:brightness(1.08); }
    button.full, .btn.full { width:100%; margin-top:var(--sp-3); }
    .btn-sm { font-size:var(--fs-xs); padding:var(--sp-3) var(--sp-4); }
    /* вторичная — нейтральная панель */
    .btn-soft { background:var(--elev); color:var(--ink); border:1px solid var(--line); }
    .btn-soft:hover { filter:none; border-color:var(--mut); }
    /* вторичная-обводка и «тихая» (аудит №14: три вида кнопок, ОДНА первичная
       на экран — иначе три одинаковых серых подряд, и глазу не за что зацепиться) */
    .btn-outline { background:transparent; color:var(--ink); border:1px solid var(--ink); }
    .btn-outline:hover { filter:none; background:var(--elev); }
    .btn-quiet { background:transparent; color:var(--mut); border:0; font-weight:600;
                 padding:var(--sp-3) var(--sp-2); }
    .btn-quiet:hover { filter:none; color:var(--ink); text-decoration:underline; }
    /* действия ИИ/директора — холодный синий тон */
    .btn-ai { background:#16202e; color:var(--ink); border:1px solid #243246; }
    .btn-ai:hover { filter:none; border-color:#33486a; }
    /* «Горящая» кнопка разбора: тренировка есть, разбора ещё нет */
    .btn-analyze { background:var(--btn-bg,var(--acc)); font-size:var(--fs-md); padding:var(--sp-4) var(--sp-4);
                   animation:pulseGlow 1.8s ease-in-out infinite; }
    /* B1.4: было пульсирующим box-shadow (тень на тёмном = грязь, не привлечение
       внимания) — тот же «дыши, жми меня» сигнал теперь лёгким масштабом. */
    @keyframes pulseGlow {
      0%,100% { transform:scale(1); }
      50%     { transform:scale(1.035); }
    }
    .btnrow { display:flex; gap:8px; justify-content:flex-end; align-items:center; margin-top:var(--sp-3); }
    .tbtn { background:transparent; border:1px solid var(--line); color:var(--mut);
            font-size:var(--fs-xs); font-weight:600; padding:var(--sp-2) var(--sp-3); border-radius:var(--r-sm); }
    .tbtn:hover { background:var(--card2); color:var(--ink); filter:none; }
    .tbtn.danger:hover { border-color:#5a2a2a; color:#ffb3a3; }
    /* «Удалить» — приглушённая иконка-корзина без текста (не постоянно на виду,
       как раньше), «Повторить» — текстовая кнопка (желанное действие, его видно). */
    .tbtn.icon-only { border:0; padding:0; width:32px; height:32px; border-radius:var(--r-sm);
                       display:inline-flex; align-items:center; justify-content:center; }
    .tbtn.icon-only .icon { width:16px; height:16px; }
    .tbtn.icon-only.danger:hover { background:rgba(90,42,42,.35); }

    /* ── СТИЛИЗОВАННЫЙ ВЫБОР ФАЙЛА (нативный input спрятан) ───────────── */
    .file-hidden { position:absolute; width:1px; height:1px; padding:0; margin:-1px;
                   overflow:hidden; clip:rect(0,0,0,0); border:0; }
    .file-trigger { cursor:pointer; }
    .file-name { display:block; color:var(--mut); font-size:var(--fs-xs); margin-top:var(--sp-2); min-height:1em; }

    /* сворачиваемые строки */
    .row { background:var(--card); border:1px solid var(--line); border-radius:var(--r-md); margin-bottom:var(--sp-3); }
    .row > summary { display:flex; align-items:center; gap:8px; padding:var(--sp-4); cursor:pointer;
                     font-weight:700; list-style:none; }
    .row > summary::-webkit-details-marker { display:none; }
    .row > summary .sub { color:var(--mut); font-weight:500; font-size:var(--fs-xs); margin-left:auto; }
    .row > summary .chev { color:var(--mut); transition:transform var(--transition-fast); display:inline-flex; }
    .row[open] > summary .chev { transform:rotate(90deg); }
    .row .body { padding:0 var(--sp-4) var(--sp-4); }

    /* цель — детальные полоски */
    .bar { margin:var(--sp-3) 0; }
    .bar .lab { display:flex; justify-content:space-between; font-size:var(--fs-sm); margin-bottom:var(--sp-2); }
    .bar .lab b { font-weight:700; }
    .bar .rem { color:var(--mut); }
    .bar .rem.over { color:var(--warn); } .bar .rem.done { color:var(--good); }
    .track { height:10px; background:var(--card2); border:1px solid var(--line);
             border-radius:var(--r-full); overflow:hidden; }
    .fill { height:100%; border-radius:var(--r-full); }
    .fill.carb{background:var(--carb);} .fill.prot{background:var(--prot);} .fill.kcal{background:var(--kcal);} .fill.fat{background:var(--fat);}
    .pill { display:inline-block; padding:var(--sp-1) var(--sp-2); border-radius:var(--r-full); font-size:var(--fs-xs);
            background:var(--card2); color:var(--mut); margin:var(--sp-1) var(--sp-1) 0 0; }

    /* приём пищи — свёрнутая строка (Пакет 4, IA-аудит 07.08): время · название ·
       ккал · углеводы, ≤72 px. Раскрытие — <details class="meal"> + .body ниже,
       паддинг переехал с .meal на > summary.mh и .body (паттерн как у .row/.row
       .body выше). Заглушки .meal-pending/.meal-pending-error — НЕ <details>
       (спиннер и кнопка «Повторить» не должны сворачиваться), поэтому им
       возвращаем паддинг явно отдельным правилом. */
    .meal { background:var(--card2); border:1px solid var(--line); border-radius:var(--r-md);
            margin-bottom:var(--sp-3); }
    .meal-pending, .meal-pending-error { padding:var(--sp-4); }
    .meal > summary.mh { display:flex; align-items:center; gap:8px; padding:var(--sp-4);
            cursor:pointer; list-style:none; }
    .meal > summary.mh::-webkit-details-marker { display:none; }
    .meal[open] > summary.mh .chev { transform:rotate(90deg); }
    .meal .mh b { font-size:var(--fs-md); }
    .meal .mh .t { color:var(--mut); font-size:var(--fs-xs); white-space:nowrap; flex:0 0 auto; }
    /* Название — единственное, что тянется и обрезается многоточием (min-width:0
       обязателен, иначе flex-элемент не сжимается меньше своего контента). */
    .meal .mh .mname { flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
            white-space:nowrap; }
    /* flex-shrink:1 (не 0): при flex:0 0 auto .mnums держал полную ширину
       всегда, и на узком экране весь дефицит падал на .mname (min-width:0 у
       него же) — имя приёма пищи сжималось до clientWidth:0, то есть исчезало
       целиком (Б10, 06.10: 320 px, видно 0 из 25 символов названия). Теперь
       оба делят недостающее место, и своя многоточие при нужде получает и
       .mnums, а не только имя. */
    .meal .mh .mnums { flex:0 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis;
            white-space:nowrap; font-size:var(--fs-xs); color:var(--mut); }
    .meal .mh .mname::before, .meal .mh .mnums::before { content:"· "; color:var(--mut); font-weight:400; }
    .meal .mh .chev { flex:0 0 auto; color:var(--mut); transition:transform var(--transition-fast); display:inline-flex; }
    .meal > summary.mh .chev .icon { width:16px; height:16px; }
    .meal .body { padding:0 var(--sp-4) var(--sp-4); }
    .chips { display:flex; gap:8px; margin:var(--sp-3) 0 var(--sp-1); }
    /* 2×2-сетка на узком экране заменена компактной однострочной сводкой
       (см. .meal .chips в @media max-width:1000px ниже) — не оставляем
       промежуточный вариант, чтобы два мобильных правила не спорили друг с другом. */
    .chip { flex:1; text-align:center; background:var(--bg); border:1px solid var(--line);
            border-radius:var(--r-sm); padding:var(--sp-2) var(--sp-1); }
    .chip b { display:block; font-size:var(--fs-lg); } .chip span { color:var(--mut); font-size:var(--fs-2xs); }
    /* Вердикт дня — главный контент карточки, а не сноска. Был утоплен в холст
       (--bg) и компенсировал это оранжевой полосой слева; теперь заметность даёт
       иерархия — поднятая поверхность --s2, ради которой третий уровень и
       заводился. Радиус заодно приведён к системе (было 0 10px 10px 0). */
    .verdict { padding:var(--sp-3); background:var(--elev); border:1px solid var(--pl-soft);
               border-radius:var(--r-md); margin:var(--sp-3) 0 var(--sp-2); font-size:var(--fs-base); }
    .advice { white-space:pre-wrap; font-size:var(--fs-sm); color:#d6dae2; }
    details.tog > summary { cursor:pointer; color:var(--mut); font-size:var(--fs-xs); margin-top:var(--sp-2);
            list-style:none; user-select:none; }
    details.tog > summary::-webkit-details-marker { display:none; }
    details.tog > summary:hover { color:var(--ink); }
    .tscroll { overflow-x:auto; -webkit-overflow-scrolling:touch; max-width:100%; }
    table { width:100%; border-collapse:collapse; margin-top:var(--sp-2); font-size:var(--fs-sm); }
    th,td { text-align:left; padding:var(--sp-2) var(--sp-1); border-bottom:1px solid var(--line); }
    th { color:var(--mut); font-weight:600; }
    td.num,th.num { text-align:right; white-space:nowrap; }
    /* Канонические ключи (ai_format.conf_key) + старые русские классы —
       вторые оставлены, чтобы уже отрисованные страницы не побледнели. */
    .conf-low,.conf-низкая{color:var(--warn);} .conf-mid,.conf-средняя{color:var(--mut);}
    .conf-high,.conf-высокая{color:var(--good);}
    .conf-warn { margin-top:var(--sp-2); padding:var(--sp-2) var(--sp-3); background:rgba(224,166,59,.08);
                 border:1px solid rgba(224,166,59,.3); border-radius:var(--r-sm);
                 font-size:var(--fs-xs); color:var(--warn); }
    /* обычные блюда — повтор в один тап */
    .fm-h { margin:var(--sp-4) 0 var(--sp-2); font-weight:700; font-size:var(--fs-sm); }
    .fm-h small { color:var(--mut); font-weight:500; margin-left:var(--sp-2); }
    .fm-chips { display:flex; flex-wrap:wrap; gap:8px; }
    .fm-chips form { flex:1 1 46%; min-width:150px; display:flex; }
    .fm-chip { flex:1; min-width:0; background:var(--card2); border:1px solid var(--line); color:var(--ink);
               border-radius:var(--r-md); padding:var(--sp-2) var(--sp-3); text-align:left; font-weight:500;
               display:block; }
    .fm-chip:hover { filter:none; border-color:var(--mut); }
    .fm-chip b { display:block; font-size:var(--fs-sm); font-weight:700;
                 overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%; }
    .fm-chip span { color:var(--mut); font-size:var(--fs-2xs); }

    /* подсказки объёма при ручном вводе */
    .phints { display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin:var(--sp-2) 0 var(--sp-1); }
    .phints:empty { margin:0; }
    .phint-tip { color:var(--mut); font-size:var(--fs-xs); margin-right:var(--sp-1); }
    .phint { background:var(--card2); border:1px solid var(--line); color:var(--ink);
             font-size:var(--fs-xs); font-weight:600; padding:var(--sp-2) var(--sp-3); border-radius:var(--r-full); cursor:pointer; }
    .phint:hover { border-color:var(--acc); filter:none; }

    /* топливо */
    .fuel-grid { display:grid; grid-template-columns:repeat(4,1fr); gap:8px; margin:var(--sp-2) 0 var(--sp-3); }
    @media (max-width:480px){ .fuel-grid { grid-template-columns:repeat(2,1fr); } }

    /* вода */
    .water .ttl small { color:var(--mut); font-weight:600; }
    .wbar { height:12px; background:var(--card2); border:1px solid var(--line);
            border-radius:var(--r-full); overflow:hidden; margin:var(--sp-2) 0 var(--sp-2); }
    .wbar-fill { height:100%; background:var(--prot); border-radius:var(--r-full); transition:width var(--transition-fast); }
    .wnote { font-size:var(--fs-xs); margin-bottom:var(--sp-3); }
    .wbtns { display:flex; gap:8px; flex-wrap:wrap; }
    .wbtns form { margin:0; }
    .wbtn { padding:var(--sp-3) var(--sp-4); border-radius:var(--r-sm); border:1px solid var(--line);
            background:var(--card2); color:var(--ink); font-size:var(--fs-base); font-weight:700; cursor:pointer; }
    .wbtn:hover { border-color:var(--prot); filter:none; }
    .wbtn.ghost { background:transparent; color:var(--mut); font-weight:500; }
    .wbtn.active-rpe { background:var(--acc); color:var(--on-acc); border-color:var(--acc); }
    .wbtn.wbtn-sel { background:var(--acc); color:var(--on-acc); border-color:var(--acc); }
    /* свои бутылки */
    .bwrap { position:relative; display:inline-flex; }
    .bwrap .wbtn { padding-right:var(--sp-8); }
    .bx { position:absolute; top:-6px; right:-6px; width:20px; height:20px;
          display:inline-flex; align-items:center; justify-content:center;
          border-radius:50%; border:1px solid var(--line);
          background:var(--card); color:var(--mut); cursor:pointer; padding:0; }
    .bx .icon { width:12px; height:12px; }
    .bx:hover { color:var(--warn); border-color:var(--warn); filter:none; }
    .baddbox { margin-top:var(--sp-3); }
    .baddbox summary { color:var(--mut); font-size:var(--fs-xs); font-weight:600; cursor:pointer; list-style:none; }
    .baddbox summary::-webkit-details-marker { display:none; }
    /* «Добавить сауну» — та же складушка, но summary выглядит как полноценная
       вторичная кнопка: мелкий серый текст юзер просто не находил. Остальные
       .baddbox (гели/блюда) намеренно не трогаем — там уместен тихий текст. */
    .baddbox summary.sauna-add-btn { display:flex; align-items:center; justify-content:center;
                    gap:8px; width:100%; padding:var(--sp-3) var(--sp-4); border:1px solid var(--line);
                    border-radius:var(--r-md); background:var(--card2); color:var(--ink);
                    font-size:var(--fs-sm); font-weight:600; line-height:1.2; }
    .baddbox summary.sauna-add-btn:hover { border-color:var(--mut); }
    .baddbox[open] > summary.sauna-add-btn { border-color:var(--mut); }
    .baddform { display:flex; gap:8px; align-items:center; margin-top:var(--sp-2); flex-wrap:wrap; }
    .baddform input { width:96px; padding:var(--sp-3) var(--sp-3); border-radius:var(--r-sm); border:1px solid var(--line);
          background:var(--card2); color:var(--ink); font-size:var(--fs-base); }
    .baddform .hint { color:var(--mut); font-size:var(--fs-xs); }
    /* FTP-онбординг: «Не знаю свой FTP» (details.ftp-unknown, см. profile_fields) —
       мини-диалог из шагов .ftp-step, переключаемых JS без перезагрузки. */
    .ftp-unknown-body { margin-top:var(--sp-2); padding:var(--sp-3); background:var(--card2);
                        border:1px solid var(--line); border-radius:var(--r-md); }
    .ftp-unknown-body .wbtns form { margin:0; }
    .fcell { background:var(--card2); border:1px solid var(--line); border-radius:var(--r-sm);
             padding:var(--sp-2) var(--sp-2); text-align:center; }
    .fcell span { display:block; color:var(--mut); font-size:var(--fs-2xs); }
    .fcell b { display:block; font-size:var(--fs-lg); margin:var(--sp-1) 0; }
    .fcell small { color:var(--mut); font-size:var(--fs-2xs); }
    .frow { margin:var(--sp-2) 0; font-size:var(--fs-sm); }
    .recovery { background:rgba(47,170,106,.1); border:1px solid rgba(47,170,106,.3);
                border-radius:var(--r-md); padding:var(--sp-3) var(--sp-4); margin:var(--sp-1) 0 var(--sp-3); }
    .recovery b { color:var(--good); }

    /* погода / готовность (внутри карточек) */
    .ready-facts { margin:0 0 var(--sp-1); padding:0; font-size:var(--fs-xs); color:var(--mut); }
    .ready-facts li { list-style:none; padding:var(--sp-1) 0; }
    .ready-facts li::before { content:"· "; }
    .rf-tip { position:relative; border-bottom:1px dashed rgba(154,163,178,.4); cursor:help; }
    /* Тултип центрируем по горизонтали (left:50% + translateX(-50%)) вместо
       прижатия к левому краю: простое CSS-решение без JS-расчёта позиции,
       которое одинаково снижает риск обрезания и слева, и справа экрана.
       Для точечных случаев у самого правого края есть модификатор ниже. */
    .rf-tip::after {
      content: attr(data-tip);
      position:absolute; bottom:calc(100% + 8px); left:50%; transform:translateX(-50%);
      background:#1a1f2b; border:1px solid var(--line); border-radius:var(--r-sm);
      padding:var(--sp-3) var(--sp-3); font-size:var(--fs-2xs); line-height:1.6; color:var(--ink);
      /* pre-line, а не normal: существующие data-tip используют &#10; для явных
         переносов строк (FTP/CTL/ATL/TSB/ACWR) — pre-line сохраняет их И, в
         отличие от pre, переносит длинный текст по словам, не вылезая за max-width */
      white-space:pre-line; width:max-content; max-width:min(320px, 80vw); z-index:50;
      opacity:0; pointer-events:none; transition:opacity var(--transition-fast);
    }
    .rf-tip:hover::after, .rf-tip.show::after { opacity:1; }
    /* модификатор для элементов у правого края экрана: тултип раскрывается влево */
    .rf-tip.rf-tip-right::after { left:auto; right:0; transform:none; }
    .wchips { display:flex; flex-wrap:wrap; gap:8px; margin:var(--sp-2) 0 var(--sp-1); }
    .wchip { background:var(--card2); border:1px solid var(--line); border-radius:var(--r-sm);
             padding:var(--sp-1) var(--sp-3); font-size:var(--fs-xs); white-space:nowrap; }
    .wchip.hot  { border-color:rgba(217,162,59,.5); color:var(--warn); }
    .wchip.rain { border-color:rgba(59,130,224,.5); color:#7bb3f0; }

    /* брифинг Performance Director — та же логика поднятой поверхности, что и
       .verdict (пакет 5, пункт 2): текст ИИ-директора лежит внутри .row/.card
       (--s1), и на --card2 (=--s0, холст) он визуально ПРОВАЛИВАЛСЯ ниже
       родителя вместо того, чтобы выделяться — тот же класс несоответствия,
       что чинили в .verdict. */
    .briefing-box { background:var(--elev); border:1px solid var(--pl-soft); border-radius:var(--r-md);
                    padding:var(--sp-4) var(--sp-4); margin:var(--sp-4) 0 var(--sp-1); font-size:var(--fs-sm); line-height:1.55; }
    .briefing-box h3 { font-size:var(--fs-xs); font-weight:700; color:var(--mut); letter-spacing:.06em;
                       margin:var(--sp-4) 0 var(--sp-1); text-transform:uppercase; }
    .briefing-box h3:first-child { margin-top:0; }

    /* Разбор заезда — единственное место, где .briefing-box лежит ВНУТРИ
       .row .body (у брифинга и разбора недели .briefing-box/.wreview стоят
       прямо в карточке, без второго вложенного паддинга). .row .body уже
       даёт боковой отступ var(--sp-4); свой паддинг+бордер у .briefing-box
       поверх него на узком экране съедал ~45% ширины текста (TZ-ai-text-
       readability-en.md, п.7, скрин shot_home_debrief_mobile.png). Токены
       те же, что у .briefing-box выше — убираем только второй слой инсета. */
    @media (max-width:560px){
      .row .body .briefing-box { padding:0; border:0; border-radius:0; background:transparent; }
    }

    /* «дорогой» разбор недели/сбора (weekreport.py) — тот же .briefing-box,
       плюс .wrep: секции пронумерованы (01…06) счётчиком, а не просто капсом,
       первый абзац — лид крупнее обычного текста, буллеты — с чертой-маркером
       вместо голого markdown "*". Всё на тех же переменных темы, что и .briefing-box. */
    .wrep { padding:var(--sp-4) var(--sp-6); counter-reset:wrsec; }
    /* ТЗ-typography-and-plan Д5 «AI section heading»: было 12px капс .12em +
       мono-счётчик — две разные манеры заголовка на экране (P6 в ТЗ). Теперь
       sentence case, тот же вес, что и у .ai-full .ai-prose h4; счётчик и
       хairline-линия остаются, просто без капс-трекинга и без mono-гарнитуры. */
    .wrep h3 { display:flex; align-items:center; gap:8px; margin:var(--sp-6) 0 var(--sp-3);
               font-size:var(--fs-sm); font-weight:var(--fw-semibold); letter-spacing:var(--ls-normal);
               color:var(--ink); text-transform:none; counter-increment:wrsec; }
    .wrep h3:first-child { margin-top:0; }
    .wrep h3::before { content:counter(wrsec, decimal-leading-zero); color:var(--faint);
                       font-family:var(--font-sans); }
    .wrep h3::after { content:''; flex:1; height:1px; background:var(--line); }
    /* лид-абзац — первый вывод сразу после первого заголовка («Вердикт недели») */
    .wrep h3:first-child + div { font-size:var(--fs-xl); font-weight:var(--fw-semibold);
                                  line-height:var(--lh-snug); max-width:var(--measure-prose); }
    .wrep div { font-size:var(--fs-md); line-height:var(--lh-prose); max-width:var(--measure-prose); }
    .wrep strong { font-weight:700; color:var(--ink); }
    .wrep .wr-li { position:relative; padding-left:var(--sp-4); margin:var(--sp-2) 0;
                   font-size:var(--fs-md); max-width:var(--measure-prose); line-height:var(--lh-prose); }
    .wrep .wr-li::before { content:'–'; position:absolute; left:0; color:var(--faint);
                          font-family:var(--font-sans); }
    /* «день: ПЛАН: … | ФАКТ: …» — Open §3 → A: было строкой прозы с капс-
       лейблами и "|"-разделителем (таблица, типографски набранная прозой).
       Теперь — блок дня: день жирным, план приглушённым, факт обычным
       цветом текста, каждый на своей строке. */
    .wr-pf { margin:var(--sp-2) 0; max-width:var(--measure-prose); }
    .wr-pf-day { display:block; font-size:var(--fs-2xs); color:var(--mut); margin-bottom:2px; }
    .wr-pf-plan { color:var(--mut); font-size:var(--fs-md); line-height:var(--lh-body); }
    .wr-pf-fact { color:var(--ink); font-size:var(--fs-md); line-height:var(--lh-body); }

    /* Долг 72 (fix pass) — скелетон внутри зарезервированной высоты
       (.briefing-box[data-stream-reserve], app.js reserveStreamHeight).
       Только полосы, БЕЗ текста и БЕЗ цифр (CLAUDE.md, правило №1: не
       выдумывать содержание) — исчезает сам в момент первого настоящего
       текста (container.innerHTML='' в makeIncrementalRenderer). */
    .stream-skeleton { display:flex; flex-direction:column; gap:var(--sp-3); padding-top:2px; }
    .skel-line { height:12px; border-radius:6px; background:var(--pl-soft); }
    @media (prefers-reduced-motion: no-preference){
      .skel-line { background-image:linear-gradient(90deg, var(--pl-soft) 0%, var(--pl) 45%, var(--pl-soft) 90%);
                   background-size:200% 100%; animation:mg-skel-shimmer 1.4s ease-in-out infinite; }
      @keyframes mg-skel-shimmer { 0% { background-position:200% 0; } 100% { background-position:-200% 0; } }
    }

    /* Долг 123 — на время стрима высота бокса РОВНО data-stream-reserve
       (app.js reserveStreamHeight ставит и class, и inline height); текст
       длиннее резерва просто обрезается — снизу его прикрывает
       .stream-expand-btn (fade + подпись, см. ниже). position:relative
       только на клампнутом состоянии — кнопке нужен якорь, самому боксу
       в обычном (не клампнутом) состоянии position не нужен нигде. */
    .briefing-box.is-stream-clamped { overflow:hidden; position:relative; }
    /* Кнопка живёт ВНУТРИ зарезервированной высоты (position:absolute — не
       добавляет боксу ни пикселя, п.2 Decision). Фон — тот же токен, что и
       фон бокса (--elev), поэтому градиент честно гаснет «в фон», а не в
       случайный цвет. ⛔ Оранжевый (--acc-text) — она интерактивна (тап
       снимает потолок), см. design-orange-means-interactive. */
    .stream-expand-btn { position:absolute; left:0; right:0; bottom:0; min-height:var(--tap-min);
                          display:flex; align-items:flex-end; justify-content:center;
                          padding:28px var(--sp-4) var(--sp-2); border:0; cursor:pointer;
                          background:linear-gradient(to bottom, transparent, var(--elev) 65%);
                          color:var(--acc-text); font-weight:700; font-size:var(--fs-xs); font-family:inherit; }
    .stream-expand-btn:hover, .stream-expand-btn:focus-visible { color:var(--acc); }

    /* Долг 142 — во время самого стрима текст временно 2–3× длиннее финального
       (проза без разметки), поэтому .stream-expand-btn загоралась почти на
       каждом разборе и гасла сама, когда структура укладывалась в резерв —
       ложная подсказка «тут скрыто», с которой нечего делать. Fade — тот же
       градиент, что у кнопки, но без текста и без тапа (pointer-events:none,
       aria-hidden в разметке): просто сигнал «текст длиннее окна», кнопка
       появляется только в конце, если это и правда так (settleStreamClamp). */
    .stream-fade { position:absolute; left:0; right:0; bottom:0; height:56px;
                   pointer-events:none;
                   background:linear-gradient(to bottom, transparent, var(--elev) 65%); }

    /* стриминг ИИ-текста (брифинг/разбор тренировки/недели) — мигающая каретка */
    .stream-caret { display:inline-block; animation:mg-blink 1s step-start infinite; color:var(--faint); }
    @keyframes mg-blink { 50% { opacity:0; } }
    /* появление новой строки во время стрима — мягкое проявление без сдвига
       layout (только opacity, без transform/height), чтобы не мигало резко.
       Уважаем prefers-reduced-motion — там строка сразу видна, без анимации. */
    @media (prefers-reduced-motion: no-preference){
      .stream-line-in { animation: mg-line-in .2s ease-out; }
      @keyframes mg-line-in { from { opacity:0; } to { opacity:1; } }
    }

    /* разбор недельного плана от директора — решение штаба, та же категория
       «вердикт», что .verdict/.briefing-box (пакет 5, п.2): было на --card2
       (=--s0) внутри .planw (--s1) — тонуло вместо того, чтобы выделяться. */
    .wreview { background:var(--elev); border:1px solid var(--pl-soft); border-radius:var(--r-md);
               padding:var(--sp-3) var(--sp-4); margin:var(--sp-3) 0 var(--sp-1); font-size:var(--fs-sm); line-height:1.55; }
    .wreview .wr-day { font-weight:700; margin-top:var(--sp-3); font-size:var(--fs-sm); }
    .wreview .wr-day:first-child { margin-top:0; }
    .wreview .wr-coach { color:var(--mut); font-size:var(--fs-xs); margin:0 0; }
    /* Лид-строка «ВЕРДИКТ: …» и голый ALL-CAPS ярлык-заголовок («РАЗБОР
       ПЛАНА:» и т.п.) — ТЗ-ai-text-readability-en.md п.3. Тот же приём, что
       .ai-verdict/.briefing-box h3: вес/кегль несёт роль строки, а не цвет. */
    .wreview .wr-verdict { font-size:var(--fs-lg); font-weight:700; line-height:1.45;
                           margin:0 0 var(--sp-3); }
    .wreview .wr-verdict:first-child { margin-top:0; }
    .wreview .wr-label { font-weight:700; font-size:var(--fs-xs); letter-spacing:.06em;
                         text-transform:uppercase; color:var(--mut); margin:var(--sp-3) 0 var(--sp-1); }
    .wreview .wr-label:first-child { margin-top:0; }
    .wreview .wr-st { font-weight:700; margin:var(--sp-1) 0; }
    .wreview .wr-keep   { color:var(--good); }
    .wreview .wr-tweak  { color:var(--warn); }
    .wreview .wr-change { color:var(--acc); }
    .wreview .wr-assign { color:#a07cf5; }
    .wreview .wr-reason { color:var(--ink); padding-left:var(--sp-1); }

    /* Назначенная сессия лесенкой (жалоба 03.08: одной строкой не читается).
       Цвет статуса задаёт класс-модификатор (.wr-tweak/.wr-change/.wr-assign),
       он же красит левую полосу — так сохраняется прежний язык цветов. */
    .wreview .wr-sess { margin:var(--sp-1) 0 var(--sp-2); border-left:2px solid currentColor;
                        padding:var(--sp-1) 0 var(--sp-1) var(--sp-3); }
    .wreview .ws-head { font-weight:700; display:flex; align-items:baseline; gap:8px;
                        flex-wrap:wrap; }
    .wreview .ws-total { color:var(--mut); font-weight:600; font-size:var(--fs-xs); }
    .wreview .ws-steps { list-style:none; margin:var(--sp-1) 0 0; padding:0;
                         display:flex; flex-direction:column; gap:3px; }
    .wreview .ws-steps li { color:var(--ink); font-weight:500; font-size:var(--fs-sm);
                            padding-left:var(--sp-4); position:relative; }
    /* Маркер шага: у работы — сплошная точка, у отдыха/разминки — контурная,
       чтобы «где пашем, а где катим» читалось без чтения текста. */
    .wreview .ws-steps li::before { content:""; position:absolute; left:2px; top:.55em;
                                    width:6px; height:6px; border-radius:50%;
                                    border:1.5px solid var(--mut); box-sizing:border-box; }
    .wreview .ws-work { font-weight:700; }
    .wreview .ws-work::before { background:currentColor; border-color:currentColor; }
    .wreview .ws-rest, .wreview .ws-warmup, .wreview .ws-cooldown { color:var(--mut); }
    .wreview .ws-fuel { color:var(--mut); font-size:var(--fs-xs); }

    /* план тренера */
    .plan-tomorrow { background:rgba(224,98,59,.08); border:1px solid rgba(224,98,59,.3);
                     border-radius:var(--r-md); padding:var(--sp-3) var(--sp-4); margin:0 0 var(--sp-3); }
    .plan-tomorrow .plan-label { color:var(--mut); font-size:var(--fs-2xs); margin-bottom:var(--sp-1); }
    .plan-tomorrow .plan-text { font-size:var(--fs-base); font-weight:600; line-height:1.45; }
    .plan-week { width:100%; border-collapse:collapse; font-size:var(--fs-xs); margin-top:var(--sp-1); }
    .plan-week td { padding:var(--sp-2) var(--sp-1); border-bottom:1px solid var(--line); vertical-align:top; }
    .plan-week .pw-date { color:var(--mut); white-space:nowrap; min-width:52px; font-size:var(--fs-2xs); padding-right:var(--sp-2); }
    .plan-week tr.pw-today .pw-date { color:var(--acc-text); font-weight:700; font-size:var(--fs-xs); }
    .plan-week tr.pw-today .pw-body { font-weight:700; }
    .plan-week tr.pw-tomorrow .pw-date { color:var(--warn); font-weight:600; }
    .plan-week .pw-body { color:var(--ink); line-height:1.4; }
    .plan-week .pw-none { color:var(--mut); }
    .pw-next-label { color:var(--mut); font-size:var(--fs-2xs); font-weight:700; letter-spacing:.05em;
                      text-transform:uppercase; margin:var(--sp-3) 0 var(--sp-1); padding-top:var(--sp-2);
                      border-top:1px dashed var(--line); }
    .empty { text-align:center; color:var(--mut); padding:var(--sp-4) 0; }
    .foot { text-align:center; color:#828c9c; font-size:var(--fs-xs); margin-top:var(--sp-6); }
    /* Кнопка «База знаний» в подвале — единственный вход в справочник на телефоне
       (там сайдбар с пунктом .sb-kb скрыт, см. мобильный @media: .sb-nav{display:none}). */
    .foot .kb-btn { display:inline-flex; align-items:center; gap:8px; margin-bottom:var(--sp-3);
                    padding:var(--sp-3) var(--sp-4); border:1px solid var(--line); border-radius:var(--r-full);
                    background:var(--card); color:var(--ink); font-size:var(--fs-sm);
                    font-weight:600; text-decoration:none; }
    .foot .kb-btn:hover { border-color:var(--acc); color:var(--acc); }
    .foot .kb-btn .icon { width:16px; height:16px; }

    /* карточка добавления приёма */
    .ghost { background:var(--card2); border:1px solid var(--line); color:var(--ink); }
    .ghost:hover { filter:none; border-color:var(--mut); }
    .or { text-align:center; color:var(--mut); font-size:var(--fs-2xs); text-transform:uppercase;
          letter-spacing:.5px; margin:var(--sp-4) 0 var(--sp-1); }
    a.synccard, button.synccard, div.synccard { display:flex; align-items:center; gap:8px; padding:var(--sp-4);
                 font-weight:700; color:var(--ink); width:100%; text-align:left;
                 background:var(--card); border:1px solid var(--line); border-radius:var(--r-md);
                 margin-bottom:var(--sp-3); font-family:inherit; font-size:var(--fs-base); cursor:pointer; }
    a.synccard .sub, button.synccard .sub, div.synccard .sub { color:var(--mut); font-weight:500; font-size:var(--fs-xs); margin-left:auto; }
    a.synccard .chev, button.synccard .chev { color:var(--mut); display:inline-flex; }
    /* призрак-превью интеграции в демо (Strava) — тот же вид карточки
       .synccard, но не кликабельный div (не <a>/<form>): приглушаем и метим
       бейджем «пример», как у hr-ghost, чтобы не выдать за реальное подключение */
    div.synccard.gc-ghost { position:relative; cursor:default; }
    div.synccard.gc-ghost > svg.icon,
    div.synccard.gc-ghost > span:not(.hr-ghost-badge) { opacity:.55; }

    /* нижняя шторка с фото-формой */
    .backdrop { position:fixed; inset:0; z-index:44; background:rgba(0,0,0,.55); display:none; }
    .backdrop.show { display:block; }
    .sheet { position:fixed; left:0; right:0; bottom:0; z-index:46; transform:translateY(101%);
             transition:transform var(--transition-fast) ease; background:var(--card);
             border-radius:var(--r-md) var(--r-md) 0 0; border-top:1px solid var(--line);
             padding:var(--sp-4) var(--sp-4) calc(var(--sp-4) + env(safe-area-inset-bottom));
             max-height:88vh; overflow:auto; }
    .sheet.show { transform:translateY(0); }
    .sheet .inner { max-width:680px; margin:0 auto; }
    .sheet .sh { display:flex; justify-content:space-between; align-items:center; margin-bottom:var(--sp-2); }
    .sheet .sh b { font-size:var(--fs-md); }
    .sheet .close { background:transparent; border:0; color:var(--mut); font-size:var(--fs-3xl);
                    line-height:1; padding:var(--sp-1) var(--sp-2); }

    /* ── адаптация к жаре: тепловая шкала ──────────────────────────── */
    .heat-timeline { display:flex; gap:2px; align-items:flex-end; height:36px; margin:var(--sp-3) 0 var(--sp-1); }
    .heat-bar { flex:1; border-radius:var(--r-sm) var(--r-sm) 0 0; min-height:2px;
                background:var(--warn); opacity:.75; transition:opacity var(--transition-fast); }
    .heat-bar.today { background:var(--ink); opacity:1; }
    .heat-bar:hover { opacity:1; }
    .heat-dates { display:flex; justify-content:space-between; font-size:var(--fs-2xs);
                  color:var(--mut); margin-bottom:var(--sp-2); }
    .heat-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; margin:var(--sp-3) 0; }
    .heat-cell { background:var(--card2); border:1px solid var(--line); border-radius:var(--r-sm);
                 padding:var(--sp-2) var(--sp-3); }
    .heat-cell .hc-val { font-size:var(--fs-xl); font-weight:800; font-variant-numeric:tabular-nums; }
    .heat-cell .hc-lbl { font-size:var(--fs-2xs); color:var(--mut); margin-top:0; line-height:1.3; }
    .heat-cell .hc-band { font-size:var(--fs-2xs); font-weight:700; margin-top:var(--sp-1); }
    .heat-cell.warn .hc-val  { color:var(--warn); }
    .heat-cell.good .hc-val  { color:var(--good); }
    .heat-cell.acc  .hc-val  { color:var(--over); }
    .hready-bar { height:8px; background:var(--card2); border:1px solid var(--line);
                  border-radius:var(--r-full); overflow:hidden; margin:var(--sp-1) 0 var(--sp-2); }
    .hready-fill { height:100%; border-radius:var(--r-full); }
    .hready-fill.high { background:var(--good); }
    .hready-fill.mid  { background:var(--warn); }
    .hready-fill.low  { background:var(--over); }
    .sauna-form { display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-top:var(--sp-3); }
    .sauna-form select { width:100%; }
    .sauna-row { background:var(--card2); border:1px solid var(--line); border-radius:var(--r-sm);
                 padding:var(--sp-2) var(--sp-3); display:flex; align-items:center; justify-content:space-between;
                 margin-bottom:var(--sp-2); font-size:var(--fs-sm); }
    .sauna-row .sr-info { color:var(--mut); font-size:var(--fs-xs); margin-left:var(--sp-2); }

    /* оверлей загрузки */
    .busy { position:fixed; inset:0; z-index:60; display:none; place-items:center;
            background:rgba(8,10,14,.8); -webkit-backdrop-filter:blur(2px); backdrop-filter:blur(2px); }
    .busy.show { display:grid; }
    .busy .box { text-align:center; padding:var(--sp-6); }
    .spin { width:46px; height:46px; margin:0 auto var(--sp-4); border-radius:50%;
            border:4px solid var(--line); border-top-color:var(--acc);
            animation:spin .9s linear infinite; }
    @keyframes spin { to { transform:rotate(360deg); } }
    .busy .msg { font-weight:700; font-size:var(--fs-md); }
    .busy .sub { color:var(--mut); font-size:var(--fs-xs); margin-top:var(--sp-2); max-width:280px; }

    /* лёгкий индикатор быстрых (не-ИИ) операций с перезагрузкой — вместо полноэкранного
       оверлея: тонкая бегущая полоса сверху страницы + приглушение карточки формы */
    .mg-progress { position:fixed; top:0; left:0; right:0; height:3px; overflow:hidden;
                   z-index:70; opacity:0; pointer-events:none; transition:opacity var(--transition-fast); }
    .mg-progress.show { opacity:1; }
    .mg-progress::after { content:""; position:absolute; top:0; left:0; height:100%; width:35%;
                           background:var(--ink); animation:mg-slide 1s ease-in-out infinite; }
    @keyframes mg-slide { 0% { left:-35%; } 100% { left:100%; } }
    .is-saving { opacity:.6; pointer-events:none; transition:opacity var(--transition-fast); }

    /* точка-чип цвета зоны (Z1–Z5) — рядом с типом сессии/интенсивностью,
       текст рядом остаётся обычного цвета (см. правило проекта: зона красит
       только чип/точку, никогда сам текст) */
    .zdot { display:inline-block; width:7px; height:7px; border-radius:50%;
            margin-right:var(--sp-1); vertical-align:1px; flex-shrink:0; }

    /* гейдж-кольцо готовности (см. macro ready_gauge) */
    .ready-gauge { flex-shrink:0; }
    .ready-gauge .rg-bg { stroke:var(--elev); }
    .ready-gauge .rg-tick { stroke:var(--line); stroke-width:2px; }
    .ready-gauge .rg-val { stroke-linecap:round; }
    .ready-gauge.rg-good .rg-val { stroke:var(--good); }
    .ready-gauge.rg-warn .rg-val { stroke:var(--warn); }
    .ready-gauge.rg-acc .rg-val { stroke:var(--over); }
    .ready-gauge .rg-num { fill:var(--ink); font-weight:800;
                            font-family:var(--font-num);
                            letter-spacing:-.03em; font-variant-numeric:tabular-nums lining-nums; }
    .ready-gauge .rg-den { fill:var(--mut); font-weight:600;
                            font-family:var(--font-num);
                            font-variant-numeric:tabular-nums lining-nums; }
    /* Сигнатурный момент: при ПЕРВОМ за день открытии кольцо дорисовывается от
       нуля до вердикта, число считается вверх синхронно (JS ниже вешает .rg-reveal
       и ведёт счёт). Второй заход в тот же день — кольцо просто стоит, иначе
       «момент» превращается в надоедливый тик. Анимируем stroke-dashoffset, а не
       dasharray: браузер тянет его плавнее. Без JS кольцо статично и целое —
       ничего не ломается. */
    .ready-gauge.rg-reveal .rg-val {
      animation: rg-draw 1100ms cubic-bezier(.22,1,.36,1) both;
    }
    @keyframes rg-draw {
      from { stroke-dashoffset: var(--rg-circ); }
      to   { stroke-dashoffset: var(--rg-off); }
    }
    @media (prefers-reduced-motion: reduce) {
      .ready-gauge.rg-reveal .rg-val { animation: none; }
    }

    /* ════════════════════════════════════════════════════════════════════
       РЕДИЗАЙН «КОМАНДНЫЙ ЦЕНТР»: сайдбар + герой + полоса формы + дашборд.
       ════════════════════════════════════════════════════════════════════ */
    /* --sidebar/--panel/--elev/--sbw — в tokens.css (алиасы на s0/s1/s2). */
    html { scroll-behavior:smooth; }
    body, button, input, select, textarea {
      font-family:var(--font-sans);
    }
    [id^="sec-"] { scroll-margin-top:108px; }
    /* Вспышка-ориентир после перехода по якорю из сайдбара: на двухколоночном
       дашборде рядом с целевой карточкой на той же высоте стоит соседняя —
       без подсветки непонятно, куда именно ты перешёл (жалоба 13.07). */
    .anchor-flash { animation: anchorFlash 1.6s ease-out; }
    @keyframes anchorFlash {
      0%, 35% { outline: 2px solid var(--acc); outline-offset: 3px; }
      100%    { outline: 2px solid transparent; outline-offset: 3px; }
    }

    /* единый набор иконок (Lucide через <use>) */
    .icon { width:18px; height:18px; stroke:currentColor; fill:none; stroke-width:2;
            stroke-linecap:round; stroke-linejoin:round; flex-shrink:0; }
    .sec-h .icon, .ttl .icon, .row > summary > .icon, .synccard > .icon { width:16px; height:16px; }
    .row > summary .chev .icon { width:16px; height:16px; }

    .app { display:grid; grid-template-columns:var(--sbw) 1fr; min-height:100vh; align-content:start; }

    /* ── САЙДБАР ─────────────────────────────────────────────────────── */
    .sidebar { position:sticky; top:0; align-self:start; height:100vh; overflow-y:auto;
               background:var(--sidebar); border-right:1px solid var(--line);
               display:flex; flex-direction:column; padding:var(--sp-4) var(--sp-3); }
    .sb-brand { display:flex; align-items:center; gap:8px; padding:var(--sp-1) var(--sp-2) var(--sp-3);
                font-size:var(--fs-base); font-weight:800; letter-spacing:.2px; line-height:1.15; }
    .sb-brand .logo { width:32px; height:32px; border-radius:var(--r-sm); display:grid; place-items:center;
                      background:#0E1013; flex-shrink:0; color:#F2F3F4; }  /* знак Ingegnere на графите, как иконка приложения (09.10) */
    .sb-brand .logo .icon { width:18px; height:18px; }
    .sb-brand small { display:block; color:var(--mut); font-size:var(--fs-2xs); font-weight:700;
                      letter-spacing:.1em; text-transform:uppercase; margin-top:var(--sp-1); }
    .sb-day { display:flex; align-items:center; gap:4px; background:var(--panel);
              border:1px solid var(--line); border-radius:var(--r-sm); padding:var(--sp-1); margin:var(--sp-1) var(--sp-1) var(--sp-2); }
    /* Аудит №14 назвал стрелки дня «основной навигацией продукта» с целью
       30×30. Зона тапа была добрана псевдоэлементом и раньше, но сама кнопка
       осталась мелкой — и на глаз, и в замерах. Теперь 40×40 визуально
       (полоса дня от этого не растёт: её высота задана паддингом) и 44×44
       по касанию. */
    .sb-day a.step { width:40px; height:40px; display:grid; place-items:center; border-radius:var(--r-sm);
                     color:var(--mut); position:relative; }
    .sb-day a.step::before { content:""; position:absolute; inset:-2px; }
    .sb-day a.step:hover { background:var(--elev); color:var(--ink); }
    .sb-day .d { flex:1; text-align:center; font-size:var(--fs-xs); font-weight:700; }
    .sb-day .d small { display:block; color:var(--mut); font-weight:500; font-size:var(--fs-2xs); }
    .sb-nav { display:flex; flex-direction:column; gap:1px; }
    .sb-nav a, .sb-navhead { display:flex; align-items:center; gap:8px; padding:var(--sp-2) var(--sp-3) var(--sp-2) var(--sp-2);
                border-radius:var(--r-sm); border-left:2px solid transparent;
                color:var(--mut); font-size:var(--fs-xs); font-weight:600; }
    .sb-nav a:hover, .sb-navhead:hover { background:var(--elev); color:var(--ink); }
    /* Аудит №14: вид и секция подсвечивались ОДИНАКОВО — два активных пункта
       разом, и непонятно, где ты. Теперь уровни разные: активный ВИД — фон
       (это «где я»), активная секция — только тонкая полоса слева («докуда
       долистал»). B1.4: полоса раньше была inset box-shadow (без сдвига
       раскладки) — теперь border-left, а базовый паддинг заранее уменьшен
       на 2px слева, чтобы появление полосы не сдвигало текст. */
    .sb-navhead.active { background:rgba(224,98,59,.12); color:var(--ink);
                         border-left-color:var(--acc); }
    .sb-nav a.active { background:transparent; color:var(--ink);
                       border-left-color:var(--mut); }
    /* Заголовок группы вида (Сегодня/План/Тренды/Профиль) — сама навигация теперь
       ОДНА система (сайдбар); бывшие горизонтальные .viewtabs удалены (жалоба
       нескольких аудитов подряд на «двойную навигацию»). Заголовок — button с
       data-view-tab, существующий JS переключения видов подхватывает его сам. */
    /* justify-content обязателен: у <button> с display:flex браузер по умолчанию
       центрирует содержимое — иконка с подписью уезжали от края, и заголовки
       не вставали в одну колонку со ссылками своей группы. */
    .sb-navhead { width:100%; justify-content:flex-start; background:none; border:0;
                  font-family:inherit; cursor:pointer;
                  text-align:left; text-transform:uppercase; letter-spacing:.06em; margin-top:var(--sp-3); }
    .sb-navhead:first-child { margin-top:0; }
    .sb-navhead .icon { width:16px; height:16px; }
    /* База знаний — отдельный вход под видами: разделитель сверху, чтобы читалось
       как «не пятый вид», а справочник. */
    .sb-nav a.sb-kb { margin-top:var(--sp-3); padding-top:var(--sp-3); border-top:1px solid var(--line);
                      border-radius:0 0 var(--r-sm) var(--r-sm); font-weight:600; }
    .sb-nav a.sb-kb .icon { width:16px; height:16px; }
    /* Точка «идёт сбор» на заголовке «План» (аудит №12: сбор больше не отдельная
       вкладка, но пока он активен — на «Плане» скромный маркер, а не бейдж). */
    .nav-camp-dot { width:6px; height:6px; border-radius:50%; background:var(--warn);
                    margin-left:auto; flex-shrink:0; }
    /* Ссылки секций НЕактивной группы вида — сворачиваем (замена приглушения
       nav-dim): один список сразу под своим заголовком, а не 11 ссылок разом. */
    .sb-group { display:none; flex-direction:column; gap:1px; padding-left:var(--sp-1); }
    .sb-group.active-group { display:flex; }
    .sb-spacer { flex:1; min-height:14px; }
    .sb-foot { padding:var(--sp-3) var(--sp-3) var(--sp-1); border-top:1px solid var(--line); margin-top:var(--sp-2);
               font-size:var(--fs-2xs); color:#8791a0; line-height:1.95; }
    .sb-foot a { color:#98a2b2; display:inline-flex; align-items:center; gap:8px; }
    .sb-foot a:hover { color:var(--ink); }
    .sb-foot .icon { width:13px; height:13px; vertical-align:-2px; }

    /* ── РАБОЧАЯ ОБЛАСТЬ ─────────────────────────────────────────────── */
    /* max-width обязан включать 100%: min-width:0 не мешает элементу сетки
       раздуться под минимальную ширину содержимого (строка с white-space:nowrap
       требует её целиком), и тогда вбок едет вся страница. Клэмп по 100% — общая
       страховка: ни один будущий неразрывный блок не сможет распереть телефон. */
    .main { min-width:0; max-width:min(1480px, 100%); margin:0 auto; padding:0 var(--sp-6) var(--sp-12); overflow-x:clip; }

    /* ── ВЕРХНЯЯ ПЛАШКА (slim sticky) ────────────────────────────────── */
    .sticky { padding:var(--sp-4) 0 var(--sp-3); margin-bottom:var(--sp-2); }
    .cmdbar { display:flex; align-items:flex-start; justify-content:space-between; gap:8px 12px;
              flex-wrap:wrap; }
    .cmdbar > div:first-child { min-width:0; flex:1 1 auto; }
    .cmdbar h1 { font-size:var(--fs-3xl); font-weight:var(--fw-bold); margin:0;
                 line-height:var(--lh-snug); letter-spacing:var(--ls-display); }
    .cmdbar .tagline { color:var(--mut); font-size:var(--fs-xs); font-weight:500; margin-top:var(--sp-1); }
    /* правый кластер должен ужиматься/переноситься, а не распирать шапку за экран */
    .cmd-right { display:flex; align-items:center; gap:8px; flex-wrap:wrap;
                 justify-content:flex-end; min-width:0; }
    .cmdbar .ph { color:var(--mut); font-size:var(--fs-2xs); font-weight:600; }
    .cmd-auth { display:inline-flex; align-items:center; gap:8px; font-size:var(--fs-xs); font-weight:700;
                color:var(--ink); border:1px solid var(--line); border-radius:var(--r-sm); padding:var(--sp-2) var(--sp-3);
                background:var(--panel); white-space:nowrap; }
    .cmd-auth:hover { border-color:var(--acc); color:var(--acc); }
    .cmd-auth .icon { width:15px; height:15px; }
    @media (max-width:560px){ .cmdbar .tagline { display:none; } }

    /* ── ГЕРОЙ: сессия дня + готовность ──────────────────────────────── */
    /* align-items:start — карточки НЕ растягиваются друг под друга. Аудит №14:
       «Сессия сегодня» держала ~450 px пустоты внутри себя просто потому, что
       соседняя карточка состояния выше. Пустота должна быть решением, а не
       побочным эффектом grid-stretch. */
    .hero { display:grid; grid-template-columns:1.25fr 1fr; gap:16px; margin-bottom:var(--sp-4);
            align-items:start; }
    @media (max-width:900px){ .hero { grid-template-columns:1fr; } }
    /* .hero-card — см. общее определение карточки выше (П5.4). */
    /* П5.4: ОДИН микро-заголовок карточки. Было три копии одного и того же с
       разным трекингом — .hero-h (.09em), .trend-card .tc-h (.08em) и .sec-h
       (.1em); на глаз это читалось как три разных шрифта в одном интерфейсе.
       .sec-h ниже добавляет к этой базе только своё: линию-разделитель и
       внешние отступы, потому что он стоит МЕЖДУ карточками, а не внутри. */
    .hero-h, .trend-card .tc-h, .sec-h {
              display:flex; align-items:center; gap:8px; font-size:var(--fs-2xs);
              font-weight:800; letter-spacing:.09em; text-transform:uppercase;
              color:var(--mut); }
              /* margin явно: это h2, дефолтные отступы заголовка сдвинули бы карточку */
    .hero-h { margin:0 0 var(--sp-3); }
    .hero-h .hero-date { margin-left:auto; font-weight:700; letter-spacing:.04em; color:var(--mut); }
    .hs-plan { font-size:var(--fs-base); font-weight:600; line-height:1.45; color:var(--ink);
               border-left:3px solid var(--pl); padding:var(--sp-1) 0 var(--sp-1) var(--sp-3); margin-bottom:var(--sp-3); }
    .hs-fact { display:flex; align-items:baseline; gap:12px; flex-wrap:wrap; }
    .hs-big { font-size:var(--fs-3xl); font-weight:800; line-height:1.1; }
    .hs-stats { color:var(--mut); font-size:var(--fs-sm); font-variant-numeric:tabular-nums; }
    .hs-rest { font-size:var(--fs-2xl); font-weight:800; }
    .hs-rest small { display:block; font-size:var(--fs-xs); font-weight:500; color:var(--mut); margin-top:var(--sp-1); }
    /* Решение штаба по дню (director.session_today) — крупный заголовок, под
       ним само задание. Ниже, отдельно и мельче, идёт ФАКТ из Garmin: заезд
       (.hs-done) или статус синка (.hs-sync). Разный вес шрифта тут и есть
       ответ на «что назначено» против «что уже сделано». */
    .hs-decision { margin-bottom:var(--sp-4); }
    .hs-decision .hs-big { margin-bottom:var(--sp-2); }
    .hs-src { font-size:var(--fs-2xs); color:var(--mut); letter-spacing:.04em; }
    .hs-raw { margin-top:var(--sp-2); font-size:var(--fs-xs); color:var(--mut); }
    .hs-raw summary { cursor:pointer; }
    .hs-done { font-size:var(--fs-xl); font-weight:700; }
    .hs-sync { font-size:var(--fs-xs); color:var(--mut); margin-top:var(--sp-3); padding-top:var(--sp-3);
               border-top:1px solid var(--line); line-height:1.45; }
    .hs-link { display:inline-block; margin-top:var(--sp-3); color:var(--acc-text); font-size:var(--fs-xs); font-weight:700; }
    .hs-link:hover { text-decoration:underline; }
    .hs-empty { font-size:var(--fs-base); line-height:1.5; }
    /* лист ожидания прямого подключения Garmin — компактный inline-блок под
       primary-кнопкой (см. #garminCtaBtn), не должен раздувать пустой экран */
    .garmin-wl { margin-top:var(--sp-3); padding:var(--sp-3); background:var(--card2); border:1px solid var(--line); border-radius:var(--r-md); }

    /* Ощущение атлета («Как зашло?») — общая разметка macro rpe_buttons()
       (index.html), переиспользуется в герое, вечернем дебрифе и догоняющем
       вопросе за вчера. Крупные mobile-friendly кнопки (≥44px) — главный
       путь ввода RPE, спрашиваем сразу после заезда. */
    .hero-rpe { margin-top:var(--sp-4); padding-top:var(--sp-3); border-top:1px solid var(--line); }
    .rpe-in-debrief { margin-top:var(--sp-3); padding-top:var(--sp-3); border-top:1px solid var(--line); }
    .rpe-q { font-size:var(--fs-sm); font-weight:700; margin-bottom:var(--sp-2); }
    .rpe-block .wbtns { display:flex; gap:8px; }
    .rpe-block .wbtn-lg { flex:1; min-height:44px; padding:var(--sp-3) var(--sp-3); font-size:var(--fs-base); }
    .rpe-block .wbtn-sm { flex:1; min-height:40px; padding:var(--sp-2) var(--sp-3); font-size:var(--fs-sm); }
    .rpe-summary { font-size:var(--fs-sm); color:var(--mut); }
    .rpe-summary b { color:var(--ink); }
    /* Шкала CR10 1–10 — ПЕРВИЧНЫЙ ввод (TZ-rpe-numeric-en.md §2), не ряд
       «уточнить» под словом. ПЯТЬ В РЯД, ДВА РЯДА — не десять в ряд: замер в
       браузере при вьюпорте 360 px даёт 268 px на самой узкой поверхности
       (#rpe-card; герой/дебриф/.yc-strip 294, FAB 285). Десять целей в ряд —
       (268 − 9×8)/10 = 19.6 px, вдвое-втрое меньше собственного пола продукта
       44 px (строка «button, .btn, .wbtn, .tbtn» ниже). Пять в ряд —
       (268 − 4×8)/5 = 47.2 px при высоте 44 px, пол соблюдён. Один тап при
       этом сохраняется: атлет жмёт цифру сразу, шлагбаума перед ней нет. */
    /* ⛔ minmax(40px, …), а НЕ голый 1fr. У 1fr нет пола: в поповере FAB
       (.fab-water-pop — position:fixed без ширины, размер по содержимому)
       десять цифр ужали его до 26 px на цель — вдвое меньше пола продукта.
       Замерено зондом, а не предположено: три слова «Легко/Нормально/Тяжело»
       распирали поповер сами, цифры этого не делают. minmax задаёт пол
       ЦЕЛИ, то есть ровно ту величину, о которой правило и есть. */
    .rpe-scale { display:grid; grid-template-columns:repeat(5, minmax(40px, 1fr)); gap:8px; }
    .rpe-scale .wbtn-num { min-height:44px; padding:var(--sp-2) var(--sp-1);
                           font-size:var(--fs-base); font-weight:700;
                           border-radius:var(--r-sm); text-align:center; }
    /* Компактный вариант: догоняющая строка за вчера (catchup) и ряд поправки
       под уже сохранённым ответом — тот же пол 44 px, мельче только шрифт и
       внутренние отступы; ниже пола не опускаемся нигде. */
    .rpe-scale-sm { margin-top:var(--sp-2); gap:6px; }
    .rpe-scale-sm .wbtn-num { font-size:var(--fs-sm); padding:var(--sp-1); }
    .rpe-scale .wbtn-num.active-rpe { opacity:1; }
    /* Легенда концов шкалы — ПОД сеткой первичного ввода (index.html
       rpe_buttons(), ветка «не отвечено» — не под .rpe-scale-sm поправки и
       не в FAB-поповере). Своя строка, не участвует в grid-template кнопок
       выше — их размер (44 px пол) эта правка не меняет. */
    .rpe-legend { display:flex; justify-content:space-between; margin-top:var(--sp-1);
                  font-size:var(--fs-sm); color:var(--mut); }

    /* Догоняющий вопрос за вчера — компактная самостоятельная строка над
       героем дня (видна и утром, и вечером), не карточка: не должна спорить
       весом с «Сессией сегодня». Пропадает целиком после ответа (AJAX). */
    .yc-strip { margin:0 0 var(--sp-4); padding:var(--sp-3) var(--sp-4); background:var(--card2);
                border:1px solid var(--line); border-radius:var(--r-md); }
    .yc-strip .rpe-q { margin-bottom:var(--sp-2); }

    /* Итог дня — вечерний дебриф (карточка после 18:00, тот же текст, что
       в письме) — 4 строки «ключ: значение», не список приёмов пищи. */
    .debrief .db-rows { display:flex; flex-direction:column; gap:8px; }
    .debrief .db-row { display:flex; justify-content:space-between; gap:12px;
                        font-size:var(--fs-sm); line-height:1.4; }
    .debrief .db-k { color:var(--mut); font-weight:700; white-space:nowrap; }
    .debrief .db-v { text-align:right; }
    @media (max-width:480px){
      .debrief .db-row { flex-direction:column; gap:2px; }
      .debrief .db-v { text-align:left; }
    }

    /* выполнение дня (habit-хук «день закрыт») */
    .day-done { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:var(--sp-4);
                padding-top:var(--sp-3); border-top:1px solid var(--line); }
    .day-done .dd-h { font-size:var(--fs-2xs); font-weight:800; letter-spacing:.06em; text-transform:uppercase;
                      color:var(--mut); margin-right:var(--sp-1); }
    .dd-chip { display:inline-flex; align-items:center; gap:4px; font-size:var(--fs-2xs); font-weight:600;
               color:var(--mut); background:var(--card2); border:1px solid var(--line);
               border-radius:var(--r-full); padding:var(--sp-1) var(--sp-3); }
    .dd-chip.ok { color:var(--good); border-color:rgba(47,170,106,.4); background:rgba(47,170,106,.08); }
    .dd-chip .icon { width:13px; height:13px; }
    .dd-badge { margin-left:auto; font-size:var(--fs-2xs); font-weight:800; color:var(--good);
                display:inline-flex; align-items:center; gap:4px; }
    .dd-badge .icon { width:14px; height:14px; }
    /* Стрик дисциплины — повод вернуться завтра. По умолчанию тлеет (сегодня ещё
       не закрыт), .live — горит ярче (сегодня закрыт, серия продолжена). */
    .dd-streak { margin-left:auto; display:inline-flex; align-items:center; gap:4px;
                 font-size:var(--fs-2xs); font-weight:800; font-variant-numeric:tabular-nums;
                 color:var(--warn); background:rgba(217,162,59,.10);
                 border:1px solid rgba(217,162,59,.32); border-radius:var(--r-full); padding:var(--sp-1) var(--sp-3); }
    /* B1.4: было мягкое кольцо box-shadow — «живая» серия теперь читается
       по более яркой заливке/границе, без тени. */
    .dd-streak.live { background:rgba(217,162,59,.20); border-color:rgba(217,162,59,.55); }
    /* Нулевая серия (новичок или серия сгорела) — механика должна быть видна,
       иначе стрик не мотивирует начать: приглушённый чип без огненной заливки. */
    .dd-streak.zero { opacity:.55; color:var(--mut); background:transparent;
                      border-color:var(--line); font-weight:600; }
    .dd-streak .icon { width:14px; height:14px; }
    .day-done .dd-badge + .dd-streak { margin-left:var(--sp-2); }

    .hero-ready .hr-top { display:flex; align-items:center; gap:16px; margin-bottom:var(--sp-3); }
    /* Место кольца готовности, когда балл не считаем (нет данных по драйверам).
       Размер 92px — тот же, что у ready_gauge, чтобы карточка не прыгала. */
    .hr-nodata { flex:0 0 92px; width:92px; height:92px; display:flex;
      align-items:center; justify-content:center; font-size:var(--fs-4xl); font-weight:700;
      color:var(--mut); border:2px dashed var(--line); border-radius:50%; }
    .hr-verdict { min-width:0; }
    .hr-label { font-size:var(--fs-base); font-weight:700; }
    .hr-advice { font-size:var(--fs-xs); color:var(--mut); margin-top:var(--sp-1); line-height:1.4; }
    .hr-drivers { list-style:none; margin:0; padding:0; display:grid; grid-template-columns:1fr 1fr; gap:8px 16px; }
    .hr-drivers li { display:flex; flex-direction:column; font-size:var(--fs-2xs); }
    .hr-drivers .hd-f { color:var(--mut); font-weight:700; font-size:var(--fs-2xs); text-transform:uppercase;
                        letter-spacing:.04em; margin-bottom:0; }
    .hr-drivers .hd-v { color:var(--ink); line-height:1.3; }
    @media (max-width:560px){ .hr-drivers { grid-template-columns:1fr; } }
    /* Блок источника под баллом готовности (спека 4.2): вклад каждого драйвера
       в баллах. Оранжевого здесь нет — это данные, а не действие. */
    .day-headline { font-size:var(--fs-2xl); line-height:1.25; font-weight:700;
                    margin:0; letter-spacing:-.01em; max-width:46ch; text-wrap:balance; }
    .prov { margin-top:var(--sp-3); }
    .prov > summary { cursor:pointer; list-style:none; display:flex; align-items:center;
                      gap:var(--sp-2); min-height:var(--tap-min); color:var(--mut);
                      font-size:var(--fs-xs); font-weight:700; }
    .prov > summary::-webkit-details-marker { display:none; }
    .prov > summary::after { content:'+'; color:var(--faint); font-size:var(--fs-md); }
    .prov[open] > summary::after { content:'\2212'; }
    .prov > summary:hover { color:var(--ink); }
    /* Свёрнутое состояние задаём явно: в закрытом <details> замер высоты списка
       дал 159px вместо нуля (грид-ребёнок внутри слота), полагаться на
       браузерное поведение здесь нельзя. */
    .prov:not([open]) .hr-drivers, .prov:not([open]) .prov-why { display:none; }
    .prov .hd-s { color:var(--faint); }
    .prov-why { display:inline-block; margin-top:var(--sp-3); color:var(--acc-text);
                font-size:var(--fs-2xs); font-weight:700; }
    /* призрак-превью готовности в пустом состоянии — тот же вид карточки, но
       приглушаем сами цифры/бар (а не весь блок), чтобы бейдж «пример» остался
       контрастным и явно читался как маркировка, а не как реальные данные */
    .hr-ghost { position:relative; pointer-events:none; }
    .hr-ghost .ready-gauge, .hr-ghost .hr-verdict { opacity:.5; }
    .hr-ghost-badge { position:absolute; top:-4px; right:0; font-size:var(--fs-xs); font-weight:700;
                       color:var(--warn); border:1px solid var(--warn); border-radius:var(--r-full);
                       padding:var(--sp-1) var(--sp-2); background:rgba(217,162,59,.14); text-transform:uppercase; letter-spacing:.04em; }

    /* ── КАРТОЧКА «ФОРМА СЕЙЧАС» (CTL/ATL/TSB/ACWR) — дом: Тренды ────────
       (IA-аудит №12 §06: раньше .formstrip стояла полосой на «Сегодня»,
       margin-bottom тут был для block-потока; теперь это айтем grid-сетки
       .trends-grid — сброс margin ниже, отступ даёт gap сетки). */
    .formstrip { background:var(--card2); border:1px solid var(--line); border-radius:var(--r-md);
                 padding:var(--sp-3) var(--sp-4); margin-bottom:var(--sp-6); }
    .trends-grid .formstrip { margin-bottom:0; }
    .fs-h { font-size:var(--fs-2xs); font-weight:800; letter-spacing:.08em; text-transform:uppercase;
            color:var(--mut); margin:0 0 var(--sp-3); display:flex; align-items:center; gap:8px; }
    .fs-h small { font-weight:600; letter-spacing:.02em; text-transform:none; color:var(--mut); margin-left:auto; }
    .fs-cells { display:grid; grid-template-columns:repeat(4,1fr); gap:8px; }
    .formstrip.has-vo2 .fs-cells { grid-template-columns:repeat(5,1fr); }
    .fs-cell > span { display:inline-block; font-size:var(--fs-2xs); font-weight:800; letter-spacing:.05em;
                      color:var(--mut); text-transform:uppercase; }
    .fs-cell > b { display:block; font-size:var(--fs-2xl); font-weight:800; line-height:1.2; margin-top:var(--sp-1);
                   font-variant-numeric:tabular-nums; }
    .fs-cell > small { font-size:var(--fs-2xs); color:var(--mut); }
    @media (max-width:560px){ .fs-cells, .formstrip.has-vo2 .fs-cells { grid-template-columns:repeat(2,1fr); } }

    /* ── ЕДИНАЯ СТАТУС-ПОЛОСА «Сегодня» (IA-аудит №12 §06) ───────────────
       Заменила три полосы подряд (формстрип/гонка/прогресс-чипы) одной
       тонкой строкой кликабельных сегментов. overflow-x:auto + nowrap на
       сегментах — на узком экране полоса скроллится вбок, а НЕ распирает
       страницу (см. общий .main{overflow-x:clip} как страховку). */
    /* B2: паддинг сверху/снизу var(--sp-3), не var(--sp-2) — overflow-x:auto
       неявно даёт overflow-y:auto (спека CSS), и зона тапа ::before на
       a.stat-seg (инсет -8px) обрезалась бы по границе паддинга при sp-2 (8px).
       sp-3 (12px) держит инсет с запасом. */
    .statusbar { display:flex; align-items:center; gap:8px; overflow-x:auto;
                 -webkit-overflow-scrolling:touch; background:var(--card2);
                 border:1px solid var(--line); border-radius:var(--r-md);
                 padding:var(--sp-3); margin-bottom:var(--sp-6); }
    .stat-seg { display:flex; align-items:center; gap:8px; flex:0 0 auto; white-space:nowrap;
                font-size:var(--fs-xs); color:var(--ink); text-decoration:none;
                padding:var(--sp-1) var(--sp-2); border-radius:var(--r-sm); }
    a.stat-seg:hover { background:var(--elev); }
    .stat-seg .icon { width:14px; height:14px; color:var(--mut); flex-shrink:0; }
    .stat-seg:not(:last-child)::after { content:""; width:1px; height:14px; background:var(--line);
                                          margin-left:var(--sp-2); flex-shrink:0; }

    /* ── ПЕРВЫЙ ЗАПУСК: доверие ───────────────────────────────────────── */
    .trustline { display:flex; gap:8px; align-items:flex-start; color:var(--mut); font-size:var(--fs-2xs);
                 line-height:1.5; margin-top:var(--sp-3); }
    .trustline .icon { width:14px; height:14px; margin-top:0; flex-shrink:0; color:var(--good); }

    /* ── спарклайн тренда веса ───────────────────────────────────────── */
    .spark { width:100%; height:46px; display:block; margin:var(--sp-2) 0 var(--sp-1); }
    .spark .sp-line { fill:none; stroke:var(--prot); stroke-width:2;
                      stroke-linejoin:round; stroke-linecap:round; }
    .spark .sp-target { stroke:var(--good); stroke-width:1.5; stroke-dasharray:4 3; opacity:.85; }
    .spark-cap { display:flex; justify-content:space-between; align-items:baseline;
                 font-size:var(--fs-2xs); color:var(--mut); margin-bottom:var(--sp-2); }
    .spark-cap .sc-tgt { color:var(--good); font-weight:600; }

    /* ── спарклайн тренда готовности (в герое) ───────────────────────── */
    .rspark { width:100%; height:34px; display:block; margin:var(--sp-4) 0 0; }
    .rspark .rs-line { fill:none; stroke-width:2; stroke-linejoin:round; stroke-linecap:round; }
    .rspark-cap { font-size:var(--fs-2xs); color:var(--mut); margin-top:var(--sp-1); }

    /* ── спарклайн тренда формы (CTL) в полосе формы ─────────────────── */
    .fspark { width:100%; height:30px; display:block; margin:var(--sp-3) 0 0; }
    .fspark .fs-spk { fill:none; stroke:var(--prot); stroke-width:2;
                      stroke-linejoin:round; stroke-linecap:round; }
    .fspark-cap { font-size:var(--fs-2xs); color:var(--mut); margin-top:var(--sp-1); }

    /* ── ПЛАН ИИ-ТРЕНЕРА ─────────────────────────────────────────────── */
    /* Правки плана по факту тренировок (петля исполнения). Не тревожный
       красный: это нормальная работа штаба, а не авария. */
    /* Быстрая оценка питания на заезде — спрашиваем ПОСЛЕ, одним тапом. */
    .rf-quick { background:rgba(90,169,255,.07); border:1px solid rgba(90,169,255,.25);
                border-radius:var(--r-sm); padding:var(--sp-2) var(--sp-3); margin:var(--sp-2) 0 var(--sp-3); }
    .rf-quick-h { font-size:var(--fs-xs); font-weight:700; margin-bottom:var(--sp-2); }
    .rf-quick-h small { color:var(--mut); font-weight:500; margin-left:var(--sp-1); }

    /* «Где обрыв» — главный практический вывод из устойчивости. */
    .pb-wall { margin-top:var(--sp-3); padding:var(--sp-2) var(--sp-3); border-radius:var(--r-sm); font-size:var(--fs-sm);
               background:rgba(224,98,59,.08); border:1px solid rgba(224,98,59,.28); }
    .pb-wall .mut { display:block; color:var(--mut); font-size:var(--fs-xs); margin-top:var(--sp-1); }

    /* Кто ведёт порог: ручной ввод против авто-оценки по кривой мощности. */
    .ftp-mode { margin-top:var(--sp-4); padding-top:var(--sp-3); border-top:1px solid var(--line); }
    .ftp-mode-h { font-weight:700; font-size:var(--fs-sm); margin-bottom:var(--sp-2); }
    .ftp-mode-opt { display:flex; gap:8px; align-items:flex-start; padding:var(--sp-2) 0; cursor:pointer; }
    .ftp-mode-opt input { margin-top:var(--sp-1); flex:none; }
    .ftp-mode-opt b { display:block; font-size:var(--fs-sm); }
    .ftp-mode-opt small { display:block; color:var(--mut); font-size:var(--fs-xs); line-height:1.45; margin-top:var(--sp-1); }
    .ftp-mode-note { margin:var(--sp-3) 0 0; font-size:var(--fs-xs); color:var(--good); display:flex;
                     align-items:baseline; gap:8px; }
    .ftp-mode-note .icon { width:13px; height:13px; }

    /* Подсказка «порог держится не 30-70 мин» (power.threshold_check) — тон
       спокойный, справочный: та же приглушённая палитра, что у ftp-mode-note,
       без красного/жёлтого — это не тревога, а факт с расчётом. */
    .ftp-hint { margin:var(--sp-3) 0 0; padding:var(--sp-2) var(--sp-3); border-radius:var(--r-sm);
                background:var(--card2); border:1px solid var(--line);
                font-size:var(--fs-xs); color:var(--ink); line-height:1.5; }
    .ftp-hint a { display:inline-block; margin-left:var(--sp-1); color:var(--acc-text); font-weight:700; }
    .ftp-hint-note { display:block; margin-top:var(--sp-2); color:var(--mut); }

    /* Книга прогрессии: кДж/зоны/RPO/durability (Тренды). */
    .pb-block { margin-top:var(--sp-4); }
    .pb-h { font-weight:700; font-size:var(--fs-sm); margin-bottom:var(--sp-2); }
    .pb-h small { color:var(--mut); font-weight:500; font-size:var(--fs-2xs); margin-left:var(--sp-2); }
    .pb-zones { display:flex; flex-wrap:wrap; gap:8px; margin-top:var(--sp-2); }
    .pb-z { font-size:var(--fs-2xs); font-weight:700; padding:var(--sp-1) var(--sp-2); border-radius:var(--r-sm);
            background:var(--elev); color:var(--mut); }
    .pb-z1, .pb-z2 { color:var(--good); }
    .pb-z3, .pb-z4 { color:var(--warn); }
    .pb-z5, .pb-z6 { color:var(--z5); }
    .pb-table { width:100%; border-collapse:collapse; font-size:var(--fs-sm); }
    .pb-table th { text-align:left; font-weight:600; font-size:var(--fs-2xs); color:var(--mut);
                   text-transform:uppercase; letter-spacing:.04em; padding:0 var(--sp-3) var(--sp-1) 0; }
    .pb-table td { padding:var(--sp-1) var(--sp-3) var(--sp-1) 0; border-top:1px solid var(--line); }
    .pb-table td.mut { color:var(--mut); }

    .pl-adjusted { background:var(--warn-fill); border:1px solid var(--warn-edge);
                   border-radius:var(--r-md); padding:var(--sp-3) var(--sp-3); margin:0 0 var(--sp-3); }
    .pl-adj-head { font-weight:700; font-size:var(--fs-sm); display:flex; align-items:center;
                   gap:8px; margin-bottom:var(--sp-2); }
    .pl-adj-head .icon { width:15px; height:15px; }
    .pl-adj-list { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px; }
    .pl-adj-list li { font-size:var(--fs-sm); color:var(--ink); }
    .pl-adj-why { display:block; color:var(--mut); font-size:var(--fs-xs); margin-top:0; }

    .planw { background:var(--card); border:1px solid var(--line); border-radius:var(--r-md);
             padding:var(--sp-4) var(--sp-4); margin:var(--sp-4) 0; }
    .planw .pl-h { display:flex; align-items:center; gap:8px; font-weight:var(--fw-bold);
                   font-size:var(--fs-lg); letter-spacing:var(--ls-normal); margin:0 0 var(--sp-1); flex-wrap:wrap; }
    .planw .pl-h small { color:var(--mut); font-weight:var(--fw-regular); font-size:var(--fs-sm);
                          margin-left:0; display:block; flex-basis:100%; }
    .planw .pl-h .pl-act { margin-left:auto; }
    .pl-stale { font-size:var(--fs-2xs); font-weight:700; color:var(--warn); border:1px solid var(--warn);
                border-radius:var(--r-full); padding:var(--sp-1) var(--sp-2); }
    /* Штаб пересобирает план сам — статус вместо кнопки «Обновить план». */
    .pl-rebuild { color:var(--mut); border-color:var(--line); font-weight:600; }
    .pl-note { color:var(--mut); font-size:var(--fs-sm); line-height:1.5; margin:var(--sp-1) 0 var(--sp-1); }
    .pl-note b { color:var(--ink); font-weight:var(--fw-bold); }
    .pl-note .pl-why { color:var(--acc-text); text-decoration:none; margin-left:var(--sp-1); white-space:nowrap; }
    .pl-note .pl-why:hover { text-decoration:underline; }
    .pl-rebuilt { display:flex; align-items:flex-start; gap:8px; color:var(--good);
                  background:rgba(47,170,106,.09); border:1px solid rgba(47,170,106,.28);
                  border-radius:var(--r-sm); padding:var(--sp-2) var(--sp-3); margin:var(--sp-2) 0 var(--sp-1); }
    .pl-rebuilt .icon { width:14px; height:14px; flex-shrink:0; margin-top:var(--sp-1); }
    .pl-rebuilt b { color:var(--good); }
    .pl-rat { color:var(--mut); font-size:var(--fs-md); line-height:var(--lh-prose);
              max-width:var(--measure-prose); margin:var(--sp-2) 0 var(--sp-1); }
    .pl-adjust { display:flex; gap:8px; align-items:flex-start; border-radius:var(--r-md);
                 padding:var(--sp-3) var(--sp-3); margin:var(--sp-3) 0; font-size:var(--fs-xs); line-height:1.45; }
    .pl-adjust.cut { background:var(--warn-fill); border:1px solid var(--warn); }
    .pl-adjust.go,.pl-adjust.ok { background:var(--ok-fill); border:1px solid var(--good); }
    .pl-adjust b { display:block; margin-bottom:var(--sp-1); }
    .pl-days { display:flex; flex-direction:column; gap:8px; margin-top:var(--sp-3); }
    /* minmax(0,1fr) в средней колонке — тот же блоwout, что у .grid/.trends-grid
       выше: голый 1fr не сжимается уже min-content названия тренировки, и
       правая колонка .pl-meta (км/ч) вылезала за экран на 320 px (Б10,
       06.10: right=329 при вьюпорте 320). */
    .pl-day { display:grid; grid-template-columns:44px minmax(0,1fr) auto; gap:8px; align-items:baseline;
              padding:var(--sp-2) var(--sp-3); border-radius:var(--r-sm); background:var(--bg); border:1px solid var(--line);
              border-left-width:3px; }
    /* полоска слева = цвет зоны (Z1–Z5), задаётся инлайн-стилем border-left-color в шаблоне —
       так она переживает .is-today ниже (inline всегда сильнее border-color оттуда) */
    /* B1.4: inset-кольцо box-shadow убран — цвет границы (уже var(--prot))
       и так выделяет сегодняшний день среди остальных строк. */
    .pl-day.is-today { border-color:var(--prot); }
    .pl-day.is-rest { opacity:.62; }
    .pl-dow { font-weight:var(--fw-semibold); font-size:var(--fs-2xs); color:var(--mut); }
    .pl-dow .pl-dnum { display:block; font-weight:var(--fw-regular); font-size:var(--fs-2xs); }
    .pl-body .pl-title { font-weight:var(--fw-semibold); font-size:var(--fs-md); line-height:var(--lh-snug);
                          text-wrap:balance; }
    .pl-body .pl-tgt { color:var(--mut); font-size:var(--fs-sm); line-height:var(--lh-body); margin-top:var(--sp-1); }
    .pl-meta { text-align:right; font-size:var(--fs-2xs); color:var(--mut); white-space:nowrap; }
    /* ТЗ-typography-and-plan Д6: число минут — герой строки (18px/700),
       единица "мин" светлее и мельче в своём span .pl-unit, а не тем же
       весом/кеглем, что цифра (было "75  мин" — P3/P2 в ТЗ). */
    .pl-meta b { display:block; color:var(--ink); font-size:var(--fs-lg); font-weight:var(--fw-bold);
                 letter-spacing:var(--ls-num); }
    .pl-meta .pl-unit { font-size:var(--fs-2xs); font-weight:var(--fw-regular); color:var(--mut); }
    .pl-fuel { display:block; color:var(--acc-text); text-decoration:none; font-size:var(--fs-2xs); margin-top:var(--sp-1); }
    .pl-fuel:hover { text-decoration:underline; }
    /* Скачать тренировку (.zwo/.erg) — компактная строка ссылок под лесенкой дня. */
    .pl-dl { margin-top:var(--sp-1); font-size:var(--fs-2xs); }
    .pl-dl a { color:var(--acc-text); text-decoration:none; }
    .pl-dl a:hover { text-decoration:underline; }
    .pl-type { display:inline-block; font-size:var(--fs-2xs); font-weight:700; text-transform:uppercase;
               letter-spacing:.04em; padding:0 var(--sp-2); border-radius:var(--r-sm); margin-right:var(--sp-2);
               vertical-align:1px; }
    .pl-t-vo2max,.pl-t-sprint { background:rgba(224,122,63,.16); color:var(--acc); }
    .pl-t-threshold,.pl-t-tempo { background:rgba(214,158,46,.16); color:var(--warn); }
    .pl-t-endurance { background:rgba(75,163,110,.14); color:var(--good); }
    .pl-t-recovery,.pl-t-rest { background:rgba(120,130,140,.14); color:var(--mut); }
    
    .pl-t-race { background:rgba(80,144,230,.16); color:var(--prot); }
    .pl-empty { color:var(--mut); font-size:var(--fs-xs); line-height:1.5; margin:var(--sp-2) 0 var(--sp-3); }

    /* ── ДАШБОРД-СЕТКА ───────────────────────────────────────────────── */
    .dash { display:block; }
    @media (min-width:1080px){
      /* 8/4, а не 6/6 (аудит №14): слева — «что делать сегодня», справа —
         топливо. При 1.35/1 правая колонка тянула на себя половину экрана,
         и продукт структурно выглядел дневником питания с панелью сбоку. */
      .dash { display:grid; grid-template-columns:2fr 1fr; gap:16px; align-items:start; }
      .dash .col-left, .dash .col-right { min-width:0; }
    }
    /* типографика — в общем правиле микро-заголовка (П5.4); здесь только своё */
    .sec-h { margin:var(--sp-8) var(--sp-1) var(--sp-3); }
    .sec-h:first-child { margin-top:var(--sp-1); }
    .sec-h::after { content:""; flex:1; height:1px; background:var(--line); }
    .col-left > .sec-h:first-child, .col-right > .sec-h:first-child { margin-top:0; }

    /* .col-right — flex-колонка ВСЕГДА (не только на десктопном гриде выше):
       нужно для order ниже — вечером «Итог дня»/«Вода»/«Топливо» поднимаются
       наверх (аудит №11, петля привычки: вечерняя сверка раньше еды), см.
       body.evening. В обычном block-потоке соседние margin схлопываются —
       зазор перед .sec-h держался на схлопывании 14px карточки и 30px
       заголовка (итог — 30, не 44); во flex margin не схлопывается, гэп бы
       задвоился. Специфичность .col-right > .sec-h выше общего .sec-h — гасим
       именно эту пару, остальные карточки (только margin-bottom, без
       встречного margin-top) визуально не меняются. */
    .col-right { display:flex; flex-direction:column; }
    .col-right > .sec-h { margin-top:0; }

    /* ── Вечерний порядок правой колонки (аудит №11) ───────────────────────
       После ~17:00 Бкк (is_evening, см. app.py) петля привычки разворачивается:
       сначала вечерняя сверка (итог дня + вода), потом топливо/еда — днём
       порядок остаётся прежним (DOM-порядок, все order:0). #sec-recovery-h —
       заголовок «Восстановление» над карточкой воды: едет вместе с ней, иначе
       остался бы висеть без содержимого (карточка воды уехала бы наверх одна). */
    body.evening .col-right #verdict-card { order:-3; }
    /* Вода уехала ВНУТРЬ карточки «Питание» (аудит №14), поэтому вечерний
       порядок задаём самой карточке, а не воде: order действует только на
       прямых детей flex-колонки. */
    body.evening .col-right #sec-meals,
    body.evening .col-right #sec-recovery-h { order:-2; }
    body.evening .col-right #sec-fuel { order:-1; }

    /* ── Дневной порядок правой колонки (Б8, TZ-B8-en.md) ───────────────────
       Тот же механизм, что вечерний блок выше (order на прямых детях
       flex-колонки), не вторая логика рядом. Днём вопрос «топливо и разбор
       заезда» — карточки питания поднимаются, verdict-card/recovery-h НЕ
       трогаем: это вечерняя, итоговая рамка дня, не дневная. */
    body.daytime .col-right #sec-fuel { order:-2; }
    body.daytime .col-right #sec-meals { order:-1; }

    /* .col-left — та же логика, что у .col-right выше (IA-аудит №12): flex-
       колонка ВСЕГДА, чтобы order ниже мог поднять/утопить карточки вечером.
       Единственный .sec-h тут — первый child «Подготовка», уже гасится общим
       правилом строкой выше (:first-child) — доп. margin-doubling тут не
       возникает. */
    .col-left { display:flex; flex-direction:column; }

    /* ── Вечерний порядок левой колонки (IA-аудит №12) ─────────────────────
       «Завтра · погода» (sec-tomorrow) вечером — мостик в завтрашний ритуал,
       поднимается ближе к дебриф-герою наверху страницы; «Сверка: вчера»
       (sec-accountability, утренняя петля подотчётности) — сворачивается
       ниже, под сегодняшней тренировкой. sec-training (сама сессия) order не
       трогаем — она остаётся между ними в обоих режимах. */
    body.evening .col-left #sec-tomorrow { order:-1; }
    body.evening .col-left #sec-accountability { order:1; }

    /* ── Дневной порядок левой колонки (Б8) ──────────────────────────────
       «Разбор заезда» — это workout_debrief ВНУТРИ #sec-training (не
       отдельная карточка), поэтому поднимаем саму секцию, а не заводим
       новый узел. sec-accountability (вчерашняя сверка) днём менее срочна,
       чем сегодняшняя тренировка — уступает место, как вечером уступает
       sec-tomorrow. */
    body.daytime .col-left #sec-training { order:-1; }
    body.daytime .col-left #sec-accountability { order:1; }

    /* ── Переключатель времени суток (Б8) — вплотную под .cmdbar, не
       поверх: своя строка sticky-шапки, без нового зазора-схлопывания
       (.sticky/.cmdbar уже flex-колонка по умолчанию блочного потока). */
    .daypart-switch { margin-top:var(--sp-2); }

    .card { padding:var(--sp-4); border-radius:var(--r-md); }
    .row > summary { padding:var(--sp-3) var(--sp-4); }

    /* ══════════════════════════════════════════════════════════════════
       ВИДЫ / ТАБЫ (progressive enhancement). Без JS класс .has-tabs не
       ставится — фильтрация не работает, страница остаётся обычным скроллом.
       Переключатель видов — ТОЛЬКО сайдбар (десктоп, .sb-navhead выше) и
       нижний .tabbar (мобильный); прежних горизонтальных .viewtabs больше нет.
       ══════════════════════════════════════════════════════════════════ */
    /* фильтрация видов */
    body.has-tabs .v-hide { display:none !important; }
    /* Фильтрация видов ДЕКЛАРАТИВНО (аудит №14 → регрессия 24.07): раньше
       секции чужих видов прятал скрипт, и после выноса app.js в отложенный
       файл это стало происходить после первой отрисовки — страница
       схлопывалась под пользователем, экран уезжал в пустоту. Правило ниже
       применяется к секции в момент её разбора, поэтому сдвига нет вообще.
       Атрибут ставит микро-бутстрап в index.html и поддерживает setView. */
    html[data-view="today"]   body.has-tabs [data-view]:not([data-view~="today"]),
    html[data-view="plan"]    body.has-tabs [data-view]:not([data-view~="plan"]),
    html[data-view="trends"]  body.has-tabs [data-view]:not([data-view~="trends"]),
    html[data-view="profile"] body.has-tabs [data-view]:not([data-view~="profile"]) { display:none !important; }
    /* в тэб-режиме секционные разделители лишние — контекст задаёт активный таб */
    body.has-tabs .sec-h { display:none; }
    /* только «Сегодня» использует две колонки; остальные виды — одна */
    body.has-tabs:not(.view-today) .dash { display:block; }

    /* ── ЭКРАН ТРЕНДОВ ───────────────────────────────────────────────── */
    /* minmax(0,1fr) — тот же блоwout, что у .grid: карточка CTL с SVG-спарклайном
       не сжималась уже содержимого и вылезала за экран (Б10, 06.10: 346px при
       вьюпорте 320, offenders=89 в замере). */
    .trends-grid { display:grid; gap:16px; grid-template-columns:minmax(0,1fr); }
    @media (min-width:760px){ .trends-grid { grid-template-columns:minmax(0,1fr) minmax(0,1fr); } }
    /* .trend-card — см. общее определение карточки выше (П5.4). */
    /* «Кривая мощности» + «Сезоны» — один общий ряд на всю ширину сетки:
       кривая слева, сезоны справа, компактнее обычных карточек. Если из пары
       отрисована только одна карточка — она занимает весь ряд (:only-child). */
    .trend-duo { grid-column:1/-1; display:grid; gap:16px; grid-template-columns:minmax(0,1fr); }
    @media (min-width:760px){
      .trend-duo { grid-template-columns:minmax(0,1fr) minmax(0,1fr); }
      .trend-duo > .trend-card:only-child { grid-column:1/-1; }
    }
    .trend-duo > .trend-card { padding:var(--sp-3) var(--sp-3); }
    /* типографика — в общем правиле микро-заголовка (П5.4); здесь только свой отступ.
       ВАЖНО: это правило идёт ПОЗЖЕ общего, поэтому оставить тут font/letter-spacing
       значило бы переопределить общее и сохранить прежний разнобой. */
    .trend-card .tc-h { margin-bottom:var(--sp-1); }
    .trend-card .tc-big { font-size:var(--fs-4xl); font-weight:800; line-height:1.1; font-variant-numeric:tabular-nums; }
    .trend-card .tc-big small { font-size:var(--fs-sm); font-weight:600; color:var(--mut); }
    .trend-card .tc-sub { font-size:var(--fs-xs); color:var(--mut); margin-top:var(--sp-1); }
    .trends-empty { color:var(--mut); font-size:var(--fs-sm); line-height:1.55; padding:var(--sp-2) var(--sp-1); }

    /* ── переключатель периода 30/90 дней (общий для всех графиков «Трендов») ── */
    .tc-rangebar { display:flex; align-items:center; gap:8px; margin:0 0 var(--sp-4); }
    .tc-rangebar .tc-rangelbl { font-size:var(--fs-2xs); font-weight:800; letter-spacing:.08em;
      text-transform:uppercase; color:var(--mut); margin-right:var(--sp-1); }
    .tc-chip { background:var(--card2); border:1px solid var(--line); color:var(--mut);
      font-size:var(--fs-xs); font-weight:700; padding:var(--sp-1) var(--sp-3); border-radius:var(--r-full); cursor:pointer; }
    .tc-chip:hover { color:var(--ink); }
    .tc-chip.active { background:var(--elev); color:var(--ink); border-color:var(--prot); }

    /* ── полноценный график тренда (вес / CTL / готовность) ──────────── */
    .tchart { position:relative; width:100%; height:172px; margin-top:var(--sp-3); }
    .tchart .tg-svg { width:100%; height:100%; display:block; overflow:visible; }
    .tchart .tg-grid { stroke:var(--line); stroke-width:1; }
    .tchart .tg-line { fill:none; stroke-width:2; stroke-linejoin:round; stroke-linecap:round; }
    .tchart .tg-dot { stroke:var(--panel); stroke-width:2; }
    .tchart .tg-ylabel { font-size:var(--fs-2xs); fill:var(--mut); }
    .tchart .tg-xlabel { font-size:var(--fs-2xs); fill:var(--mut); }
    .tchart .tg-target { fill:none; stroke:var(--good); stroke-width:1.5; stroke-dasharray:4 3; opacity:.85; }
    .tchart .tg-cross { stroke:var(--mut); stroke-width:1; stroke-dasharray:3 3; opacity:0; pointer-events:none; }
    .tchart .tg-hoverdot { stroke:var(--panel); stroke-width:2; opacity:0; pointer-events:none; }
    .tchart .tg-ttbg { fill:var(--elev); stroke:var(--line); stroke-width:1; opacity:0; pointer-events:none; }
    .tchart .tg-ttdate { font-size:var(--fs-2xs); fill:var(--mut); opacity:0; pointer-events:none; }
    .tchart .tg-ttval { font-size:var(--fs-xs); font-weight:700; fill:var(--ink); opacity:0; pointer-events:none; }
    .tchart .tg-hit { fill:transparent; cursor:crosshair; touch-action:pan-y; }
    .tc-empty2 { display:none; color:var(--mut); font-size:var(--fs-xs); line-height:1.5;
      text-align:center; padding:var(--sp-12) var(--sp-3); }
    .tchart.is-empty .tg-svg { display:none; }
    .tchart.is-empty .tc-empty2 { display:block; }

    /* ── кривая мощности (power curve): статичный SVG, масштаб сохраняется
       равномерно (без preserveAspectRatio=none) — иначе подписи искажаются.
       На узком экране контейнер скроллится по X, сам SVG не сжимается ниже
       320px — иначе 12 подписей длительностей налезают друг на друга. ── */
    .pcurve-scroll { overflow-x:auto; margin-top:var(--sp-3); padding-bottom:var(--sp-1); }
    .pcurve-inner { min-width:320px; }
    .pcurve-svg { width:100%; height:auto; display:block; }
    .pcurve-grid { stroke:var(--line); stroke-width:1; }
    .pcurve-gridlbl { font-size:var(--fs-2xs); fill:var(--mut); }
    .pcurve-line { fill:none; stroke:var(--z4); stroke-width:2.5; stroke-linejoin:round; stroke-linecap:round; }
    .pcurve-dot { fill:var(--z4); stroke:var(--panel); stroke-width:1.5; }
    .pcurve-wlabel { font-size:var(--fs-2xs); font-weight:700; fill:var(--ink); text-anchor:middle; }
    .pcurve-xlabel { font-size:var(--fs-2xs); fill:var(--mut); text-anchor:middle; }
    .pc-stats { display:flex; flex-wrap:wrap; gap:8px; margin:var(--sp-3) 0 var(--sp-1); }
    .pc-stat { background:var(--card2); border:1px solid var(--line); border-radius:var(--r-sm);
      padding:var(--sp-2) var(--sp-3); min-width:84px; }
    .pc-stat b { display:block; font-size:var(--fs-lg); font-variant-numeric:tabular-nums; }
    .pc-stat span { color:var(--mut); font-size:var(--fs-2xs); }
    .pc-backfill { margin-top:var(--sp-3); font-size:var(--fs-2xs); color:var(--mut); display:flex;
      align-items:center; gap:8px; }

    /* ── «Структура заезда»: горизонтальная полоса-профиль повторов ──────── */
    .ivstruct-scroll { overflow-x:auto; margin-top:var(--sp-2); padding-bottom:var(--sp-1); }
    .ivstruct-inner { min-width:280px; }
    .ivstruct-svg { width:100%; height:64px; display:block; }
    .ivstruct-seg { stroke:var(--panel); stroke-width:1; }
    .ivstruct-seg.z1 { fill:var(--z1); } .ivstruct-seg.z2 { fill:var(--z2); }
    .ivstruct-seg.z3 { fill:var(--z3); } .ivstruct-seg.z4 { fill:var(--z4); }
    .ivstruct-seg.z5 { fill:var(--z5); }
    .ivstruct-seg.rec { stroke:var(--warn); stroke-width:2; }
    .ivstruct-legend { display:flex; flex-wrap:wrap; gap:8px; margin-top:var(--sp-2); font-size:var(--fs-2xs); color:var(--mut); }
    .ivstruct-legend i { display:inline-block; width:9px; height:9px; border-radius:var(--r-sm); margin-right:var(--sp-1); vertical-align:-1px; }

    /* ── «Сезоны»: годовая сводка объёма + мини-таблица рекордов ─────────── */
    .season-row { display:flex; align-items:baseline; justify-content:space-between;
      gap:8px; padding:var(--sp-3) 0; border-top:1px solid var(--line); }
    .season-row:first-of-type { border-top:0; padding-top:var(--sp-1); }
    .season-year { font-size:var(--fs-xl); font-weight:800; min-width:52px; }
    .season-stats { display:flex; flex-wrap:wrap; gap:16px; flex:1; font-size:var(--fs-xs); color:var(--mut); }
    .season-stats b { color:var(--ink); font-variant-numeric:tabular-nums; }
    .season-delta { font-size:var(--fs-2xs); font-weight:700; white-space:nowrap; }
    .season-recs-scroll { overflow-x:auto; margin-top:var(--sp-1); }
    .season-recs { display:flex; gap:8px; padding-bottom:var(--sp-1); }
    .season-recs .pc-stat { min-width:64px; flex:0 0 auto; }

    /* ── тепловая карта постоянства (карточка «Постоянство», 12 нед. × 7 дн.) ──
       Одна шкала --good «светлее→темнее» (закрыт=100%, ≥50%=.55, 1–49%=.25);
       «нет данных» — нейтральный --elev, это НЕ часть зелёной шкалы. */
    .chm-scroll { overflow-x:auto; margin-top:var(--sp-3); padding-bottom:var(--sp-1); }
    .chm-inner { display:inline-block; min-width:100%; }
    .chm-months { display:grid; grid-template-columns:repeat(12, 12px); gap:2px;
      margin:0 0 var(--sp-1) var(--sp-6); }
    .chm-mlabel { font-size:var(--fs-2xs); color:var(--mut); white-space:nowrap; }
    .chm-rows { display:flex; gap:4px; }
    .chm-rowlabels { display:grid; grid-template-rows:repeat(7, 12px); gap:2px;
      width:18px; flex:0 0 auto; }
    .chm-rowlabels span { font-size:var(--fs-2xs); line-height:12px; color:var(--mut); }
    .chm-grid { display:grid; grid-template-rows:repeat(7, 12px); grid-auto-flow:column;
      grid-auto-columns:12px; gap:2px; }
    /* .chm-scroll скроллится по X → CSS обнуляет overflow-y в 'auto' и обрежет
       обычный абсолютный тултип .rf-tip::after. Поэтому у ячеек карты — свой
       вариант тултипа: position:fixed (координаты ставит JS через --tt-x/--tt-y),
       он не обрезается родительским overflow. */
    .chm-cell.rf-tip { border-bottom:none; cursor:pointer; }
    .chm-cell.rf-tip::after {
      position:fixed; bottom:auto; left:var(--tt-x, 50vw); top:var(--tt-y, 50vh);
      transform:translate(-50%, calc(-100% - 8px));
    }
    .chm-cell { width:12px; height:12px; border-radius:var(--r-sm); background:var(--good); }
    .chm-cell.lv0 { background:var(--elev); border:1px solid var(--line); }
    .chm-cell.lv1 { opacity:.25; }
    .chm-cell.lv2 { opacity:.55; }
    .chm-cell.lv3 { opacity:1; }
    .chm-cell.chm-future { visibility:hidden; }
    .chm-legend { display:flex; align-items:center; gap:12px; margin-top:var(--sp-3);
      font-size:var(--fs-2xs); color:var(--mut); flex-wrap:wrap; }
    .chm-lg-item { display:inline-flex; align-items:center; gap:4px; }
    .chm-swatch { width:10px; height:10px; border-radius:var(--r-sm); background:var(--good);
      display:inline-block; }
    .chm-swatch.lv0 { background:var(--elev); border:1px solid var(--line); }
    .chm-swatch.lv1 { opacity:.25; }
    .chm-swatch.lv2 { opacity:.55; }
    .chm-swatch.lv3 { opacity:1; }

    /* ── вехи постоянства (7/30/100 дней лучшей серии, карточка «Постоянство») ── */
    .ms-row { display:flex; gap:8px; flex-wrap:wrap; margin-top:var(--sp-3); }

    /* ── ВЕХИ / ПРОГРЕСС ─────────────────────────────────────────────── */
    /* D2 (TZ-redesign-sections-en.md): замена .progress-strip (пилюли) одной
       тихой строкой — только на /trends (body.sec), .progress-strip сам
       остаётся нетронутым (других потребителей у него нет, но переименовать
       рискованней, чем оставить короткий алиас рядом). */
    body.sec .progress-line { display:flex; align-items:baseline; gap:6px; flex-wrap:wrap; margin:0 0 var(--sp-6); }
    body.sec .progress-line .rub.more { text-transform:uppercase; }
    .progress-strip { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:0 0 var(--sp-6); }
    .progress-strip .ps-h { font-size:var(--fs-2xs); font-weight:800; letter-spacing:.08em;
                            text-transform:uppercase; color:var(--mut); }
    /* Чип теперь ссылка на карточку-источник (аудит №11: клик молчал) —
       убираем подчёркивание ссылки, вид остаётся прежним. */
    .ps-chip { display:inline-flex; align-items:center; gap:8px; font-size:var(--fs-xs); font-weight:700;
               color:var(--good); background:rgba(47,170,106,.10); text-decoration:none; cursor:pointer;
               border:1px solid rgba(47,170,106,.32); border-radius:var(--r-full); padding:var(--sp-1) var(--sp-3); }
    .ps-chip:hover { border-color:rgba(47,170,106,.55); }
    .ps-chip .icon { width:14px; height:14px; }

    /* ── ДЕМО-БАННЕР: одна строка (текст + CTA), не разваливается на 3 строки
       даже на узком экране — flex-wrap:nowrap + текст обрезается многоточием;
       на ≤480px (аудит №11: на 390px CTA всё равно обрезал текст баннера)
       раскладка меняется на колонку с полноширинной primary-кнопкой, см.
       @media ниже. ─────────────────────────────────────────────────────── */
    .demobar { display:flex; align-items:center; gap:8px; flex-wrap:nowrap; min-width:0;
               background:linear-gradient(90deg, rgba(224,98,59,.16), rgba(224,98,59,.04));
               border:1px solid rgba(224,98,59,.4); border-radius:var(--r-sm);
               padding:var(--sp-2) var(--sp-3); margin:var(--sp-4) 0 var(--sp-1); font-size:var(--fs-xs); }
    .demobar .icon { color:var(--acc); width:15px; height:15px; flex-shrink:0; }
    /* flex-basis обязан быть 0, а не auto: при auto строка с white-space:nowrap
       требует свою полную ширину ещё на этапе расчёта минимального размера —
       баннер распирал .main шире колонки сетки, и вся страница на телефоне
       ехала вбок (обрезались дата в шапке и вкладка «Профиль»). */
    .demobar span.dm-txt { min-width:0; flex:1 1 0%; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
    .demobar-cta { flex-shrink:0; font-weight:700; color:var(--acc); white-space:nowrap;
                   border:1px solid var(--acc); border-radius:var(--r-sm); padding:var(--sp-1) var(--sp-3); }
    .demobar-cta:hover { background:rgba(224,98,59,.12); }
    @media (max-width:480px){
      /* Аудит №11: на самых узких телефонах текст баннера обрезался
         многоточием рядом с мелкой outline-кнопкой — вместо сжатия в одну
         строку баннер встаёт в колонку, текст читается целиком, а CTA
         становится полноширинной primary-кнопкой (тот же токен, что у
         button/.btn — background var(--acc), белый текст). Короткий
         data-short здесь больше не нужен — места хватает на полную фразу. */
      .demobar { flex-wrap:wrap; }
      /* `.demobar span.dm-txt`, не `.demobar .dm-txt`: у базового правила
         (выше, вне media) селектор включает тег span — специфичность (0,2,1).
         Здесь без тега было (0,2,0) — ниже, и переопределение проигрывало
         каскад независимо от медиа-условия. Текст баннера обрезался
         многоточием на 320–430 px даже после аудита №11 (Б10, 06.10: замер
         clientWidth 239 < scrollWidth 345 на всех трёх ширинах). */
      .demobar span.dm-txt { white-space:normal; overflow:visible; text-overflow:clip; flex:1 1 100%; }
      .demobar-cta { flex:1 1 100%; text-align:center; background:var(--acc); color:var(--on-acc);
                     border-radius:var(--r-md); padding:var(--sp-3) var(--sp-4); }
      .demobar-cta:hover { background:var(--acc); filter:brightness(1.08); }
      .demobar-cta .cta-full { font-size:inherit; }
      .demobar-cta::before { content:none; }
    }
    /* в демо действия-формы визуально «живые», но submit перехватывается JS */

    /* ── /demo: ОДНО действие на экран (аудит №15) ─────────────────────────
       На демо-странице ~130 кликабельных элементов, и десяток из них залит
       акцентом — при том что все они ведут в один и тот же тост «это демо».
       Живое действие здесь ровно одно: «Начать свой дневник». Поэтому в демо
       акцентная заливка снимается со ВСЕХ первичных кнопок (через --btn-bg,
       см. правило button/.btn выше) и остаётся только у демо-CTA —
       TZ-design-system §1: один оранжевый на экран.
       Кнопки при этом НЕ отключаются и не прячутся: отклик на клик оставлен
       намеренно — без него демо читается как сломанный сайт (аудит №11). */
    body.demo { --btn-bg:var(--elev); --btn-fg:var(--ink); }
    body.demo button, body.demo .btn { border:1px solid var(--line); }
    body.demo .btn-analyze { animation:none; }
    /* CTA баннера — единственная первичная кнопка демо, на всех ширинах
       (была outline-чипом, залитой становилась только на ≤480px). */
    .demobar-cta { --btn-bg:var(--acc); --btn-fg:var(--on-act); }
    body.demo .demobar-cta { background:var(--acc); color:var(--on-act);
                             border:1px solid var(--acc); border-radius:var(--r-md);
                             padding:var(--sp-3) var(--sp-4); min-height:var(--tap-min);
                             display:inline-flex; align-items:center; }
    body.demo .demobar-cta:hover { background:var(--acc); filter:brightness(1.08); }

    /* ── СОСТОЯНИЕ ГОНЩИКА: трёхцветные шкалы ────────────────────────────
       Зоны и границы считает objective.state_gauges (там же их происхождение),
       тут только отрисовка. Дорожка раскрашена ЦЕЛИКОМ, а не подсвечивает
       здоровую полосу: важно видеть не «попал/не попал», а в какую сторону
       промах — недогруз и перегруз лечатся противоположными действиями. */
    .statecard { background:var(--card); border:1px solid var(--line); border-radius:var(--r-md);
                 padding:var(--sp-4) var(--sp-4) var(--sp-3); margin-bottom:var(--sp-4); }
    .statecard > .sc-h { display:flex; align-items:center; gap:8px; font-size:var(--fs-2xs);
                         font-weight:700; color:var(--mut); text-transform:uppercase;
                         letter-spacing:.05em; margin-bottom:var(--sp-3); }
    .sc-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(170px,1fr)); gap:16px 24px; }
    .sc-item .sc-top { display:flex; align-items:baseline; justify-content:space-between; gap:8px; }
    .sc-item .sc-name { font-size:var(--fs-2xs); color:var(--mut); font-weight:600; }
    .sc-item .sc-val { font-size:var(--fs-lg); font-weight:700; font-variant-numeric:tabular-nums;
                       line-height:1.1; }
    .sc-item.ok   .sc-val { color:var(--good); }
    .sc-item.low  .sc-val { color:var(--warn); }
    .sc-item.high .sc-val { color:var(--over); }
    .sc-track { position:relative; height:7px; border-radius:var(--r-full); overflow:hidden;
                margin-top:var(--sp-2); display:flex; background:var(--card2); }
    .sc-zone { height:100%; }
    .sc-zone.low  { background:rgba(217,162,59,.42); }
    .sc-zone.ok   { background:rgba(47,170,106,.55); }
    .sc-zone.high { background:rgba(194,84,58,.5); }
    /* Бегунок: белая риска с обводкой — видна на любой из трёх зон (B1.4:
       обводящее кольцо раньше рисовал box-shadow, теперь outline). */
    .sc-mark { position:absolute; top:-3px; width:3px; height:13px; border-radius:var(--r-sm);
               background:var(--ink); outline:2px solid var(--card);
               transform:translateX(-50%); transition:left .5s cubic-bezier(.4,0,.2,1); }
    /* ── ПУСТОЕ СОСТОЯНИЕ ВИДА (аудит №14, крит.3) ─────────────────────────
       Не «заглушка», а витрина: что здесь появится и что для этого нужно. */
    .view-empty { text-align:center; padding:var(--sp-8) var(--sp-6); }
    .view-empty .ve-ico { width:46px; height:46px; margin:0 auto var(--sp-4); border-radius:var(--r-md);
                          display:flex; align-items:center; justify-content:center;
                          background:var(--card2); border:1px solid var(--line); }
    .view-empty .ve-ico .icon { width:22px; height:22px; color:var(--mut); }
    .view-empty .ve-h { font-size:var(--fs-xl); margin:0 0 var(--sp-2); }
    .view-empty .ve-t { color:var(--mut); font-size:var(--fs-sm); margin:0 auto var(--sp-4); max-width:52ch; line-height:1.55; }
    .view-empty .ve-cta { display:flex; gap:8px; justify-content:center; flex-wrap:wrap; }

    /* 11px было ниже пола читаемости (--fs-2xs=12px) — аудит №14 */
    .sc-item .sc-state { font-size:var(--fs-2xs); font-weight:700; margin-top:var(--sp-1); }
    .sc-item .sc-band { color:var(--mut); font-weight:500; }
    .sc-item.ok   .sc-state { color:var(--good); }
    .sc-item.low  .sc-state { color:var(--warn); }
    .sc-item.high .sc-state { color:var(--over); }
    @media (prefers-reduced-motion: reduce) { .sc-mark { transition:none; } }
    /* Шкалы внутри карточки состояния (аудит №13, ТЗ-3): своя рамка и фон
       больше не нужны — карточка одна, вторая рамка внутри неё читалась бы как
       ещё один блок, ровно то дробление, от которого уходим. */
    /* Полоса состояния под героем (аудит №14): плитки в РЯД во всю ширину.
       Форма (CTL) — не плитка, а хвост строки: у формы нет потолка, шкала
       выдумала бы ему смысл. На узком экране CTL уходит под плитки. */
    .statecard.strip { display:flex; align-items:center; gap:24px; padding:var(--sp-4) var(--sp-4); }
    .statecard.strip .sc-grid { flex:1; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); }
    .statecard.strip .sc-form { margin-top:0; padding-top:0; padding-left:var(--sp-6);
                                border-top:0; border-left:1px dashed var(--line);
                                flex-direction:column; align-items:flex-start; gap:2px; }
    .statecard.strip .sc-form-go { margin-left:0; }
    @media (max-width:900px){
      .statecard.strip { display:block; }
      .statecard.strip .sc-form { margin-top:var(--sp-4); padding:var(--sp-3) 0 0; border-left:0;
                                  border-top:1px dashed var(--line);
                                  flex-direction:row; align-items:baseline; gap:8px; }
      .statecard.strip .sc-form-go { margin-left:auto; }
    }
    /* min-height: строка-ссылка «сверка» кликается целиком, а собиралась в
       41px — под нормой 44 (замерено в браузере). */
    .sc-form { display:flex; align-items:baseline; gap:8px; margin-top:var(--sp-4);
               padding-top:var(--sp-3); border-top:1px dashed var(--line);
               font-size:var(--fs-xs); color:var(--mut); min-height:var(--tap-min); }
    .sc-form b { font-size:var(--fs-lg); font-weight:700; color:var(--ink);
                 font-variant-numeric:tabular-nums; }
    .sc-form-go { margin-left:auto; color:var(--acc-text); font-weight:700; }

    /* ── НИЖНЯЯ ТАБ-НАВИГАЦИЯ (mobile-first; на десктопе скрыта) ──────── */
    .tabbar { display:none; }
    /* ── ПЛАВАЮЩАЯ КНОПКА «Добавить еду» (mobile-first; на десктопе скрыта) ── */
    .fab-add { display:none; }
    /* Поповер «быстрая вода» живёт в DOM всегда (см. ниже), но позиционируется
       только в мобильном @media. На десктопе без этого правила он вываливался
       в обычный поток внизу слева пачкой кнопок «мл» — гасим по умолчанию,
       мобильный @media вернёт ему display:flex. */
    .fab-water-pop { display:none; }

    /* ── МОБИЛЬНЫЙ: верхняя app-bar (бренд+день) + нижний таб-бар ─────── */
    @media (max-width:1000px){
      .app { grid-template-columns:1fr; }
      /* ⛔ min-width:0 НА САМОМ САЙДБАРЕ — ПРАВИЛО КЛАССА, А НЕ ЗАПЛАТКА НА СТРАНИЦУ.
         .sidebar — грид-элемент .app, а у грид-элементов min-width по умолчанию
         auto, то есть «не уже своего содержимого». Поэтому строка сайдбара не
         сжимается до ширины экрана, КАКИЕ БЫ дети в ней ни лежали, и тянет за
         собой весь документ: на 320 px главная ехала вбок на 29 px (ru) и 10 (en),
         а пятая вкладка таб-бара уезжала за правый край на 25 px — по ней нельзя
         было попасть (замер Б10а, B10a-mobile-320-sweep.md).
         ⚠️ Правку 10.08 ниже (.sb-day/.d/.step) НЕ УБИРАЕМ: она про то, чтобы
         дети сжимались КРАСИВО — многоточием, а не мятыми кнопками. Но сама по
         себе она держалась лишь пока детей было трое: на /plan, /health и
         /profile в сайдбаре только бренд, а на главной есть ещё .sb-day, и
         возврат дефекта был вопросом времени. Проверено опытом в живой странице:
         min-width:0 у ДЕТЕЙ ничего не меняет (349 px), min-width:0 у САМОГО
         сайдбара даёт 320. overflow:hidden тоже даёт 320, но обрезал бы дату
         вместо многоточия — поэтому не он. */
      .sidebar { position:sticky; top:0; height:auto; z-index:40; flex-direction:row;
                 align-items:center; gap:8px; padding:var(--sp-2) var(--sp-3); overflow:visible;
                 min-width:0;
                 border-right:0; border-bottom:1px solid var(--line); }
      .sb-brand { padding:0 var(--sp-2) 0 0; white-space:nowrap; min-width:0; overflow:hidden; text-overflow:ellipsis; }
      .sb-brand small { display:none; }
      /* длинный список и низ — уходят в нижний таб-бар; вверху только бренд+день */
      .sb-nav, .sb-spacer, .sb-foot { display:none; }
      /* ⛔ Горизонтальный выезд на 320px (найдено при клик-тесте /plan-/health-
         /profile, TZ-ia-pages.md, пакет 2, 10.08): flex-shrink:0 не давал этому
         блоку сжаться внутри .sidebar (flex-direction:row), а у флекс-детей
         .sb-day .d по умолчанию min-width:auto — по ширине контента (дата +
         «сегодня»), не по доступному месту. На узких телефонах (320) бренд +
         два круглых шага + дата суммарно шире экрана. min-width:0 разрешает
         сжатие; .step — flex-shrink:0, чтобы кнопки не мялись первыми. */
      .sb-day { margin:0 0 0 auto; min-width:0; }
      .sb-day .d { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
      .sb-day a.step { flex-shrink:0; }
      /* ⛔ ЗОНА НАЖАТИЯ ≥44 px БЕЗ СДВИГА РАЗМЕТКИ (Б10б, свёртка B10a §2).
         Приём тот же, что уже стоит у .sb-day a.step (::before с отрицательным
         inset): рамка элемента не меняется, растёт только область, которую
         ловит палец. Поэтому число блоков, высота страницы и порядок секций
         остаются прежними — проверено парным замером на четырёх страницах.
         ⚠️ Расширяем ТОЛЬКО ПО ВЕРТИКАЛИ там, где элементы стоят в ряд: по
         горизонтали соседи в 8 px друг от друга, и встречные зоны отбирали бы
         нажатия друг у друга — дефект вместо починки.
         ⛔ Чего здесь НЕТ и почему: .radio-native (13×13) и input (24×24) не
         расширяем — каждый лежит внутри <label class="opt-check"> размером
         238×44, и настоящая цель нажатия это метка, а не сам контрол
         (замерено). .sb-day a.step (40×40) уже расширен своим ::before с
         10.08. Инертные подписи <label> без for и без вложенного поля целями
         нажатия не являются вовсе. */
      .wbtn-sm { position:relative; }
      .wbtn-sm::after { content:""; position:absolute; inset:-2px 0; }
      .ps-chip { position:relative; }
      .ps-chip::after { content:""; position:absolute; inset:-7px 0; }
      .logout-link, .muted-2xs { position:relative; display:inline-block; }
      .logout-link::after, .muted-2xs::after { content:""; position:absolute; inset:-13px 0; }
      .pagenav a { position:relative; }
      .pagenav a::after { content:""; position:absolute; inset:-3px 0; }
      .ftp-hint a { position:relative; display:inline-block; }
      .ftp-hint a::after { content:""; position:absolute; inset:-12px 0; }

      .main { padding:0 var(--sp-4) 86px; }     /* место под фиксированный таб-бар; 86px — высота
        таб-бара + отступ, функциональное значение под реальный размер элемента, не рядом ритма */
      [id^="sec-"] { scroll-margin-top:120px; }

      /* B1.4: было ещё и box-shadow сверху — border-top уже отделяет таб-бар
         от контента, тень поверх границы была лишней. */
      .tabbar { display:flex; position:fixed; left:0; right:0; bottom:0; z-index:45;
                background:var(--sidebar); border-top:1px solid var(--line);
                padding:8px 4px calc(8px + env(safe-area-inset-bottom)); gap:2px; }
      .tabbar a { position:relative; flex:1; min-width:0; display:flex; flex-direction:column; align-items:center;
                  gap:3px; color:var(--mut); font-size:var(--fs-2xs); font-weight:500; padding:var(--sp-1) var(--sp-1);
                  border-radius:var(--r-sm); text-align:center; }
      .tabbar a .icon { width:21px; height:21px; }
      .tabbar a span { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:100%; }
      /* TZ-redesign-sections-en.md D1: активный пункт навигации — не действие,
         а состояние («ты здесь»), поэтому не несёт единственный оранжевый
         (TZ-design-system.md: оранжевый = интерактивное). --ink вместо --acc;
         фокус-кольцо (не цвет) остаётся единственным акцентом тач-таргета. */
      .tabbar a.active { color:var(--ink); }
      .tabbar a.active .icon { color:var(--ink); }
      /* Точка «идёт сбор» в нижнем таб-баре — та же .nav-camp-dot, но тут вид
         колонкой (иконка/подпись), поэтому маркер уходит в угол абсолютом. */
      .tabbar .nav-camp-dot { position:absolute; top:2px; right:calc(50% - 16px); margin-left:0; }

      /* ~58px — высота таб-бара (иконка+подпись+паддинги), см. .tabbar выше;
         +12px зазор над ним, плюс safe-area на «чёлку»/жест-бар снизу. */
      /* B1.4: было box-shadow для отрыва от фона под кнопкой — теперь тонкая
         граница поверхности (--pl), тень на тёмном читалась как грязь. */
      .fab-add { display:flex; align-items:center; justify-content:center;
                 position:fixed; right:16px; bottom:calc(58px + 12px + env(safe-area-inset-bottom));
                 width:56px; height:56px; border-radius:50%; border:1px solid var(--pl);
                 background:var(--btn-bg,var(--acc)); color:var(--btn-fg,var(--on-acc)); cursor:pointer; z-index:45;
                 transition:opacity var(--transition-fast) ease, transform var(--transition-fast) ease;
                 /* long-press (быстрая вода, см. JS) не должен всплывать нативным
                    выделением/колаутом iOS поверх нашего поповера */
                 -webkit-touch-callout:none; -webkit-user-select:none; user-select:none;
                 /* iOS Safari: без manipulation браузер ждёт возможный
                    двойной тап (зум) и отдаёт клик с задержкой — тап по кнопке
                    ощущается «через раз». Подсветку тапа гасим свою (:active). */
                 touch-action:manipulation; -webkit-tap-highlight-color:transparent; }
      /* Невидимый запас вокруг круга: у круглой кнопки палец промахивается по
         касательной чаще, чем кажется по её диаметру. 6px со всех сторон —
         это 68px области нажатия при 56px картинки, и при этом остаётся 6px
         зазора до таб-бара, чтобы кнопка не воровала тапы по вкладкам. */
      .fab-add::before { content:""; position:absolute; inset:-6px; border-radius:50%; }
      .fab-add .icon { width:24px; height:24px; }
      .fab-add:active { transform:scale(.96); }
      /* Сдвиг «уйти с дороги» и нажатие оба пишут transform: без этого правила
         нажатие по сдвинутой кнопке роняло её обратно на 14px под пальцем. */
      .fab-add.fab-shift:active { transform:translateY(-14px) scale(.96); }
      .fab-add.fab-hide { opacity:0; pointer-events:none; }

      /* ── Мини-поповер «быстрая вода» (long-press по FAB) ──────────────
         Тот же приём, что у .toast: элемент всегда в DOM, прячем
         прозрачностью+pointer-events, а не display:none — есть куда
         анимировать появление, и он виден в dump-dom для тестов. */
      .fab-water-pop { position:fixed; right:16px;
                        bottom:calc(58px + 12px + 56px + 10px + env(safe-area-inset-bottom));
                        /* выше тоста (60): тост стоит в той же полосе, и если он
                           придёт фоном уже при открытом поповере, кнопки объёма
                           должны остаться сверху и кликабельными */
                        z-index:61; display:flex; flex-direction:column; gap:8px;
                        /* B1.4: попап реально «поднят» над страницей — вместо тени
                           даёт это более светлая поверхность --elev (=--s2). */
                        background:var(--elev); border:1px solid var(--line);
                        border-radius:var(--r-md); padding:var(--sp-2);
                        opacity:0; transform:translateY(8px) scale(.95); pointer-events:none;
                        transition:opacity var(--transition-fast) ease, transform var(--transition-fast) ease; }
      .fab-water-pop.fwp-show { opacity:1; transform:translateY(0) scale(1); pointer-events:auto; }
      .fab-water-pop .fwp-btn { white-space:nowrap; }
      /* FAB — только на виде «Сегодня» (иначе тап по нему на «Плане»/«Трендах»/
         «Профиле» открывает камеру без видимого повода). Без .has-tabs в
         селекторе: если IIFE вкладок вышла раньше (!sections.length — пустое
         состояние), классов view-* на body нет, и это правило не должно молча
         прятать FAB навсегда. */
      body.has-tabs:not(.view-today) .fab-add { display:none; }

      /* Журнал еды: 4 крупные плитки .chips на телефоне растягивали карточку
         приёма на пол-экрана — 3 приёма подряд превращались в 3 экрана скролла.
         Схлопываем в одну строку «460 ккал · У 58 · Б 22 · Ж 12» чистым CSS,
         без второй разметки: числа остаются теми же <b>, меняем только раскладку
         и подменяем ДЛИННУЮ подпись (span «углев, г» и т.п.) короткой буквой
         через ::before — сама цифра нигде не дублируется. */
      .meal .chips { display:flex; align-items:baseline; flex-wrap:wrap; gap:0;
                     background:none; border:0; padding:var(--sp-1) 0 0; margin:var(--sp-2) 0 0; }
      .meal .chip { flex:0 0 auto; background:none; border:0; padding:0;
                    display:inline-flex; align-items:baseline; }
      /* разделитель «·» перед каждым чипом, кроме первого (ккал остаётся
         «460 ккал» как есть) — а для У/Б/Ж в тот же ::before добавляем букву
         ПЕРЕД числом (::before рендерится раньше <b> в потоке несмотря на то,
         что стоит в разметке после него — так получаем «· У 58», а не «58У»). */
      .meal .chip:not(:first-child)::before { color:var(--mut); margin-right:var(--sp-1); }
      .meal .chip:nth-child(2)::before { content:"· У "; }
      .meal .chip:nth-child(3)::before { content:"· Б "; }
      .meal .chip:nth-child(4)::before { content:"· Ж "; }
      .meal .chip b { font-size:var(--fs-sm); font-weight:700; }
      .meal .chip span { color:var(--mut); font-size:var(--fs-xs); margin-left:var(--sp-1); }
      /* полную подпись прячем (не удаляем — на десктопе она видна как раньше),
         не через display:none, чтобы порядок чтения скринридером не менялся */
      .meal .chip:nth-child(2) span, .meal .chip:nth-child(3) span, .meal .chip:nth-child(4) span {
        font-size:0;
      }
    }

    /* ── ТОСТ: подтверждение записи еды. Карточка-результат живёт в списке
       приёмов ниже прокрутки, а после системной камеры iOS возвращает к верху
       страницы — без закреплённой плашки атлет не видит вообще никакой
       реакции («всё пропало»). Тост виден при любой прокрутке. ── */
    /* B1.4: тост — тоже «поднятый» слой, поверхность --elev вместо тени. */
    .toast { position:fixed; left:50%; transform:translateX(-50%) translateY(14px);
             bottom:calc(20px + env(safe-area-inset-bottom)); z-index:60;
             background:var(--elev); border:1px solid var(--line);
             border-radius:var(--r-md); padding:var(--sp-3) var(--sp-4); font-size:var(--fs-sm); font-weight:600;
             opacity:0; pointer-events:none;
             transition:opacity var(--transition-fast) ease, transform var(--transition-fast) ease;
             max-width:calc(100vw - 32px); white-space:nowrap; overflow:hidden;
             text-overflow:ellipsis; cursor:pointer; }
    .toast.show { opacity:1; transform:translateX(-50%) translateY(0); pointer-events:auto; }
    /* HTML-тосты (напр. демо-режим со ссылкой «Начать →») — текст длиннее
       одной строки и не должен резаться многоточием, как у коротких
       текстовых тостов «Записано: …». */
    .toast.toast-wrap { white-space:normal; overflow:visible; text-overflow:clip;
                        text-align:center; line-height:1.4; }
    .toast-link { color:var(--acc-text); text-decoration:underline; font-weight:700; }
    @media (max-width:1000px){
      /* ⛔ ТОСТ ВЫШЕ FAB, А НЕ НА НЁМ. Раньше тост стоял на 58+14px, то есть в
         той же полосе, что и кнопка «добавить еду» (58+12px, высота 56px), был
         шириной почти во весь экран, с z-index 60 против 45 у кнопки и с
         pointer-events:auto — и ЛЮБОЙ тап по вилке с ножом ближайшие 6 секунд
         после любого действия попадал в тост, а не в кнопку. Жалоба с iPhone
         06.08: «кнопка очень плохо кликается и не всегда срабатывает».
         Ставим над кнопкой тем же расчётом, что и поповер воды:
         таб-бар 58 + зазор 12 + кнопка 56 + зазор 10. */
      .toast { bottom:calc(58px + 12px + 56px + 22px + env(safe-area-inset-bottom)); }
    }

    /* Человеческая дата рядом с нативным date-input (аудит №14) */
    .date-human { display:block; margin-top:var(--sp-1); font-size:var(--fs-2xs); color:var(--mut); }

    /* ── Переключатель недели «Штаб / Как ввёл тренер» (аудит №14) ────────── */
    .wk-tabs { display:inline-flex; gap:2px; padding:var(--sp-1); margin:0 0 var(--sp-3);
               background:var(--card2); border:1px solid var(--line); border-radius:var(--r-md); }
    .wk-tab { background:transparent; color:var(--mut); font-size:var(--fs-xs); font-weight:700;
              padding:var(--sp-2) var(--sp-4); border-radius:var(--r-sm); min-height:38px; }
    .wk-tab:hover { filter:none; color:var(--ink); }
    .wk-tab.active { background:var(--panel); color:var(--ink); }
    .wk-hide { display:none !important; }

/* ── Липкое оглавление длинной страницы (аудит №14) ─────────────────────── */
.pagenav { position:sticky; top:0; z-index:20; display:flex; gap:8px; overflow-x:auto;
           margin:0 -16px var(--sp-4); padding:var(--sp-3) var(--sp-4);
           background:var(--bg, #0f1216); border-bottom:1px solid var(--line, #232a33);
           -webkit-overflow-scrolling:touch; scrollbar-width:none; }
.pagenav::-webkit-scrollbar { display:none; }
.pagenav a { flex:0 0 auto; padding:var(--sp-2) var(--sp-3); border-radius:var(--r-full); text-decoration:none;
             font-size:var(--fs-xs); font-weight:600; white-space:nowrap;
             color:var(--mut, #93a0b0); background:var(--card2, #161b22);
             border:1px solid var(--line, #232a33); min-height:38px;
             display:inline-flex; align-items:center; }
.pagenav a:hover { color:var(--ink, #e8edf3); }
@media print { .pagenav { display:none; } }

    /* Полоса-оглавление показывается только на мобиле: на десктопе тот же
       список уже есть в сайдбаре, две навигации подряд — жалоба аудитов №5–9. */
    .pagenav.only-mobile { display:none; }
    @media (max-width:900px){ .pagenav.only-mobile { display:flex; } }

    /* Описание блюда под коротким названием (аудит №14) — второстепенное,
       нужно для сверки «что именно посчитал ИИ», но не заголовок записи. */
    .meal-desc { color:var(--mut); font-size:var(--fs-2xs); line-height:1.45;
                 margin:var(--sp-1) 0 var(--sp-2); }

    /* ── ЗОНА ТАПА ≥44 px (аудит №14) ──────────────────────────────────────
       Правило: визуальный размер контролов НЕ меняем (иначе поедет вёрстка
       карточек), а зону касания добираем псевдоэлементом — приём уже применён
       к стрелкам дня в сайдбаре, теперь он общий для всех мелких кнопок.
       Норма 44×44 — Apple HIG / WCAG 2.5.5 target size. */
    .tbtn.icon-only, .bx, .fwp-btn, .csel, .wk-tab { position:relative; }
    .tbtn.icon-only::after, .bx::after {
      content:""; position:absolute; left:50%; top:50%;
      width:44px; height:44px; transform:translate(-50%,-50%); }
    /* Чекбоксы (чек-лист сборов, опции) — 20 px рисуем, 44 px касаемся. */
    /* Чекбоксы чек-листов: 24 px рисуем (аудит просил ≥24), 44 — касаемся */
    input[type=checkbox] { position:relative; width:24px; height:24px; }
    input[type=checkbox]::after {
      content:""; position:absolute; left:50%; top:50%; width:44px; height:44px;
      transform:translate(-50%,-50%); }
    /* B2 (аудит №15): та же логика для ссылок-действий, которые аудит пропустил —
       строки сайдбара, «питание →» в плотной строке дня, сегменты статус-полосы,
       ссылки .zwo/.erg, «Повторить →». Раздувать паддингом плотные списки нельзя
       (сайдбар/строка дня едут), поэтому у каждой — свой инсет под её фактическую
       высоту, а не одно число на всех. .wk-tab и .cmd-auth не в плотном списке —
       им проще выставить min-height напрямую. */
    .wk-tab { min-height:44px; }
    .cmd-auth { min-height:44px; }
    .sb-nav a, .pl-fuel, .hs-link, a.stat-seg, .retry-link { position:relative; }
    .sb-nav a::before, .hs-link::before, .retry-link::before { content:""; position:absolute; inset:-12px; }
    .pl-fuel::before { content:""; position:absolute; inset:-13px; }
    a.stat-seg::before { content:""; position:absolute; inset:-8px; }
    /* Ссылки, стоящие БОК О БОК в одной строке (скачать .zwo/.erg, подвал
       «Зачем это»/«Политика», переключатель RU/EN) — инсет несимметричный:
       по вертикали до 44, по горизонтали уже, чтобы соседние ссылки не
       перекрывали друг друга зоной тапа. */
    .pl-dl a, .foot a, .lang-switch a { position:relative; }
    /* -14px, а не -13: строка ссылки в подвале 17px, при -13 зона выходила
       43px — на пиксель ниже нормы (замерено кликом в браузере, 390px). */
    .pl-dl a::before, .foot a::before, .lang-switch a::before {
      content:""; position:absolute; inset:-14px -3px; }

    /* ── Таблица зон Z1–Z5 (аудит №14) ────────────────────────────────────
       Цвета — те же токены --z1…--z5, что красят структуру заезда: одна зона
       имеет один цвет во всём продукте. */
    /* overflow-x:auto — тот же паттерн, что у .statusbar/.pagenav/.pcurve-scroll:
       table-layout:auto не сжимает .ztable уже содержимого (имя+описание зоны +
       ватты + %), и на 320 px таблица вылезала на 336px (Б10, 06.10, /profile).
       Горизонтальный скролл честнее, чем ломать описание зоны на случайные
       переносы — так же решено для кривой мощности выше. */
    .zones { margin-top:var(--sp-4); padding-top:var(--sp-4); border-top:1px solid var(--line);
             overflow-x:auto; }
    .zones-h { font-size:var(--fs-xs); font-weight:700; color:var(--mut); margin-bottom:var(--sp-2);
               letter-spacing:.04em; text-transform:uppercase; }
    .zones-h small { text-transform:none; letter-spacing:0; font-weight:600; }
    .ztable { width:100%; border-collapse:collapse; font-size:var(--fs-sm); }
    .ztable td { padding:var(--sp-2) var(--sp-2); border-bottom:1px solid var(--line); vertical-align:top; }
    .ztable tr:last-child td { border-bottom:0; }
    .z-code { font-weight:800; width:34px; }
    .ztable tr.z-1 .z-code { color:var(--z1,#5b9bd5); }
    .ztable tr.z-2 .z-code { color:var(--z2,#57b894); }
    .ztable tr.z-3 .z-code { color:var(--z3,#d9a23b); }
    .ztable tr.z-4 .z-code { color:var(--z4,#e0623b); }
    .ztable tr.z-5 .z-code { color:var(--z5,#c94f6d); }
    .z-name { font-weight:600; }
    .z-hint { display:block; color:var(--mut); font-weight:400; font-size:var(--fs-2xs);
              margin-top:var(--sp-1); }
    .z-w { text-align:right; font-weight:700; font-variant-numeric:tabular-nums;
           white-space:nowrap; }
    .z-pct { text-align:right; color:var(--mut); font-size:var(--fs-2xs);
             font-variant-numeric:tabular-nums; white-space:nowrap; }

    /* ── Онбординг: три шага, один экран (аудит №14) ────────────────────── */
    .onb { list-style:none; counter-reset:onb; margin:0 0 var(--sp-4); padding:0; text-align:left; }
    .onb-step { display:flex; gap:12px; align-items:flex-start; padding:var(--sp-3) 0;
                border-bottom:1px solid var(--line); }
    .onb-step:last-child { border-bottom:0; }
    .onb-n { flex:none; width:26px; height:26px; border-radius:var(--r-sm); display:grid;
             place-items:center; font-size:var(--fs-2xs); font-weight:800;
             background:var(--card2); color:var(--mut); border:1px solid var(--line); }
    .onb-step.active .onb-n { background:var(--acc); color:var(--on-acc); border-color:var(--acc); }
    .onb-step b { display:block; font-size:var(--fs-sm); }
    .onb-step.active b { color:var(--ink); }
    .onb-step:not(.active) b { color:var(--mut); }
    .onb-step span { display:block; color:var(--mut); font-size:var(--fs-2xs);
                     line-height:1.45; margin-top:var(--sp-1); }

    /* FAB уходит с дороги, когда под ним контент (аудит №14: оранжевая кнопка
       садилась прямо на строку «СОН»). Смещение, а не исчезновение: действие
       остаётся доступным. */
    .fab-add.fab-shift { transform:translateY(-14px); opacity:.85; }

    /* ── ПОЛ ЧИТАЕМОСТИ И ЗОНА ТАПА — общими правилами (аудит №14) ─────────
       <small> без явного размера браузер делает 0.83em: в шапке карточки
       (13px) это давало 10.8px — ниже практического минимума. Пиним пол;
       любое правило с классом всё ещё перебивает это (специфичность выше). */
    small { font-size:var(--fs-2xs); }
    /* Кнопки и строки-раскрывашки: 44 px — минимальная цель по WCAG 2.5.5.
       Меняем только высоту, не паддинги — вёрстка карточек не едет. */
    button, .btn, .wbtn, .tbtn { min-height:44px; }
    /* Все раскрывашки, не только .row: спойлеры «совет», «состав по позициям»
       и «полный разбор» тоже нажимают пальцем. */
    details > summary { min-height:44px; display:flex; align-items:center; }
    .tbtn.icon-only { min-height:0; }   /* у иконки зона добирается ::after выше */

    /* Журнал и вода внутри карточки «Питание» — строками без своей рамки:
       карточка одна, вторая рамка внутри читалась бы как ещё один блок. */
    #sec-meals #meals-wrap { margin-top:var(--sp-3); }
    #sec-meals .row { background:transparent; border:0; border-top:1px solid var(--line);
                      border-radius:0; padding-left:0; padding-right:0; margin:0; }

    /* Кнопка закрытия шторки — полноценная цель касания (аудит №14) */
    .sheet .close { min-width:44px; min-height:44px; }

    /* Поповер быстрых действий: заголовки групп и ряд RPE (аудит №14) */
    .fwp-h { width:100%; font-size:var(--fs-2xs); font-weight:700; color:var(--mut);
             letter-spacing:.04em; text-transform:uppercase; margin:var(--sp-1) 0 0; }
    .fwp-row { display:flex; gap:8px; width:100%; }
    .fwp-row .fwp-btn { flex:1; }
    /* Ряд RPE в поповере — та же сетка 5×2, что и на остальных четырёх
       поверхностях (.rpe-scale выше). Специфичность здесь ОБЯЗАТЕЛЬНА: у
       .rpe-scale и .fwp-row она одинаковая, а .fwp-row объявлен НИЖЕ по
       файлу и без этой пары правил выиграл бы своим display:flex, вернув
       десять цифр в один нечитаемый ряд. */
    .fwp-row.rpe-scale { display:grid; grid-template-columns:repeat(5, minmax(40px, 1fr)); }
    .fwp-row.rpe-scale .fwp-btn { flex:none; }


    /* Полоса «дневник только в этом браузере» (см. needs_account в app.py).
       Тон предупреждающий, но не тревожный: это не ошибка атлета, а факт,
       который продукт обязан назвать до того, как данные потеряются. */
    .link-warn { display:flex; align-items:center; gap:8px; margin:0 0 var(--sp-3);
      padding:var(--sp-3) var(--sp-3); border:1px solid var(--warn); border-radius:var(--r-md);
      background:color-mix(in srgb, var(--warn) 10%, transparent);
      color:var(--ink); text-decoration:none; font-size:var(--fs-xs); line-height:1.4; }
    .link-warn .icon { flex:0 0 auto; color:var(--warn); }
    .link-warn-cta { margin-left:auto; flex:0 0 auto; font-weight:700; color:var(--warn); white-space:nowrap; }
    @media (max-width:600px){ .link-warn { flex-wrap:wrap; }
      .link-warn-cta { margin-left:0; } }

    /* Пометка «это план, а не факт» над цифрами топлива (см. fuelling.planned). */
    .fuel-planned { font-size:var(--fs-2xs); color:var(--mut); margin-bottom:var(--sp-2);
      padding-left:var(--sp-2); border-left:2px solid var(--line); }

    /* ════════════════════════════════════════════════════════════════════
       B2 (аудит №15, пункт 1): 342 style="" в index.html вынесены сюда.
       Инлайном остаётся ТОЛЬКО то, что реально приходит из данных на рендере
       (ширина полос/прогресса, цвет по порогу, смещения графиков/SVG) — весь
       список см. в отчёте задачи. Классы — по назначению элемента, кроме
       короткой шкалы отступов ниже (её сам ТЗ разрешает как исключение). ═══ */

    /* ── иконки рядом с текстом строки (базовая линия выровнена вручную) ─ */
    .icon-2xs { width:12px; height:12px; vertical-align:-1px; }
    .icon-sm  { width:13px; height:13px; vertical-align:-2px; }
    .icon-md  { width:14px; height:14px; vertical-align:-2px; }
    .icon-lg  { width:15px; height:15px; vertical-align:-3px; }
    .icon-xl  { width:16px; height:16px; vertical-align:-3px; }
    /* иконка сама по себе — не в строке текста, без сдвига по базовой линии */
    .icon-standalone-sm  { width:13px; height:13px; }
    .icon-standalone-md  { width:14px; height:14px; }
    .icon-standalone-lg  { width:15px; height:15px; }
    .icon-standalone-xl  { width:16px; height:16px; }
    .icon-standalone-2xl { width:20px; height:20px; }
    .icon-flex-none { flex:none; }
    .icon-warn { color:var(--warn); }
    .icon-good { color:var(--good); }
    .icon-acc  { color:var(--acc); }

    /* мини-спиннер строки (геосервис занят) — младший брат .spin */
    .spin-sm { width:20px; height:20px; border-width:3px; margin:0; }

    /* единственная переменная ширина текстового поля вне общего 100% (ввод
       названия своего геля/батончика — рядом с числовым полем в той же строке) */
    .fuel-name-input { width:140px; flex:1; min-width:120px; }
    .w-100 { width:100%; }

    /* ── ШКАЛА ОТСТУПОВ (исключение из правила «класс по назначению», ТЗ B2
       пункт 1: значение повторяется в разметке десятки раз — короче завести
       утилиту по токену, чем считать одноразовые классы). ────────────────── */
    .mt-0 { margin-top:0; }      .mt-1 { margin-top:var(--sp-1); }
    .mt-2 { margin-top:var(--sp-2); } .mt-3 { margin-top:var(--sp-3); }
    .mt-4 { margin-top:var(--sp-4); } .mt-6 { margin-top:var(--sp-6); }
    .mb-0 { margin-bottom:0; }   .mb-1 { margin-bottom:var(--sp-1); }
    .mb-2 { margin-bottom:var(--sp-2); } .mb-3 { margin-bottom:var(--sp-3); }
    .mb-4 { margin-bottom:var(--sp-4); } .mb-6 { margin-bottom:var(--sp-6); }
    .m-0  { margin:0; }
    .ml-auto { margin-left:auto; }
    .ml-1 { margin-left:var(--sp-1); }
    .mr-1 { margin-right:var(--sp-1); }

    /* ── состояния раскладки, решённые раньше инлайном по условию Jinja ── */
    .is-hidden { display:none; }
    .d-contents { display:contents; }
    .d-inline { display:inline; }
    .d-inline-block { display:inline-block; }
    .flex-wrap { flex-wrap:wrap; }
    .col-stack { display:flex; flex-direction:column; gap:var(--sp-3); }
    /* чек-лист/радио-список «что доступно взамен» / «режим» (сборы, период без велосипеда) */
    .opt-list { display:flex; flex-direction:column; gap:var(--sp-2); margin-bottom:var(--sp-3); }
    .radio-native { width:auto; min-height:0; }

    /* ── текстовый цвет: статичный (не из данных), переиспользуется на
       ссылках/подписях по всей странице — «цвет из данных» остаётся инлайн,
       это другое: фиксированная роль (акцент/предупреждение/приглушённый). ── */
    .text-acc { color:var(--acc); }
    .text-acc-strong { color:var(--acc); font-weight:700; }
    .text-warn { color:var(--warn); }
    .text-good { color:var(--good); }
    .text-prot { color:var(--prot); }
    .text-carb { color:var(--carb); }
    .text-mut-500 { color:var(--mut); font-weight:500; }
    .text-mut-600 { color:var(--mut); font-weight:600; }
    .text-line { color:var(--line); }
    .num-highlight { color:var(--ink); font-size:var(--fs-md); }
    .retry-link { color:inherit; font-weight:700; text-decoration:underline; white-space:nowrap; }
    .logout-link { color:var(--acc-text); font-weight:700; font-size:var(--fs-sm); }
    .foot-link { color:#9aa3b2; }

    /* мини-подпись КАПС перед блоком данных (погода/план тренера/еда/сауна) */
    .mini-label { font-size:var(--fs-2xs); font-weight:700; color:var(--mut); margin-bottom:var(--sp-1); }
    .mini-label.upper { text-transform:uppercase; letter-spacing:.04em; }
    .rf-section-label { font-size:var(--fs-xs); font-weight:700; margin:var(--sp-2) 0 var(--sp-1); }

    /* «врезка» var(--card2) — переиспользуемая карточка-в-карточке (топливо на
       заезде, погода, разбор сбора) — раньше у каждой был свой инлайн-набор
       тех же четырёх свойств */
    .callout { padding:var(--sp-3); background:var(--card2); border:1px solid var(--line);
               border-radius:var(--r-md); }
    /* врезка топлива на заезде — сама себе якорь прокрутки (#ride-fuel) */
    .callout-scroll { padding:var(--sp-3); background:var(--card2); border:1px solid var(--line);
                       border-radius:var(--r-md); scroll-margin-top:var(--sp-3); }
    /* врезка-предупреждение (тёплый тон) — недостающие углеводы на заезде */
    .callout-warn { padding:var(--sp-3); background:rgba(217,162,59,.10);
                     border:1px solid rgba(217,162,59,.35); border-radius:var(--r-md); }

    /* вердикт дня — состояние «уже есть вердикт» (было border-color инлайном
       при {% if verdict %}); карточка веса — состояние «пора перевзвеситься» */
    .dayverdict.is-set { border-color:#2f4636; }
    .card.is-stale { border-color:rgba(224,98,59,.4); }

    /* лычки легенды зон Z1–Z5 в подписи к графику отрезков — статичная
       подсказка «что означает цвет», не цвет из данных заезда (тот остаётся
       инлайн — border-left-color/background по zone из шаблона) */
    .zdot-legend { display:inline-block; width:7px; height:7px; border-radius:50%;
                   margin-right:var(--sp-1); vertical-align:1px; flex-shrink:0; }
    .zdot-legend.z1 { background:var(--z1); } .zdot-legend.z2 { background:var(--z2); }
    .zdot-legend.z3 { background:var(--z3); } .zdot-legend.z4 { background:var(--z4); }
    .zdot-legend.z5 { background:var(--z5); }

    /* прогресс-бар периода сбора / периода без велосипеда — заливка одна и
       та же независимо от значения (--acc), в инлайне остаётся только width */
    .fill.acc { background:var(--ink); }
    /* полоса формы (CTL) в паспорте — фиксированный трёхцветный градиент,
       не цвет из данных (тот же градиент всегда, меняется только width) */
    .fill.form-gradient { background:linear-gradient(90deg,#e0623b,#e0a63b,#4caf78); }

    /* переключатель языка RU/EN — активный пункт ярче (было цветом-тернарником) */
    .lang-switch { display:flex; gap:var(--sp-2); font-weight:700; }
    .lang-switch a { color:var(--mut); }
    .lang-switch a.active { color:var(--ink); }

    /* .muted/.mut — компактные варианты (мельче шрифт, чем дефолт fs-sm/fs-xs) */
    .muted-sm { font-size:var(--fs-xs); }
    .muted-2xs { font-size:var(--fs-2xs); }
    .mut.tight { font-size:var(--fs-2xs); margin-top:var(--sp-2); }
    .label-sm { font-size:var(--fs-xs); }
    .fw-500 { font-weight:500; }
    .fw-600 { font-weight:600; }
    .fw-700 { font-weight:700; }
    .row-gap-2 { display:flex; gap:var(--sp-2); }
    .wbtns.stack { flex-direction:column; align-items:stretch; }
    .text-sm { font-size:var(--fs-sm); }
    .text-right { text-align:right; }
    .grid-span-full { grid-column:1/-1; }
    .nowrap { white-space:nowrap; }
    /* строка-заглушка высотой в статичный поток (стрим ИИ-текста ждёт первую строку) */
    .stream-spacer { height:4px; }
    /* драйвер готовности в списке — верхний без отступа сверху, как раньше
       давал инлайн-тернарник по loop.first */
    .driver-item { margin-top:var(--sp-3); }
    .driver-item:first-child { margin-top:0; }
    /* заливка полосы «съедено на заезде» — своя, отличная от .wbar-fill по умолчанию */
    .wbar-fill.carb-fill { background:var(--carb); }
    /* поле email в листе ожидания Garmin — единственный кастомный инпут вне общей формы полей */
    .gwl-email-input { flex:1; min-width:0; padding:var(--sp-3) var(--sp-3); border-radius:var(--r-sm);
                        border:1px solid var(--line); background:var(--card); color:var(--ink);
                        font-size:var(--fs-base); }
    /* список фактов рельефа сбора */
    .camp-terrain-list { margin:0 0 var(--sp-4); padding-left:var(--sp-4); color:var(--mut);
                          font-size:var(--fs-sm); line-height:1.6; }
    /* строка «геосервис разбирает место» со спиннером */
    .camp-loading-row { margin-bottom:var(--sp-3); display:flex; align-items:center; gap:8px; }
    /* карточка ошибки — компактный вариант (было переопределение паддинга .card инлайном) */
    .card.err.compact { margin:0 0 var(--sp-3); padding:var(--sp-3) var(--sp-4); }
    /* кнопка «Отключить Strava» — контурная без заливки */
    .btn-outline-line { background:transparent; border:1px solid var(--line); }
    /* бейдж «рекорд» на пилюле интервала — модификатор поверх .pill */
    .pill.record { background:rgba(217,162,59,.16); color:var(--warn); font-weight:700; }

    /* JS переключает эти классы (display:none ⇄ показан) — раньше вся стилизация
       жила в инлайне на каждом экземпляре, класс был голым переключателем видимости */
    .ftp-hist-note, .ftp-estimate-note { margin-top:var(--sp-2); display:none; }
    .gwl-err { display:none; margin-top:var(--sp-2); font-size:var(--fs-2xs); color:var(--over); }
    .gwl-ok { display:none; align-items:center; gap:8px; color:var(--good); font-weight:600; font-size:var(--fs-sm); }

    /* мини-подписи/заголовки конкретных карточек — по одному месту использования,
       имя даёт назначение, не значение */
    .ftp-hist-label { font-size:var(--fs-2xs); font-weight:800; letter-spacing:.05em;
                       text-transform:uppercase; color:var(--mut); margin:0 0 var(--sp-2); }
    .pc-stat-note { font-size:var(--fs-2xs); color:var(--mut); font-weight:600; }
    .hs-link-quiet { font-size:var(--fs-2xs); color:var(--mut); }
    .tbtn-sm { font-size:var(--fs-2xs); padding:var(--sp-1) var(--sp-3); }
    .camp-terrain-label { font-size:var(--fs-2xl); font-weight:800; margin-bottom:var(--sp-2); }
    .rf-header-row { font-weight:700; font-size:var(--fs-sm); margin-bottom:var(--sp-1);
                      display:flex; align-items:center; gap:8px; }
    .hc-row-label { display:flex; justify-content:space-between; font-size:var(--fs-2xs);
                     color:var(--mut); margin-bottom:var(--sp-1); }
    /* иконка-заметка со сдвигом вверх под заголовок (сборы/период без вело) */
    .mode-note { font-size:var(--fs-2xs); margin:-4px 0 var(--sp-3); }
    .weight-delta-row { font-size:var(--fs-sm); margin-bottom:var(--sp-2); }
    .director-text { font-size:var(--fs-sm); line-height:1.5; }
    .driver-phrase { font-size:var(--fs-sm); line-height:1.45; }
    .warn-note { font-size:var(--fs-xs); color:var(--warn); }

    /* ── Ручной ввод сна и утреннего пульса (карточка «Состояние гонщика») ──
       Одна строка под вердиктом: два поля и кнопка. Поля берут общий вид
       input[type=number] (пол 44 px), здесь только раскладка. При 320 px два
       поля по 110 px с зазором встают в ряд, кнопка переносится строкой ниже —
       перенос честнее, чем поле в 60 px. */
    .body-form { display:flex; flex-wrap:wrap; align-items:flex-end; gap:var(--sp-3);
                 margin-top:var(--sp-4); padding-top:var(--sp-3); border-top:1px solid var(--line); }
    .body-field { flex:1 1 110px; min-width:110px; }
    .body-label { display:block; margin:0 0 var(--sp-2); font-size:var(--fs-xs);
                  font-weight:600; color:var(--mut); }
    .body-save { flex:0 0 auto; min-height:44px; }

    /* ── Утренняя проверка гидратации (WUT: вес, цвет мочи, жажда, часть E) ── */
    .wut-sub { margin:var(--sp-1) 0 var(--sp-3); }
    .wut-form { display:flex; flex-direction:column; gap:var(--sp-4); }
    .wut-field { display:flex; flex-direction:column; gap:var(--sp-2); }
    .wut-label { font-size:var(--fs-sm); font-weight:700; color:var(--ink); }
    .wut-weight-input { max-width:140px; padding:var(--sp-2) var(--sp-3); border-radius:var(--r-sm);
                         border:1px solid var(--line); background:var(--card); color:var(--ink);
                         font-size:var(--fs-base); }
    .wut-sw-row, .wut-th-row { display:flex; gap:var(--sp-2); flex-wrap:wrap; }
    .wut-sw-wrap { position:relative; display:block; width:32px; height:32px; border-radius:50%;
                   border:2px solid var(--line); cursor:pointer; }
    .wut-sw-wrap input { position:absolute; inset:0; margin:0; opacity:0; cursor:pointer; }
    .wut-sw-wrap:has(input:checked) { border-color:var(--acc); box-shadow:0 0 0 2px var(--acc) inset; }
    /* Плашки цвета мочи 1–8 — НАША отрисовка, не валидированная карта из исследования (см. wut.py). */
    .wut-sw-wrap:nth-child(1) { background:#F7F2C8; }
    .wut-sw-wrap:nth-child(2) { background:#F5EBA6; }
    .wut-sw-wrap:nth-child(3) { background:#F3E27F; }
    .wut-sw-wrap:nth-child(4) { background:#F0D856; }
    .wut-sw-wrap:nth-child(5) { background:#E9C63C; }
    .wut-sw-wrap:nth-child(6) { background:#DDAE2A; }
    .wut-sw-wrap:nth-child(7) { background:#C8901F; }
    .wut-sw-wrap:nth-child(8) { background:#A96B14; }
    .wut-th-wrap { position:relative; display:block; width:26px; height:26px; border-radius:50%;
                   border:2px solid var(--line); background:var(--card2); cursor:pointer; }
    .wut-th-wrap input { position:absolute; inset:0; margin:0; opacity:0; cursor:pointer; }
    .wut-th-wrap:has(input:checked) { border-color:var(--acc); background:var(--acc); }
    /* Цифра на шкале видима и у цвета, и у жажды: без неё это восемь и девять
       одинаковых кружков, по которым не сказать, что ты отметил. */
    .wut-sw-num, .wut-th-num { position:absolute; inset:0; display:flex; align-items:center;
                               justify-content:center; font-size:var(--fs-2xs); font-weight:700;
                               pointer-events:none; }
    /* Тёмные плашки 6–8: чёрная цифра на них не читается — там она белая. */
    .wut-sw-num { color:#3A2D06; }
    .wut-sw-wrap:nth-child(6) .wut-sw-num,
    .wut-sw-wrap:nth-child(7) .wut-sw-num,
    .wut-sw-wrap:nth-child(8) .wut-sw-num { color:#FFF; }
    .wut-th-num { color:var(--mut); }
    .wut-th-wrap:has(input:checked) .wut-th-num { color:var(--card); }
    .wut-scale-labels { display:flex; justify-content:space-between; gap:var(--sp-2); }
    .wut-verdict { margin-top:var(--sp-4); padding-top:var(--sp-3); border-top:1px solid var(--line); }
    .wut-verdict p { margin:0 0 var(--sp-2); font-size:var(--fs-sm); line-height:1.5; }
    .wut-prov { margin-top:var(--sp-3); }

/* ── /trends: герой «Тип гонщика» — вход в паспорт (TZ-passport-
   discoverability-en.md, редизайн TZ-redesign-sections-en.md D2/D3: теперь
   первый блок страницы, крупный серийный заголовок, не рядовая карточка —
   класс переименован .type-card → .type-hero, разметка h3/.radar-head
   заменена на .type-hero-title/.type-hero-deck). Геометрия паутинки — та же,
   что у /passport (power.py power_profile), крупнее обзорной версии до
   редизайна (было ~120px). ── */
.type-hero { padding:var(--sp-6) 0; }
.type-hero-title { font-family:var(--font-head); font-weight:var(--fw-head);
  font-size:var(--fs-title); line-height:var(--lh-cover); letter-spacing:var(--tr-cover);
  margin:var(--sp-2) 0 var(--sp-2); color:var(--ink); }
.type-hero-title.mut { color:var(--mut); }
.type-hero-deck { font-size:var(--fs-lg); color:var(--mut); max-width:34ch; margin:0 0 var(--sp-4); }
.type-hero .radar-svg-wrap { display:flex; justify-content:center; margin:var(--sp-4) 0; }
.type-hero .radar-svg-wrap svg { width:100%; max-width:360px; height:auto; }
@media(min-width:960px){ .type-hero .radar-svg-wrap svg { max-width:420px; } }
.type-hero .radar-ring { fill:none; stroke:var(--line); stroke-width:1; }
.type-hero .radar-spoke { stroke:var(--line); stroke-width:1; }
.type-hero .radar-poly { fill:rgba(224,98,59,.28); stroke:var(--acc); stroke-width:2; stroke-linejoin:round; }
.type-hero .radar-dot { fill:var(--acc); stroke:var(--card); stroke-width:1.5; }
/* D3 (решение ревьюера 07.10, вариант B): ось без балла — ПОЛЫЙ кружок
   (fill:none, видимый контур), не тусклая заливка — честно «нет точки», не
   «слабая точка». */
.type-hero .radar-dot.empty { fill:none; stroke:var(--mut); stroke-width:1.5; opacity:1; }
.type-hero .radar-empty { color:var(--mut); font-size:var(--fs-sm); line-height:1.6; padding:var(--sp-2) 0; }
.type-hero .radar-noweight { color:var(--mut); font-size:var(--fs-xs); margin:var(--sp-2) 0; line-height:1.5; }
/* D2: значения осей под паутинкой — 2×2, не три-в-ряд (.trio даёт 3
   колонки, здесь ровно четыре оси). */
.type-hero .axes-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:var(--sp-4); margin:var(--sp-4) 0; }
.type-hero .axes-grid .ax-v { font-family:var(--font-num); font-size:var(--fs-hero-s);
  font-variant-numeric:tabular-nums lining-nums; color:var(--ink); }
.type-hero .axes-grid .ax-v small { font-size:var(--fs-base); color:var(--mut); font-weight:400; margin-left:2px; }
.type-hero .axes-grid .ax-v.is-empty { color:var(--mut); }
.type-hero .axes-grid .rub { display:block; margin-top:4px; }

/* ════════════════════════════════════════════════════════════════════════
   РЕДИЗАЙН «СЕГОДНЯ» — обложка (TZ-today-redesign-en.md, D1–D6).
   Классы с префиксом tc- (Today Cover): generic-имена макета (.row/.chip/
   .panel/.btn/.list/.col/.more) уже заняты другими компонентами этого же
   файла — совпадение имён дало бы реальную коллизию стилей, а не косметику.
   Весь блок живёт ТОЛЬКО под body.today .tc-cover — других экранов не
   касается (index.html — единственный шаблон с class="today" на body). */
body.today .tc-cover{ max-width:1200px; margin:0 auto; padding:var(--sp-4) 0 var(--sp-6);
  position:relative; }

/* Свечение по времени суток — ТОЛЬКО верх обложки, ≤560px (D4). Решение
   ревьюера 07.10 п.2: альфа утреннего свечения .22 — выбор владельца. */
body.today[data-daypart=morning] .tc-cover::before,
body.today[data-daypart=daytime] .tc-cover::before,
body.today[data-daypart=evening] .tc-cover::before{
  content:""; position:absolute; left:0; right:0; top:0; height:560px; z-index:-1;
  pointer-events:none;
}
body.today[data-daypart=morning] .tc-cover::before{ background-image:var(--glow-morning); }
body.today[data-daypart=daytime] .tc-cover::before{ background-image:var(--glow-day); }
body.today[data-daypart=evening] .tc-cover::before{ background-image:var(--glow-evening); }

body.today .tc-mast{ display:flex; justify-content:space-between; align-items:center;
  padding:0 0 var(--sp-3); border-bottom:1px solid var(--pl); }
body.today .tc-brand{ display:flex; align-items:baseline; gap:10px; }
body.today .tc-brand b{ font-family:var(--font-head); font-weight:var(--fw-brand);
  font-optical-sizing:auto; font-size:1.375rem; letter-spacing:-.005em; line-height:1; color:var(--ink); }
body.today .tc-rub{ font-family:var(--font-num); font-size:var(--fs-xs); font-weight:500;
  letter-spacing:var(--tr-rub); text-transform:uppercase; color:var(--mut); }
body.today .tc-rub.tc-ink{ color:var(--ink); text-transform:none; letter-spacing:0; font-size:var(--fs-sm); }
body.today .tc-dateline{ display:flex; align-items:center; gap:var(--sp-2); padding:var(--sp-2) 0; border-bottom:1px solid var(--pl); }
body.today .tc-dateline .tc-rub b{ color:var(--ink); font-weight:600; text-transform:none; letter-spacing:0; }
body.today .tc-date-c{ flex:1; text-align:center; }
body.today .tc-today-link{ margin-left:6px; color:var(--acc-text); text-transform:none; letter-spacing:0; }
body.today .tc-race-days{ white-space:nowrap; }
body.today .tc-step{ width:32px; height:32px; flex:none; display:grid; place-items:center; border-radius:var(--r-sm);
  color:var(--mut); position:relative; }
body.today .tc-step::before{ content:""; position:absolute; inset:-6px; } /* зона нажатия ≥44px без сдвига разметки */
body.today .tc-step:hover{ background:var(--elev); color:var(--ink); }
body.today .tc-step .icon{ width:16px; height:16px; }

/* Пункт 1 приёмки: ОДИН хедер на «Сегодня» — бренд и дата теперь только в
   .tc-mast/.tc-dateline, старые .sb-brand/.sb-day (верх мобильного сайдбара
   И верх десктопного сайдбара) скрыты здесь. .sb-nav/.sb-foot (реальная
   навигация по разделам) и нижний таб-бар остаются как были — это не
   дубликат хедера, это единственный способ попасть на /plan и т.д. */
body.today .sidebar .sb-brand,
body.today .sidebar .sb-day,
body.sec .sidebar .sb-brand{ display:none; } /* разделы: бренд — в своей шапке .sec-mast, как на «Сегодня» (08.10) */

body.today .tc-status{ display:flex; align-items:center; gap:8px; margin-top:var(--sp-4);
  font-size:var(--fs-sm); color:var(--mut); }
body.today .tc-status i{ width:8px; height:8px; border-radius:50%; background:var(--faint); flex:none; }
body.today .tc-status i.ok{ background:var(--ok); }
body.today .tc-status .num{ font-family:inherit; font-variant-numeric:normal; } /* моно-минус в строке текста давал «TSB  −6» */
body.today .tc-status i.low,
body.today .tc-status i.high{ background:var(--warn); }

body.today .tc-h1{ font-family:var(--font-head); font-weight:var(--fw-head); font-style:normal;
  font-size:var(--fs-cover); line-height:var(--lh-cover); letter-spacing:var(--tr-cover);
  margin-top:var(--sp-3); text-wrap:balance; color:var(--ink); }
body.today .tc-deck{ font-size:var(--fs-lg); line-height:var(--lh-snug); color:#cfd5de;
  margin-top:var(--sp-4); max-width:34ch; }

body.today .tc-race{ display:grid; grid-template-columns:auto auto minmax(0,1fr);
  margin-top:var(--sp-8); border-top:1px solid var(--pl); border-bottom:1px solid var(--pl); }
body.today .tc-race.tc-n2{ grid-template-columns:auto 1fr; }
body.today .tc-race>div{ padding:var(--sp-3) var(--sp-4) var(--sp-3) 0; }
body.today .tc-race>div+div{ padding-left:var(--sp-4); border-left:1px solid var(--pl); }
body.today .tc-v{ font-family:var(--font-num); font-size:var(--fs-hero); font-weight:500; line-height:1;
  font-variant-numeric:tabular-nums; letter-spacing:-.01em; }
body.today .tc-v small{ font-size:var(--fs-base); color:var(--mut); font-weight:400; margin-left:3px; }
body.today .tc-v.tc-s{ font-size:var(--fs-hero-s); letter-spacing:-.03em; }
body.today .tc-race .tc-rub{ display:block; margin-top:6px; font-size:var(--fs-2xs); }
/* узкий телефон: три числа в строку без вылета за край (как в макете, max-width 380 → 420) */
@media (max-width:420px){
  body.today .tc-race>div{ padding-right:var(--sp-3); }
  body.today .tc-race>div+div{ padding-left:var(--sp-3); }
  body.today .tc-race .tc-v{ font-size:2.5rem; }
  body.today .tc-race .tc-v.tc-s{ font-size:1.25rem; }
}

/* Пункт 3 приёмки: линия топлива — ОДНА горизонтальная линейка (до/заезд/
   после), без рамок-боксов (боксы — ровно то, что убирает редизайн) и без
   левого отступа у первой ячейки. */
body.today .tc-fuel{ margin:var(--sp-8) 0 0; max-width:480px; } /* margin целиком: у <figure> браузерный отступ 40px по бокам */
body.today .tc-fuel .tc-rub{ display:block; margin-bottom:var(--sp-3); }
body.today .tc-fuel-row{ display:flex; border-top:1px solid var(--pl); border-bottom:1px solid var(--pl); }
body.today .tc-fcell{ display:flex; flex-direction:column; gap:2px; padding:var(--sp-3) var(--sp-4) var(--sp-3) 0; }
body.today .tc-fcell+.tc-fcell{ padding-left:var(--sp-4); border-left:1px solid var(--pl); }
body.today .tc-fcell-ride{ flex:1; }
body.today .tc-ph{ font-family:var(--font-num); font-size:11px; letter-spacing:.1em; text-transform:uppercase; color:var(--mut); }
body.today .tc-tv{ font-family:var(--font-num); font-size:1.375rem; font-weight:500; color:var(--ink); }
body.today .tc-tv small{ font-size:.75rem; color:var(--mut); font-weight:400; }
body.today .tc-tv .tc-prot{ color:var(--prot); }
body.today .tc-in{ font-family:var(--font-num); font-size:12px; color:var(--mut); }
body.today .tc-planned{ margin:0 0 var(--sp-2); }
body.today .tc-load{ margin-top:var(--sp-8); padding-top:var(--sp-4); border-top:1px solid var(--pl); max-width:62ch; }
body.today .tc-load p{ font-size:var(--fs-md); line-height:var(--lh-snug); }
body.today .tc-load .tc-small a{ color:var(--acc-text); }
body.today .tc-rest{ margin-top:var(--sp-6); }
body.today .tc-small{ font-size:var(--fs-sm); color:var(--mut); max-width:62ch; margin-top:var(--sp-2); }

body.today .tc-cta{ display:flex; gap:var(--sp-3); margin-top:var(--sp-8); }
body.today .tc-btn{ display:inline-flex; align-items:center; justify-content:center; gap:10px;
  min-height:52px; padding:0 24px; border-radius:var(--r-md); font-weight:600; font-size:var(--fs-md);
  transition:filter var(--transition-fast); }
body.today .tc-btn-p{ background:var(--act); color:var(--on-act); flex:1; }
body.today .tc-btn-cam{ width:52px; padding:0; border:1px solid var(--act); color:var(--acc-text); }
body.today .tc-btn:hover{ filter:brightness(1.08); }
@media(min-width:960px){ body.today .tc-btn-p{ flex:0 0 auto; } }

body.today .tc-more{ margin-top:var(--sp-4); }
body.today .tc-more summary{ cursor:pointer; min-height:var(--tap-min); display:flex; align-items:center;
  color:var(--mut); font-size:var(--fs-sm); font-weight:500; }
body.today .tc-more summary:hover,
body.today .tc-more[open] summary{ color:var(--ink); }
body.today .tc-list{ list-style:none; display:grid; gap:var(--sp-2); margin-top:var(--sp-2); }
body.today .tc-list li{ display:flex; justify-content:space-between; gap:var(--sp-4); font-size:var(--fs-base); }

body.today .tc-spread{ margin-top:var(--sp-12); }
body.today .tc-col>section{ padding:var(--sp-6) 0; border-top:1px solid var(--pl); }
/* Пункт 4 приёмки: убрана особая 2px-рамка ink у первой секции колонки —
   «Брифинг штаба» теперь рендерится условно (есть текст — есть секция), и
   первой секцией в DOM то и дело становится «Тело сегодня»; одна толщина
   рамки для всех секций и проще, и не плывёт от того, что есть в brief. */
body.today .tc-sh{ display:flex; justify-content:space-between; align-items:baseline; margin-bottom:var(--sp-4); }
body.today .tc-sh a{ font-size:var(--fs-sm); }
body.today .tc-prose{ max-width:62ch; color:#d9dee6; font-size:var(--fs-md); line-height:var(--lh-prose); }

body.today .tc-trio{ display:grid; grid-template-columns:repeat(3,1fr); }
body.today .tc-trio>div{ padding-right:var(--sp-3); }
body.today .tc-trio>div+div{ padding-left:var(--sp-3); border-left:1px solid var(--pl); }
body.today .tc-trio .tc-v{ font-size:var(--fs-num); }
body.today .tc-trio .tc-rub{ font-size:var(--fs-2xs); margin-top:6px; letter-spacing:.1em; display:block; }
body.today .tc-trio .tc-s{ font-size:var(--fs-xs); margin-top:2px; color:var(--mut); }
body.today .tc-band{ height:3px; background:var(--s2); margin-top:10px; position:relative; }
body.today .tc-band b{ position:absolute; top:0; bottom:0; background:rgba(63,190,131,.5); }
body.today .tc-band i{ position:absolute; top:-4px; width:2px; height:11px; background:var(--ink); }

body.today .tc-water{ display:flex; align-items:baseline; gap:var(--sp-2); }
body.today .tc-water .tc-v{ font-size:var(--fs-num); }
body.today .tc-of{ color:var(--mut); }
body.today .tc-bar{ height:3px; background:var(--s2); margin:var(--sp-3) 0; }
body.today .tc-bar i{ display:block; height:100%; background:var(--z2); }
body.today .tc-sub{ font-size:var(--fs-sm); color:var(--mut); }
body.today .tc-row{ display:flex; justify-content:space-between; align-items:center; gap:var(--sp-3);
  flex-wrap:wrap; margin-top:var(--sp-3); }
body.today .tc-chips{ display:flex; gap:var(--sp-2); }
body.today .tc-inline{ display:inline; }
body.today .tc-chip{ min-height:var(--tap-min); padding:0 14px; border-radius:var(--r-md);
  border:1px solid var(--pl); color:var(--acc-text); font-family:var(--font-num); font-size:var(--fs-base);
  letter-spacing:.02em; background:none; }
body.today .tc-more-link{ font-size:var(--fs-sm); color:var(--acc-text); }

body.today .tc-tomorrow{ font-family:var(--font-head); font-weight:500; font-size:var(--fs-xl);
  line-height:var(--lh-snug); margin-top:6px; color:var(--ink); }

@media(min-width:960px){
  /* Сетка макета: обложка слева, колонка штаба справа (08.10 — .tc-main и
     .tc-spread теперь два соседних блока внутри .tc-body). */
  body.today .tc-body{ display:grid; grid-template-columns:minmax(0,1.3fr) minmax(0,1fr);
    column-gap:56px; align-items:start; }
  body.today .tc-spread{ margin-top:var(--sp-6); }
  body.today .tc-col{ border-left:1px solid var(--pl); padding-left:40px; }
  body.today .tc-col>section:first-child{ border-top:0; }
}

/* ── Пункт 2 приёмки редизайна «Сегодня»: блоки, которые ОСТАЮТСЯ под
   обложкой (сессия/готовность/аккаунтабилити/тренировка/итог дня/питание/
   утренняя проверка — уникальная функциональность, не дублированная
   .tc-cover), перестают быть рамками-карточками и становятся рядом секций
   на волосяных линейках — тот же приём, что уже стоит у #sec-meals .row
   (строка 1902). Один список селекторов вместо правки каждого блока. */
body.today .hero-card,
body.today .card,
body.today details.row,
body.today .statecard{
  background:transparent; border:0; border-radius:0; padding:var(--sp-6) 0;
  border-top:1px solid var(--pl); margin-bottom:0; box-shadow:none;
}
body.today .hero{ display:block; }
body.today .hero-card:first-child,
body.today .card:first-child{ border-top:0; }
/* Заголовки секций — ближе к .rub (приглушённые, не кричат рамкой вокруг себя) */
body.today .hero-h,
body.today .ttl{ color:var(--mut); font-weight:600; }
body.today .hero-h .icon,
body.today .ttl .icon{ color:var(--mut); }

/* Пункт 1 приёмки: .cmdbar теперь несёт только вход/выход (вердикт+дата —
   в .tc-cover) — один ребёнок вместо двух двигает justify-content:space-
   between в начало строки, нужен явный flex-end. */
body.today .cmdbar-slim{ justify-content:flex-end; }

/* ════════════════════════════════════════════════════════════════════
   TZ-redesign-sections-en.md — /plan, /trends, /health, /profile (D1–D6).
   Всё под body.sec: «Сегодня» (body.today, разметка выше) этот блок не
   задевает — у неё свой скелет с собственной обложкой/вердиктом. Токены и
   приёмы повторяют Today (--font-head, --fs-hero-s, --tr-rub, рамки →
   линейки), классы — свои (.rub/.more/.trio/ol.acts), а не body.today.* —
   им нужны все четыре страницы раздела, не одна. ════════════════════════ */

/* ── Рубрика: капительная приглушённая подпись (масштаб/трекинг — как
   .tc-rub на «Сегодня», без привязки к body.today). ── */
.rub{ font-family:var(--font-num); font-size:var(--fs-2xs); font-weight:500;
      letter-spacing:var(--tr-rub); text-transform:uppercase; color:var(--mut); }

/* ── Шапка раздела: бренд + рубрика (имя раздела) в прилипающей планке,
   линейка снизу — тот же приём, что .tc-mast/.tc-dateline у Today (TZ-
   today-redesign, D3.1), без зависимости от body.today. Большой серийный
   заголовок — ОТДЕЛЬНЫЙ h1.sec-title ниже планки (не sticky), тот же текст:
   кикер + заголовок, не вердикт дня (на этих страницах вердикта нет). ── */
body.sec .cmdbar{ border-bottom:1px solid var(--pl); padding-bottom:var(--sp-3); }
body.sec .masthead{ display:flex; align-items:baseline; gap:10px; }
body.sec .masthead .mast-brand{ font-family:var(--font-head); font-weight:var(--fw-brand);
  font-size:1.375rem; letter-spacing:-.005em; font-optical-sizing:auto; color:var(--ink); }
body.sec h1.sec-title{ font-family:var(--font-head); font-weight:var(--fw-head);
  font-size:var(--fs-title); line-height:var(--lh-cover); letter-spacing:var(--tr-cover);
  margin:var(--sp-6) 0 var(--sp-6); color:var(--ink); }
/* page.html (privacy/статика) — своя обёртка .wrap, без .cmdbar/.sticky. */
.page-masthead{ display:flex; align-items:baseline; gap:10px; padding-bottom:var(--sp-3);
  margin-bottom:var(--sp-4); border-bottom:1px solid var(--pl); }
.page-masthead .mast-brand{ font-family:var(--font-head); font-weight:var(--fw-brand);
  font-size:1.375rem; letter-spacing:-.005em; color:var(--ink); }

/* ── Карточки → секции на волосяных линейках (тот же приём, что уже стоит
   у body.today выше): рамка/заливка снимаются, разделитель — border-top,
   ритм — sp-8. Один список селекторов вместо правки каждого блока. ── */
body.sec .card,
body.sec details.row,
body.sec .trend-card,
body.sec .hero-card,
body.sec .formstrip,
body.sec .planw{
  background:transparent; border:0; border-radius:0; box-shadow:none;
  padding:var(--sp-8) 0; margin-bottom:0; border-top:1px solid var(--pl);
}
body.sec .card:first-child,
body.sec details.row:first-child,
body.sec .trend-card:first-child,
body.sec .planw:first-child{ border-top:0; }
/* Ошибка — единственный блок, который сохраняет собственную рамку/заливку:
   предупреждение обязано выделяться, не сливаться с остальным текстом. */
body.sec .card.err{ background:#3a1d1d; border:1px solid #5a2a2a; border-radius:var(--r-md); padding:var(--sp-4); }
/* Вложенные «карточки в карточке» (камп/эвей-блоки сборов внутри секции) —
   снимаем вторую рамку, первая (секция) уже есть. */
body.sec details.row .card,
body.sec .card .card{ border:0; background:transparent; padding:var(--sp-4) 0 0; }

/* Заголовки секций — ближе к .rub (приглушённые капители, не жирный текст
   в рамке), та же логика, что у Today (.hero-h/.ttl там). */
body.sec .ttl, body.sec .pl-h, body.sec .sec-h,
body.sec .tc-h, body.sec .hs-t, body.sec .fs-h{
  color:var(--mut); font-weight:600; text-transform:none;
}
body.sec .ttl .icon, body.sec .pl-h .icon, body.sec .tc-h .icon, body.sec .fs-h .icon{ color:var(--mut); }

/* Раскрытие/«подробнее» (summary, pl-why, hs-link, prov-why) — приглушённый
   текст, --ink на ховере/открытии, без оранжевого (TZ-design-system.md:
   оранжевый только у интерактива-ДЕЙСТВИЯ, не у чтения). */
body.sec .more,
body.sec .hs-link,
body.sec .pl-why,
body.sec .prov-why{ color:var(--mut); font-weight:500; }
body.sec .more:hover, body.sec .more[open],
body.sec .hs-link:hover, body.sec .pl-why:hover, body.sec .prov-why:hover{ color:var(--ink); }
/* D4: «полный разбор» (ai_block → .ai-full > summary) — тот же приглушённый
   язык раскрытия, без изменения макроса (общий с Today, _macros.html). */
body.sec .ai-full > summary{ color:var(--mut); font-weight:500; cursor:pointer; }
body.sec .ai-full > summary:hover{ color:var(--ink); }

/* ── Трио: три числа-героя в ряд, разделённые линейками (геометрия —
   .tc-trio у Today, без зависимости от body.today). ── */
body.sec .trio{ display:grid; grid-template-columns:repeat(3,1fr); margin:var(--sp-4) 0; }
body.sec .trio > div{ padding:0 var(--sp-3); }
body.sec .trio > div:first-child{ padding-left:0; }
body.sec .trio > div + div{ border-left:1px solid var(--pl); }
body.sec .trio .trio-v{ font-family:var(--font-num); font-size:var(--fs-hero-s);
  font-variant-numeric:tabular-nums lining-nums; color:var(--ink); }
body.sec .trio .trio-v small{ font-size:var(--fs-base); color:var(--mut); font-weight:400; margin-left:2px; }
body.sec .trio .rub{ display:block; margin-top:6px; }
body.sec .trio .trio-s{ display:block; font-size:var(--fs-xs); color:var(--mut); margin-top:2px; }
@media(max-width:480px){ body.sec .trio{ grid-template-columns:repeat(2,1fr); gap:var(--sp-3) 0; }
  body.sec .trio > div:nth-child(2n+1){ padding-left:0; border-left:0; }
  body.sec .trio > div:nth-child(2n){ border-left:1px solid var(--pl); } }

/* Нумерованные действия штаба — курсивные серийные цифры (язык Today,
   TZ-today-redesign D3.7), без зависимости от body.today. .ai-actions —
   тот же список, что рисует ai_block() (_macros.html, общий для Today и
   этих четырёх страниц) — макрос НЕ трогаем (риск для Today), переодеваем
   только здесь через CSS, scoped на body.sec. */
body.sec ol.acts, body.sec .ai-actions{ list-style:none; counter-reset:acts; margin:var(--sp-3) 0; padding:0; }
body.sec ol.acts li, body.sec .ai-actions li{ counter-increment:acts; display:flex; gap:var(--sp-3);
  padding:var(--sp-2) 0; font-size:var(--fs-base); line-height:var(--lh-snug);
  /* .ai-actions li (ai.css) задаёт своё position:relative/padding-left:30px —
     обнуляем явно, иначе наследуется только то, что мы НЕ переопределили. */
  position:static; border-bottom:0; }
body.sec ol.acts li::before, body.sec .ai-actions li::before{ content:counter(acts);
  font-family:var(--font-head); font-style:italic; font-weight:500; color:var(--mut);
  flex:0 0 auto; min-width:1.2em;
  /* ⛔ Нашли рендером (TZ-redesign-sections-en.md): .ai-actions li::before
     (ai.css) кружок-бейдж стоит position:absolute;left:0;top:7px;width:20px —
     без явного сброса эти свойства остаются в силе (новое правило их не
     трогало) и цифра перекрывала первые буквы строки («Keep» читалось как
     обрывок). Явно гасим абсолютное позиционирование и старую геометрию. */
  position:static; top:auto; left:auto; width:auto; height:auto; background:none;
  border-radius:0; text-align:left; line-height:inherit; }

/* ── D4 Plan: точка зоны вместо цветной левой кромки/залитого чипа длительности. ── */
body.sec .pl-day{ border:0; border-radius:0; padding:var(--sp-4) 0; border-top:1px solid var(--pl-soft); background:transparent; }
body.sec .pl-day:first-child{ border-top:0; }
/* «Сегодня» среди дней недели — цветная рамка (.pl-day.is-today) заменяется
   тем же приёмом, что .is-today даёт в других местах продукта: цветная
   верхняя линейка вместо снятой боковой/полной рамки. */
body.sec .pl-day.is-today{ border-top-color:var(--prot); }
body.sec .pl-dow{ color:var(--mut); font-size:var(--fs-2xs); letter-spacing:var(--tr-rub); text-transform:uppercase; }
body.sec .pl-title{ font-size:var(--fs-md); font-weight:600; }
body.sec .pl-meta b.num{ font-family:var(--font-num); font-size:var(--fs-hero-s); font-weight:500; color:var(--ink); }
body.sec .pl-meta .pl-unit{ font-size:var(--fs-base); font-weight:400; color:var(--mut); }
body.sec .pl-type{ background:none; padding:0; border:0; font-weight:600; color:var(--mut); }
body.sec .zdot{ display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:6px; vertical-align:middle; }
/* D4: числа вердикта (CTL/TSB) — трио без обвязки (ai_block → .ai-nums,
   ai.css: фон+рамка). Сами .ai-num/.ai-num>span уже размечены (ai.css), тут
   только снимаем короб и выравниваем геометрию под язык .trio. */
body.sec .ai-nums{ background:none; border:0; border-radius:0; padding:0; gap:0; }
body.sec .ai-num{ padding:0 var(--sp-4) 0 0; }
body.sec .ai-num + .ai-num{ padding-left:var(--sp-4); border-left:1px solid var(--pl); }
body.sec .ai-num b{ font-family:var(--font-num); font-size:var(--fs-hero-s); font-weight:500; }
/* Разбор недели/разбор плана: врезка .wreview/.briefing-box снимается
   (та же причина, что у .card/details.row выше — рамка внутри рамки),
   вердикт становится серийным и крупным вместо жирного сан-серифа в рамке. */
body.sec .wreview, body.sec .briefing-box{ background:none; border:0; border-radius:0; padding:0; }
body.sec .wr-verdict, body.sec .wr-label{ font-family:var(--font-head); font-size:var(--fs-3xl); font-weight:500;
  max-width:34ch; background:none; border:0; padding:0; letter-spacing:0; text-transform:none; }
body.sec .pl-adjusted{ background:none; border:0; border-left:2px solid var(--pl); border-radius:0; padding:var(--sp-2) 0 var(--sp-2) var(--sp-3); }
/* «Утренняя правка на сегодня» — тот же смысл, без зелёной рамки
   (D4: "no green frame"); подпись становится рубрикой, не жирным текстом. */
body.sec .pl-adjust{ background:none; border:0; border-radius:0; padding:var(--sp-2) 0; border-top:1px solid var(--pl-soft); }
body.sec .pl-adjust b{ display:block; font-family:var(--font-num); font-size:var(--fs-2xs); font-weight:500;
  letter-spacing:var(--tr-rub); text-transform:uppercase; color:var(--mut); margin-bottom:4px; }

/* ── D5 Health: состав тела (3 чипа) и жара (4 плитки) — числа-герои в ряд,
   разделённые линейками, вместо своих рамок/четырёх цветов на одну тему
   (TZ: «heat block = 4 tiles with 4 colours»). Единственный акцент остаётся
   у .hready-bar (полоса готовности), сами плитки/чипы его теряют. Скоуп
   #sec-passport .chips — тот же id есть и на /profile (другое содержимое,
   без .chips там, правило просто не матчится). ── */
body.sec #sec-passport .chips{ display:grid; grid-template-columns:repeat(3,1fr); gap:0; margin:var(--sp-4) 0; }
body.sec #sec-passport .chip{ flex:none; text-align:left; background:none; border:0; border-radius:0; padding:0 var(--sp-3); }
body.sec #sec-passport .chip:first-child{ padding-left:0; }
body.sec #sec-passport .chip+.chip{ border-left:1px solid var(--pl); }
body.sec #sec-passport .chip b{ font-family:var(--font-num); font-size:var(--fs-hero-s);
  font-variant-numeric:tabular-nums lining-nums; color:var(--ink); font-weight:500; }
body.sec #sec-passport .chip span{ display:block; margin-top:4px; font-size:var(--fs-2xs);
  letter-spacing:var(--tr-rub); text-transform:uppercase; color:var(--mut); }

body.sec .heat-grid{ display:grid; grid-template-columns:repeat(2,1fr); gap:var(--sp-4); margin:var(--sp-4) 0; }
body.sec .heat-cell{ background:none; border:0; border-radius:0; padding:0; text-align:left; }
body.sec .heat-cell .hc-val{ font-family:var(--font-num); font-size:var(--fs-hero-s); font-weight:500; color:var(--ink); }
body.sec .heat-cell .hc-lbl{ font-size:var(--fs-2xs); letter-spacing:var(--tr-rub); text-transform:uppercase; color:var(--mut); margin-top:4px; }
body.sec .heat-cell .hc-band{ font-size:var(--fs-xs); font-weight:500; color:var(--mut) !important; margin-top:2px; }

/* Проза — измеримая ширина строки (62ch), не во всю ширину карточки. */
body.sec #sec-passport p, body.sec .heat-grid + p, body.sec .frow, body.sec .mini-label + p{
  max-width:62ch; font-size:var(--fs-sm); line-height:var(--lh-prose);
}

/* ── D6 Profile: FTP hero-число, настроечная сетка 2/4 колонки. ── */
body.sec #sec-rider .ftp-input{ font-family:var(--font-num); font-size:var(--fs-hero); font-weight:500;
  background:transparent; border:0; border-bottom:1px solid var(--pl); padding:var(--sp-2) 0; height:auto; min-height:0; }
body.sec .settings-grid{ grid-template-columns:repeat(2,minmax(0,1fr)); }
@media(min-width:960px){ body.sec .settings-grid{ grid-template-columns:repeat(4,minmax(0,1fr)); } }
body.sec .settings-grid .hint-row{ grid-column:1/-1; }
body.sec button.btn.btn-soft, body.sec button.ghost{ background:transparent; border:1px solid var(--pl); color:var(--ink); }

/* ════════════════════════════════════════════════════════════════════
   TZ-redesign-secondary-en.md, D5 — /setup и /login: один столбец,
   420px, крупный вордмарк, один первичный вопрос/кнопка на экран.
   login.html держит свою копию (своя таблица стилей, login.css —
   значения совпадают, две строки не стоило тянуть через общий файл). ═══ */
body.auth .wrap{ max-width:420px; margin:0 auto; padding:56px 16px; }
body.auth .brand{ margin-bottom:var(--sp-8); }
body.auth .brand-mark{ display:block; font-family:var(--font-head); font-weight:500; font-size:2rem;
  letter-spacing:-.01em; color:var(--ink); text-decoration:none; }
body.auth .deck{ display:block; margin-top:6px; font-size:var(--fs-sm); color:var(--mut); }

/* Знакомство (/setup, body.auth): без карточки-рамки, заголовок шага —
   антиква, как h1 остальных экранов (приёмка второстепенных страниц 08.10). */
body.auth section.card.view-empty{ background:transparent; border:0; box-shadow:none;
  border-top:1px solid var(--pl); border-radius:0; padding-left:0; padding-right:0; }
body.auth .view-empty .ve-h{ font-family:var(--font-head); font-weight:var(--fw-head); font-size:var(--fs-2xl); }
