/* ============ DayMe — палитры ============
   data-palette — наш собственный переключатель (Настройки → Палитра).
   data-theme   — зарезервирован для хоста (светлая/тёмная тема просмотрщика
   Artifact); в автономном PWA его никто не ставит, там работает просто
   prefers-color-scheme. Без выбранной палитры дефолт подстраивается под
   обе системы; выбранная палитра фиксирует вид независимо от темы хоста. */
:root {
  /* Палитра "Индиго" — токены ТЗ "DayMe. Твои дела. Твои люди. Твой
     день." (DayMe_TAGLINE_CORRECTED_FULL_SPEC_AND_VISUALS), раздел 3.
     Это ОТДЕЛЬНЫЙ, более новый концепт, заменяющий предыдущий визуал
     (reference_screens/"DayMe — Мой день") — по явному требованию ТЗ
     не смешивать их. Значения в исходном ТЗ сами помечены как E
     (целевые инженерные, не измеренные из Figma — источник растровый
     коллаж) — берутся как есть, не как визуальная самодеятельность.
     --accent/--brand — основной синий, --accent2 — акцент встреч
     (фиолетовый из ТЗ "--accent-violet"), --dot — янтарный
     (напоминания/заметки), --success — зелёный (задачи) */
  --bg: #F5F7FC;
  --surface: #FFFFFF;
  --surface-2: #EEF1F9;
  --text: #14213D;
  --text-dim: #7283A5;
  --accent: #315FEA;
  --accent-text: #FFFFFF;
  --accent-soft: #EAF1FF;
  --accent2: #6B4EFF;
  --accent2-soft: #F2EBFF;
  --dot: #F5A623;
  --dot-soft: #FFF5E4;
  --danger: #E85B78;
  --danger-soft: #FCE3E8;
  --success: #24B987;
  --success-soft: #E8F8F2;
  /* Цвет иконок в плоских плитках сводки дня — тот же оттенок, что сама
     плитка, но более тёмный/насыщенный читаемый тон (в ТЗ пиктограммы
     на плитках явно темнее подложки) */
  --accent-icon: #1D4ED8;
  --success-icon: #0E7A54;
  --accent2-icon: #5321E0;
  --dot-icon: #C97C0A;
  --accent-light: #5E8CEE;
  --border: #E7ECF5;
  --tab-bg: rgba(255, 255, 255, 0.92);
  --shadow: 0 4px 18px rgba(39, 67, 120, .07);
  --radius: 18px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  /* Правка по обратной связи: плитки "Встречи"/"Контакты сегодня" на
     "Моём дне" — в светлой теме --accent (синий) и --accent2 (фиолетовый)
     хорошо различимы, а в тёмной (#7B7FFF/#A78BFA ниже) оба читаются как
     один и тот же лавандовый оттенок. В светлой теме эти токены просто
     равны обычным --accent/--accent2 (ничего не меняется из того, что
     уже "отлично смотрится", как и просили) — переопределяются только
     в тёмных блоках ниже, отдельными, более различимыми цветами */
  --tile-meeting-bg: var(--accent-soft);
  --tile-meeting-fg: var(--accent);
  --tile-contact-bg: var(--accent2-soft);
  --tile-contact-fg: var(--accent2);
}

/* тёмный вариант палитры "Индиго" — включается системой (если
   пользователь явно не выбрал свою палитру и явно не выбрал светлую
   тему хоста) */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-palette]) {
    --bg: #14151C;
    --surface: #1C1E28;
    --surface-2: #262838;
    --text: #ECEDF5;
    --text-dim: #9094A8;
    --accent: #7B7FFF;
    --accent-text: #14151C;
    --accent-soft: #2B2C45;
    --accent2: #A78BFA;
    --accent2-soft: #322850;
    --dot: #F0B155;
    --dot-soft: #3A2E1C;
    --danger: #F0788C;
    --danger-soft: #3D232C;
    --success: #3FC48A;
    --success-soft: #1D3328;
    /* Находка пользователя 2026-10-27 (ручная проверка в тёмной теме) —
       --success-icon в :root задан один раз (#0E7A54, тёмно-зелёный,
       рассчитан на светлый --success-soft) и не был переопределён
       здесь — текст/иконка на тёмно-зелёном --success-soft читались
       плохо. Берём то же значение, что --success в этом блоке — он уже
       подобран читаемым на тёмном --success-soft (тот же приём, что у
       .history-done-badge: background --success-soft, color --success) */
    --success-icon: #3FC48A;
    /* Задача 5 (docs/RELEASE_1NOV.md) — тот же пробел у трёх похожих
       токенов, тем же способом (значение --accent/--accent2/--dot
       этого блока — уже подобраны читаемыми на своём тёмном -soft) */
    --accent-icon: #7B7FFF;
    --accent2-icon: #A78BFA;
    --dot-icon: #F0B155;
    --border: #2E3042;
    --tab-bg: rgba(20, 21, 28, 0.92);
    --shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
    /* Правка по обратной связи: --accent/--accent2 в тёмной теме —
       оба лавандовые, плитки "Встречи" и "Контакты сегодня" сливались.
       Здесь — явно синий (встречи) и явно пурпурно-розовый (контакты),
       разные по оттенку, не только по яркости */
    --tile-meeting-bg: #1E2B4D;
    --tile-meeting-fg: #6FA4FF;
    --tile-contact-bg: #3D2150;
    --tile-contact-fg: #E08BF0;
  }
}
:root[data-theme="dark"]:not([data-palette]) {
  --bg: #14151C;
  --surface: #1C1E28;
  --surface-2: #262838;
  --text: #ECEDF5;
  --text-dim: #9094A8;
  --accent: #7B7FFF;
  --accent-text: #14151C;
  --accent-soft: #2B2C45;
  --accent2: #A78BFA;
  --accent2-soft: #322850;
  --dot: #F0B155;
  --dot-soft: #3A2E1C;
  --danger: #F0788C;
  --danger-soft: #3D232C;
  --success: #3FC48A;
  --success-soft: #1D3328;
  --success-icon: #3FC48A; /* та же причина, что в @media (prefers-color-scheme: dark) выше */
  --accent-icon: #7B7FFF;
  --accent2-icon: #A78BFA;
  --dot-icon: #F0B155;
  --border: #2E3042;
  --tab-bg: rgba(20, 21, 28, 0.92);
  --shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
  --tile-meeting-bg: #1E2B4D;
  --tile-meeting-fg: #6FA4FF;
  --tile-contact-bg: #3D2150;
  --tile-contact-fg: #E08BF0;
}

/* бывшая палитра по умолчанию (ivory/ink/terracotta) — не удалена,
   просто переехала в выбираемую "Тепло", чтобы её никто не потерял */
[data-palette="warm"] {
  --bg: #F6F1E8;
  --surface: #FFFFFF;
  --surface-2: #EFE7D8;
  --text: #211F1C;
  --text-dim: #5B564C;
  --accent: #C96A45;
  --accent-text: #FFFFFF;
  --accent-soft: #F4E6DF;
  --accent2: #8A6A9E;
  --accent2-soft: #ECE2F1;
  --dot: #D9A440;
  --dot-soft: #F7EAD2;
  --danger: #C2475B;
  --danger-soft: #F5DCE0;
  --success: #4C6B49;
  --success-soft: #E3EADF;
  --border: #E8E1D2;
  --tab-bg: rgba(246, 241, 232, 0.92);
  --shadow: 0 1px 3px rgba(33, 31, 28, 0.08);
}
@media (prefers-color-scheme: dark) {
  [data-palette="warm"]:not([data-theme="light"]) {
    --bg: #1C1A17;
    --surface: #26231F;
    --surface-2: #322E27;
    --text: #F3EEE4;
    --text-dim: #A89F8F;
    --accent: #E08860;
    --accent-text: #1C1A17;
    --accent-soft: #3A2A21;
    --dot: #E0B45E;
    --danger: #E37E8F;
    --danger-soft: #3D2429;
    --success: #7FA67A;
    --border: #3A3530;
    --tab-bg: rgba(28, 26, 23, 0.92);
    --shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
  }
}

[data-palette="terracotta"] {
  --bg: #FAF7F2;
  --surface: #FFFFFF;
  --surface-2: #F1EDE6;
  --text: #2B2B2B;
  --text-dim: #8A8478;
  --accent: #E2725B;
  --accent-text: #FFFFFF;
  --accent-soft: #F6DCD4;
  --dot: #7C9473;
  --danger: #C8553D;
  --border: #EAE3D8;
  --tab-bg: rgba(250, 247, 242, 0.92);
  --shadow: 0 1px 3px rgba(43, 43, 43, 0.08);
}

[data-palette="sage"] {
  --bg: #F4F7F2;
  --surface: #FFFFFF;
  --surface-2: #E8EEE3;
  --text: #28322A;
  --text-dim: #7E8C7B;
  --accent: #5E8C5A;
  --accent-text: #FFFFFF;
  --accent-soft: #DCE9D7;
  --dot: #C98A3E;
  --danger: #C8553D;
  --border: #DEE8D8;
}

[data-palette="ocean"] {
  --bg: #F2F6F8;
  --surface: #FFFFFF;
  --surface-2: #E4EDF0;
  --text: #223038;
  --text-dim: #74868F;
  --accent: #3C7A8C;
  --accent-text: #FFFFFF;
  --accent-soft: #D7E6EA;
  --dot: #D98E45;
  --danger: #C8553D;
  --border: #DCE6E9;
}

[data-palette="midnight"] {
  --bg: #15161A;
  --surface: #1E1F24;
  --surface-2: #26272D;
  --text: #EDEBE6;
  --text-dim: #8C8A86;
  --accent: #E2895B;
  --accent-text: #15161A;
  --accent-soft: #3A2E27;
  --dot: #7FB07A;
  --danger: #E2785B;
  --border: #302F35;
  --tab-bg: rgba(21, 22, 26, 0.92);
  --shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
}

/* ============ Базовое ============ */
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
}
body {
  overscroll-behavior-y: none;
}
#app {
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
}
button { font: inherit; }
input, textarea, select {
  font: inherit;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  width: 100%;
  max-width: 100%;
}
/* на всю ширину карточки нативный выбор даты выглядит непропорционально
   широким (растянутая кликабельная область) — ограничиваем */
input[type="date"] { max-width: 190px; }
a { color: var(--accent); text-decoration: none; }

/* ============ Header ============ */
header.topbar {
  padding: calc(var(--safe-top) + 14px) 18px 12px;
  background: var(--bg);
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex: 0 0 auto;
}
.topbar-actions { display: flex; gap: 8px; align-self: center; }
.topbar-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  border: none;
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  box-shadow: var(--shadow);
  cursor: pointer;
}
.topbar-icon-btn svg { width: 18px; height: 18px; }
header.topbar h1 {
  font-size: 26px;
  font-weight: 700;
  margin: 0;
}
header.topbar .date {
  font-size: 13px;
  color: var(--text-dim);
}
header.topbar .date.date-headline {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-dim);
  text-transform: capitalize;
}
/* Правка по обратной связи: фраза дня — просто текст под датой, без
   плашки/выделения (раньше была в карточке .daily-card, как у
   напоминаний о днях рождения — убрали оформление именно здесь) */
.motivation-line { font-size: 12.5px; font-style: italic; color: var(--text-dim); margin-top: 2px; }
/* Замер по макету (IMG_3830, координаты 340-480×95-120, медиана тёмных
   пикселей): приветствие — крупный полужирный тёмно-синий заголовок,
   а дата под ним — мелкая вторичная строка. В прошлой версии было
   наоборот (дата — крупная, приветствие — мелкая капс-метка) — реальная
   ошибка иерархии, не просто оттенок */
/* TAGLINE-концепт: бренда "DayMe" в шапке больше нет (см. switchView) —
   приветствие само единственный крупный элемент. ТЗ даёт целевой
   диапазон 19-22px/650-750 (раздел 4), но измерение по кропу
   (01_HOME_MY_DAY_FULL_PHONE.png, высота прописной "Д" ≈ 32.5px при
   масштабе кропа ≈1.93 к CSS px) даёт ≈24px — визуальный кроп
   приоритетнее табличного плейсхолдера, когда они расходятся */
.greeting-label {
  font-size: 24px;
  font-weight: 750;
  color: var(--text);
  margin-bottom: 2px;
}
/* По кропу 01_home_screen.jpg на "Моём дне" над приветствием — жирный
   бренд-wordmark "DayMe" (спецификация, раздел 4 "Шапка DayMe": 25-27px/800);
   раньше на этом экране бренд нигде не показывался */
.brand-wordmark {
  font-size: 26px;
  font-weight: 800;
  color: var(--text);
  letter-spacing: -0.01em;
}
.header-dot {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--danger);
  border: 1.5px solid var(--surface);
}
.topbar-icon-btn { position: relative; }

/* ============ Контент ============ */
main {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: 0 16px 24px;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
}
section.view { display: none; }
section.view.active { display: block; animation: fadein .15s ease; }
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }

.card {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
  margin-bottom: 10px;
}
.card.done { opacity: .55; }
/* Короткая вспышка фона после свайп-действия "В полезные"/"Закрепить"
   (и обратно) — иначе список после переключения просто мгновенно
   перерисовывался на новый HTML без всякой обратной связи, "резко".
   Сама карточка — новый DOM-узел после renderContacts()/renderNotes(),
   поэтому анимация навешивается сразу в разметке (а не через transition
   по изменению класса) — CSS-анимация на только что вставленном
   элементе всё равно проигрывается сама */
.card.flash-on { animation: flash-on-kf .7s ease; }
.card.flash-off { animation: flash-off-kf .5s ease; }
@keyframes flash-on-kf {
  0% { background-color: color-mix(in srgb, var(--success) 32%, var(--surface)); }
  100% { background-color: var(--surface); }
}
@keyframes flash-off-kf {
  0% { background-color: color-mix(in srgb, var(--text-dim) 22%, var(--surface)); }
  100% { background-color: var(--surface); }
}
/* Удаление свайпом — карточка уезжает и гаснет перед тем, как реально
   пропасть из списка, вместо мгновенного исчезновения */
.contact-swipe-wrap.removing, .note-swipe-wrap.removing {
  transition: opacity .22s ease, transform .22s ease;
  opacity: 0;
  transform: translateX(-24px);
}
/* Статус считывается по самой карточке (фон/рамка), не только по тексту —
   просроченная заметно краснее, "скоро" заметно теплее, обычная белая */
.card.status-overdue { background: var(--danger-soft, var(--surface)); border: 1px solid var(--border); }
.card.status-overdue { border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.card.status-soon { background: var(--accent-soft); border: 1px solid var(--border); }
.card.status-soon { border-color: color-mix(in srgb, var(--dot) 35%, transparent); }
.card .row { display: flex; align-items: center; gap: 10px; }
.contact-status-badge {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 4px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 11px;
  font-weight: 700;
  font-family: inherit;
  border: none;
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
  cursor: pointer;
}
.contact-status-badge svg { width: 11px; height: 11px; }
.contact-status-badge.warn { background: color-mix(in srgb, var(--dot) 18%, var(--surface)); color: var(--dot); }
.contact-chevron { flex: 0 0 auto; display: flex; color: var(--text-dim); }
.contact-chevron svg { width: 16px; height: 16px; }
.contact-actions-row {
  display: flex;
  gap: 8px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.contact-action-btn {
  flex: 1;
  /* без этого flex-item не сжимается уже своего текста (min-width:auto
     по умолчанию) — самое длинное слово-без-пробела ("Написать")
     забирало себе лишнее место за счёт соседей, и кнопка "Ещё" с
     переносимым на пробеле текстом оставалась заметно уже остальных,
     хотя flex:1 у всех одинаковый */
  min-width: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--bg);
  border: none;
  border-radius: 12px;
  padding: 8px;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
}
.contact-action-btn svg { width: 14px; height: 14px; color: var(--text-dim); flex: 0 0 auto; }
/* "Написать"/"Звонок" — слова без пробела, сами не переносятся; при 4
   кнопках в ряд (телефон + адрес + "Ещё") им может не хватать места
   при строгом равенстве ширин. Вместо обрезания текста многоточием —
   переносим насильно (как раньше само получалось у "Ещё (N)" на
   пробеле) — читаемость важнее одной строки */
.contact-action-btn span { overflow-wrap: break-word; word-break: break-word; text-align: center; }
.address-list-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: var(--text);
}
.address-list-row:last-child { border-bottom: none; }
.address-list-icon { flex: 0 0 auto; display: flex; color: var(--text-dim); }
.address-list-icon svg { width: 18px; height: 18px; }
.address-list-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.address-list-label { font-weight: 600; font-size: 14px; }
.address-list-value { font-size: 12.5px; color: var(--text-dim); }
/* overflow-wrap — без него одно длинное слово без пробелов (длинное
   имя, название компании и т.п.) не переносится, а тихо обрезается
   родительским .contact-swipe-wrap/.note-swipe-wrap (overflow:hidden,
   нужен самому механизму свайпа) без всякого многоточия — находка
   регрессионного прогона Этапа 10, п. "отсутствие обрезанного текста" */
.card .title { font-weight: 600; font-size: 16px; flex: 1; position: relative; overflow-wrap: break-word; word-break: break-word; }
.card .meta { font-size: 12.5px; color: var(--text-dim); margin-top: 4px; overflow-wrap: break-word; word-break: break-word; }
.task-contacts-inline { display: flex; align-items: center; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
.task-contact-chip { display: flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; color: var(--text-dim); }
.task-contact-chip .avatar-circle { width: 16px; height: 16px; font-size: 8px; }
.task-contact-extra { color: var(--text-dim); font-weight: 700; }

/* ============ Выполнение задачи: галочка → заливка кружка → вспышка ============
   Второй такт (см. .check.checking выше для первого): кружок заливается
   зелёным (через transition на .check) одновременно с тем, как у карточки
   запускается 5-секундная вспышка фона с зачёркиванием текста */
.card.just-done, .untimed-chip.just-done { animation: task-just-done-flash 10s linear forwards; }
.card.just-done .check, .untimed-chip.just-done .check { background: var(--success); border-color: var(--success); }
.card.just-done .title::after, .untimed-chip.just-done .untimed-chip-title::after {
  content: '';
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  animation: task-strike .35s ease forwards;
  animation-delay: .1s;
}
/* короткая задержка (1с), затем медленное угасание цвета — 4 секунды из 5,
   чтобы вспышка реально читалась как анимация, а не как мгновенный сброс */
@keyframes task-just-done-flash {
  0% { background-color: rgba(47, 163, 96, 0.3); }
  20% { background-color: rgba(47, 163, 96, 0.3); }
  100% { background-color: transparent; }
}
@keyframes task-strike { to { transform: scaleX(1); } }

/* ============ Контакты/заметки: свайп по карточке — открывает кнопку действия ============
   Карточка лежит поверх двух скрытых панелей (слева — зелёная "Полезные"/
   "Закрепить", справа — красная "Удалить"); свайп сдвигает карточку и
   приоткрывает нужную панель, но действие не выполняется автоматически —
   нужно нажать на открывшуюся кнопку (как в Телеграме/Mail), иначе легко
   случайно удалить. Разметка общая для контактов (.contact-swipe-wrap) и
   заметок (.note-swipe-wrap) */
/* Эти ячейки — только тап (открыть карточку/кнопку быстрого действия)
   и свайп влево-вправо (reveal). Текст (имя, телефон, подписи кнопок)
   не предполагает копирования — долгий тап на телефоне/кнопке в Safari
   иначе поднимает системное выделение текста/колбаут поверх нашего
   свайпа, что и путает жест, и просто не нужно для этих ячеек:
   копировать есть смысл только там, где реально можно писать
   (поля ввода в форме контакта/заметки). user-drag:none — отдельно от
   выделения текста: кнопки "Звонок"/"Написать" это <a href="tel:/sms:">,
   а такие ссылки браузер по умолчанию умеет перетаскивать (долгий тап —
   ссылка "всплывает" и ездит за пальцем) — это тоже отключаем */
.contact-swipe-wrap, .note-swipe-wrap {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  margin-bottom: 10px;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.contact-swipe-wrap a, .note-swipe-wrap a, .contact-action-btn {
  -webkit-user-drag: none;
  user-drag: none;
}
/* Карточка сама скруглена по углам (.card border-radius) — у самого
   края свайпа это оставляет маленький непрокрашенный "серпик" между
   скруглённым углом карточки и прямоугольной панелью действия (92px),
   где просвечивал обычный фон wrap'а. Красим САМ wrap в цвет активного
   действия (не только панель) — тогда этот серпик уже закрашен тем же
   цветом, и шва не видно. data-side выставляется и во время живого
   перетаскивания (см. wireSwipeReveal), не только в покое */
.contact-swipe-wrap[data-side="left"], .note-swipe-wrap[data-side="left"] { background: var(--success); }
.contact-swipe-wrap[data-side="right"], .note-swipe-wrap[data-side="right"] { background: var(--danger); }
.contact-swipe-wrap .card, .note-swipe-wrap .card { margin-bottom: 0; position: relative; z-index: 2; transition: transform .28s cubic-bezier(0.22, 1, 0.36, 1); touch-action: none; }
.contact-swipe-wrap .card.swiping, .note-swipe-wrap .card.swiping { transition: none; will-change: transform; }
.contact-swipe-action {
  position: absolute;
  top: 0; bottom: 0;
  width: 92px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  text-align: center;
  padding: 0 10px;
  line-height: 1.25;
  font-size: 12px;
  font-weight: 700;
  color: #fff;
  z-index: 1;
}
.contact-swipe-action svg { width: 18px; height: 18px; }
.contact-swipe-action.left { left: 0; background: var(--success); border-radius: var(--radius) 0 0 var(--radius); }
.contact-swipe-action.right { right: 0; background: var(--danger); border-radius: 0 var(--radius) var(--radius) 0; }
.note-pin-badge { font-size: 12px; margin-bottom: 4px; color: var(--accent); display: flex; align-items: center; gap: 4px; }
.note-pin-badge svg { width: 12px; height: 12px; }
.tag {
  display: inline-block;
  font-size: 11.5px;
  padding: 3px 9px;
  border-radius: 20px;
  background: var(--accent-soft);
  color: var(--accent);
  margin-right: 6px;
  font-weight: 600;
}
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--dot); flex: 0 0 auto; }
.check {
  width: 24px; height: 24px; border-radius: 50%;
  border: 2px solid var(--border);
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  color: var(--accent-text);
  font-size: 13px;
  transition: background-color .5s ease, border-color .5s ease, color .3s ease;
}
.check.on { background: var(--accent); border-color: var(--accent); }
.check svg { width: 14px; height: 14px; stroke-width: 3; }
.title-icon { display: inline-flex; vertical-align: -2px; color: var(--text-dim); }
.title-icon svg { width: 13px; height: 13px; }
/* первый такт анимации выполнения — галочка появляется на ещё незалитом
   кружке (см. .card.just-done .check ниже для второго такта — заливки) */
.check.checking {
  color: var(--success);
  border-color: var(--success);
  animation: check-pop .3s ease;
}
@keyframes check-pop {
  0% { transform: scale(.3); opacity: 0; }
  60% { transform: scale(1.2); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}

.actions-row { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.pill-btn {
  border: none;
  background: var(--surface-2);
  color: var(--text);
  border-radius: 20px;
  padding: 7px 13px;
  font-size: 13px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 5px;
}
.pill-btn.accent { background: var(--accent); color: var(--accent-text); }
.pill-btn.danger { background: var(--danger-soft, var(--surface-2)); color: var(--danger); }
.pill-btn svg { width: 14px; height: 14px; flex: 0 0 auto; }

.empty-state {
  text-align: center;
  color: var(--text-dim);
  padding: 60px 20px;
  font-size: 14px;
}
.empty-state svg { width: 32px; height: 32px; margin-bottom: 10px; opacity: .6; }
/* Правка: .btn-primary сам по себе (за пределами .welcome-actions/
   .meeting-prep-card) не задаёт ни padding, ни border-radius, ни border —
   кнопка "Добавить первую встречу" в пустом состоянии "Моего дня"
   рендерилась обычной квадратной браузерной кнопкой */
.empty-state .btn-primary { border: none; padding: 12px 22px; border-radius: 999px; font-size: 14px; font-weight: 700; cursor: pointer; }

.today-summary-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.summary-pill {
  display: flex;
  align-items: center;
  gap: 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}
.summary-pill svg { width: 12px; height: 12px; }
.summary-pill.danger { background: var(--danger-soft, var(--surface)); color: var(--danger); border-color: transparent; }
.summary-pill.warn { background: var(--accent-soft); color: var(--dot); border-color: transparent; }

.section-label {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-dim);
  font-weight: 700;
  margin: 18px 4px 8px;
}
.section-label:first-child { margin-top: 2px; }

/* ============ "Сегодня": сворачиваемая папка просроченных задач ============ */
.overdue-folder-header {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  border: none;
  background: var(--surface);
  box-shadow: var(--shadow);
  border-radius: var(--radius);
  padding: 13px 16px;
  margin-bottom: 10px;
  text-align: left;
}
.overdue-folder-icon { flex: 0 0 auto; color: var(--danger); display: flex; }
.overdue-folder-icon svg { width: 18px; height: 18px; }
.overdue-folder-title { font-weight: 700; font-size: 15px; color: var(--danger); flex: 1; }
.overdue-folder-count {
  background: var(--danger);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  border-radius: 12px;
  padding: 2px 9px;
  flex: 0 0 auto;
}
.overdue-folder-arrow {
  color: var(--text-dim);
  flex: 0 0 auto;
  display: flex;
  transition: transform .25s ease;
}
.overdue-folder-arrow svg { width: 15px; height: 15px; }
.overdue-folder-arrow.open { transform: rotate(180deg); }
.overdue-folder-body {
  max-height: 0;
  overflow: hidden;
  transition: max-height .35s ease;
}
.overdue-folder-body.open { max-height: 4000px; }
.overdue-folder-body .card:last-child { margin-bottom: 10px; }
/* Правка по обратной связи: та же "папка", но зелёная — для панели
   "Выполнено сегодня" */
.overdue-folder-header.is-success .overdue-folder-icon,
.overdue-folder-header.is-success .overdue-folder-title { color: var(--success); }
.overdue-folder-header.is-success .overdue-folder-count { background: var(--success); }

/* ============ Мини-календарь (фильтр по дню) ============ */
.date-filter-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
}
.date-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 8px 14px;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
}
.date-pill svg { width: 14px; height: 14px; vertical-align: -2px; margin-right: 2px; color: var(--accent); }
.search-row {
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 10px 14px;
  margin-bottom: 10px;
  color: var(--text-dim);
}
.search-row svg { width: 16px; height: 16px; flex: 0 0 auto; }
/* 16px, не 14px — iOS Safari автоматически зумит страницу при фокусе
   на поле с font-size < 16px; это касается всех полей поиска
   (Контакты/Задачи/Заметки/глобальный поиск) */
.search-row input { border: none; outline: none; background: transparent; padding: 0; width: auto; flex: 1; font-size: 16px; color: var(--text); }
.search-row-clear {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px; height: 20px;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: var(--border);
  color: var(--text-dim);
  cursor: pointer;
}
.search-row-clear svg { width: 11px; height: 11px; }
/* ============ Переключатель Список/День/Неделя ============ */
.viewmode-row {
  display: flex;
  background: var(--surface-2);
  border-radius: 12px;
  padding: 3px;
  margin-bottom: 10px;
  gap: 2px;
}
.seg-btn {
  flex: 1;
  border: none;
  background: none;
  color: var(--text-dim);
  font-size: 13px;
  font-weight: 700;
  padding: 7px 0;
  border-radius: 9px;
}
.seg-btn.active { background: var(--surface); color: var(--text); box-shadow: 0 1px 2px rgba(0,0,0,.08); }

/* Экран "План на день" (TAGLINE-концепт, 06_DAY_PLAN_FULL_PHONE.png) */
.calendar-screen-header { padding: 10px 16px; gap: 6px; }
.dayplan-month-btn {
  display: flex; align-items: center; gap: 6px;
  border: none; background: none;
  font-size: 17px; font-weight: 700; color: var(--text);
  text-transform: capitalize;
  padding: 0;
}
.dayplan-month-btn svg { width: 16px; height: 16px; color: var(--text-dim); }
/* Мини-неделя — 7 дней, выбранный день залитым кружком (по кропу —
   фиолетовым, не основным синим) */
.dayplan-week-strip { display: flex; justify-content: space-between; padding: 6px 16px 14px; }
.dayplan-day {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  border: none; background: none;
  padding: 2px 6px;
  border-radius: 12px;
  color: var(--text);
}
.dayplan-day .dow { font-size: 11px; color: var(--text-dim); font-weight: 500; }
.dayplan-day .num { font-size: 14px; font-weight: 700; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.dayplan-day.is-today .num { color: var(--accent2); }
.dayplan-day.is-selected .num { background: var(--accent2); color: #fff; }
/* Outline-переключатель День/Неделя (TAGLINE) — не сплошная заливка */
.dayplan-mode-row {
  margin: 0 16px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 3px;
}
.dayplan-mode-row .seg-btn {
  color: var(--text-dim);
  font-weight: 600;
  padding: 9px 0;
  border-radius: 999px;
}
.dayplan-mode-row .seg-btn.active {
  background: var(--accent2-soft);
  color: var(--accent2);
  box-shadow: none;
  font-weight: 700;
}
/* Правка по обратной связи: раньше у этого контейнера не было overflow-y,
   из-за чего сетка недели/дня, если она выше экрана, была "заперта" —
   прокрутка работала только по горизонтали (её явно включает
   .week-grid-scroll), а вниз было вообще не докрутить */
#calendar-screen-body { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 0 16px 24px; }
/* Упрощённые строки плана дня — время + цветная чёрточка, без
   аватара/иконки/чипов (компактнее, чем "Ближайшие события") */
.dayplan-list { display: flex; flex-direction: column; }
.dayplan-row { display: flex; align-items: center; gap: 12px; padding: 13px 0; border-bottom: 1px solid var(--border); cursor: pointer; }
.dayplan-row:last-child { border-bottom: none; }
.dayplan-time { flex: 0 0 48px; font-size: 13.5px; font-weight: 700; color: var(--text); }
.dayplan-time-empty { color: var(--text-dim); font-weight: 400; }
.dayplan-bar { flex: 0 0 auto; width: 3px; height: 30px; border-radius: 2px; }
.dayplan-bar.is-meeting { background: var(--accent2); }
.dayplan-bar.is-task { background: var(--success); }
.dayplan-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.dayplan-text .title { font-size: 14px; font-weight: 700; color: var(--text); }
.dayplan-text .sub { font-size: 12px; color: var(--text-dim); }
/* День — последовательный список событий (НЕ пропорциональная сетка
   часов) с пунктирной вертикальной линией под временем — по
   02_calendar_timeline.jpg; геометрия "высота блока ~ длительность"
   в кропе отсутствует, события просто идут друг за другом по времени */
.cal-day-list { display: flex; flex-direction: column; }
.cal-day-item { display: flex; gap: 12px; padding-bottom: 18px; position: relative; }
.cal-day-time { flex: 0 0 42px; display: flex; flex-direction: column; align-items: flex-start; gap: 3px; }
.cal-day-time .t { font-size: 13.5px; font-weight: 700; color: var(--text); }
.cal-day-dotline {
  flex: 1;
  width: 2px;
  margin-left: 3px;
  border-left: 2px dotted var(--border);
  min-height: 24px;
}
.cal-day-item:last-child .cal-day-dotline { border-left-color: transparent; }
.cal-day-lead { flex: 0 0 auto; width: 36px; height: 36px; }
.cal-day-lead .avatar-circle { width: 36px; height: 36px; font-size: 13px; }
.cal-day-ico { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--success-soft); color: var(--success); }
.cal-day-ico svg { width: 18px; height: 18px; }
.cal-day-main { flex: 1; min-width: 0; }
.cal-day-title { font-size: 14.5px; font-weight: 700; color: var(--text); }
.cal-day-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 1px; }
.cal-day-chevron { flex: 0 0 auto; color: var(--text-dim); align-self: flex-start; margin-top: 2px; }
.cal-day-chevron svg { width: 16px; height: 16px; }
.cal-notime-card {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px;
  border: none;
  border-radius: var(--radius);
  background: var(--success-soft);
  text-align: left;
  cursor: pointer;
  margin-top: 4px;
}
.cal-notime-card .body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cal-notime-card .title { font-size: 14.5px; font-weight: 700; color: var(--text); }
.cal-notime-card .sub { font-size: 12.5px; color: var(--text-dim); }
.cal-notime-card .count { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%; background: var(--success); color: #fff; font-size: 11px; font-weight: 700; display: flex; align-items: center; justify-content: center; }
.cal-notime-card .chev { flex: 0 0 auto; color: var(--text-dim); }

/* ============ Расписание (сетка по времени) ============ */
.schedule-wrap { margin-bottom: 18px; }
/* Список одна-под-другой — раньше были flex-wrap пилюли, которые у коротких
   названий сбивались в "кучу" в один ряд; теперь всегда по одной в строку,
   первая сверху, вторая под ней и так далее */
.untimed-row { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.untimed-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface-2);
  border-radius: 10px;
  padding: 9px 12px;
  font-size: 13.5px;
  font-weight: 600;
}
.untimed-chip-title { flex: 1; position: relative; }
.day-grid {
  position: relative;
  border-top: 1px solid var(--border);
  margin-top: 6px;
}
.hour-row {
  position: absolute;
  left: 0; right: 0; height: 0;
  border-top: 1px solid var(--border);
}
.hour-label {
  position: absolute;
  left: 0; top: -8px;
  font-size: 11px;
  color: var(--text-dim);
  background: var(--bg);
  padding-right: 6px;
  font-variant-numeric: tabular-nums;
}
.task-block {
  position: absolute;
  left: 50px; right: 6px;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  border-radius: 8px;
  padding: 4px 8px;
  overflow: hidden;
  z-index: 2;
}
.task-block.overdue { border-left-color: var(--danger); background: rgba(192, 80, 58, 0.22); }
.task-block.overdue .task-block-time { color: var(--danger); }

/* ============ Линия "сейчас" и заштрихованное прошедшее время ============ */
.now-hatch {
  position: absolute;
  left: 0; right: 0; top: 0;
  background: repeating-linear-gradient(
    45deg,
    rgba(90, 160, 220, 0.16), rgba(90, 160, 220, 0.16) 6px,
    rgba(90, 160, 220, 0.05) 6px, rgba(90, 160, 220, 0.05) 12px
  );
  pointer-events: none;
  z-index: 0;
}
.now-line {
  position: absolute;
  left: 50px; right: 0;
  height: 2px;
  background: #3B82F6;
  z-index: 1;
  pointer-events: none;
}
.now-line::before {
  content: '';
  position: absolute;
  left: -4px; top: -3px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: #3B82F6;
}

.note-card-clamp {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.task-block-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.task-block-time { font-size: 11px; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.task-block-title { font-size: 13px; font-weight: 600; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
.block-actions { display: flex; gap: 6px; flex: 0 0 auto; }
/* внутри маленького блока расписания пилюли слишком громоздкие — просто иконка */
.block-actions .pill-btn { background: none; padding: 0; border-radius: 0; font-size: 14px; line-height: 1; }

/* ============ Расписание (неделя) ============ */
/* touch-action: pan-x pan-y — явно разрешаем обе оси (а не оставляем
   auto), иначе на iOS, когда палец стоит в прокрученной вбок части
   недели, вертикальный свайп («полистать по времени вниз/вверх»)
   иногда не передаётся странице-предку и просто ничего не делает */
/* -webkit-overflow-scrolling: touch — старое ускорение инерции для
   overflow-x — в связке с вложенным вертикальным скроллом страницы иногда
   частично "перехватывает" вертикальный свайп (обрывает его на середине),
   именно это и было нужно убрать; touch-action: pan-x pan-y остаётся как
   явное разрешение на обе оси */
.week-grid-scroll { overflow-x: auto; margin-top: 6px; touch-action: pan-x pan-y; }
.week-grid {
  position: relative;
  display: flex;
  border-top: 1px solid var(--border);
  min-width: 100%;
}
.week-col {
  position: relative;
  flex: 1 0 74px;
  min-width: 74px;
  border-right: 1px solid var(--border);
}
.week-col-labels {
  flex: 0 0 40px;
  min-width: 40px;
  position: sticky;
  left: 0;
  z-index: 3;
  background: var(--bg);
}
.week-col-header {
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-dim);
  position: sticky;
  top: 0;
  background: var(--bg);
}
.week-col-header.is-today { color: var(--accent); }
.week-block {
  position: absolute;
  left: 3px; right: 3px;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  padding: 2px 5px;
  overflow: hidden;
}
.week-block .task-block-title { font-size: 10.5px; }
/* горизонтальные полоски часов внутри КАЖДОЙ колонки дня — те же top-смещения,
   что и в колонке меток слева, так что визуально линия идёт через всю
   ширину недели, а не только под подписями времени */
.hour-row-line {
  position: absolute;
  left: 0; right: 0; height: 0;
  border-top: 1px solid var(--border);
}

/* ============ Неделя: переключатель Сетка / Вся неделя (обзор) ============ */
.week-nav-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.week-nav-row .pill-btn { flex: 0 0 auto; width: 38px; justify-content: center; font-size: 18px; font-weight: 700; padding: 7px 0; }
.week-nav-label { flex: 1; text-align: center; font-size: 13.5px; font-weight: 700; }
.week-nav-label small { font-weight: 600; color: var(--text-dim); }
.week-mode-row { display: flex; gap: 8px; margin-bottom: 10px; }
.week-mode-row .pill-btn { flex: 1; text-align: center; }

/* ============ Месяц (Этап 6 ТЗ) ============ */
.month-grid-head {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  /* Правка по обратной связи: у .month-grid (ячейки дней) ниже есть
     gap:4px между колонками, а здесь, в шапке с буквами дней недели,
     gap не было вообще — из-за этого колонки держались разной ширины,
     и буквы постепенно "съезжали" относительно ячеек к концу строки */
  gap: 4px;
  text-align: center;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-dim);
  margin-bottom: 6px;
}
.month-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.month-day {
  aspect-ratio: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border: none;
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  cursor: pointer;
}
.month-day.is-outside { opacity: .35; }
.month-day.is-today { background: var(--accent-soft); }
.month-day.is-today .month-day-num { color: var(--accent); font-weight: 800; }
.month-day-num { font-size: 13px; font-weight: 600; }
.month-day-dots { display: flex; gap: 2px; height: 5px; }
.month-dot { width: 5px; height: 5px; border-radius: 999px; }
.month-dot.c-accent-dot { background: var(--accent); }
.month-dot.c-success-dot { background: var(--success); }

/* ============ Неделя: компактный обзор на весь экран без скролла по времени ============ */
.week-overview { display: flex; flex-direction: column; gap: 10px; }
.week-overview-day {
  display: flex;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.week-overview-day:last-child { border-bottom: none; }
.week-overview-daylabel {
  flex: 0 0 46px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-dim);
  padding-top: 2px;
}
.week-overview-daylabel.is-today { color: var(--accent); }
.week-overview-tasks { flex: 1; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.week-overview-empty { color: var(--text-dim); font-size: 13px; }
.week-overview-task {
  display: flex;
  align-items: baseline;
  gap: 7px;
  font-size: 13px;
  padding: 3px 7px;
  background: var(--accent-soft);
  border-radius: 7px;
  overflow: hidden;
}
.week-overview-time { font-size: 11px; font-weight: 700; color: var(--accent); font-variant-numeric: tabular-nums; flex: 0 0 auto; }
.week-overview-title { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }

/* ============ Фильтр-чипы ============ */
.chip-row {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 2px 2px 10px;
  margin: 0 -2px;
}
.chip {
  flex: 0 0 auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim);
  white-space: nowrap;
}
.chip.active { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
.chip svg { width: 12px; height: 12px; vertical-align: -1px; margin-right: 1px; }

/* ============ Нижний таббар — плавающая "pill"-панель ============ */
nav.tabbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-around;
  gap: 2px;
  margin: 0 16px calc(14px + var(--safe-bottom));
  padding: 6px;
  background: var(--tab-bg);
  backdrop-filter: blur(14px);
  border-radius: 22px;
  box-shadow: 0 10px 24px rgba(33, 31, 28, 0.12);
  position: relative;
  z-index: 20;
}
nav.tabbar button {
  flex: 1;
  background: none;
  border: none;
  padding: 9px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  color: var(--text-dim);
  font-size: 10px;
  font-weight: 700;
  border-radius: 14px;
  transition: background .15s ease, color .15s ease;
}
nav.tabbar button .ico { width: 20px; height: 20px; }
/* По reference_screens/01_home_screen.jpg активный пункт — просто
   синий цвет иконки/подписи, БЕЗ подсвеченной пилюли-фона позади
   кнопки (раньше была); сама иконка в кропе залита сплошным синим
   цветом — здесь упрощено до однотонной обводки того же синего
   (currentColor), двухцветный "иконка-как-лого" вид не воспроизводим
   без растрового/двухцветного SVG-ассета — зафиксировано как E */
nav.tabbar button.active { color: var(--accent); font-weight: 700; }
nav.tabbar button.active .ico { fill: var(--accent-soft); }

/* ============ Плавающая кнопка добавить ============ */
.fab {
  position: fixed;
  right: 18px;
  bottom: calc(88px + var(--safe-bottom));
  width: 56px; height: 56px;
  border-radius: 50%;
  /* TAGLINE-концепт: измерено (01_HOME_MY_DAY_FULL_PHONE.png, FAB
     ≈#6354FB) — ближе к --accent2 (фиолетовый), не к основному синему
     --accent, как было в предыдущем концепте */
  background: var(--accent2);
  color: var(--accent-text);
  border: none;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
  z-index: 20;
}
.fab svg { width: 46%; height: 46%; }

/* ============ Голосовой ИИ-ассистент ============ */
.fab-voice {
  right: 86px;
  width: 48px; height: 48px;
  background: var(--accent);
}
#voice-command-mic-toggle.listening {
  background: var(--danger);
  animation: voice-mic-pulse 1.1s ease-in-out infinite;
}
@keyframes voice-mic-pulse { 0%,100% { opacity: 1; } 50% { opacity: .7; } }
.fab-voice svg { width: 50%; height: 50%; }

/* ============ Заглушка до определения статуса входа ============ */
#boot-cover {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--accent);
}
#boot-cover svg { width: 44px; height: 44px; animation: boot-pulse 1.4s ease-in-out infinite; }
@keyframes boot-pulse { 0%, 100% { opacity: .55; } 50% { opacity: 1; } }

/* ============ Полноэкранный экран входа ============ */
/* ============ Токены ТЗ "DayMe — Welcome/Login/Registration" ============
   Намеренно ОТДЕЛЬНЫЙ набор переменных, не переопределяющий глобальные
   --accent/--text/--bg и т.п. — те красят кнопки/иконки по всему
   приложению (задачи, контакты, всё остальное), а в ТЗ просили
   переоформить только экраны входа/регистрации/почты/восстановления,
   не весь интерфейс целиком. Скоуп — на .auth-screen, под него попадают
   все пять экранов (welcome/вход-регистрация/подтверждение/
   восстановление), .welcome-screen наследует те же переменные отдельно
   на случай, если когда-то перестанет быть одним классом с .auth-screen */
.auth-screen, .welcome-screen {
  --auth-accent: #5B5FEF;
  --auth-accent2: #8B5CF6;
  --auth-bg: #F5F6FB;
  --auth-surface: #FFFFFF;
  --auth-text: #172033;
  --auth-text-secondary: #6B7280;
  --auth-border: #E6E9F2;
  --auth-success: #168A58;
  --auth-danger: #D92D45;
  --auth-focus: rgba(91,95,239,.20);
  --auth-shadow-card: 0 12px 36px rgba(26,36,75,.08);
  --auth-shadow-btn: 0 10px 22px rgba(91,95,239,.26);
}
.auth-screen {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: calc(32px + var(--safe-top)) 28px calc(28px + var(--safe-bottom));
  background:
    radial-gradient(circle at 50% 0%, rgba(91,95,239,.08), transparent 60%),
    var(--auth-bg);
  overflow-y: auto;
}
.auth-screen.show { display: flex; }
.auth-content {
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  margin: auto;
}
.auth-title {
  font-size: 28px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin: 0 0 8px;
  color: var(--auth-text);
}
.auth-tagline {
  font-size: 15px;
  color: var(--auth-text-secondary);
  line-height: 1.5;
  margin: 0 0 40px;
}
.auth-form { width: 100%; text-align: left; }
.modal-actions.stack { flex-direction: column; }
.auth-switch-link {
  display: block;
  width: 100%;
  margin-top: 12px;
  background: none;
  border: none;
  color: var(--auth-accent);
  font-size: 13.5px;
  font-weight: 700;
  text-align: center;
}
.auth-skip-link {
  margin-top: 22px;
  background: none;
  border: none;
  color: var(--auth-text-secondary);
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ============ Логотип-wordmark "dayme" ============ */
/* Точная транскрипция присланного макета — ничего не округлено и не
   "улучшено от себя". Два разных размера, т.к. в макете Welcome и
   Login используют разный font-size для одного и того же wordmark */
.dm-wordmark { font-weight: 800; letter-spacing: -0.01em; font-size: 26px; line-height: 1.1; }
.dm-wordmark .dm-dim { color: var(--auth-text-secondary); }
.dm-wordmark .dm-bright { color: var(--auth-accent); }
.dm-wordmark-light .dm-dim { color: rgba(255,255,255,.65); }
.dm-wordmark-light .dm-bright { color: #fff; }

/* ============ Экран приветствия (Welcome) ============ */
.welcome-screen, .auth-screen-flat {
  padding: 0;
  align-items: stretch;
  justify-content: flex-start;
  background: var(--auth-bg);
  /* Плоская компоновка (не hero+sheet внахлёст) — весь экран может
     спокойно скроллиться целиком, если контент не помещается
     (маленький экран/открытая клавиатура, ТЗ раздел "Адаптивность") */
  overflow-y: auto;
  /* ВАЖНО: раньше здесь была ещё height: var(--real-vh) — реальная
     высота вьюпорта, измеренная в JS через visualViewport.height.
     Баг: visualViewport.height специально УМЕНЬШАЕТСЯ, когда открывается
     клавиатура (это и есть его смысл) — экран входа послушно сжимался
     вслед за ним и оставался прижат к верху, а в образовавшуюся щель
     снизу (между новым, уменьшенным низом экрана входа и клавиатурой)
     проглядывал настоящий интерфейс приложения, лежащий ПОД этим
     полноэкранным оверлеем. Этому экрану, в отличие от редактора заметок,
     не нужно подстраиваться под клавиатуру — он должен просто сплошно
     закрывать собой всё, независимо от того, открыта клавиатура или нет.
     Простое 100dvh этого не делает (не уменьшается при клавиатуре) — то,
     что и нужно */
  height: 100vh;
  height: 100dvh;
}
.auth-top { padding: calc(20px + var(--safe-top)) 24px 0; position: relative; }
.auth-top .welcome-back { top: 0; }
.auth-top .dm-wordmark { display: flex; margin: 44px 0 20px; }
.auth-top .auth-title { margin: 0; }
.auth-top .auth-tagline { margin: 6px 0 0; }
.auth-sheet-flat {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 22px 24px calc(20px + var(--safe-bottom));
  box-sizing: border-box;
}
.auth-sheet-flat .auth-form { gap: 12px; flex: none; }
.auth-sheet-flat > .auth-skip-link { text-align: center; margin-top: auto; }
/* Поле "Имя" в регистрации — подписанное поле (ярлык внутри, над
   текстом), как email/пароль в регистрации по макету */
.field-labeled { align-items: flex-start !important; padding: 9px 14px !important; min-height: 0 !important; }
.field-labeled svg { margin-top: 13px; }
.field-labeled-col { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.field-labeled-col label { font-size: 10.5px; color: var(--auth-text-secondary); font-weight: 600; }
.field-labeled-col label i { font-weight: 400; font-style: normal; }
.field-labeled-col input { font-size: 14.5px; margin-top: 1px; }
/* Иллюстрации на экранах подтверждения почты/восстановления пароля */
.auth-illustration {
  width: 100px; height: 100px; border-radius: 999px; flex: 0 0 auto;
  background: linear-gradient(135deg,#EDEEFC,#F2ECFC);
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 20px;
}
.auth-illustration svg { width: 44px; height: 44px; }
.auth-illustration.envelope { width: 112px; height: 112px; }
.auth-illustration.envelope svg { width: 52px; height: 52px; }
.verify-email-pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--auth-bg); border-radius: 12px; padding: 10px 14px;
  font-size: 13.5px; font-weight: 700; color: var(--auth-text);
  max-width: 100%;
}
.verify-email-pill svg { width: 15px; height: 15px; color: var(--auth-text-secondary); flex: 0 0 auto; }
.verify-email-pill span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.verify-info-box {
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--auth-bg); border-radius: 14px; padding: 14px;
  margin-top: 14px; text-align: left;
}
.verify-info-box svg { width: 16px; height: 16px; color: var(--auth-accent); flex: 0 0 auto; margin-top: 1px; }
.verify-info-box div { font-size: 12px; line-height: 1.5; color: var(--auth-text-secondary); }
.verify-info-box b { color: var(--auth-text); }
/* Правка: плоский светлый фон вместо цветного блока-героя, по
   финальному макету (DayMe_AUTH_FULL_TZ_WITH_SCREENSHOTS) */
.welcome-top { padding: calc(26px + var(--safe-top)) 24px 0; }
.welcome-headline {
  margin: 20px 0 0;
  font-size: 31px;
  font-weight: 800;
  line-height: 1.14;
  letter-spacing: -0.02em;
  color: var(--auth-text);
}
.welcome-lede { margin: 12px 0 0; font-size: 14.5px; font-weight: 700; color: var(--auth-text); }
.welcome-sub { margin: 6px 0 0; font-size: 13px; line-height: 1.5; color: var(--auth-text-secondary); max-width: 300px; }
/* Плавающая композиция: 3 чипа-сущности (Контакты/Задачи/Заметки —
   по ТЗ все три обязательны) + карточка "Мой день" + карточка
   "Важное дело" + точки-индикатор, по центру (было в углу) */
.welcome-float { flex: 1; position: relative; margin: 14px 20px 0; min-height: 250px; }
.welcome-chip {
  position: absolute;
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--auth-surface);
  box-shadow: 0 6px 16px rgba(23,32,51,.08);
  color: var(--auth-accent);
  font-size: 11px; font-weight: 700;
  border-radius: 999px;
  padding: 7px 12px 7px 9px;
}
.welcome-chip.accent2 { color: var(--auth-accent2); }
.welcome-chip svg { width: 13px; height: 13px; }
.welcome-day-card {
  position: absolute; left: 0; right: 0; top: 34px;
  background: var(--auth-surface);
  border-radius: 20px;
  box-shadow: 0 20px 44px rgba(23,32,51,.14);
  padding: 16px 16px 14px;
}
.welcome-day-card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 11px; font-size: 14px; font-weight: 800; color: var(--auth-text); }
.welcome-day-card-head svg { width: 14px; height: 14px; color: var(--auth-text-secondary); }
.welcome-day-row { display: flex; align-items: center; gap: 9px; margin-top: 10px; }
.welcome-day-row:first-of-type { margin-top: 0; }
.welcome-day-row div { font-size: 12px; font-weight: 700; color: var(--auth-text); }
.welcome-day-row small { display: block; font-weight: 500; color: var(--auth-text-secondary); font-size: 10.5px; margin-top: 1px; }
.welcome-day-ico {
  width: 22px; height: 22px; border-radius: 7px; flex: 0 0 auto;
  background: var(--auth-focus); color: var(--auth-accent);
  display: flex; align-items: center; justify-content: center;
}
.welcome-day-ico.accent2 { color: var(--auth-accent2); }
.welcome-day-ico svg { width: 12px; height: 12px; }
.welcome-important-card {
  position: absolute; left: 0; right: 0; top: 196px;
  background: var(--auth-surface);
  border-radius: 18px;
  box-shadow: 0 16px 34px rgba(23,32,51,.12);
  padding: 13px 15px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.welcome-important-lead { display: flex; align-items: center; gap: 9px; min-width: 0; }
.welcome-important-lead small { display: block; font-size: 11px; font-weight: 500; color: var(--auth-text-secondary); }
.welcome-important-lead div { font-size: 12.5px; font-weight: 700; color: var(--auth-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.welcome-important-box { width: 22px; height: 22px; border-radius: 7px; border: 2px solid var(--auth-accent); flex: 0 0 auto; }
.welcome-important-avatars { display: flex; align-items: center; flex: 0 0 auto; }
.welcome-important-avatars span {
  width: 24px; height: 24px; border-radius: 999px; border: 2px solid #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: 9px; color: #fff; font-weight: 700; margin-left: -8px;
}
.welcome-important-avatars span:first-child { margin-left: 0; }
.welcome-important-avatars span.is-accent { background: var(--auth-accent); }
.welcome-dots { position: absolute; left: 50%; transform: translateX(-50%); bottom: 2px; display: flex; gap: 6px; }
.welcome-dots span { width: 6px; height: 6px; border-radius: 999px; background: #D8DAEC; }
.welcome-dots span.is-active { width: 16px; background: var(--auth-accent); }
.welcome-footnote { display: flex; align-items: center; justify-content: center; gap: 6px; margin-top: 2px; color: var(--auth-text-secondary); font-size: 12px; font-weight: 600; }
.welcome-footnote svg { width: 13px; height: 13px; }
.welcome-back {
  position: absolute;
  /* 24px буквально из макета — но макет плоский, без выреза; на реальном
     айфоне без добавки safe-area кружок утыкался прямо под чёлку/часы и
     был "не на своём месте". Это ровно тот случай, где поверх точного
     значения нужно добавить отступ под вырез, а не заменять его */
  top: calc(24px + var(--safe-top));
  left: 20px;
  width: 36px; height: 36px;
  border-radius: 999px;
  background: #fff;
  color: var(--auth-text);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 6px rgba(23,32,51,.08);
}
.welcome-back svg { width: 16px; height: 16px; }
/* Правка по ТЗ: раньше была одна кнопка "Войти или создать аккаунт" +
   текстовая ссылка "Продолжить без аккаунта" — ТЗ прямо просит ДВЕ
   содержательные кнопки (Создать аккаунт / У меня уже есть аккаунт),
   ведущие на один и тот же экран входа-регистрации, но в разном режиме
   (см. welcome-login/welcome-signup в js/firebase-sync.js) */
.welcome-actions { display: flex; flex-direction: column; gap: 12px; align-items: center; }
.welcome-actions .btn-primary,
.welcome-actions .btn-secondary-auth {
  width: 100%; box-sizing: border-box; min-height: 50px; padding: 0 16px;
  border-radius: 14px; font-size: 15.5px; font-weight: 700; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.welcome-actions .btn-primary { border: none; box-shadow: var(--auth-shadow-btn); }
.btn-secondary-auth {
  background: #fff;
  color: var(--auth-accent);
  border: 1.5px solid var(--auth-accent);
}
.welcome-actions .auth-skip-link { margin: 2px 0 0; color: var(--auth-text-secondary); font-size: 13px; font-weight: 600; text-decoration: none; padding: 4px; }
.welcome-fineprint { font-size: 11px; color: var(--auth-text-secondary); text-align: center; line-height: 1.5; }

/* ============ Онбординг (Задача 6, docs/RELEASE_1NOV.md) ============
   .auth-top/.auth-sheet-flat/.auth-illustration/.verify-info-box —
   переиспользованы как есть (см. #modal-auth/#modal-verify выше), ниже
   — только то, чего раньше не было: шаги-панели, точки прогресса,
   список выбора "чем вы занимаетесь" */
.onboarding-step { display: none; flex-direction: column; flex: 1; text-align: center; align-items: center; }
.onboarding-step.is-active { display: flex; }
.onboarding-step .auth-title { margin-top: 4px; }
.onboarding-step .modal-actions.stack { width: 100%; margin-top: auto; }
.onboarding-step .verify-info-box { width: 100%; box-sizing: border-box; text-align: left; margin-bottom: 10px; }
.onboarding-dots { display: flex; gap: 6px; justify-content: center; margin-top: 44px; }
.onboarding-dots span { width: 6px; height: 6px; border-radius: 999px; background: #D8DAEC; }
.onboarding-dots span.is-active { width: 16px; background: var(--auth-accent); }
.onboarding-skip-all { position: absolute; right: 20px; top: calc(20px + var(--safe-top)); margin: 0; }
.onboarding-choice-list { display: flex; flex-direction: column; gap: 10px; width: 100%; margin-top: 8px; }
.onboarding-choice {
  width: 100%; box-sizing: border-box; min-height: 50px; padding: 0 16px;
  border-radius: 14px; font-size: 14.5px; font-weight: 700; cursor: pointer;
  background: var(--auth-surface); color: var(--auth-text);
  border: 1.5px solid var(--auth-border); text-align: left;
}
.onboarding-choice.is-selected { border-color: var(--auth-accent); color: var(--auth-accent); }

/* ============ Экран входа (Login) ============ */
.auth-form { display: flex; flex-direction: column; gap: 12px; }
.auth-form .modal-actions.stack { margin-top: 0; }
.auth-form #auth-submit {
  margin-top: 8px; border-radius: 14px; min-height: 50px; padding: 0 15px;
  box-shadow: var(--auth-shadow-btn);
  display: flex; align-items: center; justify-content: center; gap: 8px;
}
.field-icon-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--auth-surface);
  border: 1px solid var(--auth-border);
  border-radius: 14px;
  min-height: 50px;
  padding: 0 14px;
  box-sizing: border-box;
  color: var(--auth-text-secondary);
  transition: border-color .15s, box-shadow .15s;
}
/* ТЗ раздел 10: Focus — border accent + кольцо 3px rgba(...,.20) */
.field-icon-row:focus-within {
  border-color: var(--auth-accent);
  box-shadow: 0 0 0 3px var(--auth-focus);
}
.field-icon-row.has-error { border-color: var(--auth-danger); }
.field-icon-row svg { width: 18px; height: 18px; flex: 0 0 auto; }
/* 16px, не 14.5px как в макете — тот же случай переноса на реальное
   устройство, что и safe-area: iOS Safari зумит страницу при фокусе на
   поле мельче 16px, в плоском макете этого эффекта не видно */
.field-icon-row input { border: none; outline: none; background: transparent; padding: 0; width: auto; flex: 1; font-size: 16px; color: var(--auth-text); min-width: 0; }
.field-icon-row input::placeholder { color: var(--auth-text-secondary); }
/* Правка по ТЗ: "у пароля переключатель показать/скрыть" — раньше не
   было вообще. Кнопка-глаз внутри той же field-icon-row, справа от поля */
.field-toggle-visibility {
  flex: 0 0 auto;
  background: none; border: none; padding: 4px;
  color: var(--auth-text-secondary);
  display: flex; align-items: center; justify-content: center;
  min-width: 28px; min-height: 28px;
}
.field-toggle-visibility svg { width: 18px; height: 18px; }
.auth-switch-link { color: var(--auth-accent); font-size: 13.5px; font-weight: 600; padding: 6px; }
.auth-sheet-flat .auth-skip-link { color: var(--auth-text-secondary); font-size: 13px; font-weight: 600; text-decoration: none; padding: 8px; margin: 0; }
/* Правка по ТЗ: ссылка "Забыли пароль?" — раньше вообще не было пути
   восстановления пароля на экране входа */
.auth-forgot-link {
  align-self: flex-end;
  background: none; border: none; padding: 2px 4px;
  color: var(--auth-accent); font-size: 13px; font-weight: 600;
  margin-top: -4px;
}
/* ТЗ раздел 10: "Loading: spinner + ...". Простой вращающийся кольцевой
   спиннер, без новых библиотек/анимационных зависимостей */
.auth-spinner {
  width: 16px; height: 16px; border-radius: 999px;
  border: 2px solid rgba(255,255,255,.45);
  border-top-color: #fff;
  animation: auth-spin .7s linear infinite;
  flex: 0 0 auto;
}
@keyframes auth-spin { to { transform: rotate(360deg); } }
/* ТЗ раздел 10 + правки (п.4, P1): Error — border + текст 12-13px под
   полем. Место под текст зарезервировано ВСЕГДА (min-height), а не
   display:none/block по появлению — иначе кнопка и всё, что ниже,
   прыгает вверх-вниз при каждом показе/скрытии ошибки ("резкие скачки
   макета" из п.4 ТЗ на исправления) */
.auth-field-error {
  color: var(--auth-danger);
  font-size: 12.5px;
  line-height: 1.4;
  margin: -6px 0 0;
  /* 12.5px * 1.4 = 17.5px — высота должна ТОЧНО совпадать с реальной
     высотой строки текста, иначе остаётся 1-2px сдвиг при появлении
     ошибки (min-height меньше фактической высоты строки) */
  height: 17.5px;
  overflow: hidden;
  visibility: hidden;
}
.auth-field-error.is-shown { visibility: visible; }
/* Подсказка про перенос с Firebase (docs/cutover.md) — многострочная,
   без фиксированной высоты .auth-field-error (та рассчитана строго на
   одну строку текста ошибки и обрезала бы более длинный текст) */
.auth-migration-hint {
  color: var(--auth-text-secondary);
  font-size: 12.5px;
  line-height: 1.4;
  margin: 2px 0 0;
}

/* ============ Полноэкранный редактор заметки ============ */
.note-editor {
  position: fixed;
  inset: 0;
  /* Две попытки подгонять высоту под клавиатуру через JS (сначала общая
     --real-vh, потом свой локальный пересчёт) обе ломали экран на
     реальном iPhone — обрезался, показывал список заметок под собой.
     Без доступа к реальному устройству чинить это втемную дальше
     рискованно. Здесь — простой и стабильный вариант: редактор ВСЕГДА
     на весь экран, высота никогда не трогается из JS */
  z-index: 100;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  padding-top: var(--safe-top);
  padding-bottom: var(--safe-bottom);
  transform: translateY(100%);
  opacity: 0;
  pointer-events: none;
  transition: transform .3s cubic-bezier(0.22, 1, 0.36, 1), opacity .2s ease;
}
.note-editor.show { transform: translateY(0); opacity: 1; pointer-events: auto; }

/* ============ Универсальный поиск (Этап 3 ТЗ) ============ */
.search-screen {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  padding-top: var(--safe-top);
  padding-bottom: var(--safe-bottom);
  transform: translateY(16px);
  opacity: 0;
  pointer-events: none;
  /* Правка по обратной связи ("движения — плавнее") — та же кривая, что
     уже используется для редактора заметки, вместо резкого linear/ease */
  transition: transform .28s cubic-bezier(0.22, 1, 0.36, 1), opacity .2s ease;
}
.search-screen.show { transform: translateY(0); opacity: 1; pointer-events: auto; }
/* Правка по обратной связи: при свайпе вправо экран уезжает вправо
   (куда провели пальцем), а не исчезает обычной вертикальной анимацией
   закрытия — см. triggerSwipeBack() в app.js */
.search-screen.swipe-exit-right { transition: transform .3s cubic-bezier(0.22, 1, 0.36, 1) !important; transform: translateX(100%) !important; }
/* "План на день" (TAGLINE-концепт) — таббар должен остаться виден под
   оверлеем (в отличие от остальных .search-screen) — не на весь экран,
   оставляем снизу место под плавающий таббар + его отступ.
   Правка по обратной связи: сверху тоже оставлен отступ — карточкой,
   не во весь экран — чтобы было видно (через размытый .calendar-backdrop)
   что это именно оверлей поверх прежнего экрана, а не переход на новую
   вкладку; скруглённый верх + тень усиливают ощущение "карточки сверху" */
.search-screen-with-tabbar {
  bottom: calc(78px + var(--safe-bottom));
  inset: 0 0 auto 0;
  top: calc(var(--safe-top) + 54px);
  /* Явная height вместо того, чтобы полагаться на автоматическое
     вычисление из top+bottom — в Safari это сочетание (position:fixed +
     display:flex + top/bottom) на практике давало высоту БОЛЬШЕ
     доступной (росла под контент), из-за чего #calendar-screen-body
     ниже никогда не получал реального переполнения и не скроллился */
  height: calc(100% - calc(var(--safe-top) + 54px) - calc(78px + var(--safe-bottom)));
  /* карточка уже начинается ниже чёлки/статус-бара сама по себе —
     второй раз safe-top внутри (унаследованный padding-top из
     .search-screen) создавал бы лишний пустой зазор над её шапкой */
  padding-top: 0;
  /* Правка по обратной связи: скругление теперь и снизу, не только
     сверху — карточка выглядит одинаково со всех сторон, не прилипает
     плоским нижним краем к таббару */
  border-radius: 22px;
  box-shadow: 0 10px 34px rgba(20, 33, 61, 0.18);
  overflow: hidden;
}
/* Затемнённый и размытый фон позади календаря — сам клик по нему
   закрывает календарь (см. #calendar-backdrop в app.js) */
.calendar-backdrop {
  position: fixed;
  inset: 0;
  z-index: 109;
  background: rgba(10, 14, 30, .32);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  pointer-events: none;
  transition: opacity .25s ease;
}
.calendar-backdrop.show { opacity: 1; pointer-events: auto; }
.search-screen-header {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px 10px;
  flex: 0 0 auto;
}
.search-screen-header-tagline { justify-content: space-between; }
/* Outline-пилюли поиска (TAGLINE-концепт, 05_SEARCH_FULL_PHONE.png) —
   активная "Все" синей ОБВОДКОЙ, не сплошной заливкой, как в общем
   .chip.active по умолчанию */
.search-type-row-outline .chip { background: var(--surface); }
.search-type-row-outline .chip.active { background: var(--surface); color: var(--accent); border-color: var(--accent); border-width: 1.5px; }
/* Правка по обратной связи: плашки "Все/Контакты/Заметки/Задачи" в
   поиске стояли у самого края экрана — .chip-row компенсирует свой
   внутренний padding отрицательным margin (это нужно, чтобы первая и
   последняя плашка не обрезались тенью/рамкой при горизонтальной
   прокрутке), но здесь из-за этого ряд уезжал левее строки поиска
   (у неё 16px отступ). Выравниваем именно по ней */
#global-search-type-row { margin-left: 14px; margin-right: 14px; }
#global-search-results { flex: 1; overflow-y: auto; padding: 0 16px 24px; -webkit-overflow-scrolling: touch; }
.search-results-group + .search-results-group { margin-top: 18px; }
/* Плоский список — по 07_search.jpg нет карточки-подложки/тени на
   каждой строке, просто щедрые отступы между строками */
.search-result-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 2px;
  background: none;
  box-shadow: none;
  margin-bottom: 4px;
  text-align: left;
  width: 100%;
  border: none;
  cursor: pointer;
  color: var(--text);
}
.search-result-icon {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.search-result-icon svg { width: 19px; height: 19px; }
/* Нейтральные бейджи заметки/задачи (TAGLINE-концепт) — не цветные
   круги, а сдержанные квадраты: заметка — тёплый кремовый, задача —
   светлая с тонкой обводкой */
.search-result-icon-neutral {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface);
  border: 1.5px solid var(--border);
  color: var(--text);
}
.search-result-icon-neutral.is-note { background: var(--dot-soft); border-color: transparent; color: var(--dot); }
.search-result-icon-neutral svg { width: 18px; height: 18px; }
.search-result-type { font-size: 13px; font-weight: 700; color: var(--text); }
.search-result-detail { font-size: 12.5px; color: var(--text-dim); margin-top: 3px; line-height: 1.4; }
.search-result-date { flex: 0 0 auto; font-size: 11px; color: var(--text-dim); padding-top: 2px; }
.search-result-text { flex: 1; min-width: 0; padding-top: 2px; }
.search-result-title { font-weight: 700; font-size: 14.5px; }
.search-result-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.search-result-chip { margin-top: 6px; }
.search-result-mini-row { display: flex; gap: 6px; margin-top: 8px; }
.search-result-mini {
  width: 24px; height: 24px;
  border-radius: 50%;
  background: var(--surface-2);
  color: var(--text-dim);
  display: flex; align-items: center; justify-content: center;
  border: none;
}
.search-result-mini svg { width: 12px; height: 12px; }
.search-result-chevron { flex: 0 0 auto; color: var(--text-dim); align-self: center; }
.search-result-chevron svg { width: 16px; height: 16px; }

/* ============ Сводка дня — 4 пастельные карточки (Этап 3 ТЗ) ============ */
/* Постоянная поисковая плашка под заголовком на "Моём дне" — в макете
   это отдельный, всегда видимый элемент (не то же самое, что иконка
   поиска в шапке, которая открывает тот же оверлей) — замер
   IMG_3830 ~515×185: фон #EDF2FB, скруглённая пилюля */
.today-search-trigger {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 13px 16px;
  margin-bottom: 14px;
  border: none;
  border-radius: 999px;
  background: var(--search-bar-bg, var(--surface-2));
  color: var(--text-dim);
  font-size: 14px;
  text-align: left;
}
.today-search-trigger svg { width: 18px; height: 18px; flex-shrink: 0; }
/* Карточка "Сегодня" — обзорная плашка над сводкой дня, по
   reference_screens/01_home_screen.jpg (п.4 карта экрана A); раньше
   отсутствовала полностью */
.today-overview-card {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 14px 16px;
  margin-bottom: 14px;
  border: none;
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--text);
  text-align: left;
  cursor: pointer;
}
.today-overview-card .ico {
  flex: 0 0 auto;
  width: 38px; height: 38px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--dot-soft);
  color: var(--dot-icon);
}
.today-overview-card .ico svg { width: 19px; height: 19px; }
.today-overview-card .body { flex: 1; min-width: 0; }
.today-overview-card .title { font-size: 15px; font-weight: 700; }
.today-overview-card .sub { font-size: 13px; color: var(--text-dim); margin-top: 1px; }
.today-overview-card .chev { flex: 0 0 auto; color: var(--text-dim); }
.day-summary-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin-bottom: 14px;
}
/* TAGLINE-концепт: 3 плитки, не 4 — больше места на каждую */
.day-summary-grid.day-summary-grid-3 { grid-template-columns: repeat(3, 1fr); gap: 10px; }
.day-summary-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 8px;
  border-radius: var(--radius);
  border: none;
  cursor: pointer;
  text-align: left;
  color: var(--text);
}
/* Иконка рисуется прямо на фоне плитки, без отдельного вложенного
   "бейджа" — в reference_screens/01_home_screen.jpg под иконкой нет
   отдельного слоя подложки */
.day-summary-card .ico {
  width: 22px; height: 22px;
  display: flex; align-items: center; justify-content: center;
}
.day-summary-card .ico svg { width: 20px; height: 20px; }
.day-summary-card.c-accent .ico { color: var(--tile-meeting-fg); }
.day-summary-card.c-success .ico { color: var(--success-icon); }
.day-summary-card.c-accent2 .ico { color: var(--tile-contact-fg); }
.day-summary-card.c-dot .ico { color: var(--dot-icon); }
.day-summary-card .num { font-size: 18px; font-weight: 800; line-height: 1; }
.day-summary-card .label { font-size: 11.5px; font-weight: 500; opacity: .85; }
/* Правка по обратной связи: плитки "Встречи" и "Контакты сегодня"
   сливались в тёмной теме — см. токены --tile-meeting-bg/fg и
   --tile-contact-bg/fg выше (отдельные от общих --accent и --accent2,
   которые остаются как есть везде в приложении) */
.day-summary-card.c-accent { background: var(--tile-meeting-bg); color: var(--tile-meeting-fg); }
.day-summary-card.c-accent2 { background: var(--tile-contact-bg); color: var(--tile-contact-fg); }
/* цветовые классы общие — переиспользуются и карточками сводки, и
   иконками в результатах поиска (.search-result-icon) */
.c-accent { background: var(--accent-soft); color: var(--accent); }
.c-success { background: var(--success-soft); color: var(--success); }
.c-accent2 { background: var(--accent2-soft); color: var(--accent2); }
.c-dot { background: var(--dot-soft); color: var(--dot); }

/* Бейдж "Встреча" на карточке задачи — отличаем от обычной задачи без
   привязки к человеку, без изменения модели данных: "встреча" = задача
   с контактом и временем (см. meetingBadgeHTML в app.js) */
.meeting-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 20px;
  background: var(--accent-soft);
  color: var(--accent);
}
.meeting-badge svg { width: 11px; height: 11px; }
.task-badges-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.task-badges-row:empty { display: none; }

/* ============ Шторка быстрого создания (FAB) ============ */
/* "Быстрое создание" (TAGLINE-концепт, 07_QUICK_CREATE_FULL_PANEL.png)
   — заголовок снаружи карточки, список внутри одной белой карточки с
   разделителями между строками, без подписей-пояснений */
.quick-create-sheet .modal-sheet { max-width: 420px; margin: 0 auto; }
.quick-create-title { margin: 0 0 12px 4px; font-size: 19px; font-weight: 800; color: var(--text); }
.quick-create-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0 14px;
}
.quick-create-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 0;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  color: var(--text);
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.quick-create-row:last-child { border-bottom: none; }
.quick-create-row .ico {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
}
.quick-create-row .ico svg { width: 19px; height: 19px; }
.quick-create-row .label { flex: 1; min-width: 0; font-weight: 700; font-size: 14.5px; }
.quick-create-chevron { flex: 0 0 auto; display: flex; color: var(--text-dim); }
.quick-create-chevron svg { width: 16px; height: 16px; }

/* ============ ИИ-ввод одной фразой (Задача 3, docs/RELEASE_1NOV.md) ============ */
.quick-input-status {
  font-size: 13.5px;
  color: var(--text);
  background: var(--surface-2);
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 10px;
}
/* Задача 4: «Добавить запись» с карточки контакта — видно, к кому
   привяжется результат, пока открыта панель */
.quick-input-linked-to {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--accent);
  margin-bottom: 10px;
}
/* Задача 7 — ошибка в обычном модальном окне приложения (не
   .auth-screen, там свой .auth-field-error со своими --auth-* токенами) —
   скрыта, пока пустая, показывается через .is-shown */
.plain-field-error {
  display: none;
  color: var(--danger);
  font-size: 12.5px;
  margin: -4px 0 4px;
}
.plain-field-error.is-shown { display: block; }

/* Задача 6, шаг 4 онбординга — подсказка-абзац, не короткая bold-плашка
   привязки к контакту выше, поэтому отдельный класс, не переопределение */
.quick-input-onboarding-hint {
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.5;
  color: var(--text-dim);
  background: var(--surface-2);
  border-radius: 12px;
  padding: 10px 12px;
  margin-bottom: 10px;
}
.quick-input-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 14px;
  margin-bottom: 12px;
}
.quick-input-card h3 {
  margin: 0 0 10px;
  font-size: 12.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--text-dim);
}
.quick-input-match-banner {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  margin-bottom: 12px;
  font-size: 13.5px;
}
.quick-input-match-actions { display: flex; gap: 8px; }
.quick-input-match-actions .pill-btn { flex: 1; padding: 8px 10px; font-size: 13px; }
.quick-input-empty {
  text-align: center;
  color: var(--text-dim);
  font-size: 14px;
  padding: 20px 0;
}
/* Порядок цветов по кропу: встреча-синий/задача-зелёный/
   контакт-сиреневый/заметка-янтарный */
.quick-create-row.qc-meeting .ico { background: var(--accent-soft); color: var(--accent); }
.quick-create-row.qc-task .ico { background: var(--success-soft); color: var(--success); }
.quick-create-row.qc-contact .ico { background: var(--accent2-soft); color: var(--accent2); }
.quick-create-row.qc-note .ico { background: var(--dot-soft); color: var(--dot); }

/* ============ Подготовка к встрече ============ */
.meeting-prep-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px;
  border-radius: var(--radius);
  background: var(--accent-soft);
  margin-bottom: 14px;
}
.meeting-prep-card .text { flex: 1; min-width: 0; }
.meeting-prep-card .title { font-weight: 700; font-size: 14.5px; color: var(--text); }
.meeting-prep-card .sub { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.meeting-prep-card .btn-primary { flex: 0 0 auto; padding: 10px 14px; font-size: 13px; }

/* Экран "Подготовка к встрече" (06_meeting_prep.jpg) */
#meeting-prep-body { flex: 1; overflow-y: auto; padding: 4px 16px calc(24px + var(--safe-bottom)); -webkit-overflow-scrolling: touch; }
.mp-contact-row { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.mp-contact-row .text { flex: 1; min-width: 0; }
.mp-contact-row .title { font-size: 16px; font-weight: 700; color: var(--text); }
.mp-contact-row .sub { font-size: 13px; color: var(--text-dim); margin-top: 2px; }
.mp-intro { font-size: 13.5px; color: var(--text-dim); line-height: 1.5; margin-bottom: 18px; }
.mp-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  width: 100%;
  padding: 13px 0;
  border: none;
  background: none;
  text-align: left;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.mp-row:last-of-type { border-bottom: none; }
.mp-row .ico {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.mp-row .ico svg { width: 17px; height: 17px; }
.mp-row .text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mp-row .title { font-size: 14.5px; font-weight: 700; color: var(--text); }
.mp-row .sub { font-size: 12.5px; color: var(--text-dim); }
.mp-row .chev { flex: 0 0 auto; color: var(--text-dim); align-self: center; }
.mp-row .chev svg { width: 16px; height: 16px; }
.mp-open-card-btn { width: 100%; margin-top: 20px; }

/* ============ Карточка контакта — просмотр (Этап 4 ТЗ, п. 8.3) ============
   Раньше тап по контакту сразу открывал форму редактирования — теперь
   отдельный read-only экран (это и есть .search-screen — переиспользуем
   уже готовый полноэкранный slide-in, не плодим второй такой же) с
   быстрыми действиями/тегами/контекстом/историей, а форма — отдельно,
   по кнопке "Изменить" */
#contact-view-body { padding: 0 20px 24px; overflow-y: auto; flex: 1; -webkit-overflow-scrolling: touch; }
.contact-view-header { display: flex; flex-direction: column; align-items: center; text-align: center; margin-bottom: 18px; }
.contact-view-header .avatar-circle { width: 76px; height: 76px; font-size: 26px; margin-bottom: 12px; }
.contact-view-header .name { font-size: 20px; font-weight: 800; overflow-wrap: break-word; word-break: break-word; text-align: center; }
.contact-view-header .subtitle { font-size: 13.5px; color: var(--text-dim); margin-top: 3px; overflow-wrap: break-word; word-break: break-word; text-align: center; }
/* 4 круглые кнопки без карточки-подложки — по 03_contact_profile.jpg
   там нет белых карточек под Позвонить/Написать/Email/Ещё, просто
   кружок+подпись на фоне экрана */
.contact-view-actions {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  margin-bottom: 22px;
}
.contact-view-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 0;
  border: none;
  background: none;
  color: var(--text);
  cursor: pointer;
  font-size: 11.5px;
  font-weight: 600;
}
.contact-view-action .ico { width: 44px; height: 44px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.contact-view-action .ico svg { width: 20px; height: 20px; }
.contact-view-action[disabled] { opacity: .4; pointer-events: none; }
.contact-view-section { margin-bottom: 20px; }
.contact-view-section .section-label { margin-bottom: 4px; font-size: 16px; font-weight: 800; color: var(--text); text-transform: none; letter-spacing: normal; }
.contact-view-note {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 13px 14px;
  font-size: 13.5px;
  color: var(--text);
  box-shadow: var(--shadow);
  line-height: 1.45;
}

/* Экран "Детали встречи" (TAGLINE-концепт,
   02_MEETING_DETAILS_FULL_PHONE.png) */
#meeting-details-body { flex: 1; overflow-y: auto; padding: 4px 16px calc(24px + var(--safe-bottom)); -webkit-overflow-scrolling: touch; }
/* ТЗ "Ядро DayMe" — основная кнопка замыкания цикла, фиксирована снизу
   экрана "Детали встречи", не прокручивается вместе с содержимым */
.meeting-complete-cta {
  flex: 0 0 auto;
  margin: 0 16px calc(16px + var(--safe-bottom));
  border: none;
  border-radius: 12px;
  padding: 14px;
  font-weight: 700;
  font-size: 15px;
}
/* Экран "Описание задачи" — тот же стиль, что у "Деталей встречи" */
#task-view-body { flex: 1; overflow-y: auto; padding: 4px 16px calc(24px + var(--safe-bottom)); -webkit-overflow-scrolling: touch; }
.task-view-complete-cta {
  flex: 0 0 auto;
  margin: 0 16px calc(16px + var(--safe-bottom));
  border: none;
  border-radius: 12px;
  padding: 14px;
  font-weight: 700;
  font-size: 15px;
}
.task-view-complete-cta.is-done { background: var(--success-soft); color: var(--success); }
.task-view-desc { font-size: 14px; line-height: 1.6; color: var(--text); white-space: pre-wrap; }
.task-view-chiprow { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.md-head { margin-bottom: 14px; }
.md-time { font-size: 13px; font-weight: 600; color: var(--text-dim); }
.md-title { font-size: 20px; font-weight: 800; color: var(--text); margin-top: 2px; }
.md-sub { font-size: 13px; color: var(--text-dim); margin-top: 2px; }
/* Правка по фидбэку "огромная иконка на весь экран": у .md-sub не было
   правила размера для вложенного svg (есть только у .md-ctx-row) —
   иконка адреса встречи рендерилась в непредсказуемом "естественном"
   размере браузера вместо маленькой пиктограммы рядом с текстом */
.md-sub svg { width: 14px; height: 14px; vertical-align: -2px; color: var(--accent2); flex: 0 0 auto; }
.md-contact-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 0;
  margin-bottom: 12px;
  border: none;
  background: none;
  text-align: left;
  cursor: pointer;
}
.md-contact-row .text { display: flex; flex-direction: column; gap: 1px; }
.md-contact-row .name { font-size: 14.5px; font-weight: 700; color: var(--text); }
.md-contact-row .sub { font-size: 12px; color: var(--text-dim); }
.md-actions { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 20px; }
/* Правка по обратной связи: имя контакта и кнопки были слишком мелкими
   на фоне всего экрана задачи/встречи — крупнее иконка и подпись */
.md-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
  padding: 14px 4px;
  border: none;
  border-radius: 14px;
  background: var(--accent2-soft);
  color: var(--accent2);
  cursor: pointer;
  font-size: 13.5px;
  font-weight: 700;
}
.md-action svg { width: 24px; height: 24px; }
.md-action[disabled] { opacity: .4; pointer-events: none; }
.md-section { margin-bottom: 20px; }
.md-section .section-label { margin-bottom: 8px; text-transform: none; font-size: 15px; font-weight: 800; color: var(--text); letter-spacing: normal; }
.md-points { list-style: none; margin: 0; padding: 0; }
.md-points li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13.5px;
  color: var(--text);
}
/* Правка по обратной связи: при display:flex "•" из ::before считался
   отдельным flex-элементом наравне с текстом и кнопкой-крестиком, и
   justify-content:space-between равномерно раздвигал все три — из-за
   этого текст темы визуально уезжал к центру строки, а не стоял сразу
   после точки слева. Решение — точка больше не отдельный flex-item
   (она теперь внутри текстового span через .md-point-text::before),
   а единственный flex-promoted элемент — это кнопка удаления справа
   (margin-left:auto вместо space-between) */
.md-point-text { flex: 1; min-width: 0; }
.md-point-text::before { content: '•'; margin-right: 6px; color: var(--accent2); }
.md-point-remove { margin-left: auto; }
.md-point-remove { border: none; background: none; color: var(--text-dim); flex: 0 0 auto; padding: 2px; }
.md-point-remove svg { width: 13px; height: 13px; }
.md-point-add-row { display: flex; gap: 8px; margin-top: 10px; }
.md-point-add-row input {
  flex: 1;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 9px 12px;
  font-size: 13px;
  background: var(--bg);
  color: var(--text);
}
.md-ctx-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 0;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
}
.md-ctx-row svg { width: 16px; height: 16px; color: var(--accent2); flex: 0 0 auto; }

/* Строки "Контекст" — по кропу, 4 структурные строки с иконкой в
   светлом квадрате, заголовком/значением и chevron (не один общий
   абзац, как было раньше) */
.contact-context-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 11px 0;
  border-bottom: 1px solid var(--border);
  width: 100%;
  border-left: none; border-right: none; border-top: none;
  background: none;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
}
.contact-context-row .chev { flex: 0 0 auto; color: var(--text-dim); align-self: center; }
.contact-context-row .chev svg { width: 16px; height: 16px; }
.contact-context-row:last-child { border-bottom: none; }
.contact-context-row .ico {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.contact-context-row .ico svg { width: 17px; height: 17px; }
.contact-context-row .text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.contact-context-row .title { font-size: 14px; font-weight: 700; color: var(--text); }
.contact-context-row .value { font-size: 12.5px; color: var(--text-dim); }
.contact-context-row .mutual-row { display: flex; align-items: center; gap: 6px; }
.contact-context-row .mutual-row .avatar-circle { margin-right: -8px; border: 2px solid var(--surface); }
.contact-context-row .mutual-row .avatar-circle:last-of-type { margin-right: 4px; }
.contact-context-row .mutual-names { margin-left: 4px; }
.contact-view-tag { background: var(--accent-soft); color: var(--accent); }
.contact-view-tags-row { margin-bottom: 18px !important; }
/* "Контактная информация" (TAGLINE-концепт) — простые строки иконка+
   текст, без chevron (копируются/открываются системным действием, не
   редактируются прямо тут) */
.contact-info-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 0;
  font-size: 13.5px;
  color: var(--text);
  text-decoration: none;
}
.contact-info-row svg { width: 16px; height: 16px; color: var(--accent2); flex: 0 0 auto; }
.history-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.history-item:last-child { border-bottom: none; }
.history-item .ico {
  flex: 0 0 auto;
  width: 28px; height: 28px;
  border-radius: 9px;
  display: flex; align-items: center; justify-content: center;
  margin-top: 1px;
}
.history-item .ico svg { width: 13px; height: 13px; }
.history-item .text { flex: 1; min-width: 0; }
/* Задача 4, находка 2026-10-27: "— выполнено" раньше дописывалось в
   конец названия — у длинных названий бейдж оказывался в разном месте
   каждый раз. Название теперь ограничено двумя строками с многоточием
   и никогда не наезжает на бейдж (тот — отдельный flex-элемент
   справа, .history-done-badge ниже, его ширина не сжимается) */
.history-item .title {
  font-size: 13.5px;
  font-weight: 600;
  /* Находка пользователя 2026-10-27 (тёмная тема) — .history-item это
     <button>, а у <button> в браузерах по умолчанию СВОЙ цвет текста
     (buttontext), он НЕ наследуется от родителя как у обычного div —
     без явного color здесь текст оставался тёмным/системным даже в
     тёмной теме. Тот же .contact-context-row (тоже кнопка, был в коде
     и раньше) этой ошибки избежал — там .title/.value с самого начала
     заданы явно, см. ниже по файлу */
  color: var(--text);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  word-break: break-word;
}
.history-item .date { font-size: 11.5px; color: var(--text-dim); margin-top: 2px; }
/* Зелёный "овал" — одинаково для задачи/встречи/серии (все три идут
   через один и тот же h.done). --success/--success-soft заданы
   отдельно для каждой палитры, см. :root/[data-theme] (--success-icon
   рядом — похожий токен, но он тогда ещё не был переопределён для
   тёмной темы, этим и не пользовались; переопределён теперь, см. там) */
.history-done-badge {
  flex: 0 0 auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 20px;
  background: var(--success-soft);
  color: var(--success);
  white-space: nowrap;
}

/* Задача 4 (docs/RELEASE_1NOV.md): ближайшая задача/последняя заметка/
   "последний контакт N дней назад" — видны по умолчанию, та же строка,
   что .contact-info-row, просто без ссылки */
.contact-view-facts { margin-bottom: 4px; }
.contact-view-facts .contact-info-row { align-items: flex-start; }

/* "Подробнее" — свёрнутый блок с остальными полями контакта (Задача 4:
   "Остальные поля — в блоке «Подробнее», свёрнут по умолчанию").
   Нативный <details> — бесплатная доступность (клавиатура/скринридер),
   без своего JS-тумблера */
.contact-view-details { margin-bottom: 20px; }
.contact-view-details summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  list-style: none;
  cursor: pointer;
  padding: 10px 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
}
.contact-view-details summary::-webkit-details-marker { display: none; }
.contact-view-details summary .chev { width: 18px; height: 18px; color: var(--text-dim); transition: transform .15s; }
.contact-view-details[open] summary .chev { transform: rotate(180deg); }
.contact-view-details-body { padding-top: 4px; }

/* Та же "Подробнее"-раскрывашка, что в карточке контакта выше, но для
   форм создания/редактирования (Задача 4: "форма создания контакта
   вручную — сначала 4 поля, остальное по «Подробнее»") */
.form-details { margin: 4px 0 14px; }
.form-details summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  list-style: none;
  cursor: pointer;
  padding: 10px 0;
  font-size: 14.5px;
  font-weight: 700;
  color: var(--text);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.form-details summary::-webkit-details-marker { display: none; }
.form-details summary .chev { width: 18px; height: 18px; color: var(--text-dim); transition: transform .15s; }
.form-details[open] summary .chev { transform: rotate(180deg); }
.form-details-body { padding-top: 10px; }
.note-editor-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}
.note-editor-btn {
  background: none;
  border: none;
  font-size: 16px;
  font-weight: 600;
  color: var(--text-dim);
  padding: 6px 4px;
}
.note-editor-btn.accent { color: var(--accent); font-weight: 700; }
/* Раньше это была голая иконка без подписи — пользователь мог не
   понять, что это вообще кнопка, и не находил, где у заметки
   заголовок/папка/фото. Пилюля с текстом однозначно читается как
   нажимаемый элемент */
.note-editor-icon-btn {
  background: var(--surface-2);
  border: none;
  color: var(--text);
  padding: 7px 12px 7px 10px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 12.5px;
  font-weight: 600;
}
.note-editor-icon-btn svg { width: 16px; height: 16px; color: var(--text-dim); }
/* Правка по обратной связи: минимальное форматирование текста заметки
   (жирный/курсив/моно) — markdown-лайт маркеры, см. wrapNoteSelection/
   mdLiteToHTML в app.js */
.note-fmt-row { display: flex; gap: 6px; padding: 8px 14px; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.note-fmt-btn {
  width: 30px; height: 30px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--bg);
  color: var(--text);
  font-size: 13px;
  display: flex; align-items: center; justify-content: center;
}
.note-fmt-btn.mono { font-family: 'SF Mono', Menlo, monospace; }
.note-context-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
}
.note-context-title { font-weight: 700; font-size: 13.5px; }
.note-context-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11.5px;
  font-weight: 600;
  padding: 3px 8px;
  border-radius: 20px;
}
.note-context-chip svg { width: 11px; height: 11px; }
.note-context-chip .avatar-circle { width: 16px; height: 16px; font-size: 8px; }
.note-context-empty { font-size: 12px; color: var(--text-dim); }
.note-editor-text {
  flex: 1;
  width: 100%;
  border: none;
  outline: none;
  resize: none;
  background: var(--bg);
  color: var(--text);
  font-size: 17px;
  line-height: 1.55;
  /* Правка по обратной связи: запас снизу примерно на 3 строки текста —
     чтобы то, что печатают у самого низа, раньше уходило под клавиатуру;
     экран по-прежнему не подстраивает свою высоту под клавиатуру (это
     дважды ломалось раньше), но лишний отступ снизу даёт текстовому
     полю естественно прокрутиться чуть выше заранее */
  padding: 18px 18px calc(18px + var(--safe-bottom) + 79px);
  font-family: inherit;
}

/* модалка настроек заметки должна быть ПОВЕРХ полноэкранного редактора */
#modal-note-settings { z-index: 110; }
/* может открываться поверх редактора заметки (создание контакта "по дороге") */
#modal-contact { z-index: 120; }

/* ============ Модалка ============ */
/* display:none -> flex раньше переключался мгновенно (display нельзя
   анимировать), поэтому любая модалка — настройки, карточка задачи,
   что угодно — просто резко появлялась на экране. Теперь оверлей всегда
   в layout (невидим через opacity+pointer-events, когда закрыт), а сам
   лист отдельно едет снизу — это и даёт плавное появление/закрытие */
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0);
  display: flex;
  align-items: flex-end;
  z-index: 50;
  opacity: 0;
  pointer-events: none;
  transition: opacity .22s ease, background-color .22s ease;
}
.modal-overlay.show {
  opacity: 1;
  background: rgba(0,0,0,.35);
  pointer-events: auto;
}
.modal-sheet {
  background: var(--surface);
  width: 100%;
  max-width: 100%;
  border-radius: 20px 20px 0 0;
  padding: 18px 18px calc(18px + var(--safe-bottom));
  max-height: 86vh;
  overflow-y: auto;
  overflow-x: hidden;
  /* меню должно скроллиться только вниз/вверх, никогда вбок */
  touch-action: pan-y;
  transform: translateY(16px);
  transition: transform .28s cubic-bezier(0.22, 1, 0.36, 1);
}
.modal-overlay.show .modal-sheet { transform: translateY(0); }
.modal-sheet h2 { margin: 0 0 14px; font-size: 19px; }
.field { margin-bottom: 12px; }
.field label {
  display: block;
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text-dim);
  margin-bottom: 5px;
  text-transform: uppercase;
  letter-spacing: .03em;
}
.field-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; align-items: start; }
.field-row > div { min-width: 0; overflow: hidden; }
.field-row label { margin-bottom: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: block; }

/* Форма "Новая задача" (TAGLINE-концепт, 04_CREATE_TASK_FULL_PHONE.png)
   — генерическая форма задачи (не отдельная "Создание встречи"):
   крупный заголовок, компактная пилюля даты/времени, залитые серые
   поля названия/описания, строка контакта с пустым состоянием,
   переключатели-строки "Без времени"/"С напоминанием". Та же модалка
   используется для ВСЕХ задач — существующие повтор/теги/несколько
   контактов остаются ниже, просто не стилизовались под этот кроп (там
   их нет на картинке, не на чем сверять) */
.task-form-title { font-size: 21px; font-weight: 800; color: var(--text); margin: 0 0 8px; }
.task-datetime-fields { display: flex; flex-direction: column; gap: 6px; margin: 6px 0 14px; }
.task-datetime-fields input[type="date"] {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 12px;
  font-size: 13.5px;
  background: var(--bg);
  color: var(--text);
  /* Правка по обратной связи: высота зафиксирована явно, а не отдаётся
     на откуп нативному контролу — иначе на iOS пустое поле времени
     (до выбора значения) рендерится ниже, чем уже заполненное, и строки
     визуально "скачут" по высоте */
  height: 42px;
  box-sizing: border-box;
}
.field label.task-form-label { text-transform: none; letter-spacing: normal; font-weight: 600; font-size: 13px; }
.task-filled-input {
  width: 100%;
  border: none;
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 14px;
  background: var(--bg);
  color: var(--text);
  resize: vertical;
}
.task-radio-row {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 2px;
  border: none;
  border-bottom: 1px solid var(--border);
  background: none;
  text-align: left;
  font-size: 13.5px;
  color: var(--text);
  cursor: pointer;
}
.task-radio-row .chev { margin-left: auto; color: var(--text-dim); flex: 0 0 auto; }
.task-radio-row .chev svg { width: 15px; height: 15px; }
.radio-circle {
  flex: 0 0 auto;
  width: 18px; height: 18px;
  border-radius: 50%;
  border: 2px solid var(--border);
  position: relative;
}
.radio-circle.accent { border-color: var(--accent2); }
.radio-circle.checked { border-color: var(--accent2); background: var(--accent2); }
.radio-circle.checked::after {
  content: '';
  position: absolute; inset: 4px;
  border-radius: 50%;
  background: #fff;
}
.task-contact-lead {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 12px;
  border: none;
  border-radius: 12px;
  background: var(--bg);
  text-align: left;
  cursor: pointer;
}
.task-contact-lead .text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.task-contact-lead .name { font-size: 14.5px; font-weight: 700; color: var(--text); }
.task-contact-lead .sub { font-size: 12.5px; color: var(--text-dim); margin-top: 1px; }
.task-contact-lead .chev { flex: 0 0 auto; color: var(--text-dim); }
.task-contact-lead .chev svg { width: 16px; height: 16px; }
.task-contact-lead.is-empty .name { color: var(--text-dim); font-weight: 600; }
.task-contact-lead .empty-ico { flex: 0 0 auto; width: 36px; height: 36px; border-radius: 50%; background: var(--surface-2); color: var(--text-dim); display: flex; align-items: center; justify-content: center; }
.task-contact-lead .empty-ico svg { width: 17px; height: 17px; }
.task-row-icon { display: flex; align-items: flex-start; gap: 12px; }
.task-row-icon .ico {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.task-row-icon .ico svg { width: 17px; height: 17px; }
.task-row-icon label { margin-bottom: 3px; }
.task-row-icon input[type="text"] {
  border: none; background: none; padding: 0;
  font-size: 14.5px; font-weight: 600; color: var(--text);
  width: 100%;
}
.task-card-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 2px 14px;
  margin-bottom: 12px;
}
.task-card-group .task-row-icon-compact { padding: 11px 0; border-bottom: 1px solid var(--border); }
.task-card-group .task-row-icon-compact:last-child { border-bottom: none; }
.task-datetime-inline { display: flex; flex-direction: column; gap: 6px; }
.task-datetime-inline > input[type="date"] {
  border: none; background: none; padding: 0;
  font-size: 14.5px; font-weight: 600; color: var(--text);
}
.task-datetime-inline .range-box { margin-top: 0; }
.task-note-toggle-row { display: flex; align-items: center; gap: 12px; }
.task-note-toggle-row .ico {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
}
.task-note-toggle-row .ico svg { width: 17px; height: 17px; }
.task-note-toggle-row label { text-transform: none; font-size: 14.5px; font-weight: 700; color: var(--text); margin: 0; }
/* Переключатель-пилюля (iOS-style) — только для .switch-input, обычные
   чекбоксы в Настройках остаются нативными, их тут много и менять их
   внешний вид не было основания по этому кропу */
.switch-input {
  -webkit-appearance: none; appearance: none;
  width: 42px; height: 25px;
  border-radius: 999px;
  background: var(--border);
  position: relative;
  cursor: pointer;
  flex: 0 0 auto;
  transition: background .15s ease;
}
.switch-input::before {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 21px; height: 21px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.25);
  transition: left .15s ease;
}
.switch-input:checked { background: var(--accent); }
.switch-input:checked::before { left: 19px; }

/* Пара полей "с"/"по" (дата ИЛИ время): два отдельных input'а каждый
   сам по себе не давал себя ограничить на iOS — нативные input[type=date]
   и input[type=time] игнорируют max-width/flex/grid своим внутренним
   минимальным размером. Решение общее для обоих типов — один блок с
   рамкой, разделённый пополам линией; переполнение обрезается снаружи
   одной общей рамкой, а не торчит у каждого поля отдельно. */
.range-box {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--surface-2);
  overflow: hidden;
  margin-top: 6px;
  /* Явная высота — чтобы не зависеть от того, пустой нативный
     input[type=time] внутри или уже с выбранным значением (см. выше,
     тот же приём для #task-date) */
  height: 42px;
  box-sizing: border-box;
}
.range-box .range-input {
  flex: 1 1 0%;
  min-width: 0;
  width: 0;
  height: 100%;
  border: none;
  background: transparent;
  border-radius: 0;
  box-sizing: border-box;
  /* Правка по обратной связи: было zoom:0.82 — визуально уменьшало всю
     строку времени (вместе с отступами), из-за чего она была заметно
     ниже поля даты рядом. Теперь высота фиксирована явно (height:100%
     от .range-box, у которого тоже явная высота) — не зависит от того,
     пустой контрол или уже с выбранным значением */
  font-size: 13.5px;
  padding: 0 8px;
}
.range-divider { width: 1px; flex: 0 0 auto; background: var(--border); }

.check-label {
  display: flex !important;
  align-items: center;
  gap: 8px;
  text-transform: none !important;
  font-size: 14.5px !important;
  font-weight: 600 !important;
  color: var(--text) !important;
}
/* :not(.switch-input) — иначе это правило (по специфичности) перебивает
   собственные width/height у пилюли-тумблера (42×25px), сжимая её до
   18×18px: внутренний кружок (21px) оказывается больше контейнера и
   вылезает за его границы — ровно та "уезжающая на край" поломка из
   фидбэка */
.check-label input[type="checkbox"]:not(.switch-input) { width: 18px; height: 18px; accent-color: var(--accent); }
.modal-actions { display: flex; gap: 10px; margin-top: 16px; }
.modal-actions button {
  flex: 1;
  border: none;
  border-radius: 12px;
  padding: 13px;
  font-weight: 700;
  font-size: 15px;
}
.btn-primary { background: var(--accent); color: var(--accent-text); }
.btn-secondary { background: var(--surface-2); color: var(--text); }
.btn-text-danger { background: none; color: var(--danger); font-weight: 700; }

.address-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
}
.address-row input[name="addr-label"] { flex: 0 0 90px; }
.address-row input[name="addr-value"] { flex: 1; }
.address-row button {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  border-radius: 50%;
  border: none;
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 13px;
}

.daily-card {
  background: var(--accent-soft);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 14px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text);
}
.daily-card b { color: var(--accent); }
.daily-card + .daily-card { margin-top: -6px; }
.daily-card svg { width: 14px; height: 14px; vertical-align: -2px; color: var(--accent); }

.avatar-field { display: flex; align-items: center; gap: 14px; }
.avatar-field-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.avatar-preview {
  width: 64px; height: 64px;
  border-radius: 50%;
  background: var(--surface-2);
  background-size: cover;
  background-position: center;
  flex: 0 0 auto;
  border: 1px solid var(--border);
}
.avatar-thumb {
  width: 36px; height: 36px;
  border-radius: 50%;
  background: var(--surface-2);
  background-size: cover;
  background-position: center;
  flex: 0 0 auto;
}
.avatar-circle {
  border-radius: 50%;
  background-position: center;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: 700;
  font-size: 16px;
}
.dm-scroll { -ms-overflow-style: none; scrollbar-width: none; }
.dm-scroll::-webkit-scrollbar { display: none; }
.today-contacts-row { display: flex; gap: 14px; overflow-x: auto; padding: 2px 2px 6px; }
.today-contact-avatar { display: flex; flex-direction: column; align-items: center; gap: 6px; flex: 0 0 auto; width: 60px; }
.today-contact-name { font-size: 11px; font-weight: 600; text-align: center; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 60px; }
.note-photo-preview {
  width: 100%;
  max-height: 160px;
  border-radius: 12px;
  background-size: cover;
  background-position: center;
  aspect-ratio: 16/9;
  margin-bottom: 8px;
  border: 1px solid var(--border);
}
.note-card-photo {
  width: 100%;
  aspect-ratio: 16/9;
  border-radius: 10px;
  background-size: cover;
  background-position: center;
  margin-bottom: 8px;
}

.tagpicker { display: flex; flex-wrap: wrap; gap: 7px; }
.tagpicker .chip { background: var(--surface-2); }
.tagpicker .chip.active { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
.tagpicker .chip.add-chip { background: none; border: 1px dashed var(--border); color: var(--text-dim); }

.theme-swatches { display: flex; gap: 12px; margin-top: 8px; }
.swatch {
  width: 42px; height: 42px;
  border-radius: 50%;
  border: 2px solid transparent;
  position: relative;
}
.swatch.active { border-color: var(--text); }

/* Задача 5 (docs/RELEASE_1NOV.md) — «Основные»/«Дополнительно»,
   визуальная граница крупнее обычного .section-label, чтобы не
   потеряться среди заголовков групп внутри каждого раздела */
.settings-tier-label {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: .06em;
  font-weight: 800;
  color: var(--accent);
  padding-top: 18px;
  margin-bottom: 4px;
  border-top: 1px solid var(--border);
}
.settings-tier-label:first-child { border-top: none; padding-top: 0; }
.settings-group { margin-bottom: 22px; }
.settings-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
  font-size: 15px;
}
.settings-row:last-child { border-bottom: none; }
.settings-row small { display: block; color: var(--text-dim); font-size: 12px; margin-top: 2px; }

.sync-status { font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.sync-status.ok { color: var(--success); }
.sync-status.error { color: var(--danger); }
.sync-status.saving { color: var(--text-dim); }
.sync-status .pill-btn { padding: 3px 10px; font-size: 11.5px; }
#sync-last-time { display: block; color: var(--text-dim); font-size: 12px; margin-top: 2px; }

.grouplist { display: flex; flex-direction: column; gap: 2px; }
.grouplist .empty-state { padding: 10px 0; font-size: 13px; }
/* перетаскиваемая строка группы — зажать и тащить, как порядок папок в
   Телеграме или иконок на iOS. touch-action: none — ВАЖНО: без этого
   браузер сам решает скроллить страницу при касании строки (это решение
   принимается в момент touchstart и дальше не отменяется никаким JS),
   из-за чего вместе с перетаскиванием "ехала" вся страница. При
   touch-action: none браузер в принципе не трогает скролл сам — весь
   скролл (когда палец не держат достаточно долго для начала drag) и
   само перетаскивание полностью реализованы вручную в JS, см.
   wireGroupDragReorder() в app.js */
.group-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--surface-2);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 14px;
  font-weight: 600;
  /* touch-action здесь больше НЕТ специально — перетаскивание теперь
     только за ручку (у неё своё touch-action:none ниже), а сама строка
     должна скроллиться полностью нативно браузером */
  user-select: none;
  -webkit-user-select: none;
  transition: transform .2s ease, box-shadow .15s ease, background-color .15s ease, opacity .15s ease;
}
/* у самой перетаскиваемой строки transform ведёт палец напрямую — без
   transition, иначе будет заметное отставание от пальца */
.group-row.dragging { transition: box-shadow .15s ease, background-color .15s ease, opacity .15s ease; }
.group-drag-handle { color: var(--text-dim); font-size: 20px; flex: 0 0 auto; padding: 10px 12px 10px 2px; margin: -10px 0 -10px -2px; touch-action: none; }
/* нативный <input type="color">, обрезанный в кружок — на iOS открывает
   системный выбор цвета по тапу */
.group-color-swatch {
  -webkit-appearance: none;
  appearance: none;
  width: 24px; height: 24px;
  flex: 0 0 auto;
  border: 2px solid var(--surface);
  border-radius: 50%;
  padding: 0;
  background: none;
  cursor: pointer;
}
.group-color-swatch::-webkit-color-swatch-wrapper { padding: 0; border-radius: 50%; }
.group-color-swatch::-webkit-color-swatch { border: none; border-radius: 50%; }
.group-row-label { flex: 1; }
.group-row .group-delete {
  border: none;
  background: var(--border);
  color: var(--text-dim);
  width: 22px; height: 22px;
  border-radius: 50%;
  font-size: 12px;
  line-height: 1;
  flex: 0 0 auto;
}
.group-row.dragging {
  box-shadow: 0 14px 28px rgba(0, 0, 0, 0.3);
  background: var(--surface);
  position: relative;
  z-index: 5;
  opacity: .97;
}

/* ============ Модалка выбора контактов (поиск + список) ============ */
.contact-picker-list { max-height: 50vh; overflow-y: auto; margin: 10px 0; display: flex; flex-direction: column; }
.picker-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--border);
  font-size: 14.5px;
}
.picker-row:last-child { border-bottom: none; }
.picker-row input[type="checkbox"] { width: 19px; height: 19px; accent-color: var(--accent); flex: 0 0 auto; }
/* Правка по обратной связи: "+ Новый контакт…" прямо в поиске контактов
   для задачи/встречи/заметки — раньше создать контакт можно было только
   через отдельный маленький чип ниже по форме, легко было не заметить */
.picker-row.add-row { width: 100%; text-align: left; background: none; border: none; color: var(--accent); font-weight: 700; font-size: 14.5px; }

/* ============ Широкий экран — планшет/десктоп (раздел 22 ТЗ) ============
   В самом конце файла НАРОЧНО — иначе при равной специфичности эти
   right/left/width проигрывали бы более поздним базовым правилам
   .search-screen/.modal-overlay и т.д. (а они определены ниже по
   файлу), и переопределение тихо не срабатывало.
   Приложение спроектировано как мобильный PWA (ставится на домашний
   экран телефона), полноценная отдельная desktop-раскладка с боковой
   панелью была бы избыточной архитектурой ради проекта такого размера
   (п.26 ТЗ). Вместо неё — компактная колонка по ширине телефона,
   отцентрованная на экране: это и есть "другой компактный вариант
   навигации", который раздел 5 ТЗ прямо допускает как альтернативу
   боковой панели. --app-w держит ширину колонки в одном месте — и
   сам #app, и все полноэкранные fixed-слои (поиск/редактор заметки/
   вход/карточка контакта/модалки/FAB) выравниваются по ней
   единообразно, вместо каждый по своему */
@media (min-width: 640px) {
  :root { --app-w: 480px; }
  body { background: var(--surface-2); }
  #app {
    max-width: var(--app-w);
    margin: 0 auto;
    box-shadow: 0 0 40px rgba(0, 0, 0, .14);
  }
  .search-screen, .note-editor, #screen-contact-view, .auth-screen, .modal-overlay {
    left: calc(50vw - var(--app-w) / 2);
    right: auto;
    width: var(--app-w);
  }
  .fab {
    right: calc(50vw - var(--app-w) / 2 + 18px);
  }
  /* Найдено 2026-10-27 при проверке Задачи 3 (докс/RELEASE_1NOV.md) —
     предсуществующий баг, не связанный с самой задачей: правило выше
     двигает ЛЮБОЙ .fab на одно и то же место, включая #voice-ai-btn
     (класс "fab fab-voice") — из-за этого на экранах ≥640px кнопка
     микрофона приземлялась ровно поверх кнопки "+", перекрывая её
     целиком (клик по "+" не проходил). Та же компенсация смещения
     86px, что .fab-voice уже делает на узких экранах (см. выше) —
     здесь нужно применить её ПОВЕРХ центрирования широкого экрана */
  .fab-voice {
    right: calc(50vw - var(--app-w) / 2 + 86px);
  }
}

/* ============ Уменьшение движения (раздел 21 ТЗ) ============
   Системная настройка "Уменьшить движение" — глушим длительность всех
   CSS-переходов/анимаций (открытие диалогов, шторка быстрого
   создания, смена статуса задачи, вспышки flash-on/off и т.д.) одним
   общим правилом, а не точечно в каждом компоненте */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============ "Ближайшие события" — таймлайн (точный макет) ============
   Раньше это были обычные .card друг под другом (как список задач) —
   на макете это именно таймлайн: вертикальная линия слева, на ней
   точки-маркеры по времени, время отдельной колонкой слева от линии,
   контент — справа. Полная пересборка под референс, а не перекраска
   старых карточек */
.section-label-row { display: flex; align-items: center; justify-content: space-between; margin: 18px 0 10px; }
.section-label-row .section-label { margin: 0; }
.section-link { font-size: 13px; font-weight: 700; color: var(--accent); }
/* "Ближайшие события" — по reference_screens/01_home_screen.jpg: ОДНА
   белая card-обёртка на весь список (не отдельные карточки и не
   вертикальная линия-коннектор с точками, как было раньше — в кропе
   такого элемента нет вообще), строки разделены тонким divider'ом,
   время — двумя строками (начало сверху жирным, конец снизу вторичным
   цветом) */
/* "Ближайшие события" — TAGLINE-концепт (01_HOME_MY_DAY_FULL_PHONE.png):
   цветная точка+линия таймлайна слева (была убрана в предыдущем
   концепте как отсутствующая в ЕГО референсе — в этом кропе она есть),
   список лежит прямо на фоне страницы, без белой карточки-обёртки */
.agenda-timeline { position: relative; }
.agenda-item { display: flex; gap: 10px; position: relative; }
.agenda-time { flex: 0 0 44px; font-size: 13px; font-weight: 700; color: var(--text); padding-top: 2px; }
.agenda-line { flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; width: 10px; }
.agenda-dot { width: 10px; height: 10px; border-radius: 999px; flex: 0 0 auto; margin-top: 4px; }
.agenda-dot.is-meeting { background: var(--accent2); }
.agenda-dot.is-task { background: var(--success); }
/* Правка по обратной связи: встреча с известным временем окончания —
   не толстая полоска, а отрезок из двух точек (начало/конец) с тонкой
   линией между ними — как в кропе. Длина пока не в масштабе реальных
   минут (это бы потребовало отдельной временной шкалы на весь день, как
   в "Неделе"/сетке) — просто заметно длиннее обычной точки, чтобы
   разница типа события была видна сразу */
.agenda-span { width: 10px; height: 26px; display: flex; flex-direction: column; align-items: center; justify-content: space-between; flex: 0 0 auto; margin-top: 4px; }
.agenda-span-dot { width: 6px; height: 6px; border-radius: 999px; background: var(--accent2); flex: 0 0 auto; }
.agenda-span-line { width: 2px; flex: 1; background: var(--accent2); margin: 1px 0; }
.agenda-connector { flex: 1; width: 2px; background: var(--border); margin: 2px 0; }
.agenda-item:last-child .agenda-connector { display: none; }
/* Правка по обратной связи: убраны серые разделительные линии под
   каждой встречей/задачей на "Моём дне" — остаётся только отступ между
   строками, без видимой границы */
/* Правка по обратной связи: было мало места между встречей/задачей на
   "Моём дне" — выглядело слишком тесно (особенно после того, как убрали
   разделительные линии между строками) */
.agenda-content { flex: 1; min-width: 0; padding-bottom: 28px; display: flex; align-items: flex-start; gap: 10px; }
.agenda-content-main { flex: 1; min-width: 0; }
.agenda-content .avatar-circle, .agenda-content .agenda-ico { flex: 0 0 auto; width: 34px; height: 34px; font-size: 12.5px; }
.agenda-ico { display: flex; align-items: center; justify-content: center; border-radius: 999px; background: var(--success-soft); color: var(--success); }
.agenda-ico.is-meeting { background: var(--accent2-soft); color: var(--accent2); }
.agenda-ico svg { width: 16px; height: 16px; }
.agenda-title { font-size: 14.5px; font-weight: 700; color: var(--text); }
.agenda-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 1px; }
.agenda-detail { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.agenda-chip {
  display: inline-block;
  font-size: 11px;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 999px;
  margin-top: 7px;
}
.agenda-chip.is-meeting { background: var(--accent2-soft); color: var(--accent2); }
.agenda-chip.is-task { background: var(--success-soft); color: var(--success); }
.agenda-chip.is-note { background: var(--dot-soft); color: var(--dot); }
/* 3 кнопки-пилюли Контакт/История/Заметки — вернулись по этому кропу
   (в предыдущем концепте была одна текстовая строка вместо них) */
.agenda-tags-row { display: flex; gap: 6px; margin-top: 8px; flex-wrap: wrap; }
.agenda-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  padding: 5px 10px;
  border-radius: 20px;
  background: var(--accent2-soft);
  color: var(--accent2);
  border: none;
  cursor: pointer;
}
.agenda-tag svg { width: 11px; height: 11px; }
.agenda-meta-row {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-dim);
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
}
.agenda-meta-row svg { width: 13px; height: 13px; flex: 0 0 auto; }
.agenda-chevron { flex: 0 0 auto; color: var(--text-dim); align-self: center; }
.agenda-check { align-self: center; }
.agenda-chevron svg { width: 16px; height: 16px; }
/* Правка по обратной связи: строки без времени стояли впритык друг к
   другу (и к "Выполнено сегодня" следом) — не было отступа снизу вообще */
.agenda-nodate-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  margin-bottom: 10px;
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.agenda-nodate-row .agenda-ico { background: var(--dot-soft); color: var(--dot); }

/* Тост-уведомление (решение пользователя 2026-10-22) — до этого в
   приложении не было ни одного неблокирующего уведомления, везде
   alert(); первое применение — сообщение "нет места для фото без
   сети" (js/app.js, showToast()), но функция написана как обычная
   переиспользуемая, не завязанная на этот один случай */
#toast-root {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(86px + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
  z-index: 9999;
}
.toast {
  max-width: calc(100% - 32px);
  padding: 12px 18px;
  background: var(--text);
  color: var(--bg);
  border-radius: 999px;
  box-shadow: var(--shadow);
  font-size: 14px;
  text-align: center;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .2s ease, transform .2s ease;
}
.toast.show { opacity: 1; transform: translateY(0); }
