/* Оболочка EventSync: три плотности одного стекла, единственный акцент, деньги отдельной триадой.
   Файл общий для всех страниц продукта — кабинета, админки, портала клиента и входа: второй набор
   тех же правил рядом с первым разъезжается на третьей правке, и страницы начинают выглядеть
   «почти одинаково», что хуже, чем откровенно разный дизайн. */

*,*::before,*::after{box-sizing:border-box}
html,body{height:100%}
/* Тёмная подложка под сценой. Без неё страница, у которой фон не загрузился, показывает белый
   лист под светлым текстом — а это ровно то состояние, в котором интерфейс нечитаем. */
body{background:#0f1116}
body{margin:0;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
  -webkit-font-smoothing:antialiased;overflow:hidden}
[data-act]{cursor:pointer;-webkit-user-select:none;user-select:none}
button{font:inherit;color:inherit;background:none;border:0;padding:0}
:focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:6px}

/* ── Сцена. Принимает и градиент, и фотографию: --scene подставляется как
      url(data:...) при выборе фото или загрузке своего файла.
      Фото размывается ОДИН раз здесь (--scene-blur), а не каждым окном —
      поэтому окнам хватает blur 14–26px, и текст на них не плывёт. ── */
.stage{position:fixed;inset:0;z-index:0;background:var(--scene) center/cover no-repeat;
  transform:scale(1.06);
  filter:blur(var(--scene-blur,0px)) saturate(105%);
  transition:opacity .6s cubic-bezier(.22,.7,.25,1)}
/* Второй слой той же сцены — без размытия. Видна только та его часть, что попадает в квадрат
   на «Домой»: всё остальное отрезано. Отдельным элементом, а не свойством дыры, по простой
   причине — размытие делается один раз в сцене, и «отменить его на кусочке» изнутри нечем,
   а любая плита каркаса с backdrop-filter размывает и то, что под ней.

   Тонального слоя у него нет намеренно: ради этого квадрата всё и затевалось — человек должен
   увидеть свою фотографию как она есть, а не под плёнкой. */
/* Два элемента, а не один: обрезка считается ДО масштабирования, поэтому картинку двигает
   внутренний слой, а вырез задаёт внешний — он остаётся в координатах экрана и совпадает
   с рамкой квадрата ровно. Одним элементом вырез уезжал на те самые шесть процентов. */
.stage-sharp{position:fixed;inset:0;z-index:0;pointer-events:none;
  clip-path:inset(var(--hole-t,50%) var(--hole-r,50%) var(--hole-b,50%) var(--hole-l,50%) round 28px);
  /* Резкость гаснет к краям, а не обрывается: маска из двух градиентов делает чёткий слой
     прозрачным у самой рамки, и сквозь него проступает размытая сцена. Получается не стык
     двух картинок, а переход — окно словно приоткрыто, а не вырезано ножницами.
     Растушёвка внутрь, а не наружу: наружу она вылезла бы на карточки поверх них. */
  --feather:130px;
  -webkit-mask-image:
    linear-gradient(to right, transparent var(--hx0,0px), #000 calc(var(--hx0,0px) + var(--feather)),
      #000 calc(var(--hx1,100%) - var(--feather)), transparent var(--hx1,100%)),
    linear-gradient(to bottom, transparent var(--hy0,0px), #000 calc(var(--hy0,0px) + var(--feather)),
      #000 calc(var(--hy1,100%) - var(--feather)), transparent var(--hy1,100%));
  mask-image:
    linear-gradient(to right, transparent var(--hx0,0px), #000 calc(var(--hx0,0px) + var(--feather)),
      #000 calc(var(--hx1,100%) - var(--feather)), transparent var(--hx1,100%)),
    linear-gradient(to bottom, transparent var(--hy0,0px), #000 calc(var(--hy0,0px) + var(--feather)),
      #000 calc(var(--hy1,100%) - var(--feather)), transparent var(--hy1,100%));
  -webkit-mask-composite:source-in;
  mask-composite:intersect;
  opacity:0;transition:opacity .45s var(--ease)}
.stage-sharp i{position:absolute;inset:0;display:block;
  background:var(--scene) center/cover no-repeat;transform:scale(1.06)}
.stage-sharp.on{opacity:1}
.no-scene .stage-sharp{opacity:0}

/* Постоянный тональный слой: без него светлая фотография выжигает окна
   на низкой матовости. Это не ползунок — это страховка читаемости. */
.stage::after{content:'';position:absolute;inset:0;
  background:
    radial-gradient(125% 95% at 50% 0%,transparent 48%,rgba(8,10,14,.40) 100%),
    linear-gradient(180deg,rgba(8,10,14,.04),rgba(8,10,14,.26))}
/* зерно: на фотографии оно лишнее, поэтому слабее, чем было на градиентах */
.grain{position:fixed;inset:0;z-index:1;pointer-events:none;opacity:.16;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E")}

:root{
  /* Нативные календарь, часы, селект и полоса прокрутки красятся браузером, а не этим файлом:
     единственная ручка к ним — color-scheme, и она обязана ехать вместе с темой. */
  color-scheme:dark;
  --acc:#d4f742; --acc-ink:#1c2600;
  --g:#4ade80; --b:#93c2fb; --r:#fca5b0;   /* деньги: отдельно от акцента — принцип DESIGN.md */
  /* Янтарный — «срок на днях»: третье состояние рядом с красным. Отдельный токен, а не
     смесь красного с зелёным на месте: он обязан быть читаемым во ВСЕХ четырёх темах, и
     подобранный один раз здесь не выцветает на белых окнах. */
  --am:#fbbf24;
  --rad-s:12px; --rad:20px; --rad-l:28px;
  --ease:cubic-bezier(.22,.7,.25,1);
  --spring:cubic-bezier(.16,1,.3,1);

  /* ── Мобильный каркас ────────────────────────────────────────────────────
     Размеры, от которых зависит вся телефонная раскладка. Держатся здесь, а не
     разбросаны по медиазапросам: высота нижнего меню участвует и в отступе снизу у
     контента, и в положении плавающих кнопок, и в прокрутке к якорю — три числа,
     разъехавшись, дают контент, наполовину спрятанный под меню.

     Безопасные зоны читаются один раз в переменные: env() нельзя использовать внутри
     calc() в некоторых старых WebKit напрямую, а через переменную — можно везде. */
  --safe-t:env(safe-area-inset-top, 0px);
  --safe-b:env(safe-area-inset-bottom, 0px);
  --safe-l:env(safe-area-inset-left, 0px);
  --safe-r:env(safe-area-inset-right, 0px);
  /* Минимальная область нажатия. 44 px — не «красивое число», а нижняя граница, ниже
     которой промахи пальцем перестают быть случайностью (Apple HIG, Material). */
  --tap-min:44px;
  --tabbar-h:62px;                  /* высота нижнего меню в развёрнутом виде */
  --tabbar-h-min:50px;              /* оно же сжатое — при листании вниз */
  --hdr-h:52px;                     /* липкая шапка экрана на телефоне */

  /* Стекло оболочки — тёмное. Светлое стекло над фото даёт молоко (см. GLASS-SHELL-RESEARCH.md §2.1).
     Два уровня глубины, а не один рецепт на оба блока: рельс сидит глубже и плотнее,
     панель ближе к бумаге и легче — иначе рельс с панелью читаются одним листом со швом. */
  /* Затемнение окна — один ползунок --darken (0..100) на все четыре стекла.
     0% — окна почти прозрачные, сцена бьёт насквозь; 100% — глухие.
     Стартовые доли разные, чтобы порядок глубин (рельс > поле > панель)
     сохранялся на любом положении ползунка, а не только в середине. */
  --darken:52;                      /* затемнение окна, 0..100 */
  --w-blur:18;                      /* размытие окна, 0..40 */
  /* Матовость «относительно серого»: размытие не просто мылит фон, а тянет его
     к ровному среднему тону — гасит насыщенность, сжимает контраст и притемняет.
     Поэтому белый текст читается одинаково и над небом, и над тёмным лесом,
     не завися от того, что именно оказалось под окном. */
  --w-sat:calc(115% - var(--w-blur) * 1.2%);
  --w-con:calc(100% - var(--w-blur) * .75%);
  --w-bri:calc(100% - var(--w-blur) * .72%);
  --w-fx:saturate(var(--w-sat)) contrast(var(--w-con)) brightness(var(--w-bri));
  /* ── Шкала поверхностей: одна лестница глубины на весь интерфейс ──────────
     0 — стол за окнами и рельс (самая глубокая плита)
     1 — панель, шторки
     2 — окно: рабочее поле
     3 — то, что всплывает ПОВЕРХ окна: модалка, выпадающее меню, поп-ап, тост

     Лист, карточка, строка и поле ввода своей ступени не имеют: они живут ПЛЁНКОЙ поверх
     своей поверхности (--film-1..5, --fill). Плёнка — это тон полярности с малой альфой:
     в тёмной свет, в светлой тень, поэтому «отличается от своей поверхности» выполняется
     само, на какой бы ступени плёнка ни лежала.

     Значения продублированы данными в public/js/core/theme.js, и test/theme.test.js сверяет
     их СТРОКОЙ — включая формулы от ползунка затемнения; тот же прогон перебирает каждую пару
     «чернила × поверхность» и «чернила × плёнка над поверхностью». До этой сборки цвета жили
     двумя семействами с противоположной полярностью, и светлая тема переворачивала одно.

     Базовый набор — «Стекло»: тёмная полярность на прозрачном материале. Плотность ступеней
     остаётся формулой от --darken; --pop плотный намеренно — сквозь всплывающий список не
     должен читаться текст под ним. */
  --surf-0:rgba(13,15,20,calc(.16 + var(--darken) * .0084));
  --surf-1:rgba(20,23,29,calc(.06 + var(--darken) * .0088));
  --surf-2:rgba(19,22,28,calc(.12 + var(--darken) * .0088));
  --surf-3:rgba(18,20,26,calc(.16 + var(--darken) * .0084));
  --ink:#f7f8f7;
  --ink-2:#dfe3dc;
  --ink-3:#b9c0b6;
  --on-accent:#1c2600;
  --on-solid:#f2f4ef;
  --on-solid-ink:#12151a;
  --pop:#171a21;
  --line:rgba(255,255,255,.12);
  --edge:rgba(255,255,255,.14);
  --edge-hi:rgba(255,255,255,.3);
  --fill:rgba(255,255,255,.07);
  --fill-2:rgba(255,255,255,.12);
  --stroke:rgba(255,255,255,.43);
  --stroke-hi:rgba(255,255,255,.52);
  --film-1:rgba(255,255,255,.05);
  --film-2:rgba(255,255,255,.07);
  --film-3:rgba(255,255,255,.1);
  --film-4:rgba(255,255,255,.13);
  --film-5:rgba(255,255,255,.17);
  --tag-g-bg:rgba(74,222,128,.16);
  --tag-g-ink:#8ceaa9;
  --tag-b-bg:rgba(96,165,250,.16);
  --tag-b-ink:#93c2fb;
  --tag-r-bg:rgba(251,113,133,.16);
  --tag-r-ink:#fda4b0;
  /* Янтарный — третий тон самочувствия события (таск 61). Заведён рядом с зелёным и красным,
     а не подобран на месте: цвет состояния обязан переворачиваться вместе с темой. */
  --tag-a-bg:rgba(251,191,36,.16);
  --tag-a-ink:#f0c874;

  /* Ширина рельса и панели — токены: от них считаются метка позиции и сжатие. */
  --win:100;                                        /* размер окна, 100..80 */
  /* Компенсация: рамка ужимается — внутренние поля отдают ей часть, чтобы
     полезная ширина строки падала медленнее ширины окна. 0 → 10px. */
  --pad-c:calc((100 - var(--win)) * .5px);
  --rail-h:calc(64px - (100 - var(--win)) * .3px);  /* высота ленты, 64 → 58 */
  --panel-w:calc(340px - (100 - var(--win)) * 1.4px); /* 340 → 312 */
}
.no-scene .stage,.no-scene .grain{opacity:0}
/* Уплотняются ВСЕ четыре стекла, включая рабочее поле: пропустишь одно —
   и оно останется прозрачным там, где остальные уже глухие. */
.no-scene{--surf-0:rgba(14,16,21,.97);--surf-1:rgba(18,20,26,.94);
  --surf-2:rgba(19,22,28,.96);--surf-3:rgba(24,26,32,.97)}

/* ── Псевдонимы прежних имён ────────────────────────────────────────────────
   В файле около 545 обращений к цветовым переменным. Массовая замена дала бы дифф, который
   никто не прочитает, и сломала бы то, что в тёмной теме работает. Поэтому старые имена
   остаются, но получают значения из шкалы: два семейства сходятся в один источник, и
   полярности больше нечему разъезжаться. Удаляются потом, отдельной уборкой, когда станет
   видно, какие из них лишние.

   Объявлены на body, а НЕ на :root, и это не стилистика: классы режимов висят на body, а
   var() подставляется там, где объявление написано. На :root псевдоним застыл бы со
   стеклянным значением, и светлая тема снова оказалась бы половинчатой — ровно тот баг,
   который чинит эта сборка. */
body{
  --glass-deep:var(--surf-0);          /* рельс */
  --glass:var(--surf-1);               /* панель */
  --glass-2:var(--surf-3);             /* модалка, поп-ап — всплывают поверх окна */
  --paper:var(--surf-2);               /* рабочее поле — то же окно */
  --paper-2:var(--film-2);             /* поле ввода, тег, строка внутри окна — плёнка */
  --on:var(--ink); --on-dim:var(--ink-2); --on-mute:var(--ink-3);
}

/* ── Три режима оболочки ──────────────────────────────────────────────────
   Стекло — база, объявленная выше и включённая по умолчанию.
   Тёмная и Светлая — те же формы без сцены: меняются только значения токенов,
   ни одно правило вёрстки не дублируется. Классы висят на <body>. */
/* Тёмная — те же ступени без прозрачности. Значения ровно те, что были до сборки:
   владелец тёмной темой доволен, и шкала не имеет права менять её на вид. */
.m-dark{
  color-scheme:dark;
  --surf-0:#0f1116;
  --surf-1:#161920;
  --surf-2:#111419;
  --surf-3:#1b1e26;
  --ink:#f7f8f7;
  --ink-2:#dfe3dc;
  --ink-3:#b9c0b6;
  --on-accent:#1c2600;
  --on-solid:#f2f4ef;
  --on-solid-ink:#12151a;
  --pop:#1b1e26;
  --line:rgba(255,255,255,.12);
  --edge:rgba(255,255,255,.09);
  --edge-hi:rgba(255,255,255,.14);
  --fill:rgba(255,255,255,.06);
  --fill-2:rgba(255,255,255,.11);
  --stroke:rgba(255,255,255,.38);
  --stroke-hi:rgba(255,255,255,.48);
  --film-1:rgba(255,255,255,.05);
  --film-2:rgba(255,255,255,.07);
  --film-3:rgba(255,255,255,.1);
  --film-4:rgba(255,255,255,.13);
  --film-5:rgba(255,255,255,.17);
  --tag-g-bg:rgba(74,222,128,.16);
  --tag-g-ink:#8ceaa9;
  --tag-b-bg:rgba(96,165,250,.16);
  --tag-b-ink:#93c2fb;
  --tag-r-bg:rgba(251,113,133,.16);
  --tag-r-ink:#fda4b0;
  /* Янтарный — третий тон самочувствия события (таск 61). Заведён рядом с зелёным и красным,
     а не подобран на месте: цвет состояния обязан переворачиваться вместе с темой. */
  --tag-a-bg:rgba(251,191,36,.16);
  --tag-a-ink:#f0c874;
  /* Деньги: те же значения, что в стекле, — обе темы тёмной полярности. Объявлены явно,
     чтобы триада тоже сверялась с данными, а не наследовалась молча. */
  --g:#4ade80; --b:#60a5fa; --r:#fb7185; --am:#fbbf24;
}
/* Светлая — светлая полярность на плотном материале. Вся оболочка переворачивается разом:
   до этой сборки переворачивалась только «бумага», и рельс с панелью оставались тёмными,
   а внутри окна встречались обе полярности сразу. Рельс и панель «серенькие», окна белые,
   блоки внутри окна серые — плёнками тени, теми же, что в тёмной дают плёнки света.
   Деньги и теги — ниже: их оттенок принадлежит данным, тон берётся от темы. */
.m-light{
  color-scheme:light;
  --surf-0:#e4e7ea;
  --surf-1:#f1f2f4;
  --surf-2:#ffffff;
  --surf-3:#ffffff;
  --ink:#1a1d1a;
  --ink-2:#454a45;
  --ink-3:#4f5550;
  --on-accent:#1c2600;
  --on-solid:#12151a;
  --on-solid-ink:#f2f4ef;
  --pop:#ffffff;
  --line:rgba(17,22,17,.14);
  --edge:rgba(17,22,17,.22);
  --edge-hi:rgba(17,22,17,.3);
  --fill:rgba(17,22,17,.05);
  --fill-2:rgba(17,22,17,.09);
  --stroke:rgba(17,22,17,.5);
  --stroke-hi:rgba(17,22,17,.6);
  --film-1:rgba(17,22,17,.028);
  --film-2:rgba(17,22,17,.045);
  --film-3:rgba(17,22,17,.07);
  --film-4:rgba(17,22,17,.1);
  --film-5:rgba(17,22,17,.14);
  --tag-g-bg:#e3f7ea;
  --tag-g-ink:#0f6b37;
  --tag-b-bg:#e5eefc;
  --tag-b-ink:#1b4f96;
  --tag-r-bg:#fde8ec;
  --tag-r-ink:#a32540;
  --tag-a-bg:#fdf1dd;
  --tag-a-ink:#7a4a00;
  /* Деньги на белом: яркая триада выцветает, поэтому чернильный регистр. */
  --g:#0d6f37; --b:#1f5cad; --r:#b8324a; --am:#8a5200;
}
/* ── «Стекло», белые окна ─────────────────────────────────────────────────
   Просьба владельца дословно: «нужно добавить к стеклянной форме чекбокс белые окна, а то
   слишком темно на стекле, соответственно цвет шрифтов тоже надо подогнать».

   Это не четвёртый режим со своей палитрой, а ВТОРАЯ ОСЬ: «Стекло» задаёт материал
   (прозрачность, сцена, размытие), светлое/тёмное — полярность. Поэтому класс идёт ВТОРЫМ
   поверх .m-glass и меняет только значения: сцена, блюр и все правила вёрстки остаются
   стеклянными. Чернила переворачиваются вместе с поверхностями — «подогнать шрифты» тем
   и делается, что тройка чернил здесь одна на все четыре ступени.

   Плотность выше, чем у тёмного стекла: тёмный текст на полупрозрачном белом садится быстрее,
   чем светлый на полупрозрачном чёрном. Ниже --darken:35 (MIN_DARKEN в core/theme.js) сцена
   пробивает настолько, что вторичный текст уходит за порог, — туда ползунок не пускает app.js. */
.t-light{
  color-scheme:light;
  --surf-0:rgba(228,231,234,calc(.16 + var(--darken) * .0084));
  --surf-1:rgba(241,242,244,calc(.06 + var(--darken) * .0088));
  --surf-2:rgba(255,255,255,calc(.12 + var(--darken) * .0088));
  --surf-3:rgba(255,255,255,calc(.16 + var(--darken) * .0084));
  --ink:#0a0c0a;
  --ink-2:#1a1d17;
  --ink-3:#1f231d;
  --on-accent:#1c2600;
  --on-solid:#12151a;
  --on-solid-ink:#f2f4ef;
  --pop:#ffffff;
  --line:rgba(17,22,17,.14);
  --edge:rgba(17,22,17,.22);
  --edge-hi:rgba(17,22,17,.3);
  --fill:rgba(17,22,17,.05);
  --fill-2:rgba(17,22,17,.09);
  --stroke:rgba(17,22,17,.7);
  --stroke-hi:rgba(17,22,17,.78);
  --film-1:rgba(17,22,17,.028);
  --film-2:rgba(17,22,17,.045);
  --film-3:rgba(17,22,17,.07);
  --film-4:rgba(17,22,17,.1);
  --film-5:rgba(17,22,17,.14);
  --tag-g-bg:#e3f7ea;
  --tag-g-ink:#0f6b37;
  --tag-b-bg:#e5eefc;
  --tag-b-ink:#1b4f96;
  --tag-r-bg:#fde8ec;
  --tag-r-ink:#a32540;
  --tag-a-bg:#fdf1dd;
  --tag-a-ink:#7a4a00;
  --g:#022a14; --b:#0a2244; --r:#400c19; --am:#3d2600;
}
/* Полоса прокрутки документа и фон страницы слушают color-scheme КОРНЯ, а классы режимов
   висят на body — без этой строки светлая тема получала тёмный скроллбар вокруг белых окон. */
html:has(body.m-light),html:has(body.t-light){color-scheme:light}
/* Выключенный фон уплотняет и это стекло — иначе за окнами остаётся тёмная подложка body,
   а окна стоят на ней светлыми пятнами. Значения те же, что у плотной светлой темы. */
.no-scene.t-light{--surf-0:#e4e7ea;--surf-1:#f1f2f4;--surf-2:#fff;--surf-3:#fff;
  background:var(--surf-0)}
/* Только в плотных темах поверхности непрозрачны — блюр под ними не нужен и греет GPU. */
.m-light .ws{backdrop-filter:none;-webkit-backdrop-filter:none;
  box-shadow:0 22px 50px -22px rgba(17,22,17,.28)}
.m-light tfoot td{border-top:2px solid var(--ink)}
/* Стол за окнами — своя ступень шкалы, а не чёрный лист под светлой темой. */
.m-dark,.m-light{background:var(--surf-0)}
/* Сцена живёт только в стеклянном режиме. */
.m-dark .stage,.m-dark .grain,.m-light .stage,.m-light .grain{opacity:0}

/* ── Каркас: три блока. Панель не прячется адаптивом, только сжимается. ── */
/* ── Размер окна (--win, 100..80) ──────────────────────────────────────────
   Уменьшается ТОЛЬКО рамка: поля вокруг группы и зазор между окнами растут,
   поэтому окна физически съезжаются к центру и фон виден по краям и в швах.
   Шрифты, иконки и внутренние отступы к --win не привязаны вообще — они
   заданы в px и не участвуют в масштабировании. Это сознательный отказ от
   transform:scale(): он ужал бы и текст, а именно этого просили избежать.
   Поля считаются в vh/vw, чтобы 80% означало 80% экрана на любом мониторе;
   рельс и панель сжимаются мягче содержимого, иначе список начинает рвать
   строки — то самое «съезжает». */
.app{position:relative;z-index:2;display:flex;flex-direction:column;height:100%;overflow:hidden;
  color:var(--on);
  --gap:calc(14px + (100 - var(--win)) * .8px);
  padding:calc(14px + (100 - var(--win)) * .42vh) calc(14px + (100 - var(--win)) * .42vw);
  gap:var(--gap)}
/* Рельс лежит лентой сверху, поэтому панель и рабочее поле нужны отдельной строкой:
   иначе они встали бы под рельсом друг за другом по вертикали. */
.app-row{display:flex;flex:1 1 auto;min-height:0;gap:var(--gap)}

/* Первый блок — рельс */
/* Верх — не сплошная плита, а две автономные капсулы: навигация по центру
   и профиль справа. Сам .rail прозрачен и только раскладывает их, поэтому
   между ними виден фон, а не пустые поля одной длинной ленты. */
.rail{width:auto;height:var(--rail-h);flex:0 0 var(--rail-h);display:flex;flex-direction:row;
  align-items:center;gap:var(--gap);background:none;border:0;box-shadow:none}
.pill-wrap{position:relative;display:flex;border-radius:99px}
/* Общий рецепт стекла для обеих капсул — он же был у плиты.
   isolation + overflow обязательны: backdrop-filter фильтрует прямоугольную
   область и сам по себе не подрезается радиусом — по углам вылезают
   светлые «уши» от нескруглённой подложки. */
/* Фильтр вынесен на псевдоэлемент с маской, а не висит на самой капсуле.
   Chrome применяет backdrop-filter к прямоугольной области и НЕ подрезает её
   ни border-radius, ни overflow:hidden — по нижним углам вылезали светлые
   прямоугольные «уши». Маска на псевдоэлементе обрезает результат честно,
   а тень остаётся на родителе, иначе она обрезалась бы вместе с ним. */
/* Тень без большого отрицательного spread. Со spread -18px она была уже
   капсулы на 18px с каждой стороны: под скруглёнными концами тени не
   оставалось, и её прямой край читался как срез угла. Теперь тень повторяет
   форму и просто мягко уходит вниз. */
/* clip-path, а не overflow/mask: Chrome применяет backdrop-filter к
   прямоугольной области и не режет её ни радиусом, ни overflow — на пёстром
   фоне по углам оставались серые прямоугольные «уши» от десатурации.
   clip-path срабатывает уже ПОСЛЕ фильтра и обрезает результат честно.
   Внешняя тень при этом тоже срезается, поэтому глубину держит отдельный
   слой .rail-pill::after позади капсулы. */
/* Серые прямоугольные «уши» по углам капсул давала ВНЕШНЯЯ ТЕНЬ, а не
   backdrop-filter: её слой Chrome растеризует по bounding box и на пёстром
   фоне край читается как срез. Проверено перебором — clip-path, overflow,
   mask и снятие фильтра не помогали, снятие тени убрало артефакт сразу.
   Глубину теперь держат кромка и контраст, без внешней тени. */
.rail-pill,.profile-pill,.bell{position:relative;background:var(--glass-deep);
  backdrop-filter:blur(calc(var(--w-blur) * 1.15px)) var(--w-fx);
  -webkit-backdrop-filter:blur(calc(var(--w-blur) * 1.15px)) var(--w-fx);
  border:1px solid var(--edge);border-radius:99px;
  box-shadow:inset 0 1px 0 var(--edge-hi),inset 0 -1px 0 rgba(0,0,0,.25)}
/* Левая зона пустая, но существует: она держит навигацию по центру ленты. */
.rail-side{flex:1 1 0;min-width:0}
.rail-nav{display:flex;flex:0 1 auto;min-width:0;overflow-x:auto;
  scrollbar-width:none;align-items:center;justify-content:center}
/* Разделы живут в одной капсуле, а не россыпью по ленте: так группа читается
   как единый переключатель, а Home виден как её ось. */
.rail-pill{display:flex;align-items:center;gap:2px;padding:5px;border-radius:99px}
.rail-nav::-webkit-scrollbar{display:none}
.rail-btn{position:relative;width:38px;height:38px;flex:0 0 38px;border-radius:99px;display:grid;place-items:center;
  color:var(--on-mute);transition:color .18s var(--ease),background .18s var(--ease)}
.rail-btn:hover{color:var(--on);background:var(--fill)}
/* Навигация выделяется светом, не акцентом: лайм на экране один — на действии. */
.rail-btn.on{color:var(--on-solid-ink);background:var(--on-solid);box-shadow:0 3px 10px -3px rgba(0,0,0,.45)}
/* Home крупнее соседей и всегда с подложкой — это ось капсулы, а не рядовой пункт. */
.rail-home{width:46px;height:46px;flex:0 0 46px;margin:0 7px;color:var(--on);
  background:var(--film-4)}
.rail-home svg{width:21px;height:21px}
.rail-home:hover{background:var(--film-5);color:var(--on)}
.rail-btn svg{width:19px;height:19px}
.rail-dot{position:absolute;top:5px;right:5px;width:7px;height:7px;border-radius:99px;
  background:var(--r);border:2px solid #1a1d24}
/* Боковые зоны ленты симметричны по коробке, иначе навигация между ними
   встаёт не по центру рельса, а со сдвигом на разницу отступов. */
/* Профиль стоит слева и занимает своё место, а не распирается: распорка справа (.rail-side)
   держит капсулу разделов ровно по центру ленты. */
.rail-bot{display:flex;flex-direction:row;align-items:center;justify-content:flex-start;flex:1 1 0}
/* Профиль: фото, кто и в какой роли, отдельная кнопка настроек.
   Точка уведомлений переехала на фото — вместе с колокольчиком функция
   иначе просто исчезла бы. */
/* Вся капсула — одна кнопка: клик в любое место открывает настройки. */
.profile-pill{display:flex;align-items:center;gap:9px;padding:5px;border-radius:99px;max-width:100%;
  cursor:pointer;text-align:left;transition:background .18s var(--ease)}
.profile-pill:hover{background:var(--fill)}
.profile-pill.on{background:var(--fill-2)}
.profile-pill .pp-gear{display:grid;place-items:center;width:34px;height:34px;flex:0 0 34px;
  border-radius:99px;color:var(--on-mute)}
.profile-pill:hover .pp-gear{color:var(--on)}
.pp-ava{position:relative;width:34px;height:34px;flex:0 0 34px;border-radius:99px;
  display:grid;place-items:center;font-size:12px;font-weight:600;overflow:hidden;
  background:linear-gradient(150deg,#e8b06d,#c2637a);color:#fff}
.pp-ava img{width:100%;height:100%;object-fit:cover;border-radius:inherit}
.pp-dot{position:absolute;top:0;right:0;width:9px;height:9px;border-radius:99px;
  background:var(--r);box-shadow:0 0 0 2px #23262c}
.pp-who{display:flex;flex-direction:column;justify-content:center;min-width:0;line-height:1.25;
  padding-right:2px}
.pp-who b{font-size:12.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pp-who span{font-size:11px;color:var(--on-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Тот же вид, что у кнопок навигации: светлый круг означает «здесь я сейчас»,
   а настройки — обычное действие, поэтому фон появляется только на наведении. */
.pp-gear{width:34px;height:34px;flex:0 0 34px;border-radius:99px;display:grid;place-items:center;
  color:var(--on-mute);
  transition:color .18s var(--ease),background .18s var(--ease),transform .35s var(--spring)}
.pp-gear:hover{color:var(--on);background:var(--fill);transform:rotate(60deg)}
/* Открытое меню — лёгкая подложка, а не сильный светлый круг: тот означает
   «я здесь» у навигации, а шестерёнка не позиция, а переключатель. */
.pp-gear.on{color:var(--on);background:var(--fill-2);transform:rotate(60deg)}
.pp-gear svg{width:18px;height:18px}

/* Второй блок — панель */
/* Панель без собственного окна: заголовок, кубики и подпункты стоят прямо на сцене. Стекло
   здесь ничего не отделяло — рабочее поле справа и так своё окно, а два окна подряд читаются
   как две программы рядом. Внутренние карточки остались как были: они и держат структуру. */
.panel{width:var(--panel-w);flex:0 0 var(--panel-w);display:flex;flex-direction:column;min-height:0;
  background:none;border:0;box-shadow:none;overflow:hidden;
  /* Тень под буквами вместо подложки: фон сцены светлеет к верху, и без неё заголовок и подпись
     под ним тонут в небе. Окно ради читаемости возвращать не нужно — хватает тени. */
  text-shadow:0 1px 3px rgba(0,0,0,.55)}
/* Карточки и кнопки внутри стоят на своей заливке — там тень под буквами лишняя. */
.panel .pcard,.panel .thread,.panel .btn,.panel .cpill,.panel .folder{text-shadow:none}
/* Шапка панели — такой же стеклянный блок, как карточки под ней: без окна вокруг она
   осталась бы единственным местом, где текст лежит прямо на фотографии. */
.panel-top{padding:16px;margin:0 20px 10px;flex:0 0 auto;border-radius:var(--rad-l);
  background:var(--glass);border:1px solid var(--edge);
  backdrop-filter:blur(calc(var(--w-blur) * .8px)) var(--w-fx);
  -webkit-backdrop-filter:blur(calc(var(--w-blur) * .8px)) var(--w-fx)}
.panel-title{display:flex;align-items:center;justify-content:space-between;gap:10px;margin:0 0 14px}
/* Единственное лаймовое пятно на экране — первичное действие организатора. */
/* Выпадающий список внутри строки ввода — тот же рост и радиус, что у поля рядом. */
.fld-inline{background:var(--film-3);border:1px solid var(--line);color:var(--ink);
  border-radius:99px;padding:9px 12px;font:inherit;font-size:13px;max-width:190px}
.panel-cta{width:100%;justify-content:center;margin:0 0 16px;padding:11px 14px;font-size:13.5px}
.panel-title h1{margin:0;font-size:23px;font-weight:600;letter-spacing:-.025em}
/* Действия чата («Отложенные», «Групповая беседа», «Написать») — в шапке рядом с поиском, а не
   вторым рядом пилюль: тот ряд отнимал высоту у списка бесед (таск 152, рубеж 4). Отступ слева
   прижимает группу к поиску, иначе `space-between` шапки растащил бы её на середину. */
.chat-acts{display:flex;gap:6px;margin-left:auto;flex:0 0 auto}
.chat-acts .icon-btn.on{background:var(--on-solid);color:var(--on-solid-ink)}
/* Сводка раздела строкой, а не двумя плитками: шаблон «большое число + подпись»
   и так звучит в счётчиках папок и в кольцах — третий повтор здесь лишний. */
.panel-sum{margin:0;font-size:12.5px;line-height:1.55;color:var(--on-dim);text-wrap:balance}
.panel-sum b{color:var(--on);font-weight:600}

/* Три кнопки-папки */
/* Кубики делят ширину поровну — и это работало, пока их было три. В «Документах» их семь, и
   каждому доставалось по двадцать восемь пикселей: подписи превращались в «Мо зап», «Да гос»,
   «Рабо обла» — то есть раздел переставал называть свои разделы вообще.
   Теперь ряд переносится, а кубик не сжимается ниже читаемой ширины: лучше два ряда, чем семь
   нечитаемых столбиков. */
.folders{display:flex;flex-wrap:wrap;gap:6px;padding:0 20px 14px;flex:0 0 auto}
.folder{flex:1 1 84px;min-width:84px;padding:11px 10px;border-radius:var(--rad-s);text-align:left;
  background:var(--glass);border:1px solid var(--edge);color:var(--on-dim);
  transition:background .18s var(--ease),color .18s var(--ease),border-color .18s var(--ease)}
.folder:hover{background:var(--fill-2);color:var(--on)}
.folder.on{background:var(--on-solid);color:var(--on-solid-ink);border-color:transparent;
  box-shadow:0 4px 12px -4px rgba(0,0,0,.45)}
/* Подпись папки переносится, а не обрезается. Названий здесь десяток, все короткие и все свои —
   «Люди события» в одну строку не помещалось и превращалось в «Люди собы…», то есть кубик
   переставал называть то, что за ним. Многоточие уместно там, где текст чужой и длина
   непредсказуема (имя клиента, название площадки); в собственной навигации оно означает, что
   вёрстка не смогла показать своё же слово. */
/* Перенос ТОЛЬКО между словами. Разрыв слова — хоть дефисом («Ката-лог»), хоть без него
   («Катал ог») — читается хуже сокращения: глаз спотыкается и достраивает не то слово.
   Двухсловные названия («Люди события») переносятся и видны целиком; одиночное слово, которое
   не помещается, ужимается размером шрифта ниже, а не рвётся. */
.folder b{display:block;font-size:12px;font-weight:600;line-height:1.2;
  white-space:normal;word-break:keep-all;overflow-wrap:normal;hyphens:manual;
  /* Самое длинное одиночное название кубика — «Пиротехника»: при базовом кегле оно на пять
     пикселей шире кубика в узкой панели. Кегль в этих пределах подстраивается сам, вместо
     того чтобы обрезать слово, которое разделить не на чем. */
  font-size:clamp(10.5px, 1.05vw, 12px)}
.folder i{display:block;font-style:normal;font-size:17px;font-weight:600;letter-spacing:-.025em;margin-bottom:3px}
.folder.on i{color:var(--on-solid-ink)}

/* Получай остаток, а не отдавай свой (CLAUDE.md, «flex:1 1 0, а не auto»): при `1 1 auto`
   базис равен высоте содержимого, и папки с пилюлями фильтров сверху забирают всю высоту
   колонки себе, оставляя списку только то, что даёт `min-height`. Нижний край — 100px:
   нижняя граница диапазона CLAUDE.md, замер в `test/panel-list-flex.test.js`. */
.panel-list{flex:1 1 0;min-height:100px;overflow-y:auto;padding:2px 20px 20px;
  display:flex;flex-direction:column;gap:7px}
.panel-list::-webkit-scrollbar{width:6px}
.panel-list::-webkit-scrollbar-thumb{background:var(--film-5);border-radius:99px}
/* Блок настроек (правка владельца 4, 12.09.2026): группы обозначаются не заголовком, а тонкой
   рамкой вокруг пунктов — «окантовать блоки тоненькой полосой, а пункты пускай идут как есть».
   Один класс на панель десктопа и мобильный лист (.ms-list), чтобы раскладка не разъехалась.
   Пункт — группа вкладок, подпись под названием перечисляет их (правка 6). */
.settings-block{display:flex;flex-direction:column;gap:6px;padding:6px;
  border:1px solid var(--line);border-radius:var(--rad)}
.settings-block .ms-row{flex-direction:column;align-items:flex-start;justify-content:center;padding:8px 12px}
.settings-block .ms-row span{font-size:12px;color:var(--ink-3)}
/* Капсулы вкладок пункта — между шапкой и телом, вне прокрутки, теми же `.pj-caps .pjt`,
   что в окне события. Поля — как у .ws-top. */
.settings-caps{margin:0;padding:12px 24px 0}
.pcard{padding:13px 14px;border-radius:var(--rad-s);background:var(--glass);border:1px solid var(--edge);
  text-align:left;transition:background .18s var(--ease),border-color .18s var(--ease),transform .28s var(--spring)}
.pcard:hover{background:var(--fill-2);transform:translateX(2px)}
/* Строка проекта в списке «Мои проекты» / «В команде» — тот же вид,
   что у карточки-подпункта, но не кнопка: карточки в этом списке уже
   выбраны фильтром, кликать по ним для перехода некуда. */
.pcard-static{cursor:default}
.pcard-static:hover{background:var(--fill);transform:none}
/* Позиция и действие делят лайм, но не путаются: действие — заливка,
   позиция — метка. Три уровня «где я» различимы по весу, а не по цвету. */
/* Плёнка вместо подложки здесь не годилась: панель стоит прямо на фотографии, и активная
   карточка была «тень поверх снимка» — на тёмном участке сцены 2,64:1, на светлом сходила
   на нет. Плотная поверхность (--pop, единственная непрозрачная ступень темы) делает пункт
   различимым при ЛЮБОМ снимке, а не при удачном. Отсюда же отмена размытия: сквозь плотное
   размывать нечего. */
.pcard.on{position:relative;background:var(--pop);border-color:var(--stroke-hi);
  backdrop-filter:none;-webkit-backdrop-filter:none}
.pcard.on::before{content:'';position:absolute;left:9px;top:16px;width:6px;height:6px;
  border-radius:99px;background:var(--acc)}
.pcard b{display:block;font-size:13.5px;font-weight:600;margin-bottom:3px;letter-spacing:-.005em}
.pcard span{display:block;font-size:11.5px;line-height:1.45;color:var(--on-dim)}
/* Выделенная карточка — плёнка поверх панели, а не своя полярность: чернила общие. */
.pcard.on b{color:var(--ink)}

/* Затемнение и размытие окна теперь действуют и на элементы панели: они сами стеклянные,
   а не белые плёнки поверх фотографии. Один фильтр на все поверхности — ползунки «затемнение»
   и «размытие» двигают панель вместе с рабочим полем, а не мимо него. */
.panel .folder,.panel .pcard,.panel .thread,.panel .cpill{
  backdrop-filter:blur(calc(var(--w-blur) * .55px)) var(--w-fx);
  -webkit-backdrop-filter:blur(calc(var(--w-blur) * .55px)) var(--w-fx)}
/* Выбранное остаётся плотным: это метка «вы здесь», и просвечивать она не должна. */
.panel .folder.on,.panel .cpill.on{backdrop-filter:none;-webkit-backdrop-filter:none}

/* Подвала панели с ближайшим событием (`.panel-foot`) больше нет — снят по правке владельца 8
   (12.09.2026): «в ней вообще смысла нету». Низ панели настроек — одна кнопка «Выйти». */
.settings-foot{flex:0 0 auto;margin-top:auto;padding:0 20px calc(16px + env(safe-area-inset-bottom))}

/* ══ Панель «Навигатор» (этап 1 внедрения, stitch-designs/VNEDRENIE-PLAN.md) ══════════
   Решение владельца 12.09.2026: панель — своё окно оболочки, как рабочее поле: тот же радиус,
   рамка, тень и зазор. Раньше она стояла прямо на сцене, а шапка и кубики были стеклянными
   островками — встык с окном поля они давали ступеньку на границе скруглений. Правила ниже
   ПЕРЕБИВАЮТ объявления .panel/.panel-top/.folder выше при равной специфичности — потому
   и стоят после них. Имена каркаса (.panel, .folders, .folder, .panel-list) сохранены: их
   держат сторожа и admin.js с той же оболочкой; новые имена проверены на занятость grep-ом. */
.panel{padding-top:14px;text-shadow:none;
  background:var(--glass);border:1px solid var(--edge);border-radius:var(--rad-l);
  backdrop-filter:blur(calc(var(--w-blur) * .9px)) var(--w-fx);
  -webkit-backdrop-filter:blur(calc(var(--w-blur) * .9px)) var(--w-fx);
  box-shadow:0 22px 50px -20px rgba(0,0,0,.6),inset 0 1px 0 var(--edge-hi)}
/* Окно панели режет содержимое краем (overflow:hidden выше) — кроме момента, когда открыт
   выпадающий список: он позиционируется абсолютно и иначе резался бы. Снимать обрезку
   насовсем нельзя: тесная панель (баннер почты + семь строк отбора) вылезла бы за скругление. */
.panel:has(.dd-list){overflow:visible}
.panel-top{padding:0 18px 8px;margin:0;border:0;border-radius:0;background:none;
  backdrop-filter:none;-webkit-backdrop-filter:none}
.panel-title{margin:0 0 10px}
.panel-title h1{font-size:21px;font-weight:650;letter-spacing:-.03em;min-width:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.panel-top .icon-btn{width:32px;height:32px;flex:0 0 32px;background:var(--glass);
  border:1px solid var(--edge)}
.panel-top .icon-btn:hover{background:var(--fill-2)}
.panel-cta{height:36px;padding:0 14px;border-radius:11px;margin:0 0 10px;font-size:13.5px}
.panel-top > .panel-sum{font-size:11.5px;color:var(--on-mute);margin:0 0 2px}

/* Строка поиска панели. */
.sfield{display:flex;align-items:center;gap:7px;margin:0 18px 10px;padding:0 8px 0 12px;height:34px;
  border-radius:10px;background:var(--film-2);border:1px solid var(--line);flex:0 0 auto}
.sfield>svg{width:14px;height:14px;color:var(--on-mute);flex:0 0 auto}
.sfield input{flex:1 1 auto;min-width:0;border:0;background:none;outline:none;color:var(--ink);
  font:inherit;font-size:13px}
.sfield input::placeholder{color:var(--on-mute)}

/* Кубики раздела → строки с числом справа. Одна строка = одна кнопка; выбранная помечена
   маркером-полоской слева, а не заливкой «вы здесь»: так же выглядят строки внутри
   выпадающих списков (.nrow) — один вид на всю навигацию. */
.folders{flex-direction:column;flex-wrap:nowrap;gap:0;padding:0 10px 4px}
.folder,.nrow{flex:0 0 auto;min-width:0;width:100%;display:flex;align-items:center;gap:9px;
  padding:7px 9px;border-radius:9px;border:0;background:none;color:var(--on-dim);
  font:inherit;font-size:13px;text-align:left;cursor:pointer;
  transition:background .14s,color .14s;box-shadow:none}
.panel .folder{backdrop-filter:none;-webkit-backdrop-filter:none}
.folder:hover,.nrow:hover{background:var(--film-2);color:var(--on)}
.folder.on,.nrow.on{background:var(--film-3);color:var(--on);font-weight:600;border-color:transparent}
.folder b,.nrow b{flex:1 1 auto;min-width:0;display:block;font-size:13px;font-weight:inherit;
  line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}
.folder i,.nrow i{order:2;flex:0 0 auto;display:block;margin:0;font-style:normal;font-size:12px;
  font-weight:500;letter-spacing:0;color:var(--on-mute);font-variant-numeric:tabular-nums;
  max-width:52%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.folder.on i,.nrow.on i{color:var(--on-dim)}
.nrow i.act{color:var(--on);font-weight:600}
.nrow u{order:3;flex:0 0 auto;text-decoration:none;font-size:13px;color:var(--on-mute)}
/* Маркер выбранной строки — элемент, а не ::before: на этапе 4 его повезёт FLIP. */
.mark{width:3px;height:15px;border-radius:99px;background:var(--on);margin-left:-5px;
  margin-right:1px;flex:0 0 auto;transform-origin:0 0}
/* Место раздела (корзина): открывается, а не отбирает — стоит после кубиков через зазор. */
.folder.place{margin-top:4px}
.nsep{height:1px;background:var(--line);margin:4px 14px 8px;flex:0 0 auto}
/* Вложенная кнопка в строке (звезда закрепления, крест удаления фильтра) — как у пилюль:
   диспетчер берёт ближайший data-act, поэтому нажатие по значку не открывает саму строку. */
.nrow .pin,.nrow .x{order:2;flex:0 0 auto;font-style:normal;font-size:12px;opacity:.5;
  padding:0 3px;cursor:pointer}
.nrow .pin:hover,.nrow .x:hover,.nrow .pin.on{opacity:1}
.nrow-reset{color:var(--tag-r-ink);font-weight:600;margin-top:2px;border-top:1px solid var(--line);
  border-radius:0;padding-top:9px}
.nrow-reset:hover{color:var(--tag-r-ink)}

/* «Показать ещё N» вместо портянки: список отдаёт окну ровно столько строк, сколько в него
   влезает, остальное раскрывается нажатием (правило владельца: содержимое подгоняется под
   окно, прокрутка — последнее средство). */
.more{flex:0 0 auto;margin-top:2px;padding:9px;border-radius:10px;border:1px dashed var(--line);
  background:none;cursor:pointer;font:inherit;font-size:12.5px;font-weight:600;color:var(--on-dim);
  transition:background .14s,color .14s;text-align:center}
.more:hover{background:var(--film-2);color:var(--on)}
.folders .more{margin:2px 9px 0;padding:6px}

/* Блок «Отбор»: параметры стоят строками в самой панели, выпадающим остаётся выбор значения.
   Два выпадающих подряд (параметр внутри списка) читались как лишний слой. */
/* Блок сжимаемый: в тесной панели (баннер почты сверху, восемь строк отбора у площадок) он
   отдаёт высоту и прокручивается сам, а не режется краем окна — последняя строка иначе
   пропадала молча. Открытый выпадающий снимает обрезку: он позиционирован абсолютно. */
/* Правка владельца 2 (12.09.2026): «сливается воедино, ничего не понятно, как что сортировать».
   Блок — самостоятельный орган управления, ВСТАВКА в панель: плёнка, тонкая рамка и утопленная
   тень. Не стекло с --edge, как у карточек списка (.pcard): тот же материал сделал бы отбор
   ещё одной карточкой, а список должен остаться главным. Отступы подобраны так, что текст
   строк стоит на тех же 19 px от края, что и строки навигации (10 + 9): рамка на 2 px шире. */
.filt{margin:0 8px 8px;padding:3px 1px 4px;flex:0 1 auto;min-height:0;overflow-y:auto;
  border-radius:12px;background:var(--film-1);border:1px solid var(--line);
  box-shadow:inset 0 1px 3px rgba(0,0,0,.16)}
.filt:has(.dd-list){overflow:visible}
.filt>.dd-h{color:var(--on-dim)}
.filt::-webkit-scrollbar{width:6px}
.filt::-webkit-scrollbar-thumb{background:var(--film-5);border-radius:99px}
.dd-h{display:flex;align-items:center;gap:6px;padding:6px 9px 4px;font-size:10.5px;font-weight:650;
  letter-spacing:.05em;text-transform:uppercase;color:var(--on-mute)}
.fline{display:flex;align-items:center;gap:8px;padding:2px 9px;border-radius:9px;min-height:34px;
  transition:background .14s}
.fline:hover{background:var(--film-2)}
.fline>span{flex:0 0 auto;font-size:13px;color:var(--on-dim)}
.fline .dd{margin-left:auto;min-width:0;max-width:64%}
/* Параметр с единственной альтернативой — переключатель, а не список: выбирать одно из двух
   через открытие списка значит просить два нажатия там, где хватает одного. */
.fline-sw{width:100%;border:0;background:none;cursor:pointer;font:inherit;text-align:left}
.fline-sw.on>span{color:var(--on);font-weight:600}
.tgl{margin-left:auto;flex:0 0 40px;width:40px;height:23px;border-radius:99px;
  background:var(--fill-2);position:relative;transition:background .18s var(--ease)}
.tgl i{position:absolute;top:3px;left:3px;width:17px;height:17px;border-radius:99px;
  background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.3);transition:transform .18s var(--ease)}
.tgl.on{background:var(--acc)}
.tgl.on i{transform:translateX(17px)}
.said{display:block;margin:0 18px 8px;font-size:11.5px;line-height:1.45;color:var(--on-dim);
  flex:0 0 auto}
.filt .said{margin:0 9px 6px}

/* Выпадающий список — один компонент на всю панель: кнопка с текущим значением, под ней
   значения одного параметра. Список — плотная поверхность (--pop), а не стекло: сквозь стекло
   просвечивали бы строки под ним. */
.dd{position:relative;flex:0 0 auto;min-width:0}
.dd-btn{display:inline-flex;align-items:center;gap:5px;max-width:100%;padding:0 4px;height:30px;
  border:0;border-radius:8px;background:none;cursor:pointer;font:inherit;font-size:12.5px;
  font-weight:550;color:var(--on-dim);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  transition:background .14s,color .14s}
.dd-btn:hover{background:var(--film-2);color:var(--on)}
.dd-btn.act{font-weight:650;color:var(--on)}
.dd-btn i{font-style:normal;font-size:10px;opacity:.65;flex:0 0 auto}
.dd-list{position:absolute;top:calc(100% + 6px);left:0;min-width:100%;max-width:320px;z-index:30;
  max-height:min(430px,62vh);overflow-y:auto;padding:6px;border-radius:14px;background:var(--pop);
  border:1px solid var(--edge);box-shadow:0 24px 60px -22px rgba(0,0,0,.6)}
.dd-r .dd-list{left:auto;right:0;min-width:250px}
/* У нижнего края окна список встаёт вверх от кнопки (класс ставит render() по замеру). */
.dd-list.dd-up{top:auto;bottom:calc(100% + 6px)}
.dd-list::-webkit-scrollbar{width:6px}
.dd-list::-webkit-scrollbar-thumb{background:var(--film-5);border-radius:99px}
.dd-list .city-field{margin:0 0 6px}
.dd-list .city-input{width:100%;box-sizing:border-box}
.hint{margin:6px 9px 2px;font-size:11.5px;line-height:1.45;color:var(--on-mute)}
.dd-list .cpill-new{display:block;width:calc(100% - 4px);margin:4px 2px;border-radius:9px}

/* Подвкладки внутри кубика (экраны агентства) — подчёркиванием, не кубиками. */
.tabs2{display:flex;flex-wrap:wrap;gap:0 2px;padding:0 18px;margin:0 0 10px;flex:0 0 auto;
  border-bottom:1px solid var(--line)}
.tabs2 button{flex:0 0 auto;position:relative;padding:7px 9px 9px;border:0;background:none;cursor:pointer;
  font:inherit;font-size:12.5px;font-weight:550;color:var(--on-mute);white-space:nowrap;
  border-bottom:2px solid transparent;margin-bottom:-1px}
.tabs2 button:hover{color:var(--on)}
.tabs2 button.on{color:var(--on);font-weight:650}
/* Подчёркивание открытой подвкладки — элемент `.mark`, а не цвет рамки: между перерисовками
   его везёт FLIP (этап 4), а рамка так не поедет. */
.tabs2 .mark{position:absolute;left:9px;right:9px;bottom:-1px;width:auto;height:2px;margin:0;
  border-radius:99px;transform-origin:0 0}

.panel-list{padding:2px 18px 18px}
/* Место под маркер выбора (.pcard.on::before, полоса 9–15 px) зарезервировано у ВСЕХ карточек
   панели, а не только у выбранной: иначе заголовок прыгал бы при каждом нажатии, а без
   резерва точка налезала на первую букву (правка владельца 12.09.2026, «●Сводка»). Прежний
   padding-left:22px у .pcard.on здесь не работал вовсе — это правило стоит позже и той же
   специфичности. Горящим (.hl-*, border-left 3px) маркер не мешает: он отсчитан от края
   рамки и едет вместе с текстом. */
.panel .pcard{border-radius:12px;padding:11px 13px 11px 21px}

/* ══ Дашборд «Домой» (этап 3 внедрения, stitch-designs/VNEDRENIE-PLAN.md) ═══════════
   Раздел «Домой» — не список, а сводка: панели слева нет, дашборд занимает всё рабочее поле.
   Приветствие, дата и «Новая заявка» живут в шапке окна (.ws-top). Иерархия держится не
   рамками, а размером и цветом: акцентный блок один («Что горит»), крупная цифра одна на
   карточку, семантический цвет только там, где он означает состояние. Имена `.pn-*`
   проверены на занятость (grep '^\.pn-' — ноль совпадений до этого блока). */
.ws-top .home-ava{width:40px;height:40px;flex:0 0 40px}
.ws-top .home-ava span{font-size:14px}
.ws-top .home-hi-txt p{margin:1px 0 0;font-size:12px;color:var(--on-mute)}
.ws-top .home-hi-txt h2{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pn-dash{display:grid;gap:12px;grid-template-columns:repeat(12,1fr);align-content:start;margin-bottom:14px}
.pn-dash section{background:var(--glass);border:1px solid var(--edge);border-radius:16px;
  padding:14px 16px;min-width:0;box-shadow:none;backdrop-filter:none;-webkit-backdrop-filter:none}
.pn-dash h3{margin:0 0 10px;font-size:11px;font-weight:650;letter-spacing:.06em;
  text-transform:uppercase;color:var(--on-mute)}
/* Блок с адресом — кнопка: курсор, фокус клавиатуры, нажатие. Внутри бывают свои строки-кнопки
   (li) — вложенные <button> запрещены разметкой, поэтому role="button" на div/li. */
.pn-dash [role="button"]{cursor:pointer}
.pn-dash [role="button"]:focus-visible{outline:2px solid var(--b,#1f5cad);outline-offset:2px}
.pn-dash section[role="button"]:hover{border-color:var(--line)}

/* Плитка показателя: число, изменение к прошлому году, подпись, мелкий график. Цвет дельты
   семантический — зелёное «лучше», красное «хуже». */
.pn-kpi{grid-column:span 12;display:grid;gap:8px;
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));background:none!important;
  border:0!important;padding:0!important}
.pn-kpi>div{background:var(--glass);border:1px solid var(--edge);border-radius:14px;padding:11px 13px;min-width:0}
.pn-kpi b{display:block;font-size:20px;font-weight:650;letter-spacing:-.03em;line-height:1.15;
  font-variant-numeric:tabular-nums;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pn-kpi span{display:block;font-size:11.5px;color:var(--on-mute);margin-top:3px;line-height:1.3}
.pn-kpi .pn-delta{display:inline-flex}
.pn-delta{display:inline-flex;align-items:center;gap:3px;margin-top:6px;padding:2px 7px;
  border-radius:99px;font-size:11px;font-weight:650;font-variant-numeric:tabular-nums}
.pn-delta.up{background:var(--tag-g-bg);color:var(--tag-g-ink)}
.pn-delta.down{background:var(--tag-r-bg);color:var(--tag-r-ink)}
.pn-delta.flat{background:var(--film-3);color:var(--on-mute)}
.pn-spark{fill:none;stroke-width:1.6;stroke-linejoin:round}

/* Единственный акцентный блок: то, что требует действия сегодня. */
.pn-d-hot{grid-column:span 7;background:var(--tag-r-bg);border-color:transparent}
.pn-d-hot h3{color:var(--tag-r-ink)}
.pn-d-hot ul{margin:0;padding:0;list-style:none;display:grid;gap:8px}
.pn-d-hot li{display:flex;align-items:baseline;gap:10px;font-size:13.5px;color:var(--ink);
  border-radius:8px;margin:0 -6px;padding:2px 6px}
.pn-d-hot li:hover{background:rgba(255,255,255,.35)}
.pn-d-hot li b{font-size:19px;font-weight:650;letter-spacing:-.02em;color:var(--tag-r-ink);
  font-variant-numeric:tabular-nums;min-width:58px}
.pn-d-hot li.ok b{color:var(--tag-g-ink)}
.pn-d-hot li span{color:var(--on-dim)}
.pn-d-hot.calm{background:var(--glass);border-color:var(--edge)}
.pn-d-hot.calm h3{color:var(--on-mute)}
.pn-d-hot p{margin:8px 0 0;font-size:12.5px;color:var(--on-dim)}

/* Деньги: кольцо доли полученного, рядом крупное число. */
.pn-d-money{grid-column:span 5}
.pn-d-big{font-size:24px;font-weight:650;letter-spacing:-.035em;line-height:1;
  font-variant-numeric:tabular-nums}
.pn-d-money p{margin:6px 0 0;font-size:12.5px;color:var(--on-dim)}
.pn-ring{display:flex;align-items:center;gap:14px}
.pn-ring svg{flex:0 0 78px;width:78px;height:78px}
.pn-ring-bg{fill:none;stroke:var(--film-3);stroke-width:9}
.pn-ring-on{fill:none;stroke:var(--tag-g-ink);stroke-width:9;stroke-linecap:round;
  transform:rotate(-90deg);transform-origin:50% 50%}
.pn-ring-txt{font-size:17px;font-weight:650;fill:var(--ink);text-anchor:middle;
  dominant-baseline:central}

/* Ближайшее событие — карточка с готовностью полосой. */
.pn-d-next{grid-column:span 7}
.pn-d-next .pn-d-when{font-size:13px;color:var(--on-mute);margin:0 0 4px}
.pn-d-next h4{margin:0 0 10px;font-size:17px;font-weight:650;letter-spacing:-.02em}
.pn-bar2{height:6px;border-radius:99px;background:var(--film-3);margin:0 0 8px;overflow:hidden}
.pn-bar2 i{display:block;height:100%;border-radius:99px;background:var(--tag-g-ink)}
.pn-d-next p.pn-note2{margin-top:4px}
.pn-d-next .btn{margin-top:10px}

/* Задачи на сегодня: точка состояния, текст, срок справа. */
.pn-d-tasks{grid-column:span 5}
.pn-d-tasks ul{margin:0;padding:0;list-style:none;display:grid;gap:9px}
.pn-d-tasks li{display:flex;align-items:flex-start;gap:9px;font-size:13px;line-height:1.35}
.pn-d-tasks li em{font-style:normal;flex:0 0 auto;width:7px;height:7px;border-radius:99px;
  background:var(--film-5);margin-top:5px}
.pn-d-tasks li.hot em{background:var(--tag-r-ink)}
.pn-d-tasks li span{color:var(--on-mute);margin-left:auto;flex:0 0 auto;font-size:12px}

/* Графики — своим SVG: подписи и сетка слушаются токенов темы. */
.pn-chart{grid-column:span 7}
.pn-chart2{grid-column:span 5}
.pn-chart svg,.pn-chart2 svg{display:block;width:100%;height:auto;overflow:visible}
.pn-note2{margin:8px 0 0;font-size:11.5px;line-height:1.45;color:var(--on-mute)}
.pn-g-grid{stroke:var(--line);stroke-width:1}
.pn-g-bar{fill:var(--film-4)}
.pn-g-bar.on{fill:var(--on-solid)}
.pn-g-zero{fill:var(--film-5)}
.pn-g-lbl{font-size:10px;fill:var(--on-mute)}
.pn-g-val{font-size:10.5px;fill:var(--on-dim);font-weight:600}

/* Источники заявок: полоса длиной в долю, справа — конверсия в события. */
.pn-src{grid-column:span 6}
.pn-src ul{margin:0;padding:0;list-style:none;display:grid;gap:9px}
.pn-src li{display:grid;grid-template-columns:1fr auto;gap:2px 10px;font-size:12.5px}
.pn-src li b{font-weight:600}
.pn-src li em{font-style:normal;color:var(--on-mute);font-size:11.5px;
  font-variant-numeric:tabular-nums}
.pn-src-bar{grid-column:1 / -1;height:5px;border-radius:99px;background:var(--film-3);overflow:hidden}
.pn-src-bar i{display:block;height:100%;border-radius:99px;background:var(--on-solid)}

/* Воронка: этапы сверху вниз, ширина — доля заявок на этапе. */
.pn-funnel{grid-column:span 6}
.pn-funnel ol{margin:0;padding:0;list-style:none;display:grid;gap:7px}
.pn-funnel li{display:grid;grid-template-columns:1fr auto;align-items:center;gap:8px;font-size:12.5px}
.pn-funnel .pn-fb{grid-column:1 / -1;height:22px;border-radius:7px;background:var(--film-3);
  position:relative;overflow:hidden;display:block}
.pn-funnel .pn-fb i{display:block;height:100%;background:var(--tag-b-bg);border-right:2px solid var(--b,#1f5cad)}
.pn-funnel .pn-fb span{position:absolute;left:9px;top:0;line-height:22px;font-size:11.5px;
  color:var(--ink);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:calc(100% - 40px)}
.pn-funnel .pn-fb em{position:absolute;right:9px;top:0;line-height:22px;font-size:11px;
  font-style:normal;color:var(--on-mute);font-variant-numeric:tabular-nums}

/* Загрузка по неделям: где события идут подряд. */
.pn-weeks{grid-column:span 5}
.pn-weeks .pn-wrow{display:flex;gap:3px;margin-top:6px}
.pn-weeks i{flex:1 1 0;height:26px;border-radius:4px;background:var(--film-3)}
.pn-weeks i.w1{background:var(--tag-g-bg)}
.pn-weeks i.w2{background:var(--tag-a-bg)}
.pn-weeks i.w3{background:var(--tag-r-bg)}
.pn-weeks p{margin:8px 0 0;font-size:11.5px;color:var(--on-mute)}

/* Нижняя лента итогов года. */
.pn-season{grid-column:span 12;display:grid;gap:0;
  grid-template-columns:repeat(auto-fit,minmax(160px,1fr))}
.pn-season>div{padding:2px 16px;border-left:1px solid var(--line);min-width:0}
.pn-season>div:first-child{border-left:0;padding-left:4px}
.pn-season b{display:block;font-size:19px;font-weight:650;letter-spacing:-.03em;
  font-variant-numeric:tabular-nums}
.pn-season span{display:block;font-size:11.5px;color:var(--on-mute);margin-top:3px}

/* ══ Движение (этап 4 внедрения, stitch-designs/ZADANIE-ANIMACII.md) ═══════════════════
   Перенесено из утверждённого прототипа primerka-panel.src.html. Правила: анимируются только
   transform, opacity и stroke-dashoffset — ничего, что двигает раскладку. Входы стоят под
   `.pn-anim`: класс ставит render() на #app только когда сменился ключ содержимого (раздел,
   кубик, подвкладка, «Домой»), либо на секцию дашборда, которой не было в прошлой разметке, —
   поэтому отбор, тумблер и живые обновления с сервера волну не запускают. Все входы с
   fill-mode backwards: после окончания элемент живёт своим стилем, и hover с transform-ом
   работает. Порядковый номер --i ставит render() и ограничивает двенадцатью: при шаге 24 мс
   последний элемент стартует не позже 288 мс — длинный список не «собирается на глазах». */
@keyframes pn-rise{from{opacity:0;transform:translateY(6px)}}
@keyframes pn-pop{from{opacity:0;transform:scale(.92) translateY(-4px)}}
@keyframes pn-fade{to{opacity:0}}
@keyframes pn-up{from{transform:scaleY(0)}}
@keyframes pn-wide{from{transform:scaleX(0)}}
@keyframes pn-draw{from{stroke-dashoffset:1}}
@keyframes pn-ring{from{stroke-dashoffset:var(--d,1)}}
@keyframes pn-pulse{0%{transform:scale(1);opacity:.6}70%,100%{transform:scale(3.2);opacity:0}}

/* 1. Волна появления: карточки списка панели, секции и плитки дашборда, строки внутри блоков. */
.pn-anim .panel-list>*,.pn-anim .pn-dash>section,section.pn-anim,.pn-anim .pn-kpi>div,
.pn-anim .pn-season>div,.pn-anim .pn-d-hot li,.pn-anim .pn-d-tasks li,
.pn-anim .pn-src li,.pn-anim .pn-funnel li{
  animation:pn-rise .34s cubic-bezier(.2,.8,.2,1) backwards;animation-delay:calc(var(--i,0)*24ms)}

/* 3. Графики — один раз при появлении. Столбцы растут снизу (transform-box:fill-box — точка
   масштабирования у самого прямоугольника, а не у холста), спарклайн прочерчивается
   (pathLength="1" в разметке: длину пути мерить не надо), кольцо заполняется от нуля
   (--d — стартовый сдвиг штриха, равный доле), полосы разъезжаются от левого края. */
.pn-anim .pn-g-bar,.pn-anim .pn-g-zero,.pn-anim .pn-wrow i{transform-box:fill-box;transform-origin:50% 100%;
  animation:pn-up .55s cubic-bezier(.2,.8,.2,1) backwards;animation-delay:calc(.1s + var(--i,0)*30ms)}
.pn-anim .pn-g-val{animation:pn-rise .3s backwards;animation-delay:calc(.5s + var(--i,0)*30ms)}
.pn-anim .pn-spark{stroke-dasharray:1;animation:pn-draw .9s ease-out .15s backwards}
.pn-anim .pn-ring-on{animation:pn-ring .9s cubic-bezier(.2,.8,.2,1) .15s backwards}
.pn-src-bar i,.pn-fb i,.pn-bar2 i{transform-origin:0 50%}
.pn-anim .pn-src-bar i,.pn-anim .pn-fb i,.pn-anim .pn-bar2 i{
  animation:pn-wide .55s cubic-bezier(.2,.8,.2,1) backwards;animation-delay:calc(.15s + var(--i,0)*30ms)}

/* 5. Отклик на нажатие: :active срабатывает на pointerdown — раньше клика. Сжатие быстрое,
   возврат пружиной (кривая с перелётом). Тумблер ездит бегунком (`.tgl i` — transition выше). */
.folder,.nrow,.more,.dd-btn,.tabs2 button,.fline-sw,.panel .pcard,.panel .thread{
  transition:transform .25s cubic-bezier(.34,1.56,.64,1),background .14s,color .14s}
.folder:active,.nrow:active,.more:active,.dd-btn:active,.tabs2 button:active,.fline-sw:active,
.panel .pcard:active,.panel .thread:active{transform:scale(.98);transition-duration:.06s}

/* 6. Выпадающий список раскрывается от своей кнопки; класс pn-open ставит render() только при
   открытии — перерисовка с тем же открытым списком его заново не «открывает». Уходящий список —
   призрак: клон по прежним координатам поверх нового содержимого, складывается тем же путём. */
.dd-list{transform-origin:top left}
.dd-r .dd-list{transform-origin:top right}
.dd-list.dd-up{transform-origin:bottom left}
.dd-r .dd-list.dd-up{transform-origin:bottom right}
.dd-list.pn-open{animation:pn-pop .16s cubic-bezier(.2,.8,.2,1) backwards}
.pn-ghost{position:fixed;z-index:40;overflow:hidden;pointer-events:none;box-sizing:border-box;
  animation:pn-pop .14s ease-in reverse forwards}
.pn-ghost>*{position:static;flex:none;width:100%;box-sizing:border-box;min-width:0;max-width:none;
  height:auto;max-height:none;overflow:visible}

/* 7. Пульс «что горит» — только при просрочках (класс pn-live ставит homeBurning по данным). */
.pn-d-hot h3{position:relative;padding-left:15px}
.pn-d-hot h3::before,.pn-d-hot h3::after{content:'';position:absolute;left:0;top:50%;width:7px;height:7px;
  margin-top:-3.5px;border-radius:99px;background:var(--tag-r-ink)}
.pn-d-hot.calm h3::before{background:var(--on-mute)}
.pn-d-hot h3::after{opacity:0}
.pn-d-hot.pn-live h3::after{animation:pn-pulse 2.4s ease-out infinite}

/* Д. Кликабельные блоки дашборда: подъём под курсором, тень через opacity псевдоэлемента
   (box-shadow не анимируем), нажатие. Некликабельное этих правил не получает. */
.pn-dash [role="button"]{position:relative;transition:transform .12s}
.pn-dash section[role="button"]::after,.pn-kpi>div[role="button"]::after{content:'';position:absolute;
  inset:-1px;border-radius:inherit;box-shadow:0 14px 30px -14px rgba(0,0,0,.45);opacity:0;
  transition:opacity .12s;pointer-events:none}
.pn-dash section[role="button"]:hover,.pn-kpi>div[role="button"]:hover,
.pn-season>div[role="button"]:hover{transform:translateY(-2px)}
.pn-dash section[role="button"]:hover::after,.pn-kpi>div[role="button"]:hover::after{opacity:1}
.pn-dash section[role="button"]:active,.pn-kpi>div[role="button"]:active{transform:translateY(0) scale(.99);
  transition-duration:.06s}
.pn-dash li[role="button"]:hover{transform:translateX(3px)}
.pn-dash li[role="button"]:active{transform:translateX(3px) scale(.98)}

/* Обязательный режим: движения сняты, всё показывается сразу. Глобальное правило ниже
   укорачивает анимации до .01ms, но бесконечный пульс при этом мерцал бы — снимаем явно. */
@media (prefers-reduced-motion:reduce){
  .pn-anim *,section.pn-anim,.pn-ghost,.dd-list.pn-open,.pn-d-hot.pn-live h3::after{animation:none!important}
}

/* Ряды сходятся в 12 колонок при любом наборе блоков: «Задачи на сегодня» бывают, а бывает
   их нет (дел со сроком нет — блока нет), и соседи подстраиваются селектором по наличию,
   а не оставляют пустую колонку. Правила стоят ПОСЛЕ базовых ширин — иначе те перебивают. */
@media (min-width:1101px) and (max-width:1239px){
  .pn-d-next:not(:has(+ .pn-d-tasks)){grid-column:span 12}
}
@media (min-width:1101px){
  .pn-chart:not(:has(~ .pn-weeks)){grid-column:span 12}
}
@media (min-width:1240px){
  .pn-d-hot{grid-column:span 4}
  .pn-d-money{grid-column:span 4}
  .pn-d-next{grid-column:span 4}
  .pn-d-tasks{grid-column:span 5}
  .pn-d-tasks~.pn-weeks,.pn-d-tasks~.pn-src,.pn-d-tasks~.pn-funnel{grid-column:span 4}
}
@media (max-width:1100px){
  .pn-d-hot,.pn-d-money,.pn-d-next,.pn-d-tasks,.pn-chart,.pn-chart2{grid-column:span 12}
  .pn-src,.pn-funnel,.pn-weeks{grid-column:span 6}
}
@media (max-width:720px){
  .pn-src,.pn-funnel,.pn-weeks{grid-column:span 12}
  .pn-season>div{padding:4px 10px}
  .ws-top .home-hi-txt p{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  /* На телефоне у кнопок шапки остаются значки: подпись «Новая заявка» отъедала приветствие
     до «Добры…» — а имя человека здесь и есть главное. */
  .home-ws .ws-top .btn-acc span{display:none}
  .home-ws .ws-top .btn-acc{padding:8px 11px}
  /* Аватар в шапке на телефоне не помещается рядом с именем и тремя кнопками (375 px):
     фотография человека и так стоит в нижней рельсе, имя важнее повтора. */
  .home-ws .ws-top .home-ava{display:none}
}

/* Третий блок — рабочее поле. Плотная бумага, не стекло. */
.ws{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;border-radius:var(--rad-l);overflow:hidden;
  background:var(--paper);color:var(--ink);border:1px solid var(--edge);
  backdrop-filter:blur(calc(var(--w-blur) * 1.45px)) var(--w-fx);-webkit-backdrop-filter:blur(calc(var(--w-blur) * 1.45px)) var(--w-fx);
  box-shadow:0 22px 50px -20px rgba(0,0,0,.6),inset 0 1px 0 var(--edge-hi)}
.ws-top{flex:0 0 auto;display:flex;align-items:center;gap:12px;padding:15px 24px;
  border-bottom:1px solid var(--line);background:var(--film-1)}
.ws-top h2{margin:0;font-size:20px;font-weight:600;letter-spacing:-.025em}
/* Название экрана и относящиеся к нему кнопки — в одной строке, слева. Кнопки беседы
   («Участники», «Покинуть») стоят рядом с её именем: они про эту беседу, а не про раздел. */
.ws-title-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;min-width:0}
.btn-sm{padding:5px 11px;font-size:12px}
.btn-sm svg{width:13px;height:13px}
.crumb{font-size:12px;color:var(--ink-3);margin-bottom:1px}
/* Маркер срочности — точка, а не эмодзи и не цветной border-left. */
.dotmark{width:7px;height:7px;flex:0 0 7px;border-radius:99px;background:var(--ink-3);margin-left:5px}
.dotmark-hot{background:var(--r);box-shadow:0 0 0 3px color-mix(in srgb,var(--r) 20%,transparent)}
/* Рабочее поле — обычный поток блоков сверху вниз.
   Сеткой оно уже было: repeat(auto-fit, minmax(min(100%,400px),1fr)) в Safari 18 давал узкие
   дорожки, блок .grid-2 попадал в одну из них — а сколько колонок делать внутри себя, он
   спрашивает у ширины ПОЛЯ (@container ws), не у своей. Поле широкое, блок узкий: две колонки
   по 200px, содержимое половин друг на друге. В Chrome этого не было видно вовсе.
   Раскладку по ширине делает сам экран через .grid-2 — там ширина блока равна ширине поля,
   и запрос отвечает правду. */
.ws-body{flex:1 1 auto;overflow-y:auto;container:ws / inline-size;
  padding:calc(26px - var(--pad-c)) calc(24px - var(--pad-c)) calc(32px - var(--pad-c))}
.ws-body::-webkit-scrollbar{width:9px}
.ws-body::-webkit-scrollbar-thumb{background:var(--film-5);border-radius:99px}

/* Кнопки */
/* Кнопка скорее станет выше, чем «съест» слово: подпись действия — единственное, по чему
   человек понимает, что произойдёт после нажатия. Обрезанный глагол («Сохран…», «Отмет…»)
   выглядит как рабочая кнопка и читается неверно. */
/* Перенос ТОЛЬКО между словами — то же правило, что у подписи кубика. `overflow-wrap:anywhere`
   стояло здесь ради длинного слова, но давало ровно обратное: слово рвалось по буквам, а заодно
   минимальная ширина кнопки становилась шириной одной буквы, и flex ужимал её до столбика —
   «Завершить сеансы» в панели уведомлений выходила 45×113 даже на экране 1440. */
.btn{display:inline-flex;align-items:center;gap:7px;padding:8px 14px;border-radius:99px;
  font-size:13px;font-weight:500;transition:background .18s var(--ease),color .18s var(--ease);
  white-space:normal;text-align:center;
  word-break:keep-all;overflow-wrap:normal;hyphens:manual}
.btn svg{width:15px;height:15px}
/* Заблокированная кнопка обязана выглядеть заблокированной. Без этого правила `disabled`
   виден только курсору: кнопка «Составляю…» и кнопка при исчерпанном лимите оставались
   яркими, и человек жал их впустую, считая, что не попал. */
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn-acc{background:var(--acc);color:var(--acc-ink);font-weight:600}
.btn-acc:hover{background:#c6ea2f}
.btn-ghost{background:var(--fill);color:var(--on)}
.btn-ghost:hover{background:var(--fill-2)}
.btn-ink{background:var(--on-solid);color:var(--on-solid-ink)}
.btn-ink:hover{background:#fff}
.btn-quiet{background:var(--film-3);color:var(--ink-2)}
.btn-quiet:hover{background:var(--film-5);color:var(--ink)}
.icon-btn{width:34px;height:34px;border-radius:99px;display:grid;place-items:center;background:var(--fill);color:var(--on-dim);
  transition:background .18s var(--ease),color .18s var(--ease)}
.icon-btn:hover{background:var(--fill-2);color:var(--on)}
.icon-btn svg{width:16px;height:16px}

/* Содержимое рабочего поля */
/* Лист внутри рабочего поля — плёнка света, не второе стекло: своего backdrop-filter
   у него нет, иначе блюр сложился бы с блюром .ws и текст поплыл. */
.sheet{background:var(--film-2);border:1px solid var(--line);border-radius:var(--rad);
  padding:calc(22px - var(--pad-c) * .6)}
.sheet + .sheet{margin-top:16px}
/* Перетаскиваемый блок: курсор-подсказка, приподнятое состояние у источника
   и подсветка у цели обмена. */
.sheet.drag{cursor:grab}
.sheet.drag:active{cursor:grabbing}
.sheet.is-dragging{opacity:.45;transform:scale(.99)}
.sheet.is-over{border-color:var(--acc);box-shadow:0 0 0 2px color-mix(in srgb,var(--acc) 45%,transparent)}
.sheet-h{display:flex;align-items:baseline;justify-content:space-between;gap:14px;margin-bottom:18px}
.sheet-h h3{margin:0;font-size:14.5px;font-weight:600;letter-spacing:-.01em}
.sheet-h em{font-style:normal;font-size:12px;color:var(--ink-3)}
/* Пустой блок одной строкой (таск 152): заголовок, статус, действие; форма — за нажатием. */
.sheet-line{padding-block:8px}
.sheet-line .sheet-h{margin-bottom:0;align-items:center}
.sheet-line .sheet-h em{flex:1;min-width:0}
.sheet-line-act{display:flex;gap:6px;flex-wrap:wrap}
.sheet-line + .sheet-line{margin-top:8px}
/* На узком экране длинная пара «заголовок + подпись» ломалась пополам каждая и читалась как
   каша из четырёх строк. Перенос отправляет подпись на свою строку целиком; короткие пары
   («Гости» — «3 в списке») по-прежнему стоят рядом — им переноситься не с чего. */
@media (max-width:768px){
  .sheet-h{flex-wrap:wrap;row-gap:4px}
  .sheet-h em{flex:1 0 100%}
}
/* Две колонки, но по ширине САМОГО ПОЛЯ, а не экрана: при уменьшении окна
   поле сужается, экран остаётся широким, и media-запрос удерживал бы две
   тесные колонки — заголовки переносились, кольца ломались в 2+1. */
/* minmax(0,1fr), а не 1fr: голое 1fr — это minmax(auto,1fr), и колонка
   раздувается до min-content содержимого, вылезая за пределы поля. */
/* Сетка, а не колонки. Колонки укладывали блоки плотнее, но в них нечем ограничить минимальную
   ширину содержимого: кольца денег и строки команды шире узкой колонки просто вылезали на
   соседнюю и накладывались на её текст. Сетка с minmax(0,1fr) такого не допускает.
   Блоки не растягиваются до высоты соседа — каждый ровно своей высоты. */
/* Число колонок спрашивается у рабочего поля (@container ws), поэтому блок обязан занимать
   его целиком — правило .ws-body > .grid-2 выше. Стоит блоку оказаться уже поля, как запрос
   начинает врать: поле широкое, блок узкий, а колонок всё равно две — и содержимое половин
   налезает друг на друга. Своей ширины элемент спросить не может: контейнерный запрос
   отвечает только потомкам. */
.grid-2{display:grid;grid-template-columns:minmax(0,1fr);gap:calc(16px - var(--pad-c) * .4);
  align-items:start}
@container ws (min-width:700px){ .grid-2{grid-template-columns:repeat(2,minmax(0,1fr))} }
/* Потолок — три колонки: дальше блок становится слишком узким для колец и таблиц. */
@container ws (min-width:1240px){ .grid-2{grid-template-columns:repeat(3,minmax(0,1fr))} }

/* Одиночный лист не тянется во всю ширину поля: строка длиннее ~1100px
   читается хуже — глаз теряет начало следующей. */
.ws-body > .sheet,.ws-body > .figs,.ws-body > .tw,.ws-body > .kanban,
.ws-body > .rows,.ws-body > .empty{max-width:1100px}

.rings{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px 10px}
.ring{text-align:center;min-width:0}
/* Кольцо ужимается вместе с колонкой: жёсткие 84px в три ряда переполняли
   узкое поле на уменьшенном размере окна. Число под ним не масштабируется. */
.ring svg{display:block;margin:0 auto 10px;transform:rotate(-90deg);
  max-width:100%;height:auto}
.ring b{display:block;font-size:17px;font-weight:600;letter-spacing:-.02em}
.ring span{display:block;font-size:11.5px;color:var(--ink-2);margin-top:2px}
/* ── Погода. Крупное «сейчас» и ряд дней: в один взгляд «во что одеваться завтра» и
   «не зальёт ли монтаж в субботу». Иконки — тот же stroke 1.6, что у всей оболочки. ── */
/* Поле города с подсказками: список висит под полем и не толкает форму. */
.city-field{position:relative}
.city-input{width:100%;padding:10px 13px;border-radius:var(--rad-s);border:1px solid var(--line);
  background:var(--paper-2);color:var(--ink);font:inherit;font-size:13.5px;outline:none}
.city-input:focus{border-color:var(--acc)}
.city-input::placeholder{color:var(--ink-3)}
/* Подсказки городов — на плотном слое (--paper), а не на прозрачном стекле: сквозь стекло
   просвечивают пилюли фильтра под списком, и обе надписи читаются одновременно. */
.city-drop{position:absolute;left:0;right:0;top:calc(100% + 4px);z-index:20;padding:5px;
  border-radius:var(--rad-s);background:var(--pop);border:1px solid var(--edge);
  backdrop-filter:blur(22px);-webkit-backdrop-filter:blur(22px);
  box-shadow:0 16px 36px -14px rgba(0,0,0,.6);max-height:250px;overflow:auto}
.city-opt{display:block;width:100%;text-align:left;padding:8px 10px;border-radius:8px;
  font-size:13px;color:var(--on);cursor:pointer}
.city-opt:hover{background:var(--fill)}
.weather-now{display:flex;align-items:center;gap:12px;margin:14px 0 4px}
.weather-ic .ic{width:34px;height:34px;color:var(--ink)}
.weather-now b{font-size:30px;font-weight:600;letter-spacing:-.03em;color:var(--ink)}
.weather-now span:last-child{font-size:12.5px;color:var(--ink-2);line-height:1.45}
.weather-days{display:grid;grid-template-columns:repeat(6,1fr);gap:6px;margin-top:14px}
.weather-day{display:flex;flex-direction:column;align-items:center;gap:3px;padding:9px 4px;
  border-radius:var(--rad-s);background:var(--film-1)}
.weather-day.on{background:var(--film-3)}
.weather-day span{font-size:11px;color:var(--ink-3)}
.weather-day .ic{width:19px;height:19px;color:var(--ink-2)}
.weather-day b{font-size:13px;font-weight:600;color:var(--ink);font-variant-numeric:tabular-nums}
.weather-day i{font-style:normal;font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.weather-day u{text-decoration:none;font-size:10.5px;color:var(--b)}
/* Значок погоды в клетке календаря: только температура и иконка — на большее нет места. */
/* ── Год: двенадцать мини-месяцев. Клетка — число и подсветка занятости, подробности живут
   в месячном виде, куда уводит клик по названию. ── */
.year-wrap{display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));gap:12px;margin-top:14px}
.ymonth{display:block;width:100%;text-align:left;padding:12px;border-radius:var(--rad-s);
  background:var(--film-1);border:1px solid transparent;transition:border-color .18s var(--ease),background .18s var(--ease)}
.ymonth:hover{background:var(--film-2);border-color:var(--line)}
.ymonth b{display:inline-block;font-size:13px;font-weight:600;color:var(--ink);
  text-transform:capitalize;margin-bottom:8px}
.ymonth .tag{margin-left:6px;vertical-align:top}
.ygrid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.ycell{font-style:normal;display:grid;place-items:center;aspect-ratio:1;font-size:10px;
  color:var(--ink-3);border-radius:5px}
.ycell.out{visibility:hidden}
.ycell.has{background:var(--acc);color:var(--acc-ink);font-weight:600}
.ycell.now{outline:1px solid var(--ink-2)}
.cal-w{display:inline-flex;align-items:center;gap:2px;font-size:10.5px;color:var(--ink-3);
  margin-left:auto;font-variant-numeric:tabular-nums}
.cal-w .ic{width:12px;height:12px}
.profit-line{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  margin-top:20px;padding-top:16px;border-top:1px solid var(--line);font-size:13px;color:var(--ink-2)}
.profit-line b{font-size:17px;font-weight:600;color:var(--ink);letter-spacing:-.02em}
.profit-line em{font-style:normal;font-size:12.5px;color:var(--g);margin-left:5px}

/* Линии рисуют сами ячейки, а не фон контейнера: иначе незаполненный
   хвост последнего ряда остаётся серым прямоугольником-дырой. */
.figs{display:grid;grid-template-columns:repeat(auto-fit,minmax(152px,1fr));gap:1px;
  background:transparent;border:1px solid var(--line);border-radius:var(--rad);overflow:hidden}
.fig{background:var(--film-1);padding:16px 18px;outline:1px solid var(--line)}
.fig b{display:block;font-size:21px;font-weight:600;letter-spacing:-.025em;line-height:1.1}
.fig span{display:block;font-size:11.5px;color:var(--ink-2);margin-top:5px}
.fig.pos b{color:var(--g)} .fig.neg b{color:var(--r)}

/* Широкая таблица скроллится внутри своего листа, страница вбок не едет. */
.tw{overflow-x:auto;margin:0 -6px;padding:0 6px}
.tw::-webkit-scrollbar{height:8px}
.tw::-webkit-scrollbar-thumb{background:var(--film-5);border-radius:99px}
.tw table{min-width:660px}
.tw td:first-child b{display:block;min-width:150px}
table{width:100%;border-collapse:collapse;font-size:13px}
th{text-align:left;font-weight:500;font-size:11.5px;color:var(--ink-3);padding:0 12px 9px;
  letter-spacing:.02em;text-transform:uppercase}
th.num,td.num{text-align:right;font-variant-numeric:tabular-nums}
td{padding:11px 12px;border-top:1px solid var(--line)}
tbody tr:hover{background:var(--film-1)}
tfoot td{border-top:2px solid var(--stroke-hi);font-weight:600;padding-top:13px}

/* Метка коротка и целиком осмысленна: «Постпродакшн», обрезанный до «Постпродакш», —
   это не сокращение, а опечатка на экране. Внутри flex-строки тег сжимался наравне
   с соседями, хотя ужиматься должно длинное (имя, название), а не он. */
.tag{display:inline-block;flex:0 0 auto;padding:3px 9px;border-radius:99px;font-size:11px;font-weight:500;white-space:nowrap}
.tag-g{background:var(--tag-g-bg);color:var(--tag-g-ink)} .tag-b{background:var(--tag-b-bg);color:var(--tag-b-ink)}
.tag-r{background:var(--tag-r-bg);color:var(--tag-r-ink)} .tag-n{background:var(--surf-3);color:var(--ink-2)}

.rows{display:flex;flex-direction:column}
.row{display:flex;align-items:center;gap:13px;padding:13px 2px;border-top:1px solid var(--line)}
/* Действия в строке не сжимаются ни на какой ширине: в кнопке сжимать нечего, а у подписи рядом
   ровно для этого стоит обрезка в две строки (`.row-main span`). Раньше правило жило только в
   телефонной ветке, и в узкой панели уведомлений (340 px) flex ужимал кнопку наравне с текстом —
   «Завершить сеансы» выходила столбиком из букв. */
.row > .btn, .row > .lead-x, .row > .icon-btn{flex:0 0 auto}
/* Строка с двумя тегами (участие плюс статус ТЗ): на узком экране теги уезжают на свою строку,
   а не сжимают имя специалиста до многоточия. Прокрутки вбок в кабинете не бывает. */
.row-wrap{flex-wrap:wrap}
.row:first-child{border-top:0}
/* Спутник гостя (разбор Social Tables): та же строка, но подчинённая — сдвиг и отсутствие
   разделителя показывают, что он приходит с тем, кто выше, а не сам по себе. */
.row-sub{padding-left:16px;border-top-color:transparent}
/* Заголовок блока в списке («За 5 месяцев · до 4 апреля» в плане подготовки). Своя линия сверху
   и отступ — граница между блоками: без неё сорок строк подряд читаются одним потоком, а владелец
   узнаёт свой файл именно по разметке блоками. */
.rows-blk{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:16px 2px 7px;border-top:1px solid var(--edge)}
.rows-blk:first-child{border-top:0;padding-top:0}
.rows-blk b{font-size:13px;font-weight:600;letter-spacing:-.01em}
.rows-blk em{font-style:normal;font-size:12px;color:var(--ink-3)}
/* Первая строка блока не рисует свою линию: она уже нарисована заголовком, и две подряд
   выглядят как пустая строка. */
.rows-blk + .row{border-top:0}
/* Поле, которое правится прямо в строке. Подчёркивание точками — единственный намёк, что по
   значению можно щёлкнуть: без него человек ищет кнопку «править» и не находит. Рамка
   появляется только под курсором и в фокусе, иначе список превращается в решётку из полей. */
/* Селектор с классом строки — не для красоты: `.row-main span` объявлен блочным (обрезка
   подписи в две строки), и обычный `.cell-inline` он перебивал специфичностью. Поле стола
   растягивалось на всю ширину подписи — двести пикселей ради номера «3». */
.cell-inline,
.row-main span.cell-inline{border-bottom:1px dotted var(--film-4);cursor:text;border-radius:4px;
  padding:0 3px;margin:0 -3px;min-width:24px;display:inline-block;width:auto;
  overflow:visible;-webkit-line-clamp:none}
/* На телефоне поле правится пальцем, а не курсором: цифра высотой в семнадцать пикселей —
   это промах через раз. Площадь касания растим отступами, а обратными полями возвращаем
   строку на место: иначе список разъезжается на восемь пикселей в каждой строке. */
@media (max-width:768px){
  .cell-inline,
  .row-main span.cell-inline{padding:9px 8px;margin:-9px -8px;min-width:32px}
  td.cell-inline{padding:9px 8px;margin:0}
}
.cell-inline:hover{background:var(--film-2)}
.cell-inline:focus{outline:none;background:var(--film-3);border-bottom-color:var(--acc)}
td.cell-inline{display:table-cell;margin:0}
/* Выключенная строка (пакет, скрытый со страницы): видна, но приглушена — «скрыт» это
   состояние, а не удаление, и найти такую строку нужно быстро. */
.row-off{opacity:.55}
/* Проверка перед событием (таск 55). Срочный пункт помечен полосой слева, а не цветом текста:
   красный текст на подписи-последствии съедает саму подпись, ради которой пункт и написан.
   Полоса рисуется тенью внутрь — рамка сдвинула бы строку на пиксель относительно соседних. */
.bs-urgent{box-shadow:inset 3px 0 0 var(--tag-r-ink);padding-left:11px}
/* Зелёные — спокойный блок ниже срочного: человек должен видеть, что проверено, а не что
   промолчали. Тон приглушённый намеренно: это не вторая тревога, а её отсутствие. */
.bs-ok{margin-top:14px;padding-top:12px;border-top:1px solid var(--line)}
.bs-ok > b{display:block;font-size:12px;font-weight:600;color:var(--ink-2);margin-bottom:8px}
.bs-ok-list{display:flex;flex-wrap:wrap;gap:6px}
.bs-ok-i{font-size:12px;padding:3px 9px;border-radius:99px;
  background:var(--tag-g-bg);color:var(--tag-g-ink)}
/* Отметки готовности на карточке события в списке (договор · предоплата · смета · подрядчики ·
   гости · сценарий). Точками, а не словами: в панели 340 пикселей, и шесть подписей выдавили бы
   название события. Слово остаётся в `title` — на телефоне подсказки нет, поэтому у отметок есть
   и общий счёт рядом. */
/* Селектор с классом карточки — не для красоты: `.pcard span` объявлен блочным, и обычный
   `.pcard-marks` он перебивал бы специфичностью, разложив точки столбиком. */
.pcard .pcard-marks{display:flex;align-items:center;gap:4px;margin-top:6px}
.pcard-marks i{width:7px;height:7px;border-radius:99px;background:var(--film-4)}
.pcard-marks i.on{background:var(--tag-g-ink)}
.pcard-marks span{font-size:11px;color:var(--ink-3);margin-left:4px}

/* ── Самочувствие события (таск 61) ────────────────────────────────────────
   Три тона на карточке списка и доски: по плану · есть риски · горим. Считает их автомат из
   фактов, ручного выбора нет.

   Заливка слабая (те же токены, что у тегов: альфа .16 в тёмных темах, пастель в светлых), а
   чернила остаются обычными — требование владельца «цвета не ядовитые, слегка подсвеченные,
   чтобы текст оставался читаемым». Полоса слева повторяет состояние формой: цвет, различимый
   только оттенком, для дальтоника состояния не различает вовсе.

   Денежная триада (зелёный «получено», синий «ожидается», красный «расход») тут ни при чём:
   карточка события и строка сметы на одном экране не стоят. */
.pcard.hl-ok,.lead.hl-ok{background:var(--tag-g-bg);border-left:3px solid var(--tag-g-ink)}
.pcard.hl-risk,.lead.hl-risk{background:var(--tag-a-bg);border-left:3px solid var(--tag-a-ink)}
.pcard.hl-burn,.lead.hl-burn{background:var(--tag-r-bg);border-left:3px solid var(--tag-r-ink)}
/* Наведение не должно гасить состояние: обычное `.pcard:hover` подменяет фон целиком. */
.pcard.hl-ok:hover,.lead.hl-ok:hover{background:var(--tag-g-bg)}
.pcard.hl-risk:hover,.lead.hl-risk:hover{background:var(--tag-a-bg)}
.pcard.hl-burn:hover,.lead.hl-burn:hover{background:var(--tag-r-bg)}
/* Причина цвета. Курсива нет намеренно — это факт, а не примечание. */
.pcard .hl-why,.lead .hl-why{display:block;font-style:normal;font-size:11.5px;line-height:1.4;
  color:var(--ink-2);margin:1px 0 4px}
.ava{width:36px;height:36px;flex:0 0 36px;border-radius:99px;display:grid;place-items:center;
  /* Подложка инициалов темнее прежней #8b918b: белым по ней было 2,6:1. */
  font-size:12px;font-weight:600;color:#fff;background:#666c66}
.row-main{flex:1 1 auto;min-width:0}
.row-main b{display:block;font-size:13.5px;font-weight:600;letter-spacing:-.005em}
/* Подпись строки — не всегда короткая пометка: сюда попадают объяснения вроде «Обычно это
   черновик: заезд и церемония есть, остального ещё нет». В одну строку такое не влезает и
   обрывалось на середине слова. Две строки: список не разъезжается, а фраза дочитывается.
   Обрезка по СТРОКАМ, а не по символам — многоточие встаёт на границе строки. */
.row-main span{display:block;font-size:12px;color:var(--ink-2);margin-top:2px;
  overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;
  line-height:1.35}

.bar{height:5px;border-radius:99px;background:var(--film-4);overflow:hidden;margin-top:9px}
/* Столбцы: сетка на всю ширину листа, высота задаётся инлайном от максимума ряда. */
.bars{display:flex;align-items:flex-end;gap:6px;margin-top:14px}
.bar-col{flex:1 1 0;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:5px;min-width:0}
/* Перехода по высоте здесь нет намеренно. Он тут стоял и не срабатывал ни разу: экран
   пересобирается целиком через innerHTML, столбец каждый раз новый, а на только что вставленном
   элементе переход не запускается. То есть строка обещала анимацию, которой не было, и при этом
   просила браузер пересчитывать раскладку. Понадобится рост столбцов при появлении — это
   keyframes с transform: scaleY, а не переход по высоте. */
.bar-col i{display:block;width:100%;max-width:38px;border-radius:6px 6px 3px 3px;
  background:linear-gradient(180deg,var(--acc),color-mix(in srgb,var(--acc) 35%,transparent))}
.bar-val{font-size:11px;color:var(--ink-2);font-variant-numeric:tabular-nums}
.bar-cap{font-size:11px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}
.legend{display:flex;flex-wrap:wrap;gap:10px 18px;margin-top:14px}
.legend-i{display:inline-flex;align-items:center;gap:7px;font-size:12.5px;color:var(--ink-2)}
.legend-i i{width:9px;height:9px;border-radius:3px;display:inline-block}
.legend-i b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.chart-row{display:flex;gap:26px;align-items:center;flex-wrap:wrap}
.bar i{display:block;height:100%;border-radius:99px;background:var(--ink-2)}

.kanban{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;align-items:start}
.kcol{background:var(--film-1);border-radius:var(--rad);padding:13px;min-height:150px}
.kcol h4{margin:0 0 12px;font-size:12px;font-weight:600;color:var(--ink-2);display:flex;
  justify-content:space-between;letter-spacing:.01em}
.kcard{background:var(--film-2);border:1px solid var(--line);border-radius:var(--rad-s);padding:13px;
  transition:box-shadow .22s var(--ease),transform .28s var(--spring),background .18s var(--ease)}
.kcard + .kcard{margin-top:9px}
.kcard:hover{background:var(--film-3);box-shadow:0 8px 20px -8px rgba(0,0,0,.5);transform:translateY(-2px)}
.kcard b{display:block;font-size:13px;font-weight:600;margin-bottom:5px}
.kcard span{display:block;font-size:11.5px;color:var(--ink-2)}

/* ── Чат: пилюли-фильтры и список тем в панели ───────────────────────────── */
/* ── Канбан заявок ───────────────────────────────────────────────────────
   Воронка — единственный экран, которому ширина нужна вся: у неё своя
   горизонтальная прокрутка, поэтому общий лимит 1100px здесь снимается
   более сильным селектором, иначе колонки обрезались бы на полпути. */
.ws-body > .lead-figs,.ws-body > .lead-kanban,.ws-body > .lead-bar{max-width:none}
.lead-bar{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin:16px 0}
.lead-search{flex:0 1 280px;min-width:180px;padding:9px 14px;border-radius:99px;
  border:1px solid var(--line);background:var(--film-2);color:var(--ink);font-size:13px}
.lead-search::placeholder{color:var(--ink-3)}
.lead-search:focus{outline:none;border-color:var(--stroke)}

/* Колонки скроллятся вбок: этапов бывает больше, чем влезает в поле. */
.trash-btn{margin-left:auto}
.trash-btn svg{width:13px;height:13px}
.trash-box{margin:0 0 16px;padding:14px 16px;border-radius:var(--rad);
  background:var(--film-2);border:1px solid var(--line)}
.trash-h{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:6px}
.trash-h b{font-size:13px;font-weight:600}
.trash-box .row{padding:9px 0}
.trash-box .btn{padding:6px 12px;font-size:12px}

/* ── Коллеги: компактные фильтры каталога ─────────────────────────────── */
.cat-block{padding:0 20px 14px}
.cat-label{font-size:11px;color:var(--on-mute);letter-spacing:.02em;margin:10px 0 6px}
.cat-label:first-child{margin-top:0}
.cat-spec{padding:0}
/* Пилюли специальности мельче обычных — 20 штук должны уложиться в несколько
   строк, а не растянуться на весь экран, как в списковом фильтре боевого сайта. */
.cpill-sm{padding:5px 10px;font-size:11.5px}
.mini-select{width:100%;padding:9px 12px;border-radius:var(--rad-s);border:1px solid var(--edge);
  background:var(--fill);color:var(--on);font:inherit;font-size:13px}
.mini-select option{background:var(--pop);color:var(--ink)}

/* ── Коллеги: сетка карточек специалистов/агентств ────────────────────── */
/* ── Каталог специалистов ─────────────────────────────────────────────────
   Плитка, а не строка: человека выбирают по лицу и по трём числам под ним — оценке, цене и
   готовности. Пропорция близка к квадрату, фото занимает верхнюю треть: в вытянутой строке
   фото ужимается до иконки и перестаёт работать. */
.spec-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));gap:14px}
.spec-card{display:flex;flex-direction:column;border-radius:var(--rad);overflow:hidden;
  background:var(--film-2);border:1px solid var(--line);text-align:left;cursor:pointer;
  transition:box-shadow .2s var(--ease),transform .22s var(--spring),background .18s var(--ease)}
.spec-card:hover{background:var(--film-3);box-shadow:0 10px 24px -10px rgba(0,0,0,.4);transform:translateY(-2px)}
/* Пол карточки (таск 75): женские розовые, мужские сиреневые — требование владельца, «в списке
   из двадцати человек пол читается взглядом». Красится РАМКА и полоса слева, а не подложка:
   заливка карточки цветом съела бы контраст имени и цены, ради которых карточку и читают.
   Цвет — не единственный признак: рядом буква (.spec-gender), потому что в чёрно-белой печати
   и при дальтонизме розовое от сиреневого не отличается вовсе. */
.spec-card-female{border-color:rgba(233,140,183,.55);box-shadow:inset 3px 0 0 #e98cb7}
.spec-card-male{border-color:rgba(167,139,232,.55);box-shadow:inset 3px 0 0 #a78be8}
.spec-card-female:hover{box-shadow:inset 3px 0 0 #e98cb7,0 10px 24px -10px rgba(0,0,0,.4)}
.spec-card-male:hover{box-shadow:inset 3px 0 0 #a78be8,0 10px 24px -10px rgba(0,0,0,.4)}
/* Буква на фото — тем же местом, что «новый», только справа снизу. Тёмная на светлом кружке:
   белым по розовому вышло бы 2,1:1, то есть нечитаемо ровно там, где признак и нужен. */
.spec-gender{position:absolute;left:10px;bottom:10px;min-width:20px;height:20px;padding:0 5px;
  border-radius:99px;display:grid;place-items:center;font-size:11.5px;font-weight:700;
  color:#1b1420;box-shadow:0 0 0 2px rgba(8,10,14,.35)}
.spec-gender-female{background:#f3b9d3}
.spec-gender-male{background:#c6b4f2}
/* Фото карточки. Снимок кладётся в рамку абсолютом, а не размерами в процентах: высота самой
   рамки задана пропорцией, и процент от неё браузер разрешать не обязан — вертикальный портрет
   тогда вырастает во всю свою натуральную высоту и наезжает на имя под ним. */
.spec-photo{position:relative;aspect-ratio:4/3;overflow:hidden;display:grid;place-items:center;
  font-size:30px;font-weight:600;color:rgba(255,255,255,.92);letter-spacing:.02em}
.spec-photo img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.spec-online{position:absolute;top:10px;right:10px;width:9px;height:9px;border-radius:99px;
  background:var(--g);box-shadow:0 0 0 3px rgba(8,10,14,.45)}
.spec-flag{position:absolute;left:10px;top:10px;padding:3px 8px;border-radius:99px;
  background:rgba(8,10,14,.55);color:var(--on);font-size:10.5px;font-weight:600}
.spec-body{display:flex;flex-direction:column;gap:3px;padding:12px 13px 11px;flex:1 1 auto}
.spec-name{font-size:14px;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.spec-sub{font-size:12px;color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.spec-tags{display:flex;gap:5px;flex-wrap:wrap;margin-top:3px}
.spec-meta{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:6px}
.spec-price{font-size:12px;color:var(--ink-2);font-variant-numeric:tabular-nums;white-space:nowrap}
.spec-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:auto;padding-top:9px}
/* Отметка сделанного выбора на карточке подбора. inline-flex, а не inline-block базового .tag:
   внутри галочка, и без выравнивания она съезжает относительно текста. */
.spec-chosen{display:inline-flex;align-items:center;gap:5px}
.spec-chosen .ic{width:12px;height:12px;flex:0 0 12px}
.spec-write{padding:6px 9px}
.spec-rating{display:flex;align-items:center;gap:4px;font-size:12px;color:var(--ink-2);flex:0 1 auto;min-width:0}
.spec-rating i{font-style:normal;color:var(--ink-3)}
.spec-star{width:11px;height:11px;flex:0 0 11px;color:#f5a524;fill:currentColor}

/* ── Коллеги: публичная страница ──────────────────────────────────────── */
.profile-sheet{max-width:640px}
.profile-back{margin-bottom:16px;padding:7px 12px;font-size:12px}
.profile-h{display:flex;align-items:center;gap:16px;margin-bottom:16px}
.profile-ava{width:64px;height:64px;flex:0 0 64px;border-radius:99px;display:grid;place-items:center;
  font-size:18px;font-weight:600;color:#fff}
.profile-who h3{margin:0 0 3px;display:flex;align-items:center;gap:6px;font-size:17px;font-weight:600;letter-spacing:-.01em}
.profile-who>span:not(.spec-rating){display:block;font-size:13px;color:var(--ink-2);margin-bottom:5px}
.profile-about{font-size:13.5px;line-height:1.6;color:var(--ink-2);margin:0 0 20px}
.profile-actions{display:flex;flex-wrap:wrap;gap:9px}
/* stretch, а не flex-start: колонки тянутся до высоты самой длинной, поэтому
   их нижние края выстраиваются в одну линию независимо от числа карточек. */
.lead-kanban{display:flex;gap:12px;overflow-x:auto;padding-bottom:8px;align-items:stretch;
  max-width:none;grid-template-columns:none}
.lead-col{flex:0 0 258px;display:flex;flex-direction:column;min-height:190px;max-height:62vh}
/* Одинаковая высота шапки у всех колонок: в первой там кнопка, в остальных
   строка текста — без общего минимума карточки начинались бы на разных уровнях. */
.kcol-h{display:flex;align-items:center;gap:7px;margin-bottom:10px;padding:0 2px;
  min-height:36px;flex:0 0 auto}
.kcol-dot{width:7px;height:7px;flex:0 0 7px;border-radius:99px}
.kcol-h b{font-size:12.5px;font-weight:600;outline:none;border-radius:5px;padding:1px 3px;
  min-width:20px}
.kcol-h b:focus{background:var(--film-3);box-shadow:0 0 0 2px var(--acc)}
.kcol-sum{font-size:11px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.kcol-n{margin-left:auto;font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.kcol-body{flex:1 1 auto;min-height:70px;overflow-y:auto;display:flex;flex-direction:column;gap:9px}
.kcol-empty{margin:0;padding:14px 0;text-align:center;font-size:12px;color:var(--ink-3)}
/* Приписка к колонке — «уезжает в архив» у завершения и отмены. Рядом с именем, но не внутри
   него: имя переименовывают правкой на месте, и приписка уехала бы в название этапа. */
.kcol-note{font-size:10.5px;color:var(--ink-3);white-space:nowrap}
/* Фактические числа окна под названием колонки доски задач («4 сен — 13 сен»). Окно уезжает
   вместе с сегодняшним днём, и без чисел «через 2–5 недель» ничего не говорит о датах. */
.kcol-range{margin:-6px 2px 10px;font-size:11px;color:var(--ink-3);
  font-variant-numeric:tabular-nums;white-space:nowrap}
/* Пустая колонка приглушена, а не спрятана: состав доски не должен меняться на каждое
   перетаскивание. Точка этапа тоже гаснет — иначе цвет читается как «здесь что-то есть». */
.kcol-blank .kcol-h b,.kcol-blank .kcol-n{color:var(--ink-3)}
.kcol-blank .kcol-dot{opacity:.45}
/* Колонка чужого направления во время перетаскивания. Видно сразу, куда карточку тянуть можно,
   а куда нет: узнавать это по отказу курсора над каждой колонкой — работа, а не подсказка. */
.kcol.is-off{opacity:.4}
.lead-col.is-over .kcol-body{outline:2px dashed var(--acc);outline-offset:4px;border-radius:var(--rad-s)}

.lead{background:var(--film-2);border:1px solid var(--line);border-radius:var(--rad-s);
  padding:11px 12px;cursor:grab;transition:background .18s var(--ease),transform .2s var(--ease)}
.lead:hover{background:var(--film-3)}
.lead:active{cursor:grabbing}
.lead.is-dragging{opacity:.45;transform:scale(.98)}
.lead-top{display:flex;align-items:center;gap:8px}
.lead-top b{flex:1 1 auto;min-width:0;font-size:13px;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lead-src{flex:0 0 auto;font-size:10.5px;padding:2px 7px;border-radius:99px;
  background:var(--film-4);color:var(--ink-2)}
.lead-meta{font-size:11.5px;color:var(--ink-2);margin-top:5px;font-variant-numeric:tabular-nums}
/* Карточка дела на доске задач (таск 52). Срок цветом — ТРИ состояния: будущее нейтральное,
   сегодня предупреждающее, просрочено тревожное.

   Просрочка держится на самой пилюле срока, а не на фоне карточки, и потому НЕ ГАСНЕТ ни при
   каком оформлении: у них она пропадает на цветной карточке, и это их ошибка, а не решение.
   Левая полоса у просроченной — вторая, независимая индикация: перекрасив фон, её не потерять. */
.tdue-today{background:var(--film-4);color:var(--am);font-weight:600}
.tdue-overdue{background:var(--film-4);color:var(--r);font-weight:700}
.tcard-overdue{border-left:3px solid var(--r)}
.tcard-today{border-left:3px solid var(--am)}
/* Галочка выполнения прямо на карточке: отметить дело — самое частое действие над ним, и
   открывать ради этого карточку незачем. Своя кнопка, а не иконка внутри ссылки: клик по ней
   не должен открывать панель. */
.tcheck{flex:0 0 auto;width:16px;height:16px;padding:0;border-radius:5px;cursor:pointer;
  border:1.5px solid var(--line);background:transparent;transition:all .15s var(--ease)}
.tcheck:hover{border-color:var(--g,var(--acc));background:var(--film-4)}
.tcheck:hover::after{content:'✓';display:block;font-size:11px;line-height:13px;color:var(--g,var(--acc))}
.lead-note{margin:6px 0 0;font-size:12px;line-height:1.45;color:var(--ink-2)}
/* Пять фактов карточки проекта (R20.5): клиент, отсчёт, ТЗ, план подготовки — строка через
   точки, тем же начертанием, что и «готовность/команда» ниже. */
.lead-facts{margin:6px 0 0;font-size:12px;line-height:1.45;color:var(--ink-2)}
.lead-foot{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-top:9px}
/* Кто выбран — строкой под своей капсулой профессии. Общим списком внизу окна не было видно,
   кто на какую роль взят, а незанятая профессия ничем не отличалась от занятой. Колонка не шире
   своей капсулы: длинное имя обрезается, иначе на 375px одна строка распирает ряд капсул. */
.lead-role{display:inline-flex;flex-direction:column;align-items:flex-start;gap:4px;
  max-width:100%;min-width:0}
.lead-picked{display:inline-flex;align-items:center;gap:6px;max-width:100%;min-width:0;
  padding:2px 4px 2px 2px;border-radius:99px;background:var(--fill);
  font-size:11.5px;color:var(--on-dim)}
.lead-picked b{font-weight:500;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lead-picked .th-ava{width:18px;height:18px;flex:0 0 18px;font-size:8px}
.lead-picked .lead-x{width:18px;height:18px;flex:0 0 18px}
.lead-picked .lead-x svg{width:11px;height:11px}
.lead-x{width:24px;height:24px;border-radius:99px;display:grid;place-items:center;
  color:var(--ink-3);transition:background .18s var(--ease),color .18s var(--ease)}
.lead-x:hover{background:var(--film-4);color:var(--r)}
.lead-x svg{width:13px;height:13px}
/* Кнопка на месте заголовка первой колонки: создать заявку можно там же,
   где она появится, без похода за кнопкой в шапку. */
.kcol-cta{flex:1 1 auto;justify-content:center;padding:8px 12px;font-size:12.5px;min-width:0}
.kcol-cta svg{width:14px;height:14px}
.lead-col-entry .kcol-h{gap:9px}
.kcol-x{width:22px;height:22px;flex:0 0 22px;border-radius:99px;display:grid;place-items:center;
  color:var(--ink-3);opacity:0;transition:opacity .18s var(--ease),background .18s var(--ease),color .18s var(--ease)}
.kcol:hover .kcol-x{opacity:1}
.kcol-x:hover{background:var(--film-4);color:var(--r)}
.kcol-x svg{width:12px;height:12px}
/* Подтверждение прямо в колонке: удаление этапа задевает лежащие в нём заявки,
   поэтому в вопросе сразу сказано, сколько их и куда они переедут. */
.kcol-ask{margin-bottom:9px;padding:11px 12px;border-radius:var(--rad-s);
  background:color-mix(in srgb,var(--r) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--r) 40%,transparent)}
.kcol-ask b{display:block;font-size:12.5px;font-weight:600}
.kcol-ask span{display:block;font-size:11.5px;color:var(--ink-2);margin-top:4px;line-height:1.4}
.kcol-ask-f{display:flex;gap:7px;margin-top:10px}
.kcol-ask-f .btn{flex:1 1 0;justify-content:center;padding:7px 10px;font-size:12px}
.btn-danger{background:var(--r);color:#2a0a10;font-weight:600}
.btn-danger:hover{background:#fda4b0}
/* Та же ширина, что у колонок: «добавить этап» — это будущая колонка,
   и place-holder должен занимать ровно её место. */
.kcol-add{flex:0 0 258px;align-self:stretch;min-height:190px;border-radius:var(--rad);
  border:1px dashed var(--stroke);color:var(--ink-3);display:grid;place-items:center;gap:6px;
  align-content:center;font-size:12px;transition:color .18s var(--ease),border-color .18s var(--ease)}
.kcol-add:hover{color:var(--ink);border-color:var(--ink-3)}

/* ── Календарь ─────────────────────────────────────────────────────────── */
.cal-sheet{max-width:900px}
.cal-modes{flex:0 0 auto;background:var(--film-2)}
.cal-modes .mode{color:var(--ink-2);padding:6px 12px}
.cal-modes .mode:hover{color:var(--ink)}
.cal-modes .mode.on{background:var(--ink);color:var(--paper)}
.cal-dow{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px;margin-bottom:6px}
.cal-dow span{font-size:11px;color:var(--ink-3);text-align:center;text-transform:uppercase;letter-spacing:.04em}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px}
.cal-cell{min-height:74px;border-radius:var(--rad-s);background:var(--film-1);
  border:1px solid var(--line);padding:7px 8px;display:flex;flex-direction:column;gap:4px}
.cal-out{background:none;border-color:transparent}
.cal-d{font-size:12px;color:var(--ink-2);font-variant-numeric:tabular-nums;
  display:flex;align-items:center;gap:4px}
.cal-today{border-color:var(--acc)}
.cal-today .cal-d{color:var(--ink);font-weight:700}
.cal-ev{font-size:11px;line-height:1.3;padding:3px 6px;border-radius:6px;
  background:var(--film-4);color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cal-ev-task{background:color-mix(in srgb,var(--r) 18%,transparent)}
.cal-week{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:6px}
.cal-wd{min-height:150px;border-radius:var(--rad-s);background:var(--film-1);
  border:1px solid var(--line);padding:8px;display:flex;flex-direction:column;gap:5px}
.cal-wd-h{font-size:11.5px;color:var(--ink-2)}

/* ── Модалка новой заявки ──────────────────────────────────────────────── */
.modal-back{position:fixed;inset:0;z-index:40;display:grid;place-items:center;padding:24px;
  background:rgba(8,10,14,.55);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px)}
/* Окно не выше экрана и прокручивается внутри себя. Без этого длинная форма — а карточка
   события именно такая — обрезалась снизу: поля были на месте, но добраться до них и до кнопки
   «Сохранить» было нечем. Страница при этом не едет: прокрутка своя, у окна. */
.modal{width:min(440px,100%);border-radius:var(--rad-l);padding:22px;
  background:var(--glass-2);border:1px solid var(--edge);color:var(--on);
  box-shadow:0 30px 60px -24px rgba(0,0,0,.7);
  max-height:calc(100vh - 48px);overflow-y:auto;overscroll-behavior:contain}
/* Шапка и подвал остаются на виду при прокрутке: закрыть и сохранить нужно с любого места.
   
   Только ВНУТРИ окна. Класс `.modal-f` переиспользуется как обычный ряд кнопок на листах
   («Выгрузить список», «Печатные формы»), и глобальное липкое правило заставляло такой ряд
   прилипать к нижней кромке экрана и накрывать собой строки списка — на телефоне поверх
   гостей висела полупрозрачная плашка с кнопками. */
/* Липкие шапка и подвал окна: их фон полупрозрачен по стилю оболочки, и без размытия
   содержимое, проезжающее под ними, читается сквозь кнопки — на длинных списках (условия
   площадки, смета) это выглядит как наложенные друг на друга строки. Размытие оставляет
   стекло стеклом, но делает полосу непроницаемой для текста. */
/* Фон полосы кладём ДВУМЯ слоями одного и того же стекла: `--glass-2` полупрозрачен и тем
   сильнее, чем светлее настройка затемнения у человека (0.6 при обычной, ещё меньше при
   светлой). Второй слой поднимает плотность примерно до 0.85, не меняя цвет, — полоса
   остаётся стеклом, но строки под ней перестают читаться сквозь кнопки. */
.modal .modal-h{position:sticky;top:-22px;z-index:1;
  background-image:linear-gradient(var(--glass-2),var(--glass-2)),linear-gradient(var(--glass-2),var(--glass-2));
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  padding-top:22px;margin-top:-22px}
.modal .modal-f{position:sticky;bottom:-22px;
  background-image:linear-gradient(var(--glass-2),var(--glass-2)),linear-gradient(var(--glass-2),var(--glass-2));
  backdrop-filter:blur(18px);-webkit-backdrop-filter:blur(18px);
  padding-bottom:22px;margin-bottom:-22px}
.modal-h{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:18px}
.modal-h h3{margin:0;font-size:17px;font-weight:600;letter-spacing:-.02em}
.fld{display:flex;flex-direction:column;gap:6px;margin-bottom:13px;min-width:0}
.fld span{font-size:11.5px;color:var(--on-dim)}
/* Кнопка сохранения у блока формы (таск 35): человек правит один блок и не ищет кнопку в
   конце длинной формы. Прижата вправо и втянута к своему блоку — иначе четыре кнопки подряд
   читаются как четыре разных действия, а не как «сохранить то, что рядом». */
.blk-save{display:flex;justify-content:flex-end;margin:-4px 0 14px}
/* Ряд полей карточки события с кнопкой сохранения последней ячейкой (таск 152, Э7): кнопка
   не занимает свою строку, три поля встают в строку, на узком экране ряд переносится вниз,
   а не уезжает вбок. Отступ кнопки снизу равен отступу поля — низ кнопки на линии полей. */
.fld-row.pj-row{display:flex;flex-wrap:wrap;align-items:flex-end;gap:0 12px}
.pj-row>.fld{flex:1 1 150px}
.pj-row>.blk-save{flex:none;margin:0 0 13px}

/* День недели у даты события (таск 35). Ярче самой подписи: его читают, а не перечитывают —
   человек проверяет «суббота ли», а не «как называется поле». */
.fld-wd{color:var(--on);font-weight:600;letter-spacing:.04em}
/* Многострочное поле — то же поле, только выше: без этой строки браузер рисует его белым
   моноширинным прямоугольником поверх тёмного стекла. */
/* Рамка поля — --stroke, а не --edge: у границы элемента управления свой порог (3:1,
   WCAG 1.4.11), и он проверяется прогоном. На --edge поле держалось одной заливкой. */
.fld textarea,.fld input,.fld select{padding:10px 13px;border-radius:var(--rad-s);border:1px solid var(--stroke);
  background:var(--fill);color:var(--on);font:inherit;font-size:13.5px;min-width:0}
.fld input::placeholder,.fld textarea::placeholder{color:var(--on-mute)}
/* Подсказка — не значение. Она рисовалась цветом --ink-3 против текста --ink: в тёмной теме
   #b9c0b6 против #f7f8f7, и на снимке владельца «Анна», «Иванова», «+7» читались как уже
   заполненные поля — форма выглядела полной, а была пустой. Тускнеет прозрачностью, а не новым
   цветом: одно правило работает в обеих полярностях (светлый текст на тёмном садится, тёмный на
   светлом светлеет) и накрывает все подсказки разом — поля, город, поиск, капсулу.
   Порог проверяется прогоном: test/lead-form.test.js считает контраст в каждой теме. */
::placeholder{opacity:.65}
/* Отказ виден на самом поле: рамка красная, под полем — что именно не так. Тост уезжает через
   3,2 секунды и никогда не говорил, какое из четырёх обязательных полей пустое. */
.fld.bad input,.fld.bad select,.fld.bad textarea{border-color:var(--r)}
.fld-err{font-style:normal;font-size:11.5px;color:var(--r)}
.fld input:focus,.fld select:focus,.fld textarea:focus{outline:none;border-color:var(--acc)}
.fld textarea{resize:vertical;min-height:72px;font:inherit;line-height:1.5}
.fld select option{background:var(--pop);color:var(--ink)}
/* .fld родилась для модалки на стекле оболочки (--edge/--fill/--on).
   Внутри листа настроек (.sheet) под ней — бумага рабочего поля, и в
   светлой теме та же пара даёт белый текст на белом. Токены на бумагу. */
.sheet .fld textarea,.sheet .fld input,.sheet .fld select{border-color:var(--stroke);background:var(--paper-2);color:var(--ink)}
.sheet .fld input::placeholder,.sheet .fld textarea::placeholder{color:var(--ink-3)}
.sheet .fld span{color:var(--ink-2)}
.sheet .fld select option{background:var(--pop);color:var(--ink)}
.fld-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}

/* Раскрывающийся блок — общий компонент дизайна (правило «раскрывающиеся блоки одинаковы везде,
   один компонент в core/, не три похожих», spec.md «Дизайн — правила визуальной иерархии»):
   заголовок, строка-сводка, стрелка. Нативный `<details>` даёт стрелку и раскрытие сам, вторую
   своей вёрсткой не рисуем. Родился в заявке (тикет 02, A-1) под именем .lead-block; тикет 05
   (карточка подрядчика) завёл РЯДОМ вторую вёрстку (.disc-block, core/disclosure.js) — то же
   правило дизайна нарушалось буквально: два генератора одной разметки. Правка ревью свела их в
   один (disclosureHtml, leadBlockHtml теперь только переводит форму блока заявки в его форму) —
   класс на разметке остался один, .disc-block; .lead-block в вёрстке кабинета больше не встречается.
   flex-wrap на заголовке — под сводки денег («оплачено 120 000 из 250 000…», правило 4, длиннее
   «пусто» у заявки): без переноса такая строка потребовала бы горизонтальной прокрутки на 375px. */
.disc-block{border:1px solid var(--edge);border-radius:var(--rad-s);margin-bottom:10px;overflow:hidden}
.disc-block-h{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:4px 10px;
  padding:11px 14px;cursor:pointer;list-style:none;font-size:13.5px}
.disc-block-h::-webkit-details-marker{display:none}
.disc-block-h b{font-weight:600}
.disc-block-h span{font-size:11.5px;color:var(--on-mute);text-align:right;min-width:0}
.disc-block-body{padding:0 14px 14px}
.disc-block[open] .disc-block-h{border-bottom:1px solid var(--edge)}

/* Профильный блок роли (история 26) — тот же компонент, вторым уровнем под «ТЗ и документы»:
   отступ слева и более тихая рамка читаются как «внутри» блока, а не как ещё один блок того же
   веса (правило 1, «один вес — одно место»). */
.disc-block-lvl2{margin:8px 0 0 14px;border-color:var(--line)}

/* Строка «подпись — значение» внутри блока (деньги, условия, тайминг): подпись слева, значение
   справа, перенос вместо обрезания — то же требование "без горизонтальной прокрутки на 375px",
   что и у заголовка блока выше. */
.disc-kv{display:flex;justify-content:space-between;flex-wrap:wrap;gap:2px 10px;
  padding:6px 0;border-top:1px solid var(--line);font-size:13px}
.disc-kv:first-child{border-top:0;padding-top:0}
.disc-kv b{font-weight:500;color:var(--on-mute)}

/* Личное фото в настройках профиля — карточка над полями, а не строка в их ряду: снимок узнают
   по лицу, и место под него должно быть крупнее строки текста. */
.pf-photo-row{display:flex;align-items:center;gap:16px;margin-bottom:18px}
.pf-photo{position:relative;width:72px;height:72px;flex:0 0 72px;border-radius:99px;overflow:hidden;
  display:grid;place-items:center;font-size:24px;font-weight:600;color:#fff;
  background:linear-gradient(150deg,#e8b06d,#c2637a)}
.pf-photo img{width:100%;height:100%;object-fit:cover}
.pf-photo-actions{display:flex;gap:8px;flex-wrap:wrap}
.pf-photo-actions .btn[disabled]{opacity:.6;cursor:default;pointer-events:none}
/* Загрузка фото раньше не показывала ничего между нажатием и результатом — если сеть
   помедлит, человек не понимает, сработало нажатие вообще или нет. Затемнение поверх
   кружка и крутилка на самой кнопке — оба сразу, потому что кнопка может уйти из вида
   на маленьком экране, а кружок — нет. */
.pf-photo-spin{position:absolute;inset:0;border-radius:inherit;display:grid;place-items:center;
  background:rgba(8,10,14,.45)}
.pf-photo-spin::after{content:'';width:22px;height:22px;border-radius:99px;
  border:2.5px solid rgba(255,255,255,.35);border-top-color:#fff;animation:pf-spin .7s linear infinite}
.btn-spin{display:inline-block;width:13px;height:13px;flex:0 0 13px;border-radius:99px;
  border:2px solid rgba(255,255,255,.35);border-top-color:currentColor;animation:pf-spin .7s linear infinite}
@keyframes pf-spin{to{transform:rotate(360deg)}}
@media(prefers-reduced-motion:reduce){.pf-photo-spin::after,.btn-spin{animation-duration:1.4s}}
.modal-f{display:flex;justify-content:flex-end;gap:9px;margin-top:20px}

.chat-pills{display:flex;flex-wrap:wrap;gap:6px;padding:0 20px 12px;flex:0 0 auto}
/* Пилюля — это название профессии или фильтра, то есть то, по чему выбирают. «Световое
   оформлени» и «Мобильный бар / Шеф» в узкой панели обрывались ровно там, где начинается
   разница между вариантами. Пилюля скорее станет выше, чем перестанет называть себя. */
.cpill{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;border-radius:99px;
  font-size:12px;font-weight:500;background:var(--glass);border:1px solid var(--edge);color:var(--on-dim);
  max-width:100%;white-space:normal;text-align:left;
  transition:background .18s var(--ease),color .18s var(--ease)}
.cpill:hover{background:var(--fill-2);color:var(--on)}
.cpill.on{background:var(--on-solid);color:var(--on-solid-ink);font-weight:600}
.cpill-add{padding:6px 10px;color:var(--on-mute)}
/* Поле нового фильтра занимает место пилюли, а не открывает диалог: набрал слово, нажал ввод. */
.cpill-new{padding:6px 12px;width:150px;border:1px dashed var(--line);background:transparent;
  color:var(--ink);font:inherit;font-size:12.5px;border-radius:99px;outline:none}
.cpill-new::placeholder{color:var(--ink-3)}
/* Счётчик нового на пилюле-фильтре. Кружок, а не просто число: рядом с названием фильтра
   голая цифра читается как часть названия («Гриневы 3»). */
.cpill-n{font-style:normal;font-size:11px;font-weight:700;line-height:1;padding:3px 6px;
  border-radius:99px;background:var(--on-solid);color:var(--on-solid-ink)}
.cpill.on .cpill-n{background:var(--film-3);color:var(--ink-1)}
.cpill-x{font-style:normal;margin-left:6px;opacity:.55;cursor:pointer}
.cpill-x:hover{opacity:1}
.cpill svg{width:13px;height:13px}

/* Тема — строка списка, не карточка: аватар, имя, последняя реплика, время. */
.thread{display:flex;align-items:center;gap:11px;width:100%;padding:11px 10px;border-radius:var(--rad-s);
  text-align:left;background:var(--glass);border:1px solid var(--edge);
  transition:background .18s var(--ease)}
.thread:hover{background:var(--fill)}
.thread.on{background:var(--fill-2);border-color:var(--edge)}
.th-ava{width:38px;height:38px;flex:0 0 38px;border-radius:99px;display:grid;place-items:center;
  font-size:12px;font-weight:600;color:#fff;overflow:hidden}
/* Фотография внутри кружка. Без этого снимок ложится в исходном размере и накрывает соседние
   строки списка — соседи выглядят стёртыми, хотя они на месте. */
.th-ava img{width:100%;height:100%;object-fit:cover;border-radius:inherit}
.th-ava .ic{width:16px;height:16px;opacity:.7}
.th-main{flex:1 1 auto;min-width:0}
.th-top{display:flex;align-items:baseline;gap:8px}
.th-top b{flex:1 1 auto;min-width:0;font-size:13.5px;font-weight:600;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.th-top time{flex:0 0 auto;font-size:11px;color:var(--on-mute)}
.th-last{display:block;font-size:12px;color:var(--on-dim);margin-top:2px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.th-badge{flex:0 0 auto;min-width:19px;height:19px;padding:0 6px;border-radius:99px;
  display:grid;place-items:center;font-size:10.5px;font-weight:700;
  background:var(--acc);color:var(--acc-ink)}

/* Переписка не тянется во всю ширину поля: широкий чат читается хуже —
   строка уезжает за комфортные 60-70 знаков, а реплики теряют пару. */
/* Прижата влево, а не по центру: слева и сверху одинаковый отступ,
   поэтому переписка читается как продолжение списка тем, а не отдельный остров. */
.chat-sheet{max-width:760px;width:100%;margin:0;display:flex;flex-direction:column;
  flex:1 1 auto;min-height:0;min-width:0}
/* ── Колонка беседы (правка владельца 9, 12.09.2026) ──────────────────────────────────────
   Справа от ленты пустовало поле; растягивать ленту туда владелец запретил («будет тупо»).
   Лист и колонка стоят в ряд внутри `.chat-stage`; лента остаётся главной — колонка узкая
   и первой отдаёт место. Лист теперь НЕ прямой потомок `.ws-body`, поэтому общее правило
   `.ws-body > .sheet{max-width:1100px}` его больше не цепляет, и 760 наконец действует —
   до этого оно проигрывало по специфичности, и чат тянулся до 1100.

   Порог — КОНТЕЙНЕРНЫЙ запрос по ширине поля, а не медиа по окну: поле зависит и от ползунка
   «размер окна» (--win), и медиа-запрос соврал бы при 80 %. Ниже порога колонки нет вовсе —
   она не сжимает ленту и не уезжает вбок. 820 = лента не уже ~550 при колонке 250. */
.chat-stage{display:flex;gap:18px;align-items:stretch;flex:1 1 auto;min-height:0}
.chat-side{display:none;flex:0 0 250px;flex-direction:column;gap:12px;min-height:0;
  overflow-y:auto;padding:4px 2px 14px 0}
@container ws (min-width:820px){ .chat-side{display:flex} }
.cside-card{display:flex;flex-direction:column;gap:9px;padding:12px 13px;border-radius:var(--rad-s);
  background:var(--film-2);border:1px solid var(--line)}
.cside-card h4{margin:0;font-size:11px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--ink-3)}
.cside-who{display:flex;align-items:center;gap:10px;min-width:0}
.cside-who .th-ava{width:44px;height:44px;flex:0 0 44px;font-size:14px}
.cside-who div{min-width:0}
.cside-who b{display:block;font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cside-who span{display:block;font-size:12px;color:var(--ink-2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cside-line{margin:0;font-size:12.5px;color:var(--ink-2);line-height:1.4}
.cside-line b{color:var(--ink);font-weight:600}
.cside-card .btn{align-self:flex-start}
.cside-names{display:flex;flex-wrap:wrap;gap:4px}
.cside-names .tag{background:var(--film-3);color:var(--ink-2)}
.cside-pics{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:6px}
.cside-pics a{display:block;aspect-ratio:1;border-radius:8px;overflow:hidden;background:var(--film-3)}
.cside-pics img{width:100%;height:100%;object-fit:cover;display:block}
.cside-files{display:flex;flex-direction:column;gap:6px}
.cside-files .msg-file{font-size:12.5px;color:var(--ink-2)}
.cside-note{margin:0;font-size:11px;color:var(--ink-3)}
/* Выбор цвета своих реплик — в шапке беседы, рядом с её действиями («где-то наверху, в этом
   чате»). Кружки, не подписи: пять подписей в строке заголовка не помещаются на телефоне.
   Свой класс, а не `.ac` из настроек: applyScene() снимает `.on` со всех `.ac`, чьё действие
   не `acc-…`, и чужие кружки теряли бы отметку выбора. */
.msg-tints{display:inline-flex;align-items:center;gap:6px;margin-left:auto}
.msg-tints em{font-style:normal;font-size:11.5px;color:var(--ink-3);margin-right:2px}
.mtint{width:22px;height:22px;flex:0 0 22px;border-radius:99px;border:2px solid transparent;
  padding:0;cursor:pointer;transition:transform .2s var(--spring)}
.mtint:hover{transform:scale(1.12)}
.mtint.on{border-color:var(--ink);box-shadow:0 0 0 2px var(--surf-2)}
.mtint-none{background:var(--film-5);box-shadow:inset 0 0 0 1px var(--edge-hi)}
.mtint-none.on{box-shadow:inset 0 0 0 1px var(--edge-hi),0 0 0 2px var(--surf-2)}
@media (prefers-reduced-motion:reduce){ .mtint:hover{transform:none} }
/* Поле под чатом выравнивает отступы: сверху столько же, сколько слева. */
.ws-body:has(.chat-sheet){padding-top:calc(24px - var(--pad-c))}
/* Поле под чатом становится колонкой, чтобы переписка заняла высоту целиком:
   иначе лист висит вверху, а под ним остаётся пустая половина окна. */
.ws-body:has(.chat-sheet){display:flex;flex-direction:column}
/* При открытом чате прокручивается ТОЛЬКО лист сообщений, а не вся страница: иначе поле ввода
   уезжало под сгиб, и чтобы написать, приходилось листать вниз. Теперь ws-body фиксирован по
   высоте окна, лист скроллится внутри себя, а composer всегда прижат к низу и на виду —
   на любой высоте экрана. */
.ws-body:has(.chat-sheet){overflow:hidden}
.chat{display:flex;flex-direction:column;gap:11px;padding:4px 0 14px;
  flex:1 1 auto;min-height:0;overflow-y:auto}
.msg{max-width:min(72%,460px);padding:11px 14px;border-radius:16px;font-size:13.5px;line-height:1.5}
.msg time{display:block;font-size:10.5px;margin-top:5px;opacity:.6}
.msg.them{align-self:flex-start;background:var(--film-3);border-bottom-left-radius:5px}
/* Своя реплика — плёнка оттенка поверх окна, а не плотная плашка `--on-solid` (правка владельца
   9): на светлой теме та была почти чёрной, и половина ленты стояла тёмными плитами. Оттенок
   ставит applyScene() в `--msg-me` НА BODY (на html `var(--film-5)` застыл бы стеклянным
   значением — ловушка псевдонимов шкалы); чернила — темы, поэтому одна плёнка читается в обеих
   полярностях. Рамка держит «моё / не моё» и при нейтральной плёнке, когда от чужой реплики
   пузырь отличается только долей; рамкой, а не box-shadow — тень занята подсветкой находки
   (`.msg-hit`) и отказом отправки (`.msg-failed`). Поля на пиксель меньше — размер тот же. */
.msg.me{align-self:flex-end;background:var(--msg-me,var(--film-5));color:var(--ink);
  border:1px solid var(--edge);padding:10px 13px;border-bottom-right-radius:5px}
/* Выбранная для пересылки. Обводка, а не заливка: заливка спорила бы с цветом своей и чужой
   реплики, а выбор — временная пометка, не второй вид сообщения. */
.msg-picked{outline:2px solid var(--acc);outline-offset:2px}
/* Вложения. Картинка и видео показываются прямо в облачке — ради того их и присылают;
   ширина ограничена самим облачком, поэтому отдельного размера не задаём. */
.msg-att{display:block;max-width:100%;border-radius:11px;margin-bottom:6px}
/* Селектор — «картинка ВНУТРИ .msg-att»: класс стоит на ссылке (`<a class="msg-att"><img>`),
   поэтому прежнее правило `img.msg-att` не применялось к фото чата ни разу — отсюда и жалоба
   «фото отображается очень большим». max-height держит вертикальный снимок 9:16, который иначе
   занимает 768 точек; object-fit — единственное, что спасает пропорции у вложений без
   известных размеров, которым атрибуты width/height поставить не из чего. */
.msg-att img,video.msg-att{width:auto;max-width:100%;height:auto;max-height:340px;object-fit:contain}
.msg-att-note{display:block;font-style:normal;font-size:10.5px;opacity:.55;margin:-2px 0 6px}
.msg-voice{display:block;width:230px;max-width:100%;height:38px;margin-bottom:2px}
.msg-file{display:flex;align-items:center;gap:8px;text-decoration:none;color:inherit}
.msg-file .ic{width:16px;height:16px;flex:0 0 auto;opacity:.7}
.msg-file span{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msg-file em{font-style:normal;font-size:11px;opacity:.6;flex:0 0 auto}
/* Карточка объекта: не файл и не текст — своя плитка внутри облачка. Вид подписан сверху
   мелким, чтобы «Документ события» и «Пакет услуг» различались до нажатия. */
.msg-card{display:block;width:100%;text-align:left;border:1px solid var(--film-3);border-radius:11px;
  background:var(--film-2);color:inherit;padding:8px 10px;margin-bottom:4px;cursor:pointer}
.msg-card em{display:block;font-style:normal;font-size:10.5px;opacity:.6;margin-bottom:2px}
.msg-card b{display:block;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Крестик у своего сообщения — в строке времени, а не поверх текста: появляется по наведению
   на облачко, чтобы не мозолить глаза в каждой реплике. */
/* Строка времени переносится: действий в ней до шести, и с областью нажатия в 24 пикселя они
   не помещаются в облачко на узком экране — строка распирала пузырь и двигала ленту вбок, а
   вбок интерфейс не двигается (требование владельца). */
.msg time{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.msg-del{margin-left:auto;border:0;background:none;color:inherit;opacity:0;cursor:pointer;
  padding:0;line-height:0;transition:opacity .15s}
.msg-del .ic{width:13px;height:13px}
.msg:hover .msg-del,.msg-del:focus-visible{opacity:.75}
/* Область нажатия у действий реплики — 24 пикселя на обе стороны при значке в 13. Значок
   меньше не стал, выросло только место вокруг него: приёмка мерила 12×12 и промахивалась
   пальцем. Значения общие для обоих классов, поэтому стоят одним правилом рядом с ними. */
.msg-del,.msg-reply{display:inline-flex;align-items:center;justify-content:center;
  min-width:24px;min-height:24px}
/* Там, где наведения не существует (телефон, планшет), действия видны всегда: `opacity:0` на
   таком экране означает не «скрыто до наведения», а «нет вовсе» — переслать, отложить и
   закрепить нельзя было даже узнать. Правило по `hover:none`, а не по ширине: планшет с мышью
   и телефон различаются именно этим, а не числом пикселей. */
@media (hover:none){
  .msg-del,.msg-reply{opacity:.6}
}
/* Своё сообщение в пути — приглушено; не ушло — рамка и «Повторить» прямо в строке времени.
   Оба состояния читаются на облачке, не всплывашкой: всплывашка исчезает, а сообщение остаётся. */
.msg.msg-sending{opacity:.6}
.msg.msg-failed{box-shadow:inset 0 0 0 1.5px var(--r)}
.msg.msg-failed time{opacity:1;color:var(--r)}
.msg time .btn-link{border:0;background:none;padding:0;font:inherit;color:inherit;
  text-decoration:underline;cursor:pointer}
/* «не отправлено» в строке беседы — тем же красным, что и рамка облачка. */
.th-fail{color:var(--r);font-weight:600}
/* Пометка «Черновик»: где ждёт недописанный ответ. Приглушённая и перед текстом реплики — это
   подпись к строке, а не событие; спорить с точкой непрочитанного рядом ей не за что. */
.th-draft{font-style:normal;font-weight:600;color:var(--ink-3)}
/* «печатает…» стоит вместо последней реплики и отличается от неё насыщенностью: строка одна,
   и подкрашивать её акцентным цветом значило бы спорить с точкой непрочитанного рядом. */
.th-typing{font-style:normal;font-weight:600;color:var(--on)}
/* Закреплённое стоит НАД лентой и вне её прокрутки: смысл закрепления в том, что оно на виду,
   а уехав вместе с переписью вверх, оно ничем не отличалось бы от обычной реплики. */
.chat-pinned{flex:0 0 auto;border-bottom:1px solid var(--film-2);padding:6px 0 8px;margin-bottom:2px}
.pinned-row{display:flex;align-items:center;gap:6px}
.pinned-go{display:flex;align-items:center;gap:6px;flex:1 1 auto;min-width:0;text-align:left;
  border:0;background:none;color:inherit;cursor:pointer;padding:3px 0;font-size:12.5px}
.pinned-go .ic{width:13px;height:13px;flex:0 0 auto;opacity:.6}
.pinned-go b{flex:0 0 auto}
/* Текст в одну строку с многоточием: закреплённых бывает три, и развёрнутые они съедают
   пол-экрана переписки — ровно то, ради чего человек её и открыл. */
.pinned-go span{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;color:var(--ink-2)}
.pinned-more{margin:2px 0 0;font-size:11.5px;color:var(--ink-3)}
.chat-more{display:flex;justify-content:center;padding:2px 0 8px}
/* Кнопка «вниз». Скрыта по умолчанию и показывается классом `on`, который ставит слушатель
   прокрутки: у нижнего края она закрывала бы собой ту самую последнюю реплику, ради которой
   её нажимают. Место — над полем ввода, справа: там её ищут во всех мессенджерах, и там она
   не спорит ни с одним пузырём (те шире 72% ширины не бывают).

   Держится она отрицательным отступом, а НЕ `position:sticky`: прокручивается лента, а
   ближайший скролл-контейнер у листа — `.ws-body` (`overflow:hidden` тоже создаёт его), и
   sticky прижимал кнопку к низу рабочего поля, то есть под поле ввода. В потоке она стоит
   между лентой и `.composer`, наезжая отступом на низ переписки; отступы сходятся в ноль
   (-46 + 38 + 8), поэтому места в колонке она не занимает вовсе.

   `flex:0 0 auto` обязателен: колонка листа переполнена лентой, и заявленную высоту браузер
   сожмёт до высоты значка — приёмка намерила 40×18 вместо круга. У соседнего `.composer`
   такая же защита и ровно по той же причине. */
.chat-jump{display:none;flex:0 0 auto;position:relative;align-self:flex-end;margin:-46px 4px 8px;
  z-index:5;align-items:center;gap:4px;height:38px;min-width:38px;padding:0 10px;border:0;
  border-radius:19px;cursor:pointer;background:var(--on-solid);color:var(--on-solid-ink);
  box-shadow:0 6px 18px rgba(0,0,0,.18)}
.chat-jump.on{display:inline-flex}
.chat-jump-n{font-style:normal;font-size:12px;font-weight:700}
.chat-jump-n:empty{display:none}
/* Разделитель дня и полоса «отсюда не читал». Лента — flex-колонка, где реплики прижаты к
   своей стороне (`align-self`); эти двое занимают всю ширину и центрируют подпись сами. */
.chat-day{display:flex;justify-content:center;padding:4px 0}
.chat-day span{font-size:11px;color:var(--on-mute);background:var(--film-2);
  padding:3px 10px;border-radius:999px}
/* Полоса — линия во всю ширину с подписью: человек ищет глазами именно горизонтальную границу,
   а капсула по центру (как у даты) читалась бы как ещё один разделитель дней.
   Подпись — обычным приглушённым цветом, а не акцентным: акцент здесь неоново-салатовый и на
   светлой теме как текст нечитаем; линии он в самый раз — тем же цветом горит точка
   непрочитанного в списке бесед. */
.chat-new{display:flex;align-items:center;gap:9px;padding:2px 0;color:var(--on-dim);font-size:11px}
.chat-new::before,.chat-new::after{content:"";flex:1 1 auto;height:1px;background:var(--acc);opacity:.6}
/* Имя автора над первой репликой группы. Своё не подписываем, в личной переписке — тоже:
   там подписывать некого. */
.msg-from{align-self:flex-start;font-size:11.5px;font-weight:600;color:var(--on-dim);
  margin:2px 0 -5px;padding:0 4px}
/* Продолжение группы прижимается к предыдущей реплике: подряд идущие реплики одного человека
   читаются одним блоком. Селектор «сообщение сразу за сообщением той же стороны» и есть
   признак продолжения — между группами всегда стоит имя, дата или полоса. */
.msg.me+.msg.me,.msg.them+.msg.them{margin-top:-6px}
/* Идёт запись — кнопка микрофона краснеет и пульсирует: иначе понять, что микрофон уже
   слушает, можно только по индикатору браузера. */
.icon-btn.rec{background:var(--r)!important;color:#fff!important;animation:recpulse 1.1s infinite}
/* Бесконечная пульсация — единственная анимация кабинета, которая не кончается сама, и при
   уменьшенном движении она обязана сниматься: «идёт запись» несёт цвет кнопки, а не мигание.
   Найдено сторожем этапа 5 (panel-dvizhenie-reduce). */
@media (prefers-reduced-motion:reduce){ .icon-btn.rec{animation:none} }
@keyframes recpulse{50%{opacity:.55}}
/* Перенос нужен плашкам над полем ввода: «Отвечаете такому-то», «Пишете про …», «Переслать в
   событие» объявлены во всю ширину и с `order:-1`, то есть рассчитаны на СВОЮ строку сверху.
   Без переноса плашка вставала ещё одним элементом в общий ряд, и на её ширину сжимались поле
   с кнопкой: поле оседало до 127 px, «Отправить» уходило в столбик. Телефонная ветка переносит
   с самого начала — здесь того же не хватало. */
.composer{display:flex;flex-wrap:wrap;gap:9px;align-items:center;padding-top:14px;border-top:1px solid var(--line)}
/* Поле ввода чата не участвует в прокрутке листа: оно закреплено внизу колонки и не сжимается,
   что бы ни творилось со списком сообщений выше. */
.chat-sheet>.composer{flex:0 0 auto}
.composer input{flex:1 1 auto;min-width:0;padding:11px 15px;border-radius:99px;border:1px solid var(--line);
  background:var(--film-2);font-size:13.5px;color:var(--ink)}
.composer input::placeholder{color:var(--ink-3)}
.composer input:focus{outline:none;border-color:var(--stroke);background:var(--film-3)}

.empty{padding:56px 24px;text-align:center;max-width:430px;margin:0 auto}
.empty svg{width:34px;height:34px;color:var(--ink-3);margin-bottom:16px}
.empty h3{margin:0 0 9px;font-size:15px;font-weight:600}
.empty p{margin:0;font-size:13px;line-height:1.6;color:var(--ink-2)}

.note{margin-top:20px;font-size:11.5px;color:var(--ink-3);line-height:1.6}

/* Пояснение под заголовком экрана (таск 29): серым, без рамки и без подложки — оно объясняет,
   а не спорит за внимание с содержимым. Первая строка прокручиваемого тела, поэтому верхнего
   отступа у неё нет: он оторвал бы её от заголовка, под которым она и стоит.
   `max-width` — не украшение: строка на всю ширину монитора читается хуже, а «портянкой»
   пояснение становится ровно тогда, когда занимает три строки вместо одной. */
.scr-hint{margin:0 0 14px;font-size:12.5px;line-height:1.5;color:var(--ink-3);max-width:70ch}

/* Панель обоев — демонстрация того, что фон обязан быть настройкой с выключателем */
.wall{position:fixed;right:24px;bottom:24px;z-index:20;display:flex;flex-direction:column;align-items:flex-end;gap:10px}
/* Та же ловушка, что у .wall-row[hidden] ниже: свой display:flex перебивает встроенное
   [hidden], и панель админки висела бы над формой входа — где оформление ещё некому отдать. */
.wall[hidden]{display:none}
.wall-box{display:none;flex-direction:column;gap:14px;padding:16px;width:250px;border-radius:var(--rad);
  background:var(--glass-2);backdrop-filter:blur(calc(var(--w-blur) * 1px)) var(--w-fx);-webkit-backdrop-filter:blur(calc(var(--w-blur) * 1px)) var(--w-fx);
  border:1px solid var(--edge);color:var(--on);
  box-shadow:0 20px 44px -16px rgba(0,0,0,.7),inset 0 1px 0 var(--edge-hi)}
.wall.open .wall-box{display:flex}
.wall-box h4{margin:0;font-size:12px;font-weight:600;color:var(--on-dim);letter-spacing:.02em;text-transform:uppercase}
.swatches{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
/* Число колонок = числу ячеек в ряд, и оно у экранов РАЗНОЕ. В кабинете ячеек четыре (одна
   встроенная сцена и три слота под свои фотографии) — четыре колонки дают один ровный ряд.
   В админке встроенных сцен шесть, всего девять ячеек, и в четыре колонки они ложатся 4/4/1:
   последний «плюс» висит один. Отсюда своя модификация, а не правка общего правила: три колонки
   в кабинете дали бы там 3/1 — ровно та же дыра, только у соседа. Колонки долевые, поэтому
   ширина панели не меняется: плитки становятся крупнее, сетка — выше. */
.swatches.sw-3{grid-template-columns:repeat(3,1fr)}
/* Крупнее плитки — выше коробка: девять ячеек по 66px это 216px против 48px кабинетного ряда,
   и на ноутбуке 720p верх панели уезжал за край экрана вместе с заголовком. Предел с прокруткой
   внутри, а не уменьшенные плитки: сцену выбирают глазами. Ограничение живёт у ТОЙ ЖЕ
   модификации, что и сетка: общее правило действовало и на кабинет, где оно не нужно вовсе, —
   безвредно ровно до того дня, когда кабинетная коробка дорастёт до предела и молча получит
   прокрутку, которой никто не заказывал. */
.wall-box:has(.swatches.sw-3){max-height:calc(100vh - 108px);overflow-y:auto}
.sw{aspect-ratio:1;border-radius:10px;border:2px solid transparent;transition:border-color .18s var(--ease)}
.sw.on{border-color:var(--acc)}
.sw{background-size:cover;background-position:center;position:relative;overflow:hidden}
.sw.on::after{content:'';position:absolute;inset:0;box-shadow:inset 0 0 0 2px var(--acc);border-radius:8px}
/* Плитка загрузки своего файла — не картинка, а действие: пунктир и знак «+». */
.sw-up{display:grid;place-items:center;background:var(--film-2);
  border:1px dashed var(--stroke);color:var(--on-dim)}
.sw-up:hover{background:var(--film-4);color:var(--on)}
.sw-up svg{width:16px;height:16px}
/* Свой слот — картинка с крестиком в углу. Обёртка нужна, чтобы крестик не участвовал в сетке
   миниатюр отдельной ячейкой: слот один, действий у него два. */
.sw-wrap{position:relative;display:block}
.sw-wrap .sw{width:100%}
/* Слот занят ЗАПИСЬЮ, а не загрузившейся картинкой: файла в бакете может не быть (сорванная
   загрузка, строка от прежних прогонов), и тогда плитка без подложки — прозрачный квадрат,
   неотличимый от свободного места. Сервер при этом слот считает занятым и на четвёртый фон
   отвечает отказом. Отсюда своя подложка и крестик, видимый сразу, а не по наведению: убрать
   такой слот человек обязан мочь, не догадываясь, что под пустотой что-то есть.
   Класс ставит только панель админки: у кабинета свои фотографии лежат в браузере, картинке
   там неоткуда пропасть, и открывать там крестик постоянно — менять чужой экран без повода. */
.sw-my{background-color:var(--film-3);border-color:var(--stroke)}
.sw-x{position:absolute;top:-5px;right:-5px;width:18px;height:18px;border-radius:99px;
  display:grid;place-items:center;background:var(--on-solid);color:var(--on-solid-ink);
  border:0;opacity:0;transition:opacity .18s var(--ease)}
.sw-x svg{width:11px;height:11px}
.sw-wrap:hover .sw-x,.sw-x:focus-visible,.sw-my ~ .sw-x{opacity:1}
.wall-row{display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12px;color:var(--on-dim)}
/* Скрытая строка настройки обязана исчезать: у .wall-row свой display:flex, и он перебивает
   встроенное [hidden] — «Светлые окна» оставались видны у плотных тем, где второй оси нет. */
.wall-row[hidden]{display:none}
/* Переключатель режимов — сегменты, а не выпадашка: три варианта видны сразу. */
.modes{display:flex;gap:4px;padding:3px;border-radius:var(--rad-s);background:var(--film-2)}
.mode{flex:1 1 0;padding:7px 4px;border-radius:9px;font-size:12px;font-weight:500;
  color:var(--on-dim);transition:background .18s var(--ease),color .18s var(--ease)}
.mode:hover{color:var(--on)}
.mode.on{background:var(--on-solid);color:var(--on-solid-ink);font-weight:600}
/* Настройки фона гаснут вне стеклянного режима — там сцены нет. */
.bg-off #bgHead,.bg-off .swatches,.bg-off .bg-ctl{opacity:.4;pointer-events:none}
/* Цвет интерфейсных кнопок */
.accents{display:flex;gap:9px}
.ac{width:26px;height:26px;flex:0 0 26px;border-radius:99px;border:2px solid transparent;
  transition:transform .2s var(--spring)}
.ac:hover{transform:scale(1.12)}
.ac.on{border-color:#fff;box-shadow:0 0 0 2px rgba(0,0,0,.45)}
input[type=range]{width:100%;accent-color:var(--acc);background:transparent}
input[type=range]:disabled{opacity:.35;cursor:not-allowed}
.toggle{width:40px;height:23px;border-radius:99px;background:var(--fill-2);position:relative;flex:0 0 40px;
  transition:background .2s var(--ease)}
.toggle::after{content:'';position:absolute;top:3px;left:3px;width:17px;height:17px;border-radius:99px;background:#fff;
  transition:transform .24s var(--spring)}
.toggle.on{background:var(--acc)}
.toggle.on::after{transform:translateX(17px)}
/* Кнопка выхода в подвале панели настроек и ряд каналов уведомлений. */
.settings-logout{width:100%;justify-content:center;color:var(--r)}
.settings-logout:hover{background:color-mix(in srgb,var(--r) 14%,transparent);color:var(--r)}
.notif-chans{display:flex;gap:8px;flex:0 0 auto}
/* Тумблер в списке уведомлений живёт на бумаге, а не на стекле — подложка темнее. */
.sheet .toggle{background:var(--film-4)}
.sheet .toggle.on{background:var(--acc)}
.wall-fab{width:46px;height:46px;border-radius:99px;display:grid;place-items:center;color:var(--on);
  background:var(--glass-2);backdrop-filter:blur(calc(var(--w-blur) * 1px)) var(--w-fx);-webkit-backdrop-filter:blur(calc(var(--w-blur) * 1px)) var(--w-fx);
  border:1px solid var(--edge);box-shadow:0 14px 30px -12px rgba(0,0,0,.7),inset 0 1px 0 var(--edge-hi);
  transition:transform .3s var(--spring)}
.wall-fab:hover{transform:scale(1.06)}
.wall-fab svg{width:19px;height:19px}

/* Одна авторская моторика: рабочий лист приходит из глубины при смене экрана. */
@keyframes surface{from{opacity:0;transform:translateY(10px) scale(.994);filter:blur(3px)}
  to{opacity:1;transform:none;filter:blur(0)}}
.ws-body>*{animation:surface .42s var(--ease) both}

.sprite{position:absolute;width:0;height:0;overflow:hidden}
/* Базовый размер обязателен: <use> без width/height разворачивается в дефолтные 300×150. */
svg.ic{width:18px;height:18px;flex:0 0 auto;display:block;
  fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}

@media (max-width:1180px){
  /* Панель сжимается, но не исчезает — владелец уже ловил `display:none` как «пропал второй блок». */
  :root{--panel-w:calc(264px - (100 - var(--win)) * 1.1px)}
  .panel-top,.folders,.panel-list{padding-left:14px;padding-right:14px}
  .folder i{font-size:14px}
}
@media (max-width:980px){
  /* Планшет: подписи папок переносятся, а не обрезаются многоточием. */
  .folder b{white-space:normal;font-size:11.5px}
}
@media (max-width:860px) and (min-width:721px){
  .app{padding:8px;gap:8px}
  :root{--panel-w:calc(224px - (100 - var(--win)) * .9px)}
  .kanban{grid-template-columns:1fr}
  .ws-body{padding:18px 14px 24px}
  .sheet{padding:16px}
}
/* Телефон: девять разделов в ряд не помещаются даже мелкими кнопками. Лента остаётся лентой и
   прокручивается вбок, но об этом надо сказать глазу — иначе половина разделов просто не
   существует для человека. Отсюда затухание у краёв и подкрутка активной кнопки в видимую часть
   после каждой перерисовки (см. render в app.html). */
@media (max-width:720px){
  /* justify-content:center на прокручиваемой ленте прячет её начало: при переполнении контент
     вылезает в обе стороны, а прокрутить влево от нулевой позиции нельзя — первые разделы
     становятся физически недостижимыми. Поэтому на узком экране лента прижимается к началу. */
  .rail-nav{justify-content:flex-start;
    -webkit-mask-image:linear-gradient(90deg,transparent,#000 14px,#000 calc(100% - 14px),transparent);
    mask-image:linear-gradient(90deg,transparent,#000 14px,#000 calc(100% - 14px),transparent)}
  /* Прокручивается .rail-nav, но мерит она своего ребёнка: пока обёртка капсулы тянулась на всю
     ширину, прокрутка «заканчивалась» раньше самой капсулы, и первые разделы оставались
     недостижимыми при scrollLeft = 0. */
  .pill-wrap{flex:0 0 auto;width:max-content;max-width:none}
  .rail-pill{width:max-content;flex:0 0 auto}
  /* Профиль ужимается до аватара с шестерёнкой: имя и роль на телефоне и так скрыты. */
  .rail-bot{flex:0 0 auto}
}
@media (max-width:720px){
  /* Три кубика в ряд на узком экране — каждому достаётся около шестидесяти пикселей. При
     базовом кегле «Каталог» и «Агентство» туда не встают целиком, поэтому подпись мельче:
     читаемое слово важнее одинакового размера шрифта по всему приложению. */
  .folder{padding:10px 5px}
  .folder b{font-size:11px;letter-spacing:-.02em}

  /* Пальцем в крестик 22–24 пикселя не попасть — а это кнопки УДАЛЕНИЯ, и рядом с ними лежит
     то, что удалять не собирались. Сама иконка остаётся прежней (в плотном списке крупный
     крест выглядел бы как основное действие), увеличивается только область нажатия — так же,
     как это делают системные списки. */
  .lead-x, .kcol-x{position:relative}
  .lead-x::after, .kcol-x::after{content:'';position:absolute;
    top:50%;left:50%;transform:translate(-50%, -50%);
    width:44px;height:44px;border-radius:99px}

  /* На телефоне нет наведения: кнопка удаления этапа, показываемая только при :hover, была бы
     недостижима вовсе. */
  .kcol-x{opacity:1}
}
@media (max-width:720px){
  /* Телефон: три блока в ряд не помещаются. Панель НЕ прячется — она встаёт
     над рабочим полем, а рельс разворачивается в горизонтальную ленту.
     Порядок нажатий сохраняется: рельс → папка → подпункт → экран. */
  /* Прокручивается страница целиком, поэтому высота у неё по содержимому, а не «ровно экран»:
     с height:100% боди обрезал всё, что ниже первого экрана, — страница листалась, а под сгибом
     была чернота. Заметно это стало на «Домой», где под окном теперь лежат календарь и разделы. */
  html,body{height:auto;min-height:100%}
  /* НЕ overflow:auto у body. Он делает body контейнером прокрутки, а его собственная высота
     равна высоте содержимого — прокручивать внутри нечего, зато все position:sticky внутри
     считают своим предком именно его и не срабатывают НИКОГДА. Именно поэтому шапка раздела
     уезжала вверх вместе со страницей, а нижнее меню не сжималось: события прокрутки шли не
     туда, где их слушали. Прокручивается страница целиком. */
  body{overflow:visible}
  .app{height:auto;min-height:100%;overflow:visible;padding:8px;gap:8px}
  /* Рельс уже лента; на телефоне в стек уходят панель и рабочее поле.
     Панель НЕ прячется — она встаёт над полем. */
  .app-row{flex-direction:column;min-height:0}
  .rail{--rail-h:56px;padding:0 10px}
  .rail-btn{width:38px;height:38px;flex:0 0 38px}
  .rail-bot{padding-left:6px;gap:8px}
  .rail-bot .rail-btn{display:none}
  .pp-who{display:none}
  .panel{width:auto;flex:0 0 auto;max-height:none}
  .panel-top{padding:16px 16px 12px}
  .folders{padding:0 16px 12px}
  .panel-list{overflow:visible;padding:0 16px 16px}
  .pcard span{display:none}
  .ws{flex:1 1 auto;min-height:62vh}
  .ws-top{padding:13px 16px;gap:8px}
  .settings-caps{padding:10px 16px 0}
  .ws-top .crumb{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .ws-top h2{font-size:15px}
  .ws-top .btn{white-space:nowrap;padding:8px 11px}
  .ws-top .btn-quiet span,.ws-top .btn-ink span{display:none}
  .ws-body{padding:18px 14px 26px}
  .sheet{padding:16px}
  .grid-2,.kanban{grid-template-columns:1fr}
  .wall{right:14px;bottom:14px}
}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}
@media (prefers-reduced-transparency:reduce){
  :root{--surf-0:rgba(14,16,21,.98);--surf-1:rgba(18,20,26,.96);
    --surf-2:rgba(19,22,28,.98);--surf-3:rgba(24,26,32,.98)}
  .rail,.panel,.ws,.wall-box,.wall-fab,.panel-top,
  .panel .folder,.panel .pcard,.panel .thread,.panel .cpill{backdrop-filter:none;-webkit-backdrop-filter:none}
  .stage,.grain{opacity:.25}
}
/* На печати стекла нет вообще: иначе светлый текст ушёл бы на белый лист. */
/* Лист координатора (В7 его отчёта): на бумаге первым идёт то, ради чего лист и печатают, —
   контакты. На экране этот блок не нужен: там контакты живут своим разделом с кнопками звонка,
   а второй их список рядом читался бы как ошибка. */
.print-only{display:none}

/* Чипы пробелов на карточке доски: что ещё не сделано, одним взглядом. Приглушённые, а не
   красные: это список дел, а не тревога. */
.lead-gaps{display:flex;flex-wrap:wrap;gap:4px;margin:0 0 7px}
.lead-gaps span{font-size:10.5px;padding:2px 8px;border-radius:99px;background:var(--film-3);
  color:var(--ink-3);border:1px dashed var(--line)}

/* Кнопка-ссылка внутри текста примечания: «вернуть все» — действие, но не кнопка-плита. */
.crumb-link{font:inherit;color:inherit;cursor:pointer;padding:0;border:0;background:none;
  text-decoration:underline;text-underline-offset:3px}
.crumb-link:hover{color:var(--ink)}

/* ── Документы из шаблонов ─────────────────────────────────────────────── */
/* Лист документа: светлая бумага и тёмный текст даже в тёмном кабинете — договор читают и
   печатают, и выглядеть он должен как документ, а не как чат. */
.doc-paper{background:#fff;color:#181a1e;border-radius:var(--rad-s);padding:26px 30px;
  max-height:56vh;overflow-y:auto;font-size:13.5px;line-height:1.6}
.doc-paper h1{font-size:19px;margin:0 0 14px;letter-spacing:-.02em}
.doc-paper h2{font-size:15px;margin:18px 0 8px}
.doc-paper h3{font-size:13.5px;margin:14px 0 6px}
.doc-paper p{margin:0 0 9px}
.doc-paper ul{margin:0 0 10px;padding-left:20px}
.doc-paper li{margin:0 0 4px}
.doc-paper table{border-collapse:collapse;width:100%;margin:0 0 12px}
.doc-paper td,.doc-paper th{border:1px solid #d5d7da;padding:6px 10px;font-size:12.5px}
/* Шапка таблицы документа. Отдельным `th` она стала ради печати (`display:table-header-group`
   повторяет на каждой странице только его), и раз уж она теперь шапка — выглядит шапкой. */
/* Цвет и регистр заданы ЯВНО: общий `th` оболочки красит шапку в приглушённый серый темы
   (`--ink-3`) и пишет её капителью — на белом листе документа это давало серый по серому,
   контраст 1,3:1, то есть подписи колонок было не прочитать ни на экране, ни на бумаге. */
.doc-paper th{text-align:left;font-weight:600;background:#f2f3f1;color:#181a1e;
  text-transform:none;letter-spacing:normal;font-size:12.5px}
/* Факсимиле подписи (настройки → «Документы») — тот же приём, что у doc-paper: белый лист,
   не поверхность темы, потому что печатается на реальном документе поверх такой же белой бумаги. */
.facs-preview{max-width:220px;max-height:90px;display:block;margin-bottom:10px;background:#fff;
  border:1px solid var(--line);border-radius:8px;padding:6px}
.doc-edit{width:100%;min-height:46vh;resize:vertical;background:var(--film-2);
  border:1px solid var(--line);border-radius:var(--rad-s);color:var(--ink);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;line-height:1.55;
  padding:14px}

@media print{
  /* `.tabbar` — нижнее меню телефона. На экране его прячет `body:has(.modal-back)`, но лист
     печатают и без открытого окна, и тогда семь кнопок уезжали на бумагу поверх содержимого:
     меню `position:fixed`, а фиксированный элемент печатается на КАЖДОЙ странице. */
  .stage,.grain,.rail,.panel,.wall,.tabbar{display:none}
  /* Стекло на бумаге даёт серую кашу: размытие принтер не воспроизводит, а тень печатает.
     Правило общее, а не по одному классу, — новый стеклянный блок иначе унесёт кашу с собой. */
  *{backdrop-filter:none !important;-webkit-backdrop-filter:none !important;
    box-shadow:none !important;text-shadow:none !important}
  /* Шапка таблицы повторяется на каждой странице, строка не рвётся пополам. Без первого лист
     со второй страницы становится набором чисел без подписей — а задание площадке и наряд
     координаторам это ровно таблицы на две-три страницы. */
  thead{display:table-header-group}
  tr{break-inside:avoid;page-break-inside:avoid}
  /* Окно события — flex-колонка ФИКСИРОВАННОЙ высоты (`min(760px,90vh)`), и прокручивается в
     нём только `.pj-body`. На печати это значит ровно один экран содержимого: смета на тридцать
     строк уходила в принтер первыми восемью. Высота и прокрутка снимаются с обоих. */
  .modal-full{height:auto !important;max-height:none !important;overflow:visible !important}
  .pj-body,.rows-scroll,.modal{overflow:visible !important;max-height:none !important}
  /* Смета на бумаге: таблица на экране лежит в прокручиваемой коробке, и без этого правила
     в принтер уходила бы только видимая её часть — то есть первые несколько статей.
     Заголовки разделов не отрываются от своих строк: разрыв страницы ровно между «Банкетом»
     и его первой статьёй превращает лист в загадку. */
  .tw{overflow:visible !important;max-height:none !important}
  .tw table{width:100% !important}
  .est-sec{break-after:avoid;page-break-after:avoid}
  .est-sec td{background:#f2f2f2 !important;-webkit-print-color-adjust:exact;print-color-adjust:exact}
  tfoot{break-inside:avoid;page-break-inside:avoid}
  /* Открыт документ — печатается ТОЛЬКО он: рабочее поле и шапка модалки на бумаге не нужны.
     Прячутся СОСЕДИ окна, а не `.app` целиком: кабинет рисует всё внутрь `#app`, включая сами
     окна, и `display:none` на нём уносил документ вместе с рабочим полем — в принтер уходил
     чистый лист. Найдено живой проверкой 08.09.2026 (таск 43): правило было написано под
     разметку, где окна лежали снаружи `.app`. */
  body:has(.doc-print) .app > *:not(.doc-print){display:none}
  .doc-print{position:static;background:#fff;padding:0}
  .doc-print .modal{position:static;width:auto;max-width:none;max-height:none;box-shadow:none;
    border:0;background:#fff;padding:0}
  .doc-print .doc-paper{max-height:none;overflow:visible;padding:0;border-radius:0}
  .print-only{display:block}
  /* Командный пункт на бумаге бесполезен: он про живые отметки и обратный отсчёт, а лист их не
     показывает. Печатать его — значит занять полстраницы кнопками, на которые нельзя нажать. */
  .screen-only{display:none}
  /* Кнопки на листе — пустые рамки. Единственное, что они делают на бумаге, — занимают место. */
  .btn,.modal-f{display:none}
  /* Печать пишет в ШКАЛУ и на body — там же, где объявлены псевдонимы. На :root это правило
     перестало бы действовать: псевдоним на body ближе к элементу, и --paper брал бы экранное
     значение темы, а лист уходил бы в принтер с фоном оболочки. */
  /* Селектор с классом, а не голый body: .m-dark и .m-light — тоже классы, и при печати
     из тёмной темы они перебивали бы этот набор, отправляя в принтер тёмный лист. */
  body.m-dark,body.m-light,body{--surf-0:#fff;--surf-1:#fff;--surf-2:#fff;--surf-3:#fff;--pop:#fff;
    --ink:#111;--ink-2:#444;--ink-3:#666;--line:#ddd;--edge:#ddd;--edge-hi:#ccc;
    --fill:#f2f3f1;--fill-2:#e8e9e7;--film-1:#fafafa;--film-2:#f7f7f7;--film-3:#f2f3f1;
    --film-4:#ededed;--film-5:#e8e9e7;--on-solid:#111;--on-solid-ink:#fff}
  .ws{border:0;box-shadow:none;background:#fff;backdrop-filter:none;-webkit-backdrop-filter:none}
  .ws-top,.sheet,.fig,.kcol,.kcard{background:#fff!important}
  .tag{background:#fff!important;color:#111!important;border:1px solid #ccc}
  .bar,.tw table{background:#fff}
}

/* ─── Вход: та же система, никаких новых материалов ─── */
.auth-wrap{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
.auth-card{width:100%;max-width:380px;display:flex;flex-direction:column;gap:14px;
  background:var(--paper);backdrop-filter:blur(26px) var(--w-fx);-webkit-backdrop-filter:blur(26px) var(--w-fx);
  border:1px solid var(--edge);box-shadow:0 22px 50px -20px rgba(0,0,0,.6),inset 0 1px 0 var(--edge-hi);
  border-radius:var(--rad-l);padding:26px}
.auth-logo{width:44px;height:44px;border-radius:14px;background:var(--acc);color:var(--acc-ink);
  display:flex;align-items:center;justify-content:center}
.auth-logo svg{width:24px;height:24px}
.auth-card h1{font-size:23px;font-weight:600;letter-spacing:-.025em;margin:0;color:var(--ink)}
.auth-card .note{margin:0}
.auth-err{font-size:12.5px;color:var(--r);background:color-mix(in srgb,var(--r) 16%,transparent);
  border-radius:12px;padding:9px 12px}
.auth-card .btn-acc{justify-content:center;padding:11px 16px;font-size:13.5px}
/* Отметки согласий в анкете. Текст переносится и не жмётся к квадратику: у трёх подписей со
   ссылками одна строка не бывает. Галочка сверху, а не по центру строки — иначе на двух
   строках она уезжает в середину и перестаёт читаться как отметка к первому слову. */
.chk-legal{display:flex;align-items:flex-start;gap:9px;font-size:12.5px;line-height:1.5;
  color:var(--ink-2);margin-top:9px}
.chk-legal input{margin-top:2px;flex:0 0 auto}
.chk-legal a{color:var(--ink)}
/* Плашка «подтвердите почту» — запись в колокольчике (`.bell-pop`) и перед анкетой знакомства. */
.ev-warn{flex:0 0 auto;border-color:color-mix(in srgb,var(--acc) 45%,var(--line))}
/* Та же плашка перед анкетой знакомства стоит внутри модального окна: своё стекло у окна уже
   есть, и второй рамкой с плёнкой она читалась бы как вложенная карточка. */
.modal-ev > .ev-warn{background:none;border:0;border-radius:0;padding:0}
/* В колокольчике плашка ужата: попап шириной 340px, и полей листа ей много. */
.bell-pop > .ev-warn{padding:12px 14px;margin-bottom:12px}
.bell-pop > .ev-warn .sheet-h{margin-bottom:8px}
.bell-pop > .ev-warn .ev-row{margin-top:10px}
.ev-row{display:flex;flex-wrap:wrap;align-items:center;gap:10px;margin-top:14px}
.ev-code{width:150px;padding:9px 12px;border-radius:12px;border:1px solid var(--stroke);
  background:var(--paper-2);color:var(--ink);font-size:13.5px;letter-spacing:.14em}
/* Кнопка входа через VK — та же форма, что у остальных кнопок карточки, плюс узнаваемый
   значок бренда. Сама кнопка — ссылка (полный переход, не JS), поэтому центрируем текст,
   как у обычных <button>. */
.auth-vk{justify-content:center;padding:11px 16px;font-size:13.5px;text-decoration:none}
.vk-badge{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;
  flex:0 0 18px;border-radius:5px;background:#0077ff;color:#fff;font-size:10px;font-weight:700;
  letter-spacing:-.02em}
/* Возврат на витрину. Экран входа — тупик: человек, зашедший почитать про систему, попадал сюда
   и мог только закрыть вкладку. Ссылка тихая и стоит последней: она нужна тем, кто ещё
   выбирает, а не тем, кто пришёл работать. */
.auth-home{display:block;text-align:center;color:var(--ink-3);font-size:12.5px;
  text-decoration:none;padding:2px 0}
.auth-home:hover{color:var(--ink-2)}

/* Первый шаг регистрации — выбор, кто вы. Карточка расширяется: двадцать профессий должны быть
   видны разом, а не прятаться в выпадающем списке. Список скрывает выбор — человек не понимает,
   есть ли там его профессия вообще, и уходит гадать. */
.auth-card.wide{max-width:900px}
.role-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(184px,1fr));gap:9px}
.role-card{text-align:left;background:var(--fill);border:1px solid var(--line);border-radius:var(--rad-s);
  padding:12px 13px;cursor:pointer;color:var(--ink);font:inherit;transition:background .16s var(--ease),
  border-color .16s var(--ease),transform .16s var(--spring)}
.role-card:hover{background:var(--fill-2);border-color:var(--edge-hi);transform:translateY(-1px)}
.role-card b{display:block;font-size:13.5px;font-weight:600;letter-spacing:-.01em;margin-bottom:3px}
.role-card span{display:block;font-size:11.5px;line-height:1.45;color:var(--ink-3)}
/* Две особые карточки — во всю ширину: это не «ещё одна профессия», а другой тип аккаунта. */
.role-card.full{grid-column:1/-1;background:var(--film-2)}
.role-card.full b{font-size:14.5px}
.role-sep{display:flex;align-items:center;gap:12px;margin:4px 0 2px;color:var(--ink-3);font-size:11.5px}
.role-sep::before,.role-sep::after{content:'';flex:1;height:1px;background:var(--line)}
.auth-back{background:none;border:0;padding:0;color:var(--ink-3);font:inherit;font-size:12.5px;
  cursor:pointer;text-align:left}
.auth-back:hover{color:var(--ink)}
.auth-picked{display:flex;align-items:center;gap:10px;padding:10px 13px;border-radius:var(--rad-s);
  background:var(--film-2);border:1px solid var(--line)}
.auth-picked b{font-size:13.5px;font-weight:600}
/* Заготовка от VK на анкете регистрации: фото — прямое доказательство, что данные реальные,
   а не «мы что-то придумали». Показываем присланное фото как есть; без него — тот же значок
   бренда, что на кнопке входа, чтобы происхождение данных было понятно и без снимка. */
.auth-vk-prefill{display:flex;align-items:center;gap:10px;padding:10px 13px;margin-bottom:2px;
  border-radius:var(--rad-s);background:var(--film-2);border:1px solid var(--line);
  font-size:12px;color:var(--ink-2)}
.auth-vk-prefill img{width:34px;height:34px;flex:0 0 34px;border-radius:99px;object-fit:cover}
.chips{display:flex;flex-wrap:wrap;gap:7px}
.chip-btn{padding:7px 13px;border-radius:99px;background:var(--fill);border:1px solid var(--line);
  color:var(--ink-2);font:inherit;font-size:12.5px;cursor:pointer}
.chip-btn:hover{background:var(--fill-2);color:var(--ink)}
.chip-btn.on{background:var(--on-solid);color:var(--on-solid-ink);border-color:transparent;font-weight:600}

/* Сообщение о результате действия — стекло той же плотности, что и плавающие элементы. */
.nx-toast{position:fixed;left:50%;bottom:26px;transform:translate(-50%,14px);z-index:90;
  max-width:min(520px,calc(100vw - 32px));padding:12px 18px;border-radius:99px;
  background:var(--glass-2);backdrop-filter:blur(20px) var(--w-fx);-webkit-backdrop-filter:blur(20px) var(--w-fx);
  border:1px solid var(--edge);box-shadow:0 20px 44px -16px rgba(0,0,0,.7),inset 0 1px 0 var(--edge-hi);
  color:var(--on);font-size:13px;font-weight:500;opacity:0;pointer-events:none;
  transition:opacity .2s var(--ease),transform .3s var(--spring)}
.nx-toast.on{opacity:1;transform:translate(-50%,0)}
@media(prefers-reduced-motion:reduce){.nx-toast{transition:none}}

/* Заявка: контакт и просроченное касание — то, что читают на карточке первым. */
.lead-contact{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--ink-2);margin-top:5px}
.lead-contact .ic{width:13px;height:13px;flex:0 0 auto;opacity:.75}
.lead-due{outline:1px solid color-mix(in srgb,var(--r) 55%,transparent);outline-offset:-1px}
/* Широкое окно — для форм, где полей на две колонки: заявка спрашивает всё, что сказано
   в первом разговоре, и в одну колонку это превращается в свиток. Ширина через width, а не
   max-width: у .modal своя width:min(440px,100%), и max-width её не перебил бы. */
.modal-wide{width:min(880px,94vw);max-width:none}
/* Поп-ап с личной страницей: широкий и высокий, чтобы витрина читалась целиком, а не в щель.
   Внутри — iframe на /u/<id>, поэтому у самой модалки прокрутки нет: скроллится страница
   внутри рамки. */
.modal-page{width:min(760px,94vw);max-width:none;display:flex;flex-direction:column;
  height:min(88vh,900px);overflow:hidden}
/* `flex:1 1 0`, а не `auto`: у окна фиксированная высота, и с базисом «по содержимому» рамка
   отдаёт свою высоту целиком любому блоку, выросшему рядом (правило из CLAUDE.md, куплено
   дефектом окна сметы). Над рамкой теперь стоит рабочая справка по залу — без этого она бы
   сплющила визитку в полоску. Нижняя граница живая: ниже 160 px страницу не прочитать. */
.page-frame{flex:1 1 0;min-height:160px;width:100%;border:0;border-radius:var(--rad);
  background:var(--paper);margin:4px 0}
/* Рабочая справка по залу над визиткой (таск 101): чипы в одну-две строки, дальше прокрутка
   внутри себя, чтобы зал с десятком заполненных полей не съел саму визитку. */
.page-venue{flex:0 0 auto;max-height:26vh;overflow:auto;padding:2px 0}
/* Фото в настройках страницы — сетка одинаковых квадратов, а не поток картинок во всю ширину.
   Без размера каждый снимок растягивался на всю колонку, и шесть фото превращали настройки в
   бесконечную ленту. Теперь миниатюры фиксированного размера, обрезанные по центру. */
.grid-photos{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:8px;margin:2px 0 4px}
.ph-item{position:relative;aspect-ratio:1;border-radius:var(--rad-s);overflow:hidden;border:1px solid var(--line)}
.ph-item img{width:100%;height:100%;object-fit:cover;display:block}
.ph-item .lead-x{position:absolute;top:4px;right:4px;background:rgba(0,0,0,.55);color:#fff;border-radius:99px}

/* ── Окно события: вкладки со всеми разделами ───────────────────────────────
   Окно шире и выше обычного: внутри живут те же экраны, что в разделе «Задачи», и смета с
   рассадкой в колонке на 440 пикселей не читаются. */
/* Высота ФИКСИРОВАННАЯ, а не min-height: с min-height окно прыгало по высоте на каждой
   вкладке. Прокручивается только тело (.pj-body); шапка, лента вкладок и капсулы — вне
   прокрутки, поэтому окно — flex-колонка с overflow:hidden вместо прокрутки всего .modal. */
.modal-full{width:min(1180px,96vw);max-width:none;height:min(760px,90vh);
  display:flex;flex-direction:column;overflow:hidden}
/* Шапка не ужимается: на узком экране лента вкладок переносится на две строки, и flex-колонка
   иначе отбирала бы высоту у шапки — название события съезжало под кнопку закрытия. */
.modal-full .modal-h{flex:0 0 auto}
/* Лента не листается вбок: шесть вкладок при нехватке ширины переносятся на новую строку. */
.pj-tabs{display:flex;flex-wrap:wrap;align-items:center;gap:6px;flex:0 0 auto;
  margin:0 -22px 12px;padding:0 22px 12px;
  background:var(--glass-2);border-bottom:1px solid var(--edge)}
.pjt{flex:0 0 auto;padding:7px 13px;border-radius:99px;border:1px solid transparent;
  background:transparent;color:var(--on-dim);font:inherit;font-size:13px;cursor:pointer;
  white-space:nowrap;transition:background .16s,color .16s}
.pjt:hover{background:var(--film-2);color:var(--on)}
.pjt.on{background:var(--on-solid);color:var(--on-solid-ink);font-weight:600}
/* Вкладку тащат мышью, чтобы переставить: бледнеет сама, а место броска подчёркивается
   слева — вертикальная черта читается как «встанет сюда», а рамка вокруг читалась бы как
   «выбрано». */
.pjt[draggable="true"]{cursor:grab}
.pjt.is-dragging{opacity:.45;cursor:grabbing}
.pj-tabs .pjt.is-over{box-shadow:inset 3px 0 0 var(--acc)}
/* Тащим слева направо — вкладка встанет СПРАВА от цели, и черта обязана быть там же. */
.pj-tabs .pjt.is-over-right{box-shadow:inset -3px 0 0 var(--acc)}
/* Возврат к порядку по умолчанию — не вкладка: сдвинут вправо и приглушён, чтобы не читался
   пунктом ленты. */
.pjt-reset{margin-left:auto;font-size:12px;color:var(--on-dim);opacity:.75}
/* Режим «переставить»: пальцем вкладку не потащить — HTML5 drag-and-drop на тач-экране не
   начинается вовсе, — поэтому в режиме у вкладки появляются стрелки шага к соседу. Кнопки
   размером с палец: ниже 40×34 промахи перестают быть случайностью. */
.pjt-mv{display:inline-flex;align-items:center;gap:6px;padding:3px 5px}
.pjt-arr{min-width:40px;height:34px;border:0;border-radius:99px;background:var(--film-2);
  color:inherit;font:inherit;font-size:15px;line-height:1;cursor:pointer}
.pjt-arr:hover:not(:disabled){background:var(--film-4)}
.pjt-arr:disabled{opacity:.35;cursor:default}
/* Кнопок в правом углу две — «⇅ порядок» и «↺ порядок»; вправо уводит только первая. */
.pjt-reset + .pjt-reset{margin-left:0}

/* Капсулы-подвкладки активной группы: мельче главных и с лёгким фоном, чтобы читались
   вторым уровнем, а не продолжением ленты. */
.pj-caps{display:flex;flex-wrap:wrap;gap:6px;flex:0 0 auto;margin:-2px 0 14px}
.pj-caps .pjt{font-size:12px;padding:5px 11px;background:var(--film-2)}
.pj-caps .pjt.on{background:var(--on-solid)}
.pj-body{min-width:0;flex:1 1 auto;overflow-y:auto;overscroll-behavior:contain}
/* Подпись группы профессий в команде события: карточки идут группами, и без подписи два
   фотографа подряд читались как один человек с двумя прайсами. */
.team-grp{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin:10px 0 2px}
/* Строка команды — именно СТРОКА (таск 66): имя и подпись в один ряд, аватар меньше, отступы
   уже. По умолчанию `.row-main span` блочный (он рассчитан на две строки текста), и подпись
   уходила бы вниз; на вкладке «Коллеги» человек занимал 343 px, то есть команда из десяти —
   три с половиной тысячи. Подпись обрезается многоточием: вбок кабинет не листается. */
.team-row{padding:5px 2px;gap:10px}
.team-row .ava{width:24px;height:24px;flex:0 0 24px;font-size:9.5px}
.team-row .row-main{display:flex;align-items:baseline;gap:8px}
.team-row .row-main b{flex:0 0 auto}
.team-row .row-main span{flex:1 1 auto;min-width:0;font-size:12px;color:var(--ink-3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Развёрнутая форма правки внешнего участника — единственный случай, когда строка растёт. */
.team-row.row-wrap .row-main{flex-wrap:wrap}
/* Незанятые роли одной строкой: чипсы жмутся вправо и переносятся, имя строки не сжимается. */
.team-gap .chat-pills{flex:1 1 auto;flex-wrap:wrap;gap:4px;min-width:0}
.team-grp b{font-size:13px;font-weight:600}
.team-grp em{font-size:11.5px;color:var(--ink-3);font-style:normal}
/* Предпросмотр листа ТЗ: текст переносится по словам и НЕ листается вбок — на 375px лист
   иначе растягивал бы всё окно горизонтально. */
.brief-prev{margin:8px 0 0;padding:10px 12px;border-radius:10px;background:var(--film-2)}
.brief-prev pre{margin:0 0 8px;font:inherit;font-size:12px;line-height:1.6;
  white-space:pre-wrap;overflow-wrap:anywhere;max-height:320px;overflow-y:auto}
/* Экраны внутри окна не рисуют собственный фон поверх стекла окна. */
.pj-body .sheet{background:transparent;border:0;padding:0;box-shadow:none}
.pj-body .grid-2{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:18px}

/* Площадка события — карточка, а не поле ввода: смотрят на неё чаще, чем меняют. */
.pj-venue{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:var(--rad);
  background:var(--film-2);border:1px solid var(--edge);margin-bottom:8px}
.pj-venue .row-main{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.pj-venue .row-main b{font-size:14px;font-weight:600}
.pj-venue .row-main span{font-size:11.5px;color:var(--on-dim)}
.pj-venue-empty .row-main b{color:var(--on-dim);font-weight:500}

/* Подбор — второй слой поверх окна события. Затемнение слабее: нижнее окно должно оставаться
   видимым, иначе непонятно, куда вернёшься после выбора. */
.modal-back-2{z-index:50;background:rgba(8,10,14,.4)}
/* Профессий двадцать: без своей прокрутки они выдавливают город, дату и рейтинг за нижний
   край окна — то есть прячут ровно те фильтры, ради которых окно и открывали. */
.pick-roles{max-height:150px;overflow-y:auto;overscroll-behavior:contain;padding-right:4px}
/* Окно подбора — маленький каталог: слева фильтры, справа витрина. Вопрос, с которым сюда
   приходят, звучит «кто свободен пятнадцатого в этом городе», и одним полем поиска на него
   не ответить. */
.pick-modal{width:min(1180px,96vw)}
.pick-for{display:block;margin-top:3px;font-size:12px;color:var(--on-dim);font-style:normal}
.pick-cols{display:grid;grid-template-columns:236px minmax(0,1fr);gap:20px;align-items:start}
.pick-side{display:flex;flex-direction:column;gap:0;padding-right:18px;
  border-right:1px solid var(--edge);max-height:66vh;overflow-y:auto;overscroll-behavior:contain}
.pick-side .cat-label{margin-top:14px}
.pick-side .cat-label:first-child{margin-top:0}
.pick-side .city-field{margin-top:2px}
.pick-times{display:flex;align-items:center;gap:8px;margin-top:8px;color:var(--on-mute)}
.pick-times input{flex:1 1 0;min-width:0}
.pick-check{display:flex;align-items:center;gap:8px;margin:10px 0 8px;font-size:12.5px;
  color:var(--on-dim);cursor:pointer}
.pick-main{min-width:0}
.pick-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:10px}
.pick-q{width:100%;margin-bottom:12px}
@media(max-width:860px){
  .pick-cols{grid-template-columns:minmax(0,1fr)}
  .pick-side{border-right:0;padding-right:0;border-bottom:1px solid var(--edge);padding-bottom:14px}
}
/* Витрина подбора — тот же каталог «Коллег», уменьшенный: выбирают по лицу, а не по строке
   текста, но окно не должно занимать экран целиком — под ним живёт само событие. */
.pick-grid{grid-template-columns:repeat(auto-fill,minmax(164px,1fr));gap:10px;
  max-height:52vh;overflow-y:auto;overscroll-behavior:contain;padding:2px}
.pick-grid .spec-photo{aspect-ratio:1/1;font-size:22px}
.pick-grid .spec-body{padding:9px 10px 9px;gap:2px}
.pick-grid .spec-name{font-size:13px}
.pick-grid .spec-sub,.pick-grid .spec-price{font-size:11px}
.pick-grid .spec-meta{margin-top:4px}
.pick-grid .spec-foot{padding-top:7px}
.pick-grid .tag{font-size:10.5px;padding:2px 7px}
/* Карточка в подборе никуда не ведёт — курсор не должен обещать перехода. */
.spec-card-pick{cursor:default}
.spec-card-pick:hover{transform:none}
.spec-take{padding:5px 10px;font-size:12px}
.modal-wide .cols{gap:14px}
.modal-wide .col{gap:0}
/* Пометка «похоже, это уже есть» на карточке заявки (R54). Заметная, но не запрещающая:
   заявка уже сохранена, а решение — за человеком. */
.lead-dup{margin:0 0 14px;padding:10px 12px;border:1px solid var(--a);border-radius:10px}
.lead-dup-row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;justify-content:space-between;
  padding:6px 0;border-top:1px solid var(--line)}
.lead-dup-row .note{margin:0}
.lead-touch{margin-top:14px;padding-top:14px;border-top:1px solid var(--line)}
.lead-touch-h{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:10px}
.lead-touch-h b{font-size:14.5px;font-weight:600;color:var(--ink)}
.touch-list{margin-top:12px;display:flex;flex-direction:column;gap:8px;max-height:190px;overflow-y:auto}
.touch{display:flex;align-items:baseline;gap:9px;font-size:12.5px;color:var(--ink-2);
  background:var(--film-1);border-radius:12px;padding:8px 11px}
.touch-k{flex:0 0 auto;font-size:11px;font-weight:600;color:var(--ink-3);text-transform:uppercase;letter-spacing:.02em}
.touch-t{flex:1;min-width:0}
.touch time{flex:0 0 auto;font-size:11px;color:var(--ink-3)}

/* Строка-выбор в списке людей: та же строка, что везде, но нажимается целиком и отмечается
   рамкой — галочка сбоку в списке из сорока человек читается хуже, чем подсвеченная строка. */
.row.row-pick{width:100%;text-align:left;border:1px solid transparent;background:none;cursor:pointer;
  font:inherit;color:inherit}
.row.row-pick.on{border-color:var(--acc);background:var(--film-3)}
.row.row-pick .th-ava{flex:0 0 auto}

/* Подсказка упоминания — над полем ввода, а не под ним: под полем на телефоне встаёт
   клавиатура, и список оказывается за экраном. */
.mention-drop{position:absolute;left:52px;right:52px;bottom:calc(100% + 6px);z-index:20;padding:5px;
  border-radius:var(--rad-s);background:var(--pop);border:1px solid var(--edge);
  box-shadow:0 16px 36px -14px rgba(0,0,0,.6);max-height:230px;overflow:auto}
.mention-drop .city-opt{display:flex;align-items:baseline;gap:8px}
.mention-drop em{font-style:normal;font-size:11.5px;color:var(--ink-3);margin-left:auto}
.composer{position:relative}

/* Непрочитанное упоминание — точкой слева, а не цветной строкой: строк в списке много,
   и половина закрашенных читается как ошибка, а не как «здесь вас звали». */
.row.row-new{position:relative}
.row.row-new::before{content:'';position:absolute;left:-9px;top:50%;transform:translateY(-50%);
  width:5px;height:5px;border-radius:50%;background:var(--acc)}
.row-when{font-size:11.5px;color:var(--ink-3);flex:0 0 auto}

/* Есть новое — точка, а не число: точное количество непрочитанных знает только открытая
   переписка, и цифра здесь была бы выдумана. Вопрос у списка один — заходить или нет. */
.th-dot{flex:0 0 auto;width:7px;height:7px;border-radius:50%;background:var(--acc);align-self:center}
/* «Вернуть в непрочитанные» стоит на месте точки и проявляется по наведению: колокольчик в
   каждой из сорока строк — шум, а место под него занято всегда, иначе строка прыгала бы. */
.th-un{flex:0 0 auto;align-self:center;opacity:0;cursor:pointer;color:var(--on-mute);
  line-height:0;transition:opacity .15s}
.th-un .ic{width:14px;height:14px}
.thread:hover .th-un,.th-un:focus-visible{opacity:.75}
/* На телефоне наводить нечем — там значок виден сразу. */
.th-un-tap{opacity:.5}

/* Название статьи — кнопка правки: нажимать крестик, чтобы удалить, и отдельную «карандаш»,
   чтобы изменить, — два разных места для одной строки. */
.cell-edit{display:block;width:100%;text-align:left;background:none;border:0;padding:0;font:inherit;
  color:inherit;cursor:pointer}
.cell-edit:hover b{text-decoration:underline;text-underline-offset:3px}
button.tag{cursor:pointer;font:inherit}

/* Машина в развозке: строка с данными и под ней гости пилюлями — посадка одним нажатием,
   без перетаскивания, которое на телефоне не работает. */
.route{border-top:1px solid var(--edge);padding-top:10px;margin-top:10px}
.route:first-of-type{border-top:0;margin-top:0}

/* Колонки блоков: обычный флекс с переносом. Ни сетки, ни медиазапроса — когда двум колонкам
   по 360px не хватает места, вторая переезжает вниз сама. Каждая колонка своей высоты, поэтому
   под коротким блоком не остаётся дыры до низа соседнего. */
.cols{display:flex;flex-wrap:wrap;gap:16px;align-items:flex-start}
.col{flex:1 1 360px;min-width:0;display:flex;flex-direction:column;gap:16px}
/* Список, который бывает любой длины (сеансы входа, история) — прокручивается внутри листа,
   а не растит лист на весь экран. */
.rows-scroll{max-height:340px;overflow-y:auto}
/* Лист с незакрытым вопросом к человеку — приглашение, на которое не ответили. Подсветка
   рамкой, а не заливкой: лист остаётся листом, но глазами находится первым. */
.sheet-hot{border-color:var(--acc);box-shadow:0 0 0 1px var(--acc) inset}
/* Отступ между листами внутри колонки даёт сам флекс. */
.col > .sheet + .sheet{margin-top:0}

/* Карточки тарифов: что тариф даёт — списком, а не одной строкой описания. Три карточки в ряд
   на широком, в столбик на узком — без медиазапроса, переносом. */
.plan-cards{display:flex;flex-wrap:wrap;gap:12px;margin-top:4px}
.plan-card{flex:1 1 240px;min-width:0;border:1px solid var(--line);border-radius:var(--rad);
  padding:16px;background:var(--film-1);display:flex;flex-direction:column;gap:10px}
.plan-card.on{border-color:var(--stroke-hi);background:var(--film-3)}
.plan-top{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.plan-top b{font-size:14.5px;font-weight:600}
.plan-top span{font-size:13px;font-variant-numeric:tabular-nums;color:var(--ink-2);white-space:nowrap}
.plan-desc{margin:0;font-size:12.5px;color:var(--ink-2);line-height:1.5}
.plan-feats{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:6px;flex:1 1 auto}
.plan-feats li{position:relative;padding-left:17px;font-size:12.5px;line-height:1.45;color:var(--ink-2)}
.plan-feats li::before{content:'';position:absolute;left:2px;top:6px;width:6px;height:6px;
  border-radius:50%;background:var(--acc)}
.plan-cur{font-size:12px;color:var(--ink-3);text-align:center;padding:9px 0}
/* «Большинству подходит этот» — подпись у средней карточки. Не бейдж поверх рамки: рамка тут
   означает выбранное, и второй значок на том же месте читался бы как второе состояние. */
.plan-pick{align-self:flex-start;font-size:11px;color:var(--acc);text-transform:lowercase}
/* Срок оплаты: три строки в кнопке — название, цена периода, выгода рублями. Одной строкой
   выгода не помещалась и уезжала в многоточие ровно на том числе, ради которого показана. */
.plan-pers{gap:9px}
.plan-per{display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:9px 14px;
  line-height:1.25;text-align:left}
.plan-per b{font-size:12.5px;font-weight:600}
.plan-per span{font-size:14px;font-variant-numeric:tabular-nums}
.plan-per em{font-size:11px;font-style:normal;opacity:.75}
/* Стена тарифа: текст называет работу человека, кнопки — что с этим делать. Ставится там, где
   упираются, поэтому и заметна: это не реклама на полях, а ответ на действие. */
.plan-hook{border:1px solid var(--line);border-radius:var(--rad);background:var(--film-3);
  padding:14px 16px;margin:0 0 14px;display:flex;flex-direction:column;gap:10px}
.plan-hook-t{margin:0;font-size:13px;line-height:1.5;color:var(--ink)}
.plan-hook-acts{display:flex;flex-wrap:wrap;gap:8px}
/* Полоса расхода — до упора, а не вместо него. Показывается с 80 %; когда предел достигнут,
   полоса краснеет и рядом встаёт стена. */
.plan-use{margin-top:14px}
.plan-use-full .bar i{background:var(--r)}
.plan-buy{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;
  margin-top:18px;padding-top:14px;border-top:1px solid var(--line)}
.plan-buy-sum b{display:block;font-size:22px;font-weight:600;letter-spacing:-.025em}
.plan-buy-sum span{display:block;font-size:12px;color:var(--ink-2);margin-top:3px}
.plan-buy-sum em{display:block;font-size:11.5px;font-style:normal;color:var(--g);margin-top:3px}
/* Две кнопки оплаты рядом (образец WedCRM): счёт — единственный способ заплатить без
   подключённой кассы, и прятать его за ссылкой значит оставить его ненайденным. На узком
   экране встают друг под друга и тянутся на всю ширину. */
.plan-pay-acts{display:flex;gap:10px;flex-wrap:wrap}
.pay-payer{border-top:1px solid var(--line);margin-top:18px}

/* ── Рефералка: прогресс, ступени, шаги квалификации ──────────────────────
   Полоса меряет путь от взятой ступени до следующей — от нуля она после третьего приглашённого
   почти не двигалась бы и перестала что-либо обещать. */
.ref-prog{border:1px solid var(--line);border-radius:var(--rad);background:var(--film-3);
  padding:14px 16px}
.ref-prog-h{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}
.ref-prog-h b{font-size:13.5px;font-weight:600}
.ref-prog-h span{font-size:12px;color:var(--ink-2)}
.ref-prog .bar{margin-top:11px;height:7px}
.ref-prog .bar i{background:var(--acc)}
.ref-tiers{display:flex;flex-direction:column;gap:1px}
.ref-tier{display:flex;align-items:center;gap:14px;padding:11px 2px;border-top:1px solid var(--line)}
.ref-tier:first-child{border-top:0}
.ref-tier > b{flex:0 0 34px;font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;
  text-align:right;color:var(--ink-3)}
.ref-tier-m{flex:1 1 auto;min-width:0}
.ref-tier-m span{display:block;font-size:12.5px;line-height:1.45}
.ref-tier-m em{display:block;font-style:normal;font-size:11.5px;color:var(--ink-3);margin-top:2px}
/* Взятая ступень выделена чернилами, ждущая выдачи — акцентом: «получено» и «достигнута, ждёт
   подтверждения» это разные вещи, и цвет обязан их различать так же, как подпись. */
.ref-tier--granted > b{color:var(--g)}
.ref-tier--granted .ref-tier-m span{font-weight:600}
.ref-tier--pending > b{color:var(--acc)}
.ref-tier--locked{opacity:.62}
/* Четыре шага квалификации у каждого приглашённого: пройденные — чернилами, остальные бледные.
   Общая подпись «без оплаты» не отвечает, на каком именно шаге человек стоит. */
.ref-steps{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.ref-step{font-size:10.5px;padding:2px 8px;border-radius:99px;border:1px solid var(--line);
  color:var(--ink-3);white-space:nowrap}
.ref-step.on{border-color:transparent;background:var(--tag-g-bg);color:var(--tag-g-ink)}
.ref-when{display:block;font-size:11.5px;color:var(--ink-3);margin-top:5px}

/* Разбор занятого места: типы внутри события — вложенный список, сдвинутый и приглушённый.
   Отступ слева и есть единственный признак того, что это разбор строки выше, а не соседние
   события: без него «Видео» и «Свадьба Ивановых» читаются как один уровень. */
.st-kinds{margin-left:18px;border-left:1px solid var(--line);padding-left:12px}
.st-kinds .row{padding:9px 2px;border-top:0}
.st-kinds .row-main b{font-weight:500;color:var(--ink-2)}
.st-w{flex:0 0 auto;font-style:normal;font-size:12px;color:var(--ink-2);
  font-variant-numeric:tabular-nums}

/* Звёздочка обязательного поля — цветом акцента и без отступа: она часть подписи, а не значок. */
/* Звёздочка обязательного поля — обычными чернилами. Не акцент (владелец выбирает «Белый»,
   и на светлом листе звёздочки нет вовсе) и не красный: красный в форме читают как ошибку
   ввода, а поле ещё никто не трогал. */
.req{font-style:normal;color:var(--ink-2);margin-left:2px}
/* Поле с кнопкой справа: телефон и «Найти» — одна операция, разносить их по строкам незачем. */
.fld-with-btn{display:flex;gap:8px;align-items:stretch}
.fld-with-btn input{flex:1 1 auto;min-width:0}
.fld-with-btn .btn{flex:0 0 auto;white-space:nowrap}

/* Ключик направления: закреплённое открывается по умолчанию. Звёздочка внутри пилюли, а не
   отдельной кнопкой рядом — она про эту же пилюлю и места в ряду не занимает. */
.cpill-pin{font-style:normal;margin-left:2px;opacity:.45;cursor:pointer;font-size:11px}
.cpill-pin:hover,.cpill-pin.on{opacity:1}
.cpill.on .cpill-pin{opacity:.6}
.cpill.on .cpill-pin.on{opacity:1}
/* Карточка проекта в общем списке: тот же лист, но кликается целиком. */
.proj-card{cursor:pointer;transition:transform .22s var(--spring),background .18s var(--ease)}
.proj-card:hover{transform:translateY(-2px);background:var(--film-3)}

/* «Печатает…» — строкой над полем ввода, без анимации точек: мигающие точки в тихом интерфейсе
   притягивают взгляд сильнее, чем само сообщение, ради которого их показывают. */
.typing{margin:0 0 6px;font-size:12px;color:var(--ink-3)}

/* Колокольчик у профиля — тот же материал и та же высота, что у пилюли с именем (правка
   владельца 3, 12.09.2026): стекло и кромка приходят из общего правила `.rail-pill,.profile-pill,
   .bell` выше, здесь только форма. 46px = 34px аватара плюс поля пилюли по 5px и кромка. */
.bell{flex:0 0 auto;width:46px;height:46px;display:grid;place-items:center;color:var(--on-dim);
  cursor:pointer;transition:background .18s var(--ease),color .18s var(--ease)}
.bell:hover{background:var(--fill);color:var(--on)}
.bell.on{background:var(--fill-2);color:var(--on)}
.bell .ic{width:18px;height:18px}
.bell-n{position:absolute;top:-3px;right:-3px;min-width:16px;height:16px;padding:0 4px;
  border-radius:99px;background:var(--acc);color:var(--acc-ink);font-style:normal;font-size:10px;
  font-weight:700;display:grid;place-items:center}
/* Всплывающий список: у профиля, а не по центру экрана — уведомление не задача, ради которой
   стоит закрывать всё остальное. */
.bell-pop{position:absolute;top:calc(100% + 8px);left:0;z-index:40;width:min(340px,86vw);
  padding:14px;border-radius:var(--rad);background:var(--pop);border:1px solid var(--edge);
  box-shadow:0 24px 50px -20px rgba(0,0,0,.7);max-height:70vh;overflow:auto}
.bell-h{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.bell-h b{font-size:14px;font-weight:600}
.bell-sec{font-size:11.5px;color:var(--ink-3);margin:10px 0 6px}
.rail-bot{position:relative}

/* ── «Домой» ──────────────────────────────────────────────────────────────────────────────
   С этапа 3 внедрения панели (12.09.2026) главная — рабочее поле `.ws.home-ws` во всю ширину:
   дашборд `.pn-dash` (правила выше, перед `.ws`) и под ним нижняя лента `.home-lower` из
   карточек `.home-card`. Трёхколоночной сетки с «дырой» под фотографию больше нет; правило
   `.home-hole` оставлено — его форму сторожит test/home-screen.test.js вместе со слоем
   `.stage-sharp`, а сам элемент не рисуется. */
.home-card{background:var(--paper);backdrop-filter:blur(26px) var(--w-fx);
  -webkit-backdrop-filter:blur(26px) var(--w-fx);border:1px solid var(--edge);
  box-shadow:0 22px 50px -20px rgba(0,0,0,.6),inset 0 1px 0 var(--edge-hi);
  border-radius:var(--rad-l);padding:20px 22px;color:var(--ink)}
/* Рамка почти не видна намеренно: у окна теперь мягкий край, и чёткая линия поверх растушёвки
   читалась бы как ошибка отрисовки. Она нужна лишь настолько, чтобы квадрат не терялся,
   когда фотография в этом месте однотонная. */
.home-hole{width:min(40vw,54vh);aspect-ratio:1;border-radius:28px;
  border:1px solid var(--line);box-shadow:0 24px 60px -28px rgba(0,0,0,.45)}

.home-ava{width:56px;height:56px;flex:0 0 56px;border-radius:99px;overflow:hidden;position:relative;
  display:grid;place-items:center;background:var(--film-4);color:var(--ink-2);
  font-size:17px;font-weight:600;letter-spacing:-.02em}
.home-ava img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.home-hi-txt{min-width:0}

.home-lead{margin:0;font-size:15px;line-height:1.5;color:var(--ink)}
.home-lead b{font-weight:600}
.home-sub{margin:7px 0 0;font-size:12.5px;line-height:1.55;color:var(--ink-3)}

.home-fig b{display:block;font-size:27px;font-weight:600;letter-spacing:-.035em;line-height:1.05;
  font-variant-numeric:tabular-nums}
.home-fig span{display:block;font-size:12px;color:var(--ink-3);margin-top:2px}

/* Кольцо и текст рядом: кольцо здесь не украшение, а доля полученного от договорной суммы. */
.home-money{display:flex;gap:16px;align-items:center}
.home-ring{flex:0 0 84px;width:84px}
.home-ring svg{width:84px;height:84px;display:block}
.home-money-txt{min-width:0}

.hw-now{display:flex;align-items:center;gap:12px}
.hw-ic{display:grid;place-items:center;color:var(--ink)}
.hw-ic svg{width:34px;height:34px}
.hw-now>b{font-size:27px;font-weight:600;letter-spacing:-.03em;font-variant-numeric:tabular-nums}
.hw-city{font-size:12.5px;color:var(--ink-2);line-height:1.3}
.hw-city i{display:block;font-style:normal;font-size:11.5px;color:var(--ink-3)}
.hw-days{display:flex;gap:6px;margin-top:14px}
.hw-day{flex:1 1 0;display:flex;flex-direction:column;align-items:center;gap:3px;padding:8px 2px;
  border-radius:12px;background:var(--film-2);font-size:11px;color:var(--ink-3)}
.hw-day.on{background:var(--film-4);color:var(--ink-2)}
.hw-day svg{width:16px;height:16px}
.hw-day b{font-size:12.5px;color:var(--ink);font-variant-numeric:tabular-nums}

.home-today-h{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:10px}
.home-today-h b{font-size:14.5px;font-weight:600;letter-spacing:-.01em}
.home-today-h span{font-size:12px;color:var(--ink-3)}
.home-news{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:8px 18px}
.home-news-i{display:flex;align-items:baseline;gap:9px;min-width:0;font-size:13px}
.home-news-i b{font-weight:400;color:var(--ink-2);flex:1 1 auto;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.home-news-i i{font-style:normal;font-size:11.5px;color:var(--ink-3);flex:0 0 auto}

/* ── Календарь на главной ─────────────────────────────────────────────────────
   Он тут главный экран, а не виджет: клетка обязана держать несколько строк разных слоёв и
   оставаться читаемой на телефоне. Поэтому минимальная высота больше, чем у старого календаря,
   а слои различаются цветом полоски слева, а не заливкой — заливка на шести слоях превращает
   сетку в мозаику. */
/* Календарь на главной — компактный блок, а не полотно во всю ширину. Раньше сетка тянулась на
   1235 px и 700 px в высоту: месяц занимал целый экран. Ограничиваем ширину (семь колонок на
   ~760 px читаются свободно) и прижимаем к левому краю — рядом остаётся воздух, а не растянутая
   таблица. Высота ячейки ниже (56 вместо 86), в клетку помещается два события: третье и так
   пряталось под «ещё N». */
/* Нижняя зона главной: одинаковые карточки, которые сами переносятся по ширине окна. Календарь,
   «Сегодня», приглашения и плитки разделов встают в один ряд равными блоками — раньше первые два
   растягивались во всю ширину, а плитки шли отдельным рядом, и на экране было три разных ширины.
   Календарю нужно больше места, чем подписи «Сегодня», поэтому минимум колонки задан по нему. */
.home-lower{display:grid;gap:14px;align-items:start;
  grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}
.home-lower>.home-tiles{display:contents}       /* плитки — такие же карточки этой сетки */
/* Календарь — самый высокий блок нижней зоны (≈550 px против ≈200 у соседей). В один ряд с
   ними он растягивал ряд до своей высоты, и под короткими карточками стояла пустота. Два ряда
   сетки — и рядом с ним встают четыре карточки вместо двух (таск 152, рубеж 3). */
@media (min-width:901px){ .home-lower>.hcal{grid-row:span 2} }
.home-invites .rows .row{gap:10px}

.hcal{display:flex;flex-direction:column;gap:9px;align-self:start}
.hcal-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.hcal-title{font-size:15px;font-weight:600;letter-spacing:-.02em;min-width:150px}
.hcal-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:4px}
.hcal-cell{min-height:56px;border-radius:var(--rad-s);background:var(--film-1);
  border:1px solid var(--line);padding:4px 5px;display:flex;flex-direction:column;gap:2px;
  transition:border-color .12s,background .12s}
.hcal-cell.out{background:none;border-color:transparent;opacity:.45}
.hcal-cell.today{border-color:var(--acc)}
.hcal-cell.free{background:rgba(74,222,128,.07);border-color:rgba(74,222,128,.28)}
.hcal-cell.drop{border-color:var(--acc);background:color-mix(in srgb,var(--acc) 12%,transparent)}
.hcal-d{display:flex;align-items:center;justify-content:space-between;font-size:11.5px;
  color:var(--ink-2);font-variant-numeric:tabular-nums}
.hcal-cell.today .hcal-d{color:var(--ink);font-weight:700}
.hcal-w{display:inline-flex;align-items:center;gap:2px;font-size:10px;color:var(--ink-3)}
.hcal-w .ic{width:11px;height:11px}
/* Слой виден полоской слева: шесть заливок сделали бы из месяца витраж. */
.hcal-i{font-size:10.5px;line-height:1.25;padding:2px 5px 2px 7px;border-radius:5px;
  background:var(--film-2);color:var(--ink);border-left:2px solid var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}
/* Перенос пальцем начинается долгим нажатием — а долгое нажатие по умолчанию выделяет текст и
   зовёт меню браузера, и жест не доходит до нас. Гасим только на переносимых событиях. */
.hcal-i[data-drag]{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
.hcal-i.is-dragging{opacity:.5;transform:scale(.97)}
.hcal-i.own{border-left-color:var(--acc)}
.hcal-i.team{border-left-color:#93c2fb}
.hcal-i.crew{border-left-color:#fbbf6e}
.hcal-i.stock{border-left-color:#c4a6f5}
.hcal-i.prep{border-left-color:#8ceaa9}
.hcal-i.tasks{border-left-color:#fda4b0}
.hcal-i.done{opacity:.5;text-decoration:line-through}
.hcal-more{font-size:10px;color:var(--ink-3);padding-left:7px}
.hcal-lay{display:flex;flex-wrap:wrap;gap:6px}
.hcal-lay button{font-size:12px;padding:5px 10px;border-radius:99px;border:1px solid var(--line);
  background:var(--film-1);color:var(--ink-3);cursor:pointer}
.hcal-lay button.on{background:var(--film-4);color:var(--ink);border-color:transparent}
@media(max-width:720px){
  .hcal-cell{min-height:58px;padding:4px}
  .hcal-i{font-size:9.5px;padding:1px 4px 1px 6px}
  .hcal-d{font-size:10.5px}
}

.hcal-sp{flex:1 1 auto}
/* Плитки бывшего «Канбана». Четыре группы в ряд, каждая — свои экраны: до любого два действия,
   «Домой» и название. Подпись под названием не украшение — по одним заголовкам («Источники»,
   «Показатели») человек не выбирает, он гадает. */
.home-tiles{display:grid;gap:12px;grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
/* Каждая группа — своя карточка (класс home-card даёт фон), но паддинг у неё меньше общего:
   это компактная плитка раздела, а не крупная сводка вроде погоды или денег. */
.home-tgrp{display:flex;flex-direction:column;gap:4px;min-width:0;padding:13px 15px}
.home-tgrp>b{font-size:12px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:3px}
.home-tgrp>b i{font-style:normal;font-weight:500;color:var(--ink-3);opacity:.75}
.home-tile{display:block;width:100%;text-align:left;background:none;border:0;cursor:pointer;
  padding:6px 8px;border-radius:var(--rad-s);color:var(--ink);font:inherit}
.home-tile:hover{background:var(--film-2)}
.home-tile span{display:block;font-size:13.5px;line-height:1.3}
.home-tile em{display:block;font-style:normal;font-size:11.5px;color:var(--ink-3);
  line-height:1.35;margin-top:1px}
/* Последствия переноса. Отдельным списком, а не абзацем: человек читает его перед необратимым
   действием, и три строки должны различаться взглядом, а не вчитыванием. */
.cal-imp{margin:12px 0 0;padding:0 0 0 18px;font-size:13px;line-height:1.55;color:var(--ink-2)}
.cal-imp li+li{margin-top:5px}
.cal-imp li.bad{color:var(--r)}

/* Переключатель рабочей области. Все положения видны сразу — «Все» и по кнопке на профессию:
   раньше одна кнопка перебирала их по кругу, и чтобы попасть в нужную, приходилось нажимать её
   и смотреть, куда попал. Форма — та же капсула, что у разделов внизу: это переключатель между
   равными, а не действие. Внутри слово, а не значок: «фотограф» и «видеограф» одной иконкой не
   различаются, а различать их и есть весь смысл. */
.area-pill{display:flex;align-items:center;gap:2px;flex:0 0 auto;padding:4px;border-radius:99px;
  background:var(--glass);border:1px solid var(--edge);
  backdrop-filter:blur(calc(var(--w-blur) * .55px)) var(--w-fx);
  -webkit-backdrop-filter:blur(calc(var(--w-blur) * .55px)) var(--w-fx)}
.area-btn{padding:6px 12px;border-radius:99px;font:inherit;font-size:11.5px;font-weight:600;
  letter-spacing:-.01em;white-space:nowrap;max-width:120px;overflow:hidden;text-overflow:ellipsis;
  color:var(--on-mute);cursor:pointer;
  transition:color .18s var(--ease),background .18s var(--ease)}
.area-btn:hover{color:var(--on);background:var(--fill)}
.area-btn.on{color:var(--on-solid-ink);background:var(--on-solid);box-shadow:0 3px 10px -3px rgba(0,0,0,.45)}

/* Фотоотчёт под пунктом программы — Б7 отчёта по организатору.
   Полоска превью, а не галерея: снимки смотрят мельком («зал был чистый»), а разглядывают уже
   по клику, в полном размере. */
.att-row{display:flex;gap:8px;flex-wrap:wrap;padding:0 0 10px 60px}
.att{position:relative;display:block;width:74px;height:74px;border-radius:10px;overflow:hidden;
  border:1px solid var(--line);background:var(--bg-2)}
.att img{width:100%;height:100%;object-fit:cover;display:block}
.att-k{position:absolute;left:0;right:0;bottom:0;padding:2px 4px;font-size:10px;line-height:1.2;
  text-align:center;background:rgba(8,10,14,.72);color:#fff}
@media (max-width:640px){ .att-row{padding-left:0} }

/* ── Схема зала (шаг 9) ─────────────────────────────────────────────────────
   План рисуется на процентной сетке: столы и зоны позиционируются в процентах от размера
   поля, поэтому схема одинаково выглядит на экране, в узком окне и в печати. Никаких canvas
   и библиотек — обычные блоки, которые умеет напечатать любой браузер. */
.seat-map{
  position:relative; width:100%; aspect-ratio:16/9; min-height:220px;
  border:1px solid var(--film-3); border-radius:14px; overflow:hidden;
  background:linear-gradient(0deg, var(--film-1), var(--film-1)),
    repeating-linear-gradient(0deg, transparent 0 19px, var(--film-2) 19px 20px),
    repeating-linear-gradient(90deg, transparent 0 19px, var(--film-2) 19px 20px);
}
.seat-zone{
  position:absolute; display:flex; align-items:center; justify-content:center;
  border:1px dashed var(--film-4); border-radius:10px; background:var(--film-2);
  font-size:11px; color:var(--ink-3); text-align:center; padding:2px;
}
.seat-table{
  position:absolute; width:56px; height:56px; margin:-28px 0 0 -28px;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  border-radius:50%; border:1px solid var(--film-4); background:var(--film-3);
  font-size:12px; line-height:1.1; color:var(--ink-2);
}
.seat-table.seat-rect{ border-radius:10px; width:76px; margin-left:-38px; }
.seat-table.seat-busy{ border-color:var(--g); color:var(--ink); }
/* Стол — ручка перетаскивания: курсор и отключённое выделение говорят об этом до того, как
   человек попробует. touch-action:none обязателен, иначе браузер на планшете считает движение
   пальца прокруткой страницы и стол не двигается вовсе. */
.seat-table{ cursor:grab; touch-action:none; user-select:none; }
.seat-table.seat-drag{ cursor:grabbing; z-index:5; box-shadow:0 6px 18px rgba(0,0,0,.35); }
.seat-table.seat-over{ border-color:var(--r); color:var(--r); }
.seat-table b{ font-size:13px; }
.seat-table em{ font-style:normal; font-size:10.5px; color:var(--ink-3); }

/* Стулья кружками по периметру стола (таск 59). Цвет значит РОВНО ОДНО: закрашенный — занято,
   пустой — свободно. Ребёнок и прочие пометки — обводка, а не заливка: два смысла в одном цвете
   превращают схему в ребус, который каждый разгадывает по-своему.
   Имена на схеме не пишутся: кружок отдаёт их наведением (title) и касанием.
   touch-action:none — иначе браузер считает движение пальца прокруткой и гость не переносится. */
.seat-dot{
  position:absolute; width:13px; height:13px; margin:-6.5px 0 0 -6.5px; border-radius:50%;
  border:1.5px solid var(--film-4); background:var(--film-1); z-index:4;
  touch-action:none; cursor:pointer;
}
.seat-dot.on{ background:var(--g); border-color:var(--g); }
.seat-dot.seat-dot-kid{ box-shadow:0 0 0 2px var(--b); }
.seat-dot.seat-dot-hot{ transform:scale(1.5); border-color:var(--acc); }
.seat-dot.seat-drag{ opacity:.5; }
.seat-peek{ font-weight:600; color:var(--ink-2); }
/* Выделенная галочкой строка списка: пачка видна до нажатия «посадить», а не после. */
.rows .row.row-on{ background:var(--film-2); }
@media (max-width:640px){
  /* На узком экране кружки крупнее: палец не попадает в 13 пикселей. */
  .seat-dot{ width:16px; height:16px; margin:-8px 0 0 -8px; }
}

/* Ответственный за событие в шапке карточки: отдельно от команды и всегда на виду —
   это ответ на «кому писать», а не ещё одна строка состава. */
.pj-resp{
  margin-left:auto; margin-right:12px; font-size:12.5px; color:var(--ink-3);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:46%;
}
.pj-resp b{ color:var(--ink-2); font-weight:600; }

/* Якорь сообщения: «о чём эта реплика». Мелко и сверху — чтобы читалось как пометка на полях,
   а не как часть текста сообщения. */
.msg-anchor{
  display:block; font-size:11px; line-height:1.3; margin-bottom:4px;
  color:var(--ink-3); border-left:2px solid var(--film-4); padding-left:6px;
}
/* Пересланное: чьи слова и откуда. Отдельный класс, а не цитата, — пометка о происхождении
   и цитата отвечают на разные вопросы, и путать их глазами не надо. */
.msg-fwd{
  display:block; font-size:11px; line-height:1.35; margin-bottom:4px;
  color:var(--ink-3); border-left:2px solid var(--film-4); padding-left:6px;
}
.msg-fwd b{ color:var(--ink-2); font-weight:600; }
.msg-anchor-bar{
  display:flex; align-items:center; gap:8px; width:100%; order:-1;
  font-size:12px; color:var(--ink-3); padding:4px 8px; margin-bottom:6px;
  background:var(--film-2); border-radius:8px;
}
.msg-anchor-bar b{ color:var(--ink-2); font-weight:600; }

/* Цитата: снимок чужой реплики над ответом. Полоска слева и приглушённый текст — та же
   пометка на полях, что и якорь, поэтому и выглядит так же. Кнопка, а не блок: по ней
   переходят к оригиналу, и нажатие должно быть доступно с клавиатуры. */
.msg-quote{
  display:block; width:100%; text-align:left; cursor:pointer; font:inherit;
  font-size:11.5px; line-height:1.35; margin-bottom:5px; padding:3px 0 3px 7px;
  border:0; border-left:2px solid currentColor; background:none; color:inherit; opacity:.72;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.msg-quote b{ display:block; font-weight:600; }
/* Удалённое: пузырь остаётся, содержимого нет. Курсив и полупрозрачность говорят, что это
   пометка системы, а не чьи-то слова. */
.msg.msg-gone{ opacity:.6; }
.msg-gone-note{ font-style:italic; }
/* «Прочитано» — слева от кнопок, мелко: это подтверждение, а не сообщение. */
.msg-read{ opacity:.85; }
.msg-reply{ border:0; background:none; color:inherit; opacity:0; cursor:pointer;
  padding:0; line-height:0; transition:opacity .15s; margin-left:auto; }
.msg-reply + .msg-del{ margin-left:0; }
.msg-reply .ic{ width:13px; height:13px; }
.msg:hover .msg-reply,.msg-reply:focus-visible{ opacity:.75; }
/* Куда прыгнули по цитате — подсвечивается на секунду: без этого переход к оригиналу в
   длинной ленте неотличим от «ничего не произошло». */
.msg-hit{ box-shadow:0 0 0 2px var(--acc); transition:box-shadow .3s; }

/* «Первые шаги» на главной. Карточка того же вида, что и соседние: онбординг не должен
   выглядеть баннером — он часть рабочего экрана, а не реклама поверх него. */
.home-steps{ display:flex; flex-direction:column; gap:10px; }
.home-steps-h{ display:flex; align-items:center; gap:8px; }
.home-steps-h b{ font-size:14px; }
.home-steps-h span{ font-size:12px; color:var(--ink-3); margin-right:auto; }
.home-steps-list{ display:flex; flex-direction:column; gap:2px; }
.home-step{
  display:flex; align-items:center; gap:8px; width:100%; text-align:left;
  padding:6px 8px; border:0; border-radius:9px; background:transparent;
  color:var(--ink-2); font-size:13px; line-height:1.35; cursor:pointer;
}
.home-step:hover{ background:var(--film-2); }
.home-step.done .home-step-t{ text-decoration:line-through; color:var(--ink-3); }
.home-step-t{ flex:1; }

/* Три числа на карточке события (приём O!task): договор · оплачено · осталось. Цифры мелкие
   и в одну строку — это справка на бегу, а не финансовый отчёт.

   Перенос обязателен: карточка живёт и в колонке доски (258 px), где три суммы в миллионах в
   строку не встают. Не помещается — уезжает на вторую строку, но не в прокрутку вбок: она на
   карточке доски запрещена прямо (MOBILE_KANBAN_DESIGN.md). */
.proj-money{ display:flex; flex-wrap:wrap; gap:4px 10px; margin:0 0 8px; }
.proj-money span{
  display:flex; flex-direction:column; gap:1px; font-size:10.5px; color:var(--ink-3);
  line-height:1.2; white-space:nowrap;
}
.proj-money b{ font-size:12.5px; font-weight:600; color:var(--ink-2); font-variant-numeric:tabular-nums; }
.proj-money .pos b{ color:var(--g); }
.proj-money .neg b{ color:var(--a); }

/* Состояние подготовки в шапке карточки события: рядом с ответственным, мелко и без цвета —
   это оценка, а не тревога. Красным горит уже сам список событий. */
/* Это поле ввода, а не подпись: заливка и рамка берутся у полей (--fill-2 / --stroke),
   а не у плёнок. Прежняя рамка --film-3 давала к своей заливке 1,06:1 — граница контрола,
   которой не видно (WCAG 1.4.11 требует 3:1), и «как идёт?» читалось как текст без поля. */
.pj-health{
  font-size:12px; color:var(--ink-2); background:var(--fill-2);
  border:1px solid var(--stroke); border-radius:8px; padding:3px 8px; margin-right:10px;
}

/* Подсказка об установке на телефон: полоса внизу, а не модалка поверх работы. Появляется
   один раз и уходит по любому ответу. */
.pwa-bar{
  position:fixed; left:12px; right:12px; bottom:12px; z-index:60;
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  padding:10px 14px; border-radius:14px;
  background:var(--film-3); border:1px solid var(--film-4);
  backdrop-filter:blur(18px); font-size:13px; color:var(--ink-2);
}
.pwa-bar span{ flex:1; min-width:200px; }

/* Платежи в календаре: своя метка, отличимая от событий и смен. Приглушённый жёлтый — цвет
   ожидания, а не тревоги: срок платежа это не авария. */
.hcal-i.money{ background:color-mix(in srgb,var(--acc) 14%,transparent); color:var(--ink-2);
  border-left:2px solid var(--acc); }
.hcal-i.money.done{ opacity:.55; text-decoration:line-through; }

/* ══════════════════════ МОБИЛЬНЫЙ КАРКАС ══════════════════════
   Всё ниже включается только на телефоне (≤720px) и не трогает широкий экран.

   Замер, ради которого это писалось: на 375×812 навигация занимала 561 пиксель из 812 — три
   её уровня (рельс, панель, список пунктов) вставали друг под друга, и рабочее содержимое
   начиналось под сгибом. Здесь верхний рельс скрывается, а разделы переезжают вниз, к пальцу.
   ────────────────────────────────────────────────────────────────────────── */

/* Нижнее меню. Рисуется всегда, показывается только на телефоне: перерисовывать кабинет на
   каждое изменение ширины окна дороже, чем один display:none. */
.tabbar{display:none}

@media (max-width:720px){
  /* ── Только вертикальная прокрутка ──
     overflow-x:clip, а не hidden: hidden на html/body отменяет position:sticky внутри
     (шапка экрана перестала бы липнуть), clip — не отменяет.

     min-width:0 детям рабочего поля — против главной причины уезжающего вбок содержимого:
     элемент flex/grid по умолчанию не сжимается уже своего содержимого, и одна длинная строка
     в таблице растягивает всю страницу. Именно так «Смета» выносила за край 95 элементов. */
  html{overflow-x:clip}
  body{max-width:100%}
  .ws-body > *, .ws-body .sheet > *, .ws-body .rows > *{min-width:0}

  /* Верхний рельс на телефоне не нужен: его работу делает нижнее меню, а место он занимает
     дважды — сам и своим отступом. */
  .rail{display:none}

  /* Место под капсулу внизу и под чёлку сверху.
 
     Верхний отступ обязателен именно из-за viewport-fit=cover: с ним страница рисуется под
     статус-баром и «динамическим островом», и первая строка каждого экрана — заголовок раздела —
     оказывается наполовину под часами. Без cover не работает safe-area внизу, поэтому платим
     отступом сверху, а не отказом от cover. */
  .app{padding-top:calc(8px + var(--safe-t));
    padding-bottom:calc(var(--tabbar-h) + var(--safe-b) + 18px)}

  .tabbar{display:block;position:fixed;z-index:45;
    left:max(10px, var(--safe-l));right:max(10px, var(--safe-r));
    bottom:calc(8px + var(--safe-b));
    /* Ничего не перехватываем мимо самой капсулы: под её краями лежит контент, и невидимая
       полоса на всю ширину съедала бы нажатия по нему. */
    pointer-events:none}

  .tabbar-in{pointer-events:auto;display:flex;align-items:center;justify-content:space-between;
    gap:2px;height:var(--tabbar-h);padding:0 6px;border-radius:99px;
    /* Полупрозрачное стекло той же природы, что и остальные окна кабинета: капсула поверх
       контента, и сквозь неё должно быть видно, что под ней ещё есть страница. */
    /* Ступень панели, а не своя тёмная краска: до этой сборки у мобильного блока была
       собственная палитра в два десятка строк, и светлая тема на телефон не доезжала. */
    background:var(--surf-1);
    -webkit-backdrop-filter:blur(22px) saturate(140%);
    backdrop-filter:blur(22px) saturate(140%);
    border:1px solid var(--edge);
    box-shadow:0 10px 34px rgba(0,0,0,.28), inset 0 1px 0 var(--edge-hi);
    transition:none}

  /* Сжатие при листании вниз. Капсула уменьшается ЦЕЛИКОМ — и по высоте, и по ширине, вместе
     со значками: масштабированием, а не отдельными размерами для каждой части. Так пропорции
     остаются теми же, и панель читается как та же самая, просто отодвинувшаяся, а не как
     другая панель с другими иконками.

     Точка отсчёта — низ по центру: панель «оседает» на своё место, а не уползает в угол. */
  .tabbar-in{transform-origin:bottom center;transition:transform .24s var(--ease)}
  .tabbar--min .tabbar-in{transform:scale(.78)}
  /* Подпись при сжатии убирается целиком, а не ужимается: обрезанное слово читается как брак
     вёрстки, и именно это видно на телефоне при каждом листании. */
  .tabbar--min .tb-n{display:none}

  .tb{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:2px;height:100%;border-radius:99px;
    color:var(--ink-3);
    transition:color .18s var(--ease), transform .22s var(--spring)}
  .tb .ic{width:23px;height:23px;transition:width .2s var(--ease), height .2s var(--ease)}
  .tb-i{position:relative;display:grid;place-items:center}
  /* Подпись — только у активной кнопки. Семь подписей на 375 пикселях дают по пятьдесят
     пикселей на слово: «Проекты» и «Коллеги» туда не встают, а обрезанное слово читается как
     ошибка вёрстки. Активная подписана всегда — по ней видно, где ты. */
  /* Подпись показывается только у активной кнопки и занимает целую строку: обрезка по высоте
     здесь недопустима — буквы «Домой» с отрезанными хвостами видны на каждом экране. */
  .tb-n{display:none;font-size:10px;line-height:12px;height:12px;letter-spacing:-.01em;
    font-weight:600;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .tb.on{color:var(--ink)}
  .tb.on .tb-n{display:block}
  /* Кнопки МЕНЮ акцентом не красятся: акцент принадлежит кнопкам действия, а лайм на светлой
     панели даёт 1,4:1 — активный раздел переставал быть виден именно там, где на него смотрят.
     Активную отличают чернила и подпись, а не цвет. */
  .tb.on .tb-i{color:var(--ink)}
  .tb.on .ic{color:var(--ink)}

  /* Точка непрочитанного — на самом значке, а не рядом с ним: рядом её принимают за часть
     соседней кнопки. */
  .tb-dot{position:absolute;top:-1px;right:-2px;width:8px;height:8px;border-radius:99px;
    background:var(--acc);box-shadow:0 0 0 2px var(--surf-1)}

  /* «Домой» — ось капсулы: крупнее прочих и приподнята. Это точка возврата из любого места,
     и рука находит её не глядя, по одному только положению в центре. */
  .tb-home{flex:0 0 auto;transform:translateY(-6px)}
  .tb-home .tb-i{width:44px;height:44px;border-radius:99px;
    background:var(--film-3);border:1px solid var(--edge);
    transition:width .22s var(--ease), height .22s var(--ease), background .18s var(--ease)}
  .tb-home .ic{width:24px;height:24px}
  .tb-home.on .tb-i{background:var(--acc);border-color:transparent}
  .tb-home.on .ic{color:var(--acc-ink)}

  /* Профиль — со своей фотографией: лицо находят глазами быстрее любого значка. */
  .tb-ava{width:27px;height:27px;border-radius:99px;overflow:hidden;
    background:var(--ava-bg, var(--film-4));
    font-size:11px;font-weight:700;color:var(--ink);letter-spacing:-.02em}
  .tb-ava img{width:100%;height:100%;object-fit:cover;display:block}
  .tb-me.on .tb-ava{box-shadow:0 0 0 2px var(--acc)}

  /* Плавающая кнопка обоев уступает место капсуле: раньше она висела в правом нижнем углу
     ровно там, где теперь живёт меню. */
  .wall{bottom:calc(var(--tabbar-h) + var(--safe-b) + 20px)}
}

/* Экран ниже 360 px (SE, старые Android): семь кнопок остаются, но ужимаются. */
@media (max-width:360px){
  .tabbar-in{padding:0 3px}
  .tb .ic{width:21px;height:21px}
  .tb-home .tb-i{width:40px;height:40px}
}

/* ── Лист профиля (седьмая кнопка нижнего меню) ──
   Нижний лист, а не окно по центру: на телефоне лист приезжает снизу, к пальцу, и закрывается
   тем же движением, каким открылся. Модальное окно посреди экрана требует целиться в крестик
   в противоположном от большого пальца углу. */
.sheet-back{position:fixed;inset:0;z-index:60;background:rgba(6,8,12,.5);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  display:flex;align-items:flex-end;justify-content:center;
  animation:sbFade .18s var(--ease)}
@keyframes sbFade{from{opacity:0}to{opacity:1}}
.sheet-dn{width:min(560px,100%);max-height:86vh;overflow:auto;-webkit-overflow-scrolling:touch;
  padding:8px 14px calc(18px + var(--safe-b));
  border-radius:var(--rad-l) var(--rad-l) 0 0;
  background:var(--surf-3);
  -webkit-backdrop-filter:blur(26px) saturate(140%);backdrop-filter:blur(26px) saturate(140%);
  border:1px solid var(--edge);border-bottom:0;
  box-shadow:0 -18px 50px rgba(0,0,0,.34);
  animation:sbUp .26s var(--spring)}
@keyframes sbUp{from{transform:translateY(18px)}to{transform:none}}
/* Полоска-ручка: общепринятый знак «лист тянется и закрывается». */
.sheet-grip{width:38px;height:4px;border-radius:99px;background:var(--edge-hi);
  margin:4px auto 12px}
/* Заголовок с крестиком — принадлежность ОКНА, а не листа: он появляется только на широком
   экране (правило ниже). На телефоне лист закрывают движением вниз и нажатием мимо, и целиться
   в крестик в дальнем от большого пальца углу там незачем. Стоит ДО медиа-блока намеренно:
   `display:flex` внутри него побеждает как более позднее правило той же силы. */
.sheet-head{display:none}

.ms-me{display:flex;align-items:center;gap:12px;width:100%;padding:12px;border-radius:var(--rad);
  background:var(--film-2);border:1px solid var(--line);text-align:left}
.ms-ava{width:44px;height:44px;flex:0 0 44px;border-radius:99px;overflow:hidden;
  display:grid;place-items:center;background:var(--film-4);font-weight:700;color:var(--ink)}
.ms-ava img{width:100%;height:100%;object-fit:cover;display:block}
.ms-who{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.ms-who b{font-size:15px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ms-who span{font-size:12px;color:var(--ink-3);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ms-go{flex:0 0 auto;color:var(--ink-3)}
.ms-go .ic{width:20px;height:20px}

/* Разделы, не вошедшие в капсулу, — плитками: их три, и плитка нажимается увереннее строки. */
.ms-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:12px 0}
.ms-card{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:7px;
  min-height:76px;padding:12px 6px;border-radius:var(--rad);
  background:var(--film-2);border:1px solid var(--line);color:var(--ink)}
.ms-card b{font-size:12px;font-weight:600;letter-spacing:-.01em;text-align:center;
  max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Значок раздела в листе — то же меню: на светлой плитке акцент неразличим. */
.ms-ic{color:var(--ink-2)}
.ms-ic .ic{width:22px;height:22px}

.ms-list{display:flex;flex-direction:column;gap:2px}
.ms-row{display:flex;align-items:center;min-height:var(--tap-min);padding:0 12px;
  border-radius:var(--rad-s);color:var(--ink-2);text-align:left}
.ms-row b{font-weight:500;font-size:14px}
.ms-row:active{background:var(--film-3)}
.ms-row--out{color:var(--r);margin-top:6px}

/* На широком экране лист профиля не нужен — там есть рельс и панель настроек. То же у выбора
   экрана, перемещения карточки и этапов: их кнопки на широком экране скрыты, а «Вернуть в
   работу» рисует выбор этапа прямо в карточке.

   Но не у листов ЧАТА. За «+» в строке отправки стоят объект системы, опрос и встреча, а в
   самой строке их нет; за «+» под репликой — набор реакций, и другого пути к ним тоже нет.
   Скрытые здесь, они превращали обе кнопки в мёртвые: нажатие проходило, состояние менялось,
   лист рисовался — и был невидим. Поэтому скрываем не всё подряд, а всё, КРОМЕ помеченного
   `sheet-any` — «этот лист нужен на любой ширине».

   А уцелев, он на компьютере обязан выглядеть ОКНОМ, а не шторкой снизу. Шторка — приём
   телефона: она приезжает к большому пальцу. Мышью же одно и то же действие «что отправить»
   получалось двух видов сразу — объект системы открывался окном по центру, всё остальное
   выезжало снизу во всю ширину. Разнобой владелец и назвал ошибкой.

   Значения взяты у `.modal` (`--glass-2` там и `--surf-3` здесь — одна и та же переменная),
   чтобы два окна одного действия не разъезжались по виду. Разметка при этом ОДНА: вид решает
   ширина, поэтому при растягивании окна лист переедет сам, без перерисовки из JS.

   Правила ниже намеренно без вложенности в `.sheet-any`: на этой ширине непомеченные листы
   скрыты целиком, так что единственный видимый `.sheet-dn` — как раз лист чата. Помеченный
   завтра третий лист получит вид окна сразу, а не станет третьим приёмом. */
@media (min-width:721px){
  .sheet-back:not(.sheet-any){display:none}
  .sheet-back{align-items:center;padding:24px}
  .sheet-dn{width:min(440px,100%);max-height:calc(100vh - 48px);padding:22px;
    border-radius:var(--rad-l);border-bottom:1px solid var(--edge);
    box-shadow:0 30px 60px -24px rgba(0,0,0,.7)}
  .sheet-grip{display:none}
  .sheet-head{display:flex}
}

/* Пока открыт лист, фон под ним стоит на месте, а плавающая кнопка обоев уходит: она
   рисуется поверх контента и оказывалась поверх листа — нажатие «мимо листа» попадало в неё
   и меняло обои вместо закрытия. */
body:has(.sheet-back){overflow:hidden}
body:has(.sheet-back) .wall{display:none}

/* ══════════════════════ КАНБАН НА ТЕЛЕФОНЕ ══════════════════════
   Разбор и решение — MOBILE_KANBAN_DESIGN.md.

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

/* Полоса-обзор и чипсы рисуются всегда, показываются только на телефоне. */
.kb-bar{display:none}

@media (max-width:720px){
  .kb-bar{display:block;margin:0 0 12px}

  /* Полоса: сегмент на этап, ширина — доля карточек, цвет — цвет этапа. */
  .kb-strip{display:flex;height:10px;border-radius:99px;overflow:hidden;
    background:var(--film-1);border:1px solid var(--line)}
  .kb-seg{min-width:3px;transition:flex-grow .3s var(--ease);border:0;padding:0}
  .kb-seg + .kb-seg{border-left:1px solid var(--line)}
  .kb-strip-empty{font-size:11.5px;color:var(--ink-2)}

  /* Чипсы этапов — лента прокручивается САМА (страница при этом стоит: требование
     «интерфейс не ездит вправо-влево» относится к странице, а не к ленте внутри неё). */
  .kb-chips{display:flex;gap:6px;margin-top:9px;overflow-x:auto;scrollbar-width:none;
    -webkit-overflow-scrolling:touch;padding-bottom:2px}
  .kb-chips::-webkit-scrollbar{display:none}
  .kb-chip{flex:0 0 auto;display:inline-flex;align-items:center;gap:6px;height:34px;
    padding:0 12px;border-radius:99px;background:var(--film-2);border:1px solid var(--line);
    font-size:12.5px;color:var(--ink-2);white-space:nowrap}
  .kb-chip i{font-style:normal;font-size:11px;font-weight:700;color:var(--ink)}
  /* Чипс этапа — переключатель МЕНЮ, и стоит он на той же ступени, что .cpill.on на широком
     экране: акцент принадлежит кнопкам действия. */
  .kb-chip.on{background:var(--on-solid);border-color:transparent;color:var(--on-solid-ink)}
  .kb-chip.on i{color:var(--on-solid-ink)}
  .kb-chip-dot{width:7px;height:7px;border-radius:99px;flex:0 0 7px}

  /* Колонки → секции. Одна под другой, без внутренней прокрутки. */
  .kanban{display:block}
  .kcol{background:none;padding:0;min-height:0;border-radius:0}
  .kcol + .kcol{margin-top:14px}

  /* Липкий заголовок отвечает на «а это какой этап» на любой глубине прокрутки — на широком
     экране на это отвечает сама колонка, здесь отвечать больше нечему.
     top равен нулю: своей липкой шапки у экрана пока нет, она появится этапом 2 плана. */
  .kcol-h{position:sticky;top:calc(var(--safe-t) + var(--stick-h, 0px) + var(--hdr-real, 52px));
    z-index:6;margin:0;min-height:46px;padding:8px 12px;
    border-radius:var(--rad-s);background:var(--film-2);
    -webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
    border:1px solid var(--line)}
  .kcol-h b{font-size:13.5px}
  /* Переименование этапа тапом по заголовку на телефоне не работает: тап уже занят
     сворачиванием. Правка этапов — отдельным листом (меню «⋯» экрана). */
  .kcol-h b[contenteditable]{pointer-events:none}
  .kcol-h .kcol-x{display:none}
  /* Стрелка-указатель состояния: повёрнута вниз у развёрнутой секции. */
  .kcol-h::after{content:'';flex:0 0 auto;width:9px;height:9px;margin-left:2px;
    border-right:2px solid var(--ink-2);border-bottom:2px solid var(--ink-2);
    transform:rotate(45deg) translate(-2px,-2px);transition:transform .2s var(--ease)}
  .kcol.folded .kcol-h::after{transform:rotate(-45deg) translate(-1px,1px)}
  .kcol.folded .kcol-body{display:none}
  .kcol-body{padding:10px 2px 0}

  /* Карточка: три строки вместо пяти. Готовность переезжает в полоску по нижнему краю —
     она читается мгновенно, а «40 % готовности · команда 3» отнимает целую строку. */
  .lead{padding:12px;cursor:default}
  .lead-note{display:none}
  .lead-foot{margin-top:7px}
  .lead + .lead{margin-top:8px}
  .lead-gaps{margin-top:7px}

  /* Кнопка «добавить этап» — во всю ширину: в конце длинного списка её ищут глазами. */
  .kcol-add{width:100%;justify-content:center;margin-top:14px;min-height:var(--tap-min)}
}

/* ══════════ ЭКРАН НА ТЕЛЕФОНЕ: шапка вместо панели ══════════
   Панель на широком экране — это второй и третий уровень навигации: кубики раздела и список
   его экранов. На телефоне она вставала НАД содержимым и занимала пол-экрана, поэтому здесь
   от неё остаётся только то, что нужно постоянно: название раздела, главное действие и лента
   кубиков. Список экранов уходит под название в шапке рабочего поля (стрелка вниз). */
.h2-chev{display:none}

@media (max-width:720px){
  .app-row{gap:0}

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

     И у прилипшей шапки обязан быть свой фон. Прозрачная она пропускает сквозь себя
     уезжающий контент: на экране оказываются два слоя текста в одной полосе — заголовок
     раздела поверх карточек, — и это читается как поломка вёрстки, а не как липкая шапка. */
  .panel{position:sticky;top:var(--safe-t);z-index:9;padding:0 0 6px;border:0;box-shadow:none;
    background:var(--surf-1);
    -webkit-backdrop-filter:blur(22px) saturate(130%);backdrop-filter:blur(22px) saturate(130%)}
  .panel-top{padding:10px 12px 8px}
  .panel-title h1{font-size:18px;letter-spacing:-.02em}
  /* Сводка раздела («2 заявки · 0 новых») и карточка ближайшего события с телефона убраны:
     первое повторяется числами на кубиках, второе — целый раздел «Задачи» в нижнем меню.

     Скрывается ИМЕННО сводка в шапке панели, а не класс `.panel-sum` целиком. Класс общий —
     это стиль мелкого приглушённого текста, и им размечены 359 мест в кабинете: надписи
     «Загружаем…» и «Считаем…», пустые состояния, пояснения в модальных окнах. Правило по
     классу гасило их все, и на телефоне человек видел пустоту вместо сообщения о том, что
     данные едут. Тестами это не ловится никогда: разметка на месте, текст в ней есть,
     прячет его CSS. Сторож — `test/nadpisi-ozhidaniya-vidny.test.js`. */
  .panel-top > .panel-sum{display:none}
  .settings-foot{display:none}
  /* Главное действие раздела — рядом с названием, а не отдельной полосой во всю ширину:
     полоса стоила 56 пикселей высоты на каждом экране. */
  .panel-cta{margin:0;padding:9px 14px;font-size:13px;white-space:nowrap}
  .panel-title{gap:8px}

  /* Кубики раздела → лента вкладок. Ширина по содержимому, прокрутка внутри ленты. */
  .folders{display:flex;gap:6px;padding:0 12px 8px;overflow-x:auto;scrollbar-width:none;
    -webkit-overflow-scrolling:touch}
  .folders::-webkit-scrollbar{display:none}
  .folder{flex:0 0 auto;flex-direction:row;align-items:center;gap:6px;min-height:36px;
    padding:0 12px;border-radius:99px;text-align:left}
  .folder i{font-size:11px;font-weight:700;order:2;opacity:.75}
  .folder b{font-size:12.5px;letter-spacing:-.01em;white-space:nowrap}

  /* Список экранов раздела в панели больше не рисуется — он живёт в листе по стрелке. */
  .panel-list{display:none}

  /* Шапка рабочего поля: крошки уходят, название становится кнопкой выбора экрана. */
  .ws{border-radius:var(--rad) var(--rad) 0 0}
  /* Шапка экрана прилипает под шапкой раздела: обе к одной границе — это два слоя текста
     друг на друге. Высоту первой ставит app.js в --stick-h после каждой отрисовки. */
  .ws-top{position:sticky;top:calc(var(--safe-t) + var(--stick-h, 0px));z-index:7;padding:11px 12px;
    background:var(--surf-2);
    -webkit-backdrop-filter:blur(22px) saturate(130%);backdrop-filter:blur(22px) saturate(130%);
    border-radius:var(--rad) var(--rad) 0 0}
  .ws-top .crumb{display:none}
  .ws-top h2{display:inline-flex;align-items:center;gap:6px;font-size:17px;letter-spacing:-.02em}
  .h2-chev{display:inline-block;width:8px;height:8px;flex:0 0 8px;
    border-right:2px solid var(--ink-2);border-bottom:2px solid var(--ink-2);
    transform:rotate(45deg) translate(-1px,-2px)}
  .ws-body{padding:14px 12px 22px}

  /* Подпись пункта в листе выбора — второй строкой, приглушённая. */
  .ms-row{flex-direction:column;align-items:flex-start;justify-content:center;gap:2px;
    padding:9px 12px;min-height:52px}
  .ms-row span{font-size:11.5px;color:var(--ink-2);line-height:1.35}
  .ms-row.on{background:var(--film-3)}
  .ms-row.on b{color:var(--ink)}
  .ms-head{margin:0 0 8px;padding:0 12px;font-size:11.5px;letter-spacing:.04em;
    text-transform:uppercase;color:var(--ink-2)}
}

/* Дальнейшее ужатие шапки раздела: 342 пикселя до содержимого — всё ещё много.
   Разбирается по слагаемым: заголовок с действием в одну строку (было три), фильтры лентой
   (было три ряда пилюль), числа раздела компактной полосой (было 150 пикселей плиток). */
@media (max-width:720px){
  /* Заголовок, поиск и главное действие — одной строкой. */
  .panel-top{display:flex;align-items:center;gap:8px;flex-wrap:nowrap}
  .panel-title{flex:1 1 auto;min-width:0}
  .panel-title h1{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .panel-cta{flex:0 0 auto}
  /* Подпись действия скрываем на самых узких экранах — остаётся плюс. */
  .panel-cta .ic{margin:0}

  /* Пилюли фильтров (источники заявок, фильтры чата) — одной прокручиваемой лентой вместо
     трёх рядов: три ряда пилюль стоили 118 пикселей высоты на каждом открытии раздела. */
  .panel .chat-pills{display:flex;flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;
    padding:0 12px 8px;gap:6px}
  .panel .chat-pills::-webkit-scrollbar{display:none}
  .panel .cpill{flex:0 0 auto;white-space:nowrap;min-height:34px}

  /* Числа раздела: полоса вместо плиток. Те же четыре значения читаются в одну строку. */
  .figs{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;padding-bottom:2px}
  .figs::-webkit-scrollbar{display:none}
  .fig{flex:0 0 auto;min-width:104px;padding:10px 12px}
  /* Сводка тарифа и рефералки — ПЕРЕНОС, а не лента. Три плитки не влезали в 390: последняя
     уходила на 87 пикселей за правый край, а полосы прокрутки на телефоне не видно
     (`scrollbar-width:none` выше) — догадаться, что там что-то есть, человеку нечем. Лента
     годится там, где значений четыре и больше и каждое короткое; здесь их три, и это единственная
     сводка, ради которой на экран пришли. Требование владельца (MOBILE_KANBAN_DESIGN.md):
     «интерфейс не двигается вправо-влево, только вверх-вниз». */
  .figs-wrap{flex-wrap:wrap}
  .figs-wrap .fig{flex:1 1 104px}
  .fig b{font-size:18px}
  .fig span{font-size:11px}

  /* Первый этап воронки — точка входа с кнопкой «Новая заявка» в заголовке. На телефоне это
     же действие уже стоит в шапке раздела: две одинаковые зелёные кнопки на одном экране
     заставляют выбирать между ними, хотя выбора нет. В секции остаётся обычный заголовок. */
  .lead-col-entry .kcol-cta{display:none}
  .lead-col-entry .kcol-h::before{content:attr(data-entry);flex:1 1 auto;
    font-size:13.5px;font-weight:600;color:var(--ink)}
}

/* Кнопка «фильтры» — только на телефоне: на широком экране ленты пилюль стоят всегда. */
.m-filter{display:none}
@media (max-width:720px){
  .m-filter{display:inline-flex;flex:0 0 auto}
  .m-filter.on{background:var(--on-solid);color:var(--on-solid-ink)}
  /* Под кнопку прячется ВЕСЬ блок фильтров, а не только ленты пилюль внутри него: в каталоге
     специальности и города лежат в .cat-block вместе с подписями, и скрытие одних лент
     оставляло на экране «Специальность» и «Город» без единой кнопки под ними — вид поломки. */
  .panel .chat-pills, .panel .cat-block{display:none}
  .panel.filters-on .chat-pills{display:flex}
  .panel.filters-on .cat-block{display:block;padding:0 12px 10px}
  .panel.filters-on .cat-block .chat-pills{padding-left:0;padding-right:0}
  .cat-label{font-size:11.5px;margin-bottom:6px}
  /* Блок отбора, строка поиска и подвкладки панели «Навигатор» — под той же кнопкой. */
  .panel .filt,.panel .sfield,.panel .tabs2,.panel .nsep{display:none}
  .panel.filters-on .filt{display:block}
  .panel.filters-on .sfield{display:flex;margin:0 12px 8px}
  .panel.filters-on .tabs2{display:flex;padding:0 12px}
}
/* Телефон: панель — липкая шапка, а не окно; кубики — снова лентой пилюль, потому что строки
   в столбик заняли бы пол-экрана. Ставится ПОСЛЕ правил «Навигатора», чтобы их перебить. */
@media (max-width:720px){
  .panel{border-radius:0;padding-top:0;backdrop-filter:blur(22px) saturate(130%);
    -webkit-backdrop-filter:blur(22px) saturate(130%)}
  .panel-top{padding:10px 12px 8px}
  .folders{flex-direction:row;flex-wrap:nowrap;gap:6px;padding:0 12px 8px}
  .folder{width:auto;background:var(--glass);border:1px solid var(--edge);border-radius:99px;
    padding:0 12px;min-height:36px}
  .folder.on{background:var(--on-solid);color:var(--on-solid-ink)}
  .folder.on i{color:var(--on-solid-ink)}
  .folder .mark{display:none}
  .folders .more{margin:0;padding:0 12px;min-height:36px;border-radius:99px;white-space:nowrap}
}

/* Заголовок раздела не должен уступать место кнопке: `width:100%` у действия растягивал его
   на всю строку и накрывал собой название вместе с кнопками поиска и фильтров. */
@media (max-width:720px){
  .panel-top{margin:0 12px;padding:10px 12px;border-radius:var(--rad)}
  /* Кнопка ужимается до плюса: подпись «Новая заявка» рядом с названием раздела, поиском и
     фильтрами не помещалась и обрезалась на середине слова, а обрезанное слово читается как
     поломка. Смысл плюса в шапке раздела очевиден, а для голосового доступа есть aria-label. */
  .panel-cta{width:auto;margin:0;flex:0 0 auto;font-size:0;padding:0;
    width:var(--tap-min);height:var(--tap-min);justify-content:center;border-radius:99px}
  .panel-cta .ic{width:19px;height:19px;margin:0}
  .panel-title{margin:0;justify-content:flex-start}
  .panel-title h1{flex:1 1 auto;min-width:0}
  .figs{padding-right:12px}
  .fig{min-width:96px}
}

/* Кнопка переноса карточки — только на телефоне: на широком экране карточку тащат мышью. */
.lead-move{display:none}
@media (max-width:720px){
  .lead-move{display:inline-grid;place-items:center;width:34px;height:34px;flex:0 0 34px;
    border-radius:99px;color:var(--ink-2);position:relative}
  /* Область нажатия крупнее самой иконки: значок в плотном подвале карточки не должен
     выглядеть основным действием, но попадать по нему нужно уверенно. */
  .lead-move::after{content:'';position:absolute;top:50%;left:50%;width:var(--tap-min);
    height:var(--tap-min);transform:translate(-50%,-50%);border-radius:99px}
  .lead-move .ic{width:16px;height:16px}
  .lead-foot{gap:4px}

  /* Карточка едет за пальцем, а под ней проступает подсказка «куда поедет». */
  .lead{position:relative;z-index:1;touch-action:pan-y}
  .kb-hint{position:absolute;left:0;right:0;z-index:0;display:flex;align-items:center;
    justify-content:flex-end;padding:0 16px;border-radius:var(--rad-s);
    background:color-mix(in srgb, var(--acc) 22%, transparent);
    font-size:12.5px;font-weight:600;color:var(--ink);pointer-events:none}
  .kb-hint-l{justify-content:flex-start}
  .kcol-body{position:relative}
}

/* ══════════ МОДАЛЬНЫЕ ОКНА НА ТЕЛЕФОНЕ ══════════
   Все 139 окон продукта превращаются в нижние листы одним правилом — переписывать каждое
   незачем: разметка у них общая (.modal-back > .modal), различается только содержимое.

   Почему лист, а не окно по центру: окно посреди экрана держит крестик в верхнем углу, куда
   большой палец не дотягивается, и оставляет узкие поля по бокам, отнимая ширину у формы.
   Лист приезжает снизу, к пальцу, закрывается тем же движением и занимает всю ширину. */
@media (max-width:720px){
  .modal-back{display:flex;align-items:flex-end;justify-content:center;padding:0}

  .modal{width:100%;max-width:none;
    border-radius:var(--rad-l) var(--rad-l) 0 0;
    /* Не выше 92% экрана: над листом должна остаться полоска фона — по ней видно, что это
       слой поверх страницы, а не новый экран, и по ней же закрывают. */
    max-height:92vh;
    padding:14px 14px calc(16px + var(--safe-b));
    animation:mUp .24s var(--spring)}
  /* Сдвиг задан в пикселях, а не процентах: у высокого окна 12 % — это девяносто пикселей, и
     любая пауза анимации (свёрнутая вкладка, экономия энергии) оставляет лист висящим ниже
     экрана вместе с кнопками. Восемнадцать пикселей дают то же ощущение приезда снизу и в
     худшем случае прячут только скруглённый край. */
  @keyframes mUp{from{transform:translateY(18px)}to{transform:none}}

  /* Ручка листа. Рисуется псевдоэлементом, чтобы не трогать разметку каждого окна. */
  .modal::before{content:'';display:block;width:38px;height:4px;border-radius:99px;
    background:var(--edge-hi);margin:2px auto 10px}

  .modal-h{top:-14px;padding-top:14px;margin-top:-14px;gap:8px;flex-wrap:wrap}
  /* Заголовку — остаток строки, а не остаток от остатка. На 375 пикселях шапка карточки
     события складывалась из имени, ответственного, состояния и крестика; имени доставалось
     56 пикселей, и «Дарья и Артём» вставало в три строки. Многоточие тут не спасало: без
     white-space:nowrap оно не срабатывает вовсе, а с ним имя события превращается в «Дарья и…»,
     что для заголовка хуже переноса. Поэтому не сжимаем имя, а уводим на вторую строку самое
     необязательное — ответственного: он тут же виден в самой карточке. */
  .modal-h h3{font-size:16px;min-width:0;flex:1 1 auto}
  /* `max-width:46%` и `margin-left:auto` из базового правила на второй строке уже не нужны:
     они прижимали строку к правому краю и резали имя многоточием посреди пустого места. */
  .modal-h .pj-resp{order:5;flex:1 1 100%;margin:2px 0 0;max-width:none}
  .modal-f{bottom:calc(-16px - var(--safe-b));padding-bottom:calc(16px + var(--safe-b));
    margin-bottom:calc(-16px - var(--safe-b));gap:8px}
  /* Кнопки подвала во всю ширину и в один ряд: две кнопки по 44 пикселя на 375 пикселях
     помещаются, а «Отмена»/«Сохранить» мельче становятся ловушкой для пальца.

     Подсказка («* — без этого заявку не сохранить») уходит на свою строку НАД кнопками:
     в одном ряду с ними она сжималась до колонки в одну букву шириной и растягивала подвал
     на две сотни пикселей. Текст при этом не теряется — он важен, там объяснение звёздочек. */
  .modal-f{flex-wrap:wrap;align-items:center}
  .modal-f .note{flex:1 0 100%;order:-1;margin:0 0 8px !important;font-size:11.5px}
  /* flex-basis: auto, а не 0. С нулём три кнопки делили ширину поровну — по девяносто
     четыре пикселя каждой, — и подписи вроде «Загрузить список (CSV)» ломались по буквам
     («Загру / зить / списо / к»), превращая ряд в три круга высотой в девяносто пикселей.
     С auto кнопка сначала занимает свою ширину и переносится на новую строку, когда не
     влезает: перенос у ряда уже разрешён. */
  .modal-f .btn{flex:1 1 auto;min-height:var(--tap-min);justify-content:center;align-self:stretch}

  /* Второй слой (подбор специалиста поверх карточки) остаётся листом же, но чуть ниже. */
  .modal-back-2 .modal{max-height:86vh}
}

/* ══════════ ФОРМЫ НА ТЕЛЕФОНЕ ══════════ */
@media (max-width:720px){
  /* Пары полей разворачиваются в столбик. На 375 пикселях каждому полю пары достаётся 167,
     и «Имя заказчика» с «Следующим касанием» в такой ширине набираются вслепую: подпись
     обрезается, значение не видно целиком.

     Исключение — пары, где оба значения заведомо короткие (суммы «от/до», время «с/по»):
     они помечаются классом .fld-row--pair по месту, когда до этого экрана дойдёт очередь. */
  .fld-row{grid-template-columns:1fr}
  .fld-row--pair{grid-template-columns:1fr 1fr}
  .fld{margin-bottom:11px}
  /* Поля крупнее: 16px — граница, ниже которой iOS Safari масштабирует страницу при фокусе,
     и форма уезжает вбок целиком. Это не про читаемость, это про то, что вёрстка ломается. */
  .fld input, .fld select, .fld textarea,
  .composer input, .lead-search, input[type="text"], input[type="tel"],
  input[type="email"], input[type="number"], input[type="date"], input[type="time"], textarea, select{
    font-size:16px;min-height:var(--tap-min)}
  .fld textarea{min-height:88px}
}

/* Пока открыто окно или лист, нижнее меню уходит: оно рисуется поверх содержимого и накрывало
   собой кнопки подвала — «Сохранить» оказывалось под «Домой». В мобильных приложениях модальный
   контекст точно так же закрывает панель разделов: пока не решил, что делать с окном, разделы
   всё равно недоступны. */
@media (max-width:720px){
  body:has(.modal-back) .tabbar,
  body:has(.sheet-back) .tabbar{display:none}
  /* Со скрытым меню контенту под окном больше не нужен запас снизу. */
  body:has(.modal-back) .app{padding-bottom:14px}
  body:has(.modal-back) .wall{display:none}
  /* Страница под окном не прокручивается: иначе прокрутка внутри формы «проваливается» на
     страницу, и фон уезжает вместе с пальцем. */
  body:has(.modal-back){overflow:hidden}
}

/* ══════════ ТАБЛИЦЫ НА ТЕЛЕФОНЕ ══════════
   Строка становится карточкой «подпись — значение». Подписи проставляет разметке app.js из
   заголовков той же таблицы: второй список названий колонок в стилях разъехался бы с первым. */
@media (max-width:720px){
  .tw{overflow:visible}
  /* min-width:660px держал таблицу шире экрана даже разложенной в карточки — это правило
     широкого экрана, где колонкам нужна ширина, а карточкам она не нужна вовсе. */
  .tw table, .t-cards{min-width:0}
  .t-cards{display:block;width:100%}
  .t-cards thead{display:none}
  .t-cards tbody,.t-cards tr{display:block;width:100%}
  .t-cards tr{background:var(--film-1);border:1px solid var(--line);border-radius:var(--rad-s);
    padding:10px 12px;margin-bottom:8px}
  .t-cards td{display:flex;align-items:baseline;justify-content:space-between;gap:12px;
    padding:4px 0;border:0;width:auto;text-align:right;font-size:13px}
  .t-cards td::before{content:attr(data-col);flex:0 0 auto;max-width:52%;
    font-size:11.5px;color:var(--ink-2);text-align:left;font-weight:500}
  /* Первая ячейка — заголовок карточки: у неё подпись не нужна, там имя строки. */
  .t-cards td:first-child{justify-content:flex-start;text-align:left;font-weight:600;
    font-size:14px;padding-bottom:6px}
  .t-cards td:first-child::before{display:none}
  /* Пустая ячейка не занимает строку: «Оплачено — » выглядит как потеря данных. */
  .t-cards td:empty{display:none}
}

/* ══════════ ГРАФИКИ НА ТЕЛЕФОНЕ ══════════
   «Загрузка по неделям» — сорок четыре столбца. На 375 пикселях каждому достаётся семь, и
   подпись под ним обрезается в ноль: график превращается в частокол без чисел.

   Столбцу задаётся минимальная ширина, а сам ряд прокручивается — это лента внутри карточки,
   страница при этом стоит. Данные и подписи остаются целыми, а на графике с тремя столбцами
   («мероприятия по месяцам») ничего не меняется: там минимальная ширина не срабатывает. */
@media (max-width:720px){
  .bars{overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;
    padding-bottom:4px;scroll-snap-type:x proximity}
  .bars::-webkit-scrollbar{display:none}
  .bar-col{flex:0 0 auto;min-width:34px;scroll-snap-align:start}
  .bar-cap{font-size:10.5px}
  /* Край ленты растушёван: по нему видно, что справа есть ещё столбцы. */
  .bars{-webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 18px),transparent);
    mask-image:linear-gradient(90deg,#000 calc(100% - 18px),transparent)}
}

/* ══════════ ОБЛАСТИ НАЖАТИЯ ══════════
   Замер по 97 экранам: 575 кнопок меньше 40 пикселей, из них 173 на одном «Каталоге» — там
   в каждой карточке специалиста по три кнопки 30×36. Мышью в такую попадают, пальцем — через
   раз, и промах по «написать» открывает чужой профиль.

   44 пикселя — не «красивое число», а нижняя граница, ниже которой промахи перестают быть
   случайностью (Apple HIG, Material). Кнопкам задаётся минимум, иконочным — квадрат. */
@media (max-width:720px){
  .btn{min-height:var(--tap-min)}
  .btn-sm{min-height:38px}
  .icon-btn{min-width:var(--tap-min);min-height:var(--tap-min)}
  /* Кнопка-иконка без подписи в плотном списке остаётся визуально мелкой, но область нажатия
     вокруг неё расширяется до 44: увеличивать сам значок значило бы сделать второстепенное
     действие главным на экране. */
  .lead-x, .kcol-x, .cpill-x{position:relative}
  .lead-x::after, .kcol-x::after, .cpill-x::after{content:'';position:absolute;
    top:50%;left:50%;transform:translate(-50%,-50%);
    width:var(--tap-min);height:var(--tap-min);border-radius:99px}
}

/* ══════════ СТРОКИ ВВОДА НА ТЕЛЕФОНЕ ══════════
   Строка «поле + выпадающий список + кнопка» на 375 пикселях не помещается: поле сжимается до
   тридцати двух пикселей, а подпись кнопки переносится по одной букве и растягивает её в
   вертикальный столбик высотой в сто тридцать шесть пикселей.

   Раскладываем в колонку: поле во всю ширину, под ним ряд из списка и кнопки. Так набирают
   текст на всей ширине экрана, а кнопка остаётся кнопкой. */
@media (max-width:720px){
  .composer{flex-wrap:wrap;gap:8px}
  .composer input, .composer textarea{flex:1 1 100%;min-width:0}
  .composer .fld-inline, .composer select{flex:1 1 auto;max-width:none;min-height:var(--tap-min)}
  .composer .btn{flex:0 0 auto;white-space:nowrap}
  /* Чат — исключение: там поле и «отправить» обязаны остаться в одной строке, иначе кнопка
     уезжает под клавиатуру, а сообщение отправляют десятки раз за вечер. Держит их не запрет
     переноса, а размеры: поле `flex:1 1 auto;min-width:96px` и кнопки-значки по 38 пикселей
     помещаются в один ряд на 375. Запрет же ловил и плашку «Отвечаете …» — она объявлена во
     всю ширину, вставала четвёртым элементом того же ряда и выдавливала строку отправки на
     78 пикселей за правый край экрана. */
  .chat-sheet > .composer input{flex:1 1 auto}
}

/* ══════════ СТРОКИ СПИСКОВ НА ТЕЛЕФОНЕ ══════════
   .row — самый частый компонент продукта: «аватар · текст · кнопки» в одну линию. На узком
   экране длинная подпись и две кнопки не помещаются рядом, и flex сжимает всех подряд: текст
   до девятнадцати пикселей ширины, кнопку — до столбика из букв высотой в сто двадцать семь.

   Раскладываем в две строки: содержимое сверху, действия под ним. Аватар остаётся слева от
   текста — по нему узнают, о ком строка. */
@media (max-width:720px){
  .row{flex-wrap:wrap;gap:8px 10px;padding:12px 2px}
  /* Основа строки просит 180 пикселей, а не всю ширину: там, где рядом помещается одна
     короткая кнопка («открыть»), строка остаётся однострочной и список не растягивается на
     двести пикселей на запись. Не помещается — перенос случается сам, по месту. */
  .row-main{flex:1 1 180px;order:1}
  .row .ava{order:0}
  /* Метки и действия — своей строкой: метки слева, кнопки справа. Порядок задан явно, иначе
     они выстраиваются в порядке разметки, и кнопка оказывается между двумя пометками —
     читается как ещё одна пометка, по которой почему-то можно нажать. */
  .row > .tag, .row > .kcol-n, .row > .row-side{order:2;flex:0 0 auto;white-space:nowrap}
  .row > .btn, .row > .lead-x, .row > .icon-btn{order:3;flex:0 0 auto;white-space:nowrap}
  .row > .btn:first-of-type{margin-left:auto}
  /* Аватар и первая строка текста стоят рядом: без этого лицо уезжает на свою строку. */
  .row .ava + .row-main{flex:1 1 auto;order:0}
}

/* Мелкие пилюли (роли в команде, быстрые фильтры) — 28 пикселей высоты мышью нажимаются, а
   пальцем через раз. 38 вместо 44: их бывает по два десятка подряд, и полный размер превратил
   бы плотный список в экран из одних кнопок. */
@media (max-width:720px){
  .cpill-sm{min-height:38px}
  .tag{min-height:26px;display:inline-flex;align-items:center}
}

/* Строка беседы в листе выбора: аватар, имя, последняя реплика, счётчик непрочитанного.

   Вне медиа-запроса намеренно. Пока листы жили только на телефоне, это была мобильная вёрстка;
   теперь лист чата открыт на любой ширине, и запертая внутри `max-width:720px` вёрстка давала
   на компьютере слипшиеся в строку «Опрос«Кто может 12-го?»» — кнопка работает, а выглядит
   сломанной. Значения те же, что были, так что на телефоне не изменилось ничего. */
.ms-row--th{flex-direction:row;align-items:center;gap:10px}
.ms-row--th .th-ava{width:36px;height:36px;flex:0 0 36px;border-radius:99px;
  display:grid;place-items:center;font-size:12px;font-weight:600;color:#fff}
.ms-th-main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.ms-th-main b{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ms-th-main span{font-size:11.5px;color:var(--ink-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ms-th-n{flex:0 0 auto;font-style:normal;font-size:11px;font-weight:700;
  min-width:20px;height:20px;padding:0 6px;border-radius:99px;
  background:var(--acc);color:var(--acc-ink);display:grid;place-items:center}

/* ══════════ ЧАТ НА ТЕЛЕФОНЕ ══════════
   На широком экране переписка занимает высоту окна, лента сообщений прокручивается внутри
   себя, а поле ввода прижато к низу. На телефоне страница стала расти по содержимому — и поле
   ввода уехало под конец переписки: чтобы написать «еду», надо было пролистать всю историю.

   Возвращаем прежнее устройство в мобильных мерах: рабочее поле ровно в высоту экрана за
   вычетом шапок, лента прокручивается сама, поле ввода стоит над нижним меню. */
@media (max-width:720px){
  /* Высоту НЕ считаем в vh: шапка раздела, лента кубиков и шапка экрана на разных экранах
     разной высоты, и любая формула ошибается на десятки пикселей — поле ввода то уезжает под
     нижнее меню, то оставляет под собой пустую полосу.

     Вместо этого поле прилипает к низу экрана над меню, а переписка прокручивается страницей,
     как в мессенджерах на телефоне. */
  /* Рабочее поле ровно до нижнего меню: высота считается от ФАКТИЧЕСКОГО положения его
     верхнего края (--chat-top ставит app.js после отрисовки). Формула в vh здесь ошибается
     на десятки пикселей — шапка раздела, лента кубиков и шапка экрана на разных экранах
     разной высоты.

     position:fixed для поля ввода не подходит: у рабочего поля есть backdrop-filter, а он
     создаёт содержащий блок — фиксированный элемент внутри стекла позиционируется не от
     экрана, а от стекла, и поле уезжало ниже видимой области. */
  .ws-body:has(.chat-sheet){
    height:calc(100dvh - var(--chat-top, 200px) - var(--tabbar-h) - var(--safe-b) - 14px);
    min-height:300px;overflow:hidden;padding-bottom:6px}
  .chat{overflow-y:auto;min-height:0;-webkit-overflow-scrolling:touch}
  .chat-sheet > .composer{flex:0 0 auto;z-index:9;
    padding:10px 10px;margin-top:8px;border-radius:99px;border-top:0;
    background:var(--surf-3);
    -webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);
    box-shadow:0 8px 26px rgba(0,0,0,.24)}
  /* Кнопки ужимаются до значков, включая «Отправить». Иначе на 305 пикселях ширины четыре
     кнопки с подписями съедали всё, и на само поле ввода оставалось шестьдесят пикселей —
     писать в него нельзя, а именно ради него экран и открывают.

     Бумажный самолётик вместо слова «Отправить» — общепринятый значок, его узнают без подписи;
     для голосового доступа остаётся aria-label кнопки. */
  .chat-sheet > .composer{gap:6px}
  .chat-sheet > .composer .btn{flex:0 0 auto;width:38px;min-width:38px;height:38px;
    min-height:38px;padding:0;justify-content:center;font-size:0;border-radius:99px}
  .chat-sheet > .composer .btn .ic{margin:0;width:18px;height:18px}
  .chat-sheet > .composer input{flex:1 1 auto;min-width:96px;height:40px}
}

/* Три кнопки строки отправки — «+», микрофон, смайлы — стоят на ЛЮБОЙ ширине и НЕ прячутся.
   Раньше их было четыре, и три из них (скрепка, микрофон, шаблоны) повторяли пункты списка под
   «плюсом»: на телефоне лишние прятал класс `c-hide`, на компьютере они стояли рядом со своим
   же списком. Дублирования больше нет — прятать нечего, и `c-hide` вместе с ним ушёл.

   На телефоне кнопки ужимаются до 38 пикселей: три кружка по 44 оставляли полю ввода девяносто
   пять, а именно ради поля экран и открывают. Селектор перечисляет свои классы, а не берёт все
   `.icon-btn` в строке: в композере встречаются и другие кнопки-значки (снять привязку, отмена
   отправки), и ужимать их заодно незачем. */
@media (max-width:720px){
  .composer .c-plus, .composer .c-mic, .composer .c-emo{
    width:38px;min-width:38px;height:38px;min-height:38px}
}

/* Сетка смайлов. Одна на оба листа — вставку в текст и реакцию.

   Вбок не двигается ни на каком экране: перенос строк, а не полоса прокрутки. Требование
   владельца про телефон («только вверх-вниз») действует и здесь, а на компьютере лист шириной
   440 всё равно не вместил бы ряд из двенадцати в строку. */
.emo-g{margin-top:10px}
.emo-h{margin:0 2px 6px;font-size:11px;letter-spacing:.04em;text-transform:uppercase;color:var(--ink-3)}
.emo-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(38px,1fr));gap:4px}
.emo{height:40px;min-width:0;border-radius:var(--rad-s);
  display:grid;place-items:center;font-size:21px;line-height:1;background:var(--film-2);
  border:1px solid transparent}
.emo:hover{background:var(--film-3);border-color:var(--line)}
.emo:active{background:var(--film-4)}
/* Кружок под значком строки листа — той же причины, что и вёрстка `.ms-th-main` выше: лист
   чата открывается на любой ширине, и на компьютере значок оставался без подложки. */
.ms-row--th .ms-ic{width:36px;height:36px;flex:0 0 36px;border-radius:99px;
  display:grid;place-items:center;background:var(--film-3)}

/* Рабочее поле тянется до нижнего меню, даже когда содержимого мало: обрывающаяся на середине
   экрана плита читается как «здесь что-то не догрузилось», хотя всё на месте. */
@media (max-width:720px){
  .ws{min-height:calc(100dvh - var(--ws-top, 220px) - var(--tabbar-h) - var(--safe-b) - 12px)}
}


/* ══════════ КАТАЛОГ СПЕЦИАЛИСТОВ НА ТЕЛЕФОНЕ ══════════
   Карточка в 232 пикселя минимальной ширины на экране в 375 даёт ОДНУ колонку: список
   превращается в ленту из огромных плиток, и до пятого человека надо листать полэкрана на
   каждого. Магазины (Wildberries, Ozon, Avito) на телефоне показывают ровно две карточки в
   ряд — так за один взгляд видно шестерых, а фото остаётся узнаваемым.

   Внутренности ужимаются под половинную ширину: фото квадратное (портрет в 4:3 при 170
   пикселях — это полоска), подписи мельче, кнопки в подвале равной ширины. */
@media (max-width:720px){
  .spec-grid{grid-template-columns:1fr 1fr;gap:10px}
  .spec-photo{aspect-ratio:1;font-size:22px}
  .spec-body{padding:9px 10px 10px;gap:2px}
  /* В карточке на половину экрана «Ведущий мероприятий · Барнаул» не помещается в строку ни при
     каком кегле. Даём две строки вместо многоточия: имя и профессия — это то, ради чего в
     каталог и заходят, и обрезанные они бесполезны. Третья строка уже была бы полотном. */
  .spec-name{font-size:13px;white-space:normal;display:-webkit-box;-webkit-box-orient:vertical;
    -webkit-line-clamp:2;line-height:1.25}
  .spec-sub{font-size:11.5px;white-space:normal;display:-webkit-box;-webkit-box-orient:vertical;
    -webkit-line-clamp:2;line-height:1.3}
  .spec-tags{gap:4px;margin-top:2px}
  .spec-tags .tag{font-size:10px;padding:2px 6px;min-height:20px}
  /* Цена и рейтинг на своих строках: рядом они не помещаются и сжимают друг друга в столбик. */
  .spec-meta{flex-wrap:wrap;gap:2px 8px;margin-top:4px}
  .spec-price,.spec-rating{font-size:11.5px}
  .spec-foot{flex-wrap:wrap;gap:6px;padding-top:8px}
  .spec-foot .btn{flex:1 1 100%;min-height:38px;justify-content:center;font-size:12px;padding:0 8px}
  .spec-online{top:8px;right:8px}
  .spec-flag{left:8px;top:8px;font-size:9.5px;padding:2px 6px}
}
/* Самые узкие экраны (320): две карточки остаются, но поля ещё меньше. */
@media (max-width:360px){
  .spec-grid{gap:8px}
  .spec-body{padding:8px 8px 9px}
}

/* ── Лист «Этапы доски» (телефон) ── */
@media (max-width:720px){
  .kb-bar-row{display:flex;align-items:center;gap:8px}
  /* Лента чипсов заканчивается ДО кнопки этапов: без этого последний чипс уезжает под неё и
     читается как обрезанный, хотя просто лежит ниже по слою. */
  .kb-bar-row .kb-chips{flex:1 1 auto;min-width:0;margin-top:9px;
    -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 16px),transparent);
    mask-image:linear-gradient(90deg,#000 calc(100% - 16px),transparent)}
  .kb-edit{flex:0 0 auto;display:grid;place-items:center;width:var(--tap-min);height:var(--tap-min);
    margin-top:9px;border-radius:99px;background:var(--film-2);border:1px solid var(--line);
    color:var(--ink-2)}
  .kb-edit .ic{width:17px;height:17px}

  .ms-row--st{flex-direction:row;align-items:center;gap:9px;padding:6px 8px}
  .st-name{flex:1 1 auto;min-width:0;height:40px;padding:0 12px;border-radius:var(--rad-s);
    background:var(--film-2);border:1px solid var(--line);color:var(--ink);font-size:15px}
  .st-name:focus{outline:none;border-color:var(--acc)}
  .st-lock{flex:0 0 auto;width:34px;text-align:center;color:var(--ink-3)}
  .st-ask{margin:2px 8px 10px;padding:12px;border-radius:var(--rad-s);
    background:color-mix(in srgb,var(--r) 12%,transparent);
    border:1px solid color-mix(in srgb,var(--r) 30%,transparent)}
  .st-ask b{display:block;font-size:14px;margin-bottom:4px}
  .st-ask span{display:block;font-size:12px;color:var(--ink-2);margin-bottom:10px}
  .st-ask-f{display:flex;gap:8px}
  .st-ask-f .btn{flex:1 1 0;justify-content:center;min-height:var(--tap-min)}
  .st-add{width:100%;justify-content:center;margin-top:10px;min-height:var(--tap-min)}
}

/* ══════════ ЛИПКОСТЬ: КОМУ РАЗРЕШЕНО БЫТЬ КОНТЕЙНЕРОМ ПРОКРУТКИ ══════════
   position:sticky работает относительно ближайшего предка с собственной прокруткой. У широкого
   экрана таких предков несколько нарочно: рабочее поле прокручивается внутри себя, доска едет
   вбок, лист сообщений живёт своей жизнью. На телефоне всё это мешает: элемент прилипает к
   предку, который сам не прокручивается, и просто уезжает вместе со страницей — именно так
   шапка экрана и заголовки секций оказывались поверх содержимого.

   Поэтому на телефоне прокрутка ровно одна — страничная, и все внутренние контейнеры её
   отпускают. Чат остаётся исключением: там своя лента сообщений, и она объявлена отдельно. */
@media (max-width:720px){
  .ws{overflow:visible}
  .ws-body{overflow:visible}
  .kanban{overflow:visible}
  .lead-kanban{overflow:visible}
  /* Ленты, которые ДОЛЖНЫ прокручиваться вбок, перечислены явно — они не содержат липкого. */
  .folders, .kb-chips, .figs, .bars, .panel .chat-pills{overflow-x:auto}
}

/* Плавающая кнопка обоев на телефоне: меньше и прозрачнее. Она нужна редко (обои меняют раз в
   жизни), а места занимает столько же, сколько кнопка ежедневного действия, и перекрывает
   правый край карточек. При прокрутке уходит вместе с нижним меню — по той же причине. */
@media (max-width:720px){
  .wall-fab{width:38px;height:38px;opacity:.55}
  .wall-fab .ic{width:17px;height:17px}
  /* Два правила, а не одно через запятую: браузер без поддержки :has() выбрасывает ВСЮ группу,
     и вместе с ней потерялся бы работающий соседний селектор. */
  .tabbar--min ~ .wall .wall-fab{opacity:0;pointer-events:none}
  body:has(.tabbar--min) .wall-fab{opacity:0;pointer-events:none}
}

/* ══════════ ПУБЛИЧНЫЕ СТРАНИЦЫ НА ТЕЛЕФОНЕ ══════════
   Портал пары, гостевая страница, сцена ведущего, расписание сборов, страница подрядчика,
   обеты и приглашения. У каждой своя обёртка и свой каркас — кабинетных .app и .panel здесь
   нет, — но экран у них тот же самый, с чёлкой и домашней полоской.

   Отступы даются обёрткам скопом: пропустить одну значит показать заголовок под часами
   человеку, который открыл ссылку впервые в жизни и второй раз её не откроет. */
@media (max-width:720px){
  /* body в селекторе не для красоты: у каждой страницы свои стили в <style>, и они идут ПОСЛЕ
     общего файла. Без повышения специфичности отступ проигрывал бы собственному padding
     страницы — и заголовок остался бы под чёлкой ровно там, где он и был. */
  body .sp-wrap, body .g-wrap, body .rt-wrap, body .mn-wrap,
  body .pt-wrap, body .sb-wrap, body .vw-wrap, body .st-wrap, body .br-wrap{
    padding-top:calc(20px + var(--safe-t));
    padding-bottom:calc(24px + var(--safe-b));
    padding-left:max(14px, var(--safe-l));
    padding-right:max(14px, var(--safe-r))}
  /* Ссылку открывают с чужого телефона и в спешке: кнопки крупные, поля не мельче 16 px —
     иначе iOS масштабирует страницу при первом же касании поля. */
  .sp-wrap .btn, .g-wrap .btn, .rt-wrap .btn, .mn-wrap .btn,
  .pt-wrap .btn, .sb-wrap .btn, .vw-wrap .btn, .st-wrap .btn, .br-wrap .btn{min-height:var(--tap-min)}
  .sp-wrap input, .g-wrap input, .rt-wrap input, .mn-wrap input, .pt-wrap input,
  .sb-wrap input, .vw-wrap input, .st-wrap input,
  .sp-wrap textarea, .g-wrap textarea, .pt-wrap textarea, .vw-wrap textarea, .br-wrap textarea{
    font-size:16px;min-height:var(--tap-min)}
}

/* Оценка времени шага онбординга (образец HoneyBook): «2 мин» справа от названия. */
.home-step-min{flex:0 0 auto;margin-left:auto;font-size:10.5px;color:var(--ink-3);
  padding:2px 7px;border-radius:99px;background:var(--film-3);white-space:nowrap}

/* Заголовок раздела сметы: сама строка таблицы, а не отдельный блок — иначе колонки заголовка
   и колонки статей не совпали бы, и «Итого банкета» встало бы не под суммами. Форма снята
   с реальных смет владельца: раздел, его итог, потом строки. */
.est-sec td{background:var(--fill);border-top:1px solid var(--edge);padding-top:10px}
.est-sec td b{font-size:13px}

/* ── Опрос, карточка встречи, реакции ─────────────────────────────────────
   Вариант опроса — кнопка во всю ширину пузыря: на телефоне ряд узких кнопок промахивается
   мимо пальца, а голосуют чаще с телефона. Имена проголосовавших переносятся строкой ниже —
   обрезать их нельзя, ради них сводка и нужна. */
.msg-rich{display:flex;flex-direction:column;gap:6px;margin:2px 0 4px}
.rich-q{font-weight:600}
.rich-line{font-size:12px;opacity:.75}
.rich-link{font-size:12px;text-decoration:underline}
.poll-opt{display:flex;flex-wrap:wrap;align-items:center;gap:6px;width:100%;text-align:left;
  border:1px solid var(--film-3);border-radius:10px;background:var(--film-1);
  color:inherit;padding:7px 10px;cursor:pointer;font:inherit}
.poll-opt.on{border-color:var(--acc);background:var(--film-3)}
.poll-opt b{font-weight:600;flex:1 1 auto}
.poll-opt em{font-style:normal;opacity:.7;font-variant-numeric:tabular-nums}
.poll-opt span{flex:1 0 100%;font-size:11.5px;opacity:.65}
/* Реакции стоят под репликой, а не поверх: наведения на телефоне нет, и всплывающая панель
   там недостижима вовсе. */
.msg-reacts{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}
.msg-react{display:inline-flex;align-items:center;gap:3px;border:1px solid var(--film-3);
  border-radius:999px;background:var(--film-1);color:inherit;padding:1px 7px;font-size:12px;
  line-height:18px;cursor:pointer}
.msg-react.on{border-color:var(--acc);background:var(--film-3)}
.msg-react em{font-style:normal;font-size:11px;opacity:.7}
/* Имена отметивших — рядом со значком, а не в подсказке: указателя на телефоне нет, и `title`
   там не показывается никак. Длинный список в одну строку не растягивает пузырь — чип
   переносится целиком (`.msg-reacts` уже flex-wrap), а сами имена усекаются многоточием:
   восемь имён в строке шире экрана, и от них не остаётся ни одного читаемого. */
.msg-react-who{font-style:normal;font-size:11px;opacity:.75;max-width:15em;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msg-react-who:empty{display:none}
.msg-react-add{opacity:.45}
.msg-react-add .ic{width:12px;height:12px}

/* Поиск по открытой беседе. Стоит НАД лентой и прокручивается вместе с листом: находка ведёт
   в ту же ленту, и отдельным окном её пришлось бы закрывать ради каждого перехода.
   Высота ограничена — выдача из двадцати строк не должна съедать саму переписку. */
.conv-find{
  flex:0 0 auto; padding:8px; margin-bottom:8px;
  background:var(--film-2); border-radius:10px; max-height:40%; overflow:auto;
}
.conv-find-top{ display:flex; align-items:center; gap:8px; }
.conv-find-top input{
  flex:1 1 auto; min-width:0; font:inherit; font-size:13px; padding:7px 10px;
  border:1px solid var(--line); border-radius:8px; background:var(--bg); color:var(--ink);
}
.conv-find .panel-sum{ padding:8px 2px 2px; margin:0; }
.conv-find .rows{ margin-top:6px; }

/* ── Планировка площадки (таск 56) ──────────────────────────────────────────
   Холст меряет МЕТРАМИ: viewBox равен размерам помещения, поэтому единица картинки — метр,
   а масштаб получается сам. aspect-ratio повторяет пропорции плана, и поля вокруг рисунка
   нет вовсе — иначе перевод экранных пикселей в метры пришлось бы считать с поправкой.
   Толщина линий — non-scaling-stroke: на территории в гектар обычная линия стала бы нитью
   в сотую пикселя, а в зале 6×4 — жирной полосой. */
.vp-map{
  display:block; width:100%; height:auto; touch-action:none; user-select:none;
  border:1px solid var(--film-3); border-radius:14px; background:var(--film-1);
}
.vp-floor{ fill:var(--film-1); }
.vp-grid{ stroke:var(--film-2); stroke-width:1; vector-effect:non-scaling-stroke; }
/* Сетка — фон, а не содержание: она под объектами и нажатий не перехватывает, иначе клик
   «мимо на пиксель» попадал бы в неё, а не в стол под ней. */
.vp-gridfill{ pointer-events:none; }

/* Мерная шкала: слева по высоте, снизу по ширине. Подписи стоят процентами от размера плана,
   поэтому попадают в свою линию сетки при любой ширине экрана. */
.vp-wrap{ display:grid; grid-template-columns:auto minmax(0,1fr); column-gap:6px; }
.vp-stage{ grid-column:2; grid-row:1; min-width:0; }
.vp-rule{ position:relative; font-size:10px; line-height:1; color:var(--ink-3); }
.vp-rule-y{ grid-column:1; grid-row:1; width:26px; }
.vp-rule-x{ grid-column:2; grid-row:2; height:15px; padding-top:3px; }
.vp-tick{ position:absolute; white-space:nowrap; }
.vp-rule-y .vp-tick{ right:0; transform:translateY(-50%); }
.vp-rule-x .vp-tick{ transform:translateX(-50%); }
/* Крайние подписи прижимаются к своему краю: центрированные, они уезжают за границу. */
.vp-rule-y .vp-tick-a{ transform:none; }
.vp-rule-y .vp-tick-z{ transform:translateY(-100%); }
.vp-rule-x .vp-tick-a{ transform:none; }
.vp-rule-x .vp-tick-z{ transform:translateX(-100%); }

/* Линейка. Ловушка нажатий прозрачна, но кликабельна — иначе замер по столу уходил бы в стол. */
.vp-measuring{ cursor:crosshair; }
.vp-catch{ fill:transparent; }
.vp-ruler{ pointer-events:none; }
.vp-rline{ stroke:var(--acc); stroke-width:2; vector-effect:non-scaling-stroke; }
.vp-rpt{ fill:var(--acc); }
.vp-rlbl{ fill:var(--acc); text-anchor:middle; font-weight:700; paint-order:stroke;
  stroke:var(--film-1); stroke-width:3; vector-effect:non-scaling-stroke; }
.vp-obj, .vp-tbl{ cursor:grab; }
.vp-obj > rect, .vp-obj > circle{
  fill:var(--film-3); stroke:var(--film-4); stroke-width:1; vector-effect:non-scaling-stroke;
}
.vp-tbl > rect, .vp-tbl > circle{
  fill:var(--film-2); stroke:var(--g); stroke-width:1.5; vector-effect:non-scaling-stroke;
}
/* Объект-ссылка помечен пунктиром: он не картинка, клик по нему открывает вложенный план. */
.vp-link > rect, .vp-link > circle{ stroke:var(--acc); stroke-dasharray:4 3; }
.vp-lbl{ fill:var(--ink-2); text-anchor:middle; dominant-baseline:middle; pointer-events:none; }
.vp-drag{ cursor:grabbing; }
.vp-drag > rect, .vp-drag > circle{ stroke:var(--acc); stroke-width:2; }

/* Выделенный стол и его ручка поворота (таск 77). Ручка висит НАД столом и только у
   выделенного: у всех сразу она перекрывала бы соседей на плотной расстановке. Толщина
   и радиус — non-scaling-stroke, как у всего холста: на территории в гектар обычная линия
   стала бы нитью. */
.vp-sel > rect, .vp-sel > circle{ stroke:var(--acc); stroke-width:2.5; }
.vp-rot{ fill:transparent; cursor:alias; }
.vp-rotdot{ fill:var(--acc); pointer-events:none; }
.vp-rotline{ stroke:var(--acc); stroke-width:1.5; vector-effect:non-scaling-stroke; }

/* ── Окно сметы (таск 67) ──────────────────────────────────────────────────
   Документ владельца — 60–75 строк по девять колонок, и единственное место в проекте, где
   длинная прокрутка законна. Прокручивается ТОЛЬКО таблица: шапка события, панель итогов и
   подвал стоят на месте, иначе, долистав до «Банкета», человек теряет из виду, чья это смета
   и сколько всего. Окно шире обычного — иначе девять колонок сжимаются до нечитаемых. */
.est-win{width:min(1320px,98vw)}
.est-head{flex:0 0 auto;display:flex;flex-wrap:wrap;gap:4px 16px;align-items:baseline;
  padding:0 0 10px;margin-bottom:10px;border-bottom:1px solid var(--edge)}
.est-head b{font-size:15px}
.est-head span{font-size:12.5px;color:var(--ink-3)}
.est-figs{flex:0 0 auto;margin-bottom:12px}
/* Сколько наличных нужно на руках — главный вопрос кануна, и число это заметно крупнее
   остальных: рядом с ним они справочные, а оно рабочее. */
.fig-big b{font-size:22px;color:var(--a)}
/* Базис у таблицы НУЛЕВОЙ, а не `auto`: при `auto` её базисом становится естественная высота
   содержимого (33 строки — 2628px), соседи сверху сжаться не могут (у них свой минимум по
   содержимому), и всё переполнение колонки достаётся одной таблице — в окне расчёта бюджета
   ей оставалось 26 пикселей при непустом теле. С базисом 0 она получает ОСТАТОК высоты, а не
   отдаёт свой. `min-height` держит нижний край: даже если верх разрастётся, таблица остаётся
   видимой полосой с прокруткой, а не исчезает молча. */
.est-win .est-tw{flex:1 1 0;overflow:auto;overscroll-behavior:contain;min-height:120px}
/* Ширину задаёт СОДЕРЖИМОЕ, а не число: девяти колонкам «рабочего бюджета» фиксированных
   920px не хватало, колонке «Бюджет» доставалось 88px, и жирный итог раздела ломался на два
   этажа («258 000» и «₽» под ним). Таблица берёт свою естественную ширину, а вбок едет
   контейнер — тело страницы не двигается никогда. */
.est-win .est-tw table{min-width:100%;width:max-content}
/* Деньги не переносятся ни в шапке, ни в теле, ни в подвале: число, разорванное пополам,
   читается как другое число. */
.est-win .est-tw th.num,.est-win .est-tw td.num{white-space:nowrap}
.est-win .est-tw thead th{position:sticky;top:0;z-index:1;background:var(--glass-2)}
.est-note{font-size:12px;color:var(--ink-3);max-width:280px}
/* Расхождение раскладки — словами и у самой строки: молча подправленная цифра выглядит верной
   ровно до того дня, когда по ней платят. */
.est-warn{font-size:11.5px;color:var(--r);margin-top:2px}
/* Пометка «вне базы гонорара» и подпись под строкой гонорара: обе объясняют число, поэтому
   стоят рядом с ним, а не в подсказке по наведению — на печати подсказок не бывает. */
.est-flag{display:inline-block;font-size:11px;font-style:normal;color:var(--ink-3);
  border:1px solid var(--line);border-radius:6px;padding:0 5px;margin-left:6px;white-space:nowrap}
.est-feenote{font-size:11.5px;color:var(--ink-3);margin-top:2px}
/* Денежное поле-калькулятор: подпись с результатом или отказом словами. Место под неё держится
   всегда (min-height), иначе форма прыгала бы на каждый набранный знак действия. */
.calc-out{display:block;min-height:15px;font-size:11.5px;font-style:normal;color:var(--ink-3);margin-top:3px}

/* Расчёт бюджета на заявке (таск 71). Окно то же, что у сметы (`.est-win`), добавлены только
   управление уровнем цены прямо в строке и вид выключенной статьи: она остаётся в списке
   серой — выключенное надо видеть, чтобы вернуть. */
/* Поля — ОДНОЙ строкой, а не сеткой 1fr 1fr: три поля и кнопка вставали в два ряда и занимали
   161 пиксель верха, то есть треть окна на невысоком экране. Главное содержимое здесь таблица
   статей, а поля — её настройка. */
.est-win .bc-in{display:flex;flex-wrap:wrap;gap:0 12px;padding:8px 14px 0;align-items:end}
.est-win .bc-in .fld{flex:1 1 130px;max-width:190px;margin-bottom:6px;gap:3px}
/* Карточки вариантов ниже ростом: три числа рядом читаются и без крупного кегля витрины. */
.est-win .est-figs{margin-bottom:8px}
.est-win .est-figs .fig{padding:9px 14px}
.est-win .est-figs .fig b{font-size:17px}
.est-win .est-figs .fig span{margin-top:2px}
/* Почему три варианта похожи — рядом с ними, а не в подвале: три почти равных числа без
   объяснения читаются как ошибка расчёта. */
.est-win .bc-why{margin:0 14px 8px;font-size:11.5px;color:var(--ink-3)}
.est-win .bc-src{color:var(--ink-3);font-size:11px;margin-top:2px}
.est-win .bc-ctl{padding:4px 0 0}
.est-win .bc-pick{max-width:280px;font-size:12px;padding:2px 6px;margin-top:2px}
.est-win tr.bc-off td{opacity:.45}
.est-win tr.bc-off .cpill{opacity:1}

/* ── Варианты сметы и план первой встречи (таск 70) ──────────────────────────────────────────
   Переключатель, поле плана и вопрос о платежах стоят в ШАПКЕ окна, вне прокрутки: прокручивается
   только таблица, и уехавший вверх переключатель означал бы, что человек не видит, какой вариант
   перед ним, — а это разные деньги. Всё это `flex:0 0 auto` по той же причине, что и `est-head`. */
.est-vars{flex:0 0 auto;display:flex;flex-direction:column;gap:6px;margin-bottom:10px}
/* Поле плана и его подпись — одной строкой: это одна мысль («договорились — вышло»), и в два
   этажа она съедала бы высоту таблицы. */
.est-plan{display:flex;flex-wrap:wrap;align-items:end;gap:6px 12px;font-size:12.5px;
  color:var(--ink-3)}
.est-plan .fld{flex:0 0 auto;width:180px;margin:0;gap:3px}
.est-plan .money-input{font-variant-numeric:tabular-nums}
.est-newvar{display:flex;flex-wrap:wrap;align-items:end;gap:6px 10px}
.est-newvar .fld{flex:1 1 240px;max-width:320px;margin:0;gap:3px}
/* Вопрос о судьбе платежей — панелью внутри окна, не третьим слоем: слоёв ровно два, и третий
   унёс бы окно события (test/modal-layers.test.js). */
.est-switch{padding:8px 10px;border:1px solid var(--r);border-radius:10px}
.est-switch p{margin:4px 0 6px;color:var(--ink-3);font-size:12px}
/* Три уровня паре (таск 38). Неназначенный уровень остаётся на месте и виден приглушённым: он
   и есть приглашение подготовить его, а исчезающая пилюля читалась бы как «уровней два». */
.est-levels{display:flex;flex-direction:column;gap:4px}
.est-lvl-off{opacity:.55;border-style:dashed}
.est-choice{font-size:12.5px;color:var(--ink-3)}
.est-choice-none{opacity:.75}
/* Разница в сравнении: минус зелёный (дешевле), плюс красный (дороже) — цвет здесь отвечает на
   вопрос «в какую сторону», а не «хорошо или плохо». */
.est-less{color:var(--g)}
.est-more{color:var(--r)}
.vrow-sum{width:110px;text-align:right;font-variant-numeric:tabular-nums}

/* ── График платежей группами (таск 69) ──────────────────────────────────────────────────────
   Заголовок группы — сам себе кнопка: число платежей и сумма видны свёрнутыми, и решение
   «раскрывать ли» принимается по ним, не раскрывая. Строк внутри столько же, сколько было
   лентой, — но их не видно, пока они не нужны. */
.pay-grps{display:flex;flex-direction:column;margin-top:6px}
.pay-grp-h{display:flex;align-items:baseline;gap:9px;width:100%;padding:6px 2px;
  border:0;border-top:1px solid var(--line);background:none;cursor:pointer;
  font:inherit;color:inherit;text-align:left}
.pay-grp-h:hover{color:var(--acc)}
.pay-grp-flat{cursor:default}
.pay-grp-h b{font-size:13px;font-weight:600}
.pay-grp-h em{font-style:normal;font-size:13px;font-weight:600;margin-left:auto;
  font-variant-numeric:tabular-nums}
.pay-grp-n{font-size:11.5px;color:var(--ink-3)}
/* Стрелка одна на оба состояния: раскрытая группа поворачивает её, а не меняет иконку. */
.pay-grp-h .pay-chev{flex:0 0 auto;align-self:center;transition:transform .12s}
.pay-grp.on .pay-grp-h .pay-chev{transform:rotate(180deg)}
/* Просроченное стоит НАД группами и красное: его ищут глазами, и прятать его нечем. */
.pay-grp-bad .pay-grp-h b, .pay-grp-bad .pay-grp-h em{color:var(--r)}

/* ── Свёрнутая секция вкладки (таск 69, второй заход) ────────────────────────────────────────
   Уровнем выше групп графика (.pay-grp): под шапкой прячется целый раздел. Шапка НЕСЁТ ИТОГ —
   «13 ч · продажа 4 · подготовка 9», «2 человека без строки в смете»: свёрнутый блок без числа
   человек раскрывает каждый раз, и сворачивание превращается в лишний клик. */
.fold{margin-top:10px}
.fold-h{display:flex;align-items:baseline;gap:9px;width:100%;padding:9px 14px;
  border:1px solid var(--line);background:var(--film-1);cursor:pointer;
  font:inherit;color:inherit;text-align:left}
.fold-h:hover{color:var(--acc)}
.fold-h b{font-size:13.5px;font-weight:600}
.fold-h em{font-style:normal;font-size:12.5px;color:var(--ink-2);margin-left:auto;
  font-variant-numeric:tabular-nums}
.fold-h .fold-chev{flex:0 0 auto;align-self:center;transition:transform .12s}
.fold.on .fold-h .fold-chev{transform:rotate(180deg)}
.fold.on .fold-h{border-bottom:0}
/* Числа вкладки «Финансы» ниже обычных: шесть колонок заработка и четыре сводки сметы стоят
   на одном экране с графиком и полями, и каждый лишний пиксель отступа стоит строки. */
.figs-tight .fig{padding:8px 14px}
.figs-tight .fig b{font-size:17px}
.figs-tight .fig span{margin-top:3px}
/* Вкладка «Финансы» плотнее прочих намеренно: четыре раздела, четырнадцать чисел, график и
   поля обязаны помещаться в окно события целиком — правило владельца «содержимое подгоняется
   под окно, а не окно листается под содержимое». Отступы здесь и есть та разница между
   «влезло» и «портянка»: на четырёх разделах они стоят полутора сотен пикселей. */
.fin .sheet{padding:9px 14px}
.fin .sheet-h{margin-bottom:8px}
/* 6 px, а не 8 (доводка таска 72б): свёрнутых разделов на вкладке стало шесть, и на
   шести промежутках эти два пикселя и есть разница между «влезло» (557) и «прокрутка»
   (569 при окне 566). Жать дальше нечем — шрифт ради вмещения не уменьшаем. */
.fin .sheet + .sheet,.fin .fold,.fin .sheet + .fold,.fin .fold + .sheet{margin-top:6px}
.fin > :first-child{margin-top:0}
/* ── Координация: программа дня крупными строками (таск 90) ──────────────────
   Отличается от обычных `.row` не украшением, а назначением: эти строки читают с телефона,
   стоя на площадке, и жмут пальцем на ходу. Отсюда высота цели нажатия 34 px (палец, а не
   курсор), время моноширинными цифрами (колонка времени должна читаться столбиком, а не
   прыгать на «9:00» после «11:00») и заметное перечёркивание закрытого: главный вопрос
   на площадке — «что ещё не сделано», и ответ на него должен быть виден боковым зрением. */
.coord{display:flex;flex-direction:column}
.coord-row{display:flex;align-items:flex-start;gap:11px;padding:11px 2px;
  border-top:1px solid var(--line)}
.coord-row:first-child{border-top:0}
.coord-part{padding:14px 2px 6px;font-size:12px;font-weight:600;letter-spacing:.06em;
  color:var(--ink-3);text-transform:uppercase}
.coord-tick{width:34px;height:34px;flex:0 0 34px;border-radius:10px;border:1px solid var(--line);
  background:var(--film-1);color:var(--ink);font-size:16px;line-height:1;cursor:pointer;
  display:flex;align-items:center;justify-content:center}
.coord-tick-on{background:var(--acc);border-color:var(--acc);color:var(--acc-ink)}
.coord-at{flex:0 0 auto;min-width:58px;padding-top:8px;font-size:14px;font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--ink-2)}
.coord-main{flex:1 1 auto;min-width:0;padding-top:6px;display:flex;flex-direction:column;gap:2px}
.coord-main b{font-size:15px;font-weight:600;letter-spacing:-.01em}
.coord-main span{font-size:13px;color:var(--ink-3)}
/* Своя подробность («снять декор до еды») — заметнее общего комментария: общий отвечает
   «что происходит», эта — «что при этом делаешь ты», и на площадке нужна вторая. */
.coord-main em{font-style:normal;font-size:13px;color:var(--ink)}
.coord-row-done .coord-main b{text-decoration:line-through;color:var(--ink-3)}
.coord-row > .tag{align-self:center;flex:0 0 auto}

/* ── Своё поле даты (таск 62) ────────────────────────────────────────────────
   Три части в одном поле плюс кнопка выбора; на телефоне поле остаётся нативным и сюда
   не попадает вовсе. Ширина по содержимому: «ДД.ММ.ГГГГ» — короткая строка, и поле во всю
   ширину формы читалось бы как поле для текста. */
.dfield{position:relative;display:inline-flex;align-items:center;gap:6px}
/* Поле с ISO скрыто атрибутом hidden — во flex-строке он сам по себе не прячет. */
.dfield input[hidden]{display:none}
/* Ширина: одиннадцать знаков ПЛЮС свои поля и рамка. `box-sizing: border-box` считает 11ch
   вместе с ними, и содержимому оставалось 52 px при нужных 68 — набранная дата обрезалась
   («12.10.202») во всех местах сразу. Замер: scrollWidth 94 против clientWidth 78. */
.dfield .df-txt{padding:10px 13px;border-radius:var(--rad-s);border:1px solid var(--stroke);
  background:var(--in);color:var(--ink);font:inherit;width:calc(11ch + 30px);
  letter-spacing:.02em;font-variant-numeric:tabular-nums}
/* В паре «с — по» поля не сжимаются: при нехватке ширины блок переносит второе поле строкой
   ниже (`flex-wrap` у .pf-dates), а не съедает у обоих по десятку пикселей. */
.pf-dates .dfield,.pf-dates .df-txt{flex:0 0 auto}
.dfield .df-txt:focus{outline:none;border-color:var(--acc)}
/* Ошибка границы — красной рамкой И словами рядом: одна рамка не говорит, ЧТО не так. */
.dfield .df-txt.df-bad{border-color:var(--r)}
.dfield .df-err{font-style:normal;font-size:11.5px;color:var(--r)}
.dfield .df-open{display:inline-flex;align-items:center;justify-content:center;
  width:34px;height:34px;flex:0 0 auto;border:1px solid var(--stroke);border-radius:var(--rad-s);
  background:var(--in);color:var(--on-dim);cursor:pointer}
.dfield .df-open:hover{color:var(--ink);border-color:var(--acc)}

/* Попап выбора. Position fixed — узел живёт в <body>, а не внутри формы: внутри его обрезала бы
   прокрутка окна события (`.pj-body` с overflow:hidden). */
.df-pop{position:fixed;z-index:80;background:var(--pop);border:1px solid var(--stroke);
  border-radius:var(--rad-m);box-shadow:0 12px 32px rgba(0,0,0,.28);padding:6px}
.df-cols{display:flex;gap:4px}
/* Высота фиксированная, а не по содержимому: колонка года в 70 строк вытянула бы попап за экран.
   flex:1 1 0 — не auto: в flex-строке базис по содержимому съедается соседями (правило CLAUDE.md). */
.df-col{flex:1 1 0;min-width:64px;height:210px;overflow-y:auto;scrollbar-width:thin}
.df-col::-webkit-scrollbar{width:6px}
.df-col::-webkit-scrollbar-thumb{background:var(--stroke);border-radius:3px}
.df-i{display:block;width:100%;text-align:left;padding:5px 8px;border:0;background:none;
  color:var(--ink);font:inherit;font-size:13px;border-radius:var(--rad-s);cursor:pointer;
  font-variant-numeric:tabular-nums}
.df-i:hover{background:var(--in)}
.df-i.on{background:var(--acc);color:var(--on-acc,#fff)}
.df-quick{display:flex;gap:6px;padding:6px 2px 2px;border-top:1px solid var(--stroke);margin-top:6px}
.df-quick .btn{flex:1 1 0;justify-content:center;padding:6px 8px}

/* Период одним блоком: подпись и переключатель «Одна дата · Период» в одной строке, поля —
   под ними. В режиме одной даты второе поле скрыто целиком, и блок занимает столько же
   места, сколько занимала одна дата. */
.pfield .pf-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.pf-modes{display:inline-flex;gap:4px;flex:0 0 auto}
.pf-dates{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.pf-to{display:inline-flex;align-items:center;gap:8px}
.pf-to[hidden]{display:none}
.pf-dash{font-style:normal;font-size:11.5px;color:var(--on-dim)}
