/* ===== СТРАНИЦА /favorites (редизайн Joe, см. чат 2026-08-12) =====
   Раньше строки переиспользовали вёрстку основной таблицы; теперь список
   бумаг - карточки (buildBondCardHTML в bond-row-html.js), не таблица. */

/* .builder-header (portfolio-builder.css) держит margin-bottom:30px под
   пару "заголовок + подзаголовок" - здесь заголовок теперь свой
   (.fav-page-title, с крупной звездой и счётчиком), отступ уменьшен. */
.favorites-page .builder-header {
  margin-bottom: 14px;
}

.fav-page-head { display: flex; flex-direction: column; gap: 6px; }
.fav-page-title {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--text);
}
.fav-page-star { color: var(--star); font-size: 19px; }
.fav-count {
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 12.5px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
  border: 1px solid var(--border);
}
.fav-count:empty { display: none; }

/* Быстрое добавление бумаги прямо со страницы /favorites (favorites-search.js,
   см. чат 2026-08-16) - раньше единственный способ отметить бумагу был
   вернуться в общую таблицу «Обзор». Лупа рядом с заголовком разворачивает
   поле поиска на месте, тот же приём "лупа → строка поиска", что уже
   прижился в шторке "Новости". Панель - прямой child .fav-page-head, без
   своего margin - inset тот же, что у остальной шапки (title/io-row), а не
   уже, как было бы при вложенности + собственном margin (см. первый заход
   на этот же UI в мокапе - чат 2026-08-16). */
.fav-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.fav-search-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
}
.fav-search-btn svg { width: 16px; height: 16px; }
.fav-search-btn:hover, .fav-search-btn[aria-expanded="true"] {
  border-color: var(--accent);
  color: var(--accent);
}

.fav-search-panel {
  margin-top: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.fav-search-panel[hidden] { display: none; }
.fav-search-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
}
.fav-search-row input {
  flex: 1;
  min-width: 0;
  border: none;
  background: var(--surface-2);
  border-radius: 10px;
  padding: 9px 12px;
  font-size: 13.5px;
  font-family: inherit;
  color: var(--text);
}
.fav-search-row input:focus { outline: 2px solid var(--accent-soft); }
/* iOS Safari сам зумит страницу при фокусе на <input> с font-size <16px
   (см. чат 2026-08-16, репорт "при тапе на строку поиска - увеличение
   страницы") - 16px именно на мобильном, чтобы не раздувать поле визуально
   на десктопе, где зума на фокус нет. */
@media (max-width: 768px) {
  .fav-search-row input { font-size: 16px; }
}
.fav-search-row button {
  border: none;
  background: none;
  color: var(--accent);
  font-size: 13px;
  font-weight: 600;
  flex-shrink: 0;
  padding: 6px 4px;
  cursor: pointer;
  font-family: inherit;
}

.fav-search-results { border-top: 1px solid var(--border); }
.fav-search-results:empty { border-top: none; }
.fav-search-result {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--border);
}
.fav-search-result:last-child { border-bottom: none; }
.fav-search-result-body { flex: 1; min-width: 0; }
.fav-search-result-name { font-size: 13.5px; font-weight: 700; color: var(--text); }
.fav-search-result-meta { font-size: 11.5px; color: var(--text-faint); margin-top: 1px; }
.fav-search-result-meta b { color: var(--text-muted); font-weight: 600; }
.fav-search-add-btn {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-faint);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 15px;
  line-height: 1;
}
.fav-search-add-btn.is-added { background: var(--star-soft); border-color: transparent; color: var(--star); }
.fav-search-empty, .fav-search-loading {
  padding: 16px 12px;
  text-align: center;
  font-size: 12px;
  color: var(--text-faint);
}

/* Поле "Штук" (см. чат 2026-08-11) - количество бумаг в портфеле, для
   расчёта суммы купонов в календаре ниже. Вставляется в favorites-page.js
   внутрь .bond-top карточки (insertQuantityBox) - не часть общей вёрстки
   карточки (bond-row-html.js), которая используется и на главной таблице,
   где такого поля быть не должно. */
.qty-box { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; flex-shrink: 0; }
.qty-box label { font-size: 10px; color: var(--text-faint); font-weight: 600; text-transform: uppercase; letter-spacing: 0.03em; }
.qty-box-row { display: flex; align-items: center; gap: 2px; }
/* На мобильном палец шире курсора мыши - 2px между полем количества и
   иконкой журнала (см. чат 2026-08-18, репорт "меню закрывается, экран
   уезжает вверх") достаточно для мыши, но недостаточно для тапа: мимо-тап
   на самом деле фокусировал соседний <input type=number>, iOS открывал
   цифровую клавиатуру и сам скроллил страницу под неё - в этот момент
   и срабатывал window-scroll listener ниже, закрывая только что открытую
   панель. Увеличенный зазор + сама иконка крупнее снижают шанс промаха. */
@media (max-width: 768px) {
  .qty-box-row { gap: 8px; }
}

.fav-qty-input {
  width: 56px;
  padding: 6px 4px;
  text-align: center;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
/* iOS Safari зумит страницу при фокусе на <input> с font-size <16px (тот же
   эффект, что и у .fav-search-row input выше, репорт 2026-08-18: "при
   редактировании количества/даты покупки в PWA - увеличение, невозможно
   нормально тыкать, тут же срабатывает свайп") - 16px только на мобильном,
   ширина чуть больше под тот же размер шрифта. */
@media (max-width: 768px) {
  .fav-qty-input { font-size: 16px; width: 64px; }
}

.fav-qty-input:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--surface);
}

.fav-qty-input[readonly] {
  color: var(--text-muted);
  background: var(--surface);
  cursor: default;
}

/* Журнал сделок (см. чат 2026-08-12) - иконка открывает попап с историей
   докупок/продаж по бумаге, чтобы графики на странице считали количество
   на каждую дату отдельно, а не текущее количество на всю историю. */
.fav-txn-toggle {
  border: none;
  background: transparent;
  color: var(--text-faint);
  font-size: 13px;
  line-height: 1;
  padding: 3px;
  cursor: pointer;
  border-radius: 4px;
}
@media (max-width: 768px) {
  .fav-txn-toggle {
    min-width: 36px;
    min-height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
  }
}
.fav-txn-toggle:hover, .fav-txn-toggle[aria-expanded="true"] {
  color: var(--accent);
  background: var(--surface-2);
}

.fav-txn-panel {
  /* Позиция (top/left) - инлайн, из positionTxnPanel() в favorites-page.js:
     элемент на document.body, а не внутри <td>, чтобы не зависеть от
     stacking context sticky-колонки таблицы (см. чат 2026-08-12). */
  position: absolute;
  width: 240px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  box-shadow: var(--shadow);
  z-index: 200;
  padding: 8px 10px;
  cursor: default;
}

.fav-txn-list {
  max-height: 140px;
  overflow-y: auto;
}

.fav-txn-empty {
  font-size: 11.5px;
  color: var(--text-faint);
  margin: 4px 0;
}

.fav-txn-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 0;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
}
.fav-txn-row:last-child { border-bottom: none; }

.fav-txn-sign {
  width: 14px;
  text-align: center;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.fav-txn-sign.buy { color: var(--good); }
.fav-txn-sign.sell { color: var(--poor); }

.fav-txn-qty {
  width: 52px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.fav-txn-date {
  flex: 1;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.fav-txn-del {
  color: var(--text-faint);
  cursor: pointer;
  font-size: 13px;
  padding: 2px;
}
.fav-txn-del:hover { color: var(--poor); }

.fav-txn-add {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}
.fav-txn-add select,
.fav-txn-add input {
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
  border-radius: 5px;
  padding: 4px 6px;
  font-size: 11.5px;
  font-family: inherit;
}
.fav-txn-add .fav-txn-qty-input { width: 46px; }
.fav-txn-add .fav-txn-date-input { flex: 1; min-width: 118px; }
.fav-txn-add-btn {
  background: var(--accent);
  color: var(--accent-contrast);
  border: none;
  border-radius: 5px;
  padding: 4px 10px;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  width: 100%;
}

@media (max-width: 640px) {
  .fav-txn-panel {
    /* left/top - инлайн из positionTxnPanel(), уже клампится под viewport */
    width: min(280px, 90vw);
  }
  /* Тот же iOS-зум-на-фокус, что у .fav-qty-input выше - строка добавления
     сделки (select тип + количество + дата) вся в одном 11.5px, поэтому
     зумило по любому из трёх полей. */
  .fav-txn-add select,
  .fav-txn-add input {
    font-size: 16px;
  }
  .fav-txn-add .fav-txn-qty-input { width: 56px; }
}

/* Графики стоимости портфеля и купонных выплат (см. чат 2026-08-11) -
   те же .calendar-summary-card-виджеты, что и прежняя карточка "Стоимость
   портфеля" (убрана - сумма и так на графике, см. заголовок графика ниже).
   Мокап согласован на реальных данных перед реализацией; расположение в
   ряд и уменьшенный размер - по отдельной правке того же дня. */
.fav-charts-row {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.fav-chart-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: var(--shadow);
  padding: 18px 20px 16px;
  margin-bottom: 16px;
}

/* Колонка правого/левого места в .fav-charts-row (см. чат 2026-08-17) -
   раньше каждый .fav-chart-card был прямым flex-item'ом ряда напрямую;
   теперь между ними своя колонка, чтобы в правую можно было вертикально
   сложить купонный график + новый блок "Цены сейчас" под ним, не трогая
   левую (график стоимости портфеля + "Скоро деньги" внутри неё). */
.fav-charts-col {
  flex: 1 1 380px;
  min-width: 0; /* иначе flex-item не сжимается уже svg с viewBox */
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.fav-charts-col .fav-chart-card {
  margin-bottom: 0;
}

/* Амортизация + дюрация рядом на десктопе (просьба 2026-08-16) - grid,
   не flex, т.к. высота карточек разная (список амортизаций произвольной
   длины vs фикс. блок дюрации) и flex тянул бы их к высоте самой длинной
   строкой без выравнивания сверху. */
.fav-two-col-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  align-items: start;
  margin-bottom: 16px;
}

.fav-two-col-grid > .fav-chart-card {
  margin-bottom: 0;
  min-width: 0;
}

@media (max-width: 860px) {
  .fav-two-col-grid {
    grid-template-columns: 1fr;
  }
}

/* Класс ставится из JS (favorites-charts.js syncTwoColGrid) когда амортизация
   или дюрация скрыты - без этого одна оставшаяся карточка занимала бы
   половину ширины, а вторая половина пустовала. */
.fav-two-col-grid.fav-two-col-grid-single {
  grid-template-columns: 1fr;
}

.fav-chart-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 2px;
  flex-wrap: wrap;
}

.fav-chart-card h3 {
  margin: 0 0 4px;
  font-size: 14px;
  font-weight: 700;
  color: var(--text);
}

.fav-chart-card .fav-chart-sub {
  font-size: 12px;
  color: var(--text-faint);
  margin: 0;
}

.fav-chart-headline {
  font-size: 13px;
  margin-top: 6px;
}

/* Крупная сумма первой строкой, детали (изменение/эмитенты) - мельче на
   следующей (см. чат 2026-08-12, редизайн Joe) - strong стал block, чтобы
   не трогать порядок узлов в favorites-charts.js. */
.fav-chart-headline strong {
  display: block;
  font-variant-numeric: tabular-nums;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin-bottom: 4px;
}

.fav-chart-delta-up { color: var(--good); font-weight: 700; }
.fav-chart-delta-down { color: var(--text-muted); font-weight: 700; }

/* Живая стоимость портфеля (см. чат 2026-08-17, favorites-live-prices.js) -
   строка над самим графиком, видна только при включённом тумблере "Живые
   цены" (тот же в соседней карточке "Цены сейчас"). .dot и .live-price-delta
   - те же классы/цвета, что и там, чтобы обе карточки читались как одна
   история, а не два несвязанных виджета. */
.fav-value-live-delta {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 8px;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
}

.fav-value-live-delta .dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 2.5px var(--good-soft);
}

.fav-value-live-delta b {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.fav-chart-emitters { color: var(--text-faint); }
.fav-chart-since { color: var(--text-faint); font-weight: 500; }

.fav-chart-card-compact {
  padding: 16px 18px 12px;
}

.fav-chart-card-compact h3 {
  font-size: 13px;
}

.fav-chart-card-compact .fav-chart-sub {
  font-size: 11.5px;
}

/* "Цены сейчас" (см. чат 2026-08-17, favorites-live-prices.js) — закрытие
   вчера + живая цена (тумблер), 2 колонки, скролл внутри блока, а не рост
   всей карточки, чтобы правая колонка .fav-charts-row не тянула страницу
   вниз при большом избранном. */
#fav-live-prices-card .fav-chart-card-head { align-items: center; }
#fav-live-prices-card .live-toggle { margin-top: 0; }

.live-price-updated {
  font-size: 11px;
  color: var(--text-faint);
  margin: 5px 0 0;
  font-variant-numeric: tabular-nums;
}

.live-price-updated .dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--good);
  margin-right: 5px;
  box-shadow: 0 0 0 2.5px var(--good-soft);
}

.live-price-updated.market-closed .dot {
  background: var(--text-faint);
  box-shadow: 0 0 0 2.5px var(--surface-2);
}

.live-price-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px 10px;
  margin-top: 10px;
  max-height: 430px;
  overflow-y: auto;
  padding-right: 2px;
}

@media (max-width: 1060px) {
  /* Между брейкпоинтами: колонка .fav-charts-col ещё не переросла в
     полноширинную (см. .fav-charts-row ниже), 3 узких столбца становятся
     тесными для имени вроде "БалтЛизП19" + цены - откат на 2. */
  .live-price-grid { grid-template-columns: 1fr 1fr; }
}

.live-price-cell {
  padding: 7px 2px;
  border-bottom: 1px solid var(--border);
  min-width: 0;
}

.live-price-cell.no-border {
  border-bottom: none;
}

.live-price-name {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.live-price-row {
  display: flex;
  align-items: baseline;
  gap: 5px;
  margin-top: 3px;
  flex-wrap: wrap;
}

.live-price-close {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.live-price-row.is-live .live-price-close {
  font-size: 12px;
  font-weight: 400;
  color: var(--text-faint);
}

.live-price-arrow {
  font-size: 10px;
  color: var(--text-faint);
}

.live-price-last {
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.live-price-delta {
  font-size: 10.5px;
  font-weight: 700;
  padding: 1px 5px;
  border-radius: 5px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  margin-top: 4px;
  display: inline-block;
}

.live-price-delta.down { color: var(--poor); background: var(--poor-soft); }
.live-price-delta.up { color: var(--good); background: var(--good-soft); }
.live-price-delta.flat { color: var(--text-muted); background: var(--surface-2); }

/* Внутридневной спарклайн (см. чат 2026-08-17, "вариант A" мокапа) - во
   всю ширину ячейки под чипом изменения. viewBox фиксированный,
   preserveAspectRatio="none" в разметке растягивает картинку по ширине,
   height здесь фиксирует высоту - резиновая и на 3, и на 2, и на 1
   колонке без пересчёта в JS. currentColor + класс down/up/flat - тот же
   цвет, что у чипа рядом. */
.live-price-spark-wrap {
  margin-top: 5px;
  line-height: 0;
}

.live-price-spark-wrap.down { color: var(--poor); }
.live-price-spark-wrap.up { color: var(--good); }
.live-price-spark-wrap.flat { color: var(--text-muted); }

.live-price-sparkline {
  display: block;
  width: 100%;
  height: 20px;
}

/* "Сколько заработали" (см. чат 2026-08-17, favorites-total-return.js) -
   гипотетический total-return за 1/3/6/9/12 мес, отдельными плитками
   (цена/купоны/амортизация - специально не суммированы в одну строку, см.
   комментарий в favorites.ejs). */
.fav-tr-total-row {
  margin-top: 16px;
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.fav-tr-amt {
  font-size: 30px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
}

.fav-tr-amt.up { color: var(--good); }
.fav-tr-amt.down { color: var(--poor); }
.fav-tr-amt.flat { color: var(--text-muted); }

.fav-tr-pct {
  font-size: 14px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 6px;
  font-variant-numeric: tabular-nums;
}

.fav-tr-pct.up { color: var(--good); background: var(--good-soft); }
.fav-tr-pct.down { color: var(--poor); background: var(--poor-soft); }
.fav-tr-pct.flat { color: var(--text-muted); background: var(--surface-2); }

.fav-tr-breakdown {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-top: 14px;
}

.fav-tr-bd-item {
  background: var(--surface-2);
  border-radius: 12px;
  padding: 10px 12px;
}

.fav-tr-bd-label {
  font-size: 11px;
  color: var(--text-faint);
  margin-bottom: 3px;
}

.fav-tr-bd-val {
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.fav-tr-bd-val.up { color: var(--good); }
.fav-tr-bd-val.down { color: var(--poor); }
.fav-tr-bd-val.neutral { color: var(--text-muted); }

.fav-tr-meta {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
  font-size: 11.5px;
  color: var(--text-faint);
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}

.fav-tr-meta .dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--good);
  box-shadow: 0 0 0 2.5px var(--good-soft);
  flex-shrink: 0;
}

.fav-tr-empty {
  margin-top: 14px;
  color: var(--text-faint);
  font-size: 12.5px;
}

/* ===== "Кто тянет портфель" (см. чат 2026-08-18) =====
   Живёт в fav-total-return-card head рядом - .mode-toggle тот же паттерн,
   что .fav-period-toggle (кнопки-табы), но своё состояние (₽/%), не период. */
.mode-toggle {
  display: flex;
  gap: 2px;
  background: var(--surface-2);
  border-radius: 8px;
  padding: 3px;
  flex-shrink: 0;
}
.mode-toggle button {
  border: none;
  background: none;
  font-family: inherit;
  font-size: 12px;
  font-weight: 600;
  padding: 5px 11px;
  border-radius: 6px;
  color: var(--text-muted);
  cursor: pointer;
}
.mode-toggle button.active { background: var(--surface); color: var(--text); box-shadow: var(--shadow); }

.contrib-callout {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.5;
  margin: 14px 0 16px;
}
.contrib-callout b { font-weight: 700; }
.contrib-callout b.up { color: var(--good); }
.contrib-callout b.down { color: var(--poor); }

.contrib-row { display: grid; grid-template-columns: 88px 1fr 78px; align-items: center; gap: 10px; margin-bottom: 7px; }
.contrib-name {
  display: block;
  font-size: 12px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text);
  text-decoration: none;
}
.contrib-name:hover { color: var(--accent); text-decoration: underline; }
.contrib-track {
  position: relative;
  height: 20px;
  background: var(--surface-2);
  border-radius: 5px;
  overflow: hidden;
}
.contrib-zero { position: absolute; top: 0; bottom: 0; left: 50%; width: 1px; background: var(--border-strong); }
.contrib-bar { position: absolute; top: 2px; bottom: 2px; border-radius: 4px; }
.contrib-bar.up { background: var(--good); }
.contrib-bar.down { background: var(--poor); }
.contrib-figures { text-align: right; }
.contrib-val { font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.contrib-val.up { color: var(--good); }
.contrib-val.down { color: var(--poor); }
.contrib-sub { font-size: 10px; color: var(--text-faint); font-variant-numeric: tabular-nums; }

@media (max-width: 480px) {
  .contrib-row { grid-template-columns: 72px 1fr 64px; gap: 6px; }
  .contrib-name { font-size: 11px; }
}

/* Бенчмарки (см. чат 2026-08-17) - эталонная ОФЗ, ключевая ставка, RUONIA,
   вклад-оценка - каждый своей строкой под плитками разбивки. */
.fav-tr-bench-section {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.fav-tr-bench-label {
  font-size: 11px;
  color: var(--text-faint);
  margin-bottom: 6px;
}

.fav-tr-bench-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 0;
}

.fav-tr-bench-row + .fav-tr-bench-row {
  border-top: 1px dashed var(--border);
}

.fav-tr-bench-icon {
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: var(--surface-2);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: var(--text-muted);
}

.fav-tr-bench-icon svg {
  width: 15px;
  height: 15px;
}

.fav-tr-bench-name {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text);
  min-width: 0;
}

.fav-tr-bench-name .sub {
  display: block;
  font-size: 11px;
  font-weight: 400;
  color: var(--text-faint);
  margin-top: 1px;
}

.fav-tr-bench-figures {
  margin-left: auto;
  text-align: right;
  flex-shrink: 0;
}

.fav-tr-bench-amt {
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.fav-tr-bench-pct {
  font-size: 11px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

.fav-tr-bench-vs {
  font-size: 10.5px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 5px;
  white-space: nowrap;
  flex-shrink: 0;
  min-width: 78px;
  text-align: center;
}

.fav-tr-bench-vs.ahead { color: var(--good); background: var(--good-soft); }
.fav-tr-bench-vs.behind { color: var(--poor); background: var(--poor-soft); }

@media (max-width: 560px) {
  .fav-tr-breakdown { grid-template-columns: 1fr; }
  .fav-tr-bench-row { flex-wrap: wrap; }
  .fav-tr-bench-figures { margin-left: 36px; text-align: left; }
  .fav-tr-bench-vs { margin-left: 36px; }
}

@media (max-width: 480px) {
  .live-price-grid { grid-template-columns: 1fr; }
}

.fav-period-toggle {
  display: flex;
  gap: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 3px;
}

.fav-period-toggle button {
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  padding: 6px 11px;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
}

.fav-period-toggle button.active {
  background: var(--accent);
  color: var(--accent-contrast);
}

.fav-period-toggle button:hover:not(.active) {
  color: var(--text);
}

.fav-chart-svg-wrap {
  position: relative;
  margin-top: 10px;
}

.fav-chart-svg-wrap svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.fav-chart-svg-wrap .grid-line { stroke: var(--border); stroke-width: 1; }
.fav-chart-svg-wrap .axis-label {
  fill: var(--text-faint);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
}
.fav-chart-svg-wrap .value-line {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linejoin: round;
  stroke-linecap: round;
}
.fav-chart-svg-wrap .value-area { fill: var(--accent); opacity: 0.08; }
.fav-chart-svg-wrap .value-dot { fill: var(--accent); stroke: var(--surface); stroke-width: 2; }
/* "Будущее" на купонном графике (см. чат 2026-08-12) - та же линия/area/dot,
   но пунктиром и бледнее, чтобы не выглядеть как уже случившееся. */
.fav-chart-svg-wrap .value-line.future { stroke-dasharray: 5 4; opacity: 0.75; }
.fav-chart-svg-wrap .value-area.future { opacity: 0.05; }
.fav-chart-svg-wrap .value-dot.future { fill: var(--surface); stroke: var(--accent); stroke-dasharray: 2 2; }
.fav-chart-svg-wrap .hover-crosshair {
  stroke: var(--text-faint);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  opacity: 0;
}
/* Столбики разовых выплат в нижней полосе купонного графика (см. чат
   2026-08-12) - другой цвет, чем накопительная линия, чтобы визуально не
   путать "сколько за раз" и "сколько всего". */
.fav-chart-svg-wrap .pay-bar { fill: var(--good); }
.fav-chart-svg-wrap .pay-bar.future {
  fill: var(--good-soft);
  stroke: var(--good);
  stroke-width: 1;
  stroke-dasharray: 2 2;
}
/* Амортизация - синим (тот же accent, что у "стоимости"/накопительной
   линии) - это возврат номинала, не доход, поэтому не зелёный, как купон
   (см. чат 2026-08-12). */
.fav-chart-svg-wrap .pay-bar-amort { fill: var(--accent); }
.fav-chart-svg-wrap .pay-bar-amort.future {
  fill: var(--accent-soft);
  stroke: var(--accent);
  stroke-width: 1;
  stroke-dasharray: 2 2;
}
.fav-chart-svg-wrap .pay-bar-hit { fill: transparent; cursor: pointer; }

.fav-chart-legend {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 11.5px;
  color: var(--text-faint);
  margin-top: 8px;
}
.fav-chart-legend .sw {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 2px;
  margin-right: 5px;
  vertical-align: -1px;
}
.fav-chart-legend .sw-cum { background: var(--accent); }
.fav-chart-legend .sw-pay { background: var(--good); }
.fav-chart-legend .sw-pay.future { background: var(--good-soft); border: 1px dashed var(--good); }
/* Кружок вместо квадрата (см. чат 2026-08-14) - тот же вокабуляр, что и
   новые точки-маркеры амортизации на самих графиках (.amort-marker-dot). */
.fav-chart-legend .sw-amort-dot { border-radius: 50%; background: var(--accent); border: 1.5px solid var(--surface); box-shadow: 0 0 0 1px var(--accent); }

/* Точки-маркеры амортизации на купонном и на портфельном графиках (см. чат
   2026-08-14) - крупнее и заметнее тонкой полоски внизу купонного графика,
   которую легко пропустить в масштабе "Год". */
.amort-marker-hit { fill: transparent; cursor: pointer; }
.amort-marker-dot { fill: var(--accent); stroke: var(--surface); stroke-width: 2.5; pointer-events: none; }
.amort-marker-dot.future { fill: var(--surface); stroke: var(--accent); stroke-width: 2.5; }
.amort-marker-ring { fill: none; stroke: var(--accent); stroke-width: 1.5; opacity: 0.35; pointer-events: none; }

/* Маркеры покупки/продажи и "новая цена без даты покупки" на графике
   стоимости портфеля (см. чат 2026-08-26, согласовано мокапом) - тот же
   вокабуляр ring+hit, что и у .amort-marker-* выше, но треугольник/ромб
   вместо кружка и свой цвет на направление. Продажа - не var(--poor):
   продажа часто осознанная ребалансировка, а не убыток, не хотим намекать
   "плохо" одним только цветом. */
.txn-marker-hit { fill: transparent; cursor: pointer; }
.txn-marker-shape { stroke: var(--surface); stroke-width: 2; pointer-events: none; }
.txn-marker-shape.buy { fill: var(--good); }
.txn-marker-shape.sell { fill: var(--text); }
.txn-marker-shape.nodate { fill: var(--ok); }
.txn-marker-ring { fill: none; stroke-width: 1.5; opacity: 0.35; pointer-events: none; }
.txn-marker-ring.buy { stroke: var(--good); }
.txn-marker-ring.sell { stroke: var(--text); }
.txn-marker-guide { stroke: var(--ok); stroke-width: 1.25; stroke-dasharray: 3 3; opacity: 0.8; pointer-events: none; }

.fav-chart-legend .lg-item { display: inline-flex; align-items: center; gap: 5px; }
/* width/height:14px переопределяют .fav-chart-svg-wrap svg { width:100%;
   height:auto } выше (см. чат 2026-08-26) - то правило рассчитано на
   единственный большой svg графика в этой же обёртке; без явного размера
   здесь маленькая иконка легенды растягивалась на всю ширину карточки,
   ломая и себя, и перенос текста рядом. */
.fav-chart-legend .lg-item svg { flex: none; width: 14px; height: 14px; }

.fav-chart-muted { color: var(--text-faint); }

.fav-chart-card-head-sub {
  margin-top: 6px;
}

.fav-chart-tooltip {
  position: absolute;
  pointer-events: none;
  background: var(--text);
  color: var(--surface);
  font-size: 11.5px;
  padding: 6px 9px;
  border-radius: 6px;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.1s;
  transform: translate(-50%, -100%);
  z-index: 5;
  font-variant-numeric: tabular-nums;
}
.fav-chart-tooltip b { font-weight: 700; }

.fav-chart-caption {
  font-size: 11.5px;
  color: var(--text-faint);
  margin: 10px 0 0;
  line-height: 1.5;
}

/* "Скоро деньги" (см. чат 2026-08-12, редизайн Joe) - сумма крупно первой,
   дата под ней, технические детали (какая бумага/событие) мелко внизу.
   Раньше было длинное предложение с суммой в середине текста. */
.fav-amort-banner {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  background: var(--good-soft);
  border: 1px solid var(--good-border);
  border-radius: 14px;
  padding: 14px 16px;
  margin-top: 14px;
}
.fav-amort-banner[hidden] { display: none; }
.fav-amort-banner-body { flex: 1; min-width: 0; }
.joe-alert-emoji { font-size: 22px; line-height: 1; flex-shrink: 0; margin-top: 1px; }
.joe-alert-title { margin: 0 0 3px; font-size: 12.5px; font-weight: 700; color: var(--good); }
.joe-alert-amt { font-size: 24px; font-weight: 700; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; color: var(--text); }
.joe-alert-when { font-size: 13px; color: var(--text-muted); margin: 1px 0 6px; }
/* Даты внизу карточки "Скоро деньги" (см. чат 2026-08-14) - раньше баннер
   показывал только ближайшее событие; теперь сумма за 3 месяца сверху,
   а конкретные даты, из чего она сложилась - списком внизу той же карточки. */
.joe-alert-dates { display: flex; flex-direction: column; margin-top: 10px; padding-top: 4px; border-top: 1px solid var(--good-border); }
/* Редизайн (см. чат 2026-08-16): было в одну строку, дата+пилюля "частичное
   7.5%" фиксированной ширины вытесняли название бумаги почти целиком
   (обрезалось до "Си…"/"Б…" на реальном портфеле - эмитент нечитаем). Теперь
   название - отдельной крупной строкой сверху без обрезки по ширине, а
   дата/тип события/% - мелким текстом под ним (тот же приём, что и в
   карточке "Полный график амортизации" ниже на этой же странице). */
.joe-alert-date-row { padding: 8px 0; border-top: 1px solid var(--good-border); }
.joe-alert-date-row:first-child { border-top: none; padding-top: 0; }
.joe-alert-date-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.joe-alert-date-name { font-size: 14px; font-weight: 700; color: var(--text); }
.joe-alert-date-amt { font-variant-numeric: tabular-nums; font-weight: 700; font-size: 14px; color: var(--good); flex-shrink: 0; white-space: nowrap; }
.joe-alert-date-meta { display: flex; align-items: center; gap: 7px; margin-top: 3px; font-size: 11.5px; color: var(--text-faint); }
.joe-alert-date-badge { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--good); }
.joe-alert-date-dot { opacity: 0.5; }

/* Полный график амортизации вперёд (см. чат 2026-08-14) - отдельная
   карточка под .fav-charts-row, дополняет "Скоро деньги" (там только
   3 месяца) полным списком на годы вперёд, с прогрессивным раскрытием -
   тот же вокабуляр, что и у остальных карточек на странице. */
.fav-amort-schedule-card { margin-top: 16px; }
.fav-amort-schedule-list { display: flex; flex-direction: column; margin-top: 12px; }
.fav-amort-row {
  display: flex; align-items: center; gap: 12px; padding: 10px 4px;
  border-top: 1px solid var(--border);
}
.fav-amort-row:first-child { border-top: none; padding-top: 2px; }
.fav-amort-date-badge {
  width: 42px; flex-shrink: 0; text-align: center; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 8px; padding: 5px 2px; line-height: 1.15;
}
.fav-amort-row.is-nearest .fav-amort-date-badge { background: var(--good-soft); border-color: var(--good-border); }
.fav-amort-date-day { display: block; font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); }
.fav-amort-date-mon { display: block; font-size: 10px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.02em; }
.fav-amort-row-body { flex: 1; min-width: 0; }
.fav-amort-row-name { font-size: 13.5px; font-weight: 700; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fav-amort-row-meta { font-size: 11.5px; color: var(--text-faint); margin-top: 2px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.fav-amort-pill {
  display: inline-block; font-size: 10.5px; font-weight: 700; padding: 1px 7px; border-radius: 999px;
  background: var(--neutral-pill); color: var(--text-muted);
}
.fav-amort-pill.is-final { background: var(--accent-soft); color: var(--accent); }
.fav-amort-row-amt { font-size: 14.5px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--good); flex-shrink: 0; }
.fav-amort-schedule-more {
  margin-top: 10px; width: 100%; text-align: center; padding: 9px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
  font-size: 12.5px; font-weight: 600; font-family: inherit; cursor: pointer;
}
.fav-amort-schedule-more:hover { color: var(--accent); border-color: var(--border-strong); }
.fav-amort-schedule-more[hidden] { display: none; }
.fav-amort-row.hidden-extra { display: none; }

/* Дюрация избранных бумаг + мнение по ключевой ставке (см. чат 2026-08-12) -
   отдельная полноширинная карточка под .fav-charts-row (не третья колонка
   в самом ряду - при узкой ширине флекс-колонки строки бумага+полоса+число
   становятся нечитаемыми). */
#fav-duration-card { margin-top: 16px; }
#fav-duration-card h3 { margin: 0 0 4px; font-size: 14px; font-weight: 700; }

/* position:relative - линия среднего (.fav-dur-avg-line) вставляется сюда же
   доп. ребёнком с top:0/bottom:0, растягивается на все строки сразу, а не
   на высоту отдельного зazor-блока после них (баг, см. чат 2026-08-12). */
#fav-duration-rows { position: relative; margin-top: 22px; margin-bottom: 6px; }

.fav-dur-row {
  display: grid;
  grid-template-columns: 120px 1fr 56px;
  align-items: center;
  gap: 10px;
  margin-bottom: 9px;
}
.fav-dur-name {
  font-size: 12.5px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.fav-dur-track {
  position: relative;
  height: 16px;
  background: var(--surface-2);
  border-radius: 4px;
}
.fav-dur-fill {
  position: absolute;
  top: 0; left: 0; height: 100%;
  border-radius: 4px;
  background: var(--accent);
  transition: background .2s, width .2s;
}
.fav-dur-fill.risk { background: var(--poor); }
.fav-dur-fill.safe { background: var(--good); }
.fav-dur-val {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  text-align: right;
}

.fav-dur-avg-line { position: absolute; top: 0; bottom: 0; width: 2px; background: var(--text); opacity: .5; pointer-events: none; }
.fav-dur-avg-label { position: absolute; top: -20px; font-size: 10px; color: var(--text-faint); white-space: nowrap; transform: translateX(-50%); }

.fav-rate-toggle { width: 100%; }
.fav-rate-toggle button { flex: 1; text-align: center; }

.fav-rate-note {
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--text-muted);
  background: var(--surface-2);
  border-radius: 8px;
  padding: 10px 12px;
  margin-top: 10px;
}
.fav-rate-note b { color: var(--text); }
.fav-rate-note .hl-risk { color: var(--poor); font-weight: 600; }
.fav-rate-note .hl-safe { color: var(--good); font-weight: 600; }

.fav-key-rate-tag { font-size: 11px; color: var(--text-faint); margin: 10px 0 0; }
.fav-key-rate-tag b { color: var(--text-muted); }

/* ===== Карточки бумаг (см. чат 2026-08-12, редизайн Joe) =====
   Заменяют table.bonds-table на /favorites. Рейтинг/ликвидность/теги -
   те же классы, что и в главной таблице (.rating-pill/.liquidity-status-pill/
   .type-tag, table.css) - только контейнер и раскладка другие. */
.list-head { padding: 4px 4px 8px; }
.list-head h2 { margin: 0; font-size: 15px; font-weight: 700; color: var(--text); }

/* Два столбца на десктопе (см. чат 2026-08-16) - строгая grid-сетка, а не
   flex-wrap с flex-basis (как у .fav-charts-row выше): при flex-grow на
   широких экранах в ряд встало бы 3 карточки, а не 2 (1240px контента
   вмещает 3×380px с запасом) - grid с фиксированными 2 колонками держит
   ровно две независимо от ширины экрана. align-items:start - иначе grid по
   умолчанию растягивает все карточки в ряду до высоты самой высокой
   (у карточек разное число тегов/строк описания, легко разъезжается). */
.fav-card-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: start;
  gap: 12px;
}
@media (max-width: 768px) {
  .fav-card-list { grid-template-columns: 1fr; }
}

.bond-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 15px 16px;
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.bond-top { display: flex; justify-content: space-between; gap: 10px; }
.bond-id-head { display: flex; align-items: center; gap: 6px; }
.bond-id-head h3 { margin: 0; font-size: 14.5px; font-weight: 700; color: var(--text); }
/* Название бумаги теперь ссылка (.safe-diagnosis-link, открывает
   #bond-diagnosis-modal - см. чат 2026-08-12) - сбрасываем цвет/подчёркивание
   ссылки, реальный вид текста всё равно задаёт h3-правило выше. */
.bond-id-head .safe-diagnosis-link { color: inherit; text-decoration: none; min-width: 0; }
.bond-isin { font-size: 11px; color: var(--text-faint); font-variant-numeric: tabular-nums; margin-top: 2px; }
.bond-tags { display: flex; gap: 5px; margin-top: 7px; flex-wrap: wrap; align-items: center; }

/* Звезда на карточке - та же .favorite-star, что и в таблице (table.css),
   только крупнее (тут не в узкой ячейке) и без переноса при клике по звезде
   (stopPropagation уже в wireFavoriteStar). */
.bond-id-head .favorite-star { width: 22px; height: 22px; flex-shrink: 0; }
.bond-id-head .favorite-star svg { width: 18px; height: 18px; }

.metric-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px 6px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.metric { display: flex; flex-direction: column; gap: 1px; border-radius: 8px; padding: 2px 4px; margin: -2px -4px; }
.metric span { font-size: 10px; color: var(--text-faint); font-weight: 600; text-transform: uppercase; letter-spacing: 0.02em; }
.metric b { font-size: 13.5px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); }
.metric b.bond-metric-date { font-size: 12px; }
/* .ytm повторяет цвет .yield-num.hi из главной таблицы (table.css) - зелёным
   только доходности выше 10%, не любую YTM без разбора. */
.metric b.ytm.hi { color: var(--good); }

/* Подсветка "Тек. купон" (см. чат 2026-08-15, мокап) - тот же --accent-soft/
   --accent, что у .clickable-price ниже (table.css) - единственная
   динамическая цифра купона на карточке. Нейтральный акцентный цвет, не
   --good/--poor - работает одинаково, растёт текущий купон к номиналу или
   падает (в отличие от .ytm.hi выше, который именно "хорошо/плохо"). */
.metric.coupon-now { background: var(--accent-soft); }
.metric.coupon-now span { color: var(--accent); opacity: 0.85; }
.metric.coupon-now b { color: var(--accent); }

@media (max-width: 380px) {
  .metric-grid { grid-template-columns: repeat(2, 1fr); }
}

/* Экспорт/импорт избранного (см. чат 2026-08-14) - кнопки в шапке страницы,
   по образцу .fav-period-toggle (сегментированный контрол ниже), но без
   активного состояния - это не переключатель, а два независимых действия. */
.fav-io-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  flex-wrap: wrap;
}
.fav-io-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text);
}
.fav-io-btn svg { width: 15px; height: 15px; flex-shrink: 0; }
.fav-io-btn:hover { border-color: var(--border-strong); color: var(--accent); }
.fav-io-hint {
  font-size: 12px;
  color: var(--text-faint);
}
@media (max-width: 480px) {
  .fav-io-hint { display: none; }
}

/* Модалка подтверждения импорта - тот же вокабуляр, что .fav-txn-panel
   (surface/border-strong/shadow), но по центру экрана поверх затемнения,
   а не рядом с якорем - решение о слиянии избранного важнее попапа-справки. */
.fav-io-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(19, 28, 34, 0.45);
  align-items: center;
  justify-content: center;
  z-index: 300;
  padding: 20px;
}
.fav-io-overlay.open { display: flex; }
.fav-io-modal {
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  box-shadow: var(--shadow);
  width: 100%;
  max-width: 400px;
  padding: 20px 22px 18px;
}
.fav-io-modal h3 { margin: 0 0 6px; font-size: 16px; font-weight: 700; color: var(--text); }
.fav-io-modal-text { margin: 0 0 14px; font-size: 13px; color: var(--text-muted); line-height: 1.55; }
.fav-io-summary {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
  margin-bottom: 16px;
}
.fav-io-summary-row { display: flex; justify-content: space-between; padding: 4px 0; }
.fav-io-summary-row + .fav-io-summary-row { border-top: 1px solid var(--border); }
.fav-io-summary-row b { font-variant-numeric: tabular-nums; }
.fav-io-summary-row b.good { color: var(--good); }
.fav-io-modal-actions { display: flex; gap: 8px; justify-content: flex-end; }
.fav-io-cancel, .fav-io-confirm {
  padding: 9px 16px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  border: 1px solid transparent;
}
.fav-io-cancel { background: transparent; border-color: var(--border); color: var(--text-muted); }
.fav-io-cancel:hover { color: var(--text); border-color: var(--border-strong); }
.fav-io-confirm { background: var(--accent); color: var(--accent-contrast); }
.fav-io-confirm:hover { filter: brightness(1.08); }

.fav-io-toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  transform: translate(-50%, 16px);
  background: var(--text);
  color: var(--bg);
  padding: 11px 18px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  box-shadow: var(--shadow);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s, transform .2s;
  z-index: 320;
}
.fav-io-toast.show { opacity: 1; transform: translate(-50%, 0); }

/* На мобильном тост на bottom:28px попадал за нижнюю панель навигации
   (.bottom-nav, mobile-nav.css - fixed, ~72px + safe-area, тот же брейкпоинт
   768px) - поднимаем над ней. */
@media (max-width: 768px) {
  .fav-io-toast {
    bottom: calc(88px + env(safe-area-inset-bottom));
  }
}

/* ===== "Риск по эмитентам" (favorites-risk.js, #fav-risk-card) =====
   Своя разметка (не переиспользует .siblings-table/.bond-info из
   emitters.css/bond-diagnostics-shared.css) - это отдельная более широкая
   сводная таблица (5 колонок с баром риска), не карточка одного эмитента. */
.risk-tier-summary {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.tier-chip {
  display: flex;
  align-items: baseline;
  gap: 5px;
  background: var(--surface-2);
  border-radius: 10px;
  padding: 6px 10px;
  font-size: 12px;
  color: var(--text-muted);
}

.tier-chip b {
  font-family: var(--font-mono), var(--font-mono-fallback);
  font-variant-numeric: tabular-nums;
  font-size: 14px;
  color: var(--text);
}

.tier-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  margin-right: 2px;
}
.tier-dot-low { background: var(--good); }
.tier-dot-mid { background: var(--ok); }
.tier-dot-elevated { background: var(--poor); }
.tier-dot-high { background: var(--risk-high, var(--poor)); }

.risk-callout {
  font-size: 12.5px;
  color: var(--text-muted);
  margin-bottom: 14px;
  padding: 9px 12px;
  background: var(--poor-soft);
  border-radius: 10px;
  line-height: 1.5;
}
.risk-callout b { color: var(--poor); }

.risk-table-wrap { overflow-x: auto; }

table.risk-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 680px;
}

table.risk-table th {
  text-align: left;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-faint);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
}

table.risk-table td {
  padding: 10px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  font-size: 12.5px;
}

table.risk-table tr:last-child td { border-bottom: none; }

.risk-table .emitter-cell { font-weight: 700; color: var(--text); }
.risk-table .emitter-sub { font-size: 10.5px; color: var(--text-faint); font-weight: 400; margin-top: 1px; }

/* Клик по названию открывает карточку эмитента (см. чат 2026-08-16) - тот
   же делегированный обработчик .emitter-row/data-emitter-id, что уже
   работает на /emitters (modal-manager.js), здесь только на ячейке с
   названием, а не на всей строке - остальные ячейки (рейтинг/бар/событие/
   YTM) кликом не реагируют, только сам текст названия. */
.risk-table td.emitter-row {
    cursor: pointer;
}
.risk-table td.emitter-row:hover .emitter-cell {
    color: var(--accent);
    text-decoration: underline;
}

.risk-table .outlook-note { display: block; font-size: 10.5px; color: var(--text-faint); margin-top: 3px; }
.risk-table .outlook-note.negative { color: var(--poor); }
.risk-table .outlook-note.watch { color: var(--ok); }

.risk-bar-cell { min-width: 150px; }

.risk-bar {
  display: flex;
  height: 8px;
  border-radius: 5px;
  overflow: hidden;
  background: var(--neutral-pill);
  margin-bottom: 4px;
}
.risk-bar-base { background: var(--accent); }
.risk-bar-degr { background: var(--poor); }

.risk-bar-label {
  display: flex;
  justify-content: space-between;
  font-size: 10px;
  color: var(--text-faint);
  font-family: var(--font-mono), var(--font-mono-fallback);
  font-variant-numeric: tabular-nums;
}

.tier-pill {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  padding: 3px 9px;
  border-radius: 999px;
  white-space: nowrap;
}
.tier-low { background: var(--good-soft); color: var(--good); }
.tier-mid { background: var(--ok-soft); color: var(--ok); }
.tier-elevated { background: var(--poor-soft); color: var(--poor); }
.tier-high { background: var(--risk-high-soft, var(--poor-soft)); color: var(--risk-high, var(--poor)); }
.tier-sovereign { background: var(--neutral-pill); color: var(--text-faint); }

.risk-table .event-cell { font-size: 11.5px; }
.risk-table .event-date { font-family: var(--font-mono), var(--font-mono-fallback); font-variant-numeric: tabular-nums; color: var(--text-muted); }
.risk-table .event-amount { font-weight: 700; margin-left: 3px; }
.risk-table .event-warn { color: var(--poor); }

.risk-table .ytm-cell {
  font-family: var(--font-mono), var(--font-mono-fallback);
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.risk-table tr.sovereign-row td { color: var(--text-faint); }

.method-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
  font-size: 12px;
  color: var(--text-muted);
}
.method-grid > div {
  background: var(--surface-2);
  border-radius: 10px;
  padding: 10px 12px;
}
.method-grid h4 { margin: 0 0 6px; font-size: 11.5px; color: var(--text); }
.method-grid ul { margin: 0; padding-left: 16px; }
.method-grid li { margin-bottom: 3px; }
.method-note { font-size: 11.5px; color: var(--text-faint); margin-top: 10px; line-height: 1.5; }

@media (max-width: 720px) {
  .risk-table-wrap { overflow-x: visible; }
  table.risk-table, table.risk-table tbody { display: block; width: 100%; min-width: 0; }
  table.risk-table thead { display: none; }
  table.risk-table tr {
    display: block;
    background: var(--surface-2);
    border-radius: 14px;
    padding: 10px 12px;
    margin-bottom: 8px;
  }
  table.risk-table td { display: block; padding: 3px 0; border-bottom: none; }
  table.risk-table td.risk-bar-cell { padding-top: 6px; }
  .method-grid { grid-template-columns: 1fr; }
}

/* ===== "Улучшить портфель" (см. чат 2026-08-18) =====
   Развёрнутые карточки для 3 "заметных" статусов (флаг риска/технический
   выброс/чистая замена) + компактная таблица для остального - тот же
   приём, что risk-table выше, переиспользует .rating-badge (глобальный,
   bond-diagnostics-shared.css). */
.upg-summary {
  font-size: 12.5px;
  color: var(--text-muted);
  margin-bottom: 14px;
}
.upg-summary b { color: var(--text); }

.upg-finding {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 14px 16px;
  margin-bottom: 12px;
}

/* Широкий десктоп (просьба чат 2026-08-18) - карточки находок в 2 колонки,
   иначе на широком экране блок неоправданно растягивается по высоте одной
   колонкой. 1100px, не 860px (как .fav-two-col-grid) - внутри карточки уже
   свой горизонтальный ряд (upg-bond-flow: 2 мини-карточки + стрелка), при
   более узком делении на колонки он становится тесным. */
@media (min-width: 1100px) {
  #fav-upgrade-findings {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    align-items: start;
  }
  #fav-upgrade-findings .upg-finding { margin-bottom: 0; }
}
.upg-finding-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
  flex-wrap: wrap;
}
.upg-status-pill {
  font-size: 11.5px;
  font-weight: 700;
  padding: 4px 11px;
  border-radius: 999px;
}
.upg-status-pill.good { background: var(--good-soft); color: var(--good); }
.upg-status-pill.poor { background: var(--poor-soft); color: var(--poor); }
.upg-status-pill.ok { background: var(--ok-soft); color: var(--ok); }
.upg-finding-median { font-size: 11.5px; color: var(--text-faint); }

.upg-bond-flow {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.upg-bond-mini {
  flex: 1;
  min-width: 0;
  background: var(--surface-2);
  border-radius: 11px;
  padding: 10px 12px;
}
.upg-bond-name {
  display: inline-block;
  font-weight: 700;
  font-size: 13px;
  margin-bottom: 5px;
  color: var(--text);
  text-decoration: none;
}
.upg-bond-name:hover { color: var(--accent); text-decoration: underline; }
table.upg-scan-table .upg-bond-name { margin-bottom: 0; }
.upg-bond-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.upg-yield {
  font-size: 16px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.upg-bond-sub { font-size: 11px; color: var(--text-muted); margin-top: 5px; }
.upg-flow-arrow { color: var(--text-faint); font-size: 17px; flex-shrink: 0; }

.upg-delta-chip {
  display: inline-flex;
  align-items: center;
  font-size: 12px;
  font-weight: 700;
  color: var(--good);
  background: var(--good-soft);
  border-radius: 7px;
  padding: 3px 9px;
  margin-bottom: 9px;
}

.upg-finding-note {
  font-size: 12.5px;
  color: var(--text-muted);
  line-height: 1.55;
  margin: 0;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}
.upg-finding-note b { color: var(--text); font-weight: 600; }

.upg-scan-wrap { overflow-x: auto; margin-top: 4px; }
table.upg-scan-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
table.upg-scan-table th {
  text-align: left;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-faint);
  padding: 8px 10px;
  border-bottom: 1px solid var(--border);
}
table.upg-scan-table td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
table.upg-scan-table tr:last-child td { border-bottom: none; }
.upg-scan-yield { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.upg-scan-pill {
  font-size: 10.5px;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 999px;
  white-space: nowrap;
}
.upg-scan-pill.neutral { background: var(--neutral-pill); color: var(--text-muted); }
.upg-scan-pill.poor { background: var(--poor-soft); color: var(--poor); }
.upg-scan-pill.good { background: var(--good-soft); color: var(--good); }
.upg-scan-reason { color: var(--text-faint); font-size: 11.5px; }

@media (max-width: 720px) {
  .upg-bond-flow { flex-direction: column; align-items: stretch; }
  .upg-flow-arrow { align-self: center; transform: rotate(90deg); }
  .upg-scan-wrap { overflow-x: visible; }
  table.upg-scan-table, table.upg-scan-table tbody { display: block; width: 100%; min-width: 0; }
  table.upg-scan-table thead { display: none; }
  table.upg-scan-table tr {
    display: block;
    background: var(--surface-2);
    border-radius: 14px;
    padding: 10px 12px;
    margin-bottom: 8px;
  }
  table.upg-scan-table td { display: block; padding: 3px 0; border-bottom: none; }
}

/* ===== "Профиль вашего портфеля" (favorites-strategy.js, #fav-strategy-card) =====
   Мокап согласован с пользователем 2026-08-18 — переиспользует tier-chip/
   rating-badge из соседних блоков там, где смысл совпадает, свои классы
   только там, где визуал специфичен (полосы рейтинга/валюты, шкала дюрации). */
.strat-tags { display: flex; gap: 8px; flex-wrap: wrap; margin: 12px 0 18px; }
.strat-tag {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent-soft); color: var(--accent); border-radius: 10px;
  padding: 6px 12px; font-size: 12.5px; font-weight: 700;
}

.strat-section { margin-bottom: 20px; }
.strat-section:last-child { margin-bottom: 0; }
.strat-section-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-faint); margin: 0 0 10px;
}

.strat-rating-bar { display: flex; height: 22px; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); margin-bottom: 10px; }
.strat-rating-seg { display: flex; align-items: center; justify-content: center; font-size: 10.5px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--accent-contrast); }
.strat-rating-legend { display: flex; flex-wrap: wrap; gap: 14px 18px; font-size: 12px; color: var(--text-muted); }
.strat-rating-legend-item { display: flex; align-items: center; gap: 6px; }
.strat-rating-dot { width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }
.strat-rating-legend b { color: var(--text); font-variant-numeric: tabular-nums; }

.strat-duration-axis { position: relative; height: 54px; margin: 6px 4px 4px; }
.strat-duration-line { position: absolute; left: 0; right: 0; top: 28px; height: 2px; background: var(--border); }
.strat-duration-dot {
  position: absolute; top: 21px; width: 15px; height: 15px; border-radius: 50%;
  background: var(--accent); border: 2.5px solid var(--surface); box-shadow: 0 0 0 1.5px var(--accent);
  transform: translateX(-50%); cursor: default;
}
.strat-duration-dot.solo { background: var(--ok); box-shadow: 0 0 0 1.5px var(--ok); width: 17px; height: 17px; top: 20px; }
.strat-duration-label {
  position: absolute; top: -14px; font-size: 10px; color: var(--text-faint); white-space: nowrap; transform: translateX(-50%);
  font-variant-numeric: tabular-nums;
}
.strat-duration-tick { position: absolute; top: 40px; font-size: 10px; color: var(--text-faint); transform: translateX(-50%); }
.strat-duration-note { font-size: 12.5px; color: var(--text-muted); line-height: 1.55; margin: 14px 0 0; }
.strat-duration-note b { color: var(--text); font-weight: 600; }

.strat-industry-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; font-size: 12.5px; }
.strat-industry-name { flex: 0 0 auto; max-width: 44%; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.strat-industry-track { flex: 1; height: 8px; border-radius: 4px; background: var(--surface-2); overflow: hidden; }
.strat-industry-fill { height: 100%; background: var(--accent); border-radius: 4px; }
.strat-industry-fill.flag { background: var(--poor); }
.strat-industry-pct { flex: 0 0 42px; text-align: right; font-variant-numeric: tabular-nums; color: var(--text-muted); font-weight: 600; }

.strat-callout { font-size: 12.5px; color: var(--text-muted); margin-top: 12px; padding: 9px 12px; background: var(--poor-soft); border-radius: 10px; line-height: 1.5; }
.strat-callout b { color: var(--poor); }

.strat-currency-bar { display: flex; height: 22px; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); }
.strat-currency-seg { display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; color: var(--accent-contrast); white-space: nowrap; overflow: hidden; }
.strat-currency-seg.rub { background: var(--accent); }
.strat-currency-seg.usd { background: var(--text-faint); }

@media (max-width: 640px) {
  .strat-industry-name { max-width: 38%; }
}

/* ===== "Куда вложить новые деньги" (favorites-smart-buy.js, #fav-smart-buy-card) ===== */
.buy-amount-row {
  display: flex; align-items: center; gap: 10px; margin: 14px 0 18px; flex-wrap: wrap;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px;
}
.buy-amount-label { font-size: 12px; color: var(--text-muted); flex-shrink: 0; }
.buy-amount-value {
  /* min-width гарантирует место под реальную сумму (до 8 цифр с пробелами,
     "10 000 000") - без него флекс сжимал поле почти до нуля рядом с
     кнопкой, и введённое число уезжало влево за край (text-align: right +
     переполнение) - реальный баг, 2026-08-28. flex-wrap на строке выше
     переносит кнопку на следующую строку, если места всё равно не хватает,
     вместо повторного сжатия поля. */
  flex: 1 1 100px; min-width: 100px; font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text);
  background: transparent; border: none; text-align: right; outline: none; font-family: var(--font-primary);
}
.buy-amount-value::placeholder { color: var(--text-faint); font-weight: 700; }
.buy-amount-btn {
  background: var(--accent); color: var(--accent-contrast); border: none; border-radius: 9px;
  padding: 8px 16px; font-size: 12.5px; font-weight: 700; cursor: pointer; flex-shrink: 0;
}
.buy-amount-btn:disabled { opacity: 0.55; cursor: default; }

.buy-note { font-size: 12px; color: var(--text-faint); margin: 0 0 16px; line-height: 1.5; }
.buy-empty { font-size: 13px; color: var(--text-muted); padding: 6px 0; }

.buy-card { border: 1px solid var(--border); border-radius: 14px; padding: 14px 16px; margin-bottom: 12px; position: relative; }
.buy-card:last-child { margin-bottom: 0; }
.buy-card.top { border-color: var(--good); }
.buy-rank {
  position: absolute; top: -9px; left: 14px; background: var(--surface); padding: 0 6px;
  font-size: 10px; font-weight: 800; color: var(--text-faint); letter-spacing: 0.03em; text-transform: uppercase;
}
.buy-card.top .buy-rank { color: var(--good); }
.buy-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-top: 4px; }
.buy-name { font-size: 14.5px; font-weight: 700; color: var(--text); }
.buy-name a { color: var(--text); text-decoration: none; }
.buy-name a:hover { color: var(--accent); text-decoration: underline; }
.buy-name .rating-badge { margin-left: 6px; }
.buy-yield { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); white-space: nowrap; }
.buy-yield-delta { font-size: 11px; color: var(--text-faint); font-weight: 500; margin-left: 4px; }
.buy-meta { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin: 8px 0 10px; }
.buy-chip { font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px; background: var(--accent-soft); color: var(--accent); }
.buy-reason { font-size: 12.5px; color: var(--text-muted); line-height: 1.55; margin: 0; }
.buy-reason b { color: var(--text); font-weight: 600; }
.buy-lot-row {
  display: flex; justify-content: space-between; align-items: center; margin-top: 10px; padding-top: 10px;
  border-top: 1px dashed var(--border); font-size: 12px; color: var(--text-muted); flex-wrap: wrap; gap: 6px;
}
.buy-lot-row b { color: var(--text); font-variant-numeric: tabular-nums; }

.buy-footnote { font-size: 12px; color: var(--text-faint); margin: 16px 0 0; padding-top: 12px; border-top: 1px solid var(--border); line-height: 1.55; }

@media (max-width: 640px) {
  .buy-head { flex-direction: column; align-items: flex-start; gap: 4px; }
  .buy-lot-row { flex-direction: column; align-items: flex-start; }
}

/* ===== Пустое /favorites — SEO-витрина возможностей (см. чат 2026-08-16) =====
   #fav-empty-state (.no-data-message) сам по себе центрированный короткий
   текст (index.css, общий для пустых состояний по всему сайту) - витрина
   внутри него сбрасывает text-align на левый и живёт своей вёрсткой, чтобы
   не наследовать общий центрированный стиль на длинный контент. Google
   исполняет JS (Googlebot = evergreen Chromium), а у бота никогда не будет
   localStorage с реальными избранными бумагами - то есть /favorites для
   любого краулера ВСЕГДА рендерится в этом пустом состоянии, поэтому именно
   здесь имеет смысл вкладываться в содержательный текст и картинки, а не
   в состояние "список заполнен", которое краулер физически не увидит. */
.fav-empty-showcase {
    text-align: left;
    max-width: 900px;
    margin: 28px auto 0;
    color: var(--text);
}
.fav-empty-showcase h2 {
    font-size: 18px;
    font-weight: 700;
    margin: 0 0 10px;
    color: var(--text);
}
.fav-empty-showcase > p {
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--text-muted);
    margin: 0 0 20px;
}

.fav-feature-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 10px;
    margin-bottom: 28px;
}
.fav-feature {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 13px 15px;
    text-align: left;
}
.fav-feature h3 {
    margin: 0 0 4px;
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
}
.fav-feature p {
    margin: 0;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-faint);
}
@media (max-width: 640px) {
    .fav-feature-grid { grid-template-columns: 1fr; }
}

.fav-showcase-caption-lead {
    font-size: 13px;
    color: var(--text-muted);
    margin: 0 0 10px;
}

.fav-showcase-carousel-wrap { position: relative; }

.fav-showcase-carousel {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    padding-bottom: 6px;
    /* Скроллбар виден и юзабелен (это часть UX "полистать"), но собственный
       минималистичный - системный смотрелся бы инородно рядом с остальным
       вокабуляром страницы. */
    scrollbar-width: thin;
    scrollbar-color: var(--border-strong) transparent;
}
.fav-showcase-carousel::-webkit-scrollbar { height: 6px; }
.fav-showcase-carousel::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; }

.fav-showcase-carousel figure {
    flex: 0 0 auto;
    scroll-snap-align: start;
    width: min(560px, 84vw);
    margin: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    box-shadow: var(--shadow);
    overflow: hidden;
}
.fav-showcase-carousel img {
    display: block;
    width: 100%;
    height: auto;
    background: var(--surface-2);
}
.fav-showcase-carousel figcaption {
    padding: 10px 14px 12px;
    font-size: 12.5px;
    color: var(--text-muted);
    border-top: 1px solid var(--border);
}

.fav-showcase-nav {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    margin-top: 10px;
}
.fav-showcase-nav button {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 16px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}
.fav-showcase-nav button:hover { border-color: var(--border-strong); color: var(--accent); }

/* ===== Мобильная навигация по разделам свайпом (favorites-mobile-nav.js,
   см. чат 2026-08-16) — только ≤768px, скрипт сам решает, запускаться ли,
   на десктопе этих элементов в DOM просто нет. Первый экран — сводка
   (шапка + стоимость портфеля целиком + строки-превью разделов + карточки
   бумаг), дальше 6 экранов-разделов (купоны/риск/амортизация/дюрация/
   календарь/новости) - те же карточки/id, что и раньше, просто перенесены
   JS'ом внутрь. Высота .fav-mobile-stage подстраивается под активный экран
   в JS (у разделов разная длина контента), не фиксирована в CSS. */
.fav-mobile-stage {
  position: relative;
  overflow: hidden;
  transition: height 0.32s cubic-bezier(.22,.8,.3,1);
}
.fav-filmstrip {
  display: flex;
  align-items: flex-start;
  touch-action: pan-y;
  transition: transform 0.32s cubic-bezier(.22,.8,.3,1);
}
.fav-filmstrip.dragging { transition: none; }
.fav-screen { flex: 0 0 auto; min-width: 0; }

/* Класс на <html> ставит favorites-mobile-nav.js - отключает системный
   свайп-назад Safari, который иначе конкурировал с нашим горизонтальным
   свайпом между разделами (см. чат 2026-08-16). */
/* overflow-anchor:none - тот же гочка, что и в table.css у главной таблицы:
   .fav-mobile-stage меняет свою height в remeasure() (requestAnimationFrame)
   ПОСЛЕ того, как goto() уже явно проскроллил страницу к меню разделов -
   без этого браузер "скролл-анкорит" под изменившуюся высоту и тихо
   откатывает scrollTop обратно, из-за чего возврат в сводку всё равно
   открывался с самого верха вместо меню (см. чат 2026-08-16). */
html.fav-swipe-active { overscroll-behavior-x: none; overflow-anchor: none; }

.fav-topbar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 2px 0 12px;
}
.fav-back-btn {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: none;
  flex: 0 0 auto;
  background: var(--surface-2);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.fav-back-btn svg { width: 18px; height: 18px; }
.fav-topbar-title {
  flex: 1;
  min-width: 0;
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.fav-dots { display: flex; gap: 5px; flex: 0 0 auto; }
.fav-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--border-strong); display: block; }
.fav-dots i.on { background: var(--accent); width: 14px; border-radius: 3px; }

.fav-row-menu {
  margin: 0 0 16px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.fav-row-item {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
  -webkit-tap-highlight-color: transparent;
}
.fav-row-item:last-child { border-bottom: none; }
.fav-row-item:active { background: var(--surface-2); }
.fav-row-item[hidden] { display: none; }
.fav-row-icon {
  width: 32px;
  height: 32px;
  border-radius: 9px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent-soft);
  color: var(--accent);
}
.fav-row-icon svg { width: 17px; height: 17px; }
.fav-row-icon.warn { background: var(--poor-soft); color: var(--poor); }
.fav-row-body { flex: 1; min-width: 0; }
.fav-row-title { font-size: 13.5px; font-weight: 700; color: var(--text); }
.fav-row-sub {
  font-size: 11.5px;
  color: var(--text-faint);
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* is-alert, не .alert - .alert уже занят глобальным классом алерт-боксов
   (portfolio-builder.css: padding/display:flex/margin-bottom), который
   .favorites-page наследует через .portfolio-builder, и ломал однострочный
   nowrap/ellipsis тут (найдено на первой проверке - см. чат 2026-08-16). */
.fav-row-sub.is-alert { color: var(--poor); }
.fav-row-chev { color: var(--text-faint); flex: 0 0 auto; font-size: 15px; }

/* Внешний и внутренний отступы на телефоне — те же ~2мм, что уже сделаны
   на /board (см. чат 2026-08-23): 393px CSS-viewport / 71.5мм физической
   ширины iPhone 16 Pro ≈ 5,5px/мм → 11px = 2мм. <body> нигде в проекте не
   обнуляет дефолтный браузерный margin (8px) — контейнер получает не
   "чистые" 11px, а 3px (8+3=11≈2мм), как и .board-page-container. Карточки
   (.fav-chart-card/-compact, .bond-card) уже занимают всю ширину
   контейнера, поэтому их padding-left/right трогаем отдельно, до тех же
   ~11px. Блок — в конце файла намеренно: у каждого класса своя единственная
   декларация padding выше по файлу, но `.favorites-page` наследуется из
   portfolio-builder.css (загружается раньше в <head>, см. layout.ejs) — при
   равной специфичности более поздний по каскаду файл выигрывает без доп.
   уточнения селектора, но только если правило действительно идёт ПОСЛЕ
   (см. живой баг с .card на /board в тот же день: media-query само по себе
   не поднимает специфичность). */
@media (max-width: 640px) {
  .favorites-page {
    padding-left: 3px;
    padding-right: 3px;
  }

  .fav-chart-card {
    padding-left: 11px;
    padding-right: 11px;
  }

  .fav-chart-card-compact {
    padding-left: 11px;
    padding-right: 11px;
  }

  .bond-card {
    padding-left: 11px;
    padding-right: 11px;
  }
}
