/* ============================================================
   Единая система интерфейса. Профиль «Спокойный контроль».

   Ощущение: самостоятельный аналитический продукт, а не встроенный
   кабинет площадки. Почти белый холодный лист, белые карточки,
   насыщенный синий на действии, оранжевый на росте и точках роста,
   зеленый и красный - только на смысле числа.

   Правила:
   1. Глубина: белая карточка на светлом листе плюс мягкая тень.
      Обводка тонкая и только там, где тени мало.
   2. Синий - единственный цвет обычного действия. Оранжевый занимает
      5-8 процентов экрана и означает рост или слабое место, а не «нажми».
   3. Доля цветов: 70 белого и почти белого, 20 нейтрального серо-синего,
      7 синего, 3 оранжевого и статусов. Премиальность дает воздух и
      ограничение палитры, а не темный фон.
   4. Цифры набираются табличными знаками везде, где их сравнивают глазами.
   5. Радиусы крупные: 10 на управлении, 16 на карточках, 20 на слоях.
   ============================================================ */

:root {
  /* ---- бренд ----
     Синий взят из нового знака (НОВЫЙ ЛОГОТИП.png): #1D4ED8.
     Наведение и нажатие - на тон темнее, той же гаммы. */
  --brand-primary: #1D4ED8;
  --brand-primary-hover: #1E40AF;
  --brand-primary-pressed: #1E3A8A;
  --brand-primary-soft: #EFF6FF;
  --brand-primary-border: #BFDBFE;

  /* ---- акцент: только вмешательство ---- */
  --accent-orange: #F97316;
  --accent-orange-dark: #C2410C;
  --accent-orange-soft: #FFF7ED;
  --accent-orange-border: #FED7AA;

  /* ---- второй акцент: сине-голубое ----
     Забирает у рыжего все, что не про беду: второй ряд графика, линию,
     полоску, заливку отмеченной плитки. Цвет не новый, он уже нарисован
     третьей ступенью синей шкалы и полоской выбранного пункта панели. */
  --accent-sky: #60A5FA;
  --accent-sky-soft: var(--brand-primary-soft);
  --accent-sky-line: var(--brand-primary-border);

  /* ---- рыжий: только вмешательство ----
     Имя говорит, когда его брать: не «рост», не «важное», не «наш второй
     цвет», а «человеку надо вмешаться». Нет вмешательства - нет цвета. */
  --attention: var(--accent-orange);
  --attention-ink: var(--accent-orange-dark);
  --attention-soft: var(--accent-orange-soft);
  --attention-line: var(--accent-orange-border);

  /* ---- поверхности ---- */
  --bg-app: #F6F8FC;
  --bg-surface: #FFFFFF;
  --bg-subtle: #F8FAFC;
  --bg-hover: #F1F5F9;
  --bg-selected: #EFF6FF;

  /* ---- текст ---- */
  --text-heading: #172033;
  --text-primary: #334155;
  --text-secondary: #64748B;
  --text-muted: #94A3B8;
  --text-disabled: #CBD5E1;
  --text-link: #1D4ED8;

  /* ---- границы ---- */
  --border-default: #E2E8F0;
  --border-strong: #CBD5E1;

  /* ---- статусы ---- */
  --success: #15803D;
  --success-soft: #F0FDF4;
  --success-border: #BBF7D0;
  --warning: #B45309;
  --warning-soft: #FFFBEB;
  --warning-border: #FDE68A;
  --error: #DC2626;
  --error-soft: #FEF2F2;
  --error-border: #FECACA;
  --info: #1D4ED8;
  --info-soft: #EFF6FF;

  /* ---- ряды графиков ---- */
  --chart-blue: #1D4ED8;
  --chart-orange: #F97316;
  --chart-green: #16A34A;
  --chart-purple: #7C3AED;
  --chart-cyan: #0891B2;
  --chart-yellow: #D97706;
  --chart-red: #DC2626;
  --chart-gray: #64748B;

  /* ---- порядок рядов графика ----
     Ряды берутся строго по порядку, с первого, пропускать нельзя: порядок и
     есть то, что делает их различимыми. Первые три - один тон, разведенный
     только светлотой, поэтому их различает и черно-белая печать, и человек с
     любым видом дальтонизма. Яркости соседних расходятся в 2,6, 4,1, 2,8 и
     1,55 раза, а у пятого с шестым только в 1,2 - значит, цветом различаются
     четыре ряда, дальше идет серое «Прочее». Фиолетовый стоит пятым, а не
     вторым: при дейтеранопии он похож на синий, и пока рядов четыре, он не
     появляется вовсе. Рыжего в рядах нет: ряд графика - это категория, а не
     тревога. */
  --chart-1: var(--brand-primary);           /* #1D4ED8 синий */
  --chart-2: var(--accent-sky);              /* #60A5FA голубой */
  --chart-3: var(--brand-primary-pressed);   /* #1E3A8A темно-синий */
  --chart-4: var(--chart-cyan);              /* #0891B2 бирюзовый */
  --chart-5: var(--chart-purple);            /* #7C3AED фиолетовый */
  --chart-6: var(--chart-gray);              /* #64748B серый, всегда «Прочее» */

  /* ---- синяя шкала: пять ступеней одного тона ----
     Там, где число красится насыщенностью, а не цветом: тепловая карта
     часов. Яркость соседних ступеней отличается в 1,5-1,8 раза, поэтому
     шкала читается и на черно-белой печати. Числа отсюда берет sheets.js,
     своего списка он больше не держит. */
  --blue-1: var(--brand-primary-soft);       /* #EFF6FF */
  --blue-2: var(--brand-primary-border);     /* #BFDBFE */
  --blue-3: var(--accent-sky);               /* #60A5FA */
  --blue-4: var(--brand-primary);            /* #1D4ED8 */
  --blue-5: var(--brand-primary-pressed);    /* #1E3A8A */

  /* Метки модулей. Нужны графикам, значкам и тегам внутри аналитики.
     В левом меню не применяются: там все пункты серые, активный синий.
     Метки «Слабых мест» здесь нет: она красила раздел рыжим в покое, а
     рыжий обещает беду только тогда, когда беда случилась. */
  --mod-autoload: var(--chart-blue);
  --mod-bidder: var(--chart-purple);
  --mod-rivals: var(--chart-cyan);
  --mod-hours: var(--chart-yellow);

  /* ---- Рабочие имена, которыми пользуется вся разметка ----
     Один слой псевдонимов вместо переименования тысячи строк: смысл
     остался прежним, значение теперь берется из палитры выше. */
  --canvas: var(--bg-app);
  --surface: var(--bg-surface);
  --sunken: var(--bg-subtle);
  --sunken-2: var(--bg-hover);

  --ink: var(--text-heading);
  --ink-2: var(--text-primary);
  --ink-3: var(--text-secondary);
  --ink-4: var(--text-muted);

  --line: var(--border-default);
  --line-soft: #EFF3F9;
  --line-strong: var(--border-strong);

  --blue: var(--brand-primary);
  --blue-dark: var(--brand-primary-hover);
  --blue-deep: var(--text-link);
  --blue-press: var(--brand-primary-pressed);
  --blue-soft: var(--brand-primary-soft);
  --blue-line: var(--brand-primary-border);

  --green: var(--chart-green);
  --green-ink: var(--success);
  --green-soft: var(--success-soft);
  --alarm: var(--error);
  --alarm-soft: var(--error-soft);
  --warn: var(--warning);
  --warn-soft: var(--warning-soft);
  --violet: var(--chart-purple);

  --control: var(--bg-subtle);
  --control-line: var(--border-strong);
  --focus: rgba(29, 78, 216, 0.20);

  /* Старые имена, на которые ссылается разметка внутри скриптов.
     Держим их живыми, иначе цвет молча теряется и текст падает в черный. */
  --green-dark: var(--success);
  --dim: var(--text-secondary);

  --r-s: 10px;   /* кнопки, поля */
  --r-m: 16px;   /* карточки */
  --r-l: 20px;   /* всплывающие слои */

  --shadow-card: 0 1px 3px rgba(15, 23, 42, 0.06), 0 4px 12px rgba(15, 23, 42, 0.04);
  --shadow-lift: 0 2px 6px rgba(15, 23, 42, 0.06), 0 12px 28px rgba(15, 23, 42, 0.10);
  --shadow-pop: 0 12px 40px rgba(15, 23, 42, 0.18);

  /* Пара шрифтов, 9 сентября 2026.

     Заголовки - Onest. Рисовали под длинные официальные названия и мелкие
     экраны, кириллица родная, лицензия свободная. Он и дает кабинету лицо:
     раздел читается как заголовок даже боковым зрением.

     Текст и числа - Golos Text. Авторы те же, что у PT Sans, кириллица
     родная, есть табличные цифры: в столбце сумм знаки стоят строго друг
     под другом, единица не оставляет дыру. Для кабинета, где половина
     экрана - числа, это важнее характера.

     Inter убран намеренно. Его кириллицу разбирал type.today и отказал по
     конкретным буквам (обратный контраст в И, У, к; ошибки в б, Д, Ц, Щ,
     Л, Ч, Э) - на словах «Автозагрузка» и «Анализ конкурентов» это видно.
     И он стоит по умолчанию у всего машинно сгенерированного: владелец
     смотрел на кабинет и говорил, что в нем проглядываются следы.

     Все файлы свои, в web/fonts, см. fonts.css. Geologica осталась там же
     запасной: чтобы поменять пару, хватит этих двух строк. */
  --display: Onest, 'Golos Text', -apple-system, "Segoe UI", Arial, sans-serif;
  --body: 'Golos Text', Onest, -apple-system, "Segoe UI", Arial, sans-serif;

  /* ---- Типографическая шкала: семь ступеней, восьмой нет ----

     Раньше кегли набирались по месту: 32, 28, 25, 22, 19, 17, 15, 14, 13,5,
     12,5, 12, 11,5, 11, 10,5, 9,5. Между соседними по половине пиксела -
     различить их нельзя, и экран читается ровным серым полем. Ниже семь
     ступеней из листа дизайнера, и это весь набор. Если размер не нашелся,
     значит блок стоит не на своем уровне поверхности, а не шкала мала.

     У ступени четыре свойства - кегль, интерлиньяж, вес и межбуквенное.
     Берутся вместе: кегль без веса ступени не делает.

     Заголовок экрана и заголовок блока набираются Onest (--display), все
     остальное, включая заголовок карточки и числа, - Golos Text (--body).
     Голос раздела звучит один раз за экран и один раз над блоком; пустить
     его внутрь карточек значит превратить голос в фон. */

  /* заголовок экрана: один h1 на экран, на голом холсте */
  --t-screen: 34px;   --t-screen-lh: 40px;   --t-screen-w: 800;   --t-screen-ls: -0.03em;
  /* заголовок блока: h2 над карточкой, тоже на холсте */
  --t-block: 20px;    --t-block-lh: 26px;    --t-block-w: 700;    --t-block-ls: -0.02em;
  /* заголовок карточки: h3 внутри белой карточки */
  --t-card: 15px;     --t-card-lh: 20px;     --t-card-w: 600;     --t-card-ls: -0.01em;
  /* крупное число: одно на карточку, всегда табличными знаками */
  --t-figure: 40px;   --t-figure-lh: 40px;   --t-figure-w: 700;   --t-figure-ls: -0.02em;
  /* обычный текст: абзацы и подпись под заголовком экрана */
  --t-text: 15px;     --t-text-lh: 22px;     --t-text-w: 400;     --t-text-ls: 0;
  /* подпись: строка следствия, ячейки таблиц, кнопки */
  --t-note: 13px;     --t-note-lh: 18px;     --t-note-w: 400;     --t-note-ls: 0;
  /* микроподпись: шапка таблицы, метка группы в панели, прописными */
  --t-micro: 11px;    --t-micro-lh: 14px;    --t-micro-w: 600;    --t-micro-ls: 0.06em;

  /* Два уточнения внутри ступеней. Своих кеглей они не заводят: первое -
     крупное число, ужатое до плитки, второе - подпись, которой добавили
     полтона веса, чтобы число в ячейке отделилось от текста без единой
     линии. */
  --t-tile: 24px;     --t-tile-lh: 28px;
  --t-cell-w: 500;

  /* Не ступень, а порог. Поле мельче 16px телефон приближает на фокусе, и
     верстка уезжает вбок. Живет только в правилах под 760. */
  --t-field-mobile: 16px;

  /* шаг сетки 4px */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s6: 24px; --s8: 32px; --s12: 48px;

  /* Оболочка. Панель идет от пола до потолка, поэтому --brand больше не
     полоса бренда во всю ширину: это высота белой строки на телефоне. */
  --side: 232px;
  --head: 72px;
  --brand: 64px;

  /* Рабочая колонка: одна ширина на все, что стоит справа от панели -
     верхнюю строку, содержимое и подвал. Сам потолок 1580 включается
     только с 1812 в окне (232 панели плюс колонка), но экран меняется на
     всех ширинах: вместе с этой колонкой сняты прежние потолки 1080 у
     шапки раздела и панелей, 1180 у подвала и 760 у карточки расширения.
     До правки на одном экране жили три ширины и два выравнивания -
     шапка прижата влево, карточка во всю ширину, подвал по центру.
     Число взято из макета, принятого владельцем; при поле 32 внутри
     остается 1516, а широкие таблицы листаются в своей коробке.
     --work-pad - поле этой колонки. По нему же считается ширина подвала,
     поэтому менять поле надо здесь, а не у каждого блока. Ниже 1150 оно
     становится 24, ниже 760 - 16 (workspace.css). */
  --work-max: 1580px;
  --work-pad: var(--s8);

  /* ---- темная боковая панель ----
     Панель красится нашей же чернилой: #172033 - это --text-heading, цвет,
     которым набраны все заголовки кабинета. Свой токен вместо чужого фона.
     Контраст к фону панели: белый 16,3, --sidebar-ink 11,0,
     --sidebar-muted 6,3, --sidebar-mark 6,4. Ниже нормы 4,5 не опускаемся,
     --text-secondary на панели текстом не ставим (3,4). */
  --sidebar-bg: #172033;         /* = --text-heading */
  --sidebar-ink: #CBD5E1;        /* = --text-disabled, текст пункта */
  --sidebar-muted: #94A3B8;      /* = --text-muted, подписи групп и вторые строки */
  --sidebar-selected: #1E40AF;   /* = --brand-primary-hover, подложка выбранного */
  --sidebar-mark: var(--accent-sky);  /* полоска выбранного, она же третья ступень синей шкалы */
  --sidebar-line: #334155;       /* = --text-primary, разделители внутри панели */
  --sidebar-hover: rgba(255, 255, 255, 0.06);
  --sidebar-scrim: rgba(23, 32, 51, 0.45);  /* = --text-heading, 45 % */
}

/* Телефон. Из семи ступеней меняются три, остальные держатся: подпись в 13
   не уменьшается никогда, это дно. Переопределяется здесь один раз, поэтому
   своих телефонных кеглей у отдельных блоков больше нет. */
@media (max-width: 760px) {
  :root {
    --t-screen: 26px;   --t-screen-lh: 30px;
    --t-block: 18px;    --t-block-lh: 24px;
    --t-figure: 32px;   --t-figure-lh: 34px;
  }
}

*, *::before, *::after { box-sizing: border-box; }

html { color-scheme: light; }

/* Кому тяжело от движения, тому его и не показываем */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* На касании не ждем полсекунды перед нажатием */
button, .btn, .pill, .fsel, a { touch-action: manipulation; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--blue); color: #fff; padding: 10px 16px; border-radius: 0 0 var(--r-s) 0;
}
.skip:focus { left: 0; text-decoration: none; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--body);
  font-size: var(--t-text);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

/* Заголовки по ступеням шкалы. Onest звучит на экране и над блоком, внутри
   карточки набирает Golos: голос раздела, пущенный в фон, перестает быть
   голосом. Кегли, веса и межбуквенное берутся из токенов, чтобы менять их
   в одном месте, а не в полусотне правил. */
h1, h2, h3, h4 { margin: 0; }
h1 {
  font-family: var(--display); font-size: var(--t-screen); line-height: var(--t-screen-lh);
  font-weight: var(--t-screen-w); letter-spacing: var(--t-screen-ls);
}
h2 {
  font-family: var(--display); font-size: var(--t-block); line-height: var(--t-block-lh);
  font-weight: var(--t-block-w); letter-spacing: var(--t-block-ls);
}
h3, h4 {
  font-family: var(--body); font-size: var(--t-card); line-height: var(--t-card-lh);
  font-weight: var(--t-card-w); letter-spacing: var(--t-card-ls);
}
a { color: var(--blue-deep); text-decoration: none; }
a:hover { text-decoration: underline; }
.hidden { display: none !important; }

/* Цифры одной ширины везде, где они сравниваются глазами */
.num, table, input, .kpi__v, .fun__v, .ind__v, .hub__v,
.step__v, .bid__v, .bid__pos, .portfolio-stat strong, .item-card dd, .money {
  font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1;
}

/* Знак рубля на тон тише самого числа: числу достается вес, знаку - место.
   Мелочь, которая повторяется в кабинете тысячу раз и каждый раз чуть-чуть
   убирает шум. Разметку ставит money.js, тут только цвет.
   Вес выравниваем отдельно: внутри жирного числа знак наследовал бы 700. */
.rub { color: var(--text-secondary); font-weight: var(--t-text-w); }
/* Два места, где тише не значит серее. На чернильной панели --text-secondary
   дает к фону 3,4 - ниже нормы, там знак живет цветом строки. И внутри
   строки, у которой цвет уже что-то значит: серый кусок в красном числе
   читался бы как чужой. */
.side .rub, .nav .rub, .switch .rub, .switchpop .rub,
.hub__bad .rub, .delta .rub, .plus .rub, .minus .rub { color: inherit; }


::selection { background: var(--blue); color: #fff; }
:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 4px; }

/* ---------- кнопки ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  font: inherit; font-weight: 700; font-size: var(--t-note);
  color: #fff; background: var(--blue);
  border: 1px solid var(--blue); border-radius: var(--r-s);
  padding: 9px 18px; cursor: pointer; white-space: nowrap;
  transition: background .14s ease, border-color .14s ease, box-shadow .14s ease;
}
.btn:hover { background: var(--blue-dark); border-color: var(--blue-dark); text-decoration: none; }
.btn:active { background: var(--blue-press); border-color: var(--blue-press); }
.btn:disabled, .btn[disabled] { opacity: .45; cursor: default; }
.btn:disabled:hover, .btn[disabled]:hover { background: var(--blue); border-color: var(--blue); }
.btn--light { color: var(--ink); background: var(--surface); border-color: var(--line-strong); }
.btn--light:hover { background: var(--sunken); border-color: var(--line-strong); color: var(--ink); }
/* Выключенная светлая кнопка при наведении синела: .btn:disabled:hover выше
   возвращает брендовый фон всем кнопкам разом. Специфичность равная, поэтому
   хватает порядка строк - правило ниже, значит оно и берет. */
.btn--light:disabled:hover, .btn--light[disabled]:hover { background: var(--surface); border-color: var(--line-strong); color: var(--ink); }
.btn--ghost { color: var(--ink-2); background: transparent; border-color: transparent; }
.btn--ghost:hover { background: var(--sunken-2); border-color: transparent; color: var(--ink); }
.btn--wide { width: 100%; }
.btn--sm { padding: 7px 14px; font-size: var(--t-note); }
/* Разрушительное действие: удалить правило, группу, план. Синий в кабинете
   значит «сделать», и «Удалить» тем же синим, что «Включить» и «Подключить»,
   стирало разницу между «запустить» и «стереть навсегда». Цвет берем из
   статусов, а не из бренда.
   Темнее красного в палитре нет, а новый hex заводить нельзя (правило 1),
   поэтому наведение и нажатие затемняют тот же токен фильтром. */
.btn--danger { background: var(--alarm); border-color: var(--alarm); color: #fff; }
.btn--danger:hover { background: var(--alarm); border-color: var(--alarm); color: #fff; filter: brightness(.92); }
.btn--danger:active { background: var(--alarm); border-color: var(--alarm); filter: brightness(.86); }
/* Правило .btn:disabled:hover выше возвращает брендовый фон всем кнопкам
   разом: выключенная красная кнопка синела под курсором. Специфичность
   равная, поэтому хватает порядка строк. */
.btn--danger:disabled, .btn--danger[disabled] { filter: none; }
.btn--danger:disabled:hover, .btn--danger[disabled]:hover { background: var(--alarm); border-color: var(--alarm); filter: none; }

/* ---------- поля ---------- */

.field { margin-bottom: var(--s3); }
.field label { display: block; font-size: var(--t-note); font-weight: 600; color: var(--ink-2); margin-bottom: 5px; }
.field .hint, .note { font-size: var(--t-note); color: var(--ink-2); line-height: 1.5; margin: var(--s2) 0 0; }
/* На 1440 пояснение под широкой таблицей вставало в одну строку на полтораста
   знаков, и глаз терял начало следующей. Меру берем ту же, что у подписи
   раздела (.sheet__head p, 74ch), с запасом на мелкий кегль. */
.note { max-width: 92ch; }

input[type="text"], input[type="password"], input[type="date"], input[type="number"], input[type="email"], textarea, select {
  width: 100%; font: inherit; font-size: var(--t-text); color: var(--ink);
  background: var(--control); border: 1px solid var(--control-line);
  border-radius: var(--r-s); padding: 10px 12px;
  transition: border-color .14s ease, box-shadow .14s ease, background .14s ease;
}
input::placeholder, textarea::placeholder { color: var(--ink-4); }
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px var(--focus); background: var(--surface); }

/* ---------- сообщения ---------- */

.msg { border-radius: var(--r-s); padding: 10px 13px; font-size: var(--t-note); margin-top: var(--s3); }
.msg--err { background: var(--alarm-soft); color: var(--alarm); }
.msg--ok { background: var(--green-soft); color: var(--green-ink); }
.msg--wait { background: var(--sunken-2); color: var(--ink-2); }
.empty, .loading { padding: var(--s8) var(--s4); text-align: center; color: var(--ink-2); }
.sep { height: 1px; background: var(--line); margin: var(--s6) 0; }
.right { text-align: right; }
.nowrap { white-space: nowrap; }

/* ---------- вход ----------

   Экран в два крыла: слева фирменная панель на градиенте бренда со знаком
   и тезисами, справа форма на светлом листе. Все цвета из токенов:
   градиент это три ступени брендового синего. */

.gate {
  min-height: 100vh; display: flex; background: var(--canvas);
}
.gate__brand {
  flex: 1 1 46%; display: flex; align-items: center; justify-content: center;
  padding: var(--s12) var(--s8);
  background: linear-gradient(150deg,
    var(--brand-primary) 0%,
    var(--brand-primary-hover) 55%,
    var(--brand-primary-pressed) 100%);
  color: var(--bg-surface);
}
.gate__brandin { max-width: 420px; }
.gate__mark { display: block; border-radius: 18px; box-shadow: var(--shadow-lift); }
.gate__name {
  font-family: var(--display); font-size: var(--t-tile); font-weight: 700;
  margin-top: var(--s4); letter-spacing: .01em;
}
.gate__tag { margin: 4px 0 0; font-size: var(--t-text); opacity: .85; }
.gate__points { list-style: none; margin: var(--s8) 0 0; padding: 0; display: grid; gap: var(--s3); }
.gate__points li {
  position: relative; padding-left: 30px; font-size: var(--t-text); line-height: 1.5; opacity: .95;
}
.gate__points li::before {
  content: "✓"; position: absolute; left: 0; top: 1px;
  width: 19px; height: 19px; border-radius: 50%;
  background: rgba(255, 255, 255, .18);
  font-size: var(--t-micro); font-weight: 700; display: grid; place-items: center;
}
.gate__art { display: block; width: 100%; max-width: 460px; height: auto; margin-top: var(--s8); }
.gate__side {
  flex: 1 1 54%; display: grid; place-items: center; padding: var(--s6);
}
.gate__card {
  width: 100%; max-width: 430px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-l); padding: var(--s8);
  box-shadow: var(--shadow-lift);
}

/* Узкий экран: панель складывается в шапку, тезисы прячутся,
   форма занимает всю ширину. */
@media (max-width: 960px) {
  .gate { flex-direction: column; }
  .gate__brand { flex: none; justify-content: flex-start; padding: var(--s4) var(--s6); }
  .gate__brandin { max-width: none; display: flex; align-items: center; gap: var(--s3); }
  .gate__mark { width: 44px; height: 44px; border-radius: 12px; box-shadow: none; }
  .gate__name { font-size: var(--t-tile); margin-top: 0; }
  .gate__tag { margin: 0; font-size: var(--t-note); }
  .gate__points, .gate__art { display: none; }
  .gate__side { flex: 1; align-content: start; padding-top: var(--s8); }
}
.gate__card h1 { font-size: var(--t-screen); margin-bottom: 6px; }
.gate__card .sub { margin: 0 0 var(--s6); color: var(--ink-2); font-size: var(--t-text); }
.gate__lock { font-size: var(--t-note); color: var(--ink-3); line-height: 1.5; margin-top: var(--s4); }
/* Дорога к настройкам входа прямо с ворот: без нее человек с пустым
   кабинетом не мог добраться ни до телеграма, ни до смены пароля. */
.gate__check {
  display: flex; align-items: center; gap: 8px; font-size: var(--t-note);
  color: var(--ink-2); margin: 0 0 var(--s3);
}
.gate__check input { width: 16px; height: 16px; accent-color: var(--blue); }
.gate__link { display: inline-block; margin-top: 6px; font-weight: 600; }

/* ============================================================
   Список клиентов: первый экран после пароля
   ============================================================ */

.hub { min-height: 100vh; padding: var(--s12) var(--s6); }
.hub__head {
  margin: 0 0 var(--s6);
  display: flex; align-items: center; justify-content: space-between; gap: var(--s4); flex-wrap: wrap;
}
.hub__head h1 { font-size: var(--t-screen); }
.hub__row { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }

.hub__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr)); gap: var(--s4);
}
.hub__card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
  padding: var(--s4) var(--s4) var(--s3);
  display: flex; flex-direction: column; gap: var(--s3);
  box-shadow: var(--shadow-card);
  transition: box-shadow .16s ease, transform .16s ease;
}
.hub__card:hover { box-shadow: var(--shadow-lift); transform: translateY(-1px); }

.hub__top { display: flex; align-items: center; gap: var(--s3); }
.hub__ava {
  width: 44px; height: 44px; flex: none; border-radius: 50%;
  color: #fff; font-weight: 800; font-size: var(--t-text); display: grid; place-items: center;
}
.hub__who { min-width: 0; }
.hub__name {
  font-weight: 700; font-size: var(--t-text); line-height: 1.25;
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.hub__id { font-size: var(--t-micro); color: var(--ink-3); margin-top: 2px; }
.hub__note-own { opacity: .8; font-style: italic; }

.hub__facts {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s2);
  padding: var(--s3); background: var(--sunken); border-radius: var(--r-s);
}
.hub__fact { min-width: 0; }
.hub__k { font-size: var(--t-micro); color: var(--ink-3); white-space: nowrap; }
.hub__v { font-size: var(--t-text); font-weight: 800; margin-top: 2px; white-space: nowrap; }
.hub__wait { color: var(--ink-4); font-weight: 400; }
.hub__bad { color: var(--alarm); }

/* Подвал прижат к низу: карточки в ряду разной высоты из-за длины имени,
   а кнопка «Открыть» должна стоять на одной линии во всем ряду. */
.hub__foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.hub__note { font-size: var(--t-micro); color: var(--ink-3); line-height: 1.35; }
.hub__note .ic { width: 13px; height: 13px; margin-right: 4px; vertical-align: -2px; }
.hub__open .ic { margin-left: 5px; }
.hub__x .ic, .hub__add .ic { margin-right: 6px; }
/* Список клиентов: пустой экран стоит в белой карточке, как и раньше */
.hub .art {
  max-width: none; margin: 0; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-m); box-shadow: var(--shadow-card);
}
.hub__note--ok { color: var(--green-ink); }
.hub__note--bad { color: var(--alarm); }

.hub__open, .hub__add {
  font: inherit; font-size: var(--t-note); font-weight: 700; color: #fff;
  background: var(--blue); border: 1px solid var(--blue); border-radius: var(--r-s);
  padding: 9px 17px; cursor: pointer; white-space: nowrap;
  transition: background .14s ease, border-color .14s ease;
}
.hub__open:hover, .hub__add:hover { background: var(--blue-dark); border-color: var(--blue-dark); }
.hub__tools { display: flex; gap: 2px; margin-top: -6px; }
.hub__x {
  font: inherit; font-size: var(--t-note); font-weight: 600; color: var(--ink-3);
  background: none; border: 0; padding: 5px 8px; border-radius: 7px; cursor: pointer;
}
.hub__x:hover { color: var(--blue-deep); background: var(--blue-soft); }
/* В шапке списка это полноценное действие, а не мелкая ссылка у карточки */
.hub__head .hub__x {
  font-size: var(--t-note); padding: 9px 16px; border-radius: var(--r-s);
  background: var(--surface); border: 1px solid var(--line-strong); color: var(--ink);
}
.hub__head .hub__x:hover { background: var(--sunken); color: var(--ink); }
.hub__tools .hub__x:last-child:hover { color: var(--alarm); background: var(--alarm-soft); }

.hub__empty {
  margin: 0 0 var(--s4); padding: var(--s8);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
  box-shadow: var(--shadow-card); color: var(--ink-2);
}
.hub__form {
  max-width: 480px; margin: var(--s6) auto 0; padding: var(--s6);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
  box-shadow: var(--shadow-card);
}
.hub__h2 { font-family: var(--display); font-weight: 700; margin: 0 0 var(--s3); font-size: var(--t-block); }
.hub__field { margin-bottom: var(--s3); }
.hub__field label { display: block; font-size: var(--t-note); font-weight: 600; color: var(--ink-2); margin-bottom: 5px; }
.hub__hint { font-size: var(--t-note); color: var(--ink-3); line-height: 1.45; margin: var(--s2) 0 0; }
.hub__msg { border-radius: var(--r-s); padding: 9px 12px; font-size: var(--t-note); margin-top: var(--s2); }
.hub__msg--err { background: var(--alarm-soft); color: var(--alarm); }
.hub__msg--ok { background: var(--green-soft); color: var(--green-ink); }
.hub__msg--wait { background: var(--sunken-2); color: var(--ink-2); }

/* ============================================================
   Каркас приложения: темная панель от пола до потолка, справа
   рабочая область.

   Полосы бренда во всю ширину больше нет: знак стоит в самой панели.
   Раньше белая колонка держала высоту `100vh - 62px` и на длинной
   странице обрывалась - под ней проступал лист. Панель во всю высоту
   окна не кончается нигде.
   ============================================================ */

.app {
  position: relative;
  display: grid;
  grid-template-columns: var(--side) minmax(0, 1fr);
  grid-template-rows: minmax(0, 1fr);
  min-height: 100vh;
}
/* Столбец панели закрашен на всю высоту страницы, а не только окна. Сама
   панель липкая и высотой в окно, поэтому глазами шва не видно никогда, но
   на снимке всей страницы и на печати под ней проступал бы лист. Заливка
   ровная, одной краской: ни градиента, ни тени тут нет. */
.app::before {
  content: ''; position: absolute; z-index: 0;
  left: 0; top: 0; bottom: 0; width: var(--side);
  background: var(--sidebar-bg);
}

/* Полоса бренда осталась только телефону: там она несет бургер и знак,
   а панель выезжает из-под нее. На десктопе ее место занял верх панели. */
.brandbar {
  display: none;
  grid-column: 1 / -1;
  position: sticky; top: 0; z-index: 30;
  min-height: var(--brand);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  align-items: center; gap: var(--s3);
  padding: var(--s2) var(--s6) var(--s2) var(--s4);
}
.brandbar__logo { display: inline-flex; align-items: center; }
/* Знак повторяет значок вкладки: один образ везде. */
.brandbar__mark { width: 28px; height: 28px; flex: none; border-radius: 8px; }
.brandbar__spacer { flex: 1 1 auto; }

.brandbar__back {
  font: inherit; font-size: var(--t-note); font-weight: 600; color: var(--ink-2);
  background: var(--sunken); border: 1px solid transparent; border-radius: var(--r-s);
  padding: 8px 14px; cursor: pointer; white-space: nowrap;
  transition: background .14s ease, color .14s ease;
}
.brandbar__back:hover { background: var(--blue-soft); color: var(--blue-deep); }

/* карточка клиента справа: кружок с инициалами, имя, номер */
.brandbar__who { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
.brandbar__ava {
  width: 34px; height: 34px; flex: none; border-radius: 50%;
  background: var(--blue);
  color: #fff; font-weight: 800; font-size: var(--t-note); display: grid; place-items: center;
}
.brandbar__lines { min-width: 0; line-height: 1.25; }
.brandbar__name {
  font-size: var(--t-note); font-weight: 700; max-width: 220px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.brandbar__id { font-size: var(--t-micro); color: var(--ink-3); }

/* Боковая панель: темная, во всю высоту окна, разделы группами */
.side {
  grid-column: 1; grid-row: 1;
  display: flex; flex-direction: column;
  background: var(--sidebar-bg);
  color: var(--sidebar-ink);
  padding: var(--s6) 14px var(--s4);
  position: sticky; top: 0; align-self: start;
  height: 100vh; overflow-y: auto;
  scrollbar-width: thin;
  /* Светлая полоса прокрутки на чернильном фоне читалась бы как царапина */
  scrollbar-color: var(--sidebar-line) transparent;
}

/* Знак переехал из полосы бренда сюда: продукт называет себя в том углу,
   где стоит его инструмент, а не отдельной строкой над всем экраном. */
.side__brand { display: flex; align-items: center; gap: 10px; padding: 0 var(--s2) var(--s6); }
.side__mark { width: 32px; height: 32px; flex: none; border-radius: 9px; }
.side__word {
  min-width: 0; font-size: var(--t-block); font-weight: 750; letter-spacing: -.05em;
  line-height: 1.1; color: #FFFFFF;
}
.side__word span {
  display: block; font-size: var(--t-micro); font-weight: 500; letter-spacing: .1em;
  color: var(--sidebar-muted); margin-top: 4px;
}

.nav { display: flex; flex-direction: column; gap: 3px; }
.nav__group {
  font-size: var(--t-micro); line-height: var(--t-micro-lh); font-weight: var(--t-micro-w);
  letter-spacing: var(--t-micro-ls); text-transform: uppercase;
  color: var(--sidebar-muted); padding: 20px 10px var(--s2);
}
.nav__group:first-child { padding-top: var(--s1); }
.nav button {
  position: relative;
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 40px;
  padding: 9px 10px; border: 0; background: none; border-radius: 9px;
  cursor: pointer; text-align: left; font: inherit; font-size: var(--t-note); font-weight: 500;
  color: var(--sidebar-ink);
  transition: background .13s ease, color .13s ease;
}
.nav button:hover { background: var(--sidebar-hover); color: #FFFFFF; }
/* Обводка уходит внутрь: у края панели наружную срезало бы */
.nav button:focus-visible { outline: 2px solid var(--sidebar-mark); outline-offset: -2px; }
.nav button.is-on { background: var(--sidebar-selected); color: #FFFFFF; font-weight: 600; }
/* Полоска слева: подложка выбранного дает к фону панели всего 1,9, и
   заметным выбор делает именно она - боковым зрением, без вчитывания. */
.nav button.is-on::before {
  content: ""; position: absolute; left: 0; top: var(--s2); bottom: var(--s2);
  width: 3px; border-radius: 0 3px 3px 0; background: var(--sidebar-mark);
}
/* Значок голый, без плитки: разделы в меню равны по весу, и цветной
   квадрат обещал бы одному из них важность, которой у него нет. */
.nav__i { width: 20px; height: 20px; flex: none; opacity: .75; transition: opacity .13s ease; }
.nav button:hover .nav__i, .nav button.is-on .nav__i { opacity: 1; }
.nav__t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Вид переключателя аккаунта на темной панели держит workspace.css: там он
   уже написан через #clientSwitch, и второе правило отсюда до него не дошло. */

/* рабочая область */
.work { grid-column: 2; grid-row: 1; min-width: 0; display: flex; flex-direction: column; }

/* Верхняя строка: слева свежесть данных, справа период и сбор снимка.
   Причина и лекарство в одной строке - о том, на какое время посчитаны
   цифры, говорим там, где стоит кнопка «Обновить данные». */
.top {
  position: sticky; top: 0; z-index: 20;
  background: var(--canvas);
  border-bottom: 1px solid var(--line);
}
/* Полоса тянется во всю рабочую область, а ее содержимое стоит в общей
   колонке: линия снизу отделяет строку от листа, а название раздела и
   кнопки начинаются там же, где шапка раздела и карточки под ней. */
.top__in {
  width: 100%; max-width: var(--work-max); margin-inline: auto;
  min-height: var(--head); padding: var(--s2) var(--work-pad);
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
}
.top__title { display: flex; align-items: center; gap: 7px; min-width: 0; }
.top__tools { margin-left: auto; display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
/* Строки нет вовсе, когда в ней нечего показать: на общих инструментах
   ни свежести, ни периода нет, а пустая полоса с линией снизу читается
   как оборванный блок. Браузеру без :has() строка остается видимой. */
.top:not(:has(.top__in > #stale:not(.hidden))):not(:has(.top__in > #pageTitle > *)):not(:has(.top__tools > :not(.hidden))) {
  display: none;
}

/* Потолок по ширине один на всех - --work-max. Раньше его не было вовсе, и
   на широком мониторе шапка раздела кончалась на 1344, карточка тянулась до
   1888, а подвал стоял своей колонкой посередине: три ширины и два
   выравнивания на одном экране. Теперь содержимое и подвал держат одну
   колонку и центруются равными полями. Разъехаться внутри нее не дают сами
   блоки: карточки идут сеткой, таблицы листаются внутри своей коробки, у
   абзацев своя мера строки. */
/* Строка свежести данных. Стоит в верхней строке слева, точкой и одной
   фразой: полосы во всю ширину под шапкой больше нет, отдельный слой ради
   одного предложения экран только резал.

   Форма и цвет общие с остальным кабинетом (.state ниже по файлу): серая
   точка значит «сейчас ничего не происходит, числа не сегодняшние». Раньше
   тут стоял свой коричневый цвет и своя точка на 8 - пятая форма состояния
   на тех же экранах. Слово не красится: цвет уже сказала точка. */
.stale {
  display: flex; align-items: baseline; gap: var(--s2); min-width: 0; flex: 1 1 260px;
  font-size: var(--t-note); line-height: var(--t-note-lh); color: var(--ink-2);
  overflow-wrap: anywhere;
}
.stale::before {
  content: ''; flex: none; width: 6px; height: 6px; border-radius: 50%;
  transform: translateY(-2px); background: var(--border-strong);
}

.main { width: 100%; max-width: var(--work-max); margin-inline: auto; padding: var(--s6) var(--work-pad); }

/* Пара блоков в ряд на широком экране. Раньше воронка, показатели и узкие
   карточки шли друг под другом во всю ширину, и справа оставалось пустое
   поле в пол-экрана. Ниже 1360 они снова встают столбиком. */
.cols2 { display: grid; gap: var(--s8); align-items: start; }
/* Без этого широкая таблица внутри колонки не дает ей сжаться и растягивает
   всю страницу: у ячейки грида ширина по содержимому, а не по колонке. */
.cols2 > * { min-width: 0; }
@media (min-width: 1360px) {
  .cols2 { grid-template-columns: 1fr 1fr; gap: var(--s8); }
}
/* Пара, которой мало половины экрана: делится только на очень широком */
@media (max-width: 1639px) {
  .cols2--wide { grid-template-columns: 1fr; }
}
/* Листы разборов - сплошные таблицы, разделы кабинета - карточки.
   Разница только в воздухе сверху, дальше оформление общее. */
.pane--sheet { padding-top: var(--s4); }

/* ---------- общие карточки ---------- */

/* Ритм один на весь кабинет, промежуточных значений нет: 24 внутри
   карточки, 32 между карточками, 48 между смысловыми частями экрана.
   Раньше в разметке жили 20, 28, 30 и 36 - это и есть «набиралось по
   месту», и именно по нему экран читается собранным или случайным. */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-m); padding: var(--s6);
  margin-bottom: var(--s8); box-shadow: var(--shadow-card);
}
.card > h2, .card > h3 { font-size: var(--t-card); margin-bottom: var(--s4); }
.card--flat { padding: 0; overflow: hidden; }
.grid3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: var(--s3); }
/* Пара «название - значение» держится в разумной мере: на большом мониторе
   карточка шире тысячи пикселей, и значение улетало к дальнему краю. */
.kv { display: flex; justify-content: space-between; gap: var(--s3); padding: 8px 0; border-bottom: 1px solid var(--line-soft); max-width: 760px; }
.kv:last-child { border-bottom: 0; }
.kv span:first-child { color: var(--ink-2); }
.kv span:last-child { font-weight: 700; text-align: right; }

/* ---------- таблицы, один вид на все приложение ----------

   Коробка таблицы держит рамку и выбор сортировки, а прокручивается только
   сама таблица внутри нее. Из-за этого шапка со столбцами и остается на
   виду: липкий заголовок прилипает к своему контейнеру прокрутки, а не к
   окну, и без ограничения по высоте не работал вовсе. */

.tablebox {
  border: 1px solid var(--line); border-radius: var(--r-m);
  background: var(--surface); box-shadow: var(--shadow-card);
  margin-bottom: var(--s4); overflow: hidden;
}
.tablebox > .scroll {
  border: 0; border-radius: 0; box-shadow: none; margin: 0;
  /* Высоту режем только у длинных таблиц: короткие остаются как были */
  max-height: calc(100vh - 200px);
}

.scroll {
  overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-m);
  background: var(--surface); margin-bottom: var(--s4); box-shadow: var(--shadow-card);
  /* Тень у края появляется, только когда вбок действительно есть что
     листать: в таблице объявлений за краем остаются расходы и цена заявки,
     и без этой подсказки их просто не находят. Две «заслонки» едут вместе с
     содержимым и гасят тень, когда доехали до края. */
  background-image:
    linear-gradient(to right, var(--surface), rgba(255, 255, 255, 0)),
    linear-gradient(to left, var(--surface), rgba(255, 255, 255, 0)),
    radial-gradient(farthest-side at 0 50%, rgba(15, 23, 32, .13), rgba(15, 23, 32, 0)),
    radial-gradient(farthest-side at 100% 50%, rgba(15, 23, 32, .13), rgba(15, 23, 32, 0));
  background-position: left center, right center, left center, right center;
  background-repeat: no-repeat;
  background-size: 26px 100%, 26px 100%, 13px 100%, 13px 100%;
  background-attachment: local, local, scroll, scroll;
}
table { border-collapse: collapse; width: 100%; font-size: var(--t-note); }
th, td { padding: 9px var(--s3); text-align: right; white-space: nowrap; border-bottom: 1px solid var(--line-soft); }
th:first-child, td:first-child, th.t, td.t { text-align: left; }
/* Клетка с текстом, а не с числом: отзыв или длинное название переносится
   по словам и держится в разумной ширине, а не растягивает таблицу. */
th.wrap, td.wrap { white-space: normal; min-width: 240px; max-width: 460px; }
td.wrap { line-height: 1.45; padding-top: 11px; padding-bottom: 11px; }
th.nowrap, td.nowrap { white-space: nowrap; }
.clamp { display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden; }
/* Шапка светлая: заливка во всю ширину спорила бы с цифрами внутри.
   Читается она регистром и весом, а держится линией снизу. */
thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--sunken); color: var(--ink-3);
  font-weight: var(--t-micro-w); font-size: var(--t-micro); line-height: var(--t-micro-lh);
  letter-spacing: var(--t-micro-ls); text-transform: uppercase;
  border-bottom: 1px solid var(--line); white-space: normal;
}

/* Явный выбор сортировки над таблицей. На широком экране его нет: щелчок
   по заголовку столбца делает то же самое, а лишняя строка с нативным
   списком стояла над каждой таблицей как чужая. На телефоне заголовки
   мелкие и в прокрутке, там список остается. */
.sortbar {
  display: none; align-items: center; gap: var(--s2); flex-wrap: wrap;
  padding: var(--s2) var(--s3); border-bottom: 1px solid var(--line-soft);
  background: var(--sunken); font-size: var(--t-note);
}
@media (max-width: 760px) { .sortbar { display: flex; } }
.sortbar__k { color: var(--ink-3); }
.sortbar__sel {
  width: auto; min-width: 150px; padding: 5px 34px 5px 10px; font-size: var(--t-note);
  background-color: var(--surface); border-radius: var(--r-s);
}
.sortbar__dir {
  font: inherit; font-size: var(--t-note); font-weight: 600; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line-strong);
  color: var(--ink-2); border-radius: var(--r-s); padding: 5px 12px;
}
.sortbar__dir:hover { border-color: var(--blue-line); color: var(--blue-deep); }
.sortbar__dir:disabled { opacity: .45; cursor: default; border-color: var(--line); }
.sortbar__dir:disabled:hover { border-color: var(--line); color: var(--ink-2); }
.sortbar__dir::before { content: '↓ '; }
.sortbar__dir[data-dir="up"]::before { content: '↑ '; }

/* Заголовок-кнопка: сортировка столбца. Кнопка наследует у ячейки все,
   кроме курсора, поэтому шапка выглядит как прежде, пока в нее не ткнули. */
th .th__b {
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  background: none; border: 0; padding: 0; margin: 0; cursor: pointer;
  display: inline-flex; align-items: center; gap: 5px; text-align: inherit;
}
th .th__b:hover { color: var(--blue-deep); }
th .th__b .ic { width: 12px; height: 12px; opacity: .35; }
th .th__b:hover .ic { opacity: .75; }
th.is-sorted .th__b { color: var(--blue-deep); }
th.is-sorted .th__b .ic { opacity: 1; }

tbody tr:hover td { background: var(--blue-soft); }
tbody tr:last-child td { border-bottom: 0; }
tr.total td { background: var(--sunken-2); font-weight: 800; color: var(--ink); }
tr.total:hover td { background: var(--sunken-2); }
.dim { color: var(--ink-2); }
td.fact { font-weight: 700; }
/* Проценты в таблицах - это доли и конверсии, а не рост. Зеленый в системе
   означает «выросло», поэтому здесь он вводил в заблуждение: доля 1,26 %
   светилась зеленым как достижение. Оставляем вес, цвет обычный. */
td.cv { color: var(--ink); font-weight: 700; }
td.zero { color: var(--ink-4); }
td a { color: var(--blue-deep); border-bottom: 1px solid var(--blue-line); text-decoration: none; }
td a:hover { border-bottom-color: var(--blue); text-decoration: none; }

.wide-first td:first-child, .wide-first th:first-child {
  position: sticky; left: 0; z-index: 1; background: var(--surface);
  max-width: 320px; overflow: hidden; text-overflow: ellipsis;
}
.wide-first thead th:first-child { background: var(--sunken); z-index: 3; }
.wide-first tbody tr:hover td:first-child { background: var(--blue-soft); }
.wide-first tr.total td:first-child { background: var(--sunken-2); }

/* ---- Выбор строк и панель массового действия ----

   Светофор «Слабых мест»: человек отмечает объявления галочкой и открывает
   их в Авито одной кнопкой. Столбец с галочкой держится у левого края при
   прокрутке вбок - иначе на 1024 и на телефоне, где за кадром остаются
   расходы и цена заявки, отметка уезжала бы из виду вместе со столбцом.
   Правила повторяют .wide-first выше: тот же прием и тот же порядок фонов,
   иначе строка просвечивала бы сквозь липкую клетку. */
th.pickcol, td.pickcol {
  position: sticky; left: 0; z-index: 1; background: var(--surface);
  width: 40px; padding-right: var(--s2);
  /* Волосок справа: под липкой клеткой уезжает соседний столбец, и без
     края от него оставался обрубок слова прямо у галочки. Линия та же, что
     под шапкой, - она отделяет столбец выбора от чисел, а не рисует сетку. */
  border-right: 1px solid var(--line);
}
thead th.pickcol { background: var(--sunken); z-index: 3; }
tbody tr:hover td.pickcol { background: var(--blue-soft); }
/* Отмеченная строка светится целиком: галочка уезжает за край при
   прокрутке вбок, и цвет остается единственным признаком выбора. Правило
   стоит после наведения и с равной специфичностью, поэтому берет оно. */
tbody tr.is-picked td, tbody tr.is-picked td.pickcol { background: var(--bg-selected); }
/* Строка, которую в этом заходе уже открыли. Кабинет открывает отмеченные по
   одной вкладке за нажатие, и на двадцать девятом объявлении человек без
   пометки не помнит, где остановился.

   Черта слева, в столбце выбора: он липкий и виден при любой прокрутке вбок.
   Синяя, а не зеленая и не рыжая: это след прохода, а не состояние
   объявления, и спорить с точкой светофора ей нельзя. Рисуем внутренней
   тенью, а не рамкой - рамка сдвинула бы галочку на свою толщину. */
tbody tr.is-opened td.pickcol { box-shadow: inset 3px 0 0 var(--blue); }

/* Галочка выбора. Размер и цвет те же, что у галочек биддера и автозагрузки
   (.bid__pick, .feed__check input), но эта стоит одна в клетке таблицы,
   поэтому курсор и выключенный вид ей нужны свои. */
.pick__box {
  width: 16px; height: 16px; margin: 0; accent-color: var(--blue);
  cursor: pointer; vertical-align: middle;
}
.pick__box:disabled { cursor: not-allowed; accent-color: var(--line-strong); opacity: .5; }

/* Панель массового действия. Прием тот же, что «Выбрано: N» в управлении
   ставками: счетчик обычной строкой, рядом кнопки. Заливка у панели та же,
   что у отмеченной строки, - выбор читается одним цветом.

   Стоит она под таблицей, внутри той же рамки. Сверху панель появлялась и
   пропадала между двумя нажатиями и сдвигала строки на свою высоту, и
   вторая галочка попадала не в ту строку. Снизу строки стоят на месте. */
.pickbar {
  display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
  padding: var(--s2) var(--s3); border-top: 1px solid var(--line);
  background: var(--bg-selected);
}
/* Пустой панели не бывает: пока ничего не отмечено, ее нет вовсе. Правило
   нужно отдельной строкой - display выше сильнее скрытого узла самого по
   себе, и без него панель висела бы с нулем. */
.pickbar[hidden] { display: none; }
/* Счетчик - не кнопка, как и .bids__count в ставках: строка без рамки и
   заливки, цифры табличные, чтобы счет не прыгал по ширине.

   Цвет тут на ступень темнее обычной подписи. Панель залита --bg-selected, и
   на этой заливке серый --ink-3 дает 4,37 к 1 - ниже нужных 4,5. На белой
   карточке тот же серый проходит, поэтому правило только для панели. */
.pickbar__count { font-size: var(--t-note); color: var(--ink-2); font-variant-numeric: tabular-nums; }
/* Что открывать: форму редактирования или карточку. Развилка сделана теми
   же таблетками, что выбор периода в сводке (.pill), новой формы для нее не
   заводим: третья кнопка в один ряд с «Открыть следующее» и «Открыть все
   сразу» сделала бы панель кашей, а таблетка сразу читается как выбор
   одного из двух, а не как действие.

   Первой строкой панели: она говорит, что сделают кнопки под ней. */
.pickbar__mode {
  flex: 1 0 100%; display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap;
}
.pickbar__mode-t { font-size: var(--t-note); color: var(--ink-2); }
/* Таблетка стоит на заливке панели, а не на белой карточке: невыбранной
   нужна своя поверхность, иначе она сливается с фоном и читается надписью.
   По той же причине она держит белый фон и под курсором: обычное наведение
   заливает таблетку --blue-soft, а это тот же цвет, что у панели, и таблетка
   под курсором растворялась бы. Наведение показываем краем и цветом слова.
   Порядок правил важен: выбранная таблетка описана ниже наведения, поэтому
   синей она остается и под курсором. */
.pickbar__mode .pill { background: var(--surface); }
.pickbar__mode .pill:hover { background: var(--surface); border-color: var(--blue-line); color: var(--blue-deep); }
.pickbar__mode .pill--on { background: var(--blue); }
.pickbar__mode .pill--on:hover { background: var(--blue-dark); border-color: var(--blue-dark); color: #fff; }

/* Ход захода: «Открыто 3 из 29» и полоса. Отдельной строкой под кнопками, а
   не рядом со счетчиком: счет меняется на каждое нажатие, и рядом со
   счетчиком он менял бы ширину первой клетки панели, двигая кнопку из-под
   курсора - ту самую, по которой бьют двадцать девять раз подряд. */
.pickbar__step {
  flex: 1 0 100%; display: flex; align-items: center; gap: var(--s3);
  font-size: var(--t-note); color: var(--ink-2);
}
.pickbar__step-t { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Полоса та же, что у сбора данных. Дорожка у нее своя: обычная (--sunken-2)
   на заливке панели (--bg-selected) не видна, обе почти белые. Берем вторую
   ступень синей шкалы - тот же тон, на два шага темнее. */
.pickbar__step .bar-progress {
  flex: 0 1 200px; margin-top: 0; background: var(--blue-line);
}
/* Кнопка «Снять выбор» появляется только в конце захода. Правило нужно
   отдельной строкой по той же причине, что и у панели выше: display у .btn
   задан классом, и он сильнее скрытого узла самого по себе. */
.pickbar .btn[hidden] { display: none; }
/* Ответ панели: отдельной строкой под кнопками, во всю ширину. Пока
   сказать нечего, места не занимает. */
.pickbar__msg { flex: 1 0 100%; min-width: 0; }
.pickbar__msg:empty { display: none; }
/* Адрес страницы настроек браузера в подсказке - одно длинное слово на
   тридцать знаков. На телефоне оно упиралось бы в край панели и растягивало
   таблицу вбок, поэтому переносится по буквам. */
.pickbar__msg .msg { margin-top: var(--s2); overflow-wrap: break-word; }

@media (max-width: 760px) {
  /* Телефон: счет отдельной строкой, кнопки во всю ширину друг под другом,
     клетка с галочкой шире - 44px хватает пальцу. */
  .pickbar { padding: var(--s3); }
  .pickbar__count, .pickbar .btn { flex: 1 0 100%; }
  /* Полосе на телефоне отдаем весь остаток строки: 200px рядом со счетом
     оставляли справа пустое поле в треть ширины. */
  .pickbar__step .bar-progress { flex: 1 1 auto; }
  /* Слово «Открывать» уходит на свою строку, таблетки делят следующую
     пополам: рядом друг с другом они на 390 не помещались. */
  .pickbar__mode-t { flex: 1 0 100%; }
  .pickbar__mode .pill { flex: 1 1 auto; }
  th.pickcol, td.pickcol { width: 44px; }
  .pick__box { width: 20px; height: 20px; }
}

/* Бейдж - нейтральная приписка к имени: «Вы», «Скоро». Состояний он больше
   не показывает: цветные метки светофора уехали на единую точку (.state), и
   вместе с ними ушли .badge--bad, .badge--off и .badge--on. */
.badge {
  display: inline-block; border-radius: 999px; padding: 2px 9px;
  font-size: var(--t-micro); font-weight: 700; white-space: nowrap;
  background: var(--sunken-2); color: var(--ink-2);
}
.badge + .badge { margin-left: 4px; }

.tag--ok { background: var(--green-soft); color: var(--green-ink); }
.tag--off { background: var(--sunken-2); color: var(--ink-2); }
.tag--bad { background: var(--alarm-soft); color: var(--alarm); }
.plus { color: var(--green-ink); font-weight: 700; }
.minus { color: var(--alarm); font-weight: 700; }
.calcd { text-decoration: underline dotted var(--warn); text-underline-offset: 3px; cursor: help; }

/* ---------- показатели строкой, как в ведомости ---------- */

/* Показателей всегда четыре, поэтому сетка идет парами: при трех колонках
   четвертый оставался один в ряду и рядом зияла пустота. */
.ind { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); gap: var(--s8) var(--s12); }
@media (min-width: 760px) { .ind { grid-template-columns: 1fr 1fr; } }
.ind__head { display: flex; align-items: baseline; gap: var(--s2); }
.ind__k { font-size: var(--t-text); font-weight: 700; }
.ind__fill { flex: 1; border-bottom: 1px dotted var(--line-strong); transform: translateY(-4px); min-width: 20px; }
.ind__v { font-size: var(--t-text); font-weight: 800; white-space: nowrap; }
.bars { margin-top: var(--s3); display: grid; gap: 7px; }
.bar { display: grid; grid-template-columns: 150px minmax(50px, 1fr) auto; gap: var(--s3); align-items: center; }
.bar__k { font-size: var(--t-note); color: var(--ink-2); line-height: 1.25; }
.bar__track { height: 6px; background: var(--sunken-2); border-radius: 999px; overflow: hidden; }
.bar__fill { height: 100%; background: var(--blue); border-radius: 999px; }
.bar__v { font-size: var(--t-note); white-space: nowrap; }
.bonus { font-size: var(--t-note); margin-top: var(--s2); }
.bonus b { color: var(--green-ink); font-weight: 700; }

/* воронка тремя колонками, как в кабинете Авито */
.fun { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: var(--s6); align-items: start; }
.fun__t { font-size: var(--t-text); font-weight: 700; display: flex; align-items: center; gap: 6px; }
.fun__hint {
  width: 16px; height: 16px; border-radius: 50%; background: var(--sunken-2); color: var(--ink-3);
  font-size: var(--t-micro); display: inline-grid; place-items: center; cursor: help; font-weight: 800;
}
.fun__line { display: flex; align-items: baseline; gap: var(--s2); margin-top: var(--s2); flex-wrap: wrap; }
.fun__v { font-size: var(--t-figure); line-height: var(--t-figure-lh); font-weight: var(--t-figure-w); letter-spacing: var(--t-figure-ls); }
.fun__d { font-size: var(--t-note); line-height: var(--t-note-lh); color: var(--ink-2); margin-top: var(--s2); }
.delta { font-size: var(--t-note); font-weight: 700; }
.delta--up { color: var(--green-ink); }
.delta--down { color: var(--alarm); }
/* Ступень воронки: доля просмотров, дошедших до заявки. Стоит своей строкой
   под числом, ширина по тексту. */
.conv {
  margin: var(--s2) 0 0; display: inline-flex; align-items: center; gap: 5px;
  background: var(--brand-primary-soft); border: 1px solid var(--brand-primary-border);
  border-radius: 999px; padding: 3px 10px;
  font-size: var(--t-note); font-weight: 700; color: var(--text-link); white-space: nowrap;
}

/* ---- Плитка показателя: число и следствие ----

   Ни одно крупное число в кабинете не стоит голым. Под ним всегда строка,
   которая переводит его в деньги, в дни или в действие: «780» само по себе
   не говорит ничего, «каждая заявка обошлась в 51,52 руб» решает вопрос.
   Отсюда и правило набора: следствие - это подпись 13/18 цветом
   --text-primary с отступом 8, а не мелкая сноска 11 серым по серому,
   которой она была. Читать надо обе строки, а не одну.

   Правило не действует в ячейках таблицы: там роль подписи выполняет шапка
   столбца, и вторая строка в каждой ячейке превратила бы таблицу в кашу. */
.kpis { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr)); gap: var(--s4); margin-bottom: var(--s8); }
.kpi {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
  padding: var(--s4); box-shadow: var(--shadow-card);
}
.kpi__k { font-size: var(--t-note); color: var(--ink-2); }
.kpi__k .ic { width: 14px; height: 14px; margin-right: 5px; vertical-align: -2px; }
.kpi__v { font-size: var(--t-tile); line-height: var(--t-tile-lh); font-weight: var(--t-figure-w); letter-spacing: var(--t-figure-ls); font-variant-numeric: tabular-nums; margin-top: var(--s2); }
/* Значение словом, а не числом. «Понедельник» кеглем 25 занимает 214px и в
   карточку 180px не влезает: на 1024 оно выталкивало страницу вбок на 11px.
   Слово переносом не рвем - оно должно читаться целиком, - поэтому кегль
   уменьшаем только здесь, числовые плитки остаются как были. */
.kpi__v-word { font-size: var(--t-block); line-height: var(--t-block-lh); letter-spacing: var(--t-block-ls); }
.kpi__n { font-size: var(--t-note); line-height: var(--t-note-lh); color: var(--ink-2); margin-top: var(--s2); }
/* Голое число - это осознанный случай, а не забытая строка: следствие
   собрать не из чего. Тогда плитка не проваливается по высоте рядом с
   соседями, у которых следствие есть. */
.kpi--bare { align-self: stretch; }
/* Плитка, где надо вмешаться. Рыжий значит ровно одно: пока не откроешь и
   не починишь, деньги текут. Не синим, потому что синий в этой системе -
   обычное действие, и залитая синим плитка спорила бы с кнопками. Текст на
   рыжем темный: белый по #F97316 читается хуже. */
.kpi--alert {
  background: var(--attention-soft);
  border-color: var(--attention-line);
  border-left: 3px solid var(--attention);
  color: var(--ink);
}
.kpi--alert .kpi__k { color: var(--attention-ink); font-weight: 700; }
.kpi--alert .kpi__n { color: var(--ink-2); }
/* Плитка с главным числом экрана. Раньше это был тот же рыжий класс, и один
   цвет отвечал на два разных вопроса: «здесь беда» и «это главное число».
   Пока он был один, рыжий значил то одно, то другое и переставал значить
   хоть что-нибудь. Отмеченная плитка в ряду одна. */
.kpi--mark {
  background: var(--accent-sky-soft);
  border-color: var(--accent-sky-line);
  border-left: 3px solid var(--brand-primary);
  color: var(--ink);
}
.kpi--mark .kpi__k { color: var(--text-link); font-weight: 700; }
.kpi--mark .kpi__n { color: var(--ink-2); }

/* ---------- шапка раздела кабинета ----------

   Разделы кабинета рисуют свою шапку сами: заголовок, кнопка выгрузки,
   переключатель вкладок и строка фильтров. Раньше этих правил не было
   вовсе, и вкладки выходили системными серыми кнопками браузера. */

.head {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  margin-bottom: var(--s3);
}
.head h1 { font-size: var(--t-screen); line-height: var(--t-screen-lh); letter-spacing: var(--t-screen-ls); }

/* Выгрузка - действие второго ряда, поэтому уходит вправо и остается тихой.
   Выгрузок в шапке бывает две: таблица открытого экрана и все таблицы
   аналитики файлом Excel. Вправо уезжает первая, вторая встает рядом: два
   автоматических отступа поделили бы свободное место пополам и растащили
   кнопки по строке. */
.head > .pill, .head > #btnBook { margin-left: auto; }
.head > .pill ~ #btnBook { margin-left: 0; }

/* Переключатель вкладок: одна дорожка, выбранное поднято белым */
.tabs {
  display: inline-flex; gap: 2px; padding: 3px;
  background: var(--sunken-2); border-radius: 12px;
  margin-bottom: var(--s4); max-width: 100%; overflow-x: auto;
}
.tabs button {
  font: inherit; font-size: var(--t-note); font-weight: 600; color: var(--ink-2);
  background: none; border: 0; border-radius: 9px;
  padding: 7px 16px; cursor: pointer; white-space: nowrap;
  transition: background .13s ease, color .13s ease;
}
.tabs button:hover { color: var(--ink); }
.tabs button.is-on {
  background: var(--surface); color: var(--ink); font-weight: 700;
  box-shadow: 0 1px 3px rgba(10, 26, 43, 0.10);
}

.fbar { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: center; margin-bottom: var(--s4); }

/* Карточка с графиком: у нее свои поля, потому что подписи дней и месяцев
   рисуются внутри картинки и лишний воздух снизу выглядел бы провалом. */
.card--plot { padding: var(--s4); }

/* Заголовок блока на общей странице: слева имя, справа его настройки.
   Отбивает блоки друг от друга, раз вкладок между ними больше нет. */
/* Заголовок блока делит экран на смысловые части, поэтому сверху 48. */
.block__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s3); flex-wrap: wrap;
  margin: var(--s12) 0 var(--s6);
}
.block__head h2 { font-size: var(--t-block); }

/* Разбивка расходов по услугам: точка цвета, название, отточие, сумма.
   Отточие ведет глаз от названия к сумме через пустое место строки. */
.legend__k { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-text); }
.legend__dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.legend__total { border-top: 1px solid var(--line); margin-top: var(--s2); padding-top: var(--s3); }
.legend__total .ind__k, .legend__total .ind__v { font-weight: 800; }

/* Секция раздела: та же карточка, что и .card, но заголовок внутри крупнее */
.block {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-m); padding: var(--s6);
  margin-bottom: var(--s8); box-shadow: var(--shadow-card);
}
.block > h2 { font-size: var(--t-card); margin-bottom: var(--s6); }

/* ---------- фильтры и всплывающие слои ---------- */

.filters { display: flex; gap: var(--s2); flex-wrap: wrap; align-items: center; }
.pill {
  font: inherit; font-size: var(--t-note); font-weight: 600; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
  padding: 7px 14px; cursor: pointer;
  transition: background .13s ease, border-color .13s ease, color .13s ease;
}
.pill:hover { border-color: var(--blue-line); color: var(--blue-deep); background: var(--blue-soft); }
.pill--on { background: var(--blue); border-color: var(--blue); color: #fff; }
.pill--on:hover { background: var(--blue-dark); border-color: var(--blue-dark); color: #fff; }
.pill--muted { color: var(--ink-3); cursor: default; }
.pill--muted:hover { background: var(--surface); border-color: var(--line); color: var(--ink-3); }
/* Отключенная второстепенная кнопка: у .btn такое правило есть, у .pill не
   было, и «Скопировать» без ссылки выглядела рабочей. */
.pill:disabled, .pill[disabled] { opacity: .45; cursor: default; }
.pill:disabled:hover, .pill[disabled]:hover { background: var(--surface); border-color: var(--line); color: var(--ink-2); }

.fsel {
  position: relative; font: inherit; font-size: var(--t-text); font-weight: 600; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-s);
  padding: 9px 14px; cursor: pointer; display: inline-flex; align-items: center; gap: var(--s2);
  transition: border-color .13s ease, background .13s ease;
}
.fsel:hover { border-color: var(--line-strong); }
.fsel--filled { color: var(--ink); }
.fsel--open { border-color: var(--blue); box-shadow: 0 0 0 3px var(--focus); }
.fsel__chev { width: 8px; height: 8px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translate(-2px, -2px); opacity: .5; }
.fsel--open .fsel__chev { transform: rotate(-135deg); }

.pop {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 40;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-l);
  box-shadow: var(--shadow-pop); padding: var(--s4); cursor: default;
}
/* Кнопки в правой части шапки: слой раскрывается влево, иначе календарь
   шириной в два месяца уезжал бы за край экрана. */
.top__tools .pop { left: auto; right: 0; }
.pop--menu { min-width: 250px; max-height: 330px; overflow: auto; padding: 6px; }
.pop__item { display: block; width: 100%; text-align: left; border: 0; background: none; padding: 8px 10px; border-radius: 8px; cursor: pointer; font: inherit; font-size: var(--t-text); color: var(--ink); }
.pop__item:hover { background: var(--sunken); }
.pop__item.is-on { font-weight: 700; background: var(--blue-soft); color: var(--blue-deep); }

.dp__pills { display: flex; gap: 6px; margin-bottom: var(--s3); }
.dp__months { display: flex; gap: var(--s6); }
.dp__m { width: 236px; }
.dp__cap { display: flex; align-items: center; justify-content: center; gap: var(--s2); font-weight: 700; margin-bottom: var(--s2); font-size: var(--t-text); }
.dp__grid { display: grid; grid-template-columns: repeat(7, 1fr); }
.dp__dow { font-size: var(--t-micro); color: var(--ink-4); text-align: center; padding-bottom: 5px; }
.dp__d { height: 32px; border: 0; background: none; cursor: pointer; font: inherit; font-size: var(--t-note); border-radius: 8px; color: var(--ink); }
.dp__d:hover { background: var(--sunken-2); }
.dp__d[disabled] { color: var(--ink-4); cursor: default; }
.dp__d[disabled]:hover { background: none; }
/* Отрезок закрашивается сплошь: с просветами между клетками он читался
   бы как набор отдельных дней, а не как выбранный промежуток. */
.dp__d.in { background: var(--blue-soft); border-radius: 0; }
.dp__d.edge { background: var(--blue); color: #fff; border-radius: 8px; }
.dp__nav {
  border: 0; background: none; cursor: pointer; color: var(--ink-3);
  width: 28px; height: 28px; border-radius: 6px;
  display: inline-flex; align-items: center; justify-content: center;
}
.dp__nav:hover { background: var(--sunken-2); color: var(--ink); }
.dp__nav svg { display: block; }

/* ---------- листы аналитики ---------- */

.sheet__head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; margin-bottom: var(--s6); }
.sheet__head h2 { font-size: var(--t-screen); }
.sheet__head p { margin: var(--s2) 0 0; color: var(--ink-2); font-size: var(--t-note); max-width: 74ch; }
.sheet__tools { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; justify-content: flex-end; }

.funnel { display: grid; gap: 6px; }
.step { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: var(--s3); }
/* Дорожка светло-серая, залитая часть синяя: на светло-синей дорожке
   заливка терялась и ступени воронки читались одинаковыми. */
.step__bar { height: 42px; background: var(--sunken-2); border-radius: var(--r-s); display: flex; align-items: center; padding: 0 var(--s3); font-weight: 700; position: relative; overflow: hidden; }
.step__fill { position: absolute; inset: 0 auto 0 0; background: var(--blue); opacity: .38; }
.step__t { position: relative; }
.step__v { font-size: var(--t-block); line-height: var(--t-block-lh); font-weight: var(--t-figure-w); min-width: 100px; text-align: right; }
.step__cv { color: var(--green-ink); font-size: var(--t-note); font-weight: 700; padding-left: var(--s3); }

.heat th, .heat td { padding: 5px 6px; font-size: var(--t-note); text-align: center; }
.heat td:first-child, .heat th:first-child { text-align: left; padding-left: var(--s3); }

.bar-progress { height: 6px; background: var(--sunken-2); border-radius: 999px; overflow: hidden; margin-top: var(--s2); }
.bar-progress__in { height: 100%; width: 100%; background: var(--blue); transform: scaleX(0); transform-origin: left; transition: transform .3s; }

/* ---------- полоса ожидания лимита ----------

   Полоса заполняется ровно столько, сколько осталось ждать: доля
   закрашенного равна доле прожитого. Плавность короткая, иначе заливка
   отстает от подписи в процентах и они спорят друг с другом. */

.wait { display: flex; align-items: center; gap: var(--s3); max-width: 340px; margin: var(--s4) auto 0; }
.wait .bar-progress { flex: 1; height: 8px; margin-top: 0; }
.wait__pct { font-size: var(--t-note); font-weight: 700; color: var(--ink-2); min-width: 40px; text-align: right; }
.bar-progress--wait .bar-progress__in { transition: transform .14s linear; }

/* Дошли до конца: запрос ушел, время ответа неизвестно. Замершая на сотне
   полоса врала бы, что вот-вот, поэтому дальше идет бегущая заливка. */
.bar-progress--run .bar-progress__in {
  width: 38%; transform: none; transition: none;
  animation: barrun 1.05s ease-in-out infinite alternate;
}
@keyframes barrun { from { margin-left: 0; } to { margin-left: 62%; } }
/* Кому движение мешает, тому вместо бега просто приглушенная полоса:
   застывшая на месте бегущая заливка читалась бы как зависание. */
@media (prefers-reduced-motion: reduce) {
  .bar-progress--run .bar-progress__in { width: 100%; opacity: .35; }
}
.load { display: grid; place-items: center; min-height: 46vh; text-align: center; }
.load .card { max-width: 440px; }

/* ---------- графики ---------- */

.charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)); gap: var(--s3); margin-bottom: var(--s4); }
.chart {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-m); padding: var(--s3) var(--s4); box-shadow: var(--shadow-card);
}
.chart__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s2); margin-bottom: var(--s2); }
/* Итог графика и следствие под ним. Кегль итога взят из шкалы: это крупное
   число, ужатое до плитки, а не десятый размер по месту. Раньше он стоял
   строчным стилем прямо в charts.js. */
.chart__fig { text-align: right; min-width: 0; }
.chart__v {
  font-size: var(--t-tile); line-height: var(--t-tile-lh); font-weight: var(--t-figure-w);
  letter-spacing: var(--t-figure-ls); color: var(--ink); font-variant-numeric: tabular-nums;
}
.chart__why { margin-top: var(--s2); font-size: var(--t-note); line-height: var(--t-note-lh); color: var(--ink-2); }
.chart__t { font-size: var(--t-note); font-weight: 700; }
.chart__n { font-size: var(--t-micro); color: var(--ink-3); text-align: right; }
.chart__plot { position: relative; }
.chart__svg { display: block; width: 100%; height: 168px; overflow: visible; }
.chart__scale { display: flex; justify-content: space-between; font-size: var(--t-micro); color: var(--ink-3); margin-top: 4px; }
.chart__cap { position: absolute; top: 0; left: 0; font-size: var(--t-micro); color: var(--ink-4); pointer-events: none; }
.chart__tip {
  position: absolute; top: -4px; z-index: 5; pointer-events: none;
  background: var(--ink); color: #fff; border-radius: 8px; padding: 5px 9px;
  font-size: var(--t-note); line-height: 1.3; white-space: nowrap;
  display: flex; flex-direction: column; gap: 1px;
  box-shadow: var(--shadow-card);
}
.chart__tip span { opacity: .7; font-size: var(--t-micro); }

/* ---------- обозреватель методов ---------- */

.explorer { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: var(--s4); align-items: start; }
.explorer__list { border: 1px solid var(--line); border-radius: var(--r-m); max-height: 70vh; overflow: auto; background: var(--surface); box-shadow: var(--shadow-card); }
.explorer__list button { display: block; width: 100%; text-align: left; border: 0; background: none; padding: 8px 12px; cursor: pointer; font: inherit; font-size: var(--t-note); color: var(--ink); border-bottom: 1px solid var(--line-soft); }
.explorer__list button:hover { background: var(--sunken); }
.explorer__list button.is-on { background: var(--blue-soft); color: var(--blue-deep); font-weight: 700; }
.explorer__sec { padding: 8px 12px; font-weight: var(--t-micro-w); background: var(--sunken-2); font-size: var(--t-micro); line-height: var(--t-micro-lh); letter-spacing: var(--t-micro-ls); text-transform: uppercase; color: var(--ink-2); position: sticky; top: 0; z-index: 1; }
.verb { font-weight: 800; margin-right: 5px; font-size: var(--t-micro); }
.verb--GET { color: var(--green-ink); }
.verb--POST { color: var(--blue-deep); }
.verb--PUT { color: var(--warn); }
.verb--DELETE { color: var(--alarm); }
pre.out { margin: 0; padding: var(--s4); background: #172033; color: #CBD5E1; border-radius: var(--r-m); font-family: Consolas, monospace; font-size: var(--t-note); line-height: 1.5; max-height: 58vh; overflow: auto; white-space: pre-wrap; word-break: break-word; }
textarea.body { min-height: 120px; font-family: Consolas, monospace; font-size: var(--t-note); }

/* ---------- биддер ---------- */

/* Плашка осталась ровно для двух случаев, и оба - не состояние.

   Первый: результат, который можно взять руками. «Готов 4/4» в очереди
   отчетов - это вещь, рядом с ней стоит кнопка «Скачать», и точка тут
   рассказывала бы про процесс, которого уже нет.

   Второй: значение, у которого цвет и есть смысл. Оценка отзыва 3 и ниже.

   Все, что отвечает на вопрос «что сейчас происходит и надо ли вмешаться»,
   набирается единой точкой (.state) и плашкой быть перестало. */
.tag {
  display: inline-flex; align-items: center; gap: 5px; border-radius: 999px; padding: 3px 10px;
  font-size: var(--t-micro); font-weight: 700; white-space: nowrap;
}
/* Значок внутри метки берет ее цвет: у метки он уже осмысленный */
.tag .ic { width: 13px; height: 13px; vertical-align: 0; color: inherit; }
td .ic { vertical-align: -2px; }
a .ic { margin-left: 4px; }
/* ---------- список правил карточками ----------

   Таблица здесь не годилась: у каждого объявления своя жизнь - позиция,
   коридор ставки, бюджет, расписание, - и строка таблицы заставляла бы
   бегать глазами по двенадцати колонкам. Карточка показывает то же самое
   четырьмя блоками, которые читаются с одного взгляда. */

.bid__search {
  width: 100%; margin-bottom: var(--s4);
}
.bid__list { display: grid; gap: var(--s4); }

.bid__group {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
  box-shadow: var(--shadow-card); overflow: hidden;
}
.bid__ghead {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  padding: var(--s3) var(--s4); background: var(--sunken); border-bottom: 1px solid var(--line);
}
.bid__ghead.is-off { opacity: .6; }
.bid__ghead--loose { background: var(--surface); }
.bid__gname { font-family: var(--display); font-weight: 700; font-size: var(--t-card); }
.bid__gfacts { display: flex; align-items: center; gap: var(--s4); font-size: var(--t-note); color: var(--ink-2); margin-left: var(--s3); flex-wrap: wrap; }
.bid__gtools { display: flex; gap: var(--s2); margin-left: auto; }
.bid__empty { padding: var(--s6) var(--s4); color: var(--ink-3); font-size: var(--t-note); text-align: center; }

/* Тумблер. Своя разметка вместо галочки: включение правила стоит денег,
   и оно должно выглядеть как рубильник, а не как отметка в списке. */
.bid__switch {
  width: 38px; height: 22px; flex: none; border-radius: 999px; cursor: pointer;
  background: var(--line-strong); border: 0; padding: 0; position: relative;
  transition: background .14s ease;
}
.bid__switch::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; transition: transform .14s ease;
}
.bid__switch.is-on { background: var(--green); }
.bid__switch.is-on::after { transform: translateX(16px); }
.bid__switch:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
/* Пока запрос идет, рубильник выключен: без этого он выглядел рабочим, а
   нажатие уже не считалось. Состояние ставит act() в bidder.js. */
.bid__switch:disabled, .bid__switch[disabled] { opacity: .55; cursor: default; }

.bid__bar { display: block; width: 90px; height: 5px; border-radius: 999px; background: var(--sunken-2); overflow: hidden; margin-top: 4px; }
.bid__bar-in { display: block; height: 100%; background: var(--blue); border-radius: 999px; }
.bid__bar-in.is-full { background: var(--alarm); }
.bid__budget { display: inline-flex; flex-direction: column; }

.bid__card { padding: var(--s4); border-bottom: 1px solid var(--line-soft); }
.bid__card:last-child { border-bottom: 0; }
.bid__card.is-off { background: var(--sunken); }
.bid__card.is-off .bid__title { color: var(--ink-2); }

.bid__top { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.bid__pick { width: 16px; height: 16px; accent-color: var(--blue); flex: none; }
.bid__who { min-width: 0; }
.bid__title { font-weight: 700; font-size: var(--t-text); color: var(--ink); border: 0; }
.bid__title:hover { color: var(--blue-deep); text-decoration: none; }
.bid__sub { font-size: var(--t-note); color: var(--ink-3); margin-top: 2px; }
.bid__sub a { border: 0; }
.bid__fill { flex: 1; }
.bid__tools { display: flex; gap: var(--s2); }

.bid__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
  gap: var(--s3) var(--s4); margin-top: var(--s3);
}
.bid__cell { min-width: 0; }
.bid__k { font-size: var(--t-micro); color: var(--ink-3); }
.bid__v { font-size: var(--t-block); line-height: var(--t-block-lh); font-weight: var(--t-figure-w); letter-spacing: var(--t-block-ls); margin-top: 2px; }
.bid__note { font-size: var(--t-micro); color: var(--ink-3); margin-top: 2px; }

/* Позиция - главное число карточки, поэтому она пилюлей и цветом:
   зеленая внутри цели, оранжевая мимо, серая когда объявления нет. */
.bid__pos {
  display: inline-block; margin-top: 2px; padding: 2px 12px; border-radius: 999px;
  font-size: var(--t-block); font-weight: 800; font-variant-numeric: tabular-nums;
  background: var(--warn-soft); color: var(--warn);
}
.bid__pos.is-ok { background: var(--green-soft); color: var(--green-ink); }
.bid__pos.is-lost { background: var(--sunken-2); color: var(--ink-3); font-size: var(--t-text); padding: 5px 12px; }

/* Полоса позиций: зона цели и точка, где мы сейчас. Отступ сверху держит
   обертка: под полосой бывает еще строка-ключ, и они идут одним блоком. */
.bid__rangebox { margin-top: var(--s3); }
.bid__range { display: flex; align-items: center; gap: var(--s2); }
.bid__edge { font-size: var(--t-micro); color: var(--ink-4); font-variant-numeric: tabular-nums; }
.bid__track { position: relative; flex: 1; height: 8px; border-radius: 999px; background: var(--sunken-2); }
.bid__zone { position: absolute; top: 0; height: 100%; border-radius: 999px; background: var(--green-soft); border: 1px solid var(--green); }
.bid__dot {
  position: absolute; top: 50%; width: 12px; height: 12px; border-radius: 50%;
  background: var(--warn); border: 2px solid var(--surface); transform: translate(-50%, -50%);
}
.bid__dot.is-ok { background: var(--green-ink); }
/* Пока позиции нет, зона цели теряет заливку и остается отметкой: залитый
   отрезок у левого края читался как шкала, выполненная на десять процентов.
   Слова к отметке ставит rangeBar строкой ниже полосы. */
.bid__range--wait .bid__zone { background: transparent; }
.bid__rangenote { font-size: var(--t-micro); color: var(--ink-3); margin-top: 6px; }

.bid__last { margin-top: var(--s3); font-size: var(--t-note); color: var(--ink-2); }
/* Значок «последнего решения» стоял вплотную к первой букве: строка не
   флексовая, отступ надо задать самому. */
.bid__last .ic { margin-right: 6px; }
.bid__foot { display: flex; gap: var(--s2); margin-top: var(--s3); flex-wrap: wrap; }

/* Отказ показывается там, где нажали: строка под шапкой раздела на телефоне
   уезжает за верхний край, и человек ее не видит. Внутри карточки правила
   поля уже есть, а между карточками группы сообщение стоит во всю ширину
   коробки, поэтому поля ему нужны свои. */
.bid__err { margin-top: var(--s3); }
.bid__card > .bid__err { margin-bottom: 0; }
.bid__err--pad { margin: var(--s3) var(--s4); }

/* Полоса массовой правки: появляется, только когда что-то отмечено */
.bid__bulk {
  position: sticky; bottom: var(--s4); z-index: 5;
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  margin-top: var(--s4); padding: var(--s3) var(--s4);
  background: var(--ink); color: #fff; border-radius: var(--r-m); box-shadow: var(--shadow-pop);
}
.bid__bulk .pill { background: transparent; border-color: rgba(255, 255, 255, .35); color: #fff; }
.bid__bulk .pill:hover { background: rgba(255, 255, 255, .12); color: #fff; border-color: rgba(255, 255, 255, .5); }
.bid__bulkrow { display: grid; grid-template-columns: 260px minmax(0, 1fr); gap: var(--s3); align-items: center; margin-bottom: var(--s3); }
.bid__bulklabel { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-note); cursor: pointer; }
.bid__bulklabel input { width: 16px; height: 16px; accent-color: var(--blue); }
.bid__bulkfield { transition: opacity .14s ease; }
.bid__two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2); }

/* Расписание */
.bid__sched { margin-top: var(--s6); border-top: 1px solid var(--line-soft); padding-top: var(--s4); }
.bid__sched h3 { font-size: var(--t-card); margin-bottom: var(--s3); }
.bid__days { display: flex; gap: var(--s2); flex-wrap: wrap; margin-bottom: var(--s3); }
.bid__day {
  min-width: 46px; padding: 7px 10px; border-radius: var(--r-s); cursor: pointer;
  font: inherit; font-size: var(--t-note); font-weight: 700; letter-spacing: .04em;
  background: var(--surface); border: 1px solid var(--line-strong); color: var(--ink-3);
}
.bid__day.is-on { background: var(--blue-soft); border-color: var(--blue-line); color: var(--blue-deep); }
.bid__windows { display: grid; gap: var(--s2); margin-bottom: var(--s3); }
.bid__window { display: flex; align-items: center; gap: var(--s2); }
.bid__window input { width: 120px; }
.bid__wk { font-size: var(--t-note); color: var(--ink-2); }

/* ---------- окно поверх экрана ---------- */

/* z-index выше выдвижной панели автоматики (.adraw, 90): окно «Включить
   автоматику?» открывается поверх нее и должно быть сверху. */
.bmodal {
  position: fixed; inset: 0; z-index: 100; display: grid; place-items: center;
  background: rgba(10, 26, 43, .45); padding: var(--s4);
}
.bmodal__win {
  width: 100%; max-width: 620px; max-height: 88vh; display: flex; flex-direction: column;
  background: var(--surface); border-radius: var(--r-l); box-shadow: var(--shadow-pop); overflow: hidden;
}
.bmodal__head {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s4); border-bottom: 1px solid var(--line);
}
.bmodal__head h3 { font-size: var(--t-block); }
.bmodal__x {
  margin-left: auto; background: none; border: 0; cursor: pointer; color: var(--ink-3);
  padding: 4px; border-radius: 8px; display: grid; place-items: center;
}
.bmodal__x:hover { background: var(--sunken-2); color: var(--ink); }
.bmodal__body { padding: var(--s4); overflow-y: auto; }
.bmodal__text { margin: 0; font-size: var(--t-text); line-height: 1.55; color: var(--ink-2); overflow-wrap: anywhere; }
.bmodal__text + .bmodal__text { margin-top: var(--s2); }
.bmodal__foot {
  display: flex; justify-content: flex-end; gap: var(--s2);
  padding: var(--s3) var(--s4); border-top: 1px solid var(--line); background: var(--sunken);
}

/* ---------- автоматика ставок: выдвижная панель ----------

   Настройка планов цены по времени. Панель выезжает справа и не прячет
   таблицу целиком: видно, к чему применяешь. Дни недели переиспользуют
   кнопки .bid__day из биддера. */

.adraw {
  position: fixed; inset: 0; z-index: 90; display: flex; justify-content: flex-end;
  background: rgba(10, 26, 43, .45);
}
.adraw__win {
  width: min(560px, 100%); height: 100%; display: flex; flex-direction: column;
  background: var(--surface); box-shadow: var(--shadow-pop);
  animation: adrawIn .18s ease;
}
@keyframes adrawIn { from { transform: translateX(28px); opacity: 0; } }
.adraw__head {
  display: flex; align-items: flex-start; gap: var(--s3);
  padding: var(--s6) var(--s6) var(--s4); border-bottom: 1px solid var(--line-soft);
}
.adraw__head h3 { font-family: var(--display); font-size: var(--t-block); color: var(--ink); }
.adraw__sub { margin-top: 2px; font-size: var(--t-note); color: var(--ink-3); }
.adraw__x {
  margin-left: auto; background: none; border: 0; cursor: pointer; color: var(--ink-3);
  padding: 4px; border-radius: 8px; display: grid; place-items: center; flex: none;
}
.adraw__x:hover { background: var(--sunken-2); color: var(--ink); }
.adraw__x--sm { margin-left: auto; }
.adraw__body { flex: 1; overflow-y: auto; padding: var(--s4) var(--s6); }
.adraw__foot {
  display: flex; justify-content: flex-end; gap: var(--s2);
  padding: var(--s3) var(--s6); border-top: 1px solid var(--line); background: var(--sunken);
}

.adraw__modes { display: grid; gap: var(--s2); margin-bottom: var(--s4); }
.adraw__opt {
  display: flex; gap: var(--s3); align-items: flex-start; cursor: pointer;
  padding: var(--s3) var(--s4); border: 1px solid var(--line); border-radius: var(--r-m);
}
.adraw__opt:has(input:checked) { border-color: var(--blue-line); background: var(--blue-soft); }
.adraw__opt input { margin-top: 3px; width: 16px; height: 16px; accent-color: var(--blue); flex: none; }
.adraw__opt b { display: block; font-size: var(--t-text); color: var(--ink); }
.adraw__opt span { display: block; margin-top: 2px; font-size: var(--t-note); color: var(--ink-3); }

.adraw__range {
  background: var(--sunken); border-radius: var(--r-m);
  padding: var(--s4); margin-bottom: var(--s3);
}
.adraw__rhead { display: flex; align-items: center; gap: var(--s3); margin-bottom: var(--s3); }
.adraw__rname { font-size: var(--t-note); font-weight: 700; color: var(--ink); white-space: nowrap; }
.adraw__days { margin-bottom: 0; }
.adraw__days .bid__day { min-width: 38px; padding: 6px 6px; }
.adraw__line { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.adraw__k { font-size: var(--t-note); color: var(--ink-2); }
.adraw__price { display: flex; align-items: center; gap: var(--s2); margin-left: var(--s2); }
/* Селектор с тегом: глобальное input[type="text"] дает width 100%,
   классу его не перебить, а полю цены ширина нужна своя. */
input.adraw__time, input.adraw__num {
  height: 40px; padding: 0 12px; border: 1px solid var(--line-strong);
  border-radius: var(--r-s); background: var(--surface); font: inherit; font-size: var(--t-text);
  flex: none;
}
input.adraw__time { width: 108px; }
input.adraw__num { width: 150px; }
.adraw__base { margin-top: var(--s4); }
.adraw__common { margin-top: var(--s6); border-top: 1px solid var(--line-soft); padding-top: var(--s4); display: grid; gap: var(--s3); }
.adraw__check { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-note); cursor: pointer; }
.adraw__check input { width: 16px; height: 16px; accent-color: var(--blue); }
.adraw__hint { font-size: var(--t-note); color: var(--ink-3); margin: var(--s3) 0 var(--s2); }
.adraw__logline { margin-top: var(--s1); }

/* Мини-карта активности: день строкой, час клеткой */
.aheat { display: grid; gap: 2px; }
.aheat__row { display: flex; gap: 2px; align-items: center; }
.aheat__day { width: 20px; flex: none; font-size: var(--t-micro); color: var(--ink-4); }
.aheat__cell { flex: 1; height: 14px; min-width: 8px; border-radius: 3px; background: var(--sunken-2); }

/* Ячейка «Автоматика» в таблице ставок: кнопка без вида кнопки */
.plancell { background: none; border: 0; padding: 0; cursor: pointer; font: inherit; text-align: left; }

.bid__form { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: var(--s6); align-items: start; }
.bid__form h3 { font-size: var(--t-card); margin-bottom: var(--s3); }
.bid__flags { display: grid; gap: var(--s2); margin-top: var(--s4); }
.bid__check { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-note); cursor: pointer; }
.bid__check input { width: 16px; height: 16px; accent-color: var(--blue); }
.bid__row-tools { display: flex; gap: var(--s2); justify-content: flex-end; position: relative; }
.bid__chart { width: 100%; height: auto; display: block; }

/* ============================================================
   Значки и картинки состояний
   ============================================================

   Значок это квадрат, закрашенный currentColor, а картинка задает ему
   форму маской. Отсюда главное свойство: один файл годится и серому
   пункту меню, и зеленой строке роста, потому что цвет берется с места,
   куда значок поставлен. Тегом img так не выйдет: картинку не покрасить.

   Размер по умолчанию 18: на нем толщина линии значка совпадает с весом
   текста рядом. Крупнее ставим только там, где значок несет смысл сам,
   а не подпирает слово. */

.ic {
  display: inline-block; width: 18px; height: 18px; flex: none;
  background-color: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
  vertical-align: -3px;
}
.ic--sm { width: 15px; height: 15px; }
.ic--lg { width: 22px; height: 22px; }
.ic--xl { width: 26px; height: 26px; }
.ic--dim { opacity: .5; }

/* Состояние красится смыслом, а не местом: зеленое это хорошо,
   красное это потеря, серое это «неизвестно». */
.ic--ok { color: var(--green-ink); }
.ic--bad { color: var(--alarm); }
.ic--warn { color: var(--warn); }
.ic--unknown, .ic--paused, .ic--offline { color: var(--ink-3); }
.ic--limit, .ic--syncing { color: var(--blue-deep); }
.ic--noaccess { color: var(--ink-2); }

.btn .ic { width: 15px; height: 15px; vertical-align: -2px; }
.pill .ic, .fsel .ic, .hub__x .ic, .hub__open .ic { width: 14px; height: 14px; vertical-align: -2px; }
.fsel .ic { margin-right: 5px; color: var(--ink-3); }

/* значок у показателя воронки и у строки ведомости */
.fun__t .ic, .ind__k .ic { color: var(--ink-3); margin-right: 5px; }
.legend__k .ic { width: 17px; height: 17px; }
.hub__k .ic { width: 12px; height: 12px; margin-right: 4px; opacity: .7; vertical-align: -1px; }

/* ---------- пустой экран ----------

   Раньше на месте отсутствующих данных стояла одна серая надпись, и это
   читалось как поломка. Теперь картинка, строка о том, что случилось, и
   пояснение, почему так, - человек понимает, ждать ему или чинить. */

.art { padding: var(--s6) var(--s4); text-align: center; }
/* Меряем картинку высотой, а не шириной: рисунки разной формы, и по ширине
   вертикальный сейф выходил бы вдвое крупнее лежачего календаря. */
.art__img { height: 132px; width: auto; max-width: 90%; display: block; margin: 0 auto var(--s3); }
.art__t { font-size: var(--t-card); font-weight: 700; }
.art__s {
  font-size: var(--t-note); color: var(--ink-2); line-height: 1.5;
  margin: 5px auto 0; max-width: 440px;
}
.art .btn, .art .pill { margin-top: var(--s4); }
.art--sm { padding: var(--s6) var(--s4); }
.art--sm .art__img { height: 96px; }

/* Картинка при отказе Авито стоит слева от объяснения: отказ читают, а не
   разглядывают, поэтому текст остается главным. */
.msg--art { display: flex; align-items: center; gap: var(--s4); }
.msg--art .art__img { height: 68px; width: auto; margin: 0; flex: none; }
.msg--art > div { min-width: 0; }

/* ---------- советы по времени ----------

   Таблица часов не говорит, что делать. Советы говорят: каждый со своим
   значком, своим утверждением и числом, на котором оно построено. */

.advice { display: grid; gap: var(--s4); margin-top: var(--s4); }
.advice__row { display: flex; gap: var(--s3); align-items: flex-start; }
.advice__ic {
  width: 34px; height: 34px; flex: none; border-radius: 10px;
  display: grid; place-items: center; font-size: var(--t-card);
  background: var(--blue-soft);
}
.advice__t { font-weight: 700; font-size: var(--t-text); }
.advice__s { font-size: var(--t-note); color: var(--ink-2); line-height: 1.5; margin-top: 2px; }
.sheet__sub { font-size: var(--t-block); margin: var(--s12) 0 var(--s6); }

/* ---------- узкие экраны ---------- */

/* Панель остается колонкой до самого телефона: лентой поперек экрана она
   становилась вторым заголовком, а с темным фоном - еще и полосой в пол-окна.
   Ниже 760 на ее место встает выезжающий слой, см. workspace.css. */
@media (max-width: 1000px) {
  .main { padding: var(--s4) var(--work-pad); }
  .explorer { grid-template-columns: minmax(0, 1fr); }
  .dp__months { flex-direction: column; }
}

@media (max-width: 620px) {
  .art__img { height: 108px; }
  .msg--art { display: block; }
  .msg--art .art__img { margin: 0 0 var(--s2); }
  .brandbar__name { max-width: 130px; }
  .top__in { padding: var(--s2) var(--work-pad); }
  .hub { padding: var(--s6) var(--s4); }
  .hub__grid { grid-template-columns: minmax(0, 1fr); }
  .card { padding: var(--s4); }
  .gate__card { padding: var(--s6); }
}

/* ============================================================
   Автозагрузка

   Слева список объявлений, справа выбранное целиком, поле за полем. Так
   задумано: таблица в сотню колонок влезает только в электронную книгу, а
   работать с ней глазами невозможно - в готовых решениях это самое больное
   место. Здесь виден один объект целиком, а общее для всех ставится кнопкой
   «Поставить всем».
   ============================================================ */

.feed__bar {
  display: flex; align-items: center; gap: var(--s3);
  flex-wrap: wrap; margin-bottom: var(--s4);
}
.feed__cat {
  flex: 1 1 320px; min-width: 0;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
  padding: 10px 14px; font-size: var(--t-note); color: var(--ink-2);
}
.feed__cat b { color: var(--ink); font-weight: 700; }
.feed__cat .ic { width: 15px; height: 15px; vertical-align: -3px; margin-right: 8px; color: var(--ink-3); }

.feed__acts { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; margin-bottom: var(--s3); }
.feed__state { font-size: var(--t-note); color: var(--ink-3); margin-left: auto; }

.feed__split {
  display: grid; grid-template-columns: minmax(230px, 300px) minmax(0, 1fr);
  gap: var(--s4); align-items: start;
}
.feed__list {
  display: flex; flex-direction: column; gap: 6px;
  max-height: 74vh; overflow-y: auto; padding-right: 4px;
}
.feed__row {
  display: block; width: 100%; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-s);
  padding: 10px 12px; font: inherit; color: var(--ink);
}
.feed__row:hover { border-color: var(--line-strong); }
.feed__row.is-on { border-color: var(--blue); background: var(--bg-selected); }
.feed__row.is-off { opacity: .5; }
.feed__rowtop { display: block; font-size: var(--t-note); line-height: 1.35; }
.feed__rowsub { display: block; font-size: var(--t-micro); color: var(--ink-3); margin-top: 3px; }

.feed__form {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-m); padding: var(--s6);
}
.feed__formtop {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s4);
}
.feed__formtop h2 { font-size: var(--t-block); min-width: 0; }
.feed__gr { font-size: var(--t-micro); line-height: var(--t-micro-lh); font-weight: var(--t-micro-w); text-transform: uppercase; letter-spacing: var(--t-micro-ls); color: var(--ink-3); margin-bottom: var(--s3); }
.feed__field { margin-bottom: var(--s4); }
.feed__req { color: var(--alarm); font-weight: 600; }
.feed__tag {
  font-family: ui-monospace, Consolas, monospace;
  font-size: var(--t-micro); color: var(--ink-4); background: var(--sunken-2);
  border-radius: 4px; padding: 1px 5px; font-weight: 400;
}
.feed__under { display: flex; align-items: baseline; gap: var(--s3); margin-top: 5px; }
.feed__under .hint { flex: 1; min-width: 0; margin: 0; }
.feed__all {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; font-size: var(--t-note); color: var(--blue-deep); white-space: nowrap;
}
.feed__all:hover { text-decoration: underline; }
.feed__more {
  background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
  font-weight: 600; color: var(--ink-2); margin-bottom: var(--s3);
}
.feed__more .ic { width: 14px; height: 14px; vertical-align: -3px; margin-right: 6px; transition: transform .15s; }
.feed__more.is-on .ic { transform: rotate(180deg); }

.feed__checks { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.feed__check { display: flex; align-items: center; gap: 6px; font-size: var(--t-note); cursor: pointer; }
.feed__check input { width: 15px; height: 15px; accent-color: var(--blue); }

.feed__photos { display: flex; flex-direction: column; gap: var(--s2); }
.feed__thumbs { display: flex; flex-wrap: wrap; gap: 8px; }
.feed__thumb { position: relative; width: 82px; height: 62px; }
.feed__thumb img {
  width: 100%; height: 100%; object-fit: cover;
  border-radius: var(--r-s); border: 1px solid var(--line);
}
.feed__thumbx {
  position: absolute; top: -6px; right: -6px; width: 20px; height: 20px;
  border-radius: 50%; border: 1px solid var(--line); background: var(--surface);
  color: var(--ink-2); cursor: pointer; line-height: 1; font-size: var(--t-text);
}
.feed__thumbx:hover { color: var(--alarm); border-color: var(--alarm); }
.feed__gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); gap: 8px; }
.feed__galitem { padding: 0; border: 2px solid transparent; border-radius: var(--r-s); cursor: pointer; background: none; }
.feed__galitem img { width: 100%; height: 88px; object-fit: cover; border-radius: var(--r-s); display: block; }
.feed__galitem.is-on { border-color: var(--blue); }

.feed__bads { margin: var(--s2) 0 0; padding-left: 18px; }
.feed__bads li { cursor: pointer; padding: 2px 0; }
.feed__bads li:hover { text-decoration: underline; }

.feed__link { display: flex; gap: var(--s2); align-items: center; margin-bottom: var(--s3); }
.feed__link input { flex: 1; min-width: 0; }
.feed__url { font-size: var(--t-micro); word-break: break-all; text-align: right; font-weight: 400; }

.feed__hours { display: grid; grid-template-columns: repeat(auto-fill, minmax(64px, 1fr)); gap: 6px; margin-bottom: var(--s3); }
.feed__days { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: var(--s4); }
.feed__hour {
  padding: 7px 4px; text-align: center; cursor: pointer; font: inherit; font-size: var(--t-note);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-s); color: var(--ink-2);
}
.feed__hour:hover { border-color: var(--blue-line); }
.feed__hour.is-on { background: var(--blue); border-color: var(--blue); color: #fff; }
.feed__days .feed__hour { min-width: 52px; }

.feed__item { border-bottom: 1px solid var(--line-soft); padding: var(--s3) 0; }
.feed__item:last-child { border-bottom: 0; }
.feed__itemtop { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; }
.feed__itemsub { font-size: var(--t-note); color: var(--ink-3); margin-top: 3px; }
.feed__item .msg { margin-top: 6px; }

.feed__mask {
  position: fixed; inset: 0; z-index: 60; background: rgba(15, 23, 42, .45);
  display: flex; align-items: flex-start; justify-content: center; padding: 6vh var(--s4);
}
.feed__win {
  background: var(--surface); border-radius: var(--r-m); width: min(720px, 100%);
  max-height: 80vh; display: flex; flex-direction: column; box-shadow: var(--shadow-lift);
}
.feed__winhead {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--s4) var(--s6); border-bottom: 1px solid var(--line);
}
.feed__winhead h2 { font-size: var(--t-block); }
.feed__winx { background: none; border: 0; font-size: var(--t-tile); line-height: 1; cursor: pointer; color: var(--ink-3); }
.feed__winx:hover { color: var(--ink); }
.feed__winbody { padding: var(--s4) var(--s6) var(--s6); overflow-y: auto; }
.feed__cats { display: flex; flex-direction: column; gap: 2px; margin-top: var(--s3); }
.feed__cat1 {
  text-align: left; background: none; border: 0; border-radius: var(--r-s);
  padding: 8px 10px; cursor: pointer; font: inherit; font-size: var(--t-note); color: var(--ink-2);
}
.feed__cat1:hover { background: var(--blue-soft); color: var(--blue-deep); }

@media (max-width: 900px) {
  .feed__split { grid-template-columns: minmax(0, 1fr); }
  .feed__list { max-height: 260px; }
}

.feed__nopic {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; border: 1px dashed var(--line-strong);
  border-radius: var(--r-s); font-size: var(--t-micro); color: var(--ink-4);
}

/* ---- таблица объявлений ----

   Ведет себя как электронная таблица, поэтому и выглядит как она: тонкие
   линии, плотные строки, липкая шапка и первый столбец с номерами. Рамка
   текущей клетки синяя, выделение бледно-синее, клетка с ошибкой красная. */

.grid__box {
  border: 1px solid var(--line); border-radius: var(--r-m);
  background: var(--surface); overflow: auto;
  max-height: 62vh; outline: none;
}
.grid__box:focus-within { border-color: var(--blue-line); }
.grid { border-collapse: separate; border-spacing: 0; font-size: var(--t-note); width: max-content; min-width: 100%; }
.grid th, .grid td {
  border-right: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);
  padding: 6px 9px; text-align: left; vertical-align: top;
  min-width: 110px; max-width: 280px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.grid thead th {
  position: sticky; top: 0; z-index: 3;
  background: var(--sunken); font-size: var(--t-micro); font-weight: 700;
  color: var(--ink-2); white-space: nowrap; border-bottom: 1px solid var(--line);
}
.grid thead th.is-req { color: var(--ink); }
/* Тег файла Авито под русским заголовком нужен только тем, кто читает
   спецификацию. По умолчанию его не видно, он проступает при наведении на
   заголовок и целиком в режиме «Все поля» (.grid.is-all). Прячем через
   visibility, а не display: иначе шапка прыгает по высоте под курсором. */
.grid__tag {
  display: block; font-family: ui-monospace, Consolas, monospace;
  font-size: var(--t-micro); color: var(--ink-4); font-weight: 400; margin-top: 1px;
  visibility: hidden;
}
.grid thead th:hover .grid__tag,
.grid thead th:focus-within .grid__tag,
.grid.is-all .grid__tag { visibility: visible; }
.grid__n, .grid__sw {
  position: sticky; z-index: 2; background: var(--sunken);
  color: var(--ink-3); text-align: center; width: 1%;
  font-variant-numeric: tabular-nums; user-select: none;
}
.grid__n { left: 0; min-width: 44px; }
.grid__sw { left: 44px; min-width: 34px; cursor: pointer; }
.grid__sw .ic { width: 13px; height: 13px; vertical-align: -2px; }
.grid thead .grid__n, .grid thead .grid__sw { z-index: 4; }
.grid tbody tr:hover .grid__n { color: var(--ink); }
.grid tbody tr.is-here .grid__n { background: var(--blue-soft); color: var(--blue-deep); }
.grid tbody tr.is-off td { opacity: .45; }
.grid td.is-sel { background: var(--bg-selected); }
.grid td.is-cur { box-shadow: inset 0 0 0 2px var(--blue); background: var(--surface); }
.grid td.is-bad { background: var(--alarm-soft); box-shadow: inset 2px 0 0 var(--alarm); }
.grid td.is-bad.is-cur { box-shadow: inset 0 0 0 2px var(--alarm); }
.grid__in {
  width: 100%; min-width: 160px; border: 0; outline: none; padding: 0;
  font: inherit; background: transparent; color: inherit;
}

.feed__more2 { display: flex; gap: var(--s2); margin-left: var(--s3); flex-wrap: wrap; }
.feed__cols {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 4px 14px; margin: var(--s3) 0;
}
.feed__under2 {
  margin-top: var(--s4); background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-m); padding: var(--s4) var(--s6);
}
.feed__two { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s6); align-items: start; }
.feed__two textarea { min-height: 150px; }

@media (max-width: 900px) {
  .feed__two { grid-template-columns: minmax(0, 1fr); }
  .grid__box { max-height: 50vh; }
}

.grid td { position: relative; }
.grid td.is-fill { background: var(--blue-soft); box-shadow: inset 0 0 0 1px var(--blue-line); }
.grid__pull {
  position: absolute; right: -4px; bottom: -4px; width: 8px; height: 8px;
  background: var(--blue); border: 1px solid #fff; border-radius: 2px;
  cursor: crosshair; z-index: 2;
}
.grid tbody tr:hover td { background-color: rgba(29, 78, 216, .03); }

.feed__steps { margin: var(--s3) 0; padding-left: 20px; font-size: var(--t-note); color: var(--ink-2); line-height: 1.7; }
.feed__steps li { margin-bottom: 4px; }

/* Полоска листов - как вкладки книги, только сверху таблицы */
.feed__sheets { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: var(--s3); }
.feed__sheet {
  display: inline-flex; align-items: center; gap: 7px;
  background: var(--sunken); border: 1px solid var(--line); border-bottom-color: transparent;
  border-radius: var(--r-s) var(--r-s) 0 0; padding: 7px 13px;
  font: inherit; font-size: var(--t-note); color: var(--ink-2); cursor: pointer;
}
.feed__sheet:hover { color: var(--ink); background: var(--bg-hover); }
.feed__sheet.is-on { background: var(--surface); color: var(--ink); font-weight: 700; border-color: var(--line); box-shadow: inset 0 2px 0 var(--blue); }
.feed__sheetn { font-size: var(--t-micro); color: var(--ink-4); font-variant-numeric: tabular-nums; }
.feed__sheet--add { color: var(--blue-deep); border-style: dashed; }
.feed__sheet--add .ic { width: 13px; height: 13px; vertical-align: -2px; }

.grid__st { position: sticky; left: 78px; z-index: 2; background: var(--surface); min-width: 130px; }
.grid thead .grid__st { z-index: 4; background: var(--sunken); }
.grid__stq { color: var(--ink-4); }
.grid__st .tag { font-size: var(--t-micro); padding: 2px 6px; }
.grid__st a { text-decoration: none; }

.feed__rulename {
  font-family: var(--display); font-weight: 700; font-size: var(--t-card);
  border: 0; border-bottom: 1px dashed var(--line-strong); border-radius: 0;
  padding: 2px 0; background: none; max-width: 320px;
}
.feed__rulename:focus { border-bottom-color: var(--blue); }
.grid--rule { width: 100%; min-width: 0; font-size: var(--t-note); table-layout: fixed; }
.grid--rule th { position: static; background: var(--sunken); font-size: var(--t-micro); white-space: normal; }
.grid--rule th:last-child { width: 34px; }
.grid--rule td { min-width: 0; max-width: none; padding: 4px 5px; }
.grid--rule .grid__in { min-width: 0; width: 100%; }
.grid--rule .feed__all { padding: 0; }
.grid--rule .feed__all .ic { width: 14px; height: 14px; }

/* Узкий экран: таблицей на телефоне работать невозможно, поэтому там
   объявления идут списком - по карточке на строку. Правится все то же самое,
   просто по одному объявлению за раз. */
.feed__cards { display: flex; flex-direction: column; gap: 8px; }
.feed__card {
  display: block; width: 100%; text-align: left; cursor: pointer; font: inherit;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-s);
  padding: 11px 13px; color: var(--ink);
}
.feed__card.is-on { border-color: var(--blue); background: var(--bg-selected); }
.feed__card.is-off { opacity: .5; }
.feed__cardtop { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.feed__cardtop b { font-size: var(--t-text); line-height: 1.3; }
.feed__cardsub { display: block; font-size: var(--t-note); color: var(--ink-3); margin-top: 4px; }

@media (max-width: 760px) {
  .feed__acts { gap: 6px; }
  .feed__acts .pill, .feed__acts .btn { font-size: var(--t-note); padding: 7px 11px; }
  .feed__more2 { margin-left: 0; width: 100%; }
  .feed__two { grid-template-columns: minmax(0, 1fr); }
  .grid__box { max-height: none; }
}

/* Во весь экран: таблица занимает окно целиком. Меню и карточка уезжают -
   на сотне объявлений видно тридцать строк вместо трех. */
.feed__wrap.is-full {
  position: fixed; inset: 0; z-index: 40; overflow: auto;
  background: var(--bg-app); padding: var(--s4) var(--s6) var(--s6);
}
.feed__wrap.is-full .grid__box { max-height: calc(100vh - 150px); }

/* Плюсик в шапке - как в Google: раскрывает спрятанные столбцы */
.grid__plus {
  position: sticky; right: 0; z-index: 2;
  width: 34px; min-width: 34px; max-width: 34px; text-align: center;
  background: var(--surface); border-left: 1px solid var(--line);
  color: var(--ink-3); cursor: pointer; user-select: none; font-size: var(--t-text);
}
.grid thead .grid__plus { background: var(--sunken); z-index: 5; }
.grid thead .grid__plus:hover { color: var(--blue-deep); background: var(--blue-soft); }
.grid__plus i { display: block; font-style: normal; font-size: var(--t-micro); color: var(--ink-4); }

/* ============================================================
   ЭТАП 1. Дизайн-система: выравнивание фундамента.
   Токены и компоненты в кабинете уже были, здесь только чиню
   расхождения с брифом и добавляю недостающие состояния. Блок
   стоит в конце файла: где надо, он мягко перебивает базовые
   правила своей позицией, ничего не переименовывая.
   ============================================================ */

:root {
  --r-c: 12px;                 /* компактная карточка */
}

/* ---- Шкала типографики: семь ступеней классами. Порядок тот же, что у
   токенов в :root. Класс ставится там, где элемент не h1, h2 и не h3 -
   на span, div или ячейку. ---- */
body { font-size: var(--t-text); line-height: 1.45; }

.t-screen { font-family: var(--display); font-size: var(--t-screen); line-height: var(--t-screen-lh); font-weight: var(--t-screen-w); letter-spacing: var(--t-screen-ls); }
.t-block  { font-family: var(--display); font-size: var(--t-block); line-height: var(--t-block-lh); font-weight: var(--t-block-w); letter-spacing: var(--t-block-ls); }
.t-card   { font-size: var(--t-card); line-height: var(--t-card-lh); font-weight: var(--t-card-w); letter-spacing: var(--t-card-ls); }
.t-figure { font-size: var(--t-figure); line-height: var(--t-figure-lh); font-weight: var(--t-figure-w); letter-spacing: var(--t-figure-ls); font-variant-numeric: tabular-nums; }
.t-tile   { font-size: var(--t-tile); line-height: var(--t-tile-lh); font-weight: var(--t-figure-w); letter-spacing: var(--t-figure-ls); font-variant-numeric: tabular-nums; }
.t-text   { font-size: var(--t-text); line-height: var(--t-text-lh); font-weight: var(--t-text-w); letter-spacing: var(--t-text-ls); }
.t-note   { font-size: var(--t-note); line-height: var(--t-note-lh); font-weight: var(--t-note-w); letter-spacing: var(--t-note-ls); }
.t-micro  { font-size: var(--t-micro); line-height: var(--t-micro-lh); font-weight: var(--t-micro-w); letter-spacing: var(--t-micro-ls); text-transform: uppercase; color: var(--ink-3); }
/* Число в ячейке: та же подпись, но весом 500 и к правому краю */
.t-cell   { font-size: var(--t-note); line-height: var(--t-note-lh); font-weight: var(--t-cell-w); letter-spacing: var(--t-note-ls); font-variant-numeric: tabular-nums; text-align: right; }

/* Прежние имена шкалы. Разметка ими уже набрана, поэтому они остались, но
   собственных кеглей больше не держат: каждое - псевдоним ступени. */
.t-h1 { font-family: var(--display); font-size: var(--t-screen); line-height: var(--t-screen-lh); font-weight: var(--t-screen-w); letter-spacing: var(--t-screen-ls); }
.t-h2 { font-family: var(--display); font-size: var(--t-block); line-height: var(--t-block-lh); font-weight: var(--t-block-w); letter-spacing: var(--t-block-ls); }
.t-h3 { font-size: var(--t-card); line-height: var(--t-card-lh); font-weight: var(--t-card-w); letter-spacing: var(--t-card-ls); }
.t-body { font-size: var(--t-text); line-height: var(--t-text-lh); font-weight: var(--t-text-w); }
.t-table { font-size: var(--t-note); line-height: var(--t-note-lh); font-weight: var(--t-note-w); }
.t-caption { font-size: var(--t-note); line-height: var(--t-note-lh); font-weight: var(--t-note-w); color: var(--ink-3); }
.t-caption--strong { font-weight: var(--t-cell-w); }

/* ---- Кнопки: вес по брифу и состояние загрузки ---- */
.btn { font-weight: 600; min-height: 40px; }
.btn--sm { min-height: 34px; }
.btn.is-loading { color: transparent !important; pointer-events: none; position: relative; }
.btn.is-loading::after {
  content: ""; position: absolute; width: 16px; height: 16px;
  border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
  color: #fff; animation: fh-spin .6s linear infinite;
}
.btn--light.is-loading::after, .btn--ghost.is-loading::after { color: var(--ink-2); }
@keyframes fh-spin { to { transform: rotate(360deg); } }

/* ---- Поля: высота, ошибка, отключено, загрузка ---- */
input[type="text"], input[type="password"], input[type="date"], input[type="number"], input[type="email"], select {
  min-height: 40px;
}
input:disabled, textarea:disabled, select:disabled {
  background: var(--sunken); color: var(--ink-4); cursor: not-allowed; border-color: var(--line);
}
.field--error input, .field--error textarea, .field--error select,
input.is-error, textarea.is-error {
  border-color: var(--alarm); background: var(--alarm-soft);
}
.field--error input:focus, input.is-error:focus {
  box-shadow: 0 0 0 3px rgba(220, 38, 38, .18);
}
.field__err { display: block; margin-top: 5px; font-size: var(--t-note); line-height: 16px; color: var(--alarm); }
.field.is-loading { position: relative; }
.field.is-loading input { padding-right: 38px; }
.field.is-loading::after {
  content: ""; position: absolute; right: 12px; top: 32px; width: 14px; height: 14px;
  border: 2px solid var(--ink-4); border-top-color: transparent; border-radius: 50%;
  animation: fh-spin .6s linear infinite;
}

/* Поле с кнопкой показа пароля. Разметку под нее ставим на Этапе 3,
   стиль готов заранее. */
.field--pw { position: relative; }
.field--pw input { padding-right: 44px; }
.field__eye {
  position: absolute; right: 6px; top: 26px; width: 32px; height: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; background: transparent; color: var(--ink-3); cursor: pointer; border-radius: 8px;
}
.field__eye:hover { background: var(--sunken-2); color: var(--ink); }

/* На узком экране поля выше - легче попасть пальцем. Кегль 16px: меньше
   него телефон при фокусе приближает страницу, и верстка уезжает вбок. ---- */
@media (max-width: 760px) {
  input[type="text"], input[type="password"], input[type="date"], input[type="number"], input[type="email"], input[type="time"], input[type="search"], textarea, select {
    min-height: 44px; padding: 12px; font-size: var(--t-field-mobile);
  }
  select { padding-right: 36px; }
  .btn { min-height: 44px; }
}
/* Списки на телефоне тоже 16px. Правило выше их не удерживает: workspace.css
   подключается следом за ui.css и сбрасывает всем полям font: inherit, а у
   списка нет type, по которому ui.css перебило бы это, как у полей ввода.
   Поэтому селектор на класс выше - и только по своим местам: форма правила,
   массовая правка и выбор периода бюджета. Чужие экраны сейчас в работе,
   общее правило для всех списков туда лезть не должно. */
@media (max-width: 760px) {
  .bid__form select, .bid__bulkrow select, select.pill { min-height: 44px; font-size: var(--t-field-mobile); }
}

/* ---- Бейджи: добавляю нейтральный «Вы» и информационный «Скоро».
   Оба со своим текстом, статус не только цветом. ---- */
.badge--you { background: var(--blue-soft); color: var(--blue-deep); }
.badge--soon { background: var(--warn-soft); color: var(--warn); }
.badge--info { background: var(--blue-soft); color: var(--blue-deep); }

/* ---- Обобщенная карточка и вложенный блок. Помогают собирать новые
   экраны из одних кирпичей, старые классы не трогают. ---- */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-m); padding: var(--s6);
}
.card--compact { border-radius: var(--r-c); padding: var(--s4); }
.subcard {
  background: var(--sunken); border-radius: var(--r-s); padding: var(--s4);
  border: 1px solid var(--line-soft);
}

/* ---- Пустое состояние: единый каркас (иллюстрация, заголовок, текст,
   действие). Полностью экраны переведем на него на своем этапе. ---- */
.blank {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--s3); padding: var(--s8) var(--s4);
}
.blank img, .blank svg { width: clamp(120px, 20vw, 160px); height: auto; }
.blank h3 { font-size: var(--t-card); line-height: 22px; font-weight: 600; margin: 0; color: var(--ink); }
.blank p { margin: 0; max-width: 42ch; font-size: var(--t-text); line-height: 20px; color: var(--ink-3); }
.blank .btn { margin-top: var(--s1); }

/* ============================================================
   Переключатель клиента в шапке (промт дизайнера, шаг 1).
   Всегда виден, кого ведем; смена клиента с любого экрана без
   возврата в список. Ширина фиксированная, чтобы шапка не
   прыгала от длинных имен.
   ============================================================ */

.switch {
  display: inline-flex; align-items: center; gap: var(--s2);
  width: 264px; max-width: 264px; flex: none;
  font: inherit; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-s); padding: 5px 10px;
  transition: border-color .14s ease, background .14s ease;
}
.switch:hover { border-color: var(--line-strong); background: var(--sunken); }
.switch[aria-expanded="true"] { border-color: var(--blue); background: var(--surface); }
.switch__ava {
  width: 30px; height: 30px; flex: none; border-radius: 50%;
  background: var(--blue); color: #fff; font-weight: 700; font-size: var(--t-note);
  display: grid; place-items: center;
}
.switch__lines { min-width: 0; flex: 1; line-height: 1.2; }
.switch__name {
  display: block; font-size: var(--t-note); font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.switch__sub {
  display: block; font-size: var(--t-micro); color: var(--ink-3); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.switch__chev { flex: none; color: var(--ink-4); font-size: var(--t-micro); }

/* Выпадающий список */
.switchpop {
  position: absolute; top: calc(var(--brand) - 6px); left: var(--s4);
  z-index: 60; width: 340px; max-width: calc(100vw - 32px);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-m); box-shadow: var(--shadow-pop);
  overflow: hidden; display: none;
}
.switchpop.is-open { display: block; }
.switchpop__search { padding: var(--s3); border-bottom: 1px solid var(--line); }
.switchpop__search input { min-height: 38px; }
.switchpop__scroll { max-height: 60vh; overflow: auto; padding: var(--s2); }
.switchpop__group {
  padding: var(--s2) var(--s3) var(--s1); font-size: var(--t-micro); font-weight: 600;
  letter-spacing: var(--t-micro-ls); text-transform: uppercase; color: var(--ink-4);
}
.switchpop__row {
  display: flex; align-items: center; gap: var(--s3); width: 100%;
  padding: 8px var(--s3); border: 0; background: transparent; border-radius: var(--r-s);
  font: inherit; text-align: left; cursor: pointer;
}
.switchpop__row:hover, .switchpop__row.is-cur { background: var(--sunken); }
.switchpop__row.is-here { outline: 2px solid var(--blue); outline-offset: -2px; }
.switchpop__ava {
  width: 30px; height: 30px; flex: none; border-radius: 50%;
  background: var(--blue); color: #fff; font-weight: 700; font-size: var(--t-note);
  display: grid; place-items: center;
}
.switchpop__lines { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.switchpop__name {
  display: block; font-size: var(--t-note); font-weight: 600; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.switchpop__facts { display: block; font-size: var(--t-micro); color: var(--ink-3); margin-top: 1px; }
.switchpop__facts b { color: var(--ink); font-weight: 600; }
/* Состояние аккаунта в списке переключателя - та же точка со словом, что и
   везде (.state). Голая точка отсюда убрана: цвет без слова читается
   наугад, а подпись в title на телефоне не показывается вовсе. Строка
   молчит, когда у аккаунта все хорошо: в списке из шести хорошая новость
   не должна отнимать внимание у плохой. */
.switchpop__st { flex: none; max-width: 52%; text-align: right; }
.switchpop__st > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.switchpop__foot {
  display: flex; gap: var(--s3); padding: var(--s3);
  border-top: 1px solid var(--line);
}
.switchpop__foot button {
  flex: 1; font: inherit; font-size: var(--t-note); font-weight: 600; cursor: pointer;
  padding: 9px; border-radius: var(--r-s); border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-2);
}
.switchpop__foot button:hover { background: var(--sunken); color: var(--ink); }
.switchpop__foot .is-primary { border-color: var(--blue); background: var(--blue); color: #fff; }
.switchpop__foot .is-primary:hover { background: var(--blue-dark); border-color: var(--blue-dark); color: #fff; }
.switchpop__none { padding: var(--s6) var(--s3); text-align: center; color: var(--ink-3); font-size: var(--t-note); }

/* Узкая шапка: переключатель ужимаем, но текущего клиента видно всегда */
@media (max-width: 760px) {
  .switch { width: auto; max-width: 190px; }
  .switch__sub { display: none; }
  .switchpop { left: var(--s2); right: var(--s2); width: auto; }
}

/* ============================================================
   Скелетоны (промт дизайнера, шаг 2). Пока число едет, на его
   месте серая плашка, а не ноль и не пустота. Ноль это значение,
   подменять им незагруженное нельзя. Высоту держим, чтобы строки
   и карточки не прыгали и не сбивали клик.
   ============================================================ */
.skel {
  display: inline-block; border-radius: 5px; vertical-align: -2px;
  background: linear-gradient(90deg, var(--bg-hover) 25%, var(--bg-subtle) 37%, var(--bg-hover) 63%);
  background-size: 400% 100%; animation: fh-skel 1.2s ease-in-out infinite;
}
.skel--num { width: 46px; height: 15px; }
.skel--sm { width: 34px; height: 13px; }
.skel--wide { width: 80px; height: 13px; }
@keyframes fh-skel { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* ============================================================
   Портфель клиентов: таблица, итоги, фильтры, поиск, вид (шаги 3-6).
   ============================================================ */

/* Переключатель вида таблица/карточки */
.hub__seg { display: inline-flex; padding: 3px; background: var(--sunken); border-radius: var(--r-s); gap: 2px; }
.hub__segb {
  font: inherit; font-size: var(--t-note); font-weight: 600; cursor: pointer;
  padding: 5px 12px; border: 0; border-radius: 7px; background: transparent; color: var(--ink-3);
}
.hub__segb:hover { color: var(--ink); }
.hub__segb.is-on { background: var(--surface); color: var(--ink); box-shadow: 0 1px 2px rgba(15,23,42,.08); }

/* Строка итогов: отвечает на утренний вопрос за секунду, каждый кусок фильтрует */
.hub__sum {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) var(--s2);
  margin: var(--s4) 0 var(--s3); font-size: var(--t-text); color: var(--ink-2);
}
.hub__sumdot { color: var(--ink-4); }
.hub__sumx {
  font: inherit; font-size: var(--t-text); color: var(--ink-2); background: transparent;
  border: 0; padding: 2px 4px; border-radius: 6px; cursor: pointer;
}
.hub__sumx:hover { background: var(--blue-soft); color: var(--blue-deep); }

/* Быстрые фильтры */
.hub__filters { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s3); }
.hub__flt {
  font: inherit; font-size: var(--t-note); font-weight: 500; cursor: pointer;
  padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-2);
}
.hub__flt:hover { border-color: var(--line-strong); }
.hub__flt.is-on { background: var(--blue); border-color: var(--blue); color: #fff; }
.hub__flt i { font-style: normal; opacity: .7; margin-left: 3px; }
.hub__flt.is-on i { opacity: .85; }

.hub__search { margin-bottom: var(--s3); }
.hub__searchbox { position: relative; max-width: 380px; }
.hub__searchbox .ic {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--ink-3); pointer-events: none;
}
.hub__search input {
  width: 100%; box-sizing: border-box;
  padding: 10px 14px 10px 38px;
  font: inherit; font-size: var(--t-text); color: var(--ink);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-s);
  transition: border-color .12s, box-shadow .12s;
}
.hub__search input::placeholder { color: var(--ink-4); }
.hub__search input:hover { border-color: var(--line-strong); }
.hub__search input:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px var(--blue-soft);
}
.hub__searchbox:focus-within .ic { color: var(--blue); }

/* Таблица портфеля */
.hub__tblwrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r-m); background: var(--surface); }
.ptbl { width: 100%; border-collapse: collapse; font-size: var(--t-note); }
.ptbl th, .ptbl td {
  padding: 10px 14px; border-bottom: 1px solid var(--line); text-align: left; white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.ptbl thead th {
  position: sticky; top: 0; background: var(--sunken); z-index: 1;
  font-size: var(--t-micro); line-height: var(--t-micro-lh); font-weight: var(--t-micro-w);
  letter-spacing: var(--t-micro-ls); text-transform: uppercase;
  color: var(--ink-3); cursor: pointer; user-select: none;
}
.ptbl thead th:hover { color: var(--ink); }
.ptbl__num { text-align: right; }
.ptbl thead .ptbl__num { text-align: right; }
.ptbl tbody tr { cursor: pointer; }
.ptbl tbody tr:hover { background: var(--sunken); }
.ptbl tbody tr:last-child td { border-bottom: 0; }
.ptbl__cli { display: flex; align-items: center; gap: var(--s3); }
.ptbl__ava {
  width: 30px; height: 30px; flex: none; border-radius: 50%;
  background: var(--blue); color: #fff; font-weight: 700; font-size: var(--t-note); display: grid; place-items: center;
}
.ptbl__name { font-weight: 600; color: var(--ink); }
.ptbl__name i { display: block; font-style: normal; font-weight: 400; font-size: var(--t-micro); color: var(--ink-4); }
.ptbl__own { color: var(--blue-deep); }
.ptbl__upd { color: var(--ink-3); }
.hub__stale { color: var(--ink-4); }
.ptbl__act { text-align: right; }
.hub__dots {
  font: inherit; font-size: var(--t-note); font-weight: 600; cursor: pointer;
  padding: 5px 12px; border: 1px solid var(--blue-line); border-radius: var(--r-s);
  background: var(--blue-soft); color: var(--blue-deep);
}
.hub__dots:hover { background: var(--blue); color: #fff; border-color: var(--blue); }
.hub__none { padding: var(--s8) var(--s4); text-align: center; color: var(--ink-3); }

@media (max-width: 760px) {
  .hub__seg { order: 3; }
  .ptbl th, .ptbl td { padding: 9px 10px; }
}

/* ============================================================
   Клиентский интерфейс, сентябрь 2026.
   Строка состояния, свои списки и переключатели, меню «Еще» на
   «Моих аккаунтах», форма правила шагами на телефоне, ставки без
   столбцов за краем, два графика правила, служебный раздел хозяина.
   ============================================================ */

/* ---- Единая точка состояния: одна форма на весь кабинет ----

   До этой правки на одном экране жили четыре формы разом: цветная плашка,
   значок в кружке, точка в таблице и просто серое слово. Форма перестает
   что-либо значить, когда их четыре. Осталась одна: точка 6 пикселов и
   слово рядом.

   Цветов у точки ровно четыре, и каждый отвечает на единственный вопрос
   человека - надо ли вмешиваться:

     --ok   зеленый  идет само, вмешиваться не надо;
     --run  синий    идет прямо сейчас, работа в ходу;
     --act  рыжий    нужно вмешаться, и это единственный рыжий на экране;
     --off  серый    ничего не происходит: черновик, пауза, пусто, неизвестно.

   Красного среди них нет намеренно. Отказ сервера и упавший сбор - это
   тоже «надо вмешаться», а не отдельная беда: человек все равно делает
   одно и то же движение, и второй тревожный цвет ему ничего не добавляет.

   Слово рядом набирается подписью 13/18 весом 400 цветом --text-primary.
   Не прописными, не жирным, не цветным: цвет уже сказала точка, повторять
   его текстом значит кричать дважды.

   .state       - точка со словом внутри строки, ячейки, карточки;
   .state-line  - та же точка отдельной строкой над списком (очередь
                  отчетов, правила биддера), с отступом снизу. */
.state, .state-line {
  align-items: baseline; gap: 8px; min-width: 0;
  font-size: var(--t-note); line-height: var(--t-note-lh); font-weight: var(--t-note-w);
  color: var(--ink-2);
}
.state { display: inline-flex; }
.state-line { display: flex; margin: 0 0 var(--s4); }
.state::before, .state-line::before {
  content: ''; flex: none; width: 6px; height: 6px; border-radius: 50%;
  /* Точка держится на базовой линии слова, а не на середине блока: иначе
     при переносе в две строки она уезжала к середине абзаца. */
  transform: translateY(-2px);
  background: var(--border-strong);
}
.state > span, .state-line > span { min-width: 0; overflow-wrap: anywhere; }
.state--ok::before,  .state-line--ok::before  { background: var(--success); }
.state--run::before, .state-line--run::before { background: var(--brand-primary); }
.state--act::before, .state-line--act::before { background: var(--attention); }
.state--off::before, .state-line--off::before { background: var(--border-strong); }
.state--off, .state-line--off { color: var(--ink-3); }

/* ---- Тройка кошелька ----

   Деньги аккаунта не показываются одним числом. Остаток сам по себе ничего
   не решает: 28 450 руб - это много или мало, зависит от того, сколько
   уходит в день. Поэтому всегда тройка, и третье число наше:

     28 450 руб · аванс 18 000 руб · хватит на 21 день

   Первые два есть и у Авито, и у конкурента. Третьего нет ни у кого, и
   только оно превращает остаток в срок, а срок - единственное, что человек
   может решить сегодня утром.

   Третье число берется там, где известен расход в день: на сводке и на
   слабых местах он считается по выбранному периоду. Где расхода нет - в
   панели и в списке аккаунтов - показываются два первых, и выдумывать
   третье нельзя.

   Когда дней меньше пяти, рыжеет только число дней: рыжий тут значит «пора
   класть деньги», а не «тревога». Суммы остаются черными. */
.wallet {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 5px;
  min-width: 0; font-size: var(--t-note); line-height: var(--t-note-lh); color: var(--ink-3);
}
.wallet__i { white-space: nowrap; }
.wallet b { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.wallet__x { color: var(--line-strong); }
.wallet--low .wallet__days b { color: var(--attention-ink); }
/* Тройка под заголовком экрана: она часть шапки, а не первый блок
   содержимого, поэтому лежит на голом холсте и отбита сверху на шаг. */
.head__wallet { margin: 0 0 var(--s2); }

/* Полоса «цифры собраны за другой период». Уровней поверхности в кабинете
   два - холст и карточка; эта полоса лежит на холсте и карточкой не
   притворяется. Раньше она была серой плашкой внутри белой карточки, то
   есть третьим уровнем ради одного предложения. */
.period-gap {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  margin: 0 0 var(--s6); padding: var(--s3) var(--s4);
  border: 1px solid var(--line); border-radius: var(--r-s);
  background: var(--sunken); color: var(--ink-2);
  font-size: var(--t-note); line-height: var(--t-note-lh);
}
.period-gap > span { min-width: 0; flex: 1 1 320px; }
/* В переключателе аккаунта строка узкая и одна. Обычным потоком, а не
   флексом: так работает многоточие, если аккаунт назван очень длинно. */
.switch__sub .wallet { display: block; }
/* Кнопка в строке состояния есть только у хозяина и ведет в «Служебное».
   Тихая ссылка-глагол: спорить с главной кнопкой рядом ей нечем. */
.state-line__set {
  flex: none; border: 0; padding: 0; background: none; font: inherit;
  font-weight: 600; color: var(--blue-deep); cursor: pointer;
}
.state-line__set:hover { text-decoration: underline; }
.state-line__set:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; border-radius: 4px; }

/* ---- Выпадающий список и выбор времени в стиле кабинета ----
   Нативная стрелка и высота у каждого браузера свои; здесь список выглядит
   как поле рядом: та же рамка, радиус и высота, своя стрелка. Стрелка
   нарисована серым из палитры (#64748B, это --text-secondary): внутри
   data-URI переменная не работает. Списки с size и multiple остаются
   прокручиваемыми, стрелка им не нужна. */
select {
  -webkit-appearance: none; appearance: none; cursor: pointer;
  padding-right: 36px;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%2364748B' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center; background-size: 12px 8px;
}
select:hover:not(:disabled) { background-color: var(--surface); }
select:disabled { cursor: not-allowed; background-image: none; }
select[size], select[multiple] { background-image: none; padding-right: 12px; cursor: default; }
/* Диалог автозагрузки задает списку свой padding: под стрелку нужен правый отступ */
.workflow-dialog select:not([size]) { padding-right: 34px; }
input[type="time"] {
  -webkit-appearance: none; appearance: none;
  width: auto; min-height: 40px; font: inherit; font-size: var(--t-text); color: var(--ink);
  background: var(--control); border: 1px solid var(--control-line);
  border-radius: var(--r-s); padding: 8px 12px;
  transition: border-color .14s ease, box-shadow .14s ease, background .14s ease;
}
input[type="time"]::-webkit-calendar-picker-indicator { opacity: .55; cursor: pointer; }
input[type="time"]:hover::-webkit-calendar-picker-indicator { opacity: 1; }
/* Кегль поля времени на телефоне. Общее правило узкого экрана стоит выше по
   файлу, а это - ниже и с такой же специфичностью, поэтому оно возвращало
   14px: телефон при фокусе приближал страницу, и она уезжала вбок. Повторяем
   правило здесь, ниже по файлу, - специфичность поднимать не нужно. */
@media (max-width: 760px) {
  input[type="time"] { min-height: 44px; padding: 12px; font-size: var(--t-field-mobile); }
}

/* ---- Переключатель с подписью: «Пробный режим» ----
   Галочка, одетая как рубильник .bid__switch: настройка про деньги должна
   читаться с одного взгляда, а не теряться четвертой в списке. Сам input
   спрятан, но остается в порядке табуляции и читается вслух. */
.toggle { position: relative; display: flex; align-items: flex-start; gap: var(--s3); cursor: pointer; max-width: 640px; }
.toggle input {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}
.toggle__ui {
  position: relative; flex: none; width: 38px; height: 22px; margin-top: 1px;
  border-radius: 999px; background: var(--line-strong); transition: background .14s ease;
}
.toggle__ui::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px;
  border-radius: 50%; background: var(--surface); transition: transform .14s ease;
}
.toggle:hover input:not(:checked):not(:disabled) + .toggle__ui { background: var(--ink-4); }
.toggle input:checked + .toggle__ui { background: var(--green); }
.toggle input:checked + .toggle__ui::after { transform: translateX(16px); }
.toggle input:focus-visible + .toggle__ui { outline: 2px solid var(--blue); outline-offset: 2px; }
.toggle input:disabled + .toggle__ui { opacity: .45; }
.toggle__text { min-width: 0; font-size: var(--t-note); line-height: 1.4; }
.toggle__text b { display: block; font-weight: 600; color: var(--ink); }
.toggle__text small { display: block; margin-top: 2px; font-size: var(--t-note); color: var(--ink-3); }
.bid__dry { margin: var(--s6) 0 var(--s4); padding-top: var(--s4); border-top: 1px solid var(--line-soft); }

/* ---- «Еще» на «Моих аккаунтах» ----
   Служебные действия под одной кнопкой, главная «Добавить аккаунт» одна.
   Тот же details, что у «Еще» в очереди отчетов. */
.hub__more { position: relative; }
.hub__more > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font: inherit; font-size: var(--t-note); font-weight: 600; color: var(--ink);
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--r-s);
  padding: 9px 16px; white-space: nowrap;
}
.hub__more > summary::-webkit-details-marker { display: none; }
.hub__more > summary:hover, .hub__more[open] > summary { background: var(--sunken); }
.hub__more > summary .ic { width: 14px; height: 14px; }
.hub__menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 15;
  display: flex; flex-direction: column; gap: 2px; min-width: 250px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m); box-shadow: var(--shadow-pop);
}
/* Три класса: .hub__head .hub__x одевает кнопку в рамку, внутри меню это
   пункт списка без рамки. */
.hub__head .hub__menu .hub__x {
  justify-content: flex-start; width: 100%; text-align: left; min-height: 40px;
  padding: 9px 12px; border: 0; border-radius: var(--r-s); background: transparent; color: var(--ink); font-size: var(--t-note);
}
.hub__head .hub__menu .hub__x:hover { background: var(--blue-soft); color: var(--blue-deep); }
.hub__head .hub__menu .hub__x:disabled { opacity: .5; cursor: default; background: transparent; color: var(--ink); }
.hub__status { max-width: 100%; }
.hub__status .ic { width: 14px; height: 14px; }

/* ---- «Еще» на карточке правила биддера ----
   Тот же details, что у «Еще» на «Моих аккаунтах» выше: шесть одинаковых
   кнопок в шапке не давали главного действия, а «Удалить» стояло рядом с
   «Изменить». Кнопка меню одета как остальные в ряду (.btn--sm .btn--light),
   поэтому своих размеров тут нет - только раскрытие и сам слой. */
.bid__more { position: relative; }
.bid__more > summary { list-style: none; cursor: pointer; }
.bid__more > summary::-webkit-details-marker { display: none; }
.bid__more[open] > summary { background: var(--sunken); }
.bid__menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 15;
  display: flex; flex-direction: column; gap: 2px; min-width: 230px; padding: 6px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m); box-shadow: var(--shadow-pop);
}
.bid__mitem {
  display: flex; align-items: center; gap: var(--s2); width: 100%; min-height: 40px;
  font: inherit; font-size: var(--t-note); font-weight: 600; color: var(--ink); text-align: left;
  background: transparent; border: 0; border-radius: var(--r-s); padding: 9px 12px; cursor: pointer;
}
.bid__mitem .ic { width: 15px; height: 15px; }
.bid__mitem:hover { background: var(--blue-soft); color: var(--blue-deep); text-decoration: none; }
.bid__mitem:disabled { opacity: .45; cursor: default; background: transparent; color: var(--ink); }
/* Разрушительное отделено чертой и красное с самого начала, а не только под
   курсором: на телефоне наведения нет вовсе, и «Удалить» там ничем не
   отличалось от «Остановить». */
.bid__mitem--danger {
  margin-top: 4px; border-top: 1px solid var(--line-soft);
  border-radius: 0 0 var(--r-s) var(--r-s); color: var(--alarm);
}
.bid__mitem--danger:hover { background: var(--alarm-soft); color: var(--alarm); }
.bid__mitem--danger:disabled { color: var(--alarm); }

/* Своя пометка правится прямо в карточке, а не в окне браузера */
.hub__rename { display: grid; gap: var(--s2); padding-top: var(--s3); border-top: 1px solid var(--line-soft); }
.hub__rename .hub__field { margin-bottom: 0; }

/* Таблица аккаунтов: «Состояние» несет точку и причину целиком, «Обновлено»
   держит дату. На 1024 первым уходит «Обновлено»: состояние важнее даты. */
.ptbl__state { white-space: normal; min-width: 170px; max-width: 320px; line-height: 1.35; }
@media (max-width: 1150px) {
  .ptbl__upd { display: none; }
  /* Клетки тесней, чтобы «Открыть» не уходил за край */
  .ptbl th, .ptbl td { padding: 10px 10px; }
  .ptbl__state { min-width: 130px; }
}

/* ---- Таблица аккаунтов на телефоне: строка становится карточкой ----
   Столбцов восемь, в кадр 356 влезали только «Сегодня» и «Вчера»: «Состояние»
   уходило за правый край, и аккаунт с пометкой «мало денег» выглядел здоровым.
   Подпись каждой клетки берется из шапки столбца: ее кладет в data-l hub.js
   (HUB_LBL в hubTable), сама шапка на телефоне не нужна. Тот же прием, что у
   таблицы ставок ниже в этом файле (.bids-table). */
@media (max-width: 760px) {
  .hub__tblwrap { overflow: visible; border: 0; border-radius: 0; background: none; }
  /* Рамка и фон уехали к строкам-карточкам, а «Никого не нашлось по этому
     фильтру» без коробки повисало на голом фоне страницы: возвращаем ему
     ту же карточку, что у строк. */
  .hub__tblwrap .hub__none {
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
    box-shadow: var(--shadow-card);
  }
  .ptbl, .ptbl tbody { display: block; width: 100%; }
  .ptbl thead { display: none; }
  .ptbl tbody tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--s2);
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
    box-shadow: var(--shadow-card); padding: var(--s3) var(--s4); margin-bottom: var(--s3);
  }
  .ptbl tbody tr:hover { background: var(--surface); }
  .ptbl th, .ptbl td {
    display: block; width: auto; border: 0; padding: 5px 0; text-align: right; white-space: normal;
    flex: 1 0 100%; min-width: 0; overflow-wrap: anywhere;
  }
  /* Имя аккаунта - шапка карточки: кружок и имя стоят рядом, как в списке */
  .ptbl td.ptbl__cli { display: flex; text-align: left; padding-bottom: var(--s3); }
  /* «Обновлено» скрыто и здесь, как на 1024: состояние важнее даты */
  .ptbl td.ptbl__upd { display: none; }
  .ptbl td[data-l]:not(.ptbl__cli):not(.ptbl__upd) {
    display: flex; gap: var(--s3); align-items: baseline; justify-content: space-between;
  }
  .ptbl td[data-l]:not(.ptbl__cli):not(.ptbl__upd)::before {
    content: attr(data-l); flex: none; color: var(--ink-3); font-size: var(--t-note); text-align: left;
  }
  /* Причина отказа бывает длинной: она занимает остаток строки и переносится */
  .ptbl td.ptbl__state { min-width: 0; max-width: none; }
  .ptbl td.ptbl__state .ptbl__why { flex: 0 1 auto; min-width: 0; }
  /* Действие строки - последним и во всю ширину карточки */
  .ptbl td.ptbl__act { padding-top: var(--s3); }
  .ptbl td.ptbl__act .hub__dots { width: 100%; min-height: 44px; border-radius: var(--r-s); }
}

/* ---- Форма правила на телефоне: сначала выбор объявления, потом форма ----
   На широком экране оба блока видны сразу, как раньше. */
/* Два класса: .btn и button.pill в workspace.css задают display позже
   и равной специфичностью вернули бы кнопки шагов на широкий экран */
.bid__steps .bid__next, .bid__steps .bid__stepback { display: none; }
@media (max-width: 760px) {
  .bid__steps .bid__next { display: inline-flex; width: 100%; margin-top: var(--s3); }
  .bid__steps .bid__stepback { display: inline-flex; margin-bottom: var(--s3); }
  .bid__steps[data-step="1"] .bid__formbody, .bid__steps[data-step="1"] .bid__stepback { display: none; }
  .bid__steps[data-step="2"] .ad-picker, .bid__steps[data-step="2"] .bid__next { display: none; }
  .bid__steps[data-step="1"] .ad-picker { border-bottom: 0; margin-bottom: 0; padding-bottom: 0; }
  .bid__form + .bid__sched { margin-top: var(--s4); }
  .bid__window input[type="time"] { width: auto; flex: 1; min-width: 0; }
}

/* ---- Управление ставками ----
   Город и целевое действие ушли под название объявления, деньги вернулись
   в кадр. Ярлык «и биддер» с пояснением строкой, а не во всплывашке. */
.bids__ad { white-space: normal; min-width: 220px; max-width: 420px; line-height: 1.4; }
.bids__ad small { display: block; margin-top: 3px; font-size: var(--t-micro); color: var(--ink-3); }
.plancell { white-space: normal; max-width: 280px; line-height: 1.4; }
.plan-warn { display: block; margin-top: 4px; font-size: var(--t-micro); color: var(--ink-3); font-weight: 400; }
/* Счетчик отмеченных: обычная строка рядом с кнопкой, без рамки и заливки.
   В виде пилюли он читался как вторая кнопка. */
.bids__count { font-size: var(--t-note); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.bids__form { display: flex; align-items: flex-start; gap: var(--s2); flex-wrap: wrap; margin-top: var(--s3); }
.bids__field { display: grid; gap: 4px; }
.bids__field .hint { margin: 0; font-size: var(--t-note); color: var(--ink-3); }
input.bids__num { width: 150px; min-height: 44px; }
input.bids__num--wide { width: 180px; }
.bids__form .btn { min-height: 44px; }
/* На 1024 деньги и «Настроить» должны остаться в кадре: заголовкам денег
   можно переноситься, клеткам - быть теснее */
@media (max-width: 1150px) {
  .bids-table th.right.nowrap { white-space: normal; min-width: 92px; }
  .bids-table th, .bids-table td { padding: 9px 8px; }
  .bids-table .bids__ad { min-width: 180px; max-width: 300px; }
  .bids-table .plancell { max-width: 200px; }
}
@media (max-width: 760px) {
  .bids__form > *, .bids__field, input.bids__num, input.bids__num--wide { width: 100%; }

  /* Строка таблицы становится карточкой. Таблица шириной 500 в кадр 356 не
     влезала: единственное действие строки, «Настроить ставку», уходило за
     правый край, а коробка прокрутки со своей высотой давала вторую
     прокрутку внутри страницы. Ни того, ни другого на телефоне быть не
     должно, а сузить пять столбцов до 356 нечестно.
     Подпись каждой клетки берется из шапки столбца: ее кладет в data-l
     tableOf (cabinet.js), сама шапка на телефоне не нужна. */
  .bids-table .tablebox { border: 0; border-radius: 0; background: none; box-shadow: none; overflow: visible; }
  .bids-table .tablebox > .scroll {
    max-height: none; overflow: visible; border: 0; border-radius: 0;
    box-shadow: none; background: none;
  }
  .bids-table table, .bids-table tbody { display: block; width: 100%; }
  /* Ширину клеткам задает только flex-basis ниже: width: 100% на клетке
     раздувал галочку на всю строку, и название уезжало под нее. */
  .bids-table td { display: block; width: auto; }
  .bids-table thead { display: none; }
  .bids-table tbody tr {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--s2);
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-m);
    box-shadow: var(--shadow-card); padding: var(--s3) var(--s4); margin-bottom: var(--s3);
  }
  .bids-table tbody tr:hover td { background: none; }
  .bids-table th, .bids-table td {
    border: 0; padding: 5px 0; text-align: left; white-space: normal;
    flex: 1 0 100%; min-width: 0; overflow-wrap: anywhere;
  }
  /* Галочка и название стоят одной строкой, как в списке правил биддера */
  .bids-table td:first-child { flex: 0 0 auto; padding-right: var(--s2); }
  .bids-table td.bids__ad { flex: 1 1 0; min-width: 0; max-width: none; font-size: var(--t-text); }
  .bids-table td[data-l]:not(.bids__ad) {
    display: flex; gap: var(--s3); align-items: baseline; justify-content: space-between;
  }
  .bids-table td[data-l]:not(.bids__ad)::before {
    content: attr(data-l); flex: none; color: var(--ink-3); font-size: var(--t-note);
  }
  .bids-table .plancell { max-width: none; text-align: right; }
  /* Действие строки - последним и во всю ширину карточки */
  .bids-table td:last-child { padding-top: var(--s3); }
  .bids-table td:last-child .pill { width: 100%; min-height: 44px; border-radius: var(--r-s); }
  /* Выбор сортировки остался единственным способом переставить строки:
     заголовков столбцов на телефоне нет, значит щелкать не по чему. */
  .bids-table .sortbar { border: 1px solid var(--line); border-radius: var(--r-m); margin-bottom: var(--s3); }
}

/* ---- Два графика правила с общей осью времени ----
   Позиция сверху синим (1 место наверху), ставка снизу рыжим пунктиром.
   Один график - один ряд, как везде в кабинете. */
.bid__charts { display: grid; gap: var(--s3); }
.bid__chart-t { font-size: var(--t-note); font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }
.bid__chart-scale { display: flex; justify-content: space-between; gap: var(--s3); font-size: var(--t-micro); color: var(--ink-3); margin-top: 4px; }
.bid__chart-scale span { min-width: 0; overflow-wrap: anywhere; }

/* Легенда над журналом решений: только когда в нем есть пробные записи */
.bid__legend { font-size: var(--t-note); color: var(--ink-3); margin: 0 0 var(--s3); }

/* ---- «Служебное» хозяина ----
   Карточки одной ширины и сетки с остальным разделом: своего потолка у
   сетки нет, ширину держит рабочая колонка (--work-max). Форма идет во всю
   карточку, карта «Люди» из hub.js не выделяется. */
hr.nav__sep { border: 0; border-top: 1px solid var(--sidebar-line); margin: var(--s4) 10px; }
.owner-cards { display: grid; gap: var(--s4); }
/* Ячейка грида по умолчанию не уже своего содержимого: таблица журнала
   сбоев (width: max-content внутри .scroll) растягивала карточку за край
   телефона. С min-width: 0 прокручивается таблица, а не страница. */
.owner-cards > * { min-width: 0; }
.owner-card { margin: 0; }
.owner-card .kv { max-width: none; }
/* Галочка внутри .field: общее правило .field label делает ее блоком с
   жирной подписью, здесь нужна строка «квадратик плюс слова» */
.field .owner-check { display: flex; align-items: center; gap: var(--s2); margin: 0; font-size: var(--t-note); font-weight: 400; color: var(--ink); }
.owner-card .hub__form h3 { font-size: var(--t-card); margin: 0 0 var(--s3); }
/* Карта «Люди» приезжает уже в одежде .hub__card: тень при наведении, сдвиг,
   заголовок в две строки, узкая форма по центру. Три класса, чтобы перебить
   .hub__card:hover и .hub__form с их специфичностью. */
.owner-cards .owner-card.hub__card { display: block; padding: var(--s6); transform: none; box-shadow: none; }
.owner-cards .owner-card.hub__card:hover { transform: none; box-shadow: none; }
.owner-cards .owner-card.hub__card .hub__name {
  display: block; overflow: visible; -webkit-line-clamp: unset;
  font-size: var(--t-card); margin-bottom: var(--s3);
}
.owner-cards .owner-card.hub__card .hub__id { font-size: var(--t-note); color: var(--ink-2); margin: 0 0 var(--s3); }
.owner-cards .owner-card .hub__form {
  max-width: none; margin: var(--s4) 0 0; padding: var(--s4) 0 0;
  border: 0; border-top: 1px solid var(--line-soft); border-radius: 0; box-shadow: none; background: none;
}
.owner-faults { display: grid; gap: 0; margin-top: var(--s2); }
.owner-fault {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--s2) var(--s3); align-items: start;
  padding: var(--s2) 0; border-bottom: 1px solid var(--line-soft); font-size: var(--t-note);
}
.owner-fault:last-child { border-bottom: 0; }
.owner-fault .pill { white-space: nowrap; }
.owner-fault__text { min-width: 0; overflow-wrap: anywhere; color: var(--ink-2); line-height: 1.5; padding-top: 4px; }
.owner-check { display: flex; align-items: center; gap: var(--s2); font-size: var(--t-note); cursor: pointer; }
.owner-check input { width: 16px; height: 16px; accent-color: var(--blue); }
@media (max-width: 760px) {
  .owner-fault { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .owner-cards .owner-card.hub__card { padding: var(--s4); }
  /* Только шапка списка: правило ловило и кнопки внутри карточек «Входа и
     безопасности» и поднимало «Сменить» над заголовком и полями. В карточке
     .hub__card кнопка и так растягивается на всю ширину колонки. */
  .hub__head .hub__add { order: -1; width: 100%; }
  .hub__more { order: 2; }
  /* Открытое меню занимает всю строку, переключатель вида уходит ниже */
  .hub__more[open] { flex-basis: 100%; }
  .hub__menu { position: static; box-shadow: none; padding: 6px 0 0; min-width: 0; width: 100%; }
  /* То же для «Еще» на карточке правила: всплывающий слой на телефоне уходил
     бы за правый край, поэтому он встает обычным блоком под кнопкой. */
  .bid__more[open] { flex-basis: 100%; }
  .bid__menu { position: static; box-shadow: none; padding: 6px 0 0; min-width: 0; width: 100%; }
}
