/* ПроЦифры - светлая тема в духе Ресториума: пепельно-синий фон, белые карточки,
   индиго-акцент. Гротеск жирный везде, сериф - только вход и хиро Ассистента. */
* { box-sizing: border-box; margin: 0; }
img { height: auto; max-width: 100%; }
:root {
  --bg: #eef1f7;
  --card: #ffffff;
  --line: #e3e7f1;
  --text: #1d2436;
  --text-2: #4a536b;
  --muted: #6b7488;
  --placeholder: #868ea2;
  --accent: #4f6bf5;
  --accent-ink: #3d55d6;
  --accent-soft: #e9edfe;
  --field: #f7f8fc;
  --radius: 16px;
  color-scheme: light;
  --shadow: 0 1px 2px rgba(29, 36, 54, .04), 0 8px 24px rgba(29, 36, 54, .06);
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
  --space-5: 24px; --space-6: 32px;
  --radius-sm: 10px;
  --up: #1e8e4e;
  --down: #c0392b;
  /* Скрим спотлайт-тура (KT: access-funnel-03) - отдельный токен на тему, не одно rgba
     на обе: на белых карточках светлой темы rgba(10,12,20,.62) визуально не считывалась
     как затемнение (uxui-verdict.md §1а, Никита "всё кроме элемента затемняется" -
     блокер), для тёмной темы прежний тон был достаточен. */
  --tour-dim: rgba(15, 18, 30, .82);
}
/* Тёмная тема - переключаемая, не замена дефолта (Никита 19.08.2026: "возможность включить").
   Значения тёмного набора выведены из тех же ролей, что светлые - см. app.js applyTheme
   и toggle в сайдбаре/"Ещё". Первый визит всегда светлый, выбор живёт в localStorage. */
:root[data-theme="dark"] {
  --bg: #14161c;
  --card: #1c1f28;
  --line: #2a2e3a;
  --text: #e7e9f0;
  --text-2: #b9c0d2;
  --muted: #8b93a8;
  --placeholder: #767e94;
  --accent: #5b74ff;
  --accent-ink: #8fa0ff;
  --accent-soft: #232a4a;
  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 8px 24px rgba(0, 0, 0, .35);
  --up: #2fbf62;
  --down: #e5534b;
  --tour-dim: rgba(4, 5, 10, .78);
  --field: #20242f;
  /* Нативное, куда CSS не достаёт: календарь input[type=month], скроллбары, автозаполнение,
     стрелки у number. Без этой строки они остаются светлыми на тёмном. */
  color-scheme: dark;
}
/* Места без переменных - нашлись только чтением файла целиком, глазами такие не ищутся. */
:root[data-theme="dark"] #sidebar { background: #191c24; }
:root[data-theme="dark"] #sidenav button:hover { background: rgba(255, 255, 255, .05); }
:root[data-theme="dark"] .abc.a { background: rgba(47, 191, 98, .15); }
:root[data-theme="dark"] .abc.c { background: rgba(255, 255, 255, .06); color: #c9b896; }
:root[data-theme="dark"] .error { color: var(--down); }
html, body { height: 100%; }
body {
  font: 15px/1.5 -apple-system, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  background: var(--bg); color: var(--text);
  overflow-x: hidden; /* широкие таблицы скроллятся в карточках, не страницей */
}
.hidden { display: none !important; }
.muted { color: var(--muted); }
.error { color: #d64545; min-height: 1.2em; }
/* Поле выглядит одинаково везде. Раньше фон был прописан только у .form-field и
   .login-card, поэтому любое поле вне их - панель «О заведении», выбор месяца в целях -
   оставалось голым браузерным контролом: белый прямоугольник посреди тёмной темы. */
input, textarea, select {
  font: inherit; color: var(--text); background: var(--field);
  border: 1px solid var(--line); border-radius: 12px; padding: 11px 13px;
}
input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }
/* Нативную стрелку select не покрасить - глушим её и рисуем свой шеврон тем же приёмом,
   что календарь у выбора периода (Никита 01.09.2026 про селект роли в модалке приглашения). */
select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234f6bf5' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center; background-size: 15px;
}
/* Нативные стрелки input[type=number] наезжают на текст в узких полях (Никита 01.09.2026 про
   «Брутто/Нетто» в своих ТТК) и остаются системным контролом на тёмной теме - в «Целях» видны
   те же две стрелки. Числа везде набирают с клавиатуры, шаг стрелками нигде не задуман. */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.team-me { margin: 2px 0 12px; font-size: 13px; }
.team-me b { font-weight: 600; }
input::placeholder, textarea::placeholder { color: var(--placeholder); opacity: 1; }
/* Вводное описание карточки (вход, регистрация, «демо закончилось», «доступ истёк») -
   ступень между заголовком и подписями полей, а не тот же muted, что у подписей. */
.card-lead { color: var(--text-2); }
.serif {
  font-family: -apple-system, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  font-weight: 800; letter-spacing: -.01em;
}
.serif em { font-style: normal; color: var(--accent); }
/* Хиро Ассистента - единственное место, где остаётся серифный бренд-шрифт.
   Вход теперь несёт фирменный знак ПроЦифры и набран тем же гротеском, что и остальной UI. */
#chat-hero h2.serif {
  font-family: "Iowan Old Style", "Palatino", Georgia, serif; font-weight: 600;
}
#chat-hero h2.serif em { font-style: italic; }
.card {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.crumb {
  font-size: 11px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 2px;
}
/* KT access-funnel-04: голая <button> в браузере получает UA-цвет buttontext (тёмный)
   вместо цвета темы, даже когда предок задаёт --text - в тёмной теме заголовки
   .fn-card/.tpl (b) читались как чёрный на тёмном. color: inherit чинит корень для
   ВСЕХ карточных кнопок разом; .primary/.ghost и т.п. переопределяют цвет своим
   классом (выше по специфичности), regression не даёт. */
button { font: inherit; cursor: pointer; color: inherit; }
.primary {
  background: var(--accent); border: 0; border-radius: 12px;
  padding: 12px 20px; color: #fff; font-weight: 600;
}
.primary:hover { background: var(--accent-ink); }
.ghost {
  background: transparent; border: 1px solid var(--line); color: var(--text);
  border-radius: 10px; padding: 8px 12px; font-size: 14px;
}

/* ---------- вход ---------- */
#login-view, #invite-view, #reg-view { display: flex; align-items: center; justify-content: center; min-height: 100dvh; padding: 24px; }
.login-card { width: 100%; max-width: 380px; display: flex; flex-direction: column; gap: 12px; text-align: center; padding: 36px 28px; }
.login-card h1, .login-card .brand-h1 { font-size: 34px; }
/* Вордмарк ПроЦифры на карточках входа (24.08.2026): инлайн-SVG, чёрные пути через
   currentColor наследуют цвет темы; ширина - чтобы «[цифры]» читались и на 375. */
.brand-wordmark { width: 212px; margin: 6px auto 2px; color: var(--text); }
.brand-wordmark svg { display: block; width: 100%; height: auto; }

/* Регистрация внешнего ресторана по ссылке (/reg/<token>): та же карточка входа, с
   повторяемыми блоками "заведение" - несколько заведений (кассы) заводятся сразу. */
.reg-card { text-align: left; }
.reg-card h1, .reg-card > p:first-of-type { text-align: center; }
.reg-ws-block { display: flex; flex-direction: column; gap: 10px; padding-top: 12px; border-top: 1px solid var(--line); }
.reg-ws-block:first-of-type { border-top: none; padding-top: 0; }
.reg-ws-head { display: flex; align-items: center; justify-content: space-between; }
.reg-ws-remove { padding: 3px 10px; font-size: 12.5px; }
.reg-hint { font-size: 12.5px; text-align: left; }

/* ---------- бренд-строка в приложении (сайдбар/мобильная шапка) ---------- */
/* Знак слева на две строки, название сверху, подпись агентства под ним. В одну строку
   всё это в 264px сайдбара не влезало - вордмарк Креатека обрезался правым краем. */
/* Связка бренда: марка продукта и название, одной строкой по центру.
   Марка «Креатек» отсюда убрана - вордмарк шириной 200px сжимался до 11px высоты
   и приглушался до 60%, штрихи уходили в субпиксель, а мятный спорил с индиго
   (Никита 18.08.2026: «Вот это максимально хуево выглядит»). Атрибуция агентства
   переехала вниз сайдбара, где ей хватает места быть читаемой. */
.app-brand {
  display: flex; align-items: center; gap: 10px; padding: 2px 6px 0;
  background: none; border: none; font: inherit; cursor: pointer; border-radius: 8px;
}
.app-brand:hover .brand-name { color: var(--accent); }
.app-brand:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.brand-mark { width: 30px; height: 30px; border-radius: 9px; flex-shrink: 0; }
.brand-name { font-size: 17px; font-weight: 800; color: var(--text); letter-spacing: -.015em; transition: color .15s; }
.brand-name em { font-style: normal; color: var(--accent); }
.made-by {
  display: flex; align-items: baseline; gap: 6px; margin-top: 12px; padding-left: 8px;
  font-size: 10px; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); text-decoration: none; width: fit-content;
}
/* baseline даёт логотипу "повиснуть" от нижней линии текста - явно указываем, где эта
   линия для картинки (её собственный baseline = нижний край) через vertical-align. */
.made-by img { vertical-align: baseline; position: relative; top: 1px; }
/* inline-flex, не flex: блочная кнопка без карты-ограничителя растягивалась на весь
   контейнер (третий возврат Никиты по этому элементу, 28.08) - капсула по содержимому */
.theme-toggle { display: inline-flex; width: auto; align-items: center; gap: 8px;
  /* родитель #tab-settings - flex-колонка со stretch, а display:flex кнопке ставит более
     жёсткий селектор; align-self со !important зажимает капсулу по содержимому при любом
     display (третий возврат Никиты по этой плашке, 28.08) */
  align-self: flex-start !important; }
.theme-toggle .ico-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .ico-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .ico-moon { display: block; }
.made-by:hover { color: var(--text); }
.made-by:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
.made-by img { height: 15px; width: auto; }
.brand-mark-m { width: 24px; height: 24px; border-radius: 7px; flex-shrink: 0; }
.login-card input { padding: 13px 14px; font-size: 16px; } /* 16px - иначе iOS зумит форму входа */
.login-card input.input-err { border-color: var(--down); }
.forgot-line { font-size: 12.5px; margin-top: -2px; }
.auth-switch { font-size: 13.5px; }
.auth-switch .link-btn, .locked-exit .link-btn { background: none; border: 0; padding: 0; font: inherit; color: var(--accent-ink); font-weight: 600; }

/* Google-вход (26.08.2026) - показывается только когда сервер отдаёт ключи. */
.auth-divider { display: flex; align-items: center; gap: 10px; color: var(--muted); font-size: 12.5px; }
.auth-divider::before, .auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.btn-google {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  padding: 12px 14px; border-radius: 12px; border: 1px solid var(--line);
  background: #fff; color: #3c4043; font-size: 15px; font-weight: 500;
  text-decoration: none; cursor: pointer;
}
.btn-google:hover { background: #f7f8fc; }
:root[data-theme="dark"] .btn-google { background: #232838; color: var(--text); }
:root[data-theme="dark"] .btn-google:hover { background: #2a3044; }

/* ---------- каркас ---------- */
#app-view { display: flex; height: 100dvh; }
#sidebar {
  width: 264px; flex-shrink: 0; display: flex; flex-direction: column;
  background: #f7f8fb; border-right: 1px solid var(--line); padding: 16px 12px;
  gap: 16px;
}
.ws-card {
  display: flex; align-items: center; gap: 10px; padding: 10px;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); cursor: pointer; position: relative;
}
.ws-card:hover { border-color: var(--accent); }
.ws-meta { flex: 1; min-width: 0; }
.ws-cap {
  font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted);
}
.ws-chev { color: var(--muted); font-size: 22px; line-height: 1; }
.side-sep {
  margin: 14px 12px 4px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.fc-good { color: var(--up); font-weight: 700; }
.ws-avatar {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.ws-avatar img { width: 100%; height: 100%; display: block; }
.ws-name {
  font-size: 16px; font-weight: 700; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ws-menu {
  display: none; position: absolute; top: calc(100% + 8px); left: 0; min-width: 100%;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 12px 34px rgba(29, 36, 54, .16); padding: 6px; z-index: 60;
}
.ws-card.open .ws-menu { display: block; }
.ws-card.open .ws-chev { transform: rotate(180deg); }
.ws-chev { transition: transform .15s; }
.ws-item {
  display: flex; align-items: center; gap: 10px; width: 100%;
  background: none; border: 0; border-radius: 10px; padding: 9px 10px;
  font-size: 15px; font-weight: 600; color: var(--text); text-align: left;
}
.ws-item:hover { background: var(--accent-soft); }
.ws-item img { width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0; }
.ws-item .check {
  margin-left: auto; width: 16px; height: 16px; flex-shrink: 0;
  fill: none; stroke: var(--accent-ink); stroke-width: 2.4;
  stroke-linecap: round; stroke-linejoin: round;
}
.ws-item.active { color: var(--accent-ink); }
#sidenav { display: flex; flex-direction: column; gap: 2px; }
#sidenav button {
  display: flex; align-items: center; gap: 10px; text-align: left;
  background: none; border: 0; border-radius: 12px; padding: 11px 12px;
  color: var(--text); font-size: 15px; font-weight: 500;
}
.ico {
  width: 19px; height: 19px; flex-shrink: 0;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
#sidenav button .ico { color: var(--muted); }
#sidenav button:hover { background: #eef0f6; }
#sidenav button.active { background: var(--accent-soft); color: var(--accent-ink); }
#sidenav button.active .ico { color: var(--accent-ink); }
.side-footer { margin-top: auto; display: flex; flex-direction: column; gap: 8px; padding: 8px 6px; font-size: 13px; }

#content { flex: 1; display: flex; flex-direction: column; min-width: 0; }
#mobile-header {
  display: none; gap: 8px; align-items: center; padding: 10px 14px;
  padding-top: calc(10px + env(safe-area-inset-top));
  background: var(--card); border-bottom: 1px solid var(--line);
}
main { flex: 1; overflow: hidden; display: flex; }
.tab { flex: 1; display: flex; flex-direction: column; overflow-y: auto; padding: 22px 22px 28px; }
.tab > * { flex-shrink: 0; } /* дети скролл-колонки не сжимаются, скроллим а не плющим */
/* Настройки - блоки идут подряд карточками, без ритма они слипаются встык (замер 19.08.2026:
   зазоры 0,0,0 и карточки читались как наложенные). .tab уже flex-колонка, поэтому хватает gap. */
#tab-settings { gap: 14px; }
/* Таблица команды шире мобильного экрана (781px при 375) - скроллим её внутри карточки, а не
   разъезжаемся всем разделом. Та же грабля, что у ABC/P&L в аналитике, см. specs/app.md. */
#team-body { overflow-x: auto; }
.page-head { margin-bottom: 14px; }
.page-head h2 { font-size: 26px; }
.empty-card { padding: 40px 32px; display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.empty-card .empty-ico { width: 40px; height: 40px; color: var(--muted); margin-bottom: 4px; }
.empty-card h3 { font-size: 21px; margin-bottom: 0; }
.empty-card p { max-width: 380px; }

/* ---------- чат ---------- */
/* Диалоги - выдвижная панель слева от переписки, не отдельный экран (Nikita: "как в Клоде",
   переписка должна оставаться видна). #tab-chat - flex-row из панели и #chat-main. */
#tab-chat { overflow: hidden; padding: 0; flex-direction: row; }
#chat-main { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; }
#dialogs-panel {
  width: 0; flex-shrink: 0; overflow: hidden; background: var(--card);
  border-right: 1px solid var(--line); display: flex; flex-direction: column;
  transition: width .18s ease;
}
#dialogs-panel.open { width: 280px; }
.dialogs-panel-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 14px 10px; white-space: nowrap;
}
.dialogs-panel-head h2 { font-size: 15px; }
#dialogs-panel .list { padding: 0 10px 10px; gap: 6px; overflow-y: auto; }
/* Обрезка длинного заголовка живёт на самой строке, а не на флекс-контейнере пункта:
   на контейнере она не работала и выдавливала дату за нижний край карточки. */
#dialogs-panel .list li { gap: 3px; padding: 9px 11px; }
#dialogs-panel .list li .dlg-title {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: 14px; line-height: 1.35;
}
#dialogs-panel .list li small { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
#dialogs-panel .list li.active { border-color: var(--accent); background: var(--accent-soft); }
#chat-tools {
  display: flex; gap: 8px; justify-content: space-between;
  padding: 12px 20px 0; max-width: 800px; margin: 0 auto 4px; width: 100%;
}
/* padding-bottom 36px >= 28px градиента #chat-form::before: последнее сообщение, докрученное
   до конца, стоит выше затемнения, а не под ним (Никита 04.09.2026: «блюр налезает на ответ»). */
#chat-scroll { flex: 1; overflow-y: auto; padding: 24px 20px 36px; }
#chat-hero { max-width: 620px; margin: 0 auto; padding-top: 24px; text-align: center; }
.hero-mark {
  width: 64px; height: 64px; margin: 0 auto 18px; border-radius: 50%;
  display: block; box-shadow: 0 10px 26px rgba(12, 42, 36, .25);
}
#chat-hero h2 { font-size: 34px; margin-bottom: 10px; }
#chat-hero p { max-width: 480px; margin: 0 auto; }
#fn-cards { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 10px; margin-top: 22px; text-align: left; }
.fn-card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px; display: flex; flex-direction: column; gap: 3px; box-shadow: var(--shadow);
}
.fn-card:hover { border-color: var(--accent); }
.fn-card b { font-size: 15px; }
.fn-card span { font-size: 13px; color: var(--muted); }
#chat-log { max-width: 800px; margin: 0 auto; display: flex; flex-direction: column; gap: 10px; }
.msg { max-width: 86%; padding: 11px 15px; border-radius: var(--radius); white-space: pre-wrap; overflow-wrap: break-word; }
.msg.user { align-self: flex-end; background: var(--accent); color: #fff; border-bottom-right-radius: 6px; }
.msg.assistant { align-self: flex-start; background: var(--card); border: 1px solid var(--line); box-shadow: var(--shadow); border-bottom-left-radius: 6px; white-space: normal; max-width: 92%; }
/* Ответ ассистента приходит в Markdown и рендерится в HTML (app.js mdToHtml) - .msg.assistant
   больше не голый текст, поэтому свои отступы вместо pre-wrap на переносах строк. */
.msg.assistant p { margin: 0 0 8px; }
.msg.assistant p:last-child { margin-bottom: 0; }
.msg.assistant h1, .msg.assistant h2, .msg.assistant h3, .msg.assistant h4 { margin: 12px 0 6px; line-height: 1.3; }
.msg.assistant h1:first-child, .msg.assistant h2:first-child, .msg.assistant h3:first-child, .msg.assistant h4:first-child { margin-top: 0; }
.msg.assistant ul, .msg.assistant ol { margin: 0 0 8px; padding-left: 22px; }
.msg.assistant li { margin: 2px 0; }
.msg.assistant code { background: var(--bg); border-radius: 4px; padding: 1px 5px; font-size: .92em; }
.msg.assistant table { border-collapse: collapse; width: 100%; margin: 6px 0 10px; font-size: 13px; }
.msg.assistant th, .msg.assistant td { border: 1px solid var(--line); padding: 5px 8px; text-align: left; }
.msg.assistant th { background: var(--bg); }
/* Честный индикатор ожидания: раньше это был только мигающий курсор после ПУСТОГО
   текста - на тяжёлых запросах (185 gross с до первого байта, живой замер на проде)
   пустая строка с мигающим курсором читалась как зависание, приёмка так и завела дефект.
   Три прыгающих точки (видимое движение) + счётчик секунд (бесспорное доказательство,
   что процесс жив, не просто зациклленная CSS-анимация) - переживает минуты ожидания,
   заменяется реальным текстом как только придёт первый байт (см. app.js startThinking). */
.msg.typing { display: flex; flex-direction: column; gap: 6px; }
/* .chat-heartbeat - курсивные статусы инструментов (app.py _tool_heartbeat), рендерятся
   сверху и не трогают .thinking-card под ними, пока идёт длинная цепочка вызовов. */
.chat-heartbeat:empty { display: none; }
.chat-heartbeat { color: var(--muted); }
.chat-heartbeat p { margin: 0; }
.thinking-card { display: flex; align-items: center; gap: 8px; }
.typing-label { font-size: 13px; color: var(--muted); }
.typing-dots { display: inline-flex; gap: 3px; }
.typing-dots span {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  animation: typing-bounce 1.1s infinite ease-in-out;
}
.typing-dots span:nth-child(2) { animation-delay: .15s; }
.typing-dots span:nth-child(3) { animation-delay: .3s; }
.primary .typing-dots { vertical-align: middle; }
.primary .typing-dots span { background: currentColor; }  /* точки на кнопке - цветом текста кнопки */
@keyframes typing-bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .4; } 30% { transform: translateY(-4px); opacity: 1; } }
.typing-elapsed { font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
#chat-form {
  position: relative; display: flex; gap: 8px; padding: 10px 20px calc(14px + env(safe-area-inset-bottom));
  max-width: 800px; margin: 0 auto; width: 100%;
}
/* Мягкое затемнение над строкой ввода - последнее сообщение не обрывается жёсткой
   границей формы (Никита 19.08.2026: "как у тебя"). bottom:100% ставит градиент
   прямо над формой, визуально перекрывая нижний край #chat-scroll. */
#chat-form::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 28px;
  background: linear-gradient(to bottom, transparent, var(--bg) 80%);
  pointer-events: none;
}
#chat-input {
  flex: 1; resize: none; background: var(--card); border: 1px solid var(--line);
  border-radius: 18px; padding: 13px 16px; font-size: 16px; color: var(--text);
  max-height: 140px; box-shadow: var(--shadow);
}
#chat-input:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }
#chat-send { border-radius: 50%; width: 48px; height: 48px; padding: 0; font-size: 17px; align-self: flex-end; }
#chat-send:disabled { opacity: .5; }
/* Скрепка: тот же круг, что у отправки, но вторичный - файл прикладывают редко. */
#chat-attach {
  border-radius: 50%; width: 48px; height: 48px; padding: 0; align-self: flex-end;
  display: flex; align-items: center; justify-content: center; color: var(--muted);
}
#chat-attach:hover { color: var(--accent); }
#chat-attach-bar {
  max-width: 800px; margin: 0 auto; width: 100%; padding: 0 20px 6px;
  display: flex; flex-wrap: wrap; gap: 6px 8px; font-size: 13px;
}
#chat-attach-bar .chip-file {
  display: inline-flex; align-items: center; gap: 8px; max-width: 100%;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 6px 8px 6px 12px; color: var(--text);
}
#chat-attach-bar .chip-file i { color: var(--muted); font-style: normal; }
#chat-attach-bar .chip-file.err { color: var(--down); }
#chat-attach-bar .chip-file button {
  background: none; border: 0; padding: 0 4px; color: var(--muted); cursor: pointer; font-size: 14px;
}

/* ---------- аналитика ---------- */
#subtabs, #kitchen-subtabs, #report-subtabs {
  display: flex; gap: 4px; background: var(--card); border: 1px solid var(--line);
  border-radius: 12px; padding: 4px; margin-bottom: 12px; width: fit-content; max-width: 100%;
  overflow-x: auto;
}
#kitchen-search {
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 11px 14px; font-size: 15px; color: var(--text); margin-bottom: 12px; width: 100%; max-width: 420px;
}
#kitchen-search:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }
.prod-count { margin: 0 0 10px 2px; font-size: 13px; }
.prod-row { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.prod-row small { color: var(--muted); }
.prod-row .chev { color: var(--muted); }
.chart-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.kbju-btn { margin-left: auto; padding: 6px 12px; font-size: 13px; white-space: nowrap; }
/* Плашки карточки позиции (техкарта, КБЖУ, калькуляция) слипались - у .card
   своего вертикального отступа нет, калькуляция вдобавок живёт в своём холдере. */
#kitchen-body .card { margin-bottom: 14px; }
.chart-table { width: 100%; border-collapse: collapse; font-size: 14px; }
.chart-table th, .chart-table td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line); }
.chart-table th { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 600; }
.chart-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.chart-table tr.linked { cursor: pointer; }
.chart-table tr.linked:hover td { background: var(--accent-soft); }
/* Раскрытие категорий ОПиУ (Никита 01.09.2026): родительская строка кликабельна,
   стрелка поворачивается, блюда - подстроки с отступом и приглушённым именем. */
.chart-table tr.opu-parent { cursor: pointer; }
.chart-table tr.opu-parent:hover td { background: var(--accent-soft); }
.opu-arrow { display: inline-block; width: 14px; color: var(--muted); transition: transform .15s; }
.opu-arrow::before { content: "\25B8"; }
tr.opu-parent.open .opu-arrow { transform: rotate(90deg); }
.chart-table td.opu-sub-name { padding-left: 32px; color: var(--muted); }
.chart-table th[data-col] { cursor: pointer; user-select: none; white-space: nowrap; }
.chart-table th[data-col]:hover { color: var(--text); }
.chart-table th.sort-asc::after { content: " \25B2"; }
.chart-table th.sort-desc::after { content: " \25BC"; }

.sec-title { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; margin-bottom: 10px; }
.info-btn {
  border: 1px solid var(--line); background: var(--card); color: var(--muted);
  width: 20px; height: 20px; border-radius: 50%; font-size: 12px; font-weight: 700;
  line-height: 1; padding: 0; flex-shrink: 0;
}
.info-btn:hover { color: var(--accent); border-color: var(--accent); }
.back-btn { margin-bottom: 12px; }
#tpl-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; margin-bottom: 14px; }
.tpl {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; display: flex; flex-direction: column; gap: 2px; text-align: left;
  box-shadow: var(--shadow);
}
.tpl:hover { border-color: var(--accent); }
.tpl b { font-size: 14px; }
.tpl span { font-size: 12px; color: var(--muted); }
.tpl:disabled { opacity: .6; }
.report-tag {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--accent-ink); background: var(--accent-soft);
  border-radius: 6px; padding: 2px 8px; margin-right: 8px;
}
.abc {
  font-weight: 700; letter-spacing: .15em; font-size: 13px; color: var(--accent-ink);
  background: var(--accent-soft); border-radius: 6px; padding: 2px 6px;
}
/* Статусный красный только для FC выше нормы, всегда с самим числом рядом */
.fc-high { color: var(--down); font-weight: 700; }
/* Отчёт рендерится через mdToHtml (заголовки/таблицы/списки), не сырым текстом -
   моноширинный pre-wrap отсюда убран (Никита 28.08.2026: "форматирование - пиздец").
   .kb-content уже даёт прозу+таблицы вменяемо, .report-body добавляет только отступы. */
.report-body { font-size: 14px; line-height: 1.6; }
.report-body h1, .report-body h2, .report-body h3, .report-body h4 { margin: 18px 0 8px; }
.report-body h1:first-child, .report-body h2:first-child { margin-top: 0; }
.report-body p, .report-body ul, .report-body ol { margin: 0 0 10px; }
.kb-content { font-size: 14px; line-height: 1.55; }
.kb-content .kb-table-wrap { overflow-x: auto; margin: 4px 0 14px; }
.kb-content table { width: max-content; min-width: 100%; }
.calc-totals { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 14px; font-size: 13px; color: var(--muted); }
.calc-totals b { color: var(--text); font-size: 14px; }
.subtab {
  border: 0; background: none; border-radius: 9px; padding: 8px 14px;
  color: var(--muted); font-weight: 500; white-space: nowrap;
}
.subtab.active { background: var(--accent-soft); color: var(--accent-ink); font-weight: 600; }
.subtab:disabled { cursor: default; opacity: .55; }
#period-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; align-items: flex-start; }
.chip {
  background: var(--card); border: 1px solid var(--line); border-radius: 999px;
  padding: 7px 14px; font-size: 13px; color: var(--text);
}
.chip.active { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; }
.chip.ok {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent-soft); color: var(--accent-ink);
  border-radius: 999px; padding: 5px 12px; font-size: 13px; font-weight: 600;
}

/* ---------- Настройки: единый визуальный язык карточек (§4.1 ux-audit,
   access-funnel-04 settings-uxui-spec.md) ---------- */
.settings-card { padding: var(--space-5); }
/* Карточки одной вкладки лежали впритык (Никита 06.09.2026) */
.stab-body > .card + .card { margin-top: var(--space-4); }
/* Раздел читается одной колонкой: карточки одной ширины, ряды не растягиваются на весь
   экран (Никита, 29.08.2026 - четвёртый заход по дизайну раздела; до этого "Аккаунт" был
   420px рядом с карточками во всю ширину, и раздел выглядел собранным из кусков). */
#tab-settings > * { max-width: 880px; }
.settings-head {
  font-size: 18px; font-weight: 700; color: var(--text);
  margin: 28px 0 10px;
}
.settings-head:first-child { margin-top: 0; }
.settings-head-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: 28px 0 10px;
}
.settings-head-row .settings-head { margin: 0; }
.settings-sub { font-size: 13px; color: var(--muted); margin: -6px 0 10px; }
/* Подзаголовок ВНУТРИ карточки (например "Смена пароля"): обычный регистр - капслок уже
   занят подписями полей, два капслочных уровня подряд читались как одна каша. */
.settings-subhead { font-size: 14px; font-weight: 600; color: var(--text); margin-top: var(--space-5); }
.settings-note {
  font-size: 12px; font-weight: 600; letter-spacing: .02em; text-transform: uppercase;
  color: var(--muted); margin-top: 10px;
}
.settings-row {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--card);
}
.settings-row + .settings-row { margin-top: 8px; }
.settings-row:hover { border-color: var(--accent); }
/* Ряд заведения ("Мои заведения") - сетка вместо инлайнового space-between, чтобы
   название/статус и кнопки не плавали по ширине карточки. */
.settings-row-ws {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--space-3);
}
/* Строка статуса кассы без вида кликабельной плашки - точка-маркер, не капсула
   (settings-uxui-spec.md §2). */
.status-text { font-size: 13px; font-weight: 600; }
/* Ряд участника команды - именованная сетка на 3 колонки (имя/роль/кнопки), дата вступления
   скрыта до миграции memberships.created_at (settings-ia.md, п.3 табл. №9). */
.team-row {
  display: grid;
  /* Хвост фиксированной ширины, не auto: каждый ряд - свой грид, и auto-колонка с двумя
     кнопками против «Это вы» давала рядам разную сетку - роль плыла по вертикали
     (Никита, скрины 01.09.2026). 220px >= самой широкой пары кнопок; изменится текст
     кнопок - перемерить. */
  grid-template-columns: minmax(160px, 2fr) minmax(90px, 1fr) minmax(220px, auto);
  align-items: center; gap: var(--space-3);
}
@media (max-width: 1023px) {
  #team-body .team-row, #my-ws-body .settings-row-ws {
    grid-template-columns: 1fr; justify-items: start; gap: 4px;
  }
}
/* Блок "Аккаунт" - аватар-плейсхолдер + имя/почта вместо голого muted-текста. */
.account-id { display: flex; align-items: center; gap: var(--space-3); }
.avatar-circle {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  background: var(--accent-soft); color: var(--accent-ink);
  display: flex; align-items: center; justify-content: center;
  font-size: 15px; font-weight: 700;
}
.account-id > div { display: flex; flex-direction: column; gap: 2px; }
.account-id b { font-size: 15px; color: var(--text); }
.account-id .muted { font-size: 13px; }
/* "Выйти" (settings-uxui-spec.md §1) живёт в ряду с именем аккаунта справа - там же,
   где действия у всех остальных рядов раздела, без отдельной хвостовой полосы. */
.account-id { min-width: 0; }
/* Кнопка "Пригласить ссылкой" в демо-воркспейсе - видима, но неактивна (Никита: не прятать,
   а задизейблить с тултипом). pointer-events остаётся включённым - иначе hover/тултип не
   сработает; клик гасится JS-guard'ом (app.js). */
.demo-disabled { opacity: .5; filter: grayscale(.3); cursor: not-allowed; }
@media (max-width: 1023px) {
  #team-body .settings-row { flex-direction: column; align-items: flex-start; gap: 4px; }
}

/* ---------- сортировка карточных списков (Продукция, Отчёты, ТТК, база знаний) ---------- */
.sort-row { display: flex; gap: 8px; margin-bottom: 12px; flex-wrap: wrap; }
/* 420px - запасной потолок на случай, когда JS ещё не подогнал высоту (см. syncDuoHeight
   в app.js: после рендера пары в .duo высота этого списка выставляется inline под высоту
   соседней карточки, а не под фиксированное число строк). */
.scroll-list { max-height: 420px; overflow-y: auto; }
.fc-note { display: block; margin: -4px 0 10px; }
.sort-chip.dir-asc::after { content: " \25B2"; }
.sort-chip.dir-desc::after { content: " \25BC"; }

/* ---------- произвольный период ----------
   Оверлей поверх карточек, а не в потоке: раскрываясь, ничего не толкает вниз
   (Никита 04.09.2026: «он должен открываться поверх»; до этого 18.08 был в потоке). */
#period-chips { position: relative; }
#custom-period-pop {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 30;
  width: min(540px, 100%);
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 14px; box-shadow: var(--shadow); display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
}
.custom-period-field { display: flex; flex-direction: column; gap: 4px; flex: 1 1 150px; min-width: 130px; }
.custom-period-field label {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--muted);
}
/* Нативный input[type=date] стилизовать нельзя в принципе, а его локаль зависит от
   браузера, а не от языка приложения (принято 18.08.2026 после ponytail - см. app.md).
   Поля теперь readonly-текст в нашем формате ДД.ММ.ГГГГ, открывающий свой календарь
   #custom-calendar. Пилюля той же высоты (35.5px) и скругления (999px), что чипы периода. */
#custom-period-pop input[type="text"] {
  border: 1px solid var(--line); border-radius: 999px; padding: 0 34px 0 14px; height: 35.5px;
  font-family: -apple-system, "SF Pro Text", "Segoe UI", Roboto, sans-serif;
  font-size: 13px; color: var(--text); font-variant-numeric: tabular-nums;
  width: 100%; min-width: 0; cursor: pointer;
  background: var(--card) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234f6bf5' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='5.5' width='16' height='14' rx='3'/%3E%3Cpath d='M8 3.5v4M16 3.5v4M4 10.5h16'/%3E%3C/svg%3E") no-repeat right 12px center;
  background-size: 16px 16px;
}
.custom-period-field.active input[type="text"] {
  border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft);
}
#custom-status { width: 100%; margin: 2px 0 0; font-size: 12px; }

/* ---------- свой календарь диапазона (замена системного виджета, без библиотек) ---------- */
#custom-calendar {
  flex: 1 0 100%; border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 10px 6px; background: var(--bg);
}
.cal-head { display: flex; align-items: center; justify-content: space-between; }
.cal-title { font-size: 13px; font-weight: 600; text-transform: capitalize; }
.cal-mode { font-size: 11px; color: var(--muted); margin: 2px 0 6px; }
.cal-nav {
  min-width: 44px; min-height: 44px; display: flex; align-items: center; justify-content: center;
  background: none; border: 0; font-size: 18px; color: var(--accent-ink); border-radius: 8px;
}
.cal-nav:hover, .cal-nav:focus-visible { background: var(--accent-soft); }
.cal-weekdays, .cal-days { display: grid; grid-template-columns: repeat(7, 1fr); }
.cal-weekdays span {
  text-align: center; font-size: 11px; color: var(--muted); padding: 4px 0; font-weight: 600;
}
.cal-day {
  border: 0; background: none; color: var(--text); font-size: 13px; border-radius: 8px;
  min-height: 44px; font-variant-numeric: tabular-nums;
}
.cal-day--empty { pointer-events: none; }
.cal-day:not(.cal-day--empty):not(.cal-day--disabled):hover { background: var(--accent-soft); }
.cal-day:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.cal-day--range { background: var(--accent-soft); border-radius: 0; }
.cal-day--edge { background: var(--accent); color: #fff; font-weight: 600; }
.cal-day--disabled { color: var(--muted); opacity: .4; cursor: default; }

/* Полоска "данные от ЧЧ:ММ" над разделом аналитики - вместо пустого экрана на каждый
   переход показываем последний ответ сразу, полоска сигналит про фоновое обновление
   и его исход (см. app.md "Показ последних данных"). */
.analytics-status {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-bottom: 10px; padding: 8px 14px; border-radius: 10px;
  background: var(--card); border: 1px solid var(--line); font-size: 12.5px; color: var(--muted);
}
.analytics-status.is-loading #analytics-status-text::before {
  content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 6px;
  border-radius: 50%; background: var(--accent); animation: pulse-dot 1s ease-in-out infinite;
}
.analytics-status.is-error { color: var(--down); border-color: var(--down); }
.analytics-status #analytics-refresh { padding: 5px 12px; font-size: 12.5px; flex-shrink: 0; }
@keyframes pulse-dot { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
#analytics-body { display: flex; flex-direction: column; gap: 14px; }
/* auto-fit вместо жёстких 4 колонок - в узком блоке конструктора (ресайз по ширине) плашки
   переносятся вместо сжатия в нечитаемые столбики (04.09.2026, бриф: "перенос сетки плашек"). */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); grid-auto-rows: 1fr; gap: 12px; } /* auto-rows 1fr: в 2x2 ряд с «после скидок» не выше ряда без неё (Никита 05.09.2026) */
/* flex-колонка + margin-top:auto у дельты: карточки ряда одной высоты (grid stretch),
   дельты прижаты к низу и стоят на одной линии, даже когда у «Выручки» есть kpi-sub */
.kpi {
  padding: 16px 18px; display: flex; flex-direction: column; align-items: flex-start;
  container-type: inline-size; /* .kpi-value уменьшает шрифт по своей же ширине ниже */
}
.kpi .kpi-label { font-size: 12px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
/* nowrap - значение с ₽ (nbsp в rub()) не переносится на вторую строку и не тянет высоту
   всей строки KPI-плашек (04.09.2026, брифом п.1: "1 315 943 ₽" ломало ряд из 4 карточек).
   ellipsis - страховка на совсем узкой клетке, font-size ниже уменьшает раньше, чем до неё дойдёт. */
.kpi .kpi-value {
  font-size: 26px; font-weight: 700; margin-top: 4px; font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.kpi .kpi-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
@container (max-width: 150px) { .kpi .kpi-value { font-size: 20px; } }
/* baseline, не center: на 375px подпись переносится на две строки, и при center
   стрелка уезжала к нижней строке. nowrap+ellipsis - дельта теперь всегда одна строка,
   полный текст "к пред. периоду" живёт в title (04.09.2026, брифом п.1). */
.kpi-delta {
  font-size: 12px; font-weight: 700; margin-top: auto; padding-top: 4px; display: inline-flex;
  align-items: baseline; gap: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.kpi-delta.up { color: var(--up); }
.kpi-delta.down { color: var(--down); }
.kpi-delta .arr { font-size: 10px; }
.kpi-delta .kd-main { white-space: nowrap; }
/* Суффикс " к пред. периоду" прячется первым на узкой карточке - число и стрелка остаются,
   title у .kpi-delta несёт полный текст. Порог 200px (было 150 - Возврат 1, 04.09.2026 ·
   оркестратор: "«к пред. периоду» пропал даже на 12 колонках, где места полно" - при 150
   суффикс прятался только на совсем узкой карточке, а на широкой должен показываться
   ЦЕЛИКОМ, порог подняли, чтобы полная строка была видна дальше, а не наоборот раньше). */
@container (max-width: 120px) { .kpi-delta .kd-suffix { display: none; } } /* 200 прятало хвост и на 12 колонках: плашка там 173px */
/* Плашки в блоке главной складываются ступенями по ширине КЛЕТКИ: 4 в ряд, ниже 780px
   (полная дельта «▼2.4% к пред. периоду» в 4 столбца не влезает) - 2x2, ниже 390px - в один
   столбец. Ступени вместо auto-fit, чтобы дельта не резалась (Никита 05.09.2026). */
@container eblock (max-width: 779px) { .kpi-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
@container eblock (max-width: 389px) { .kpi-grid { grid-template-columns: minmax(0, 1fr); } }
.chart-card { padding: 18px; overflow-x: auto; }
.duo > * { min-width: 0; }
/* Заголовок в одну строку, хвосты ("· все 7") не режутся посреди слова - каждый узел
   между "·" держит nowrap, перенос возможен только МЕЖДУ ними (04.09.2026, брифом п.5:
   "Категории · по выручке · все 7" переносилось на три строки посреди слова). */
.chart-card h3 { font-size: 15px; margin-bottom: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 0 0 auto; } /* flex-shrink:0 - во flex-колонке карточки заголовок сжимался до 0px на узком блоке (зонд 04.09.2026) */
.chart-card h3 small { color: var(--muted); font-weight: 400; }
/* «?» вместо абзаца-пояснения про FC - строка h3 не растёт на узкой карточке
   (04.09.2026, брифом п.7: пояснение "занимает четверть блока"). */
.fc-note-ico {
  display: inline-flex; align-items: center; justify-content: center; width: 15px; height: 15px;
  border-radius: 50%; background: var(--accent-soft); color: var(--accent); font-size: 10px;
  font-weight: 700; cursor: help; vertical-align: middle; flex-shrink: 0;
}
.duo { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 14px; align-items: start; }
/* Закупки: правый список поставщиков на 30% уже обычного (40% -> 28% ширины строки) -
   в нём короткие строки, а таблице цен нужны колонки. Без .duo. в селекторе, иначе
   правило перебьёт мобильную раскладку .duo { 1fr } ниже. */
.duo-narrow { grid-template-columns: minmax(0, 72fr) minmax(0, 28fr); }
.bar-chart { width: 100%; display: block; }
.bar-chart rect.bar { fill: var(--accent); }
.bar-chart rect.bar:hover { fill: var(--accent-ink); }
.bar-chart text { font: 11px -apple-system, sans-serif; fill: var(--muted); }
.bar-chart line.grid { stroke: var(--line); stroke-width: 1; }

.rank-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.rank-list li { display: flex; flex-direction: column; gap: 3px; }
.rank-top { display: flex; justify-content: space-between; gap: 10px; font-size: 13.5px; }
.rank-top .val { font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--text); font-weight: 600; }
.rank-top .qty { color: var(--muted); font-weight: 400; }
.rank-bar { height: 6px; border-radius: 4px; background: var(--accent-soft); overflow: hidden; }
.rank-bar i { display: block; height: 100%; border-radius: 4px; background: var(--accent); }

.empty-analytics { padding: 40px 24px; text-align: center; }
.empty-analytics h3 { font-size: 22px; margin-bottom: 8px; }
.empty-analytics.compact { padding: 16px; }
.skeleton { padding: 32px; text-align: center; color: var(--muted); }

/* «Выручка за 12 месяцев» - была фиксированная ширина 720px с горизонтальным скроллом
   карточки (design-spec §6, старый дизайн) - именно эта строка держала SVG на 720px и
   сводила на нет .revenue-fc-grid ниже (та же специфичность, .chart-revenue-fc правило
   ПОЗЖЕ .bar-chart в файле - побеждает; 04.09.2026 · Никита, revenue_12m резался на
   минимуме, диагностика computed style: 720px вместо 100%). Ширину теперь держит только
   `.bar-chart { width: 100% }`. */
.rev-fc-outer { fill: var(--accent-soft); stroke: var(--line); stroke-width: 1; }
.rev-fc-seg { fill: var(--accent); }
.rev-fc-seg.high { fill: var(--down); }
.rev-fc-partial { fill-opacity: .6; stroke-dasharray: 3 2; }
.rev-fc-rub { font-size: 10px; paint-order: stroke; stroke: var(--card); stroke-width: 3px; stroke-linejoin: round; } /* обводка цветом карточки - читается поверх соседних столбиков на узком графике */
/* Дима 26.08.2026: «цифры внутри столбцов себестоимости ни хуа не видны, нужен чёрный
   шрифт, а не тонкий серый». Буквально чёрным нельзя: подпись лежит НА тёмной заливке
   сегмента (--accent, при FC>35% --down, у текущего месяца ещё и fill-opacity .6), чёрный
   по ним читается хуже белого. Поэтому не подбираем цвет под фон, а снимаем зависимость
   от фона: крупнее, жирнее и тёмная обводка через paint-order - держит контраст на всех
   трёх заливках. Вынос над коротким столбцом НЕ возвращаем - Никита 24.08.2026:
   «пусть он будет только при наведении» (specs/app.md:47).
   ВАЖНО - селектор с `.bar-chart`, а не голый класс: строкой 563 стоит
   `.bar-chart text { font: 11px ...; fill: var(--muted) }`, у неё специфичность (0,1,1)
   против (0,1,0) у одного класса. Прежний `.rev-fc-pct-in { fill: var(--card) }` ей
   проигрывал, поэтому подпись была не белой, а СЕРОЙ --muted #7b849c - Дима увидел ровно
   то, что есть. Шорткат `font:` там же сбрасывает и font-weight в 400, так что жирность
   тоже надо перебивать. Проверять только getComputedStyle на живой странице: в исходнике
   правило выглядит рабочим. */
.bar-chart text.rev-fc-pct-in { font-size: 12px; font-weight: 800; fill: #fff;
  paint-order: stroke; stroke: rgba(0, 0, 0, .45); stroke-width: 2.5px;
  stroke-linejoin: round; }
.rev-fc-nodata { opacity: .35; }
.revenue-fc-skel { display: flex; align-items: flex-end; gap: 12px; height: 164px; margin-top: 18px; }
.revenue-fc-skel i { flex: 0 0 46px; background: var(--line); opacity: .5; border-radius: 4px 4px 0 0; animation: pulse-dot 1.4s infinite; }

/* Правая колонка «Топ позиций за 12 месяцев» (design-spec §9, Никита 22.08.2026) -
   грид ПОД общим h3 карточки, график и список - независимые колонки/загрузки. */
/* колонки-грида - ВСЕГДА с полом (minmax(0,...)), а не голый fr: fr не сжимается
   ниже min-content того, что внутри, без явного пола - задокументированный проект-питфол
   (rules/coding-style.md "fr без пола"). chart-col держит 720px svg - без min-width:0
   на самой grid-ячейке в части браузеров это может схлопнуть вторую колонку/весь ряд. */
/* Колонки резиновые, а не 720px хардкод (04.09.2026 · Никита: "обрезал по ширине... все
   данные срезались") - хардкод держал минимальную ширину грида в 720+190=910px независимо
   от фактической ширины карточки конструктора, список справа вылезал за карточку и резался.
   Топ-колонка держит пол 150px, потолок 260px - график забирает остальное и сам
   масштабируется (viewBox), горизонтальный скролл ему больше не нужен. */
/* Грид сам получает высоту от .card.chart-card (flex-колонка на всю клетку, правило ниже
   "Контент под размер клетки") - без этого chart-col/top-col росли под свой контент и
   молча вылезали ЗА нижний край белой карточки (04.09.2026 · Никита, contain: revenue_12m
   на минимуме резался и по ширине, и по высоте). grid-template-rows: minmax(0,1fr) + пол
   для строки, align-items:stretch - обе колонки получают РОВНО высоту карточки, дальше
   каждая сама решает, что с ней делать (график - масштаб, список - свой скролл). */
/* .revenue-fc-grid снят 05.09.2026 - график и топ позиций теперь два блока (Никита: «давай разделим»). */
.home-list .eblock > .card.chart-card > .revenue-fc-chart-col,
.home-list .eblock > .card.chart-card > .revenue-fc-top-col { flex: 1 1 auto; min-height: 0; }
.revenue-fc-chart-col { margin-top: 12px; }
.revenue-fc-chart-col { min-width: 0; min-height: 0; overflow: hidden; }
.revenue-fc-top-col { min-width: 0; min-height: 0; overflow: hidden; display: flex; flex-direction: column; }
.revenue-fc-top-col h3 { flex: 0 0 auto; }
.revenue-fc-top-col .rank-list { margin-top: 12px; }
/* Список - свой скролл В ГРАНИЦАХ отведённой высоты (не расползается за карточку), а не
   обрезка текста. data-scroll - список размечен как заведомо прокручиваемый для проверки
   scripts/measure_home_min.py. */
.revenue-fc-top-col .rank-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-gutter: stable; }
/* «ещё N» - строки/пункты, спрятанные строкой ниже, вместо внутреннего скролла карточки
   (04.09.2026 · оркестратор, возврат 2, п.2). Кликабельная подсказка, не декорация. */
.rank-more.home-more { white-space: nowrap; } /* «ещё 2» в узкой колонке не переносится на две строки (05.09.2026) */
.home-hidden { display: none !important; } /* !important: .rank-list > li { display:flex } специфичнее класса */
.rank-more, .home-table-more td {
  color: var(--accent); font-size: 12.5px; font-weight: 600; cursor: pointer; padding-top: 2px;
}
.rank-more:hover, .home-table-more:hover td { text-decoration: underline; }
.rank-list.compact { gap: 6px; }
.rank-list.compact .rank-top { align-items: baseline; font-size: 12.5px; }
.rank-num { flex: 0 0 16px; color: var(--muted); font-variant-numeric: tabular-nums; }
.rank-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-meta { display: flex; justify-content: space-between; align-items: center; }
.rank-share { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }
.fc-chip { font-size: 11px; color: var(--text); }
.fc-chip.fc-high { color: var(--down); font-weight: 700; }
.fc-chip.muted { color: var(--muted); }
.rank-list.compact .rank-bar { height: 4px; }
.revenue-fc-top-skel { height: 19px; background: var(--line); opacity: .5; border-radius: 4px; animation: pulse-dot 1.4s infinite; }

/* Однострочные строки - только с ≥1440 (оркестратор 22.08.2026, проверка на 1280: при card≈970px
   правая колонка ≈200px резала названия до "Фил…"/"Стри…" - нечитаемо, а 1280 самая ходовая
   ширина ноутбука). На 1024-1439 остаётся двухколоночный грид карточки (720px 1fr), но строки
   списка - двухстрочные, как в стеке на ≤1023 (та же база .rank-list.compact ниже, без
   переопределения) - имя получает всю ширину колонки, читается 14-20 символов; список там
   выйдет выше графика - осознанный размен читаемости на геометрию, см. design-spec.md §9.
   Разметка (rank-top/rank-meta) не меняется - на ≥1440 оба контейнера становятся
   display:contents, их дети превращаются в прямые ячейки грида на <li>, порядок задаёт `order`. */
/* Была `@media (min-width: 1440px)` - решала по ширине ОКНА, а не карточки: на широком
   окне с узкой клеткой (6 колонок) режим всё равно включался и сжимал имя до "П.."/"Б.."
   (04.09.2026 · оркестратор, возврат 2, my-rev12m-half.jpg). Триггер - реальная ширина
   .eblock (container query, тот же container-type что и остальная адаптивность блока);
   700px - примерно та ширина карточки revenue_12m, при которой раньше срабатывал 1440px. */
@container eblock (min-width: 700px) {
  /* Дорожки живут на СПИСКЕ, строки подключаются к ним через subgrid. Две правки Димы
     27.08.2026 подряд лечатся только так:
     1) «правые значения липнут» - было `34px 38px 44px`, содержимое в дорожки не влезало
        («FC 36%» жирным при FC>35% шире 38px, «290 691» шире 44px) и наезжало на соседа;
     2) «почему они на разной ширине начинаются» - auto на грид КАЖДОЙ строки меряет
        только эту строку, поэтому «FC 36%» и «FC 24%» давали разную ширину колонки
        и выручка стартовала вразнобой.
     Общие дорожки на списке меряют самое широкое значение по ВСЕМ строкам разом: и не
     режет, и колонка одна на всех. Пиксельные ширины сюда не возвращать - они прятали
     обрезку, а не решали её. */
  .rank-list.compact {
    display: grid;
    grid-template-columns: 14px minmax(0, 1fr) auto auto auto;
    column-gap: 10px;
  }
  .rank-list.compact li {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
    /* Оба зазора явно: у subgrid СВОИ gap перебивают родительские, а базовое
       `.rank-list li { gap: 3px }` иначе тихо ставит колонкам 3px вместо 10. */
    gap: 3px 10px;
    align-items: baseline;
  }
  .rank-list.compact .rank-top, .rank-list.compact .rank-meta { display: contents; }
  .rank-list.compact .rank-num { order: 1; }
  .rank-list.compact .rank-name { order: 2; }
  .rank-list.compact .rank-share { order: 3; text-align: right; white-space: nowrap; }
  .rank-list.compact .fc-chip { order: 4; text-align: right; white-space: nowrap; }
  .rank-list.compact .val { order: 5; text-align: right; }
  .rank-list.compact .rank-bar { order: 6; grid-column: 1 / -1; }
  .rank-share-word { display: none; } /* "выручки" - остаётся в тултипе, тут места нет */
}

#tooltip {
  position: fixed; z-index: 50; pointer-events: none;
  background: #1d2436; color: #fff; font-size: 12px; line-height: 1.4;
  border-radius: 8px; padding: 7px 10px; box-shadow: 0 6px 20px rgba(0,0,0,.25);
  max-width: 240px;
}

/* ---------- строка-лидер/хвост в таблицах (ABC) ---------- */
.chart-table tr.row-a td:first-child { border-left: 3px solid var(--up); padding-left: 7px; }
.chart-table tr.row-c td:first-child { border-left: 3px solid var(--muted); padding-left: 7px; }
.abc.a { background: #e6f6ec; color: var(--up); }
.abc.b { background: var(--accent-soft); color: var(--accent-ink); }
.abc.c { background: #f4f1ea; color: #8a7a52; }

/* ---------- подсказка вместо пустого низа страницы ---------- */
/* Верхний зазор уже даёт .page-head { margin-bottom: 14px }; нижний ставим тем же
   значением, чтобы подсказка была на равном расстоянии от заголовка и от следующего блока
   (было 30px сверху вплотную к строке поиска снизу). */
.tab-hint { margin-top: 0; margin-bottom: 14px; padding: 0 4px; font-size: 13px; color: var(--muted); }

/* ---------- скролл-маска подвкладок (мобайл) ---------- */
.subtabs-wrap { position: relative; width: fit-content; max-width: 100%; }
.subtabs-wrap::after {
  content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: 28px;
  background: linear-gradient(to right, transparent, var(--bg));
  pointer-events: none; display: none; border-radius: 0 12px 12px 0;
}
.subtabs-wrap.end::after { display: none; }
@media (max-width: 1023px) { .subtabs-wrap::after { display: block; } }

/* ---------- заголовок раздела с кнопкой действия ---------- */
.section-toolbar { display: flex; gap: 10px; align-items: center; justify-content: space-between; margin-bottom: 14px; flex-wrap: wrap; }
/* "Справочник КБЖУ" крайняя правая группа ("Свои ТТК") - вплотную к "+ Новая ТТК", не по
   центру пустоты (Никита). Один flex-child внутри space-between-родителя уходит вправо
   целиком, кнопки внутри группы держит свой gap. */
.ttk-toolbar-right { display: flex; gap: 8px; margin-left: auto; }
/* "Команда и доступ" - кнопки одним кластером слева, не растянуты по всей ширине
   (settings-uxui-spec.md §3). */
#team-toolbar { justify-content: flex-start; gap: var(--space-2); }
.section-toolbar input[type="search"] {
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  padding: 11px 14px; font-size: 15px; color: var(--text); flex: 1; min-width: 200px; max-width: 420px;
}
.section-toolbar input[type="search"]:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }

/* ---------- список с метаданными (продукция / ттк / база знаний) ---------- */
.list li { display: flex; flex-direction: column; gap: 4px; }
.list-row-top { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
/* Плашка статуса - короткая метка, ломаться на две строки внутри овала она не должна:
   во флексе узкой карточки (регистрация, 380px) «касса подключена» разрывалась пополам. */
.list-row-top .chip { white-space: nowrap; flex-shrink: 0; }
.list-meta { display: flex; gap: 14px; font-size: 12.5px; color: var(--muted); flex-wrap: wrap; }
.list-meta b { color: var(--text); font-variant-numeric: tabular-nums; }
.list-meta .fc-high { font-weight: 700; }

/* ---------- форма ---------- */
.form-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-4); }
.form-field { display: flex; flex-direction: column; gap: 6px; }
.form-field label { font-size: 12.5px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
/* Голая браузерная кнопка «Choose File» - единственный неоформленный элемент в приложении.
   Красим саму кнопку выбора, поле остаётся тем же, что у прочих. */
.form-field input[type="file"] { padding: 8px 10px; cursor: pointer; }
.form-field input[type="file"]::file-selector-button {
  font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  background: var(--card); border: 1px solid var(--line); color: var(--text);
  border-radius: 10px; padding: 7px 12px; margin-right: 12px;
}
.form-field input[type="file"]::file-selector-button:hover { border-color: var(--accent); color: var(--accent-ink); }
.form-actions { display: flex; gap: 10px; margin-top: var(--space-5); justify-content: flex-end; }
.form-full { grid-column: 1 / -1; }
.rows-editor { display: flex; flex-direction: column; gap: 8px; }
.rows-editor .row-line { display: grid; grid-template-columns: minmax(0, 1fr) 90px 90px 32px; gap: 8px; align-items: center; }
.rows-editor .row-line input { width: 100%; }
.row-remove { background: none; border: 0; color: var(--muted); font-size: 18px; cursor: pointer; padding: 4px; }
.row-remove:hover { color: var(--down); }

/* Свой подбор сырья вместо нативного input[list]/datalist - на 1000+ позициях системная
   простыня не листается клавишами, режет длинные имена и на телефоне занимает весь экран
   (Никита, 18.08). .ing-combo - позиционирующий якорь для выпадашки нашей вёрстки. */
.ing-combo { position: relative; }
.ing-results {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 30;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px;
  box-shadow: var(--shadow); max-height: 260px; overflow-y: auto; padding: 4px;
}
.ing-result {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 8px; cursor: pointer; font-size: 13.5px;
  white-space: nowrap; overflow: hidden;
}
.ing-result span:first-child { overflow: hidden; text-overflow: ellipsis; }
.ing-result:hover, .ing-result.active { background: var(--accent-soft); color: var(--accent-ink); }
.ing-result .unit { font-size: 12px; color: var(--muted); flex-shrink: 0; }
.ing-result.active .unit { color: var(--accent-ink); }
.ing-more { padding: 6px 10px; font-size: 12px; color: var(--muted); }

/* Цена/себес строки ТТК (28.08, привязка к номенклатуре iiko) - полноширинная подстрока
   грида row-line, поэтому колонки .rows-editor .row-line трогать не нужно. */
.tr-price { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; font-size: 12.5px; color: var(--muted); }
.tr-badge { background: var(--accent-soft); color: var(--accent-ink); border-radius: 999px; padding: 2px 9px; font-weight: 600; font-size: 11.5px; }
.tr-price-info { color: var(--text); font-weight: 600; }
.tr-price-manual { width: 130px; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px; background: var(--card); color: var(--text); font: inherit; font-size: 12.5px; }
.tr-auto-hint { display: flex; align-items: center; gap: 6px; }
.tr-auto-revert { font-size: 11.5px; padding: 2px 6px; }
.ttk-cost { margin-top: 6px; font-size: 14px; }

/* ---------- модальное окно ---------- */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(29,36,54,.35); backdrop-filter: blur(2px);
  display: flex; align-items: center; justify-content: center; z-index: 100; padding: 20px;
}
.modal {
  background: var(--card); border-radius: var(--radius); box-shadow: 0 24px 60px rgba(29,36,54,.25);
  width: 100%; max-width: 440px; padding: 28px; display: flex; flex-direction: column; gap: 14px;
}
.modal h3 { font-size: 20px; }
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 8px; }
.modal .form-grid { grid-template-columns: 1fr; }
.modal .pass-out {
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 18px; font-weight: 700;
  background: var(--accent-soft); color: var(--accent-ink); border-radius: 10px; padding: 12px 14px;
  text-align: center; letter-spacing: .04em; user-select: all;
}
/* ссылка длиннее пароля - тот же приём, но мельче и с переносом, а не одной строкой */
.modal .link-out {
  font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: 13px; font-weight: 600;
  background: var(--accent-soft); color: var(--accent-ink); border-radius: 10px; padding: 12px 14px;
  text-align: left; word-break: break-all; user-select: all;
}
@media (max-width: 1023px) {
  .modal-backdrop { align-items: flex-end; padding: 0; }
  .modal { max-width: none; border-radius: 20px 20px 0 0; padding: 24px 20px calc(24px + env(safe-area-inset-bottom)); }
}

/* ---------- печатная форма ТТК ---------- */
.ttk-print { display: none; }
@media print {
  body * { visibility: hidden; }
  .ttk-print, .ttk-print * { visibility: visible; }
  .ttk-print {
    display: block; position: absolute; top: 0; left: 0; width: 100%;
    font-family: Georgia, "Times New Roman", serif; font-size: 12pt; color: #000;
    padding: 20mm 18mm;
  }
  .ttk-print h1 { font-size: 14pt; text-align: center; margin-bottom: 4mm; }
  .ttk-print .approve { display: flex; justify-content: space-between; align-items: flex-start; gap: 10mm; margin-bottom: 10mm; }
  .ttk-print .approve-left { font-size: 10pt; }
  .ttk-print .approve-box { text-align: center; font-size: 10pt; }
  .ttk-print .approve-box b { display: block; text-transform: uppercase; margin-bottom: 8mm; }
  .ttk-print table { width: 100%; border-collapse: collapse; margin: 6mm 0; }
  .ttk-print th, .ttk-print td { border: 1px solid #000; padding: 4pt 6pt; font-size: 10pt; }
  .ttk-print .foot { margin-top: 10mm; font-size: 10pt; color: #444; }
}

/* ---------- списки ---------- */
/* UA-стиль ul даёт padding-inline-start:40px даже при list-style:none - левый край
   карточек в списке уезжал направо от заголовка/фильтров раздела, правый совпадал.
   Обнулено здесь, а не в каждом разделе (Продукция/Отчёты/Свои ТТК/Команда/КБЖУ - все на .list). */
.list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.list li { background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; cursor: pointer; }
.list li:hover { border-color: var(--accent); }
.list li small { display: block; color: var(--muted); }

/* ---------- таб-бар (мобайл) ---------- */
#tabbar { display: none; border-top: 1px solid var(--line); background: var(--card); padding-bottom: env(safe-area-inset-bottom); }
#tabbar button {
  flex: 1; background: none; border: 0; color: var(--muted);
  padding: 8px 0 6px; display: flex; flex-direction: column; align-items: center; gap: 3px;
}
#tabbar button .ico { width: 22px; height: 22px; }
#tabbar button span { font-size: 10.5px; }
#tabbar button.active { color: var(--accent-ink); }

.ws-card-m { flex: 1; padding: 6px 10px; box-shadow: none; min-width: 0; }
.ws-avatar-m { width: 30px; height: 30px; }
.more-plans { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 8px 16px; }

#tab-more .card { padding: 20px; display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }

@media (max-width: 1023px) {
  #sidebar { display: none; }
  #mobile-header { display: flex; }
  #tabbar { display: flex; }
  .tab { padding: 16px 14px 20px; }
  .kpi-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .kpi .kpi-value { font-size: 22px; } /* с дельтой снизу иначе переносится криво в узкой карточке */
  .duo { grid-template-columns: 1fr; }
  /* Диалоги на мобиле - шторка поверх переписки (места на постоянную колонку нет),
     закрывается после выбора диалога (см. openDialog в app.js). */
  #tab-chat { position: relative; }
  #dialogs-panel { position: absolute; top: 0; left: 0; bottom: 0; z-index: 15; box-shadow: none; }
  #dialogs-panel.open { width: min(84vw, 320px); box-shadow: var(--shadow); }
  /* Ассистент на мобиле: убрали иконку и подводку, свернули 4 карточки в горизонтальный
     ряд чипов без описаний - иначе до поля ввода надо было скроллить. */
  #chat-hero { padding-top: 4px; }
  .hero-mark { display: none; }
  #chat-hero p { display: none; }
  #fn-cards {
    display: flex; grid-template-columns: none; overflow-x: auto; gap: 8px;
    margin-top: 10px; padding-bottom: 2px;
  }
  .fn-card {
    flex: 0 0 auto; flex-direction: row; align-items: center; padding: 9px 14px; white-space: nowrap;
  }
  .fn-card span { display: none; }
  #chat-hero h2 { font-size: 22px; margin-bottom: 0; }
  .page-head h2 { font-size: 22px; }
  #tpl-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  #tab-chat { padding: 0; }
  .form-grid { grid-template-columns: 1fr; }
  .list-meta > span:nth-child(2) { display: none; }
  .section-toolbar { flex-direction: column; align-items: stretch; }
  .section-toolbar input[type="search"] { max-width: none; }
  /* строка состава ТТК на узком экране: 4 колонки в ряд обрезали плейсхолдер "Наимен..." */
  .rows-editor .row-line { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 32px; row-gap: 6px; }
  .rows-editor .row-line .ing-combo { grid-column: 1 / -1; }
}

/* Гостевой просмотр (одноразовая ссылка, без аккаунта) - см. app.js enterGuestMode.
   Виден только раздел Аналитика/Продукция, без переключателя заведения и записи. */
#guest-banner {
  background: var(--accent-soft); color: var(--accent-ink); font-size: 13px; font-weight: 600;
  text-align: center; padding: 8px 12px;
}
body.guest-mode .ws-card { pointer-events: none; opacity: .6; }

/* Демо-воркспейс свежего аккаунта - та же семья, что #guest-banner, плюс inline-CTA
   (design-spec.md §2). Одна строка на десктопе, перенос на мобиле. */
.demo-banner {
  background: var(--accent-soft); color: var(--accent-ink); font-size: 13px; font-weight: 600;
  padding: 10px 22px; display: flex; justify-content: space-between; align-items: center; gap: 12px;
}
.demo-banner span { max-width: 720px; }
.demo-banner .primary { padding: 8px 16px; font-size: 13px; flex-shrink: 0; }
.demo-banner .ghost { padding: 8px 16px; font-size: 13px; flex-shrink: 0; background: transparent; }
#demo-trial-pending { flex-shrink: 0; }
@media (max-width: 1023px) {
  .demo-banner { flex-wrap: wrap; padding: 10px 16px; }
  .demo-banner .primary, .demo-banner .ghost { flex: 1 0 100%; }
}

/* Счётчик дней триала (этап 2, 28.08.2026): строка, не баннер - Никита "ненавязчивый",
   поэтому без фона/рамки, в отличие от .demo-banner. */
#trial-counter { padding: 6px 22px; font-size: 12.5px; color: var(--muted); }
@media (max-width: 1023px) { #trial-counter { padding: 6px 16px; } }

/* Экран "доступ истёк" - та же карточка, что вход. */
#expired-view { display: flex; align-items: center; justify-content: center; min-height: 100dvh; padding: 24px; }
#expired-view .login-card { text-align: left; }
#expired-view h2 { text-align: center; }
/* Экран "демо закончилось" - тот же блокирующий каркас, что у истёкшего доступа. */
#demo-over-view { display: flex; align-items: center; justify-content: center; min-height: 100dvh; padding: 24px; }
#demo-over-view .login-card { text-align: left; max-width: 440px; }
#demo-over-view h2 { text-align: center; }
/* Выход из запертого экрана - строкой внизу карточки, не кнопкой наравне с целевым
   действием: путь нужен всегда, но не конкурирует с заявкой. */
.locked-exit { text-align: center; font-size: 13px; margin-top: 4px; }
/* Гостю - полный просмотр (Никита, 18.08.2026). Читаемые разделы открыты: сервер отдаёт
   их гостю через current_actor. Закрыты только Ассистент (пишет в базу) и Настройки
   (административный экран и своя учётка - у гостя ни того, ни другого нет). */
body.guest-mode #sidenav button[data-tab="chat"],
body.guest-mode #sidenav button[data-tab="settings"],
body.guest-mode #tabbar button[data-tab="chat"],
body.guest-mode .more-plans button[data-tab="settings"] { display: none; }
body.guest-mode #new-chat,
body.guest-mode #logout, body.guest-mode #logout-side { display: none; }

/* ---------- конструктор главной (KT: home-builder, design-spec v2, 24.08.2026) ---------- */

.home-edit-entry { margin-bottom: 12px; }
/* Иконка+текст в "Редактировать" - без flex наследовался инлайновый baseline-align,
   карандаш проседал ниже строки текста (Никита 28.08.2026: "кнопка кривоватая"). */
#home-edit-btn { display: inline-flex; align-items: center; gap: 8px; }

.edit-toolbar {
  position: sticky; top: 0; z-index: 5; background: var(--bg);
  padding: 10px 0 14px; border-bottom: 1px dashed var(--line);
  display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;
}
.edit-toolbar-left, .edit-toolbar-right { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.edit-toolbar-label {
  font-size: 12.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent-ink);
}
.edit-toolbar .error { margin: 8px 0 0; flex-basis: 100%; }
/* Подсказка про ручки - живёт, пока пользователь ни разу не тянул за угол (04.09.2026 ·
   Никита: "как пользователь должен увидеть эту кнопку, если он не знает что она там"),
   прячется в JS по localStorage после первого ресайза. */
.edit-toolbar-hint { margin: 8px 0 0; flex-basis: 100%; font-size: 12.5px; color: var(--muted); }
.edit-toolbar-hint.hidden { display: none; }

/* Настоящая 2D-сетка дашборда - GridStack.js (static/vendor/gridstack, MIT), заход 4
   (04.09.2026 · Никита: "адаптивно и по ширине, и по высоте, в любом соотношении, соседи
   не должны закрываться, призрак у курсора, живой плейсхолдер"). GridStack сам считает
   позиции через .grid-stack-item (position:absolute, transform) - x,y,w,h идут как
   gs-x/gs-y/gs-w/gs-h атрибуты, наш .eblock живёт ВНУТРИ как .grid-stack-item-content и
   получает высоту 100% от родителя. Библиотечный CSS (gridstack.min.css) даёт базовую
   раскладку и штатную ручку ресайза (угол se) - тут только наш дизайн поверх. */
.home-list.grid-stack { --gs-column-width: unset; }
.eblock {
  position: relative; overflow: auto; /* скролл внутри блока - контент не режется на маленьком размере.
     Высоту НЕ задавать: GridStack кладёт карточку absolute с inset 10px, height:100% вылезала
     на 10px за клетку и съедала вертикальный зазор между блоками (Никита 04.09.2026). */
  scrollbar-gutter: stable; /* полоса скролла резервирует место, а не ложится поверх текста
     (04.09.2026, брифом п.2/7/8/9: "скроллбар наезжает на текст"). */
  container-type: inline-size; container-name: eblock; /* грид/список внутри блока реагирует
     на ширину КЛЕТКИ, а не окна - иначе @media на 1023px никогда не сработает для узкого
     блока на широком экране (04.09.2026 · Никита, revenue_12m). */
}
.eblock.removing { opacity: 0; transition: opacity .15s; }
.home-list .drag-handle, .home-list .remove-btn, .home-list .content-veil { display: none; }
.home-list.editing .eblock {
  border: 1.5px dashed var(--accent); border-radius: var(--radius); padding: 10px;
}
.home-list.editing .drag-handle, .home-list.editing .remove-btn { display: flex; }
/* Драг за любое место карточки - курсор говорит об этом всей поверхностью, не только
   ручке (04.09.2026, брифом: "при наведении, клике и drag'е раздела"). */
.home-list.editing .eblock { cursor: grab; }
.home-list.editing .eblock:active { cursor: grabbing; }
.home-list.editing .eblock button, .home-list.editing .eblock a,
.home-list.editing .eblock th[data-col], .home-list.editing .eblock .home-more { cursor: pointer; }
.home-list.editing .content-veil { display: block; }
/* Призрак драга - сам перетаскиваемый .grid-stack-item поднимается над остальными и чуть
   наклоняется, штатный GridStack .ui-draggable-dragging ходит за курсором; плейсхолдер
   (пунктирная клетка на целевом месте) рисует сам GridStack, .grid-stack-placeholder ниже
   только докрашивает его под наш акцент вместо дефолтного серого. */
.grid-stack-item.ui-draggable-dragging .eblock,
.grid-stack-item.ui-resizable-resizing .eblock {
  box-shadow: 0 14px 30px rgba(29,36,54,.22); opacity: .92;
}
.grid-stack-placeholder > .placeholder-content {
  background: var(--accent-soft); border: 1.5px dashed var(--accent); border-radius: var(--radius);
}
/* Ручки живут ВНУТРИ белой карточки, а не над её краем - top:-10 раньше клал их на
   границу пунктирной рамки .eblock, снаружи белого контента (04.09.2026 · Никита:
   "как пользователь должен увидеть эту кнопку, если он не знает что она там"). Offset
   родителя - padding-box самого .eblock (10px паддинг в режиме редактирования), top:8
   кладёт ручку у самого верхнего края белой карточки, чуть внахлёст - заметно и не улетает. */
.drag-handle, .remove-btn {
  position: absolute; top: 8px; z-index: 4; width: 40px; height: 40px;
  align-items: center; justify-content: center; border-radius: 10px;
  background: var(--card); border: 1px solid var(--line); box-shadow: var(--shadow);
  font-size: 15px; cursor: pointer; touch-action: none;
}
/* Ручка драга - в правом верхнем углу, рядом с ✕, а не слева над заголовком (04.09.2026 ·
   оркестратор, возврат 2: ⠿ лежал поверх первой буквы h3). right:56 = remove-btn (right:8,
   ширина 40) + 8px зазор, обе ручки в одном ряду и не наезжают на текст заголовка слева. */
/* Заголовок блока в редактировании не уходит под ⠿ и ✕ (возврат 2, 04.09.2026). На узком
   блоке (Возврат 1, 04.09.2026 · оркестратор: "заголовок узкого блока исчезает" - 104px
   паддинга на карточке шириной ~250px не оставляли места тексту вовсе) паддинг и сами
   ручки меньше - контейнерный запрос на .eblock (container-name:eblock), не на окно. */
.home-list.editing .eblock h3:first-of-type, .home-list.editing .eblock h4:first-of-type { padding-right: 64px; }
@container eblock (min-width: 360px) {
  .home-list.editing .eblock h3:first-of-type, .home-list.editing .eblock h4:first-of-type { padding-right: 104px; }
}
/* Хвост "· ..." у small прячется первым на узком блоке - сам заголовок остаётся видимым
   всегда (h3 nowrap+ellipsis выше режет остаток, если он всё же не поместился). */
@container eblock (max-width: 359px) {
  .chart-card h3 small { display: none; }
  .home-list.editing .drag-handle, .home-list.editing .remove-btn { width: 28px; height: 28px; font-size: 12px; }
  .home-list.editing .drag-handle { right: 38px; }
  .home-list.editing .remove-btn { right: 6px; }
}
.drag-handle { right: 56px; color: var(--muted); cursor: grab; touch-action: pan-y; -webkit-touch-callout: none; user-select: none; }
.drag-handle:active { cursor: grabbing; }
.remove-btn { right: 8px; color: var(--down); }
.content-veil { position: absolute; inset: 0; z-index: 3; }
/* Штатная ручка ресайза GridStack (угол se) - перекрашена под нашу палитру вместо
   дефолтной, курсор диагональный, тянет и ширину, и высоту разом - один жест, любое
   соотношение (04.09.2026 · Никита, было - только ширина). */
/* GridStack прячет ручку до hover (класс ui-resizable-autohide) - в режиме редактирования
   она нужна видимой у каждого блока сразу. */
.home-list.editing .grid-stack-item.ui-resizable-autohide > .ui-resizable-se { display: block; }
/* Ручка ресайза - ВНУТРИ белой карточки, не на границе .eblock (04.09.2026 · Никита: ручка
   стояла снаружи карточки, "ни на что не похожа"). .ui-resizable-se - потомок
   .grid-stack-item, который занимает ту же площадь, что и .eblock (без своего инсета) -
   right/bottom считаем от паддинга+рамки .eblock (10+1.5), чтобы попасть в угол белой
   карточки. Акцентный цвет и полупрозрачность в покое, непрозрачная по наведению на
   карточку - её иначе не видно тому, кто не знает про неё. Зона хвата 26px (>= 24px). */
/* В покое почти не видна была при opacity:.55 на неконтрастном --accent-soft фоне
   (04.09.2026 · оркестратор, возврат 2, п.4) - крупнее и заметнее в покое, полная
   непрозрачность по наведению на карточку (правило ниже не менялось). */
.home-list .ui-resizable-se {
  width: 28px; height: 28px; right: 17px; bottom: 17px; cursor: nwse-resize;
  border-radius: 6px; background-color: var(--accent-soft); opacity: .8;
  background-image: repeating-linear-gradient(135deg, var(--accent) 0 2px, transparent 2px 5px);
  background-position: 7px 7px; background-repeat: no-repeat; background-size: 14px 14px;
  transition: opacity .15s;
}
.home-list .grid-stack-item:hover > .ui-resizable-se,
.home-list .ui-resizable-se:hover { opacity: 1; }
.home-list:not(.editing) .ui-resizable-se, .home-list:not(.editing) .drag-handle,
.home-list:not(.editing) .remove-btn { display: none; }
/* Контент под размер клетки, а не клетка под контент (04.09.2026 · Никита: "уменьшать и по
   ширине и по высоте в любом соотношении, не лишая контента"): карточка блока - колонка на
   всю высоту клетки, SVG-диаграмма занимает остаток и масштабируется под обе стороны
   (viewBox + preserveAspectRatio meet - пропорции держит сам браузер), списки и таблицы
   скроллятся в остатке. ponytail: таблица скроллится вместе с шапкой h3 через .eblock
   overflow:auto - липкая шапка, если попросят. */
.home-list .eblock > .card.chart-card { height: 100%; display: flex; flex-direction: column; min-height: 0; margin: 0; }
/* Список категорий/топа внутри блока - ограничен остатком карточки, иначе ul высотой auto
   вылезал за карточку и .eblock резал строку пополам, а truncateHomeList («ещё N») видел
   ul.scrollHeight == clientHeight и молчал (05.09.2026 · Никита: «обрезать пол продукта»).
   Ровно то же, что у .revenue-fc-top-col .rank-list выше. */
.home-list .eblock > .card.chart-card > .rank-list,
.home-list .eblock > .card.chart-card > [data-scroll]:has(> .rank-list) { flex: 1 1 auto; min-height: 0; overflow: hidden; display: flex; flex-direction: column; max-height: none; } /* :has - обёртки таблиц (ОПиУ, ABC) не трогаем: во flex-колонке таблица сжималась до своей ширины (05.09.2026) */
.home-list .eblock > .card.chart-card > [data-scroll] > .rank-list { flex: 1 1 auto; min-height: 0; overflow: hidden; } /* «Категории» оборачивают ul в div - та же цепочка вниз */
.home-list .chart-card > svg.bar-chart { flex: 1 1 0; min-height: 0; width: 100%; height: 100%; }
.home-list .chart-card > .rank-list { flex: 1 1 auto; min-height: 0; overflow: auto; scrollbar-gutter: stable; }

.subtabs-wrap.dimmed { opacity: .35; pointer-events: none; }

.dim-backdrop { position: fixed; inset: 0; background: rgba(20,22,30,.1); z-index: 9; }
.catalog-panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: 380px;
  background: var(--card); border-left: 1px solid var(--line);
  box-shadow: -8px 0 32px rgba(29,36,54,.12); padding: 18px; overflow-y: auto; z-index: 10;
}
.sheet-grip { display: none; width: 36px; height: 4px; border-radius: 2px; background: var(--line); margin: 0 auto 10px; }
.catalog-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
.catalog-head h3 { font-size: 17px; }
/* Группа каталога - отдельная полоса с фоном (var(--bg)) и своим радиусом, не просто текст
   между строк (04.09.2026 · Никита: "все еще читается плохо, нет явного разделения").
   list-style:none на <summary> не убирает нативный треугольник в Safari сам по себе - тут
   его дублирует явный display:flex (не list-item) + -webkit-details-marker:none ниже. */
.catalog-group {
  background: var(--bg); border-radius: 12px; margin-bottom: 10px; overflow: hidden;
}
.catalog-group + .catalog-group { margin-top: 0; }
#catalog-body summary {
  cursor: pointer; padding: 10px 12px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--text);
  display: flex; align-items: center; gap: 7px; list-style: none;
}
#catalog-body summary::-webkit-details-marker { display: none; }
/* Шеврон вместо нативного треугольника у <summary> (Никита 28.08.2026: "кривоватая
   менюшка") - косая галочка, поворачивается на 90° при открытии секции. */
#catalog-body summary::before {
  content: ""; width: 6px; height: 6px; flex-shrink: 0;
  border-right: 1.5px solid var(--muted); border-bottom: 1.5px solid var(--muted);
  transform: rotate(-45deg); transition: transform .15s;
}
.catalog-group[open] > summary::before { transform: rotate(45deg); }
.catalog-group-body { padding: 0 12px 4px; }
/* Строка внутри группы - отступ слева от заголовка группы, имя и подпись размера в одну
   колонку, компактная кнопка справа (04.08.2026 - "список выглядит ебано" - чип занимал
   целую колонку, подпись переносилась на 2-3 строки). Подпись размера серым под именем. */
.catalog-row {
  display: flex; align-items: center; gap: 10px; padding: 9px 0 9px 8px;
  border-top: 1px solid var(--line);
}
.catalog-group-body .catalog-row:first-child { border-top: 0; }
.catalog-row-main { flex: 1; min-width: 0; }
.catalog-row-name { font-size: 14px; display: block; }
.catalog-size-chip {
  display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px;
  background: none; border: none; padding: 0; text-transform: none; letter-spacing: normal;
}
.catalog-add { flex-shrink: 0; padding: 6px 12px; font-size: 13px; white-space: nowrap; }
.catalog-empty { padding: 6px 0 10px 8px; font-size: 12.5px; }

@media (max-width: 1023px) {
  /* На мобиле GridStack сам переключается в одну колонку (oneColumnSize в app.js) - ширина
     всегда полная, ручка se тянет только высоту (GridStack сам гасит w-часть в one-column
     режиме). */
  .edit-toolbar-left, .edit-toolbar-right { width: 100%; justify-content: space-between; }
  #edit-add-block { width: 100%; }
  .catalog-panel {
    top: auto; left: 0; right: 0; bottom: 0; width: auto; max-height: 78vh;
    border-left: 0; border-radius: 20px 20px 0 0; box-shadow: 0 -8px 32px rgba(29,36,54,.2);
    padding: 8px 16px calc(16px + env(safe-area-inset-bottom));
  }
  .sheet-grip { display: block; }
}

/* ---------- спотлайт-тур демо (KT: access-funnel-03) ---------- */
.tour-overlay.hidden { display: none; }
.tour-panel {
  position: fixed; background: var(--tour-dim); backdrop-filter: blur(1.5px); z-index: 150;
}
.tour-ring {
  position: fixed; z-index: 150; border-radius: 12px; pointer-events: none;
  border: 2px solid var(--accent); box-shadow: 0 0 0 3px var(--accent-soft), 0 4px 20px rgba(0, 0, 0, .3);
  transition: top .15s, left .15s, width .15s, height .15s;
}
.tour-bubble {
  position: fixed; z-index: 151; max-width: 300px; background: var(--card);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 14px 16px; color: var(--text);
}
.tour-bubble p { margin: 0; font-size: 14px; line-height: 1.4; }
.tour-bubble-microhint { margin-top: 6px !important; font-size: 12px; color: var(--muted); }
.tour-skip {
  float: right; margin: -2px -4px 8px 8px; background: none; border: 0; color: var(--muted);
  font-size: 12.5px; cursor: pointer; display: flex; align-items: center; gap: 4px;
}
.tour-skip:hover { color: var(--text); }

/* ---------- чек-лист "первые шаги" (KT: access-funnel-03) ---------- */
.checklist-widget {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 16px 18px; margin-top: 16px;
}
.checklist-widget.hidden { display: none; }
#checklist-items { list-style: none; margin: 8px 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
#checklist-items li {
  display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--text);
}
#checklist-items li.done { color: var(--muted); text-decoration: line-through; }
.checklist-dot {
  width: 20px; height: 20px; flex-shrink: 0; border-radius: 50%; border: 1.5px solid var(--line);
  display: flex; align-items: center; justify-content: center; font-size: 12px; color: var(--accent);
}
#checklist-items li.done .checklist-dot { background: var(--accent-soft); border-color: var(--accent); }

/* Цели: полоска выполнения плана внутри KPI-карточки (31.08.2026) */
/* Отступ до края плашки: у `.card` его нет, каждая карточка задаёт свой (chart-card 18,
   kpi 16/18, settings-card 24), а этим двум не задали - заголовок и поля лежали вплотную
   к краю (замер 01.09.2026: сверху 1px, слева 1px). Соседи по «Аналитике» - chart-card,
   поэтому 18px, а не 24: в одном ряду плашки дышат одинаково. */
.goals-head { padding: 18px; display: flex; justify-content: space-between; align-items: center; gap: 16px; flex-wrap: wrap; }
.goals-head-controls { display: flex; gap: 8px; align-items: center; }
/* Свой переключатель месяца: название по-русски, стрелки той же высоты, что кнопка рядом. */
.month-nav { display: flex; align-items: center; gap: 2px; }
.month-nav b { min-width: 128px; text-align: center; font-size: 14px; font-variant-numeric: tabular-nums; }
.month-nav button { padding: 6px 11px; font-size: 16px; line-height: 1.1; border-radius: 10px; }
.month-nav button:disabled { opacity: .35; cursor: default; }
/* Три числа в ряд, а не колонка полей во всю ширину карточки. */
.goals-form { padding: 18px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px 16px; align-items: end; }
.goals-form > p, .goals-form > button { grid-column: 1 / -1; }
.goals-form > button { justify-self: start; }
@media (max-width: 700px) { .goals-form { grid-template-columns: 1fr; } }
.goal .goal-bar { width: 100%; align-self: stretch; margin-top: 10px; height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; }
.goal .goal-bar i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.goal .goal-pct, .goal .goal-need { margin-top: 6px; font-size: 12px; color: var(--muted); }

/* ---------- раздел «Расходы» + досье заведения (05.09.2026; панель в чате снята) ---------- */
.chat-tools-right { display: flex; gap: 8px; }
/* Отступ до края плашки: у `.card` его нет (см. комментарий у .goals-head) - третий раз
   на те же грабли (31.08 Продукция, 01.09 Цели, 05.09 Расходы, Никита: «опять нарушено
   правило отступов внутри плашек»). Раздел стоит отдельно, как Настройки - 24px как у
   settings-card, на узком экране 16. */
#tab-expenses .card { margin-bottom: 14px; padding: var(--space-5); }
@media (max-width: 600px) { #tab-expenses .card { padding: 16px; } }
#tab-expenses .card h3 { margin-bottom: 18px; }
#tab-expenses .card h3 small { color: var(--muted); font-weight: 400; }
#exp-rows { display: grid; gap: 22px; }
.exp-group { display: grid; gap: 8px; }
.exp-group h4 { margin: 0 0 2px; font-size: 12.5px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.exp-group .exp-add { justify-self: start; font-size: 13px; padding: 6px 10px; }
.var-grid { display: grid; gap: 22px 20px; grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 22px; }
.var-grid small { font-size: 12px; text-transform: none; letter-spacing: 0; font-weight: 400; }
.var-pair { display: grid; grid-template-columns: 120px minmax(0, 1fr); gap: 8px; }
.exp-row.var-deliv { grid-template-columns: minmax(0, 1fr) 140px 190px 36px; }  /* .exp-row объявлен ниже - одиночный класс проигрывал */
#var-deliv-rows { display: grid; gap: 8px; margin-bottom: 8px; }
.var-deliv-head { margin-bottom: 4px; } .var-deliv-head small { font-size: 11.5px; text-transform: none; letter-spacing: 0; }  /* заполненные «30» и «10» без подписи не читаются */
.kpi-note { margin: 10px 2px 0; font-size: 12px; color: var(--muted); }
.beta { font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--accent); background: var(--accent-soft); border-radius: 6px; padding: 1px 5px; margin-left: 4px; vertical-align: middle; }
.beta-banner { font-size: 13px; color: var(--text-2); background: var(--accent-soft); border-radius: 10px; padding: 10px 14px; margin-bottom: 14px; }
.profit-be .kpi-value { margin: 6px 0 4px; }
.profit-record { margin: 0 0 12px; font-size: 15px; }
.be-hist { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 8px; }
.be-m { display: grid; gap: 2px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; font-size: 12px; color: var(--muted); }
.be-m b { font-size: 14px; color: var(--text); }
.goal-pct .up { color: var(--up); } .goal-pct .down { color: var(--down); }
@media (max-width: 600px) { .var-grid { grid-template-columns: 1fr; } .exp-row.var-deliv { grid-template-columns: minmax(0, 1fr) 80px 90px 32px; } }
.exp-row { display: grid; grid-template-columns: minmax(0, 1fr) 160px 36px; gap: 8px; align-items: center; }
.exp-row input { width: 100%; padding: 9px 11px; font-size: 14px; border-radius: 10px; }
.exp-row .exp-sum { font-variant-numeric: tabular-nums; text-align: right; }
.exp-del { padding: 6px 0; text-align: center; }
.exp-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 12px; }
.exp-foot .muted { font-size: 13px; font-variant-numeric: tabular-nums; }
.exp-save { display: flex; align-items: center; gap: 10px; }
#venue-fields { display: grid; gap: 22px 20px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.venue-wide, .venue-hours { grid-column: 1 / -1; }
/* Подписи и зазоры - как у .form-field в Настройках, чтобы формы приложения выглядели одной рукой */
.venue-field { display: flex; flex-direction: column; gap: 8px; }
.venue-field > span { font-size: 12.5px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.venue-seats input { max-width: 120px; }
.venue-sep { grid-column: 1 / -1; font-size: 11.5px; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); border-top: 1px solid var(--line); padding-top: 12px; margin-top: 4px; }  /* потерян при перезаписи style.css соседней сессией 05.09 */
.venue-field textarea { width: 100%; resize: vertical; line-height: 1.5; }
.hours-grid { display: grid; gap: 10px; }
.hours-row { display: grid; grid-template-columns: 30px 132px 14px 132px auto; gap: 10px; align-items: center; }
.hours-row b { font-weight: 600; font-size: 12.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.hours-row i { text-align: center; color: var(--muted); }
.hours-row select { padding: 9px 34px 9px 12px; font-size: 14px; font-variant-numeric: tabular-nums; }
.hours-row.off select { opacity: .45; }
.h-off { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text-2); white-space: nowrap; justify-self: start; margin-left: 6px; cursor: pointer; }
/* Глобальное input { border-radius; padding; width } из .venue-field превращало чекбокс в овал вдали от подписи */
.hours-cap { display: none; }
.h-off input { appearance: auto; -webkit-appearance: checkbox; width: 16px; height: 16px; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; accent-color: var(--accent); }
.kpi .kpi-link { font-size: 15px; font-weight: 600; color: var(--accent); text-decoration: underline; }
@media (max-width: 600px) {
  .exp-row { grid-template-columns: minmax(0, 1fr) 120px 32px; }
  #venue-fields { grid-template-columns: 1fr; }
  /* Один ряд на день (Никита 05.09.2026): слово «выходной» прячем, остаётся галка */
  .hours-row { grid-template-columns: 26px minmax(0, 1fr) 10px minmax(0, 1fr) 20px; gap: 8px; }
  .hours-row select { padding: 9px 28px 9px 10px; }
  .h-off { margin-left: 0; }
  .h-off span { display: none; }
  /* Никита: «и как понять, что это выходной?» - подпись над столбцом галок,
     а отмеченный день сворачивает время и пишет слово */
  .venue-hours > span { display: flex; justify-content: space-between; align-items: baseline; }
  .hours-cap { display: inline; font-style: normal; font-weight: 500; letter-spacing: 0; text-transform: none; font-size: 12px; }
  .hours-row.off select, .hours-row.off i { display: none; }
  .hours-row.off .h-off { grid-column: 2 / -1; justify-self: stretch; justify-content: space-between; flex-direction: row-reverse; padding-right: 4px; /* галка ровно под столбцом (столбец 20px, галка 16) */ }
  .hours-row.off .h-off span { display: inline; color: var(--muted); }
}
.page-head-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
#feed-btn { display: inline-flex; align-items: center; gap: 7px; position: relative; }
#feed-btn .ico { width: 17px; height: 17px; }
.feed-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--danger, #c0492f);
  display: inline-block;
}
.feed-pop {
  border: 1px solid var(--line); background: var(--card); border-radius: var(--radius);
  padding: 8px; margin-bottom: 14px; display: grid; gap: 8px; box-shadow: var(--shadow);
}
.feed-card { padding: 11px 13px; border: 1px solid var(--line); border-radius: var(--radius); }
.feed-card.ask { border-color: var(--accent); background: var(--accent-soft); }
.feed-card .feed-top {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 3px;
}
.feed-card b { font-size: 14px; }
.feed-card small { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.feed-card p { margin: 0; font-size: 13px; color: var(--text-2, var(--muted)); }
.feed-card button { margin-top: 9px; }
@media (max-width: 900px) {
  .feed-btn-label { display: none; }
}

/* ---------- «Задать вопрос» и рассылка админов (05.09.2026, finance-plan фазы 6-7) ---------- */
.ask-btn {
  position: fixed; right: 24px; bottom: 24px; z-index: 60; width: 48px; height: 48px; border-radius: 50%;
  border: 1px solid var(--line); background: var(--card); color: var(--accent); font: inherit; font-size: 20px; font-weight: 700;
  box-shadow: var(--shadow); cursor: pointer;
}
.ask-btn:hover { border-color: var(--accent); }
.ask-btn .feed-dot { position: absolute; top: 4px; right: 4px; }
/* Мини-чат поддержки: прижат к правому нижнему углу над кнопкой «?» (Никита 05.09.2026:
   «должен быть в правом нижнем углу», «в виде чата»). Внутренний отступ - как у .card, 24px. */
.ask-pop {
  position: fixed; right: 24px; bottom: 88px; z-index: 61; width: min(360px, calc(100vw - 48px)); height: min(520px, calc(100vh - 112px));
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 24px; display: flex; flex-direction: column; gap: 12px;
}
.ask-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.ask-head small { display: block; font-size: 12px; margin-top: 2px; }
.ask-log { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 8px; padding: 2px 0; }
.ask-log .ask-msg { font-size: 14px; }
.ask-log .ask-msg small { display: block; margin-top: 4px; font-size: 11px; opacity: .7; }
.ask-empty { margin: auto 0; text-align: center; font-size: 13px; }
.ask-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: end; }
.ask-form textarea { width: 100%; resize: none; max-height: 120px; }
.ask-form .primary { padding: 10px 14px; }
.ask-status { font-size: 12px; min-height: 14px; }
@media (max-width: 767px) {
  .ask-btn { bottom: calc(76px + env(safe-area-inset-bottom)); }
  .ask-pop { right: 0; bottom: 0; width: 100vw; height: 100dvh; border-radius: 0; padding: 20px 16px calc(16px + env(safe-area-inset-bottom)); z-index: 120; }
}
.feed-card.answer { border-color: var(--accent); }
.feed-card p { white-space: pre-line; }
.bc-opts { display: flex; gap: 18px; }
.bc-preview b { display: block; margin-bottom: 4px; }
