/* ═══════════════════════════════════════════════════════════════════════════
   ОБЩИЙ КАТАЛОГ «ПАМПИНГА» — стили списка и карточки товара.

   Файл подключают ДВЕ независимые страницы: панель (bot_Ozon/webapp) и витрина
   (web_gruzchiki). Своих копий этих правил у них быть не должно — расхождение
   вида здесь означает, что один и тот же товар выглядит по-разному в
   зависимости от того, откуда на него смотрят.

   ─── ЧТО ОБЯЗАН ОБЪЯВИТЬ ХОЗЯИН СТРАНИЦЫ ─────────────────────────────────────
   Ни одного конкретного цвета в разметочных правилах ниже нет — только ссылки
   на словарь оформления. Поэтому страница, подключающая файл, объявляет его у
   себя целиком. Пропущенное имя даёт не «цвет по умолчанию», а прозрачный фон
   или чёрный текст — молча и только в одном месте, поэтому список полный:

     поверхности   --surface --surface-1 --surface-2 --surface-3 --surface-4
                   --bg-elevated
     границы       --border --border-strong --border-subtle
     текст         --text --text-primary --text-secondary --text-tertiary
                   --text-quaternary
     акцент        --accent --accent-line --accent-soft --accent-softer
                   --accent-glow
     скругления    --r-md --r-lg --r-xl
     прочее        --t-fast --danger

   Цвета графика (--viz-*) объявлены ЗДЕСЬ и одинаковы у всех: они несут смысл
   («синий — цена»), а не оформление, и переопределять их странице незачем.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Цвета данных ───────────────────────────────────────────────────────────
   Цвет здесь несёт РОВНО ОДИН смысл каждый, и роли не пересекаются:
     синий  — цена (главный ряд, цвет акцента раздела);
     серый  — остаток (контекст, намеренно не конкурирует с ценой);
     палитра кампаний — идентичность акции, и больше ничего.
   Ни один цвет кампании не синий: иначе полоса акции спорила бы с линией цены
   за одно и то же значение «важное». Набор кампаний прогнан валидатором на
   различимость при дальтонизме (worst ΔE 8.4 protan на тёмном фоне, 9.1 на
   светлом) — подбирать оттенки на глаз тут нельзя.
   Токены висят на body, а не на модалке: теми же цветами красятся значки акций
   в списке, и цвет кампании обязан быть одним на весь раздел. */
body {
  --viz-price:   #4C8DFF;
  --viz-stock:   #93A0B5;
  --viz-grid:    var(--border-subtle);
  --viz-c1: #d95926; --viz-c2: #199e70; --viz-c3: #c98500;
  --viz-c4: #d55181; --viz-c5: #9085e9; --viz-c6: #e66767;
  --viz-c0: #6B7280;        /* «другая акция» — за пределами шести слотов */
}
[data-theme="light"] body {
  --viz-price: #2563EB; --viz-stock: #6B7684;
  --viz-c1: #eb6834; --viz-c2: #1baf7a; --viz-c3: #eda100;
  --viz-c4: #e87ba4; --viz-c5: #4a3aa7; --viz-c6: #e34948;
  --viz-c0: #8A9099;
}

/* ── Запасные органы управления ─────────────────────────────────────────────
   Кнопки, выпадающие списки и плитки сводки модуль рисует ТЕМИ классами, что
   ему передали в `classes`. У панели своя дизайн-система, и она передаёт свои —
   поэтому её вид этим файлом не задевается вовсе. Правила ниже работают только
   для страницы, которая своих классов не дала (витрина): без них она получила
   бы голые системные кнопки посреди оформленного списка. */
.cb-btn {
  appearance: none; cursor: pointer; font: inherit; font-size: 12.5px;
  padding: 7px 14px; border-radius: 999px; color: var(--text-secondary);
  background: var(--surface); border: 1px solid var(--border);
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.cb-btn:hover { background: var(--surface-2); color: var(--text); }
.cb-btn:disabled { opacity: .6; cursor: default; }
.cb-select {
  appearance: none; font: inherit; font-size: 12.5px; max-width: 100%;
  padding: 7px 28px 7px 12px; border-radius: 999px; cursor: pointer;
  color: var(--text-secondary); background: var(--surface);
  border: 1px solid var(--border);
}
.cb-select:focus { outline: none; border-color: var(--accent-line, var(--accent)); }
.cb-kpi-grid { display: grid; gap: 8px; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
.cb-kpi {
  padding: 9px 11px; background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.cb-kpi .cb-kpi-title { font-size: 10.5px; text-transform: uppercase;
                        letter-spacing: .06em; color: var(--text-tertiary); }
.cb-kpi-value { margin-top: 3px; font-size: 17px; font-weight: 650;
                font-variant-numeric: tabular-nums; }
.cb-panel { display: block; }
.cb-panel + .cb-panel { margin-top: 14px; }
.cb-section-title { font-size: 12px; font-weight: 600; text-transform: uppercase;
                    letter-spacing: .05em; color: var(--text-tertiary); }

/* Плитка-фильтр: цифра, по которой можно кликнуть и увидеть сами товары.
   Состояние берём из положения переключателя над списком — второй источник
   правды тут разъехался бы при первом же ручном снятии. */
.kpi--tap, .cb-kpi--tap { cursor: pointer; }
.kpi--tap:hover, .cb-kpi--tap:hover { border-color: var(--border-strong); }
.kpi--tap.is-on, .cb-kpi--tap.is-on { border-color: var(--accent); background: var(--surface-2); }
/* Единица — отдельным спаном, а не частью числа: значение моноширинное и
   крупное, и «шт» в нём выглядело бы вторым числом. */
.kpi-unit { font-family: var(--font-sans, inherit); font-size: 13px;
            font-weight: 400; color: var(--text-tertiary); margin-left: 5px; }

/* ── Слежения ─────────────────────────────────────────────────────────────── */
.cb-add { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.cb-add input[type=url] {
  flex: 1 1 340px; min-width: 0; padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--text-primary); font-size: 13px;
  font-family: inherit;
}
.cb-add input[type=url]:focus { outline: none; border-color: var(--accent); }

.cb-watches { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.cb-watch {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 10px 7px 12px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; font-size: 12px; cursor: pointer; user-select: none;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.cb-watch:hover { background: var(--surface-3); }
.cb-watch.is-active { border-color: var(--accent); background: var(--surface-3); }
.cb-watch-title { font-weight: 600; max-width: 200px; overflow: hidden;
                  text-overflow: ellipsis; white-space: nowrap; }
.cb-watch-meta { color: var(--text-tertiary); font-size: 11px; }
.cb-watch-x { color: var(--text-tertiary); padding: 0 2px; border-radius: 4px; }
.cb-watch-x:hover { color: var(--danger, #e5484d); }

/* ── Сетка товаров ──────────────────────────────────────────────────────────
   Плитки, а под ценой — ОДНА строка со всем, что решает: чем цена отличается
   от обычной, сколько штук осталось, когда привезут. Раньше эти факты жили
   пятью отдельными плашками, и плитка расползалась на разную высоту; теперь
   строка одна, высота у всех одинаковая, сетка не рвётся. */
.cb-grid {
  display: grid; gap: 10px; margin-top: 12px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
/* Узкая раскладка — не «то же самое на маленьком экране», а осознанное
   положение: витрину открывают в окне Telegram шириной с телефон, и там колонка
   ровно одна при любой ширине. Признак ставит хозяин страницы, а не медиа-
   запрос: окно Telegram на планшете широкое, а плитки в нём всё равно должны
   идти в одну колонку. */
.cb-scope--narrow .cb-grid { grid-template-columns: 1fr; gap: 8px; margin-top: 10px; }
.cb-card {
  display: flex; flex-direction: column; gap: 10px; padding: 12px;
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--r-lg); cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast);
}
.cb-card:hover { background: var(--surface-2); border-color: var(--border-strong); }
.cb-card:active { background: var(--surface-3); }
.cb-card-top { display: flex; gap: 10px; align-items: flex-start; }
.cb-thumb {
  width: 52px; height: 52px; flex: 0 0 52px; border-radius: var(--r-md);
  object-fit: cover; background: var(--surface-3);
}
/* Название — максимум две строки: третья почти всегда состоит из артикулов и
   цветов, а высоту плитки задирает всем соседям по ряду. */
.cb-name {
  font-size: 12.5px; line-height: 1.35; color: var(--text-primary);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Цена и значок акции — одной строкой: значок относится к цене, а не к товару
   вообще, и стоять должен рядом с ней. */
.cb-price-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.cb-price { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums;
            white-space: nowrap; }
.cb-delta { font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.cb-delta.down { color: #3fb950; }
.cb-delta.up   { color: #e5484d; }
/* Одна строка фактов под ценой. Через точку, без плашек: пять пилюль читаются
   дольше, чем короткий текст, и переносятся как попало. */
.cb-meta {
  font-size: 11.5px; color: var(--text-tertiary);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: flex; gap: 6px; align-items: baseline;
}
.cb-meta i { font-style: normal; color: var(--text-quaternary); }
.cb-meta .down { color: #3fb950; font-weight: 600; }
.cb-meta .up   { color: #e5484d; font-weight: 600; }
.cb-meta .low  { color: #ff8a8a; }
/* ТРЕТЬЯ СТРОКА — только у выпавших из выдачи. Отдельной строкой, а не в общем
   ряду фактов: это не свойство цены, а оговорка ко всей плитке — «товара в
   выдаче нет, цена добыта карточкой». Тонкая линия сверху отделяет оговорку от
   данных, чтобы её нельзя было прочитать как ещё один факт. */
.cb-gone {
  display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap;
  font-size: 11px; color: var(--text-tertiary);
  padding-top: 8px; border-top: 1px dashed var(--border);
}
.cb-gone i  { font-style: normal; color: var(--text-quaternary); }
.cb-gone .ok  { color: #3fb950; }   /* убедились: карточка ответила «жив» */
.cb-gone .bad { color: #ffb4b4; }   /* НЕ убедились — цена может быть старой */
/* ЗНАЧОК АКЦИИ — справа от цены, цветом своей кампании (тот же цвет, что в
   сводке и на полосе в карточке). Внутри время в ЧАСАХ: «2 дня» — это и 25
   часов, и 47, а решают по часам. */
.cb-promo {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px 3px 7px;
  border-radius: 999px; font-size: 11.5px; font-weight: 600;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  background: var(--surface-3); color: var(--text-secondary);
}
.cb-bolt-wrap { display: inline-flex; flex: 0 0 13px; }
.cb-bolt { width: 13px; height: 13px; fill: currentColor; }
.cb-promo .w { font-style: normal; font-weight: 400; color: var(--text-tertiary); }
/* Срок доставки — у правого края строки фактов: он отвечает на отдельный вопрос
   «когда привезут», и в общий ряд через точку не встаёт. */
.cb-eta { margin-left: auto; padding-left: 8px; color: var(--text-tertiary);
          white-space: nowrap; }
.cb-promo--soon { color: #ffb4b4; background: rgba(229,72,77,.16); }
.cb-promo--none { display: none; }   /* нет акции — нет и места под неё */

/* ФИЛЬТР СПИСКА — пилюли того же вида, что переключатель окна в карточке
   (.cb-range ниже), с общими стилями. Форма выбрана по смыслу: положение одно
   из нескольких, и независимые чекбоксы врали об этом самой формой — квадратик
   обещает «можно отметить оба». Иконка ведёт взглядом быстрее подписи, поэтому
   она у каждого положения, а слово одно. */
.cb-filters { display: flex; gap: 6px; flex-wrap: wrap; }
.cb-filters button { display: inline-flex; align-items: center; gap: 6px; }
/* ПОИСК — рядом с фильтрами, а не в шапке раздела: он сужает тот же список и
   относится к нему, а не ко всей странице. Форма пилюли общая с фильтрами по
   той же причине — это соседние органы управления одним списком. */
.cb-search-wrap { display: flex; gap: 6px; align-items: center; flex: 1 1 220px;
                  max-width: 320px; min-width: 0; }
.cb-scope--narrow .cb-search-wrap { max-width: none; flex-basis: 100%; }
.cb-search {
  flex: 1 1 auto; min-width: 0; padding: 5px 12px; font: inherit; font-size: 12px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 999px; color: var(--text-primary);
  transition: border-color var(--t-fast), background var(--t-fast);
}
.cb-search::placeholder { color: var(--text-tertiary); }
.cb-search:focus { outline: none; border-color: var(--accent-line, var(--accent));
                   background: var(--surface-2); }
.cb-search:focus-visible { box-shadow: var(--accent-glow); }
/* Родной крестик Chrome на тёмном фоне почти не виден — рисуем свой. */
.cb-search::-webkit-search-cancel-button { display: none; }
.cb-search-x {
  appearance: none; cursor: pointer; font: inherit; font-size: 12px; line-height: 1;
  padding: 5px 9px; border-radius: 999px; color: var(--text-tertiary);
  background: var(--surface); border: 1px solid var(--border);
}
.cb-search-x:hover { background: var(--surface-2); color: var(--text); }
.cb-search-x[hidden] { display: none; }
/* Иконка не должна ужиматься на узком экране: сплющенная стрелка читается как
   другой значок. */
.cb-filters svg { width: 14px; height: 14px; flex: 0 0 14px; }

/* Строка органов управления списком. На широкой странице они жмутся к правому
   краю рядом с заголовком, на узкой — идут отдельными строками во всю ширину:
   в окне шириной с телефон «в один ряд» превращается в лесенку из огрызков. */
.cb-tools { display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
            flex: 1 1 auto; justify-content: flex-end; }
.cb-head-row { display: flex; justify-content: space-between; align-items: center;
               gap: 12px; flex-wrap: wrap; }
.cb-scope--narrow .cb-tools { justify-content: flex-start; }
.cb-scope--narrow .cb-tools > * { flex: 1 1 auto; }
.cb-scope--narrow .cb-filters { width: 100%; }
.cb-scope--narrow .cb-filters button { flex: 1 1 auto; justify-content: center; }

@media (max-width: 560px) {
  .cb-grid { grid-template-columns: 1fr; gap: 8px; }
  .cb-card { padding: 10px; gap: 8px; }
  .cb-thumb { width: 44px; height: 44px; flex-basis: 44px; }
  .cb-price { font-size: 17px; }
  .cb-promo .w { display: none; }
}

/* ── Карточка товара ────────────────────────────────────────────────────────
   Модалка живёт в конце <body>, а не внутри списка: она перекрывает страницу
   целиком, и вложенная в колонку с прокруткой она обрезалась бы её границами. */
.cb-modal {
  position: fixed; inset: 0; z-index: 60; display: none;
  align-items: center; justify-content: center; padding: 16px;
  background: rgba(0,0,0,.6); backdrop-filter: blur(3px);
}
.cb-modal.is-open { display: flex; }
.cb-modal-box {
  width: min(760px, 100%); max-height: 88vh; overflow: auto; padding: 18px 18px 20px;
  background: var(--bg-elevated); border: 1px solid var(--border);
  border-radius: var(--r-xl, 16px);
  box-shadow: 0 24px 64px rgba(0,0,0,.45), 0 2px 8px rgba(0,0,0,.30);
}
.cb-modal-top { display: flex; justify-content: space-between; gap: 12px;
                align-items: flex-start; }
/* Появление графика — короткий подъём с проявлением. Ровно столько движения,
   чтобы глаз понял «это перерисовалось», и ни кадром больше. */
@media (prefers-reduced-motion: no-preference) {
  .cb-chart.is-in { animation: cbRise .26s ease-out; }
  @keyframes cbRise { from { opacity: 0; transform: translateY(6px); } }
}
/* ── Шапка карточки ───────────────────────────────────────────────────────── */
.cb-head { display: flex; gap: 12px; align-items: flex-start; }
.cb-head-thumb { width: 64px; height: 64px; flex: 0 0 64px; border-radius: var(--r-md);
                 object-fit: cover; background: var(--surface-3); }
.cb-head-name { font-size: 14px; line-height: 1.35; font-weight: 600; }
.cb-head-sub  { margin-top: 4px; font-size: 12px; color: var(--text-tertiary);
                display: flex; gap: 10px; flex-wrap: wrap; align-items: baseline; }
.cb-head-price { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }
/* ── Стат-плитки: четыре числа, ради которых карточку открывают ───────── */
.cb-stats { display: grid; gap: 8px; margin-top: 14px;
            grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
.cb-stat  { padding: 9px 11px; background: var(--surface); border: 1px solid var(--border);
            border-radius: var(--r-md); }
.cb-stat-l { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
             color: var(--text-tertiary); }
.cb-stat-v { margin-top: 3px; font-size: 15px; font-weight: 600; }
.cb-stat-n { font-size: 11px; color: var(--text-tertiary); margin-top: 2px; }
/* Переключатель окна — одной строкой НАД всем, что он сужает (график и обе
   таблицы). Пресетами, а не календарём: «последние 7 дней» никто не хочет
   набирать двумя датами. */
.cb-range { display: flex; gap: 6px; align-items: center; margin-top: 14px; }
/* Общий вид пилюли — и у окна наблюдения, и у фильтра списка выше: это одна и
   та же роль «выбери одно положение», и выглядеть она обязана одинаково. */
.cb-range button, .cb-filters button {
  appearance: none; cursor: pointer; font: inherit; font-size: 12px;
  padding: 5px 12px; border-radius: 999px; color: var(--text-secondary);
  background: var(--surface); border: 1px solid var(--border);
  transition: background var(--t-fast), border-color var(--t-fast), color var(--t-fast);
}
.cb-range button:hover, .cb-filters button:hover { background: var(--surface-2); color: var(--text); }
.cb-range button.is-on, .cb-filters button.is-on {
                         border-color: var(--accent-line, var(--accent));
                         background: var(--accent-soft, var(--surface-3)); color: var(--text); }
.cb-range button:focus-visible,
.cb-filters button:focus-visible { outline: none; box-shadow: var(--accent-glow); }
/* ── График: панели на одной оси времени ────────────────────────────────
   Сверху цена, под ней остаток, внизу — кампании. Порядок не декоративный:
   цена — то, ради чего смотрят; остаток объясняет, сколько осталось времени на
   раздумья; полоса кампаний — почему цена такая. Шкалы у панелей РАЗНЫЕ и
   никогда не совмещаются в одну (две оси Y на одном поле рисуют корреляцию,
   которой в данных нет). */
.cb-viz { position: relative; margin-top: 10px; }
.cb-chart { width: 100%; height: auto; aspect-ratio: 720 / 300; display: block;
            border-radius: var(--r-md); }
.cb-chart:focus-visible { outline: none; box-shadow: var(--accent-glow); }
.cb-chart .grid       { stroke: var(--viz-grid); stroke-width: 1; }
.cb-chart .axis       { stroke: var(--border); stroke-width: 1; }
.cb-chart .price-line { fill: none; stroke: var(--viz-price); stroke-width: 2;
                        stroke-linecap: round; stroke-linejoin: round; }
.cb-chart .price-area { fill: url(#cbPriceFill); stroke: none; }
.cb-chart .stock-line { fill: none; stroke: var(--viz-stock); stroke-width: 1.5;
                        stroke-linejoin: round; stroke-linecap: round; }
/* Пунктир — «на этом отрезке остаток не показывали». Единственное место, где
   штрих осмыслен: он говорит о неизвестности, а не украшает. */
.cb-chart .stock-line--gap { stroke-dasharray: 3 4; opacity: .5; }
/* Одинокий замер между двумя провалами: кривой его не нарисовать, а потерять
   нельзя — точка и есть всё, что мы о том окне знаем. */
.cb-chart .price-dot  { fill: var(--viz-price); }
.cb-chart .stock-dot  { fill: var(--viz-stock); }
/* Провал «не было в продаже». Серая штриховка поверх дорожек — нейтральный цвет
   намеренно: это не событие рынка (у тех свои цвета), а отсутствие данных о
   нём. Прозрачность держит читаемыми сетку и полосу кампаний под полосой:
   «кончился ли он посреди акции» спрашивают сразу. */
.cb-chart .out-band { fill: url(#cbOutHatch); stroke: var(--border-strong);
                      stroke-width: 1; stroke-dasharray: 2 3; opacity: .9; }
.cb-chart .out-lbl  { fill: var(--text-secondary); font-size: 10.5px;
                      font-weight: 600; }
.cb-chart .stock-area { fill: url(#cbStockFill); stroke: none; }
.cb-chart .stock-gap  { fill: url(#cbHatch); }
.cb-chart .lbl        { fill: var(--text-tertiary); font-size: 10px;
                        text-transform: uppercase; letter-spacing: .07em; }
.cb-chart .tick       { fill: var(--text-tertiary); font-size: 10px;
                        font-variant-numeric: tabular-nums; }
.cb-chart .endlbl     { fill: var(--text); font-size: 11.5px; font-weight: 600;
                        font-variant-numeric: tabular-nums; }
.cb-chart .cursor     { stroke: var(--border-strong); stroke-width: 1; }
.cb-chart .cursor-dot { fill: var(--viz-price); stroke: var(--bg-elevated); stroke-width: 2; }
/* Наведение на кампанию в легенде приглушает остальные полосы — так видно, где
   именно шла именно она, когда эпизодов много. */
.cb-chart .band { transition: opacity .14s; }
.cb-chart.is-dim .band { opacity: .22; }
.cb-chart.is-dim .band.is-hot { opacity: 1; }
/* Подсказка курсора — единственное место, где сходятся все ряды сразу: цена,
   остаток и кампания на один и тот же момент. */
.cb-tip {
  position: absolute; pointer-events: none; z-index: 2; min-width: 148px;
  padding: 8px 10px; font-size: 11.5px; line-height: 1.5;
  background: var(--surface-4, var(--surface-2)); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  box-shadow: 0 8px 24px rgba(0,0,0,.35); opacity: 0; transition: opacity .12s;
}
.cb-tip.is-on { opacity: 1; }
/* В подсказке ведёт ЗНАЧЕНИЕ, а не название ряда: читатель уже знает, на что
   смотрит, и пришёл за числом. */
.cb-tip b { font-variant-numeric: tabular-nums; color: var(--text); }
.cb-tip-row { display: flex; justify-content: space-between; gap: 14px; align-items: baseline; }
.cb-tip-k { color: var(--text-tertiary); }
/* Ключ ряда — короткий штрих, а не залитый квадрат: при плотности подсказки
   квадрат добавляет чернил веса данных там, где нужна просто метка. */
.cb-key { display: inline-block; width: 10px; height: 2px; border-radius: 1px;
          margin-right: 6px; vertical-align: middle; }
/* ── Легенда кампаний ─────────────────────────────────────────────────── */
.cb-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 10px 0 2px; font-size: 11.5px; }
.cb-lg { display: inline-flex; align-items: center; gap: 6px; color: var(--text-secondary);
         cursor: default; }
.cb-note-line { flex-basis: 100%; margin-top: 2px; font-size: 11px;
                color: var(--text-quaternary); }
.cb-lg i, .cb-dot { width: 9px; height: 9px; border-radius: 3px; display: inline-block; }
.cb-dot { margin-right: 6px; vertical-align: middle; border-radius: 50%; }
.cb-muted { color: var(--text-tertiary); font-size: 11px; }
.cb-sub { margin: 20px 0 8px; font-size: 12px; font-weight: 600;
          text-transform: uppercase; letter-spacing: .05em; color: var(--text-tertiary); }
/* ── Таблицы карточки ───────────────────────────────────────────────────
   Шесть колонок в телефон не влезают. Скроллим САМУ таблицу, а не модалку:
   иначе горизонтальный сдвиг уводит и график, и шапку, а последняя колонка
   («Держалось») — та, ради которой таблицу и открывают. */
.cb-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cb-scroll .cb-hist { min-width: 540px; }
.cb-hist { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 4px; }
.cb-hist th { text-align: left; font-weight: 600; color: var(--text-tertiary);
              font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
              padding: 6px 8px; border-bottom: 1px solid var(--border); }
.cb-hist td { padding: 7px 8px; border-bottom: 1px solid var(--border);
              font-variant-numeric: tabular-nums; }
.cb-hist tr:hover td { background: var(--surface); }
.cb-held { font-weight: 600; }
.cb-held-n { color: var(--text-tertiary); font-weight: 400; }
/* Положение, которое держится прямо сейчас — точка живого состояния, её ищут
   первой. */
.cb-hist tr.is-now td { background: var(--accent-softer, var(--surface)); }
/* На телефоне холст графика ужимается вдвое, и подписи по 10px в его
   координатах становятся нечитаемыми — поднимаем их размер, раскладка панелей
   при этом не меняется. */
@media (max-width: 560px) {
  .cb-modal { padding: 8px; }
  .cb-modal-box { padding: 14px; }
  .cb-head-thumb { width: 48px; height: 48px; flex-basis: 48px; }
  .cb-chart .lbl, .cb-chart .tick { font-size: 15px; }
  .cb-chart .endlbl { font-size: 16px; }
}

/* ХВОСТ СПИСКА. Строка «показано 300 из 2033» — не украшение: без неё
   долистанный до конца список выглядит полным, и человек делает вывод, что
   товаров триста. Кнопка рядом со счётчиком, а не вместо него: счётчик говорит,
   СКОЛЬКО осталось, кнопка — что с этим сделать. */
.cb-more { display: flex; gap: 12px; align-items: center; justify-content: center;
           flex-wrap: wrap; padding: 16px 0 2px; }
.cb-more-n { font-size: 12px; color: var(--text-tertiary);
             font-variant-numeric: tabular-nums; }

.cb-empty { padding: 32px 16px; text-align: center; color: var(--text-tertiary); font-size: 13px; }
.cb-note  { font-size: 11.5px; color: var(--text-tertiary); margin-top: 6px; line-height: 1.5; }
