  /* Палитра построена от пастельного фисташкового фона: акцент применяется
     только к активным элементам и прогрессу, контрасты выверены по WCAG
     (значения не подбирать на глаз при правках). */
  :root{
    --bg:          #e4efdf;
    --panel:       #fbfdf9;
    --panel-2:     #eff5ec;
    --line:        #c6d8c0;
    --text:        #1c2a20;
    --dim:         #556657;
    --accent:      #0a7b5e;
    --accent-soft: #cceae3;
    --accent-line: #acd8cd;
    --accent-text: #106550;
    --on-accent:   #ffffff;
    /* Синий акцент вкладки «Вода» (wq-3b3) — парный набор к --accent*,
       чтобы вода отличалась на глаз и в мини-аппе, и в боте. Значения и
       контрасты подобраны владельцем заранее, пересчитывать не нужно. */
    --water:      #1268a6;
    --water-soft: #d6e8f4;
    --water-line: #b3d4e8;
    --water-text: #0f5987;
    --warm:        #a85f2e;
    --danger:      #b4443c;
    --danger-soft: #f7e2e0;   /* подложка строки-списания в ленте */
    --gold:        #8f6820;
    --mono: 'JetBrains Mono','SFMono-Regular',Consolas,monospace;
    /* Длительности анимаций — централизованно, чтобы крутить темп в одном
       месте, а не искать все transition по файлу.
       --dur-fast  — тактильный отклик на нажатие (:active кнопок и строк);
       --dur-base  — переходы состояния (прогресс-бары, переключатели, тосты)
                     и появление содержимого вкладки, поэтому не длиннее 200мс;
       --dur-slow  — единственное исключение: заполнение XP-полосы при
                     получении опыта — это не отклик на тап, а "награда",
                     ей уместно быть чуть более заметной и плавной. */
    --dur-fast: 120ms;
    --dur-base: 200ms;
    --dur-slow: 450ms;
    /* Высота нижней панели навигации БЕЗ учёта safe-area — как отдельная
       переменная, чтобы отступ контента (body) и высота самой панели
       (.tabs) считались от одного числа и не расходились при правке. */
    --tabbar-h: 58px;
  }
  *{box-sizing:border-box;}
  /* Узор — на html, а не на body: body шириной максимум 520px, и на широком
     экране узор оборвался бы по краям колонки. У body фон прозрачный, иначе
     он перекрыл бы рисунок в этой самой колонке.
     background-size задаёт масштаб плитки: чем меньше число, тем плотнее
     листья. Цвет под картинкой обязателен — если она не загрузится,
     страница останется фисташковой, а не белой. */
  html{margin:0;padding:0;color:var(--text);
    background-color:var(--bg);
    background-image:url("background.png");
    background-repeat:repeat;
    background-size:520px;
    font-family:-apple-system,'Segoe UI',Roboto,Arial,sans-serif;}
  /* Нижний паддинг раньше был фиксированным 60px под тост. Теперь снизу ещё
     и панель навигации (fixed, не в потоке документа) — без запаса под её
     высоту последняя карточка любой вкладки навсегда пряталась бы под ней.
     env(safe-area-inset-bottom) — та же безопасная зона iPhone, что и у
     .tabs ниже; без неё запас верный на Android, но короткий под "домашним"
     жестом iOS. +16px — зазор между последней карточкой и панелью. */
  body{margin:0 auto;padding:18px 14px calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 16px);max-width:520px;background:transparent;
    color:var(--text);font-family:inherit;}
  .hud-top{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:4px;}
  .brand{font-family:var(--mono);font-weight:700;letter-spacing:2px;font-size:13px;color:var(--dim);}
  .lvl{font-family:var(--mono);font-size:13px;color:var(--accent);font-weight:700;}
  .xpbar-wrap{height:8px;background:var(--panel-2);border-radius:5px;overflow:hidden;margin-bottom:22px;border:1px solid var(--line);}
  .xpbar{height:100%;background:var(--accent);transition:width var(--dur-slow) ease;}
  h1{font-size:26px;margin:0 0 2px;letter-spacing:-0.5px;}
  .sub{color:var(--dim);font-size:13px;margin-bottom:20px;}
  .row2{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:12px;}
  .card{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:16px;margin-bottom:12px;}
  .card-title{font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:var(--dim);margin-bottom:8px;font-weight:600;}
  .big-num{font-family:var(--mono);font-size:34px;font-weight:700;line-height:1;}
  .big-num small{font-size:15px;color:var(--dim);font-weight:500;margin-left:3px;}
  .delta{font-size:13px;margin-top:6px;font-family:var(--mono);}
  .delta.down{color:var(--accent);} .delta.up{color:var(--danger);} .delta.flat{color:var(--dim);}
  .streak-flex{display:flex;align-items:center;gap:14px;}
  .streak-num{font-family:var(--mono);font-size:40px;font-weight:800;color:var(--warm);}
  .streak-best{font-size:11px;color:var(--dim);}
  input[type=number],input[type=text]{width:100%;background:var(--panel-2);border:1px solid var(--line);
    color:var(--text);border-radius:10px;padding:12px;font-size:16px;font-family:var(--mono);margin-top:6px;}
  input[type=number]:focus,input[type=text]:focus{outline:none;border-color:var(--accent);}
  textarea{width:100%;background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    border-radius:10px;padding:12px;font-size:13.5px;line-height:1.5;font-family:inherit;
    min-height:110px;resize:vertical;margin-top:6px;}
  textarea:focus{outline:none;border-color:var(--accent);}
  .plan-display{font-size:13.5px;line-height:1.6;white-space:pre-wrap;}
  .plan-edit-link{font-size:11.5px;color:var(--accent);cursor:pointer;margin-top:8px;display:inline-block;
    transition:transform var(--dur-fast) ease-out;}
  .plan-edit-link:active{transform:scale(0.94);}
  /* transform на :active — основной инструмент "отклика на нажатие" во всём
     приложении. Именно transform/opacity, а не что-то из потока (width,
     margin), чтобы никогда не триггерить лишний layout соседних элементов. */
  button{background:var(--accent);color:var(--on-accent);border:none;border-radius:10px;
    padding:13px 16px;font-size:15px;font-weight:700;cursor:pointer;width:100%;margin-top:10px;
    transition:transform var(--dur-fast) ease-out;}
  button:active{transform:scale(0.97);}
  button:disabled{opacity:0.5;}
  .checklist{display:flex;flex-direction:column;gap:8px;}
  .chk{display:flex;align-items:center;gap:10px;background:var(--panel-2);
    border:1px solid var(--line);border-radius:10px;padding:11px 13px;cursor:pointer;user-select:none;
    transition:transform var(--dur-fast) ease-out;}
  .chk:active{transform:scale(0.97);}
  .chk.done{border-color:var(--accent-line);background:var(--accent-soft);}
  .chk .box{width:20px;height:20px;border-radius:6px;border:2px solid var(--dim);flex:none;
    display:flex;align-items:center;justify-content:center;font-size:13px;}
  .chk.done .box{border-color:var(--accent);background:var(--accent);color:var(--on-accent);}
  .chk .label{font-size:14px;flex:1;}
  /* Пропущенный приём пищи (эпик D, wq-hqy) — не нажимается (у элемента
     нет data-action, см. today.js), поэтому и выглядеть он не должен
     нажимаемым: курсор по умолчанию, без тактильного scale на :active. */
  .chk.missed{cursor:default;}
  .chk.missed:active{transform:none;}
  .chk.missed .box{border-color:var(--danger);color:var(--danger);}
  .chk.missed .label{color:var(--danger);}
  /* recoverable (wq-b4s): «отметку сняли после закрытия окна» — в отличие
     от обычного .chk.missed, эта карточка получает data-action в today.js
     и обязана визуально выглядеть нажимаемой, иначе возврат недостижим
     тем же образом, каким раньше был недостижим весь пропущенный пункт. */
  .chk.missed.recoverable{cursor:pointer;}
  .chk.missed.recoverable:active{transform:scale(0.97);}
  .chk .meal-status{font-size:11px;color:var(--danger);margin-top:2px;}
  .badges{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;}
  .badge{aspect-ratio:1;border-radius:12px;display:flex;flex-direction:column;align-items:center;justify-content:center;
    background:var(--panel-2);border:1px solid var(--line);opacity:0.35;}
  .badge.unlocked{opacity:1;background:var(--accent-soft);border-color:var(--accent-line);}
  .badge .n{font-family:var(--mono);font-weight:800;font-size:17px;}
  .badge .u{font-size:9px;color:var(--dim);margin-top:2px;}
  .badge.unlocked .n{color:var(--gold);}

  /* Достижения (achievements.py) — список, а не сетка .badges: у каждой
     строки название + подсказка "за что дают", сетке столько текста не
     ужать. Закрытые приглушены --dim целиком (значок, заголовок, подсказка)
     и без рамки-акцента — карточка не должна выглядеть наполовину "успешной"
     раньше времени; полученные получают акцентную рамку и золотую звезду,
     тот же приём, что у .badge.unlocked .n. */
  .achv-list{display:flex;flex-direction:column;gap:6px;}
  .achv{display:flex;align-items:center;gap:10px;background:var(--panel-2);
    border:1px solid var(--line);border-radius:10px;padding:9px 12px;opacity:0.55;}
  .achv.earned{opacity:1;border-color:var(--accent-line);background:var(--accent-soft);}
  .achv-mark{flex:none;width:20px;text-align:center;font-size:15px;color:var(--dim);}
  .achv.earned .achv-mark{color:var(--gold);}
  .achv-body{flex:1;min-width:0;}
  .achv-title{font-size:13px;font-weight:600;}
  .achv-hint{font-size:11px;color:var(--dim);margin-top:1px;}
  .achv-xp{flex:none;font-family:var(--mono);font-size:12px;color:var(--dim);}
  .achv.earned .achv-xp{color:var(--accent-text);}
  canvas{width:100%;height:140px;display:block;}
  /* Тост поднят над панелью навигации: раньше bottom:20px был безопасен,
     потому что ниже не было ничего кроме края экрана, теперь там fixed
     .tabs — без сдвига тост всплывал бы поверх подписей вкладок и
     закрывал их на те же 2.2с, что и показывается. */
  .toast{position:fixed;bottom:calc(var(--tabbar-h) + env(safe-area-inset-bottom) + 14px);left:50%;
    transform:translateX(-50%) translateY(20px);
    background:var(--accent);color:var(--on-accent);padding:12px 20px;border-radius:12px;font-weight:700;
    font-size:14px;opacity:0;transition:opacity var(--dur-base) ease,transform var(--dur-base) ease;
    pointer-events:none;z-index:50;white-space:nowrap;}
  .toast.show{opacity:1;transform:translateX(-50%) translateY(0);}
  .loading{color:var(--dim);text-align:center;padding:40px 0;font-family:var(--mono);}

  /* Нижняя навигация, а не полоска сверху: раньше шесть подписей-кнопок не
     помещались в строку на 375px и переносились в два ряда — визуально
     список кнопок, а не навигация, и съедало верх экрана. Здесь все шесть
     в один ряд (flex без wrap, поровну по 1/6 через flex:1) — иконка
     компактнее самого длинного слова, перенос не нужен.
     position:fixed + left/right:0 — во всю ширину вьюпорта, max-width и
     margin:auto те же, что у body, чтобы на широком экране панель
     выравнивалась по той же колонке, а не тянулась во весь браузер.
     env(safe-area-inset-bottom) — запас под индикатор жеста iPhone;
     работает только вместе с viewport-fit=cover в index.html. */
  .tabs{position:fixed;left:0;right:0;bottom:0;margin:0 auto;max-width:520px;
    display:flex;z-index:40;
    background:var(--panel);border-top:1px solid var(--line);
    padding:6px 4px calc(6px + env(safe-area-inset-bottom));}
  .tab{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;
    min-width:0;padding:2px;border-radius:10px;color:var(--dim);cursor:pointer;
    transition:transform var(--dur-fast) ease-out,color var(--dur-base) ease;}
  .tab:active{transform:scale(0.93);}
  /* Акцент только цветом иконки и подписи — без заливки-пилюли под активной
     вкладкой: с ней панель читалась тяжелее, чем нужно для шести кнопок
     подряд. font-weight подписи растёт вместе с цветом — второй сигнал
     активности на случай, если пользователь путает оттенки. */
  /* var(--tab-accent, var(--accent)) — общий механизм переопределения, а
     не отдельное CSS-правило на каждую вкладку: конкретный цвет вкладка
     задаёт инлайн-стилем в renderTabsBar() (app.js), здесь только фолбэк
     на обычный мятный акцент (wq-3b3, синяя «Вода»). */
  .tab.active{color:var(--tab-accent, var(--accent));}
  .tab.active .tab-label{font-weight:800;}
  .tab-icon{display:flex;}
  .tab-icon svg{width:22px;height:22px;display:block;}
  .tab-label{font-size:10.5px;font-weight:600;line-height:1.1;white-space:nowrap;}

  /* Появление #tabContent при переключении вкладки — короткий фейд+сдвиг.
     Класс намеренно НЕ висит на .tab-content постоянно: он навешивается из
     app.js только когда вкладка реально сменилась. #tabContent
     пересоздаётся ПРИ КАЖДОЙ перерисовке (галочка в чек-листе, правка
     порции и т.п.), а не только при смене вкладки — если бы анимация была
     безусловной, она переигрывалась бы на каждый тап и весь экран мигал
     бы вместо тихого отклика. См. комментарий в app.js рядом с render(). */
  @keyframes tabContentEnter{
    from{opacity:0;transform:translateY(6px);}
    to{opacity:1;transform:translateY(0);}
  }
  .tab-content-enter{animation:tabContentEnter var(--dur-base) ease-out;}

  .dish-row{display:flex;justify-content:space-between;align-items:center;gap:8px;
    background:var(--panel-2);border:1px solid var(--line);border-radius:10px;padding:10px 12px;margin-bottom:6px;}
  /* Атрибутный селектор, а не просто .dish-row: строки состава блюда внутри
     редактора (renderCompositionRow) переиспользуют тот же класс, но не
     кликабельны — им курсор и отклик на нажатие не нужны и вводили бы
     в заблуждение. */
  .dish-row[data-action]{cursor:pointer;transition:transform var(--dur-fast) ease-out;}
  .dish-row[data-action]:active{transform:scale(0.97);}
  .dish-row .dname{font-size:13.5px;font-weight:600;}
  .dish-row .dmacros{font-size:11px;color:var(--dim);font-family:var(--mono);margin-top:2px;}
  /* Цель для пальца: минимум 44x44. Раньше было 26x22 — и поскольку
     крестик лежит внутри строки блюда с собственным действием, промах на
     пару пикселей открывал редактор вместо удаления. */
  .dish-del{color:var(--danger);font-size:18px;cursor:pointer;flex:none;
    min-width:44px;min-height:44px;display:flex;align-items:center;justify-content:center;
    margin:-11px -8px -11px 0;border-radius:10px;transition:transform var(--dur-fast) ease-out;}
  .dish-del:active{background:var(--panel-2);transform:scale(0.9);}

  .field-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:8px;}
  .field-grid input{width:100%;background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    border-radius:8px;padding:9px;font-size:13px;font-family:var(--mono);}
  .field-grid input:focus{outline:none;border-color:var(--accent);}
  .field-grid label{font-size:10px;color:var(--dim);display:block;margin-bottom:3px;}

  .target-bar-wrap{height:10px;background:var(--panel-2);border-radius:5px;overflow:hidden;margin:8px 0;border:1px solid var(--line);}
  .target-bar{height:100%;transition:width var(--dur-base) ease;}
  .target-bar.ok{background:var(--accent);}
  .target-bar.over{background:var(--danger);}
  .target-row{display:flex;justify-content:space-between;font-size:12px;font-family:var(--mono);margin-top:2px;}
  .meal-plan-line{font-size:11px;color:var(--dim);margin-top:2px;}

  /* Списки ингредиентов и блюд растут вместе со справочником и без потолка
     растягивали бы всю страницу — до кнопок внизу пришлось бы прокручивать
     простыню длиной в весь список. max-height (не height: короткий список
     не должен оставлять пустой хвост) + overflow-y:auto держат скролл
     внутри блока, а не всей страницы. 60vh, а не 80vh из ориентира
     владельца — на вкладке два таких списка одновременно, и по 80vh на
     каждый смысла нет. */
  .ing-list{max-height:60vh;overflow-y:auto;}
  .dish-list{max-height:60vh;overflow-y:auto;}
  /* Список продуктов на неделю (wq-hg5) растёт вместе с планом — тот же
     приём, что у справочника выше: max-height (не height, короткий список
     не должен оставлять пустой хвост) + скролл внутри блока. */
  .shopping-list{max-height:60vh;overflow-y:auto;}

  .ing-row{background:var(--panel-2);border:1px solid var(--line);border-radius:10px;
    padding:10px 12px;margin-bottom:6px;}
  .ing-row .dname{font-size:13.5px;font-weight:600;}
  .ing-row .dmacros{font-size:11px;color:var(--dim);font-family:var(--mono);margin-top:2px;}
  .form-error{color:var(--danger);font-size:12px;margin-top:8px;}
  .ing-row{cursor:pointer;transition:transform var(--dur-fast) ease-out;}
  .ing-row:active{transform:scale(0.97);}
  .ing-row-edit{background:var(--panel-2);border:1px solid var(--line);border-radius:10px;
    padding:10px 12px;margin-bottom:6px;}
  .ing-row-actions{display:flex;gap:8px;margin-top:10px;}
  /* Базовая кнопка шириной 100% — три штуки в ряд суммарно шире карточки
     и вылезают за её рамку. flex:1 делит доступную ширину поровну и не
     даёт ни одной кнопке требовать 100% сама по себе; min-width:0 снимает
     дефолтный auto, из-за которого flex-shrink не срабатывает на кнопках
     с длинным текстом ("Отмена"). Компактный padding/font — только
     визуальная толщина, min-height держит область нажатия не меньше 44px
     по высоте независимо от того, как метрики шрифта посчитают высоту
     строки. */
  .ing-row-actions button{margin-top:0;flex:1;min-width:0;min-height:44px;
    padding:9px 6px;font-size:13px;}

  .comp-grams{width:64px;background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    border-radius:8px;padding:6px;font-size:13px;font-family:var(--mono);text-align:right;}
  select.ing-picker{width:100%;background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    border-radius:8px;padding:9px;font-size:13px;margin-top:6px;}

  .week-nav{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;}
  .week-range{display:flex;flex-direction:column;align-items:center;gap:2px;font-family:var(--mono);font-size:13px;}
  .week-status{font-size:10px;text-transform:uppercase;letter-spacing:1px;color:var(--dim);}
  .week-status.launched{color:var(--accent);}
  /* Режим копирования дня: полоска дней превращается в выбор приёмника.
     Отдельного списка нет намеренно — состояние в DOM пересоздавалось при
     каждой перерисовке #tabContent и ломало выбор. */
  .day-strip-card{padding:10px 12px;}
  .ds-day.copy-target{border:1px dashed var(--accent-line);background:var(--accent-soft);}
  .ds-day.copy-source{opacity:0.45;}
  .copy-hint{margin-top:8px;font-size:12px;color:var(--accent-text);
    display:flex;justify-content:space-between;align-items:center;gap:8px;}
  /* Подсказка режима переноса блюда (замена долгого нажатия) — тот же вид,
     что у .copy-hint выше, только рядом с кнопкой «Переместить блюдо» над
     списком приёмов пищи (wq-rb0), а не в полоске дней. */
  .move-hint{margin-top:8px;font-size:12px;color:var(--accent-text);
    display:flex;justify-content:space-between;align-items:center;gap:8px;}
  .day-strip{display:flex;justify-content:space-between;padding:10px 8px;}
  .ds-day{display:flex;flex-direction:column;align-items:center;gap:6px;cursor:pointer;padding:4px;border-radius:8px;
    transition:transform var(--dur-fast) ease-out;}
  .ds-day:active{transform:scale(0.94);}
  .ds-day.selected{background:var(--panel-2);}
  .ds-name{font-size:11px;color:var(--dim);}
  .ds-dots{display:flex;flex-direction:column;gap:3px;align-items:center;}
  .ds-dot{width:7px;height:7px;border-radius:50%;background:var(--panel-2);border:1px solid var(--line);}
  .ds-dot.filled{background:var(--accent);border-color:var(--accent);}

  .meal-list{padding-top:4px;}
  .meal-section{margin-bottom:14px;border-radius:10px;transition:background var(--dur-fast) ease-out;}
  .meal-section:last-child{margin-bottom:0;}
  .meal-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;}
  /* Заголовок приёма пищи — приёмник в режиме переноса блюда в два тапа
     (замена не сработавшего у владельца долгого нажатия). cursor:pointer —
     единственная подсказка "сюда можно тапнуть": подсветка всех заголовков
     сразу выглядела бы шумнее, чем подсветка одной выбранной строки-источника
     (.meal-dish-row.move-source ниже). */
  .meal-header.move-target{cursor:pointer;}
  .meal-title{font-size:13px;font-weight:600;}
  /* line-height:1 обязателен: без него глиф "+" центрируется по строчной
     коробке шрифта (со своими над-/подстрочными полями), а не по видимому
     контуру символа, и в квадрате 22x22 это заметный сдвиг вниз. Flex сам
     по себе центрирует лишь line box, а не форму символа внутри неё. */
  .meal-add-btn{width:22px;height:22px;border-radius:7px;background:var(--accent);color:var(--on-accent);
    display:flex;align-items:center;justify-content:center;font-weight:700;font-size:15px;line-height:1;
    cursor:pointer;flex:none;transition:transform var(--dur-fast) ease-out;}
  .meal-add-btn:active{transform:scale(0.9);}
  .meal-empty{font-size:12px;color:var(--dim);padding:4px 0;}
  .meal-dish-row{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:4px 0;
    transition:transform var(--dur-fast) ease-out;}
  /* Строка-источник в режиме переноса блюда — тот же токен-пара
     accent-soft/accent-line, что у .ds-day.copy-target (полоска дней,
     копирование дня): единый визуальный язык "это выбрано" по вкладке. */
  .meal-dish-row.move-source{background:var(--accent-soft);border-radius:8px;
    outline:1px dashed var(--accent-line);outline-offset:-1px;}
  /* cursor:pointer — иначе непонятно, что по названию можно тапнуть (открыть
     редактор блюда либо, в режиме переноса, выбрать источник); :active —
     тот же отклик на нажатие, что у .chk/.picker-row по всему проекту. */
  .meal-dish-name{font-size:13px;flex:1;cursor:pointer;transition:transform var(--dur-fast) ease-out;}
  .meal-dish-name:active{transform:scale(0.97);}
  .meal-dish-portions{font-size:12px;color:var(--dim);font-family:var(--mono);}
  .meal-dish-actions{display:flex;gap:4px;flex:none;}
  /* Тот же приём, что у .dish-del, но зеркально: там хитбокс раздвигали
     наружу за пределы видимого крестика, здесь наоборот — видимый квадрат
     меньше хитбокса. Кнопка (.mini-btn) — прозрачная область 44x44, ровно
     цель для пальца; красит и скругляет только вложенный .mini-btn-visual
     28x28. Раздельные элементы, а не background-clip:content-box на самой
     кнопке — иначе border-radius при вычитании padding даёт почти острые
     углы вместо аккуратного скругления. */
  .mini-btn{width:44px;height:44px;min-width:44px;padding:0;margin:0;background:transparent;
    display:inline-flex;align-items:center;justify-content:center;flex:none;}
  .mini-btn-visual{width:28px;height:28px;border-radius:8px;background:var(--accent);color:var(--on-accent);
    display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:700;line-height:1;}
  .mini-btn.danger .mini-btn-visual{background:var(--danger);color:#fff;}

  /* wq-0vy: попап пикера открывается ПОВЕРХ прежнего контента страницы, но
     нижняя навигация (.tabs) — отдельный fixed-элемент со своим z-index:40,
     появившийся позже .picker-overlay (z-index:20) и оставшийся выше него
     в порядке отрисовки — последний пункт списка блюд оказывался под
     панелью и без доступа. 45 — выше .tabs(40), но ниже .toast(50): тост с
     ошибкой обязан оставаться видимым, даже пока пикер открыт. */
  .picker-overlay{position:fixed;inset:0;background:rgba(0,0,0,0.55);display:flex;
    align-items:flex-end;justify-content:center;z-index:45;}
  /* max-height (не height, короткий список не должен оставлять пустой
     хвост) уже держал скролл внутри карточки. Не хватало запаса снизу под
     env(safe-area-inset-bottom) — тот же приём, что у .tabs и у тоста:
     иначе последний пункт списка на iPhone прячется под индикатором жеста. */
  .picker-card{background:var(--panel);border-radius:16px 16px 0 0;
    padding:16px 16px calc(16px + env(safe-area-inset-bottom));width:100%;
    max-width:480px;max-height:70vh;overflow-y:auto;}
  /* .dish-search — поиск блюд на вкладке «Блюда» — визуально то же поле,
     что и .picker-search в пикере блюда сетки недели, поэтому делят одно
     правило вместо копии стилей под новым именем. */
  .picker-search,.dish-search{width:100%;background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    border-radius:8px;padding:8px 10px;font-size:13px;margin:8px 0;}
  .picker-row{display:flex;justify-content:space-between;align-items:center;
    min-height:44px;padding:10px 6px;border-bottom:1px solid var(--line);cursor:pointer;
    transition:transform var(--dur-fast) ease-out;}
  .picker-row:active{background:var(--panel-2);transform:scale(0.98);}
  .picker-row:last-child{border-bottom:none;}
  .picker-name{font-size:13.5px;}
  .picker-macros{font-size:11px;color:var(--dim);font-family:var(--mono);}

  .exchange-card h3{font-size:13px;margin:0 0 8px;}
  .exchange-textarea{font-family:var(--mono);font-size:12px;min-height:130px;}
  .exchange-buttons{display:flex;gap:8px;}
  .exchange-buttons button{margin-top:10px;}
  .exchange-report{font-size:12.5px;line-height:1.6;margin-top:10px;color:var(--dim);}

  .week-copy-actions{display:flex;gap:8px;margin-top:10px;}
  .day-actions{display:flex;gap:6px;margin-top:10px;flex-wrap:wrap;align-items:center;}
  .copy-day-select{background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    border-radius:8px;padding:6px 8px;font-size:12px;}
  .secondary-btn{background:var(--panel-2);color:var(--text);border:1px solid var(--line);}
  .danger-btn{background:var(--danger);color:#fff;}
  /* «Опасная зона»: рамка в цвет danger отделяет необратимое действие от
     рядовых настроек визуально, а не просто порядком в разметке — иначе
     кнопка удаления профиля ничем не отличалась бы от «Сохранить цели»
     на быстрый взгляд. */
  .card--danger{border-color:var(--danger);}
  .card--danger .card-title{color:var(--danger);}

  .settings-meals{display:flex;flex-direction:column;gap:8px;}
  .settings-meal-row{display:flex;align-items:center;gap:8px;background:var(--panel-2);
    border:1px solid var(--line);border-radius:10px;padding:8px 10px;transition:opacity var(--dur-base) ease;}
  .settings-meal-row--off{opacity:0.5;}
  .settings-meal-name{flex:1;min-width:0;background:var(--panel);border:1px solid var(--line);
    color:var(--text);border-radius:8px;padding:9px;font-size:13px;}
  .settings-meal-time{flex:none;width:92px;background:var(--panel);border:1px solid var(--line);
    color:var(--text);border-radius:8px;padding:9px 6px;font-size:13px;font-family:var(--mono);}
  .settings-meal-name:focus,.settings-meal-time:focus{outline:none;border-color:var(--accent);}
  /* Цель для пальца: сам переключатель нарисован маленьким (38x22), но
     клик ловится всей меткой 44x44 — тот же приём, что у .dish-del, чтобы
     не повторить баг с промахом мимо мелкого хитбокса. */
  .switch{position:relative;flex:none;width:44px;height:44px;display:flex;
    align-items:center;justify-content:center;cursor:pointer;}
  .switch input{position:absolute;inset:0;margin:0;opacity:0;cursor:pointer;z-index:1;}
  .switch-track{width:38px;height:22px;border-radius:11px;background:var(--panel);
    border:1px solid var(--line);position:relative;pointer-events:none;
    transition:background var(--dur-base) ease,border-color var(--dur-base) ease;}
  .switch-track::after{content:'';position:absolute;top:1px;left:1px;width:18px;height:18px;
    border-radius:50%;background:var(--dim);transition:transform var(--dur-base) ease,background var(--dur-base) ease;}
  .switch input:checked + .switch-track{background:var(--accent-soft);border-color:var(--accent-line);}
  .switch input:checked + .switch-track::after{transform:translateX(16px);background:var(--accent);}

  /* Карточка «Отпуск» (wq-36y): список отпусков — тот же приём строки,
     что у .water-glass-row (дата слева, действие справа), плюс явная
     пометка текущего отпуска акцентным цветом — иначе в списке из
     нескольких отпусков непонятно, какой из них идёт прямо сейчас. */
  .vacation-list{display:flex;flex-direction:column;margin-top:8px;}
  .vacation-row{display:flex;justify-content:space-between;align-items:center;
    padding:9px 0;border-bottom:1px solid var(--line);font-size:13px;}
  .vacation-row:last-child{border-bottom:none;}
  .vacation-range{font-family:var(--mono);}
  .vacation-row--current .vacation-range{color:var(--accent-text);font-weight:700;}
  .vacation-current-tag{margin-left:6px;font-weight:600;
    font-size:11px;color:var(--accent-text);background:var(--accent-soft);
    border-radius:6px;padding:2px 6px;}
  /* Заметка на «Сегодня», пока идёт отпуск — тот же мятный акцент, что и
     у выполненных приёмов пищи (.chk.done): отпуск не тревожный сигнал,
     а спокойное состояние, поэтому не --danger. */
  .card--vacation{background:var(--accent-soft);border-color:var(--accent-line);
    color:var(--accent-text);font-size:13px;}

  /* Вкладка «Вода»: три мелкие кнопки в ряд (+100/+500/убрать последний) —
     тот же grid-приём, что у .row2, только на три колонки. */
  .water-actions{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-top:8px;}
  .water-glass-list{display:flex;flex-direction:column;gap:2px;}
  .water-glass-row{display:flex;justify-content:space-between;padding:9px 0;
    border-bottom:1px solid var(--line);font-size:13px;}
  .water-glass-row:last-child{border-bottom:none;}
  .water-glass-time{font-family:var(--mono);color:var(--dim);}
  .water-glass-ml{font-family:var(--mono);}
  /* Переключатель «напоминать» — своя строка, а не внутри .field-grid: у
     него нет числового значения, только подпись и .switch, как у строки
     приёма пищи в settings.js. */
  .water-toggle-row{display:flex;align-items:center;justify-content:space-between;
    margin:10px 0 0;font-size:14px;}

  /* wq-ktd: владелец увидел вкладку «наполовину синей» — прогресс, кнопка
     «+ стакан» и крупные цифры уже брали --water (wq-3b3), а «Сохранить
     настройки», тоггл «Напоминать» и рамка полей при фокусе оставались на
     общем мятном --accent. Решение пересмотрено: красим вкладку целиком.
     Кандидатов набралось много (обычная кнопка, .switch, :focus нескольких
     типов инпутов) — вместо scoped-правила на каждый переопределяем сами
     переменные --accent* внутри .tab-water. Любой элемент общего CSS,
     который красится через var(--accent*), автоматически становится синим
     на этой вкладке без отдельной правки под каждый — так закрываются и
     кнопка «Сохранить настройки» (общее правило button{background:
     var(--accent)}), и тоггл «Напоминать» (.switch input:checked +
     .switch-track читает --accent-soft/--accent-line/--accent), и рамка
     инпутов в фокусе (input[type=number]/.field-grid input:focus).
     Проверено: внутри .tab-water не рендерится ничего из общих
     --accent-потребителей за пределами воды (.chk/.badge/.achv/
     .week-status и т.п.) — переопределение не задевает ничего постороннего.
     secondary-btn/danger-btn (+100/+500/«убрать последний») не читают
     --accent* вовсе — свой панельный/красный цвет, остаются нейтральными,
     как и раньше. Шапка с уровнем и тост — вне .tab-water (см. index.html,
     .toast — сосед #tabContent, а не его потомок), этой переменной не
     касаются, как и просил владелец. */
  .tab-water{
    --accent: var(--water);
    --accent-soft: var(--water-soft);
    --accent-line: var(--water-line);
    --accent-text: var(--water-text);
  }

  /* Синий акцент вкладки «Вода» (wq-3b3), позже расширенный wq-ktd выше.
     .big-num не задаёт цвет в общем правиле — своей строки не миновать.
     .target-bar.ok и кнопка с data-action теперь дублируют то же значение,
     что уже даёт переопределение --accent* выше (оба читают var(--accent)
     в общих правилах) — оставлены как есть, чтобы не трогать более старые
     тесты wq-3b3, которые ищут именно эти строки. */
  .tab-water .target-bar.ok{background:var(--water);}
  .tab-water .big-num{color:var(--water);}
  .tab-water [data-action="water-add-glass"]{background:var(--water);}
  /* Приглушённая пара токенов — дорожка прогресса и список отметок. Без
     них на вкладке было три синих пятна посреди мятного; с ними вкладка
     читается синей целиком, но негромко: --water-soft/--water-line той же
     светлоты, что мятные --accent-soft/--accent-line, а --water-text даёт
     6:1 по светлой заливке. Заодно эти три токена перестают быть
     объявленными и никем не используемыми. */
  .tab-water .target-bar-wrap{background:var(--water-soft);border-color:var(--water-line);}
  .tab-water .water-glass-row{border-bottom-color:var(--water-line);}
  .tab-water .water-glass-ml{color:var(--water-text);}

  .feed-header{padding:10px;}
  .feed-nav{display:flex;align-items:center;gap:8px;}
  .feed-nav-btn{flex:none;width:40px;padding:8px 0;margin:0;}
  .feed-date-input{flex:1;background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    border-radius:8px;padding:8px;font-size:14px;}
  .feed-date-input:focus{outline:none;border-color:var(--accent);}
  .feed-list{display:flex;flex-direction:column;gap:2px;}
  .feed-row{display:flex;gap:10px;padding:9px 0;border-bottom:1px solid var(--line);}
  .feed-row:last-child{border-bottom:none;}
  /* Списания (пропуск, срыв) в ленте нельзя оставлять обычным текстом:
     лента читается взглядом сверху вниз, и «−10 XP» той же серой мелочью,
     что и время, просто не замечается. Подложка + красная полоса слева +
     красная сумма — три сигнала, из которых достаточно любого одного.
     Признак приходит из formatEvent (tone), разметка сама не решает. */
  .feed-row.negative{background:var(--danger-soft);border-left:3px solid var(--danger);
    padding-left:9px;margin:2px -6px;border-radius:8px;border-bottom-color:transparent;}
  .feed-row.negative .feed-detail{color:var(--danger);font-weight:700;}
  .feed-time{flex:none;width:70px;font-family:var(--mono);font-size:11px;color:var(--dim);padding-top:1px;}
  .feed-body{flex:1;min-width:0;}
  .feed-text{font-size:13px;color:var(--text);}
  .feed-detail{font-size:11px;color:var(--dim);margin-top:2px;}

  /* Уважаем prefers-reduced-motion безусловно: для части людей движение на
     экране — не украшательство, а источник реального дискомфорта (укачивание,
     головная боль). Правило универсальное и стоит последним, чтобы бить
     ЛЮБОЙ transition/animation выше по файлу разом, а не требовать держать
     в уме "не забыть добавить exception" при каждой новой анимации. */
  @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;
    }
  }
