/* Скин страницы коннектора — дизайн-система EVStations, Direction A (светлое).
 *
 * ★★ ЭТОТ ФАЙЛ ГРУЗИТ ТОЛЬКО web/connector/index.html (замер grep -rln 04.09.2026).
 * /chargers держит СВОЮ инлайн-копию правил .conn-* (см. предупреждение ниже), поэтому
 * рескин ЗДЕСЬ на /chargers не течёт — EVStations-облик остаётся страницей коннектора,
 * список /chargers остаётся в облике TOL.Charge. Это и есть развилка бренда веб-входа,
 * разведённая по файлам, а не по среде (карточка #631, ревью владельца раунд 2).
 *
 * ⚠ ГРАНИЦА НАЗВАНА ЧЕСТНО: правила .conn-* / .status-badge ЕЩЁ РАЗ лежат инлайном в
 * web/chargers/index.html. Это вторая поверхность одного знания, и она названа, не скрыта.
 * Классы эмитит ОДИН рендерер (connector-view.js, ADR-0337 Р-2) — расходится не разметка, а
 * СКИН, и расходится намеренно. Правя здесь, /chargers не трогаешь; правя там — сюда.
 *
 * 🔴 ЦВЕТ: cyan/blue взяты из LIVE-палитры EVStations (tokens_LIVE_20260904.css, знак логотипа,
 * обновл. 29.08) — cyan #00C9E1 / blue #2265AF. Устаревшие из архива (#1ABDC2/#3A57CA) НЕ
 * использованы. Остальное (ink/paper, статус #2E8E5A, геометрия 4/8px) — из бандла zip.
 *
 * ⚠ ШРИФТ — SELF-HOST СО СВОЕГО ORIGIN, не веб-шрифты с googleapis. Бренд EVStations несёт
 * Manrope (дисплей) / Inter (текст) / JetBrains Mono (моно); ронять их в системный стек =
 * ронять бренд (решение координатора 04.09). Но и чужой origin эта страница НЕ тянет — это её
 * инвариант (TA-0229 §1.3, #621: fonts.googleapis.com названа ПЕРВОЙ статьёй цены холодного
 * старта, три лишних TLS-рукопожатия в мобильном WebView). Разрешение обоих требований —
 * self-host: файлы лежат в `/assets/fonts/` НА ЭТОМ ЖЕ origin (charge.tol.kz), лишнего
 * рукопожатия нет. Начертания субсечены (Latin+Cyrillic+₸/№/стрелки) и variable (все веса в
 * одном файле): Manrope 31 КБ + Inter 63 КБ + JetBrains 44 КБ = ~140 КБ, `font-display:swap`
 * ⇒ первый рендер НЕ блокируется (текст рисуется системным fallback и подменяется). Стеки
 * ниже держат тот же fallback на время загрузки. Субсет-исходники — variable-TTF на диске
 * (Manrope/Inter — Windows-шрифты, JetBrains — web/assets/kp/), пересобрать: fontTools.subset.
 */
@font-face {
  font-family: "Manrope"; font-style: normal; font-weight: 200 800; font-display: swap;
  src: url("/assets/fonts/manrope-var.woff2") format("woff2");
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("/assets/fonts/inter-var.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 100 800; font-display: swap;
  src: url("/assets/fonts/jbmono-var.woff2") format("woff2");
}

:root {
  /* Brand accent — LIVE (tokens_LIVE_20260904.css) */
  --ev-cyan-500: #00C9E1;
  --ev-blue-500: #2265AF;
  /* Ink / paper / line — zip tokens.css (Direction A) */
  --ev-ink-900: #0E0F0D;
  --ev-ink-700: #2C2E2A;
  --ev-ink-600: #494B43;
  --ev-ink-500: #6A6C61;
  --ev-ink-400: #94968B;
  --ev-ink-300: #C9CAC2;
  --ev-ink-200: #E5E5DF;
  --ev-ink-100: #F2F2EE;
  --ev-paper:   #FAFAF6;
  --ev-paper-2: #F4F4EE;
  --status-ok:     #2E8E5A;
  --status-warn:   #C58A14;
  --status-error:  #C0392B;
  --status-offline: var(--ev-ink-400);
  --status-live:   var(--ev-cyan-500);

  /* ── Цвета СТАТУС-ПЛАШКИ: рамка+шрифт, без заливки (владелец, 04.09) ────────────────────
     🔴 КОНТРАСТ ЗАМЕРЕН, А НЕ НА ГЛАЗ (WCAG, текст на поверхности карточки). Базовые токены
     палитры как МЕЛКИЙ ТЕКСТ на белом AA не держат (--status-ok 4.09:1, --status-warn 2.99:1,
     --status-offline 3.00:1) ⇒ для текста берутся производные оттенки ТЕХ ЖЕ токенов, а серый —
     готовая ступень шкалы ink. Значения ниже — измеренные, не подобранные на глаз. */
  --st-ok-fg:      #24734A;   /* от --status-ok · 5.79:1 на #FFFFFF */
  --st-warn-fg:    #8A6110;   /* от --status-warn · 5.53:1 */
  --st-error-fg:   #C0392B;   /* --status-error как есть · 5.44:1 */
  --st-offline-fg: #6A6C61;   /* --ev-ink-500 (шкала) · 5.34:1 */
  --st-blue-fg:    #2265AF;   /* --ev-blue-500 LIVE · 5.92:1 */
  --st-ok-fill-bg: #24734A;   /* Preparing — единственная заливка */
  --st-ok-fill-fg: #FFFFFF;   /* белый на заливке · 5.79:1 */

  --bg-app:       var(--ev-paper);
  --bg-surface:   #FFFFFF;
  --bg-surface-2: var(--ev-paper-2);
  --fg-1:     var(--ev-ink-900);
  --fg-2:     var(--ev-ink-600);
  --fg-3:     var(--ev-ink-400);
  --fg-muted: var(--ev-ink-500);
  --line-1: var(--ev-ink-200);
  --line-2: var(--ev-ink-300);

  --font-display: "Manrope", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body:    "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --radius-sm: 4px;
  --radius-button: 4px;
  --radius-card: 8px;
  --ease-out: cubic-bezier(0.2, 0.7, 0.3, 1);
}

/* Тёмная тема (TMA colorScheme=dark, атрибут ставит PlatformAdapter.theme()).
   Мокап нарисован в Direction A (светлом); тёмная — не регрессировать TMA-dark: те же
   роли токенов, поверхности на тёмном инке, cyan чуть ярче для контраста (DS Direction B). */
html[data-bs-theme="dark"] {
  --ev-cyan-500: #35D6EC;
  --bg-app:       #0E0F0D;
  --bg-surface:   #1A1C19;
  --bg-surface-2: #161714;
  --fg-1:     #F4F4EE;
  --fg-2:     #C9CAC2;
  --fg-3:     #94968B;
  --fg-muted: #A8AA9F;
  --line-1: #2C2E2A;
  --line-2: #3A3C37;

  /* Те же роли на тёмном — контраст измерен на поверхности карточки #1A1C19 (все ≥4.5:1). */
  --st-ok-fg:      #5FBF8A;   /* 7.60:1 */
  --st-warn-fg:    #E0A62F;   /* 7.90:1 */
  --st-error-fg:   #E8776B;   /* 5.95:1 */
  --st-offline-fg: #94968B;   /* --ev-ink-400 · 5.71:1 */
  --st-blue-fg:    #7E96E0;   /* --ev-dark-blue-fg (DS: «blue on dark, passes AA») · 5.99:1 */
  --st-ok-fill-bg: #5FBF8A;
  --st-ok-fill-fg: #1A1C19;   /* ink на заливке · 7.60:1 */
}

/* ── оболочка мини-аппа: полоса под «Назад» (#635, замечание владельца 07.09.2026) ──────────
   В Telegram DOM-кнопка `#backBtn` скрыта (platform.js::back() → нативная BackButton), а
   инлайн-правило страниц /connector, /profile, /history `.topbar { min-height:32px;
   margin-bottom:14px }` резервировало под неё пустые 46 px над заголовком (кадр iPhone
   /connector/1001). Правило ОДНО на всех потребителей и живёт здесь; ключ — `data-identity`,
   который каждая страница ставит из TolPlatform.getIdentity().kind. В вебе (кнопка в DOM)
   ничего не меняется. Заголовок страницы (/profile «Профиль», /history «Мои зарядки») несёт
   отступ сам, чтобы не прилипнуть к первой карточке. Сторож: tests/test_631_connector_e2.py. */
html[data-identity="telegram"] .topbar { min-height: 0; margin-bottom: 0; }
html[data-identity="telegram"] .topbar > .page-title { margin-bottom: 14px; }

/* ── строка коннектора = карточка DS ──────────────────────────────────────────────────── */
.conn-row {
  padding: 14px 15px;
  background: var(--bg-surface);
  border: 1px solid var(--line-1);
  border-radius: var(--radius-card);
  margin-bottom: 6px;
}
/* ★ РАСКЛАДКА СТРОКИ ДЕТЕРМИНИРОВАНА, А НЕ «КАК ВЛЕЗЕТ» (владелец, 04.09): статус остаётся НА
   СТРОКЕ С НОМЕРОМ, тариф уезжает на СВОЮ строку. Держится `order` + `flex-basis:100%` у
   тарифа: он всегда переносится целиком, поэтому плашка статуса НЕ «плавает» между строками
   при длинном тарифе (живой день/ночь: «день: 60 ₸/кВт*ч, ночь: 50 ₸/кВт*ч (…)»).
   ⚠ Раскладка сделана ТОЛЬКО CSS этой страницы: разметку эмитит общий connector-view.js, и
   правка его порядка узлов уехала бы в /chargers. Здесь — свой скин, чужой экран не трогаем. */
.conn-main {
  display: flex;
  align-items: center;
  gap: 6px 10px;
  flex-wrap: wrap;
}
.conn-main > .conn-code { order: 0; }
.conn-main > .conn-type { order: 1; }
.conn-main > .status-badge,
.conn-main > .conn-until,
.conn-main > .conn-session-info { order: 2; }
.conn-main > .conn-tariff { order: 3; flex: 0 0 100%; }
.conn-tariff:empty { display: none; } /* #643: хост /connector передаёт tariffText:'' в ходе/итоге (TA-0247 §5) */
.conn-details {
  display: none;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line-1);
}
.conn-row.expanded .conn-details { display: block; }

/* Состояние «готов к запуску» — следствие серверного вердикта action==='start'
   (ставит рендерер классом .status-preparing на строке), не догадка фронта. */
.conn-row.status-preparing {
  background: var(--bg-surface);
  border-color: color-mix(in srgb, var(--status-ok) 45%, var(--line-1));
}

.conn-code {
  font-family: var(--font-mono);
  font-size: 1rem;
  font-weight: 600;
  color: var(--fg-1);
  min-width: 50px;
  letter-spacing: .02em;
  font-variant-numeric: tabular-nums;
}
.conn-type {
  font-size: .8rem;
  color: var(--fg-2);
  flex: 1;
  min-width: 88px;
}
.conn-tariff {
  font-size: .82rem;
  color: var(--fg-1);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.conn-power { font-size: .74rem; color: var(--fg-3); }
.conn-session-info {
  font-size: .7rem;
  font-weight: 600;
  color: var(--status-warn);
  white-space: nowrap;
}
/* «до HH:MM» справа от плашки хода (#658 п. 10.5, модуль `untilHtml`) — тем же тёплым цветом, что плашка. */
.conn-until { font-size: .7rem; font-weight: 600; color: var(--st-warn-fg); white-space: nowrap; }

/* SOC-бар (ветка charging рендерера) */
.soc-bar-wrap { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.soc-bar { flex: 1; height: 8px; background: var(--line-1); border-radius: 4px; overflow: hidden; }
.soc-bar-fill { position: relative; overflow: hidden; height: 100%; background: var(--ev-cyan-500); border-radius: 4px; transition: width .4s; }
.soc-label {
  font-size: .78rem; font-weight: 700; color: var(--fg-1);
  min-width: 34px; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.conn-detail-hint { font-size: .8rem; color: var(--fg-2); line-height: 1.45; }
.conn-detail-power { font-size: .85rem; font-weight: 700; color: var(--fg-1); margin-bottom: 4px; }

/* ── статус-бейдж: бордер-пилюля DS ───────────────────────────────────────────────────────
   Рендерер эмитит класс из statusClass(status_ocpp). «Готов к запуску» — это статус
   `preparing` (коннектор вставлен, action='start'), он и есть зелёный ready-бейдж. Коллизии
   с `available` (свободен, бледный) нет: ready — насыщенный зелёный success (#2E8E5A),
   available — нейтральный. Различимы в одной легенде (ревью владельца п.1). */
/* 🔴 БАЗОВОЕ ПРАВИЛО — СЕРОЕ, И ЭТО БЕЗОПАСНЫЙ ДЕФОЛТ, А НЕ ОФОРМЛЕНИЕ. Множество статусов
   ОТКРЫТО: `status_ocpp` — text без CHECK, наполняют станции (инвариант направления, урок
   остановленной #622). Статус, которого мы не знаем, обязан выглядеть НЕЙТРАЛЬНО, а не
   унаследовать чужой цвет: рендерер отдаёт таким `unknown`, и оба попадают сюда.
   Рамка = currentColor ⇒ у каждого состояния рамка и шрифт ОДНОГО цвета, заливки нет
   (решение владельца 04.09). Единственное исключение с заливкой — `preparing`. */
.status-badge {
  font-family: var(--font-mono);
  font-size: .625rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  color: var(--st-offline-fg);        /* ← безопасный дефолт для НЕизвестного статуса */
  border: 1px solid currentColor;
  background: transparent;
}
.status-badge.available { color: var(--st-ok-fg); }
.status-badge.charging,
.status-badge.finishing,
.status-badge.occupied  { color: var(--st-warn-fg); }
.status-badge.faulted   { color: var(--st-error-fg); }
.status-badge.offline,
.status-badge.unknown   { color: var(--st-offline-fg); }

/* Уточнения ДОБАВОЧНЫМ классом рендерера — идут ПОСЛЕ базовых, поэтому перебивают их.
   `Unavailable` приезжает как `faulted unavailable`, `Finished` — как `unknown finished`:
   у /chargers остаётся прежний первый токен и прежний вид, здесь — свой цвет. */
.status-badge.unavailable { color: var(--st-offline-fg); }
.status-badge.finished    { color: var(--st-blue-fg); }

/* Preparing — ЕДИНСТВЕННОЕ состояние с заливкой (исключение, санкционировано владельцем). */
.status-badge.preparing {
  color: var(--st-ok-fill-fg);
  background: var(--st-ok-fill-bg);
  border-color: var(--st-ok-fill-bg);
}

/* ── цена + метка тарифа (условная, серверная: «Индивидуальный»/«Общий») ──────────────── */
.pay-price { display: flex; align-items: baseline; gap: 8px; margin: 2px 0 3px; }
.pay-price .amt {
  font-family: var(--font-display); font-size: 2.4rem; font-weight: 800;
  letter-spacing: -.03em; color: var(--fg-1); font-variant-numeric: tabular-nums; line-height: 1;
}
.pay-price .unit { font-size: .82rem; color: var(--fg-2); }
/* ⚠ Многоставочный тариф (день/ночь) крупной ценой НЕ рисуется вовсе: крупным кеглем он выдал
   бы первую ставку за единственную, а строкой он уже есть в шапке коннектора. Дом решения —
   `_split_tariff_display` на сервере (там же разбор и замер). */
.tariff-label { font-size: .85rem; color: var(--fg-1); font-weight: 600; margin-bottom: 14px; }

/* ── CTA-система DS (cta.css донора, значения побайтно; primary A = заливка ink) ───────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  font-family: var(--font-body); font-weight: 600; letter-spacing: -.005em;
  border-radius: var(--radius-button); border: 1px solid transparent;
  cursor: pointer; white-space: nowrap; text-decoration: none; box-sizing: border-box;
  transition: background .12s var(--ease-out), color .12s var(--ease-out),
    border .12s var(--ease-out), transform 80ms var(--ease-out);
}
.btn:active { transform: scale(.985); }
.btn:disabled { opacity: .4; cursor: not-allowed; transform: none; }
.btn:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(0,201,225,.45); }
.btn--lg { padding: 16px 26px; font-size: .95rem; font-weight: 700; }
.btn--block { width: 100%; }
.btn--primary { background: var(--ev-ink-900); color: #fff; }
.btn--primary:hover { background: var(--ev-ink-700); }
html[data-bs-theme="dark"] .btn--primary { background: #fff; color: var(--ev-ink-900); }
.btn--secondary { background: transparent; color: var(--fg-1); border-color: var(--fg-1); }
.btn--secondary:hover { background: rgba(14,15,13,.05); }
html[data-bs-theme="dark"] .btn--secondary:hover { background: rgba(255,255,255,.06); }
.btn--tertiary { background: transparent; color: var(--ev-ink-700); border-color: transparent; padding: 10px 0 2px; font-weight: 600; font-size: .875rem; }
html[data-bs-theme="dark"] .btn--tertiary { color: var(--fg-2); }
.btn--tertiary:hover { color: var(--fg-1); }
.btn__arrow { font-family: var(--font-mono); font-size: .95em; transition: transform .16s var(--ease-out); }
.btn:hover .btn__arrow { transform: translateX(3px); }
.stack > * + * { margin-top: 8px; }

.fineprint { font-size: .78rem; color: var(--fg-muted); line-height: 1.5; margin-top: 12px; white-space: pre-line; }

/* ── экран ожидания оплаты и старта ───────────────────────────────────────────────────── */
.wait-box { text-align: center; padding: 8px 4px 2px; }
/* ── Фирменный кружок ожидания — ОДИН компонент на все состояния экрана (#643 п. 9, владелец
   07.09: «слева от текста фирменный кружок, который крутится и отображает, что что-то
   происходит»). `.spin` — строчный, размер по высоте текста (1em): кольцо blue-500 с бегущим
   сегментом cyan-500 (пара EVStations); `.spin--lg` — блочный 34 px для «Ждём подтверждения…»
   и «Запускаем вашу зарядку…» (прежний `.spinner`, теперь тот же компонент). На тёмной primary-
   кнопке дорожка — полупрозрачный cyan: blue-500 на ink-900 не читается (2.3:1).
   Кнопка с кружком disabled (немеет), но не гаснет до .4 — иначе гас бы и сам кружок.
   prefers-reduced-motion — статичное кольцо с сегментом, без вращения. */
.spin {
  display: inline-block; width: 1em; height: 1em; box-sizing: border-box; flex: 0 0 auto;
  border: 2px solid var(--ev-blue-500); border-top-color: var(--ev-cyan-500); border-radius: 50%;
  vertical-align: -.15em; animation: conn-spin .9s linear infinite;
}
.spin--lg { display: block; width: 34px; height: 34px; border-width: 3px; margin: 6px auto 12px; }
.btn--primary .spin { border-color: rgba(0,201,225,.32); border-top-color: var(--ev-cyan-500); }
.btn.is-busy:disabled { opacity: .75; cursor: progress; }
@keyframes conn-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation: none; } }
.wait-title { font-family: var(--font-display); font-weight: 700; font-size: 1rem; letter-spacing: -.01em; margin-bottom: 4px; color: var(--fg-1); }
.wait-sub { font-size: .82rem; color: var(--fg-2); }
.wait-steps { list-style: none; margin: 16px 0 0; padding: 0; text-align: left; }
.wait-steps li { display: flex; align-items: center; gap: 10px; padding: 6px 0; font-size: .85rem; color: var(--fg-2); }
.wait-steps li .dot { width: 15px; height: 15px; border-radius: 50%; flex: 0 0 auto; border: 2px solid var(--line-2); }
.wait-steps li.done { color: var(--status-ok); }
.wait-steps li.done .dot { background: rgba(46,142,90,.12); border-color: var(--status-ok); }
.wait-steps li.now { color: var(--fg-1); font-weight: 600; }
.wait-steps li.now .dot { border-color: var(--ev-cyan-500); }
.wait-timer {
  font-family: var(--font-mono); font-size: .75rem; color: var(--status-warn);
  background: rgba(197,138,20,.08); border: 1px solid rgba(197,138,20,.25);
  border-radius: var(--radius-sm); padding: 7px 10px; margin-top: 14px; font-variant-numeric: tabular-nums;
}

/* ── edge-case отказа по балансу (не основное состояние; текст без витринных ярлыков) ──── */
.deny-box {
  background: var(--bg-surface-2); border: 1px solid var(--line-1);
  border-radius: var(--radius-card); padding: 10px 12px; font-size: .82rem; color: var(--fg-2);
  margin-top: 12px;
}

/* ── пересылка (путь 4 + шеринг) ──────────────────────────────────────────────────────── */
/* Возврат «Оплатить самому ↑» — тот же tertiary-линк, что и вход в пересылку; отличается
   только направлением стрелки и, соответственно, направлением hover-сдвига. Правило
   аддитивное: классов .share-back/.btn__arrow--up на /chargers нет, там оно инертно. */
.share-back { padding: 2px 0 6px; }
.btn__arrow--up { display: inline-block; }
.btn:hover .btn__arrow--up { transform: translateY(-3px); }
.share-lede { font-family: var(--font-display); font-size: 1rem; font-weight: 700; letter-spacing: -.01em; color: var(--fg-1); margin: 2px 0 4px; }
.share-sub { font-size: .82rem; color: var(--fg-2); margin: 0 0 12px; }
.share-row {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  background: var(--bg-surface); border: 1px solid var(--line-1); border-radius: var(--radius-card);
  padding: 11px 13px; font: inherit; font-size: .875rem; font-weight: 600; color: var(--fg-1);
  cursor: pointer; margin-bottom: 8px;
}
.share-row .ic {
  width: 30px; height: 30px; border-radius: var(--radius-sm); flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: .68rem; font-weight: 600; color: #fff;
}
.share-row .ic.tg { background: #229ED9; }
.share-row .ic.wa { background: #25D366; }
.share-row .ic.cp { background: var(--fg-2); }
.share-row small { display: block; font-weight: 400; font-size: .74rem; color: var(--fg-3); font-family: var(--font-body); }
.fwd-card {
  background: var(--bg-surface); border: 1px solid var(--line-1);
  border-left: 3px solid var(--ev-blue-500); border-radius: var(--radius-card);
  padding: 11px 13px; margin: 12px 0 2px;
}
.fwd-card .from { font-family: var(--font-mono); font-size: .68rem; color: var(--ev-blue-500); font-weight: 600; letter-spacing: .03em; margin-bottom: 4px; }
.fwd-card .msg { font-size: .82rem; color: var(--fg-1); line-height: 1.5; }
.fwd-card .inline-btn { margin-top: 9px; background: var(--ev-ink-900); color: #fff; border-radius: var(--radius-button); padding: 9px 13px; font-size: .8rem; font-weight: 700; text-align: center; }
html[data-bs-theme="dark"] .fwd-card .inline-btn { background: #fff; color: var(--ev-ink-900); }

/* ── ход зарядки внутри тела коннектора (#643, TA-0247 §2/§6; мокап ta0247_643_charging_v2) ──
   Блок СТРАНИЧНЫЙ (эмитит /connector/index.html), классы .prog-* свои — модуль
   connector-view.js их не знает, на /chargers и /app правила инертны. Состояния: идёт · итог ·
   чужая · запускаем. */
.prog { padding-top: 4px; }
/* герой SOC */
.prog-hero { margin-bottom: 12px; }
.prog-hero-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.prog-soc-big { font-family: var(--font-display); font-size: 2.25rem; font-weight: 800; letter-spacing: -.03em; line-height: 1; color: var(--fg-1); font-variant-numeric: tabular-nums; }
.prog-soc-big small { font-family: var(--font-body); font-size: 1rem; font-weight: 600; color: var(--fg-3); margin-left: 3px; }
.prog-soc-goal { font-size: .8rem; color: var(--fg-3); text-align: right; font-variant-numeric: tabular-nums; }
.prog-soc-goal b { color: var(--fg-1); font-weight: 700; }
.prog-soc-bar { position: relative; height: 12px; background: var(--line-1); border-radius: 6px; overflow: visible; }
.prog-soc-fill { position: relative; overflow: hidden; height: 100%; background: linear-gradient(90deg, var(--ev-blue-500), var(--ev-cyan-500)); border-radius: 6px; transition: width .4s var(--ease-out); }
.prog-soc-fill.done { background: var(--st-ok-fg); }
/* #643 п. 11 (владелец 07.09: «полоску SOC, если она со значениями, сделай пульсирующую слева направо»):
   бегущий блик поверх ЗАПОЛНЕННОЙ части — и у героя своей сессии, и у публичной полосы чужой.
   Псевдоэлемент внутри заливки (overflow:hidden режет по её краю) ⇒ пустая заливка (0 %) блика не даёт;
   анимируется только transform — без перерисовки layout. Итог (.done) — статичен, prefers-reduced-motion — статично. */
.prog-soc-fill::after, .soc-bar-fill::after { content: ""; position: absolute; top: 0; bottom: 0; left: -45%; width: 45%;
  background: linear-gradient(90deg, rgba(0,201,225,0) 0%, rgba(53,214,236,.45) 35%, rgba(255,255,255,.6) 50%, rgba(53,214,236,.45) 65%, rgba(0,201,225,0) 100%);
  animation: soc-shine 2s ease-in-out infinite; will-change: transform; pointer-events: none; }
.prog-soc-fill.done::after { display: none; }
@keyframes soc-shine { to { transform: translateX(322%); } }
@media (prefers-reduced-motion: reduce) { .prog-soc-fill::after, .soc-bar-fill::after { animation: none; display: none; } }
.prog-soc-start { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--fg-3); opacity: .6; }
.prog-soc-target { position: absolute; top: -4px; bottom: -4px; width: 2px; background: var(--fg-1); }
.prog-soc-target::after { content: ""; position: absolute; left: -3px; top: -4px; border: 4px solid transparent; border-top-color: var(--fg-1); }
.prog-eta { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: .78rem; color: var(--fg-3); margin-top: 8px; font-variant-numeric: tabular-nums; }
.prog-eta-end { display: inline-flex; align-items: center; gap: 5px; color: var(--fg-1); font-weight: 600; }
.prog-eta-end svg { width: 13px; height: 13px; stroke: var(--ev-blue-500); }
.prog-eta-end small { font-weight: 500; color: var(--fg-2); }
/* ряд «стрелка · кольцо» */
.prog-viz { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 10px; }
.prog-card { background: var(--bg-surface); border: 1px solid var(--line-1); border-radius: var(--radius-card); padding: 8px 10px 8px; min-width: 0; }
.prog-card-t { font-size: .68rem; color: var(--fg-3); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 2px; }
.prog-card svg { width: 100%; height: auto; display: block; overflow: visible; }
.prog-card text { font-family: var(--font-body); fill: var(--fg-3); font-size: 9px; }
.prog-card text.big { font-family: var(--font-display); font-weight: 800; font-size: 22px; fill: var(--fg-1); letter-spacing: -.02em; }
.prog-card text.sub { font-size: 9.5px; fill: var(--fg-2); }
.prog-gauge .track { fill: none; stroke: var(--line-1); stroke-width: 11; stroke-linecap: round; }
.prog-gauge .arc { fill: none; stroke: var(--ev-cyan-500); stroke-width: 11; stroke-linecap: round; }
.prog-gauge .tick { stroke: var(--line-2); stroke-width: 1; }
.prog-gauge .needle { stroke: var(--fg-1); stroke-width: 2.5; stroke-linecap: round; }
.prog-gauge .hub { fill: var(--fg-1); }
.prog-ring .track { fill: none; stroke: var(--line-1); stroke-width: 11; }
.prog-ring .arc { fill: none; stroke: var(--ev-cyan-500); stroke-width: 11; stroke-linecap: butt; transition: stroke-dasharray .4s var(--ease-out); }
.prog-ring .arc.ok { stroke: var(--st-ok-fg); }
.prog-legend { display: flex; flex-wrap: wrap; gap: 2px 10px; font-size: .72rem; color: var(--fg-2); margin-top: 4px; font-variant-numeric: tabular-nums; }
.prog-legend b { color: var(--fg-1); font-weight: 600; }
.prog-legend i { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: 4px; vertical-align: 0; background: var(--line-2); }
.prog-legend i.cyan { background: var(--ev-cyan-500); }
.prog-legend i.ok { background: var(--st-ok-fg); }
.prog-legend i.blue { background: rgba(34,101,175,.35); }
.prog-legend i.warn { background: var(--status-warn); height: 2px; vertical-align: 3px; }
/* профиль зарядки */
.prog-profile { margin-bottom: 12px; }
.prog-profile-h { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; margin-bottom: 2px; }
.prog-profile-h b { font-size: .8rem; font-weight: 700; color: var(--fg-1); }
.prog-profile-h span { font-size: .7rem; color: var(--fg-3); }
.prog-profile svg { width: 100%; height: auto; display: block; }
.prog-profile text { font-family: var(--font-body); fill: var(--fg-3); font-size: 8.5px; }
.prog-profile .grid { stroke: var(--line-1); stroke-width: 1; }
.prog-profile .bar { fill: rgba(34,101,175,.32); }
.prog-profile .power { fill: none; stroke: var(--ev-cyan-500); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.prog-profile .power-area { fill: rgba(0,201,225,.10); }
.prog-profile .tariff { fill: none; stroke: var(--status-warn); stroke-width: 1.6; stroke-dasharray: 4 3; }
.prog-profile .now { fill: var(--ev-cyan-500); stroke: var(--bg-surface); stroke-width: 2; }
/* плитки — рамкой, не заливкой (DS: карточки и статусы — рамкой) */
/* #710: левая ячейка ряда — стрелка и под ней две плашки. Карточка мощности
   больше НЕ тянется на высоту кольца (там и пустовала половина поля), остаток
   высоты добирают плашки (flex: 1) — пустого поля под датчиком не остаётся.
   На узком экране колонка не меняется: кратность ряда задана на .prog-viz и одна. */
.prog-col { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.prog-col > .prog-card { flex: 0 0 auto; }
.prog-col > .prog-cell { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; }
.prog-cell { background: var(--bg-surface); border: 1px solid var(--line-1); border-radius: var(--radius-card); padding: 8px 10px; min-width: 0; }
.prog-label { font-size: .68rem; color: var(--fg-3); text-transform: uppercase; letter-spacing: .05em; }
.prog-val { font-family: var(--font-display); font-size: 1.1rem; font-weight: 700; color: var(--fg-1); font-variant-numeric: tabular-nums; letter-spacing: -.01em; }
.prog-val small { font-family: var(--font-body); font-size: .74rem; font-weight: 500; color: var(--fg-2); margin-left: 3px; }
.prog-done { display: flex; align-items: center; gap: 8px; font-family: var(--font-display); font-weight: 700; font-size: 1rem; color: var(--st-ok-fg); border: 1px solid var(--st-ok-fg); border-radius: var(--radius-card); padding: 8px 12px; margin-bottom: 12px; }
.prog-done svg { width: 18px; height: 18px; stroke: currentColor; }
.prog-live { font-size: .76rem; color: var(--fg-2); display: flex; align-items: center; gap: 6px; margin-bottom: 12px; }
.prog-live .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--ev-cyan-500); box-shadow: 0 0 0 3px rgba(0,201,225,.18); }
.prog-foreign { font-size: .78rem; color: var(--fg-3); margin-top: 6px; }
.prog-starting { text-align: center; color: var(--fg-2); font-size: .84rem; padding: 6px 0; }
.prog-starting-sub { font-size: .76rem; color: var(--fg-3); margin-top: 2px; }
/* «Детали и чек» — раскрывающийся блок под кнопкой, без оверлея */
.prog-more { width: 100%; display: flex; justify-content: space-between; align-items: center; border: 1px solid var(--line-1); background: var(--bg-surface); color: var(--fg-1); border-radius: var(--radius-card); padding: 11px 12px; font: inherit; font-size: .875rem; font-weight: 600; cursor: pointer; margin-top: 8px; }
.prog-more .chev { font-family: var(--font-mono); color: var(--fg-3); transition: transform .16s var(--ease-out); }
.prog-more[aria-expanded="true"] .chev { transform: rotate(180deg); }
.prog-more[aria-expanded="true"] { border-radius: var(--radius-card) var(--radius-card) 0 0; }
.prog-sheet { border: 1px solid var(--line-1); border-top: 0; border-radius: 0 0 var(--radius-card) var(--radius-card); background: var(--bg-surface); padding: 4px 12px 8px; }
.prog-kv { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-top: 1px solid var(--line-1); font-size: .8rem; }
.prog-kv:first-child { border-top: 0; }
.prog-kv span { color: var(--fg-3); flex: 0 0 auto; }
.prog-kv b { font-weight: 600; color: var(--fg-1); text-align: right; font-variant-numeric: tabular-nums; }
.prog-kv b.pre { white-space: pre-line; font-weight: 500; color: var(--fg-2); }
.prog-kv b.mono { font-family: var(--font-mono); font-weight: 500; }
