/**
 * «Верная карта» — 2026 Ultra-Luxury Neo-FinTech Design System
 * Inspired by Apple Card, Revolut Ultra, Cash App & Linear
 */

:root {
  /* Цветовая палитра */
  --bg-deep: #07090E;
  --bg-surface: #0E121B;
  --bg-card: #141923;
  --bg-card-elevated: #1C2331;
  --bg-card-hover: #242D3F;

  /* Токены свечения и границ */
  --border-glass: rgba(255, 255, 255, 0.07);
  --border-glass-bright: rgba(255, 255, 255, 0.14);
  --border-focus: rgba(212, 246, 56, 0.5);

  /* Фирменный неоновый лайм (Volt Lime 2026) */
  --volt-lime: #D4F638;
  --volt-lime-glow: rgba(212, 246, 56, 0.3);
  /* Подложка под лаймовым текстом (чипы ставок, значки-акценты) — по образцу
     --color-danger-bg / --color-warning-bg. */
  --volt-lime-bg: rgba(212, 246, 56, 0.14);
  --volt-lime-dark: #A6C71E;
  --volt-text: #07090E;

  /* Вспомогательные акценты */
  --accent-cyan: #00F0FF;
  --accent-purple: #9D4EDD;
  --color-danger: #FF3B30;
  --color-danger-bg: rgba(255, 59, 48, 0.12);
  --color-success: #30D158;
  --color-warning: #FF9F0A;
  --color-warning-bg: rgba(255, 159, 10, 0.12);

  /* Текст */
  --text-main: #FFFFFF;
  --text-muted: #8E9BAE;
  --text-dim: #4B5565;

  /* Шрифты */
  --font-display: 'Outfit', -apple-system, sans-serif;
  --font-body: 'Plus Jakarta Sans', -apple-system, sans-serif;

  /* Радиусы (Apple Continuous Squircles) */
  --r-sm: 12px;
  --r-md: 20px;
  --r-lg: 28px;
  --r-xl: 36px;
  --r-pill: 9999px;

  /* Отступы безопасной зоны */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* Сброс */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  -webkit-tap-highlight-color: transparent;
}

html, body {
  width: 100%;
  height: 100%;
  background-color: var(--bg-deep);
  color: var(--text-main);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow: hidden;
  user-select: none;
}

/* Главный контейнер */
.app-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
  max-width: 440px;
  margin: 0 auto;
  position: relative;
  background-color: var(--bg-deep);
  background-image: 
    radial-gradient(circle at 50% -10%, rgba(212, 246, 56, 0.08) 0%, transparent 60%),
    radial-gradient(circle at 100% 60%, rgba(0, 240, 255, 0.04) 0%, transparent 50%),
    radial-gradient(circle at 0% 100%, rgba(157, 78, 221, 0.04) 0%, transparent 50%);
}

/* --------------------------------------------------------------------------
   ШАПКА (LUXURY FINTECH HEADER)
   -------------------------------------------------------------------------- */
.app-header {
  padding-top: calc(var(--safe-top) + 14px);
  padding-left: 20px;
  padding-right: 20px;
  padding-bottom: 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* 0.92, а не 0.7: там, где backdrop-filter не поддерживается (старый Android),
     сквозь шапку читался прокручиваемый контент */
  background: rgba(7, 9, 14, 0.92);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  z-index: 100;
}

/* Вход в кабинет читается как кнопка: контур, фон-поверхность и шеврон.
   Без них аватар с приветствием выглядел декорацией и кабинет не находили. */
.header-user-profile {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  min-height: 52px;
  padding: 4px 10px 4px 4px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  text-align: left;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.header-user-profile:active {
  background: var(--bg-card-elevated);
  border-color: var(--volt-lime);
}

.header-user-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.header-profile-chevron {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  color: var(--text-muted);
}

.user-avatar-badge {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: linear-gradient(135deg, #1C2331 0%, #141923 100%);
  border: 1.5px solid var(--border-glass-bright);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
}

.user-avatar-badge img {
  width: 100%;
  height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

/* Длинное имя из Telegram обязано обрезаться многоточием, а не распирать шапку */
.header-greeting {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 500;
  letter-spacing: 0.2px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.header-user-name {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--text-main);
  letter-spacing: -0.3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.header-icon-btn {
  width: 42px;
  height: 42px;
  border-radius: 50%;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-main);
  cursor: pointer;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  transition: all 0.2s ease;
}

.header-icon-btn:active {
  transform: scale(0.92);
  background: var(--bg-card-elevated);
}

/* Колокольчик — настоящая <button> (A2): сброс системных отступов кнопки, иначе
   иконка съезжает, а цель остаётся 42px только на бумаге. */
.header-bell-btn {
  position: relative;
  flex: 0 0 auto;
  padding: 0;
  font: inherit;
}

.header-bell-btn.bell-open {
  border-color: var(--volt-lime);
}

/* Точка непрочитанных — отдельный узел (Ф19): прежде кружок был нарисован в самом
   SVG и горел всегда. Видна, только пока есть непрочитанные (UI.renderBellState). */
.header-bell-dot {
  position: absolute;
  top: 8px;
  right: 9px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--volt-lime);
  border: 1.5px solid var(--bg-deep);
  pointer-events: none;
}

.header-bell-dot[hidden] {
  display: none;
}

/* Пока имени нет, «Личный кабинет» — единственная строка кнопки (A1) и читается
   как её название, а не как мелкая приписка над пустотой. */
.header-user-text.is-solo .header-greeting {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  color: var(--text-main);
  letter-spacing: -0.2px;
}

/* --------------------------------------------------------------------------
   ОСНОВНОЙ СКРОЛЛ
   -------------------------------------------------------------------------- */
.app-main-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 12px 20px calc(var(--safe-bottom) + 120px) 20px;
}

.app-screen {
  display: none;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.app-screen.screen-active {
  display: block;
  opacity: 1;
  transform: translateY(0);
}

/* --------------------------------------------------------------------------
   ГОЛОГРАФИЧЕСКАЯ HERO-КАРТА (2026 VOLT LIME LUXURY CARD)
   -------------------------------------------------------------------------- */
.section-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

.section-card-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-main);
  letter-spacing: -0.2px;
}

.btn-add-card-pill {
  position: relative;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: all 0.2s ease;
}

/* Расширенная зона нажатия, не ломающая визуальный ритм пилюли */
.btn-add-card-pill::after {
  content: '';
  position: absolute;
  inset: -6px -4px;
}

.btn-add-card-pill:active {
  color: var(--volt-lime);
  border-color: var(--volt-lime);
}

.hero-bank-card-container {
  width: 100%;
  margin-bottom: 24px;
  perspective: 1200px;
}

.hero-bank-card {
  width: 100%;
  height: 220px;
  border-radius: var(--r-lg);
  padding: 24px;
  color: var(--volt-text);
  background: 
    linear-gradient(135deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 50%),
    linear-gradient(135deg, #E2FF4A 0%, #D4F638 50%, #B2E819 100%);
  box-shadow: 
    0 20px 40px -10px rgba(212, 246, 56, 0.35),
    0 1px 0 1px rgba(255, 255, 255, 0.6) inset;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  position: relative;
  overflow: hidden;
}

/* Световой блик на карте */
.hero-bank-card::after {
  content: '';
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: radial-gradient(circle at 30% 20%, rgba(255, 255, 255, 0.4) 0%, transparent 60%);
  pointer-events: none;
}

.hero-card-top-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  z-index: 2;
}

.hero-card-brand-logo {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 900;
  letter-spacing: -0.5px;
  display: flex;
  align-items: center;
  gap: 6px;
}

.hero-card-contactless {
  opacity: 0.85;
}

.hero-card-number-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: 'Outfit', monospace;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 2px;
  opacity: 0.9;
  z-index: 2;
}

.hero-card-bottom-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  z-index: 2;
}

.hero-card-balance-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  opacity: 0.7;
  margin-bottom: 2px;
}

.hero-card-balance-val {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 900;
  letter-spacing: -0.8px;
  line-height: 1.1;
}

/* EMV смарт-чип: слева сверху, как на физической карте (в нижнем ряду
   он стоял вплотную к сумме и читался как случайная нашлёпка). */
.emv-sim-chip {
  width: 46px;
  height: 35px;
  border-radius: 6px;
  background: linear-gradient(135deg, #F6F3E6 0%, #DFD9BE 45%, #B7AE8A 100%);
  border: 1px solid rgba(0, 0, 0, 0.22);
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.65);
  position: relative;
  align-self: flex-start;
  flex: 0 0 auto;
  z-index: 2;
}

/* Внутренняя площадка контактов */
.emv-sim-chip::before {
  content: '';
  position: absolute;
  inset: 3px;
  border: 1px solid rgba(0, 0, 0, 0.2);
  border-radius: 3px;
}

/* Перемычки между контактами */
.emv-sim-chip::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    linear-gradient(to right,
      transparent 45%, rgba(0, 0, 0, 0.2) 45%,
      rgba(0, 0, 0, 0.2) 55%, transparent 55%),
    linear-gradient(to bottom,
      transparent 43%, rgba(0, 0, 0, 0.2) 43%,
      rgba(0, 0, 0, 0.2) 57%, transparent 57%);
}

/* --------------------------------------------------------------------------
   4 КНОПКИ БЫСТРЫХ ДЕЙСТВИЙ (SQUIRCLE ACTION GRID)
   -------------------------------------------------------------------------- */
.quick-actions-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: 1fr;
  align-items: stretch;
  gap: 12px;
  margin-bottom: 28px;
}

.quick-action-item {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 16px 8px;
  min-width: 0;
  min-height: 84px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--text-main);
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

.quick-action-item:active {
  transform: scale(0.92);
  background: var(--bg-card-elevated);
  border-color: var(--volt-lime);
}

.quick-action-icon {
  width: 24px;
  height: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-main);
}

.quick-action-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-muted);
  /* Подпись в одну строку: перенос делал первую плитку выше соседних */
  white-space: nowrap;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* --------------------------------------------------------------------------
   ТРАНЗАКЦИИ / ПРЕСЕТЫ ЧЕКОВ (TRANSACTION ROWS)
   -------------------------------------------------------------------------- */
.transactions-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

.transactions-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-main);
  letter-spacing: -0.2px;
}

.transactions-view-all {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  cursor: pointer;
}

.transactions-list-box {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}

.transaction-card-row {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  cursor: pointer;
  transition: all 0.2s ease;
  width: 100%;
  text-align: left;
  border-top: 1px solid var(--border-glass);
}

.transaction-card-row:active {
  background: var(--bg-card-elevated);
  transform: scale(0.98);
}

.transaction-left {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}

.transaction-avatar-icon {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass-bright);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 15px;
  color: var(--volt-lime);
}

/* Второстепенную подпись обрезаем многоточием, название мерчанта — нет:
   узнать «Вкусно и точка» важнее, чем выровнять строки по высоте */
.transaction-left > div:last-child {
  min-width: 0;
}

.transaction-merchant-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-main);
  letter-spacing: -0.2px;
  margin-bottom: 2px;
}

.transaction-category-sub {
  font-size: 12px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Сумма и «₽» одной строкой: на 320px «+2 450,00» переносило знак валюты вниз */
.transaction-amount-val {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 800;
  color: var(--text-main);
  text-align: right;
  letter-spacing: -0.3px;
  margin-bottom: 2px;
  white-space: nowrap;
}

.transaction-type-sub {
  font-size: 11px;
  font-weight: 600;
  color: var(--volt-lime);
  text-align: right;
  /* «СБП Привет 10%» переносилось на 2 строки и делало строку выше соседних */
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   ВИДОИСКАТЕЛЬ СКАНЕРА (CAMERA VIEWPORT)
   -------------------------------------------------------------------------- */
/* Высота карточки задаётся пропорцией, а не константой 240px: на 320x568
   фиксированная высота вместе с блоками выше уводила низ карточки под таб-бар. */
.scanner-viewport-card {
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  max-height: min(320px, 46vh);
  background: #000000;
  border-radius: var(--r-lg);
  overflow: hidden;
  position: relative;
  margin-bottom: 24px;
  border: 1px solid var(--border-glass-bright);
  box-shadow: 0 16px 36px rgba(0, 0, 0, 0.5);
}

.camera-feed {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Ни одного оверлея, сдвигающего рамку: рамка обязана стоять ровно в центре
   карточки. Там же браузер рисует заглушку пустого <video> (треугольник play),
   и любое смещение рамки читается как «видоискатель съехал вверх». */
.scanner-overlay-ui {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.3);
}

.scan-target-frame {
  width: min(50%, 176px);
  height: auto;
  aspect-ratio: 1 / 1;
  max-height: 74%;
  border: 2px solid var(--volt-lime);
  border-radius: 24px;
  box-shadow: 0 0 30px var(--volt-lime-glow), inset 0 0 20px var(--volt-lime-glow);
  position: relative;
}

/* Метка LIVE прижата к верхнему левому углу: при пропорции 4:3 её низ
   не доходит до верхней границы рамки даже на 320px. */
.scanner-live-chip {
  position: absolute;
  top: 8px;
  left: 10px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  color: var(--volt-lime);
  background: rgba(7, 9, 14, 0.72);
  border-radius: var(--r-pill);
  padding: 5px 9px;
  pointer-events: none;
}

/* Кнопки камеры живут в строке-заголовке над карточкой */
.scanner-head-row {
  gap: 12px;
}

.scanner-head-row .transactions-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.scanner-head-controls {
  display: flex;
  gap: 8px;
  flex: 0 0 auto;
}

.btn-camera-ctrl {
  background: var(--bg-surface);
  color: var(--text-main);
  border: 1px solid var(--border-glass);
  width: 38px;
  height: 38px;
  flex: 0 0 auto;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.btn-camera-ctrl:active {
  background: var(--bg-card-elevated);
  border-color: var(--volt-lime);
}

/* --------------------------------------------------------------------------
   СТАТИСТИКА (STATICS SCREEN MATCHING REFERENCE)
   -------------------------------------------------------------------------- */
.statics-top-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}

.statics-title {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  color: var(--text-main);
}

.statics-period-pills {
  display: flex;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  padding: 4px;
  border-radius: var(--r-pill);
  margin-bottom: 24px;
}

.statics-period-btn {
  flex: 1 1 0;
  min-width: 0;
  min-height: 44px;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 13px;
  font-weight: 600;
  padding: 10px 6px;
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: all 0.2s ease;
}

.statics-period-btn.pill-active {
  background: var(--volt-lime);
  color: var(--volt-text);
  box-shadow: 0 4px 16px var(--volt-lime-glow);
}

.stats-total-header {
  font-size: 13px;
  color: var(--text-muted);
  font-weight: 500;
  margin-bottom: 4px;
}

/* Значок роста переносится на свою строку, а сумма со знаком «₽» остаётся
   единой строкой: при семизначной выгоде «₽» отрывался от числа */
.stats-total-val-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 20px;
}

.stats-total-amount {
  font-family: var(--font-display);
  font-size: clamp(24px, 8.5vw, 36px);
  font-weight: 900;
  letter-spacing: -1px;
  line-height: 1.1;
  color: var(--text-main);
  white-space: nowrap;
}

/* Значок роста показывает измеренное изменение к прошлому такому же периоду.
   Сравнивать не с чем — значок скрыт (см. UI.renderStatsTab). */
.stats-growth-badge {
  display: flex;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  min-height: 32px;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  background: rgba(212, 246, 56, 0.12);
  color: var(--volt-lime);
  border: 1px solid rgba(212, 246, 56, 0.3);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  white-space: nowrap;
}

.stats-growth-badge[hidden] {
  display: none;
}

.stats-growth-badge.badge-down {
  background: rgba(255, 255, 255, 0.06);
  border-color: var(--border-glass);
  color: var(--text-muted);
}

.stats-growth-badge.badge-down .stats-growth-arrow {
  transform: scaleY(-1);
}

/* Столбиковый график */
.statics-chart-container {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-lg);
  padding: 20px;
  margin-bottom: 24px;
}

.chart-bars-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  height: 140px;
  gap: 8px;
  padding-top: 10px;
}

.chart-bar-col {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  height: 100%;
  justify-content: flex-end;
}

/* max-width: при одной записи в истории столбик один, и без ограничения
   он растягивался бы во всю карточку — это читалось бы как «данных много» */
.chart-bar-pillar {
  width: 100%;
  max-width: 64px;
  margin: 0 auto;
  background: var(--bg-card-elevated);
  border-radius: 8px;
  min-height: 8px;
  flex: 0 1 auto;
}

.chart-bar-pillar.pillar-active {
  background: var(--volt-lime);
  box-shadow: 0 0 20px var(--volt-lime-glow);
}

/* Пустая корзина внутри диапазона: заметно, что там ноль, а не малое значение */
.chart-bar-pillar.pillar-empty {
  background: rgba(255, 255, 255, 0.07);
  box-shadow: none;
}

.chart-bar-label {
  font-size: 11px;
  color: var(--text-muted);
  font-weight: 600;
  flex: 0 0 auto;
  white-space: nowrap;
}

.chart-bar-label.bar-label-active {
  color: var(--volt-lime);
  font-weight: 700;
}

.statics-period-pills[hidden] {
  display: none;
}

/* Пустое состояние статистики повторяет пустое состояние карусели карт */
.stats-empty-state {
  margin-bottom: 24px;
}

.hero-cards-empty[hidden] {
  display: none;
}

/* Двойные карточки аналитики.
   На 320px две колонки дают 102px под число: «25 022,50 ₽» переносилось, и знак «₽»
   уходил на отдельную строку. Одна колонка предсказуемее двух тесных. */
.dual-stats-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 24px;
}

@media (max-width: 380px) {
  .dual-stats-grid {
    grid-template-columns: 1fr;
  }
}

.metric-stat-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 18px;
  position: relative;
  overflow: hidden;
}

.metric-stat-card::before {
  content: '';
  position: absolute;
  left: 0;
  top: 18px;
  bottom: 18px;
  width: 3px;
  background: var(--volt-lime);
  border-radius: 2px;
}

.metric-stat-card.blue::before {
  background: var(--accent-cyan);
}

.metric-stat-icon {
  width: 28px;
  height: 28px;
  color: var(--text-main);
  margin-bottom: 12px;
}

.metric-stat-label {
  font-size: 12px;
  color: var(--text-muted);
  margin-bottom: 4px;
}

/* Сумма и «₽» — одной строкой при любых данных: у активного пользователя
   годовая выгода семизначная, и кегль ужимается вместо переноса */
.metric-stat-val {
  font-family: var(--font-display);
  font-size: clamp(16px, 4.6vw, 20px);
  font-weight: 800;
  color: var(--text-main);
  letter-spacing: -0.4px;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   НИЖНИЙ ТАБ-БАР (2026 FLOATING DOCK C FAB)
   -------------------------------------------------------------------------- */
.bottom-nav-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  /* Непрозрачный фон: сквозь 0.88 читался текст контента под подписями, при 0.97
     оставались призраки. Блюр здесь бесполезен (и на старом Android его нет),
     мягкость даёт градиент-затухание над баром — см. ::before ниже. */
  background: var(--bg-deep);
  border-top: 1px solid var(--border-glass);
  padding-top: 10px;
  padding-bottom: calc(var(--safe-bottom) + 10px);
  padding-left: 8px;
  padding-right: 8px;
  display: flex;
  align-items: center;
  justify-content: space-around;
  z-index: 200;
}

/* Мягкое затухание контента над баром */
.bottom-nav-bar::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 24px;
  background: linear-gradient(to top, var(--bg-deep), rgba(7, 9, 14, 0));
  pointer-events: none;
}

.nav-tab-btn {
  background: none;
  border: none;
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  /* 12px + --text-muted: было 10px/#4B5565 с контрастом 2.64:1 (норма AA — 4.5:1) */
  font-size: 12px;
  font-weight: 700;
  line-height: 1.2;
  cursor: pointer;
  transition: all 0.2s ease;
  min-width: 56px;
  min-height: 48px;
  padding: 2px 4px;
}

.nav-tab-btn.nav-active {
  color: var(--text-main);
}

.nav-tab-btn.nav-active .nav-svg-icon {
  color: var(--volt-lime);
}

.nav-svg-icon {
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Центральная парящая кнопка (+) FAB */
.nav-fab-btn {
  /* Кнопка выступает над баром на 30px и попадала под градиент-затухание
     .bottom-nav-bar::before — её верх притеняло, круг выглядел срезанным.
     Собственный слой поднимает её над градиентом. */
  position: relative;
  z-index: 1;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: var(--volt-lime);
  color: var(--volt-text);
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 10px 28px var(--volt-lime-glow);
  cursor: pointer;
  margin-top: -30px;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.nav-fab-btn:active {
  transform: scale(0.92);
  box-shadow: 0 4px 16px var(--volt-lime-glow);
}

/* --------------------------------------------------------------------------
   МОДАЛЬНАЯ ШТОРКА РЕШЕНИЯ (DARK GLASS SHEET)
   -------------------------------------------------------------------------- */
.decision-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.8);
  backdrop-filter: blur(24px);
  -webkit-backdrop-filter: blur(24px);
  z-index: 500;
  display: none;
  align-items: flex-end;
  justify-content: center;
}

.decision-modal-overlay.modal-active,
.decision-modal-overlay.modal-visible {
  display: flex;
}

.decision-sheet-content {
  width: 100%;
  max-width: 440px;
  background: #0E121B;
  border-top-left-radius: var(--r-xl);
  border-top-right-radius: var(--r-xl);
  border-top: 1px solid var(--border-glass-bright);
  padding: 14px 20px calc(var(--safe-bottom) + 20px) 20px;
  box-shadow: 0 -20px 50px rgba(0, 0, 0, 0.8);
  /* Лист не выше экрана и скроллится внутри себя: на 320px верх шторки
     (бейдж + сумма) уезжал за верхнюю границу экрана без возможности прокрутки. */
  max-height: calc(100vh - 24px);
  max-height: calc(100dvh - 24px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

.sheet-grabber {
  width: 40px;
  height: 4px;
  background: var(--text-dim);
  border-radius: var(--r-pill);
  margin: 0 auto 14px auto;
  flex: none;
}

/* --------------------------------------------------------------------------
   СОДЕРЖИМОЕ ШТОРКИ РЕШЕНИЯ
   -------------------------------------------------------------------------- */
.sheet-status-row {
  text-align: center;
  margin-bottom: 10px;
}

.sheet-status-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  text-align: left;
}

.sheet-status-badge.badge-ok {
  color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.12);
  border: 1px solid rgba(212, 246, 56, 0.28);
}

.sheet-status-badge.badge-warn {
  color: var(--color-warning);
  background: var(--color-warning-bg);
  border: 1px solid rgba(255, 159, 10, 0.28);
}

.sheet-amount-header {
  text-align: center;
  margin-bottom: 16px;
}

/* Сумма и «₽» — один блок: раньше число уезжало влево мелким кеглем,
   а знак валюты стоял отдельно крупным по центру. */
.sheet-amount-box {
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: 4px;
  max-width: 100%;
  position: relative;
  cursor: text;
}

.sheet-amount-val,
.sheet-amount-mirror {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -1px;
  font-variant-numeric: tabular-nums;
  color: var(--text-main);
}

.sheet-amount-val {
  min-width: 40px;
  max-width: 100%;
  padding: 0;
  border: none;
  outline: none;
  background: none;
  text-align: right;
  -webkit-appearance: none;
  appearance: none;
}

/* Невидимый двойник поля: по нему меряется ширина, чтобы «₽» стоял вплотную к числу */
.sheet-amount-mirror {
  position: absolute;
  left: 0;
  top: 0;
  white-space: pre;
  visibility: hidden;
  pointer-events: none;
}

.sheet-currency {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 800;
  color: var(--text-main);
}

.sheet-amount-hint {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-dim);
  margin-top: 2px;
}

.sheet-merchant-sub {
  font-size: 13px;
  color: var(--text-muted);
  margin-top: 4px;
}

.sheet-quick-amts {
  display: flex;
  gap: 6px;
  margin-bottom: 16px;
}

.btn-quick-amt {
  flex: 1 1 0;
  min-width: 0;
  min-height: 40px;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  color: var(--text-main);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  white-space: nowrap;
  border-radius: var(--r-sm);
  cursor: pointer;
}

.btn-quick-amt:active {
  border-color: var(--volt-lime);
  color: var(--volt-lime);
}

.hero-recommendation-box {
  background: var(--bg-card);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-md);
  padding: 16px;
  margin-bottom: 12px;
}

.hero-rec-top {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  margin-bottom: 6px;
}

.hero-rec-bank {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 800;
  color: var(--text-main);
  letter-spacing: -0.3px;
  min-width: 0;
}

.hero-rec-reward {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.5px;
  font-variant-numeric: tabular-nums;
  color: var(--volt-lime);
  white-space: nowrap;
}

.hero-rec-text {
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-muted);
  margin-bottom: 14px;
}

/* Объяснение про месячный потолок кешбэка. Стоит ПОСЛЕ главного ответа и его
   суммы — сперва «чем платить», потом «почему вернётся меньше», — но выделено
   рамкой предупреждения: молча уменьшенное число читается как ошибка расчёта.
   Переносы разрешены: текст длинный и на 320px занимает 3-4 строки. */
.hero-rec-limit {
  font-size: 12px;
  line-height: 1.45;
  color: var(--color-warning);
  background: var(--color-warning-bg);
  border: 1px solid rgba(255, 159, 10, 0.28);
  border-radius: var(--r-sm);
  padding: 8px 10px;
  margin-bottom: 14px;
}

/* Объяснение про род награды. В отличие от .hero-rec-limit рамки тревоги нет:
   начисление не урезано, просто человек сказал, что ему нужны рубли (или мили),
   и мы не приравниваем к ним бонусы по выдуманному курсу. */
.hero-rec-goal {
  font-size: 12px;
  line-height: 1.45;
  color: var(--text-muted);
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  padding: 8px 10px;
  margin-bottom: 14px;
}

.hero-recommendation-box .btn-open-bank {
  margin-bottom: 0;
}

.ranked-mini-list {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 4px 12px;
  margin-bottom: 12px;
}

/* Строка варианта: название способа и награда идут ДВУМЯ строками одной колонки,
   а не рядом. Награда лоялти («+125 Спасибо (~125 ₽)» = 149px, на крупных суммах
   «+622500 Спасибо (~622500 ₽)» = 204px) в 3-4 раза длиннее обычной «+125 ₽», и
   рядом с названием (200px) она не помещается НИ НА ОДНОЙ ширине телефона:
   200 + 10 + 149 = 359px против 254px внутри списка на 320px и 324px на 390px.
   Раньше награда выдавливала название, оно переносилось, и строка становилась
   вдвое-втрое выше соседей (40 / 55 / 111px) — ряд читался как рваный.
   Обе строки — одноуровневые, с фиксированной line-height в px, поэтому высота
   ряда одинакова при любых данных и в любом движке. */
.ranked-mini-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  gap: 2px;
  min-height: 52px;
  padding: 6px 0;
  font-size: 13px;
  /* Разделитель заведён всем строкам прозрачным: иначе первая строка ровно на
     ширину бордюра ниже остальных, и ряд снова расходится по высоте. */
  border-top: 1px solid transparent;
}

.ranked-mini-row + .ranked-mini-row {
  border-top-color: var(--border-glass);
}

.rank-title {
  color: var(--text-muted);
  min-width: 0;
  /* line-height в px, а не в множителе: высота строки перестаёт зависеть от
     метрик шрифта движка (в WebKit тот же ряд расходился на 33px). */
  line-height: 18px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ranked-mini-row.rank-first .rank-title {
  color: var(--text-main);
  font-weight: 700;
}

.rank-reward {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 14px;
  line-height: 20px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rank-reward.rank-positive {
  color: var(--volt-lime);
}

/* Вариант, срезанный месячным потолком. Метка дописана в ту же строку награды,
   а не третьей строкой: высота ряда здесь фиксирована намеренно (см. выше), и
   лишняя строка развалила бы ровный список. Влезает при любых данных — срезанная
   награда по определению не больше лимита карты, то есть максимум «+10 000 баллов
   (~10 000 ₽) · лимит»: замерено 235px против 262px доступных на 320px. */
.rank-reward.rank-capped {
  color: var(--color-warning);
}

/* Метка — inline-block фиксированной высоты, выровненный по ВЕРХУ строки, а не по
   базовой линии. Причина измеримая: у метки другой шрифт и кегль, при выравнивании
   по базовой линии её строчный бокс вылезал за 20px строки награды, и ряд со
   срезанной картой становился на 1px выше соседних (замерено 20 / 21px) — ровную
   высоту рядов этот список держит намеренно, см. комментарий к .ranked-mini-row. */
.rank-limit-tag {
  display: inline-block;
  height: 20px;
  line-height: 20px;
  vertical-align: top;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 11px;
  opacity: 0.85;
}

.ranked-mini-row.rank-first .rank-reward {
  font-size: 15px;
}

/* Блок «чего нет в кошельке»: карты рынка с повышенным кешбэком в этой категории.
   Живёт ПОД основным решением и намеренно приглушён — ни лайма, ни крупных цифр,
   ни кнопки во всю ширину. Главный ответ шторки — «чем платить сейчас», и блок
   предложения не должен с ним конкурировать ни цветом, ни весом. */
.market-upgrade-box {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 12px 14px;
  margin-bottom: 12px;
}

.market-upgrade-head {
  font-size: 12px;
  line-height: 16px;
  color: var(--text-muted);
  margin-bottom: 10px;
}

.market-upgrade-row + .market-upgrade-row {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border-glass);
}

.market-upgrade-card {
  font-size: 13px;
  line-height: 18px;
  font-weight: 700;
  color: var(--text-main);
  /* Название карты бывает длинным («Дебетовая карта «Космос»»): на 320px оно
     переносится, а не выдавливает соседей из строки. */
  overflow-wrap: anywhere;
}

.market-upgrade-gain {
  font-family: var(--font-display);
  font-size: 14px;
  line-height: 20px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text-main);
}

.market-upgrade-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 8px;
  font-size: 11px;
  line-height: 16px;
  /* не --text-dim: он даёт 2.6:1 к фону шторки при норме 4.5:1 для мелкого текста */
  color: var(--text-muted);
}

.market-upgrade-meta a {
  /* Приглушённый лайм: ссылка читается как ссылка, но слабее главной кнопки оплаты */
  color: var(--volt-lime-dark);
  text-decoration: none;
  font-weight: 600;
  white-space: nowrap;
}

/* ДЫРЫ В КОШЕЛЬКЕ на экране статистики. Тон намеренно спокойный: ни красного,
   ни восклицательных знаков — это разбор, а не претензия. Сумма выделена
   размером, но не цветом тревоги; «до» стоит прямо в строке, потому что
   месячный потолок и число повышенных слотов карты в ней не вычтены. */
.wallet-gaps-box {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px;
  margin-bottom: 24px;
}

.wallet-gaps-head {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  color: var(--text-main);
  margin-bottom: 4px;
}

.wallet-gaps-sub {
  font-size: 12px;
  line-height: 16px;
  color: var(--text-muted);
  margin-bottom: 12px;
}

.wallet-gaps-row + .wallet-gaps-row {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border-glass);
}

/* Название категории и оборот по ней: на 320px они переносятся друг под друга,
   а не сжимают число до многоточия. */
.wallet-gaps-cat {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 2px 8px;
  font-size: 13px;
  line-height: 18px;
  font-weight: 700;
  color: var(--text-main);
}

.wallet-gaps-spent {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}

.wallet-gaps-miss {
  font-family: var(--font-display);
  font-size: 14px;
  line-height: 20px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text-main);
  margin-top: 2px;
}

.wallet-gaps-fix {
  font-size: 11px;
  line-height: 16px;
  /* не --text-dim: он даёт 2.6:1 к фону при норме 4.5:1 для мелкого текста */
  color: var(--text-muted);
  margin-top: 2px;
}

.wallet-gaps-note {
  font-size: 11px;
  line-height: 15px;
  color: var(--text-muted);
  opacity: 0.85;
}

.wallet-gaps-row + .wallet-gaps-note {
  margin-top: 10px;
}

/* НАСТРОЙКА «ЧТО ВАМ НУЖНЕЕ» в кабинете. Пилюли те же, что у периода в
   статистике, но их четыре и подписи длиннее («Не важно»), поэтому ряд может
   переноситься: на 320px четыре кнопки в одну строку не влезают по-читаемому. */
.reward-goal-box {
  margin-bottom: 24px;
}

.reward-goal-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  padding: 4px;
  border-radius: var(--r-md);
}

.reward-goal-btn {
  flex: 1 1 64px;
  min-width: 0;
  min-height: 44px;
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  padding: 10px 6px;
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: all 0.2s ease;
  /* Подпись не переносится внутри пилюли: не влезла — уходит на следующий ряд
     целиком, иначе кнопка становится вдвое выше соседних. */
  white-space: nowrap;
}

.reward-goal-btn.pill-active {
  background: var(--volt-lime);
  color: var(--volt-text);
  box-shadow: 0 4px 16px var(--volt-lime-glow);
}

.reward-goal-hint {
  font-size: 11px;
  line-height: 15px;
  color: var(--text-muted);
  margin-top: 8px;
}

.market-upgrade-note {
  margin-top: 10px;
  font-size: 11px;
  line-height: 15px;
  color: var(--text-muted);
  opacity: 0.85;
}

.btn-open-bank {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  background: var(--volt-lime);
  color: var(--volt-text);
  text-decoration: none;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 16px;
  padding: 16px;
  border-radius: var(--r-md);
  border: none;
  cursor: pointer;
  box-shadow: 0 10px 24px var(--volt-lime-glow);
  margin-bottom: 12px;
}

.btn-sheet-secondary {
  width: 100%;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  color: var(--text-main);
  padding: 14px;
  border-radius: var(--r-md);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

/* Главная кнопка состояний, где выгоды нет (6.2 и «лимит выбран»): размер и место
   те же, что у .btn-open-bank, но без кислотной заливки и без свечения — она
   закрывает экран, а не зовёт платить. Кислотный цвет здесь читался бы как
   «вот выгодное действие», которого на этом чеке нет. */
.btn-sheet-close-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  color: var(--text-main);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 16px;
  padding: 16px;
  border-radius: var(--r-md);
  cursor: pointer;
  margin-bottom: 12px;
}

/* В состояниях «советовать нечего» эта кнопка — последняя в карточке решения, и
   её 12 px складывались с 16 px паддинга: под кнопкой пустела полоса в 28 px при
   нулевом отступе НАД ней. Отступ снизу отдаём паддингу карточки. */
.btn-sheet-close-cta:last-child {
  margin-bottom: 0;
}

.btn-sheet-close-cta:active {
  transform: scale(0.98);
}

/* Карточки банков во вкладке Карты */
.card-config-item {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 16px;
  margin-bottom: 12px;
}

.card-config-item.card-enabled {
  border-color: rgba(212, 246, 56, 0.4);
}

.card-item-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.card-header-left {
  display: flex;
  align-items: center;
  gap: 12px;
  /* иначе длинное описание карты сплющивает переключатель справа */
  min-width: 0;
}

.card-name-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-main);
}

.card-desc-text {
  font-size: 12px;
  color: var(--text-muted);
}

/* Свитч */
.toggle-switch {
  position: relative;
  display: inline-block;
  flex: 0 0 46px;
  width: 46px;
  height: 26px;
}

/* Зона нажатия 46×44 при сохранении визуального размера свитча */
.toggle-switch::after {
  content: '';
  position: absolute;
  inset: -9px 0;
}

.toggle-switch input {
  opacity: 0;
  width: 0;
  height: 0;
}

.toggle-slider {
  position: absolute;
  cursor: pointer;
  inset: 0;
  background-color: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  transition: .25s;
  border-radius: var(--r-pill);
}

.toggle-slider:before {
  position: absolute;
  content: "";
  height: 20px;
  width: 20px;
  left: 2px;
  bottom: 2px;
  background-color: white;
  transition: .25s;
  border-radius: 50%;
}

input:checked + .toggle-slider {
  background-color: var(--volt-lime);
}

input:checked + .toggle-slider:before {
  transform: translateX(20px);
  background-color: var(--volt-text);
}

.card-categories-section {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--border-glass);
}

.categories-label {
  font-size: 12px;
  color: var(--text-muted);
  font-weight: 600;
  display: block;
  margin-bottom: 8px;
}

/* Один чип на строку. Две равные колонки на 320px дают 124px под чип
   (155px на 390px), а самая длинная категория «Такси и каршеринг» занимает
   158-166px — подпись пришлось бы переносить или обрезать. При width:auto
   ряды складывались как 1-1-2-1-1-1-2-1 и выглядели случайными. */
.category-chips-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
}

/* Свой [hidden] обязателен: правило браузера display:none проигрывает
   объявленному здесь display:grid, и «скрытый» список остался бы на экране. */
.category-chips-grid[hidden] {
  display: none;
}

/* Нулевое состояние «Категории месяца не отмечены» (свод И10): одна строка с
   причиной вместо стены чипов, список раскрывает кнопка. */
.categories-empty {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
}

.categories-empty[hidden] {
  display: none;
}

.categories-empty-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-main);
}

.categories-empty-text {
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-muted);
}

.btn-mark-categories {
  margin-top: 4px;
  min-height: 38px;
  padding: 9px 16px;
  background: rgba(212, 246, 56, 0.12);
  border: 1px solid var(--volt-lime);
  color: var(--volt-lime);
  border-radius: var(--r-pill);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.btn-mark-categories:active {
  transform: scale(0.97);
}

.category-chip {
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  color: var(--text-muted);
  width: 100%;
  min-height: 38px;
  padding: 8px 14px;
  border-radius: var(--r-pill);
  font-size: 12px;
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.category-chip.chip-active {
  background: rgba(212, 246, 56, 0.15);
  border-color: var(--volt-lime);
  color: var(--volt-lime);
}

.chip-rate {
  font-size: 10px;
  opacity: 0.8;
  /* Ставки бывают «1,5%» и «0,5%» — четыре знака вместо двух. Перенос внутри
     числа читается как два числа, поэтому чип не переносим, а даём ему не
     сжиматься: рвать надо строку категории, а не процент. */
  white-space: nowrap;
  flex: none;
}

/* Своя ставка человека (её пишет импорт скриншота) от справочной отличается
   тем же способом, что и везде в продукте, — цветом акцента, а не значком. */
.chip-rate-own {
  opacity: 1;
  color: var(--volt-lime);
  font-weight: 700;
}

/* Неотмеченный чип, у которого есть своя ставка: расчёт применяет её и без
   отметки, поэтому чип не может выглядеть «выключенным» — пунктир акцента. */
.category-chip.chip-has-own {
  border-style: dashed;
  border-color: var(--volt-lime);
}

/* --------------------------------------------------------------------------
   СВОИ ПРОЦЕНТЫ ПО АКЦИЯМ (план own-rates-fitness, П2)
   Кнопка во всю ширину под чипами карты и шторка #card-rates-modal.
   -------------------------------------------------------------------------- */
.btn-own-rates {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 44px;
  margin-top: 10px;
  padding: 10px 16px;
  background: var(--bg-card-elevated);
  border: 1px dashed var(--border-glass-bright);
  border-radius: var(--r-pill);
  color: var(--text-main);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
}

.btn-own-rates.has-own {
  border-style: solid;
  border-color: var(--volt-lime);
  color: var(--volt-lime);
  background: var(--volt-lime-bg);
}

.btn-own-rates:active {
  transform: scale(0.98);
}

.card-rates-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 4px 0 18px;
}

/* Строка: имя | поле с «%» | «×» сброса; сообщение (ошибка/предупреждение) —
   под строкой во всю ширину. Ячейка сброса есть ВСЕГДА, даже пустая: иначе поля
   строк со своей ставкой и без неё стояли бы со сдвигом. Сброс — в той же
   строке, а не своим рядом: рядом 44px высоты делал строки со своей ставкой
   в полтора раза выше соседних (замер 320: 110 против 76px). */
.card-rate-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 44px;
  grid-template-areas:
    "name field reset"
    "msg msg msg";
  align-items: center;
  column-gap: 6px;
  padding: 6px 4px 6px 14px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
}

.card-rate-name {
  grid-area: name;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  cursor: pointer;
}

.card-rate-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-main);
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.card-rate-hint {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.3;
}

.card-rate-field {
  grid-area: field;
  display: flex;
  align-items: center;
  gap: 4px;
}

/* 16px — меньше iOS увеличивает страницу при фокусе. */
.card-rate-input {
  width: 72px;
  min-height: 44px;
  padding: 8px 10px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-sm);
  color: var(--text-main);
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 700;
  text-align: right;
}

.card-rate-input::placeholder {
  color: var(--text-dim);
  font-weight: 600;
}

.card-rate-input:focus {
  outline: none;
  border-color: var(--border-focus);
}

.card-rate-input[aria-invalid="true"] {
  border-color: var(--color-danger);
}

.card-rate-suffix {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-muted);
}

.btn-card-rate-reset {
  grid-area: reset;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  background: transparent;
  border: none;
  border-radius: var(--r-sm);
  color: var(--text-muted);
  cursor: pointer;
}

.btn-card-rate-reset:active {
  background: var(--bg-card-hover);
  color: var(--text-main);
}

/* Свой [hidden]: display у кнопки не объявлен, но правило браузера держим явно,
   как у .category-chips-grid — чтобы будущий display не вернул её на экран. */
.btn-card-rate-reset[hidden],
.card-rate-msg[hidden] {
  display: none;
}

.card-rate-msg {
  grid-area: msg;
  margin: 4px 10px 4px 0;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--text-muted);
}

.card-rate-msg.is-error {
  color: var(--color-danger);
}

.card-rate-msg.is-warn {
  color: var(--color-warning);
}

#card-rates-modal-content .btn-sheet-primary {
  width: 100%;
  margin-bottom: 8px;
}

/* Ручной ввод ссылки */
.manual-input-box {
  background: var(--bg-surface);
  border-radius: var(--r-md);
  border: 1px solid var(--border-glass);
  padding: 6px 6px 6px 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 20px;
}

.input-text-field {
  flex: 1 1 0;
  /* width:100% + min-width:0 обязательны: иначе интринсик-ширина input (≈20 знаков,
     а у поля суммы кегль 24px) распирает контейнер — на 320px вылезало на 4px */
  width: 100%;
  min-width: 0;
  min-height: 44px;
  border: none;
  outline: none;
  background: none;
  /* 16px — иначе iOS зумит экран при фокусе (зум страницы больше не запрещён) */
  font-size: 16px;
  color: var(--text-main);
  font-family: inherit;
  text-overflow: ellipsis;
}

/* Поля цели-мечты стоят ГОЛЫМИ, а не внутри .manual-input-box, которая и рисует рамку
   с фоном. Без этого правила название и сумма выглядят обычным текстом: человек не
   понимает, что сюда можно нажать и печатать. Рамка та же, что у соседнего
   <select> карт лояльности (index.html), чтобы поля ввода читались одинаково. */
#dream-fields .input-text-field {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: 10px;
  padding: 0 12px;
}

#dream-fields .input-text-field:focus {
  border-color: var(--border-focus);
}

#dream-fields .input-text-field::placeholder {
  color: var(--text-dim);
}

.btn-submit-action {
  flex: 0 0 auto;
  background: var(--volt-lime);
  color: var(--volt-text);
  border: none;
  min-height: 44px;
  padding: 10px 16px;
  border-radius: var(--r-sm);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}

/* Тост.
   Ширину контейнеру задают ОБА края, а не `left:50%` + `transform`. У `position:fixed`
   без правого края ширина считается shrink-to-fit, а доступное место — это остаток
   вправо от левого края, то есть ровно ПОЛОВИНА экрана. Замерено в браузере: контейнер
   получал 160px на 320 и 195px на 390, длинный тост разваливался на 4 строки при
   свободных 320px. Центрируем сам тост внутри колонки, а не контейнер — сдвигом. */
.toast-container {
  position: fixed;
  top: calc(var(--safe-top) + 20px);
  left: 12px;
  right: 12px;
  z-index: 1000;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  /* Тостов бывает два подряд («Запрос данных в реестре НСПК…» → «ВкусВилл: 1 250 ₽»,
     js/app.js:775 и :819, жизнь тоста 2400 мс). Без зазора они слипались в одну плашку. */
  align-items: center;
  gap: 8px;
}

.toast {
  /* Значок и подпись одной строкой — своим правилом, а не общим списком `inline-flex`:
     инлайновая ширина внутри shrink-to-fit контейнера ломала перенос текста. */
  display: flex;
  align-items: center;
  gap: 8px;
  max-width: 100%;
  background: var(--bg-card-elevated);
  color: var(--text-main);
  border: 1px solid var(--volt-lime);
  padding: 10px 20px;
  border-radius: var(--r-pill);
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  text-align: center;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}

/* --------------------------------------------------------------------------
   ИНТЕРАКТИВНЫЙ ОНБОРДИНГ (APPLE WALLET DARK ONBOARDING)
   -------------------------------------------------------------------------- */
.onboarding-overlay-container {
  position: fixed;
  inset: 0;
  background: rgba(7, 9, 14, 0.88);
  backdrop-filter: blur(28px);
  -webkit-backdrop-filter: blur(28px);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

/* Экран банков — девять целей для пальца, и на 320x568 он в высоту карточки
   не влезает никогда. Прокручивается при этом ТОЛЬКО область слайда: точки и
   кнопки прибиты к низу карточки, поэтому «Далее» видна всегда и долистывать
   до неё не нужно. Обрезки нет — есть прокрутка ровно того, что длинное. */
.onboarding-card {
  width: 100%;
  max-width: 380px;
  max-height: calc(100vh - 40px);
  max-height: calc(100dvh - 40px);
  overflow: hidden;
  background: #0E121B;
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-xl);
  padding: 28px 22px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.8);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

#onboarding-slides-container {
  width: 100%;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* Содержимое слайда центрируется само: раньше это делала «сжатая по контенту»
   ширина контейнера, а с width:100% значок камеры уехал бы к левому краю. */
.onboarding-slide-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: 100%;
}

.onboarding-card .onboarding-dots-row,
.onboarding-card .onboarding-btn-row {
  flex: 0 0 auto;
}

/* Правки под узкий экран собраны ОДНИМ блоком в конце раздела (см. ниже,
   после .onboarding-demo-*): медиазапрос не поднимает специфичность, и
   объявления, стоящие в файле раньше базовых правил, молча проигрывают им. */

.onboarding-hero-icon {
  width: 72px;
  height: 72px;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 20px;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass-bright);
}

.onboarding-title {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.5px;
  color: var(--text-main);
  margin-bottom: 10px;
  line-height: 1.25;
}

.onboarding-text {
  font-size: 14px;
  color: var(--text-muted);
  line-height: 1.45;
  margin-bottom: 18px;
}

/* Плашка потери. Красное — только САМА ЦИФРА (ТЗ 3): красный фон и красный
   текст целиком превращали рассказ в предупреждение об ошибке, а мы не пугаем,
   а сообщаем то, чего человек не знал. */
.onboarding-loss-badge {
  background: var(--bg-surface);
  color: var(--text-muted);
  border: 1px solid var(--border-glass-bright);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.35;
  padding: 9px 16px;
  border-radius: var(--r-pill);
  margin-bottom: 14px;
}

.onboarding-loss-badge strong {
  color: var(--color-danger);
  font-weight: 800;
  white-space: nowrap;
}

.onboarding-tip-card {
  background: rgba(0, 240, 255, 0.12);
  color: var(--accent-cyan);
  border: 1px solid rgba(0, 240, 255, 0.25);
  font-size: 13px;
  font-weight: 700;
  padding: 8px 16px;
  border-radius: var(--r-pill);
  margin-bottom: 14px;
}

.onboarding-gain-badge {
  background: rgba(212, 246, 56, 0.12);
  color: var(--volt-lime);
  border: 1px solid rgba(212, 246, 56, 0.25);
  font-size: 13px;
  font-weight: 700;
  padding: 8px 16px;
  border-radius: var(--r-pill);
  margin-bottom: 14px;
}

/* Строка под плашкой потери и подпись под демо-списком: 15px, а не мелкий
   служебный шрифт, — это продолжение мысли экрана, а не сноска. */
.onboarding-subline {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-main);
  line-height: 1.4;
  margin-bottom: 4px;
}

.onboarding-title-sm {
  font-size: 19px;
}

.onboarding-text-tight {
  margin-bottom: 12px;
}

/* Подсказка «выберите банк». Место под неё занято всегда (visibility, а не
   display): иначе появление строки дёргало бы всю сетку чипов вверх-вниз. */
.onboarding-hint {
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--color-warning);
  min-height: 17px;
  margin-bottom: 8px;
}

.onboarding-hint.hint-shake {
  animation: onboarding-hint-shake 0.32s ease;
}

@keyframes onboarding-hint-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-4px); }
  75% { transform: translateX(4px); }
}

.onboarding-footnote {
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-dim);
}

.onboarding-banks-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  width: 100%;
  margin-bottom: 10px;
}

/* Чип — кнопка: цель для пальца не ниже 44px, подпись переносится, а не
   выпирает за границу («Газпромбанк» шире половины карточки на 320px). */
.bank-chip {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  width: 100%;
  text-align: left;
  background: var(--bg-surface);
  border: 1.5px solid var(--border-glass);
  padding: 8px 10px;
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-main);
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.bank-chip-label {
  min-width: 0;
  line-height: 1.2;
  overflow-wrap: anywhere;
}

.bank-dot-logo {
  display: inline-flex;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
}

.bank-chip-monogram {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 7px;
  background: var(--bg-card-elevated);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 800;
}

/* «+ Другой банк» — не девятый банк, а другое действие: поэтому он занимает
   ряд целиком. Полуряд с пустой клеткой рядом читался бы как забытый чип. */
.bank-chip-more {
  grid-column: 1 / -1;
  justify-content: center;
  min-height: 38px;
  color: var(--text-muted);
  border-style: dashed;
}

.bank-chip.chip-active {
  background: var(--volt-lime-bg);
  border-color: var(--volt-lime);
  box-shadow: 0 0 16px var(--volt-lime-glow);
}

/* --------------------------------------------------------------------------
   ОНБОРДИНГ: ДЕМО-ЭКРАН РЕЗУЛЬТАТА
   Числа считает тот же движок, что и настоящую шторку (js/engine/onboarding.js
   → CashbackCalculator), поэтому здесь только раскладка.
   -------------------------------------------------------------------------- */
.onboarding-demo-badge {
  display: inline-block;
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--bg-card-elevated);
  border-radius: var(--r-pill);
  padding: 5px 12px;
  margin-bottom: 12px;
}

.onboarding-demo-merchant {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-muted);
  margin-bottom: 12px;
}

.onboarding-demo-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  margin-bottom: 14px;
}

/* Одна строка — один способ оплаты. Две колонки, а не сетка auto-fit: на 320px
   вторая колонка с крупным числом уже не помещается, и ряд ломается. */
.onboarding-demo-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  text-align: left;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  padding: 11px 12px;
}

.onboarding-demo-row.demo-row-best {
  background: var(--volt-lime-bg);
  border-color: var(--volt-lime);
}

.onboarding-demo-way {
  font-size: 12.5px;
  line-height: 1.3;
  color: var(--text-muted);
  min-width: 0;
}

.demo-row-best .onboarding-demo-way {
  color: var(--text-main);
  font-weight: 700;
}

.onboarding-demo-sum {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  color: var(--text-dim);
  white-space: nowrap;
}

.demo-row-best .onboarding-demo-sum {
  color: var(--volt-lime);
}

/* --------------------------------------------------------------------------
   ОНБОРДИНГ НА УЗКОМ ЭКРАНЕ (320px)
   Блок стоит ПОСЛЕ всех базовых правил раздела: медиазапрос специфичность не
   повышает, и те же селекторы, записанные выше, проигрывают базовым по порядку.
   Проверено замером: при блоке выше по файлу у чипа оставались font-size:13px
   и padding:8px 10px, то есть правка не доезжала вовсе.
   -------------------------------------------------------------------------- */
@media (max-width: 359px) {
  .onboarding-overlay-container { padding: 12px; }
  .onboarding-card { padding: 20px 14px; max-height: calc(100dvh - 24px); }
  .onboarding-title { font-size: 20px; }
  /* Последние 9px, из-за которых список банков уходил под прокрутку. */
  .onboarding-banks-grid { gap: 6px; margin-bottom: 8px; }
  .onboarding-hint { min-height: 16px; margin-bottom: 6px; }
  .onboarding-text-tight { margin-bottom: 8px; }
  .onboarding-footnote { line-height: 1.3; }
  .onboarding-dots-row { margin-top: 12px; margin-bottom: 16px; }

  /* Подписи «Райффайзен» (нужно 82px) и «Газпромбанк» (86px) рвались посреди
     слова: на подпись оставалось 79px. Значок ужимается до 20px, отступы — до
     8px, кегль — до 12px, и слово встаёт целиком. */
  .bank-chip { min-height: 40px; font-size: 12px; padding: 8px; gap: 6px; }
  .bank-chip .bank-dot-logo { width: 20px; height: 20px; }
  .bank-chip .bank-dot-logo svg { width: 100%; height: 100%; }

  /* Две колонки в строке демо уже тесные: у бонусной карты сумма приходит
     строкой «8 Спасибо (~7,50 ₽)» и вместе с nowrap выдавливает название
     способа оплаты. На узком экране строка становится одноколоночной. */
  .onboarding-demo-row {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
}

.onboarding-dots-row {
  display: flex;
  gap: 6px;
  margin-top: 14px;
  margin-bottom: 20px;
}

.onboarding-dot {
  width: 6px;
  height: 6px;
  border-radius: 3px;
  background: var(--bg-card-elevated);
  transition: all 0.3s ease;
}

.onboarding-dot.dot-active {
  width: 22px;
  background: var(--volt-lime);
  box-shadow: 0 0 8px var(--volt-lime-glow);
}

.btn-onboarding-main {
  width: 100%;
  background: var(--volt-lime);
  color: var(--volt-text);
  border: none;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 16px;
  padding: 16px;
  border-radius: var(--r-md);
  cursor: pointer;
  box-shadow: 0 8px 24px var(--volt-lime-glow);
}

/* Заблокированная «Далее»: видно, что кнопка есть и что она пока не работает.
   display:none был бы хуже — исчезнувшая кнопка читается как поломка экрана. */
.btn-onboarding-main.btn-onboarding-locked {
  background: var(--bg-card-elevated);
  color: var(--text-dim);
  box-shadow: none;
  cursor: default;
}

.btn-onboarding-text {
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
  color: var(--text-muted) !important;
  font-size: 13px;
  font-weight: 600;
  padding: 10px;
  cursor: pointer;
  display: block;
  width: 100%;
  margin-top: 6px;
  min-height: 36px;
}

.btn-onboarding-text[hidden] {
  display: none !important;
}

/* --------------------------------------------------------------------------
   ЭКРАН ЗАПРОСА КАМЕРЫ (перед системным диалогом)
   -------------------------------------------------------------------------- */
#camera-permission-overlay[hidden] {
  display: none !important;
}

.onboarding-hero-icon.bg-lime-soft {
  background: var(--volt-lime-bg);
  border-color: var(--volt-lime);
}

/* Отказ камеры прямо в видоискателе: чёрный прямоугольник без слов обещал
   сканер, которого нет. */
.camera-blocked-layer {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 16px;
  text-align: center;
  background: rgba(7, 9, 14, 0.92);
}

.camera-blocked-layer[hidden] {
  display: none;
}

.camera-blocked-title {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 800;
  color: var(--text-main);
}

.camera-blocked-text {
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--text-muted);
  max-width: 240px;
}

.btn-camera-retry {
  margin-top: 4px;
  min-height: 36px;
  padding: 8px 16px;
  border: none;
  border-radius: var(--r-pill);
  background: var(--volt-lime);
  color: var(--volt-text);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   ЭКРАН «КАК ЭТО РАБОТАЕТ» (ТЗ 1.4) И КАРТОЧКА-ВХОД НА ГЛАВНОЙ
   -------------------------------------------------------------------------- */
.howto-overlay-container {
  position: fixed;
  inset: 0;
  z-index: 9998;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(7, 9, 14, 0.9);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
}

.howto-overlay-container[hidden] {
  display: none !important;
}

.howto-sheet {
  position: relative;
  width: 100%;
  max-width: 400px;
  max-height: calc(100vh - 32px);
  max-height: calc(100dvh - 32px);
  display: flex;
  flex-direction: column;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-xl);
  padding: 22px 18px 18px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.8);
}

/* Текст справки длинный по существу, поэтому прокрутка живёт ВНУТРИ листа:
   кнопка «Начать» остаётся на виду и до неё не надо долистывать. */
.howto-scroll {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  margin-bottom: 14px;
  padding-right: 2px;
}

/* Подсказка «текст продолжается»: на 320px под сгибом остаётся 642px, и без
   растворяющегося края последняя строка упирается в кнопку так, будто это конец.
   Полоса не перехватывает нажатия и на коротком тексте просто не видна. */
.howto-sheet::after {
  content: '';
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 84px;
  height: 26px;
  pointer-events: none;
  background: linear-gradient(to top, var(--bg-surface), rgba(14, 18, 27, 0));
}

.howto-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: var(--bg-card-elevated);
  color: var(--text-muted);
  cursor: pointer;
}

.howto-title {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 800;
  line-height: 1.22;
  letter-spacing: -0.5px;
  color: var(--text-main);
  margin: 6px 34px 12px 0;
}

.howto-text {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-muted);
  margin-bottom: 10px;
}

.howto-figure {
  font-size: 13.5px;
  line-height: 1.45;
  font-weight: 700;
  color: var(--text-main);
  background: var(--volt-lime-bg);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-sm);
  padding: 12px 14px;
  margin: 4px 0 8px;
}

/* Строка под блоком с цифрой. Не красная: это не потеря и не ошибка, а вторая
   половина мысли — красный на целой фразе читался бы как предупреждение. */
.howto-subline {
  font-size: 13.5px;
  line-height: 1.4;
  font-weight: 700;
  color: var(--text-main);
  margin-bottom: 14px;
}

.howto-steps-title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 800;
  color: var(--text-main);
  margin-bottom: 10px;
}

.howto-steps {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 14px;
}

.howto-steps li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text-muted);
}

.howto-step-num {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--volt-lime);
  color: var(--volt-text);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 800;
}

/* Блок «Что уходит с телефона»: те же отступы, что у шагов, но маркер —
   точка, а не номер: это перечень фактов, а не последовательность действий. */
.howto-facts {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.howto-facts li {
  position: relative;
  padding-left: 16px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-muted);
}

.howto-facts li::before {
  content: '';
  position: absolute;
  left: 2px;
  top: 8px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--volt-lime);
}

.howto-footnote {
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-dim);
}

/* Карточка-вход на главной. Три шага в одну строку каждый — это не справка,
   а напоминание; за подробностями ведёт «Подробнее». */
.howto-card {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px;
  margin-bottom: 24px;
}

.howto-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 10px;
}

.howto-card-title {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 800;
  color: var(--text-main);
  min-width: 0;
}

.howto-card-more {
  flex: 0 0 auto;
  min-height: 32px;
  padding: 6px 12px;
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--volt-lime);
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 700;
  cursor: pointer;
}

.howto-card-steps {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.howto-card-steps li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13px;
  line-height: 1.35;
  color: var(--text-muted);
}


/* --------------------------------------------------------------------------
   ИСТОРИЯ РАСЧЁТОВ: ПУСТОЕ СОСТОЯНИЕ
   -------------------------------------------------------------------------- */
/* Экран растягивается на всю доступную высоту скролл-контейнера, список
   забирает остаток — иначе пустому блоку не в чем центрироваться. */
#screen-history.screen-active {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

.history-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1 1 auto;
}

/* Единственный дочерний блок БЕЗ класса — это заглушка из renderHistoryTab
   (у строк истории класс .history-row-item, они под это правило не попадают). */
.history-list > div:only-child:not([class]) {
  margin: auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
}

/* Строка истории: у .history-row-item и её потомков не было НИ ОДНОГО правила —
   реальная история рисовалась голым столбиком текста. Раскладка повторяет
   «Последние покупки», чтобы экраны читались одинаково. */
.history-row-item {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.history-row-item > div:first-child {
  min-width: 0;
}

.history-row-item > div:last-child {
  flex: 0 0 auto;
  text-align: right;
}

/* Длинное имя мерчанта переносится максимум на две строки, а не растягивает ряд */
.history-m-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--text-main);
  letter-spacing: -0.2px;
  margin-bottom: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.history-m-sub {
  font-size: 12px;
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Сумма не рвётся по «₽»: реальные чеки бывают вида «12 450 000 ₽» */
.history-reward-val {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 800;
  color: var(--volt-lime);
  letter-spacing: -0.3px;
  margin-bottom: 2px;
  white-space: nowrap;
}

/* Сумма не измерена (И21): прочерк не должен выглядеть начислением, поэтому
   кислотный цвет снимается — цветом в этом столбце помечен только доход. */
.history-reward-unknown {
  color: var(--text-muted);
}

.history-sum-val {
  font-size: 12px;
  color: var(--text-muted);
  white-space: nowrap;
}

.history-list > div:only-child:not([class])::before {
  content: '';
  width: 72px;
  height: 72px;
  border-radius: 50%;
  border: 1px solid var(--border-glass);
  background-color: var(--bg-surface);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234B5565' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 12a9 9 0 1 0 3-6.7L3 8'/%3E%3Cpath d='M3 3v5h5'/%3E%3Cpath d='M12 7.5V12l3 2'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 32px 32px;
}

/* --------------------------------------------------------------------------
   УЗКИЕ ЭКРАНЫ (320–360px): iPhone SE 1-го поколения и старые Android
   -------------------------------------------------------------------------- */
@media (max-width: 360px) {
  .app-main-content {
    padding-left: 16px;
    padding-right: 16px;
  }

  .app-header {
    padding-left: 16px;
    padding-right: 16px;
  }

  /* Плитка должна вмещать «Скан QR» в одну строку, иначе ряд становится рваным */
  .quick-actions-grid {
    gap: 8px;
  }

  .quick-action-item {
    padding: 14px 4px;
    gap: 8px;
  }

  .hero-bank-card {
    padding: 20px;
    height: 200px;
  }

  .hero-card-balance-val {
    font-size: 24px;
  }

  .decision-sheet-content {
    padding-left: 16px;
    padding-right: 16px;
  }

  .sheet-amount-val,
  .sheet-amount-mirror {
    font-size: 30px;
  }

  .sheet-currency {
    font-size: 22px;
  }

}

/* Подсказка под иконкой пустой истории: объясняет, откуда там возьмутся записи */
.history-empty-hint {
  margin-top: 8px;
  font-size: 13px;
  line-height: 1.4;
  /* не --text-tertiary: он даёт 3.4:1 к фону при норме 4.5:1 для мелкого текста */
  color: var(--text-muted);
  max-width: 260px;
  margin-left: auto;
  margin-right: auto;
}

/* --------------------------------------------------------------------------
   КАРУСЕЛЬ ВЫБРАННЫХ КАРТ (главный экран)
   Карточки — это карты, отмеченные пользователем во вкладке «Карты».
   Слайд листается внутри своего скролл-контейнера и не тащит вбок страницу.
   -------------------------------------------------------------------------- */
.hero-cards-area {
  margin-bottom: 14px;
}

.hero-cards-carousel {
  display: flex;
  align-items: stretch;
  gap: 12px;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* место под тень карты: внутри overflow:auto она обрезается по краю */
  padding-bottom: 14px;
  margin-bottom: -6px;
}

.hero-cards-carousel::-webkit-scrollbar {
  display: none;
}

/* Слайд занимает 86% ширины: край следующей карты виден и подсказывает свайп */
.hero-card-slide {
  flex: 0 0 86%;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  width: auto;
  height: auto;
  aspect-ratio: 1.62 / 1;
  min-height: 168px;
  max-height: 212px;
  padding: 18px;
  gap: 6px;
  box-shadow:
    0 12px 26px -10px rgba(212, 246, 56, 0.4),
    0 1px 0 1px rgba(255, 255, 255, 0.55) inset;
}

/* Хвостовой отступ: без него последняя карта не доезжает до позиции снапа */
.hero-slide-spacer {
  flex: 0 0 calc(14% - 12px);
  align-self: stretch;
}

.hero-card-slide .hero-card-top-row {
  gap: 8px;
}

.hero-card-slide .hero-card-brand-logo {
  min-width: 0;
  overflow: hidden;
}

.hero-card-logo-mark {
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero-card-logo-mark svg {
  display: block;
}

.hero-card-bank-name {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.3px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hero-card-slide .emv-sim-chip {
  width: 38px;
  height: 29px;
}

.hero-card-name-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
  z-index: 2;
}

.hero-card-name {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 900;
  letter-spacing: -0.5px;
  line-height: 1.15;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hero-card-pay {
  font-size: 11px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  opacity: 0.65;
  white-space: nowrap;
  flex: 0 0 auto;
}

.hero-card-rates-row {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  z-index: 2;
}

.hero-card-rate {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  background: rgba(7, 9, 14, 0.10);
  border: 1px solid rgba(7, 9, 14, 0.16);
  border-radius: var(--r-pill);
  padding: 5px 10px;
  font-size: 11px;
  font-weight: 700;
  white-space: nowrap;
}

.hero-card-rate b {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 900;
  letter-spacing: -0.2px;
}

/* Индикатор позиции: не кнопка, а метка — поэтому размер меньше пальца допустим */
.hero-carousel-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 8px;
  margin-top: 12px;
}

.hero-carousel-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(142, 155, 174, 0.55);
  transition: width 0.2s ease, background 0.2s ease;
}

.hero-carousel-dot.dot-active {
  width: 20px;
  border-radius: var(--r-pill);
  background: var(--volt-lime);
}

/* Пустое состояние: карт не выбрано — карусели нет, есть путь во вкладку «Карты» */
.hero-cards-carousel.carousel-empty {
  display: block;
  overflow: visible;
  scroll-snap-type: none;
  padding-bottom: 0;
  margin-bottom: 0;
}

.hero-cards-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
  background: var(--bg-surface);
  border: 1px dashed rgba(255, 255, 255, 0.18);
  border-radius: var(--r-lg);
  padding: 24px 18px;
}

.hero-empty-icon {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  color: var(--volt-lime);
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero-empty-title {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 800;
  color: var(--text-main);
}

.hero-empty-text {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-muted);
  max-width: 260px;
}

.btn-hero-empty-cta {
  width: 100%;
  max-width: 280px;
  min-height: 48px;
  background: var(--volt-lime);
  color: var(--volt-text);
  border: none;
  border-radius: var(--r-md);
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 800;
  cursor: pointer;
  box-shadow: 0 10px 24px var(--volt-lime-glow);
}

.btn-hero-empty-cta:active {
  transform: scale(0.97);
}

/* Накоплено выгоды: подпись и сумма в столбик — крупное число ни при каких
   данных не сталкивается с подписью (реальные суммы бывают семизначными) */
.home-saved-strip {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px 16px;
  margin-bottom: 24px;
}

.home-saved-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--text-muted);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.home-saved-val {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 900;
  letter-spacing: -0.6px;
  line-height: 1.15;
  color: var(--volt-lime);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   ЛИЧНЫЙ КАБИНЕТ (экран, открывается по аватару в шапке)
   -------------------------------------------------------------------------- */
.header-user-profile.profile-open .user-avatar-badge {
  border-color: var(--volt-lime);
}

.profile-top-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
}

.btn-icon-back {
  width: 40px;
  height: 40px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  color: var(--text-main);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

.btn-icon-back:active {
  background: var(--bg-card-elevated);
  border-color: var(--volt-lime);
}

.profile-identity-card {
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 16px;
  margin-bottom: 10px;
}

.profile-avatar {
  width: 56px;
  height: 56px;
  flex: 0 0 auto;
  border-radius: 50%;
  background: var(--bg-card-elevated);
  border: 1.5px solid var(--border-glass-bright);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.profile-avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.profile-identity-text {
  min-width: 0;
}

.profile-name {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.3px;
  color: var(--text-main);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.profile-username {
  font-size: 13px;
  line-height: 1.35;
  color: var(--text-muted);
  /* пояснение про локальное хранение не влезает в строку и обрывалось многоточием */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.profile-auth-badge {
  display: flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  max-width: 100%;
  font-size: 12px;
  font-weight: 700;
  padding: 8px 14px;
  border-radius: var(--r-pill);
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  color: var(--text-muted);
  margin-bottom: 24px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.profile-auth-badge.badge-signed {
  color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.10);
  border-color: rgba(212, 246, 56, 0.35);
}

/* Вход через Telegram виден только в обычном браузере: внутри мессенджера кнопки нет,
   там вход происходит сам. Кнопка не главное действие кабинета, поэтому она вторичная —
   лаймовый акцент остаётся за выгодой; от Telegram здесь только цвет значка. */
.profile-login-box {
  margin-bottom: 24px;
}

.profile-login-box[hidden] {
  display: none;
}

.btn-telegram-login {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-md);
  color: var(--text-main);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 15px;
  padding: 15px;
  cursor: pointer;
}

.btn-telegram-login svg {
  color: #2AABEE;
  flex: 0 0 auto;
}

.btn-telegram-login:active {
  border-color: var(--volt-lime);
}

.btn-telegram-login[disabled] {
  opacity: 0.55;
  cursor: default;
}

.profile-login-hint {
  margin-top: 8px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-muted);
  text-align: center;
}

.profile-login-hint-cloud {
  margin-top: 4px;
}

/* «Зачем входить» — до кнопки (Б1): человек решает, нажимать ли, а не узнаёт
   задним числом, что нажал. */
.profile-login-why {
  margin-bottom: 12px;
}

.profile-login-why-title {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  color: var(--text-main);
  margin-bottom: 4px;
}

.profile-login-why-text {
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   ЭКРАН УВЕДОМЛЕНИЙ (A2, план П5)
   Одна колонка карточек. Тексты приходят с сервера до 128 + 256 знаков, поэтому
   перенос разрешён внутри слова: неразрывная строка не имеет права тащить экран
   вбок (замер 320px — tests/notifications-inbox.test.js, проверка 9).
   -------------------------------------------------------------------------- */
.notif-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.notif-item {
  display: block;
  min-width: 0;
  padding: 14px 16px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  color: inherit;
  text-decoration: none;
  overflow-wrap: anywhere;
  cursor: default;
}

/* Нажимается только то, у чего есть адрес; у остальных нет ни шеврона, ни руки. */
.notif-item.notif-link {
  cursor: pointer;
}

.notif-item.notif-link:active {
  background: var(--bg-card-elevated);
  border-color: var(--volt-lime);
}

.notif-item.notif-unread {
  border-color: var(--border-focus);
}

.notif-item-head {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.notif-new-dot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  margin-top: 7px;
  border-radius: 50%;
  background: var(--volt-lime);
}

.notif-item-title {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  line-height: 1.35;
  color: var(--text-main);
}

.notif-item-chevron {
  flex: 0 0 auto;
  font-size: 20px;
  line-height: 1;
  color: var(--text-muted);
}

.notif-item-body {
  margin-top: 6px;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text-muted);
}

.notif-item-date {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-muted);
}

.notif-empty {
  padding: 28px 20px;
  text-align: center;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
}

.notif-empty[hidden] {
  display: none;
}

.notif-empty-title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 700;
  color: var(--text-main);
  margin-bottom: 6px;
}

.notif-empty-text,
.notif-offline {
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text-muted);
}

.notif-offline {
  padding: 20px 16px;
  text-align: center;
}

/* Загрузка: силуэты карточек без текста — экран работает, ответ в пути. */
.notif-skeleton {
  height: 92px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  opacity: 0.6;
  animation: notif-skeleton-pulse 1.4s ease-in-out infinite;
}

@keyframes notif-skeleton-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 0.3; }
}

@media (prefers-reduced-motion: reduce) {
  .notif-skeleton { animation: none; }
}

.profile-stat-list {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 0 16px;
  margin-bottom: 24px;
}

/* Бордюр есть у всех строк, но прозрачный: иначе первая строка ниже соседних
   на его толщину и список выглядит рваным */
.profile-stat-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 52px;
  border-top: 1px solid transparent;
}

.profile-stat-row + .profile-stat-row {
  border-top-color: var(--border-glass);
}

.profile-stat-label {
  font-size: 14px;
  color: var(--text-muted);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.profile-stat-val {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 800;
  letter-spacing: -0.3px;
  color: var(--text-main);
  white-space: nowrap;
  flex: 0 0 auto;
}

.profile-stat-val.profile-stat-accent {
  color: var(--volt-lime);
}

/* Сводка-навигация: строка показывает число и ведёт в свой раздел.
   Один список вместо «неподвижная сводка + отдельные ссылки». */
.profile-nav-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}

.profile-nav-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  text-align: left;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  color: var(--text-main);
  font-family: var(--font-body);
  padding: 12px 14px;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}

.profile-nav-btn:active {
  background: var(--bg-card-elevated);
  border-color: var(--volt-lime);
}

.profile-nav-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--bg-card-elevated);
  color: var(--volt-lime);
}

/* Подпись переносится по словам, а не режется многоточием: рядом стоит сумма,
   и при семизначной выгоде от «Накоплено выгоды» оставалось «Накопле…» */
.profile-nav-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
}

.profile-nav-val {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: clamp(14px, 4.4vw, 17px);
  font-weight: 800;
  letter-spacing: -0.3px;
  white-space: nowrap;
}

.profile-action-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 24px;
}

.profile-action-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  text-align: left;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  color: var(--text-main);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  padding: 14px 16px;
  cursor: pointer;
}

.profile-action-btn:active {
  background: var(--bg-card-elevated);
}

.profile-action-btn > span:first-child {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.profile-action-chevron {
  /* стрелка — элемент управления: нужен контраст не ниже 3:1 */
  color: var(--text-muted);
  font-size: 18px;
  line-height: 1;
  flex: 0 0 auto;
}

.profile-action-btn.action-danger {
  color: var(--color-danger);
  border-color: rgba(255, 59, 48, 0.28);
}

/* Подтверждение разрушительного действия: строка раскрывается на месте,
   промахнуться по «Стереть» с первого нажатия невозможно */
.danger-confirm-row {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--color-danger-bg);
  border: 1px solid rgba(255, 59, 48, 0.32);
  border-radius: var(--r-md);
  padding: 14px 16px;
}

.danger-confirm-row[hidden] {
  display: none;
}

.danger-confirm-text {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--text-main);
}

.danger-confirm-actions {
  display: flex;
  gap: 8px;
}

.btn-confirm-cancel,
.btn-confirm-danger {
  flex: 1 1 0;
  min-width: 0;
  min-height: 44px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}

.btn-confirm-cancel {
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  color: var(--text-main);
}

.btn-confirm-danger {
  background: var(--color-danger);
  border: none;
  color: #fff;
}

/* Экран резервной копии (ТЗ 11.1). Своих размеров у него нет — только текст,
   статус и предупреждение; кнопки и строка подтверждения берутся из кабинета. */
.backup-lead {
  margin: 0 0 16px;
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* Строка статуса и предупреждение занимают ОДНО место: копия либо есть, либо
   нет, и показывается ровно одна из двух строк. */
.backup-status,
.backup-warning {
  border-radius: var(--r-md);
  padding: 12px 14px;
  margin-bottom: 16px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.35;
}

.backup-status {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  color: var(--text-main);
}

.backup-warning {
  background: var(--color-warning-bg);
  border: 1px solid var(--color-warning);
  color: var(--text-main);
}

.backup-status[hidden],
.backup-warning[hidden] {
  display: none;
}

/* Служебный блок свёрнут: «заводской сброс» не попадается под палец случайно */
.profile-service-block {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  overflow: hidden;
}

.profile-service-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  row-gap: 2px;
  min-height: 52px;
  padding: 14px 16px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 700;
  color: var(--text-muted);
  list-style: none;
}

.profile-service-summary::-webkit-details-marker {
  display: none;
}

.profile-service-hint {
  font-size: 11px;
  font-weight: 600;
  /* не --text-dim: он даёт 2.4:1 к фону карточки при норме 4.5:1 */
  color: var(--text-muted);
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.profile-service-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 6px 12px 14px 12px;
  border-top: 1px solid var(--border-glass);
}

.profile-service-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-muted);
  margin-top: 6px;
}

.tester-profiles-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Строки персон рисовались белыми кнопками браузера по умолчанию */
.tester-profile-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  min-height: 56px;
  text-align: left;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  color: var(--text-main);
  font-family: var(--font-body);
  padding: 12px 14px;
  cursor: pointer;
}

.tester-profile-row.tester-profile-active {
  border-color: rgba(212, 246, 56, 0.45);
  background: rgba(212, 246, 56, 0.08);
}

.tester-profile-title {
  font-size: 14px;
  font-weight: 700;
  color: var(--text-main);
}

/* Описание в две строки: иначе на 320px строки списка разъезжаются 78 / 96px */
.tester-profile-sub {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tester-profile-mark {
  flex: 0 0 auto;
  font-weight: 800;
  color: var(--text-muted);
}

.tester-profile-active .tester-profile-mark {
  color: var(--volt-lime);
}

/* --------------------------------------------------------------------------
   УЗКИЕ ЭКРАНЫ: карусель и кабинет
   -------------------------------------------------------------------------- */
@media (max-width: 360px) {
  .hero-card-slide {
    padding: 16px;
  }

  .hero-card-bank-name {
    font-size: 15px;
  }

  .hero-card-name {
    font-size: 16px;
  }

  .hero-card-slide .emv-sim-chip {
    width: 34px;
    height: 26px;
  }

  .home-saved-val {
    font-size: 21px;
  }

  .profile-name {
    font-size: 17px;
  }

  .profile-avatar {
    width: 48px;
    height: 48px;
  }
}

.tester-profile-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

/* Отметка, что ставка задана пользователем, а не взята из каталога */
.hero-card-rate-custom { position: relative; }
.hero-rate-mark {
  font-style: normal;
  margin-left: 4px;
  font-size: 15px;
  line-height: 1;
  vertical-align: middle;
  opacity: 0.55;
}

/* ============================================================
   ЗАСТАВКА ЗАПУСКА
   Задача одна: закрыть белую вспышку первых ~150 мс и уйти.
   Она НЕ должна задерживать: скрывается, как только приложение готово.
   ============================================================ */
.app-splash {
  position: fixed;
  inset: 0;
  z-index: 9000;
  background: var(--bg-deep, #0A0D14);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 260ms ease, visibility 260ms ease;
}

.app-splash.splash-hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

/* Знак процента из иконки приложения: два кружка и косая черта */
.splash-mark {
  position: relative;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--volt-lime, #C6F432);
  transform: scale(0.82);
  opacity: 0;
  animation: splash-in 420ms cubic-bezier(0.2, 0.9, 0.3, 1) forwards;
}

.splash-dot,
.splash-slash {
  position: absolute;
  background: var(--bg-deep, #0A0D14);
}

.splash-dot {
  width: 19px;
  height: 19px;
  border-radius: 50%;
  opacity: 0;
  animation: splash-dot-in 300ms ease forwards;
}

.splash-dot-top { top: 21px; left: 21px; animation-delay: 200ms; }
.splash-dot-bottom { right: 21px; bottom: 21px; animation-delay: 300ms; }

.splash-slash {
  top: 12px;
  left: 50%;
  width: 10px;
  height: 72px;
  margin-left: -5px;
  border-radius: 5px;
  transform: rotate(28deg) scaleY(0);
  transform-origin: center;
  animation: splash-slash-in 340ms cubic-bezier(0.3, 0.8, 0.3, 1) 120ms forwards;
}

@keyframes splash-in {
  from { transform: scale(0.82); opacity: 0; }
  to   { transform: scale(1);    opacity: 1; }
}
@keyframes splash-dot-in {
  from { opacity: 0; transform: scale(0.5); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes splash-slash-in {
  from { transform: rotate(28deg) scaleY(0); }
  to   { transform: rotate(28deg) scaleY(1); }
}

/* Кому анимации мешают — показываем знак сразу, без движения */
@media (prefers-reduced-motion: reduce) {
  .splash-mark,
  .splash-dot,
  .splash-slash {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .splash-slash { transform: rotate(28deg); }
  .app-splash { transition: opacity 120ms ease; }
}

/* Индикатор связи с ЦБ РФ отражает реальное состояние, а не горит всегда */
.scanner-live-chip[data-state="checking"] { opacity: 0.55; }
.scanner-live-chip[data-state="offline"] {
  color: var(--text-muted);
  border-color: rgba(255, 255, 255, 0.12);
}

/* =========================================================
   ПОДСКАЗКИ И ПУШИ (HINTS & NOTIFICATIONS)
   ========================================================= */
.hint-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-left: 3px solid var(--volt-lime);
  border-radius: 14px;
  padding: 12px 14px;
  margin: 0 0 16px 0;
  position: relative;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

.hint-banner.hint-hidden {
  display: none !important;
}

.hint-icon {
  font-size: 18px;
  flex-shrink: 0;
  line-height: 1.2;
}

.hint-body {
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-muted);
  flex-grow: 1;
}

.hint-body strong {
  color: var(--text-main);
}

.hint-close-btn {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 18px;
  cursor: pointer;
  padding: 0 4px;
  line-height: 1;
  border-radius: 4px;
  transition: color 0.15s ease;
}

.hint-close-btn:hover {
  color: var(--text-main);
}

.scanner-hint-pill {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border-glass);
  border-radius: 20px;
  padding: 8px 14px;
  margin: 12px auto 0 auto;
  max-width: 380px;
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.35;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.scanner-hint-icon {
  flex-shrink: 0;
  font-size: 14px;
}

.notification-setting-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 16px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: 14px;
  margin-bottom: 12px;
}

/* Свой [hidden]: display:flex карточки иначе перебивает правило браузера (строки вечернего
   вопроса прячутся у гостя и вне Mini App). */
.notification-setting-card[hidden] {
  display: none;
}

.notification-setting-info {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.notification-setting-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-main);
}

.notification-setting-desc {
  font-size: 12px;
  color: var(--text-muted);
}

.notification-setting-desc[hidden] {
  display: none;
}

/* Действие внутри строки настройки (вечерний вопрос: «Включить уведомления»): ссылка,
   а не вторая кнопка рядом с тумблером — на 320 px строке места под неё нет. */
.notification-setting-action {
  align-self: flex-start;
  margin-top: 4px;
  padding: 0;
  background: none;
  border: 0;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  color: var(--volt-lime);
  cursor: pointer;
}

.notification-setting-action[hidden] {
  display: none;
}

/* =========================================================
   КАРТЫ ЛОЯЛЬНОСТИ МАГАЗИНОВ (STORE LOYALTY CARDS)
   ========================================================= */
.cards-segment-control {
  display: flex;
  background: rgba(255, 255, 255, 0.05);
  padding: 4px;
  border-radius: 12px;
  margin-bottom: 16px;
  border: 1px solid var(--border-glass);
  gap: 4px;
}

.cards-segment-btn {
  flex: 1;
  padding: 8px 12px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  background: transparent;
  border: none;
  border-radius: 9px;
  cursor: pointer;
  transition: all 0.2s ease;
  text-align: center;
}

.cards-segment-btn.active {
  background: var(--bg-card);
  color: var(--text-main);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

.loyalty-cards-grid {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 24px;
}

.loyalty-card-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px;
  border-radius: 16px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.loyalty-card-item:active {
  transform: scale(0.98);
}

.loyalty-card-left {
  display: flex;
  align-items: center;
  gap: 14px;
}

.loyalty-card-monogram {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 800;
  background: rgba(255, 255, 255, 0.2);
  color: #ffffff;
  backdrop-filter: blur(6px);
}

.loyalty-card-title {
  font-size: 16px;
  font-weight: 700;
  color: #ffffff;
  margin-bottom: 4px;
}

.loyalty-card-number {
  font-size: 13px;
  font-family: monospace;
  color: rgba(255, 255, 255, 0.8);
  letter-spacing: 1px;
}

.loyalty-card-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.loyalty-barcode-icon-box {
  background: rgba(255, 255, 255, 0.15);
  border-radius: 8px;
  padding: 8px 10px;
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loyalty-delete-btn {
  background: transparent;
  border: none;
  color: rgba(255, 255, 255, 0.5);
  cursor: pointer;
  padding: 8px;
  font-size: 16px;
  border-radius: 8px;
  transition: color 0.15s ease;
}

.loyalty-delete-btn:hover {
  color: #ffffff;
}

/* Модальное окно полноэкранного штрихкода */
.barcode-modal-content {
  background: #ffffff;
  border-radius: 24px;
  padding: 24px 20px;
  max-width: 360px;
  width: 90%;
  margin: auto;
  text-align: center;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
}

.barcode-store-header {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-bottom: 20px;
}

.barcode-store-title {
  font-size: 20px;
  font-weight: 800;
  color: #111111;
}

.barcode-svg-wrapper {
  background: #ffffff;
  padding: 16px 8px;
  border-radius: 12px;
  border: 1px dashed #d0d0d0;
  margin-bottom: 16px;
}

.barcode-helper-text {
  font-size: 13px;
  color: #666666;
  margin-bottom: 20px;
  line-height: 1.4;
}

/* Плашка карты лояльности в кассовой шторке */
.decision-loyalty-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-radius: 14px;
  margin-bottom: 14px;
  cursor: pointer;
  border: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
  transition: transform 0.15s ease;
}

.decision-loyalty-banner:active {
  transform: scale(0.98);
}

.decision-loyalty-info {
  display: flex;
  align-items: center;
  gap: 10px;
}

.decision-loyalty-icon {
  font-size: 20px;
}

.decision-loyalty-title {
  font-size: 14px;
  font-weight: 700;
  color: #ffffff;
}

.decision-loyalty-sub {
  font-size: 11px;
  color: rgba(255, 255, 255, 0.85);
}

.decision-loyalty-badge {
  background: #ffffff;
  color: #000000;
  font-size: 12px;
  font-weight: 700;
  padding: 6px 10px;
  border-radius: 20px;
}

/* =========================================================
   DREAM VAULT & STREAKS (CANONICAL NEO-FINTECH DESIGN)
   ========================================================= */

/* Виджет копилки на главном экране (под каруселью карт) */
.dream-widget-card {
  width: 100%;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px 16px;
  margin-bottom: 22px;
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.2s ease, background 0.2s ease;
  user-select: none;
}

.dream-widget-card:active {
  transform: scale(0.985);
  border-color: var(--volt-lime);
  background: var(--bg-card);
}

.dream-widget-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.dream-widget-info {
  display: flex;
  align-items: center;
  gap: 10px;
  /* min-width:0 обязателен на всей цепочке flex-родителей: без него интринсик-ширина
     текста не даёт колонке сжаться, и ellipsis у заголовка не срабатывает вовсе. */
  min-width: 0;
}

.dream-widget-info > div {
  min-width: 0;
}

.dream-widget-icon {
  font-size: 24px;
  line-height: 1;
}

.dream-widget-title {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 800;
  letter-spacing: -0.2px;
  color: var(--text-main);
  /* Название цели набирает человек, до 80 знаков (DreamVault.DREAM_LIMITS): без обрезки
     карточка на 320px растягивалась со 111px до 215px пятью строками заголовка. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dream-widget-sub {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-muted);
}

/* Сумма — неразрывный кусок, а не набор слов. На 320px под подпись остаётся 146px,
   и «из 2 450 000 ₽» рвалось ВНУТРИ числа: «из 2 » на первой строке, «450 000 ₽» на
   второй. Цель при этом читается как «2». Переносить строку между «Выгода …» и
   «из …» можно и нужно — запрещён перенос только внутри самих чисел. */
.dream-widget-sub #hero-card-saved-val,
.dream-widget-sub .dream-widget-goal {
  white-space: nowrap;
}

.dream-widget-sub #hero-card-saved-val {
  color: var(--volt-lime);
  font-weight: 800;
}

.dream-streak-badge {
  background: rgba(255, 159, 10, 0.12);
  border: 1px solid rgba(255, 159, 10, 0.28);
  color: #FFB340;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 800;
  padding: 4px 9px;
  letter-spacing: 0.3px;
  white-space: nowrap;
}

/* Прогресс-бар мечты */
/* Полосы «0% закрыто» под несуществующей целью быть не должно (свод 4.3, п.5):
   у блока есть свой display, поэтому [hidden] прописан явно. */
.dream-progress-track[hidden] {
  display: none;
}

.dream-progress-track {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: var(--r-pill);
  overflow: hidden;
  position: relative;
  margin: 10px 0 8px 0;
}

.dream-progress-bar {
  height: 100%;
  background: linear-gradient(90deg, var(--volt-lime-dark) 0%, var(--volt-lime) 100%);
  border-radius: var(--r-pill);
  transition: width 0.5s cubic-bezier(0.16, 1, 0.3, 1);
  box-shadow: 0 0 12px var(--volt-lime-glow);
}

.dream-widget-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.dream-widget-percent {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 800;
  color: var(--volt-lime);
  letter-spacing: -0.2px;
}

.btn-dream-edit {
  background: none;
  border: none;
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  padding: 2px 4px;
  border-radius: 4px;
  transition: color 0.15s ease;
}

.btn-dream-edit:hover, .dream-widget-card:hover .btn-dream-edit {
  color: var(--volt-lime);
}

/* Сетка пресетов в модалке */
.dream-presets-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.dream-preset-item {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px 12px;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease, transform 0.15s ease;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.dream-preset-item:active {
  transform: scale(0.97);
}

.dream-preset-item.active {
  border-color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.08);
  box-shadow: 0 0 18px var(--volt-lime-glow);
}

.dream-preset-icon {
  font-size: 26px;
  line-height: 1;
  margin-bottom: 2px;
}

.dream-preset-name {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  color: var(--text-main);
  letter-spacing: -0.2px;
}

.dream-preset-amount {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--volt-lime);
}

/* Выбор значка цели. auto-fill вместо фиксированного числа колонок: на 320px в ряд
   встаёт на одну кнопку меньше, чем на 390px, и сетка не выносит шторку за экран. */
.dream-icon-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(44px, 1fr));
  gap: 8px;
}

.dream-icon-btn {
  /* 44px — цель пальца, а не курсора: значков много и стоят они вплотную. */
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease, transform 0.15s ease;
}

.dream-icon-btn:active {
  transform: scale(0.94);
}

.dream-icon-btn.active {
  border-color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.08);
  color: var(--volt-lime);
}

/* Карточка в кассовой шторке решения */
.decision-dream-box {
  margin: 12px 0 16px 0;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-md);
  padding: 14px;
  position: relative;
  overflow: hidden;
}

.decision-dream-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}

.decision-dream-headline {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  color: var(--text-main);
}

.decision-dream-add {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 800;
  color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.12);
  border: 1px solid rgba(212, 246, 56, 0.25);
  padding: 3px 8px;
  border-radius: var(--r-pill);
}

.decision-dream-desc {
  font-size: 12px;
  color: var(--text-muted);
  line-height: 1.4;
  margin-bottom: 6px;
}

.decision-dream-desc b {
  color: var(--text-main);
}

/* Блок мечты в профиле */
.profile-dream-box {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 16px;
  margin-bottom: 18px;
}

/* Верх карточки — кнопка копилки (Р1-а): сбрасываем браузерный вид <button>,
   а нажимаемость показываем шевроном и откликом, как у пилюль главной. */
.profile-dream-main {
  display: block;
  width: 100%;
  padding: 0 0 12px 0;
  margin: 0;
  background: none;
  border: 0;
  font-family: var(--font-body);
  color: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: var(--r-sm);
  transition: transform 0.15s ease;
}

.profile-dream-main:active,
.profile-streak-info:active {
  transform: scale(0.98);
}

.profile-dream-top {
  display: flex;
  align-items: center;
  gap: 12px;
}

.profile-dream-icon {
  font-size: 28px;
  flex: 0 0 auto;
}

/* min-width:0 — иначе длинное название цели распирает ряд и уносит шеврон за край */
.profile-dream-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
}

.profile-dream-title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 800;
  color: var(--text-main);
  overflow-wrap: anywhere;
}

.profile-dream-sub {
  font-size: 12px;
  color: var(--text-muted);
}

.profile-row-chevron {
  flex: 0 0 auto;
  font-size: 20px;
  line-height: 1;
  color: var(--text-muted);
}

.profile-dream-main .dream-progress-track {
  display: block;
  margin: 12px 0 6px 0;
}

.profile-dream-main .dream-progress-bar {
  display: block;
}

.profile-dream-main .dream-progress-track[hidden] {
  display: none;
}

/* Суммы цели под полосой: «12 450 000 ₽ из …» на 320px обязана переноситься,
   а не уезжать за карточку. */
.profile-dream-sum {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-main);
  overflow-wrap: anywhere;
}

.profile-dream-sum[hidden] {
  display: none;
}

.profile-streak-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--border-glass);
}

/* Нижняя ручка карточки — серия (Р4-а): вся строка до значка «В Stories», высота
   цели не меньше 40px — ради неё экран и открывают. */
.profile-streak-info {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
  min-height: 40px;
  padding: 0;
  margin: 0;
  background: none;
  border: 0;
  font-family: var(--font-body);
  text-align: left;
  color: inherit;
  cursor: pointer;
  border-radius: var(--r-sm);
  transition: transform 0.15s ease;
}

.profile-streak-text {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: 700;
  color: var(--text-main);
  font-size: 13px;
}

/* «В Stories» — второстепенная ручка: значок 40×40, без подписи текстом (Р1-а). */
.btn-share-story.btn-share-story-icon {
  flex: 0 0 auto;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  color: var(--text-muted);
}

/* Серия на главной стала кнопкой: гасим браузерный вид, как у соседней пилюли Декса.
   Шеврон — тот же знак нажимаемости, что «0 из 20 магазинов ›» у Декса. */
button.go-streak-pill {
  width: 100%;
  text-align: left;
  font-family: var(--font-body);
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.2s ease, background 0.2s ease;
  user-select: none;
}

button.go-streak-pill:active {
  transform: scale(0.97);
  border-color: var(--volt-lime);
  background: var(--bg-card);
}

button.go-streak-pill .go-pill-sub::after {
  content: ' ›';
}

/* Шторка «Серия оплат» (Р4-а) */
.streak-sheet-lead {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-muted);
  margin: 0 0 10px 0;
}

.streak-sheet-count {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 800;
  color: var(--volt-lime);
  margin-bottom: 14px;
  overflow-wrap: anywhere;
}

.streak-sheet-count[hidden] {
  display: none;
}

.streak-rule {
  margin-bottom: 12px;
}

.streak-rule-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text-main);
  margin-bottom: 3px;
}

.streak-rule-text {
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-muted);
  margin: 0;
}

.streak-ladder-title {
  margin-top: 4px;
  margin-bottom: 8px;
}

.streak-ladder {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 6px;
}

.streak-rank-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 40px;
  padding: 8px 12px;
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  background: var(--bg-surface);
  font-size: 13px;
  color: var(--text-main);
}

.streak-rank-row.is-current {
  border-color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.08);
}

.streak-rank-icon {
  display: inline-flex;
  flex: 0 0 auto;
  line-height: 0;
  color: var(--volt-lime);
}

.streak-rank-label {
  flex: 1 1 auto;
  min-width: 0;
}

.streak-rank-now {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 700;
  color: var(--volt-lime);
}

.btn-share-story {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass-bright);
  color: var(--text-main);
  padding: 6px 14px;
  border-radius: var(--r-pill);
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: all 0.15s ease;
}

.btn-share-story:hover {
  border-color: var(--volt-lime);
  color: var(--volt-lime);
}

.btn-share-story:active {
  transform: scale(0.96);
}

/* =========================================================
   CASHBACK GO: TROPHY DEX & GEO-RADAR
   ========================================================= */

/* Главная: блоки 6 и 7 порядка ТЗ 4.1 — Кешбэк-Декс и стрик.
   ОДНА колонка на любой ширине, а не две тесных: во второй колонке подпись
   «Пойдёт с первой подтверждённой оплаты» обрезалась многоточием уже на 390px
   (замер: контейнер 118px при нужных 229px, cut=111px), а на 320 то же самое
   делала живая строка превью радара. minmax(0,1fr) оставлен потому же, почему
   стоял: у 1fr минимум колонки равен min-content, и nowrap внутри плитки
   распирает ряд. */
.cashback-go-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  margin-bottom: 10px;
}

.go-radar-pill, .go-dex-pill {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 10px 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  /* это <button>: гасим дефолтные шрифт, цвет и выравнивание браузера */
  width: 100%;
  min-height: 52px;
  text-align: left;
  font-family: var(--font-body);
  color: var(--text-main);
  transition: transform 0.15s ease, border-color 0.2s ease, background 0.2s ease;
  user-select: none;
}

.go-radar-pill:active, .go-dex-pill:active {
  transform: scale(0.97);
  border-color: var(--volt-lime);
  background: var(--bg-card);
}

.radar-ping-dot {
  width: 10px;
  height: 10px;
  background: var(--volt-lime);
  border-radius: 50%;
  position: relative;
  flex: 0 0 auto;
  box-shadow: 0 0 10px var(--volt-lime);
  animation: radar-ping 1.8s infinite;
}

@keyframes radar-ping {
  0% { transform: scale(0.9); opacity: 1; }
  50% { transform: scale(1.4); opacity: 0.5; box-shadow: 0 0 14px var(--volt-lime); }
  100% { transform: scale(0.9); opacity: 1; }
}

.dex-trophy-icon {
  font-size: 18px;
  line-height: 1;
  flex: 0 0 auto;
}

.go-pill-content {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.go-pill-title {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 800;
  color: var(--text-main);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.go-pill-sub {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--volt-lime);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ШТОРКА КЕШБЭК-ДЕКСА */
.dex-sheet-content {
  overflow: hidden;
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  max-height: 85dvh;
}

/* Всё, кроме прокручиваемого списка, держит свою высоту. Без этого flex сжимал ряд
   фильтров до 5px, а карточки Декса — со 105 до 26px на вьюпорте 568px. */
.dex-sheet-content > *,
.radar-sheet-content > * {
  flex: 0 0 auto;
}

.dex-sheet-content > .dex-grid,
.radar-sheet-content > .radar-spots-list {
  flex: 1 1 auto;
  min-height: 0;
}

.dex-summary-card {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 12px 14px;
  margin-bottom: 12px;
}

.dex-summary-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.dex-rank-badge {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 800;
  color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.12);
  border: 1px solid rgba(212, 246, 56, 0.25);
  padding: 3px 8px;
  border-radius: var(--r-pill);
}

.dex-counter-text {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--text-muted);
}

.dex-progress-track {
  width: 100%;
  height: 6px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: var(--r-pill);
  overflow: hidden;
}

.dex-progress-bar {
  height: 100%;
  background: linear-gradient(90deg, var(--volt-lime-dark) 0%, var(--volt-lime) 100%);
  border-radius: var(--r-pill);
  transition: width 0.4s ease;
  box-shadow: 0 0 10px var(--volt-lime-glow);
}

/* Фильтры сетов категорий */
.dex-filter-pills, .radar-filter-pills {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  margin-bottom: 14px;
  padding-bottom: 2px;
}

.dex-filter-pills::-webkit-scrollbar, .radar-filter-pills::-webkit-scrollbar {
  display: none;
}

.dex-filter-btn, .radar-filter-btn {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 700;
  /* 36px по высоте вместо 29: палец не попадал по пилюле фильтра */
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  flex: 0 0 auto;
  padding: 0 14px;
  border-radius: var(--r-pill);
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.15s ease;
}

.dex-filter-btn.active, .radar-filter-btn.active {
  background: var(--volt-lime);
  color: var(--volt-text);
  border-color: var(--volt-lime);
  font-weight: 800;
}

/* Сетка покемонов-брендов в Дексе */
.dex-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* без max-content неявные ряды растягиваются/сжимаются вместе с flex-родителем,
     а overflow:hidden у карточки обнуляет её автоминимум — карточка схлопывалась в 26px */
  grid-auto-rows: max-content;
  gap: 10px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: 2px;
  scrollbar-width: thin;
}

.dex-card {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  position: relative;
  overflow: hidden;
  transition: transform 0.15s ease, border-color 0.2s ease;
}

.dex-card.caught {
  border-color: rgba(212, 246, 56, 0.4);
  background: linear-gradient(135deg, rgba(212, 246, 56, 0.05) 0%, rgba(14, 18, 27, 0.9) 100%);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}

.dex-card.locked {
  opacity: 0.65;
  background: rgba(14, 18, 27, 0.7);
  border-style: dashed;
}

.dex-card-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.dex-card-icon {
  font-size: 26px;
  line-height: 1;
}

.dex-card.locked .dex-card-icon {
  filter: grayscale(1) opacity(0.5);
}

.dex-rarity-badge {
  font-size: 10px;
  font-weight: 800;
  text-transform: uppercase;
  padding: 2px 6px;
  border-radius: var(--r-pill);
  /* Подложка и рамка заданы здесь, а не только инлайном: цвет редкости приходит через
     color-mix (Chrome 111+, Safari 16.2+), а в Telegram WebView на старых Android его
     может не быть. Там браузер выбрасывает объявление ЦЕЛИКОМ вместе с рамкой, и бейдж
     остался бы голым текстом. Инлайн-стиль перекрывает эти значения, где color-mix есть. */
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--border-glass);
}

.dex-card-name {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 800;
  color: var(--text-main);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dex-card.locked .dex-card-name {
  color: var(--text-muted);
}

.dex-card-hint {
  font-size: 11px;
  color: var(--text-muted);
  line-height: 1.3;
}

.dex-card-status {
  font-size: 11px;
  font-weight: 700;
  color: var(--volt-lime);
  margin-top: 2px;
}

/* ШТОРКА РАДАРА СОКРОВИЩ */
.radar-sheet-content {
  overflow: hidden;
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  max-height: 85dvh;
}

.radar-spots-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-right: 2px;
}

.radar-spot-card {
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 12px 14px;
  display: flex;
  /* Два ряда, а не две колонки: с именем карты в подписи (Д4) ставка «1,5% Рестораны
     и кафе · Райффайзенбанк» в правой колонке 46% шла в три строки и сжимала имя
     места до переноса посреди слова («Шоколадниц/а», 320px). */
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  transition: border-color 0.2s ease;
}

.radar-spot-card:hover {
  border-color: var(--border-glass-bright);
}

.radar-spot-left {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  flex: 1 1 100%;
}

.radar-spot-icon {
  font-size: 26px;
  line-height: 1;
  flex: 0 0 auto;
}

.radar-spot-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.radar-spot-name {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  color: var(--text-main);
  line-height: 1.2;
  /* имя точки — то, ради чего карточку читают: на 320px «Первая свежесть»
     обрезалось многоточием на 34px. Переносим в две строки, а не режем. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.radar-spot-meta {
  font-size: 11px;
  color: var(--text-muted);
  /* был flex-ряд: «412 м • адрес • статус» распадался на три узкие колонки, и адрес
     шёл лесенкой в 6 строк при полупустой карточке. Это одно предложение. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.35;
  overflow-wrap: anywhere;
  margin-top: 2px;
}

.radar-spot-dist {
  color: var(--volt-lime);
  font-weight: 700;
}

.radar-spot-right {
  /* Нижний ряд карточки: ставка слева под текстом (отступ = значок + зазор), «Маршрут»
     справа. space-between, а не margin-left:auto: при переносе ряд не оставит дыру. */
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  flex: 1 1 100%;
  min-width: 0;
  padding-left: 32px;
}

.radar-spot-reward {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 800;
  color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.12);
  border: 1px solid rgba(212, 246, 56, 0.25);
  padding: 4px 10px;
  /* не pill: с именем банка подпись на 320px идёт в 2-3 строки, и капсула становилась пузырём */
  border-radius: var(--r-sm);
  text-align: left;
  line-height: 1.25;
  min-width: 0;
}
/* Категорию места не прислали — подписи нет, пустую пилюлю не рисуем */
.radar-spot-reward:empty { display: none; }

.btn-spot-route {
  /* ради этой кнопки экран и открывают, а была цель 70×20 без фона и с радиусом 4px */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 32px;
  padding: 6px 12px;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-main);
  text-decoration: none;
  white-space: nowrap;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-pill);
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}

.btn-spot-route:hover, .btn-spot-route:active {
  color: var(--volt-lime);
  border-color: var(--volt-lime);
  background: rgba(212, 246, 56, 0.12);
}

/* БАННЕР ПОИМКИ ТРОФЕЯ НА КАССЕ */
.decision-trophy-caught-banner {
  background: linear-gradient(135deg, rgba(212, 246, 56, 0.15) 0%, rgba(20, 25, 35, 0.95) 100%);
  border: 1px solid var(--volt-lime);
  border-radius: var(--r-md);
  padding: 12px 14px;
  margin: 10px 0 14px 0;
  display: flex;
  align-items: center;
  gap: 12px;
  box-shadow: 0 0 20px var(--volt-lime-glow);
  animation: trophy-bounce 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

@keyframes trophy-bounce {
  0% { transform: scale(0.92); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}

.trophy-caught-icon {
  font-size: 28px;
  line-height: 1;
}

.trophy-caught-info {
  display: flex;
  flex-direction: column;
}

.trophy-caught-title {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 800;
  color: var(--volt-lime);
  letter-spacing: -0.2px;
}

.trophy-caught-sub {
  font-size: 11px;
  color: var(--text-main);
}

/* ПАНЕЛЬ ГЕОЛОКАЦИИ И ВЫБОРА ГОРОДА В РАДАРЕ */
.radar-location-bar {
  margin-bottom: 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 10px 12px;
}

.radar-loc-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.radar-loc-status {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-main);
}

.radar-loc-dot-gps {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--volt-lime);
  box-shadow: 0 0 8px var(--volt-lime);
}

.radar-loc-dot-manual {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-warning);
}

.btn-loc-action {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--border-glass);
  /* был var(--r-full) — токен не объявлен, объявление отбраковывалось, радиус падал в 0 */
  border-radius: var(--r-pill);
  color: var(--text-main);
  font-size: 11px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 6px 12px;
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.15s ease;
}

/* Кнопки плашки локации. Ряд переносится: «Выбрать город» + «GPS» рядом с именем
   «Ростов-на-Дону» на 320px в одну строку не влезают. */
.radar-loc-header { flex-wrap: wrap; }
.radar-loc-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

/* Состояние геопозиции (Д2): ждём ответа / закрыт / не ответил / город руками */
.radar-loc-note {
  font-size: 12px;
  color: var(--text-muted);
  margin-top: 8px;
  line-height: 1.35;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.radar-loc-note .app-icon { flex: 0 0 auto; margin-top: 1px; }
.radar-loc-note.is-warning { color: var(--color-warning); }
.radar-loc-settings { margin-top: 8px; }

/* Что показано под фильтрами (Д3): «Все места рядом · 12 мест» / «Только АЗС · 3 места» */
.radar-filter-state {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-main);
  margin: -6px 4px 10px;
  line-height: 1.3;
}
.radar-filter-state:empty { display: none; }

.btn-loc-action:hover, .btn-loc-action:active {
  background: rgba(212, 246, 56, 0.15);
  border-color: var(--volt-lime);
  color: var(--volt-lime);
}

.radar-cities-drawer {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border-glass);
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  /* 11 городов в столбик занимали 150px из 483px шторки, списку точек оставалось 115px.
     Потолок обрезает третий ряд на середине — это и есть подсказка «ниже есть ещё». */
  max-height: 112px;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

/* Раскрытый список городов — состояние первого запуска (GPS ещё не дали). На экране
   568px он забирал 176px из 483px шторки, и списку точек не оставалось даже на карточку. */
@media (max-height: 700px) {
  .radar-cities-drawer {
    max-height: 74px;
  }
}

.city-pill-btn {
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-pill);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 6px 12px;
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.15s ease;
}

.city-pill-btn.active {
  background: rgba(212, 246, 56, 0.2);
  border-color: var(--volt-lime);
  color: var(--volt-lime);
  font-weight: 700;
}

.city-pill-btn:hover {
  color: var(--text-main);
  border-color: rgba(255, 255, 255, 0.3);
}

/* --------------------------------------------------------------------------
   ШАПКА ШТОРКИ: ЗАГОЛОВОК И КНОПКА ЗАКРЫТИЯ
   Правил не было вовсе: ✕ рисовался дефолтом браузера — белый прямоугольник
   14×20px системным шрифтом на тёмной шторке. Задето и окно «Цель-мечта».
   -------------------------------------------------------------------------- */
.modal-header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.sheet-title {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.3px;
  color: var(--text-main);
  min-width: 0;
}

.btn-close-sheet {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-pill);
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.btn-close-sheet:hover,
.btn-close-sheet:active {
  background: rgba(255, 255, 255, 0.12);
  border-color: var(--border-glass-bright);
  color: var(--text-main);
}

/* --------------------------------------------------------------------------
   НАБОР ИКОНОК (js/engine/icons.js)
   Эмодзи ушли из интерфейса: их рисует шрифт системы, поэтому на Android,
   iOS и в Telegram WebView один и тот же экран выглядел по-разному, размер
   задавался font-size и не совпадал с 25 инлайновыми SVG, которые в проекте
   уже были. Здесь — общее поведение значка, единое для всех мест.
   -------------------------------------------------------------------------- */
.app-icon {
  display: inline-block;
  /* значок садится на строку текста; в flex-контейнерах свойство не мешает */
  vertical-align: -0.15em;
  /* Значок никогда не сжимается: в ряду с длинным названием магазина flexbox
     сплющивал бы его в полоску шириной 4px вместо квадрата 22px. */
  flex: 0 0 auto;
  /* цвет наследуется от текста, отдельного токена значку не нужно */
  color: inherit;
}

/* Пилюли фильтров, статусы и кнопки: значок и подпись одной строкой */
.dex-filter-btn,
.radar-filter-btn,
.btn-loc-action,
.btn-spot-route,
.dex-rank-badge,
.dream-streak-badge,
.btn-dream-edit,
.dex-card-status,
.trophy-caught-title,
.radar-spot-catch,
.sheet-title {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.dex-filter-btn .app-icon,
.radar-filter-btn .app-icon,
.dex-rank-badge .app-icon,
.dream-streak-badge .app-icon,
.dex-card-status .app-icon,
.radar-spot-catch .app-icon,
.trophy-caught-title .app-icon {
  vertical-align: 0;
}

.sheet-title { gap: 9px; }
.sheet-title-icon { color: var(--volt-lime); }

.btn-dream-edit { gap: 4px; }
.dex-card-status { gap: 4px; }
.radar-spot-catch { gap: 3px; }

/* Кнопки-иконки: значок центрируется, размер цели не меняется */
.btn-close-sheet,
.hint-close-btn,
.loyalty-delete-btn,
.tester-profile-mark,
.scanner-hint-icon,
.hint-icon,
.dream-widget-icon,
.profile-dream-icon,
.dex-card-icon,
.dex-trophy-icon,
.radar-spot-icon,
.trophy-caught-icon,
.decision-loyalty-icon,
.dream-preset-icon,
#profile-streak-rank-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  line-height: 0;
}

/* Кнопка удаления карты лояльности: цель была 32×32 при значке 16 — оставляем
   цель, но выравниваем значок по центру, а не по базовой линии текста. */
.loyalty-delete-btn { min-width: 32px; min-height: 32px; }
.hint-close-btn { min-width: 32px; min-height: 32px; }

/* «Сменить цель» — вход в шторку копилки, а цель была 102×17: палец по ней не попадает.
   Высота цели 32px, но СТРОКА не растёт: отрицательные поля возвращают внешний бокс к
   прежним 18px. Вертикальный бюджет главной на 320×568 — 427px, лишних 15px там нет. */
.btn-dream-edit {
  min-height: 32px;
  padding: 0 4px;
  /* Отрицательные поля ТОЛЬКО по вертикали: правое (-6px) выносило кнопку за
     контент-бокс строки, и .dream-widget-footer начинал прокручиваться на 6px. */
  margin: -7px 0;
}

/* Тост со значком: значок акцентный, раскладка — у самого .toast выше */
.toast .app-icon { color: var(--volt-lime); }

/* --------------------------------------------------------------------------
   ЦВЕТНЫЕ ТОЧКИ ВМЕСТО ЦВЕТНЫХ ЭМОДЗИ
   Там, где смысл несёт РОВНО цвет (редкость трофея, состояние связи, «данные
   живые»), значок этот смысл только зашумил бы. Точку рисует CSS: она берёт
   цвет у самого элемента (currentColor), поэтому редкость задаётся одним
   инлайновым `color` и больше нигде не дублируется.
   -------------------------------------------------------------------------- */
.dex-rarity-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.dex-rarity-badge::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

.scanner-live-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.scanner-live-chip::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
}

/* «Реальные магазины вокруг вас» — признак живого ответа OSM, а не пресетов */
.radar-live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 auto;
  display: inline-block;
}

/* --------------------------------------------------------------------------
   ПЛИТКА ЗНАЧКА В КЕШБЭК-ДЕКСЕ
   Значки трофеев теперь КАТЕГОРИЙНЫЕ (решение владельца: тележка, бургер,
   колонка, аптечный крест — не логотипы брендов), поэтому внутри одной
   категории они одинаковы, и бренд различает НАЗВАНИЕ. Плитка нужна, чтобы
   значок не сливался с названием и чтобы пойманное читалось с одного взгляда:
   лаймовый — «есть у меня», приглушённый — «ещё не пойман».
   -------------------------------------------------------------------------- */
.dex-card-icon {
  width: 38px;
  height: 38px;
  border-radius: 11px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid var(--border-glass);
  color: var(--text-muted);
}

.dex-card.caught .dex-card-icon {
  background: rgba(212, 246, 56, 0.12);
  border-color: rgba(212, 246, 56, 0.3);
  color: var(--volt-lime);
}

/* Обесцвечивать нечего: значок и так рисуется одним цветом через currentColor,
   а filter: grayscale на обводке давал грязный серо-зелёный вместо чистого. */
.dex-card.locked .dex-card-icon {
  filter: none;
  color: var(--text-dim);
}

.dex-trophy-icon { color: var(--volt-lime); }
.radar-spot-icon { color: var(--volt-lime); }
.dream-widget-icon,
.profile-dream-icon { color: var(--volt-lime); }
.decision-loyalty-icon { color: #ffffff; }
.scanner-hint-icon,
.hint-icon { color: var(--volt-lime); }
#profile-streak-rank-icon { color: var(--volt-lime); }
.trophy-caught-icon { color: var(--volt-lime); }
.dream-preset-icon { color: var(--text-main); }
.dream-preset-item.active .dream-preset-icon { color: var(--volt-lime); }

/* Бейдж редкости стоит на своей строке, а не в ряду со значком: в ряду он не влезал
   в карточку 140px на 320 («Легендарный» — 101px при 116px внутренней ширины), а у
   .dex-card стоит overflow:hidden — текст резался молча, без горизонтального скролла. */
.dex-card-top {
  justify-content: flex-start;
}

.dex-rarity-badge {
  align-self: flex-start;
  max-width: 100%;
}

/* --------------------------------------------------------------------------
   ГЛАВНАЯ КНОПКА ШТОРКИ
   Правил не было вовсе — ровно тот же дефект, что был у .btn-close-sheet: при
   живом .btn-sheet-secondary парная ему .btn-sheet-primary рисовалась дефолтом
   браузера, белым системным прямоугольником на тёмной шторке. Задето четыре
   места: «Сохранить цель», «Сохранить карту», «+ Добавить карту», «Готово».
   -------------------------------------------------------------------------- */
.btn-sheet-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 14px 18px;
  background: var(--volt-lime);
  color: var(--volt-text);
  border: none;
  border-radius: var(--r-md);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 800;
  line-height: 1.2;
  cursor: pointer;
  transition: filter 0.15s ease, transform 0.1s ease;
}

.btn-sheet-primary:hover { filter: brightness(1.06); }
.btn-sheet-primary:active { transform: scale(0.985); }

/* Непойманный трофей: значок «?» на --text-dim под общей непрозрачностью 0.65
   давал контраст, при котором плитка читалась как пустая. Оттенок на ступень
   светлее — карточка по-прежнему приглушена, но значок в ней виден. */
.dex-card.locked .dex-card-icon {
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   ДИАЛОГ ПОДТВЕРЖДЕНИЯ ОПЛАТЫ И ЭКРАН УСПЕХА (ТЗ 7.1–7.3)
   Тот же лист, что и у шторки решения (.decision-sheet-content), поэтому здесь
   только содержимое: вопрос, ответы, сноска. Ни одного нового токена — всё на
   палитре :root, иначе объявление молча выбросит браузер, а тест 26 покраснеет.
   -------------------------------------------------------------------------- */
.confirm-head {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.4px;
  color: var(--text-main);
  margin-bottom: 8px;
}

.confirm-sub {
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-muted);
  margin-bottom: 18px;
}

/* Ответы идут столбиком с одинаковым шагом: у .btn-sheet-secondary своего
   нижнего отступа нет, а у .btn-sheet-primary он 12px только в одной ветке. */
.confirm-choice {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  margin-bottom: 10px;
}

/* Четвёртый путь — строка-ссылка, а не четвёртая кнопка: он не равноправен
   трём ответам ТЗ и не должен спорить с ними за внимание у кассы. */
.confirm-link-row {
  display: block;
  width: 100%;
  background: none;
  border: none;
  padding: 10px 0;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  color: var(--volt-lime);
  text-align: center;
  cursor: pointer;
}

.confirm-note {
  font-size: 12px;
  line-height: 1.4;
  color: var(--text-dim);
  text-align: center;
  margin-top: 12px;
}

.confirm-dream-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 12px 14px;
  margin-bottom: 16px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-main);
}

.confirm-dream-row svg {
  flex: none;
  color: var(--volt-lime);
}

/* --------------------------------------------------------------------------
   СТАТУСЫ ЗАПИСЕЙ В ИСТОРИИ (ТЗ 7.4)
   Незакрытая покупка — серая и без вклада в итоги, отменённая — зачёркнутая.
   Подтверждённая выглядит ровно как раньше: у неё своего правила нет.
   -------------------------------------------------------------------------- */
.history-row-pending .history-reward-val,
.history-row-cancelled .history-reward-val {
  color: var(--text-dim);
}

.history-row-cancelled .history-reward-val {
  text-decoration: line-through;
}

.history-row-cancelled .history-m-name {
  color: var(--text-muted);
}

/* Подпись статуса строки истории («Ждём ответа», «Отменено», «Сумму не считали»).
   12px, а не 11: это единственное объяснение, почему в строке нет суммы, и читать
   его приходится на ходу. Замер на 320 после правки: горизонтального скролла нет
   даже у строки с именем в 57 знаков и суммой 12 450 000 ₽. */
.history-status-note {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
  white-space: nowrap;
  margin-top: 2px;
}

/* ==========================================================================
   ЭТАП 2B: ГЛАВНЫЙ ЭКРАН (ТЗ 4), СКАНЕР (ТЗ 5), ШТОРКА РЕЗУЛЬТАТА (ТЗ 6)
   Узкоэкранные переопределения собраны ОДНИМ блоком в конце раздела: медиазапрос
   не поднимает специфичность, и правило, записанное выше базового, проигрывает
   ему по порядку (поймано 11.09.2026 на .bank-chip).
   ========================================================================== */

/* Подсказка ТЗ 5 «в рамке». Абсолютный слой поверх видоискателя: любой отступ
   внутри .scanner-overlay-ui уводит рамку прицела с центра карточки. */
.scanner-frame-hint {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 10px;
  text-align: center;
  font-size: 11.5px;
  line-height: 1.3;
  color: rgba(255, 255, 255, 0.9);
  background: rgba(7, 9, 14, 0.66);
  border-radius: var(--r-sm);
  padding: 6px 8px;
  pointer-events: none;
}

/* `hidden` — атрибут браузера со СЛАБОЙ специфичностью: правило `[hidden]{display:none}`
   из таблицы браузера проигрывает `.manual-input-box{display:flex}`, и свёрнутая форма
   ссылки оставалась на экране (замер: видна на 320 и 390). Это же касается любого
   display-блока, который прячут атрибутом. */
.manual-input-box[hidden],
.loss-week-card[hidden],
.howto-card[hidden] {
  display: none;
}

/* Камера не включена — подсказку про код прячем: слой отказа стоит ровно там же,
   и два сообщения в одной карточке накладываются друг на друга. */
.camera-blocked-layer:not([hidden]) ~ .scanner-frame-hint {
  display: none;
}

/* Главное действие экрана (ТЗ 4.1, блок 1) */
.btn-scan-main {
  width: 100%;
  min-height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--volt-lime);
  color: var(--volt-text);
  border: none;
  border-radius: var(--r-md);
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.2px;
  cursor: pointer;
  box-shadow: 0 10px 24px rgba(212, 246, 56, 0.18);
  transition: transform 0.15s ease;
}

.btn-scan-main:active {
  transform: scale(0.97);
}

.scan-main-sub {
  margin: 8px 0 12px;
  text-align: center;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-muted);
}

/* Запасные пути сканера. Один ряд из трёх целей; на 320px подписи не режутся,
   потому что колонки равные и minmax(0,...) не даёт nowrap распирать ряд. */
.scan-fallback-row {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 14px;
}

.scan-fallback-chip {
  min-width: 0;
  min-height: 44px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 7px 4px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  color: var(--text-main);
  font-family: var(--font-body);
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  cursor: pointer;
}

.scan-fallback-chip:active {
  border-color: var(--volt-lime);
  background: var(--bg-card);
}

.scan-fallback-chip svg {
  flex: 0 0 auto;
  color: var(--volt-lime);
}

.btn-scan-secondary {
  width: 100%;
  min-height: 44px;
  margin-bottom: 22px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  color: var(--text-main);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
}

.btn-scan-secondary:active {
  border-color: var(--volt-lime);
  background: var(--bg-card);
}

/* --------------------------------------------------------------------------
   ВИДЖЕТ «МИМО ЗА НЕДЕЛЮ» (ТЗ 4.1 блок 2, 14.2)
   Одна колонка на любой ширине: крупное число и подпись рядом на 320px
   означают вторую колонку, в которую семизначная сумма не помещается.
   -------------------------------------------------------------------------- */
.loss-week-card {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 14px;
  margin-bottom: 22px;
}

.loss-week-card:empty {
  display: none;
}

.loss-week-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

.loss-week-title {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--text-main);
}

.loss-week-icon {
  display: inline-flex;
  color: var(--color-warning);
}

.loss-week-big {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(24px, 8vw, 30px);
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.6px;
  color: var(--text-main);
  white-space: nowrap;
}

.loss-week-earned {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  font-weight: 600;
  color: var(--volt-lime);
  white-space: nowrap;
}

.loss-week-note {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.35;
  color: var(--text-muted);
}

.loss-week-cta {
  width: 100%;
  min-height: 40px;
  margin-top: 12px;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  color: var(--text-main);
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 700;
  cursor: pointer;
}

.loss-week-cta:active {
  border-color: var(--volt-lime);
}

/* --------------------------------------------------------------------------
   СТРОКА БАНКОВ (ТЗ 4.1, блок 3)
   -------------------------------------------------------------------------- */
.banks-line-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
}

.banks-line-text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-main);
}

/* Строка-ссылка, а не кнопка-пилюля: цель 32px по высоте даёт палец, а вид —
   подпись рядом с перечислением банков (свод текстов, строчное «изменить»). */
.banks-line-edit {
  flex: 0 0 auto;
  min-height: 32px;
  padding: 4px 8px;
  background: none;
  border: none;
  color: var(--volt-lime);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   СТРИК ОТДЕЛЬНЫМ БЛОКОМ (ТЗ 4.1, блок 7) И РАДАР ВО ВСЮ ШИРИНУ (блок 8)
   -------------------------------------------------------------------------- */
.go-streak-pill {
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-md);
  padding: 10px 12px;
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  min-height: 52px;
  color: var(--text-main);
}

/* Единственная подпись пилюли с ПОСТОЯННЫМ текстом: ей перенос, а не многоточие
   (у соседей текст приходит из данных, и там многоточие — осознанный выбор). */
#go-streak-sub {
  white-space: normal;
  overflow: visible;
}

.go-streak-icon {
  flex: 0 0 auto;
  display: inline-flex;
  color: var(--volt-lime);
}

.go-radar-row {
  /* Отступ до следующего блока держит теперь строка про координаты под кнопкой
     (.go-radar-privacy): она часть этой же пилюли, и 24px между ними разорвали бы
     пару «кнопка — предупреждение». */
  margin-bottom: 6px;
}

.go-radar-privacy {
  margin-bottom: 24px;
  padding: 0 2px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   ШТОРКА РЕЗУЛЬТАТА (ТЗ 6.1): магазин, категория, один крупный итог
   -------------------------------------------------------------------------- */
.sheet-merchant-name {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
  line-height: 1.25;
  color: var(--text-main);
  margin-top: 10px;
  /* Длинное имя магазина переносится, а не растягивает шторку вбок */
  overflow-wrap: anywhere;
}

.sheet-category-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 4px;
  font-size: 13px;
  color: var(--text-muted);
}

.sheet-category-name {
  min-width: 0;
  overflow-wrap: anywhere;
}

.btn-change-category {
  min-height: 32px;
  padding: 4px 8px;
  background: none;
  border: none;
  color: var(--volt-lime);
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.category-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 10px 0 4px;
}

.category-picker[hidden] {
  display: none;
}

.category-picker-chip {
  min-height: 34px;
  padding: 6px 12px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-pill);
  color: var(--text-main);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}

.category-picker-chip.chip-current {
  border-color: var(--volt-lime);
  color: var(--volt-lime);
}

/* Единственное место, где на шторке стоит сумма кешбэка (ТЗ 6.1). */
.hero-rec-big {
  font-family: var(--font-display);
  font-size: clamp(26px, 9vw, 34px);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.8px;
  color: var(--volt-lime);
  white-space: nowrap;
  margin-top: 6px;
}

.hero-rec-compare {
  margin-top: 4px;
  font-size: 13px;
  color: var(--text-muted);
  white-space: nowrap;
}

.sheet-limit-plate {
  display: block;
  margin-top: 10px;
  padding: 10px 12px;
  background: var(--color-warning-bg);
  border: 1px solid rgba(255, 159, 10, 0.35);
  border-radius: var(--r-sm);
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--text-main);
}

.sheet-limit-plate b {
  color: var(--color-warning);
}

.other-cards {
  margin-top: 14px;
  background: var(--bg-surface);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
}

.other-cards-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  min-height: 44px;
  padding: 10px 14px;
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 700;
  color: var(--text-main);
  cursor: pointer;
  list-style: none;
}

.other-cards-summary::-webkit-details-marker {
  display: none;
}

.other-cards-summary::after {
  content: '';
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg);
  transition: transform 0.2s ease;
}

.other-cards[open] .other-cards-summary::after {
  transform: rotate(-135deg);
}

.other-cards .ranked-mini-list {
  padding: 0 14px 10px;
}

.sheet-footnote {
  display: block;
  margin-top: 14px;
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--text-dim);
}

/* Пояснение под заголовком решения (6.1а, 6.2, 6.2а). Нижний отступ обязателен:
   замер на 320 и 390 давал 0 px между последней строкой текста и кнопкой «Закрыть» —
   палец накрывал строку, а сама кнопка читалась как часть абзаца. Сверху 8 px,
   снизу 14 px: главное действие экрана должно быть отделено от объяснения. */
.sheet-no-card-note {
  display: block;
  margin-top: 8px;
  margin-bottom: 14px;
  font-size: 13px;
  line-height: 1.4;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   УЗКИЕ ЭКРАНЫ (≤359px) — одним блоком в конце раздела
   -------------------------------------------------------------------------- */
@media (max-width: 359px) {
  /* Кегль НЕ уменьшаем: 10.5px — это уже нечитаемо (порог 11.5px). Подпись
     переносится на вторую строку, а плитка становится выше — так «Вставить
     ссылку» помещается в колонку шириной 82px. */
  .scan-fallback-chip {
    padding: 7px 2px;
  }

  .btn-scan-main {
    font-size: 15px;
  }

  /* «Наведите на QR кассы» не влезало в строку с двумя кнопками камеры
     (не хватало 3px) и резалось многоточием. */
  .scanner-head-row .transactions-title {
    font-size: 17px;
  }

  .scanner-frame-hint {
    font-size: 11.5px;
    left: 6px;
    right: 6px;
  }
}

/* --------------------------------------------------------------------------
   СОСТОЯНИЯ ОШИБОК (ТЗ 11)
   Лист тот же, что у шторки решения и диалога оплаты (.decision-sheet-content),
   поэтому здесь только содержимое: значок, заголовок «что произошло», текст
   «что делать» и одна-две кнопки. Ни одного нового токена — всё с палитры
   :root, иначе объявление молча выбросит браузер (проверка дизайн-токенов).
   -------------------------------------------------------------------------- */
.error-sheet-content {
  text-align: left;
}

.error-sheet-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-bottom: 12px;
  border-radius: var(--r-sm);
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

/* Кнопки состояния идут столбиком с одинаковым шагом — как ответы диалога
   подтверждения: в ряд на 320px «Открыть в браузере» и «Понятно» не влезают,
   а перенос ряда оставляет одинокую кнопку с дырой во всю ширину. */
#error-state-content .btn-sheet-primary,
#error-state-content .btn-sheet-secondary {
  width: 100%;
  margin-bottom: 10px;
}

/* --------------------------------------------------------------------------
   ПЛАШКИ СОСТОЯНИЙ ВНУТРИ ШТОРКИ РАСЧЁТА
   «Не узнали магазин» и «Категории за прошлый месяц» (ТЗ 11): ситуация уже
   на экране расчёта, и уводить с него отдельным листом значит прятать ответ,
   за которым человек и пришёл.
   -------------------------------------------------------------------------- */
.sheet-notice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  margin: 0 0 10px 0;
  padding: 10px 12px;
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-sm);
  background: var(--bg-card);
}

.sheet-notice-title {
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  line-height: 1.25;
  color: var(--text-main);
}

.sheet-notice-text {
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text-muted);
}

/* Цель пальца: 34px по высоте даже там, где текст кнопки в одну строку. */
.btn-sheet-notice {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  margin-top: 4px;
  padding: 7px 14px;
  border: 1px solid var(--volt-lime);
  border-radius: var(--r-pill);
  background: var(--volt-lime-bg);
  color: var(--volt-lime);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 800;
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   ЗАГЛУШКА КАМЕРЫ: РЯД КНОПОК (ТЗ 11, «Камера выключена»)
   -------------------------------------------------------------------------- */
.camera-blocked-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 4px;
}

/* Второй выход из состояния не спорит с первым за внимание, но остаётся
   целью пальца: та же высота, другой вес. */
.btn-camera-ghost {
  background: transparent;
  border: 1px solid var(--border-glass-bright);
  color: var(--text-main);
}

.btn-camera-ghost[hidden],
.btn-camera-retry[hidden] {
  display: none;
}

/* ТЗ 12.3: служебного блока в продовой сборке нет. `[hidden]` из таблицы
   браузера проигрывает любому своему `display`, поэтому правило явное. */
.profile-service-block[hidden] {
  display: none;
}

/* --------------------------------------------------------------------------
   ЛИСТ РАЗБОРА СКРИНШОТА КАТЕГОРИЙ (ТЗ 10.2)
   Банк, который не прочитался, ВЫБИРАЕТ человек: список банков — цель пальца,
   а не декорация, поэтому 38px и перенос по ширине, а не горизонтальный ряд.
   -------------------------------------------------------------------------- */
.screenshot-bank-card {
  background: var(--bg-card-elevated);
  padding: 12px 14px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-glass);
  margin-bottom: 16px;
}

.screenshot-bank-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.screenshot-bank-option {
  min-height: 38px;
  padding: 9px 14px;
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-pill);
  background: var(--bg-card);
  color: var(--text-main);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  cursor: pointer;
}

.screenshot-bank-option.bank-option-chosen {
  background: var(--volt-lime);
  border-color: var(--volt-lime);
  color: var(--volt-text);
}

.screenshot-cats-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 10px;
}

.screenshot-cats-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 18px;
}

.category-confirm-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-height: 44px;
  padding: 10px 14px;
  background: var(--bg-card);
  border-radius: var(--r-sm);
  border: 1px solid var(--border-glass);
  cursor: pointer;
}

.category-confirm-left {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.category-confirm-name {
  font-size: 14px;
  font-weight: 500;
  color: var(--text-main);
}

.screenshot-cat-check {
  width: 18px;
  height: 18px;
  accent-color: var(--volt-lime);
  flex: none;
}

/* Ставка, которую НЕ прочитали, не притворяется ставкой: другой цвет, слова
   вместо числа. Подставленные «5%» человек утверждал бы своей же кнопкой. */
.chip-rate-unknown {
  background: transparent;
  border: 1px dashed var(--border-glass-bright);
  color: var(--text-muted);
  font-weight: 600;
  white-space: nowrap;
}

/* Погашенная главная кнопка: банк не выбран — сохранять некуда. */
.btn-sheet-primary[disabled] {
  opacity: 0.45;
  cursor: default;
}

/* ============================================================
   ОБУЧАЮЩИЕ ПОДСКАЗКИ (ТЗ 8) И ТУЛТИПЫ «?» (ТЗ 9)

   Правило 8.1 «подсвеченный элемент + карточка рядом, не диалог по центру»
   держится на двух узлах: .coach-spot — дырка в затемнении ровно по элементу
   (затемнение рисует его же box-shadow, а не отдельный слой: так «дырка»
   гарантированно совпадает с подсветкой), .coach-card — карточка, которой
   координаты ставит placeCard из js/engine/coachmarks.js с учётом краёв экрана.

   Слой лежит НИЖЕ онбординга (9999) и справки (9998) сознательно: правило
   «не запускаем поверх онбординга» продублировано порядком слоёв, чтобы даже
   ошибка в условии показа не дала двух обучений сразу.
   ============================================================ */

.coach-layer,
.tip-layer {
  position: fixed;
  inset: 0;
  display: none;
}

.coach-layer { z-index: 9500; }
.tip-layer { z-index: 9600; }

.coach-layer.coach-visible,
.tip-layer.coach-visible { display: block; }

.coach-spot {
  position: fixed;
  border-radius: 14px;
  border: 2px solid var(--volt-lime);
  box-shadow: 0 0 0 9999px rgba(7, 9, 14, 0.82);
  pointer-events: none;
}

.coach-card,
.tip-card {
  position: fixed;
  /* Ширина зажата экраном: на 320 это 296px, и карточка не может вылезти за
     край даже у элемента, стоящего у самой кромки. */
  width: min(320px, calc(100vw - 24px));
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-sm);
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55);
}

.coach-counter {
  font-size: 12px;
  font-weight: 600;
  color: var(--volt-lime);
  letter-spacing: 0.2px;
}

.coach-card-title,
.tip-card-title {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 800;
  line-height: 1.25;
  color: var(--text-main);
}

.tip-card-title { font-size: 15px; }

.coach-card-text,
.tip-card-text {
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--text-muted);
}

.btn-coach-next {
  margin-top: 6px;
  min-height: 44px;
  padding: 11px 16px;
  background: var(--volt-lime);
  color: var(--volt-text);
  border: none;
  border-radius: var(--r-sm);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 800;
  cursor: pointer;
}

.btn-coach-secondary {
  min-height: 44px;
  padding: 11px 16px;
  background: transparent;
  color: var(--text-main);
  border: 1px solid var(--border-glass-bright);
  border-radius: var(--r-sm);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

/* «Пропустить обучение»: мелким текстом, но цель пальца полной высоты —
   правило 8.1 требует, чтобы выход был доступен ВСЕГДА. */
.btn-coach-skip {
  min-height: 32px;
  padding: 6px 8px;
  background: none;
  border: none;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 500;
  text-decoration: underline;
  cursor: pointer;
}

/* Значок «?»: видимый кружок 22px, цель пальца 32px за счёт ::after.
   Живёт внутри кнопок и кликабельных строк, поэтому своё нажатие движок
   останавливает на перехвате (capture), не давая сработать родителю.

   Вынос ::after считается от ПАДДИНГ-бокса, а не от рамки: при 22px кружке с
   бордюром 1px это 20px, поэтому -5px давали цель 30×30, а не 32×32 — замерено
   elementFromPoint по углам (18.09.2026). -6px дают ровно 32. */
.tip-btn {
  position: relative;
  /* Цель пальца шире самого кружка и заходит на соседей. Без своего слоя её
     края перекрывали блоки, идущие ниже по разметке (строка суммы на «Статах»,
     соседние колонки строки истории): нажатие туда уходило им, и замеренная
     цель падала с 32 до 22 px. */
  z-index: 2;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-left: 4px;
  border-radius: 50%;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass-bright);
  color: var(--text-muted);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  user-select: none;
  vertical-align: middle;
}

.tip-btn::after {
  content: '';
  position: absolute;
  top: -6px;
  left: -6px;
  right: -6px;
  bottom: -6px;
  border-radius: 50%;
}

/* Кнопка-пилюля с «?» внутри держит подпись одной строкой: на 320 значок
   переносился на вторую строку ВНУТРИ кнопки, и она становилась двухэтажной
   (замер 18.09.2026, «+ Скриншот» на экране «Карты»). */
.btn-add-card-pill {
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   ЭКРАНЫ СВОДОК (ТЗ 14.3 неделя, 14.4 месяц, 14.5 год, 14.6 план месяца)

   Одна колонка на любой ширине. Вторая колонка под крупное число здесь
   запрещена сознательно: суммы у живого человека четырёх-семизначные
   («1 250 000 ₽» с white-space:nowrap — это ~110px), и на 320px она
   возвращает горизонтальную прокрутку всей страницы.

   Все узкоэкранные переопределения — ОДНИМ блоком в конце этого раздела:
   медиазапрос не поднимает специфичность, и правка, записанная выше базового
   правила, молча проигрывает ему по порядку (поймано 11.09.2026 на .bank-chip).
   -------------------------------------------------------------------------- */

/* Вход со вкладки «Статистика» */
.summary-entry-row {
  display: flex;
  gap: 8px;
  margin-bottom: 22px;
}

.summary-entry-btn {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 40px;
  padding: 0 10px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  color: var(--text-main);
  font-family: var(--font-display);
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}

.summary-entry-btn:active {
  border-color: var(--volt-lime);
}

/* Переключатель вида внутри листа. Прокрутка вбок здесь ЗАДУМАНА (помечена
   data-scroll-x): на 320 четыре пилюли могут не встать в строку, и уехать
   должен сам ряд, а не лист. */
.summary-view-pills {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  margin-bottom: 14px;
  padding-bottom: 2px;
}

.summary-view-pills::-webkit-scrollbar {
  display: none;
}

.summary-view-btn {
  flex: 0 0 auto;
  min-height: 36px;
  padding: 0 14px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-pill);
  color: var(--text-muted);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}

.summary-view-btn.pill-active {
  background: var(--volt-lime);
  border-color: var(--volt-lime);
  color: var(--volt-text);
}

/* Содержимое вида */
.summary-head {
  font-family: var(--font-display);
  font-size: clamp(19px, 6.2vw, 24px);
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.4px;
  color: var(--text-main);
}

.summary-sub {
  margin-top: 6px;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--text-muted);
}

.summary-block-title {
  margin-top: 16px;
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  color: var(--text-main);
}

.summary-rows {
  margin-top: 10px;
  background: var(--bg-card);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
  overflow: hidden;
}

/* Строка источника или категории: текст слева переносится, число справа —
   никогда. min-width:0 у текста обязателен, иначе длинное название категории
   распирает flex-строку и вылезает за карточку. */
.summary-row {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 12px;
  border-top: 1px solid var(--border-glass);
}

.summary-row:first-child {
  border-top-color: transparent;
}

.summary-row-text {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 13px;
  line-height: 1.35;
  color: var(--text-main);
  overflow-wrap: anywhere;
}

.summary-row-note {
  display: block;
  margin-top: 3px;
  font-size: 11.5px;
  line-height: 1.3;
  color: var(--text-muted);
}

.summary-row-val {
  flex: 0 0 auto;
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text-main);
  white-space: nowrap;
}

.summary-row[data-source="no_card"] .summary-row-val,
.summary-row[data-source="none"] .summary-row-val {
  color: var(--text-muted);
}

/* Пара «Вернули / Мимо прошло» месяца — две СТРОКИ, а не две колонки. */
.summary-pair {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.summary-pair-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.summary-pair-label {
  font-size: 13px;
  color: var(--text-muted);
}

.summary-pair-val {
  font-family: var(--font-display);
  font-size: clamp(17px, 5.4vw, 20px);
  font-weight: 800;
  color: var(--text-main);
  white-space: nowrap;
}

.summary-good {
  color: var(--volt-lime);
}

.summary-compare {
  margin-top: 8px;
  font-size: 12.5px;
  line-height: 1.35;
  color: var(--text-muted);
}

.summary-earned {
  margin-top: 12px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--volt-lime);
  line-height: 1.35;
}

.summary-earned-loss {
  color: var(--color-warning);
}

/* Прогноз и итог месяца: единственное место, где стоит слово «около», поэтому
   блок отделён фоном — его легко отличить от измеренных чисел выше. */
.summary-forecast {
  margin-top: 14px;
  padding: 12px;
  background: var(--bg-card-elevated);
  border: 1px solid var(--border-glass);
  border-radius: var(--r-sm);
}

.summary-forecast-title {
  display: block;
  font-family: var(--font-display);
  font-size: 13.5px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text-main);
}

.summary-forecast-note {
  display: block;
  margin-top: 5px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-muted);
}

.summary-cta {
  display: block;
  width: 100%;
  min-height: 46px;
  margin-top: 12px;
  padding: 0 14px;
  background: var(--volt-lime);
  border: 1px solid var(--volt-lime);
  border-radius: var(--r-sm);
  color: var(--volt-text);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 800;
  cursor: pointer;
}

.summary-cta-ghost {
  background: var(--bg-card-elevated);
  border-color: var(--border-glass);
  color: var(--text-main);
}

@media (max-width: 359px) {
  .summary-entry-btn {
    font-size: 11.5px;
    padding: 0 6px;
  }

  .summary-view-btn {
    padding: 0 11px;
  }

  .summary-row {
    padding: 10px;
  }
}

/* Пояснение к покупкам без подходящей карты: рублей у них нет, и крупное число
   их не включает — строка стоит там, где иначе читалось бы «мимо прошло 0 ₽». */
.summary-note {
  margin-top: 8px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   ДВИЖЕНИЕ (10.10.2026, ветка feat/ui-motion)
   Только transform и opacity. Служебное движение ≤ 260 мс, счёт чисел и момент
   «деньги вернулись» ведёт js/engine/motion.js. Всё новое движение объявлено
   внутри (prefers-reduced-motion: no-preference): кому оно мешает — того оно
   не касается по построению, а общий блок в конце гасит и старое.
   Шторка решения у кассы (#decision-modal) не въезжает и не затухает, экран
   сканера не затухает: решение видно с первого кадра (решение владельца 10.10.2026).
   -------------------------------------------------------------------------- */

/* Счёт вверх: текст узла — уже финальное число (его читают тесты и скринридер),
   на время счёта он прозрачен, а кадр рисует ::after из data-motion-run.
   Ширина узла с первого кадра финальная — строка не прыгает. */
.motion-counting {
  position: relative;
  -webkit-text-fill-color: transparent;
}

.motion-counting::after {
  content: attr(data-motion-run);
  /* Пустой альтернативный текст: скринридер не читает промежуточное число.
     Браузер без этой записи берёт строку выше. */
  content: attr(data-motion-run) / "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  /* Перенос — как у самого узла: сумма под полосой копилки на 320 в две строки. */
  white-space: inherit;
  -webkit-text-fill-color: currentColor;
  pointer-events: none;
}

/* Полосы прогресса растут сдвигом (Motion.growBar), а не шириной. */
.dream-progress-bar[data-bar] {
  transition: none;
}

/* Монеты «деньги вернулись»: слой над шторками, касаний не ловит. */
.motion-coin-layer {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  z-index: 900;
  pointer-events: none;
}

.motion-coin {
  position: fixed;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #FFF6B0 0%, var(--volt-lime) 55%, var(--volt-lime-dark) 100%);
  box-shadow: 0 0 10px var(--volt-lime-glow);
  pointer-events: none;
  will-change: transform, opacity;
}

/* Копилка экрана успеха — цель, куда летят монеты. */
.reward-hero {
  display: flex;
  justify-content: center;
  margin: 2px 0 12px 0;
}

.reward-piggy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: rgba(212, 246, 56, 0.12);
  border: 1px solid rgba(212, 246, 56, 0.35);
  color: var(--volt-lime);
}

.reward-amount {
  white-space: nowrap;
}

@media (prefers-reduced-motion: no-preference) {
  /* Шторки: фон проявляется, лист въезжает снизу. */
  .decision-modal-overlay.modal-active:not(#decision-modal) {
    animation: vk-overlay-in 200ms ease-out backwards;
  }
  .decision-modal-overlay.modal-active:not(#decision-modal) > * {
    animation: vk-sheet-in 260ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
  }

  /* Выезд: класс ставит Motion.watchSheets на время ухода. Шторка видна, но
     касаний не ловит — то, что под ней, нажимается сразу. */
  .decision-modal-overlay.modal-leaving {
    display: flex;
    animation: vk-overlay-out 180ms ease-in forwards;
  }
  .decision-modal-overlay.modal-leaving,
  .decision-modal-overlay.modal-leaving * {
    pointer-events: none !important;
  }
  .decision-modal-overlay.modal-leaving > * {
    animation: vk-sheet-out 180ms ease-in forwards;
  }

  /* Вкладки: новый экран чуть поднимается и проявляется. У сканера — только
     сдвиг, без затухания: с него начинается путь у кассы. */
  .app-screen.screen-active {
    animation: vk-screen-in 220ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
  }
  #screen-scanner.screen-active {
    animation-name: vk-screen-shift;
    animation-duration: 180ms;
  }

  /* Иконка выбранной вкладки отзывается коротким толчком. */
  .nav-tab-btn.nav-active .nav-svg-icon {
    animation: vk-tab-pop 260ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  /* Отклик на нажатие у основных кнопок, где его не было. */
  .btn-sheet-secondary,
  .btn-open-bank,
  .confirm-link-row,
  .nav-svg-icon {
    transition: transform 120ms ease-out;
  }
  .btn-sheet-secondary:active,
  .btn-open-bank:active {
    transform: scale(0.98);
  }
  .confirm-link-row:active {
    transform: scale(0.97);
  }
  .nav-tab-btn:active .nav-svg-icon {
    transform: scale(0.86);
  }
}

@keyframes vk-overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes vk-overlay-out {
  from { opacity: 1; }
  to   { opacity: 0; }
}

@keyframes vk-sheet-in {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}

@keyframes vk-sheet-out {
  from { transform: translateY(0); }
  to   { transform: translateY(40%); }
}

@keyframes vk-screen-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes vk-screen-shift {
  from { transform: translateY(6px); }
  to   { transform: translateY(0); }
}

@keyframes vk-tab-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.18); }
  100% { transform: scale(1); }
}

/* Кому движение мешает — всё мгновенно, и новое, и старое (сплэш, радар,
   трофеи, переходы кнопок). 1 мс, а не none: анимации с заполнением
   встают сразу в финальное состояние, а не остаются в начальном. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}
