/* ═══════════════════════════════════════════════════════════════════════
   GrowoAI — Shared Components
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══ Buttons — premium glass with depth ═══ */
.btn {
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-md);
  font-size: var(--text-sm); font-weight: var(--font-medium); cursor: pointer;
  border: 1px solid var(--border-secondary); background: var(--glass-bg);
  color: var(--text-primary); font-family: var(--font-sans);
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(255,255,255,0.06);
  transition:
    transform var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-normal) var(--ease-smooth),
    border-color var(--duration-normal) var(--ease-smooth),
    background var(--duration-normal) var(--ease-smooth);
}
.btn:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--bg-card-hover); border-color: var(--border-accent);
  box-shadow: var(--shadow-md), inset 0 1px 0 0 rgba(255,255,255,0.1);
  transform: translateY(-1px);
}
.btn:not(:disabled):not([aria-disabled="true"]):active { transform: scale(0.97) translateY(0); }
.btn-primary {
  background: var(--accent-gradient); border-color: transparent; color: #fff;
  box-shadow: var(--shadow-md), var(--underglow-emerald), inset 0 1px 0 0 rgba(255,255,255,0.2);
}
.btn-primary:not(:disabled):not([aria-disabled="true"]):hover {
  filter: brightness(1.08); border-color: transparent;
  box-shadow: var(--shadow-lg), var(--underglow-emerald), inset 0 1px 0 0 rgba(255,255,255,0.25);
}
.btn-danger { background: var(--danger-solid, #be123c); border-color: transparent; color: #fff;
  box-shadow: var(--shadow-md), var(--underglow-rose); } /* a11y: rose-700 — белый текст 6.28:1 (rose-600 давал 3.66:1) */
.btn-danger:not(:disabled):not([aria-disabled="true"]):hover { filter: brightness(1.1); box-shadow: var(--shadow-lg), var(--underglow-rose); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--text-secondary);
  box-shadow: none; }
.btn-ghost:not(:disabled):not([aria-disabled="true"]):hover { background: var(--bg-inset); color: var(--text-primary); box-shadow: none; transform: none; }

/* ═══ Button full-states (единый контракт всех кнопочных семейств) ═══
   Disabled: opacity .5 + cursor not-allowed, без lift/press/filter.
   Loading: aria-busy="true" — inline spinner-слот (::before, currentColor,
   адаптируется к варианту кнопки) либо явный <span class="fm-spinner">. */
button:disabled, .btn:disabled, .btn[aria-disabled="true"],
.fm-btn:disabled, .fm-btn[aria-disabled="true"] { cursor: not-allowed; }
.btn:disabled, .btn[aria-disabled="true"],
.fm-btn:disabled, .fm-btn[aria-disabled="true"] {
  opacity: 0.5; transform: none; filter: none;
}
.btn[aria-busy="true"]::before, .fm-btn[aria-busy="true"]::before {
  content: ''; width: 14px; height: 14px; flex-shrink: 0;
  border-radius: var(--radius-full);
  border: 2px solid currentColor; border-top-color: transparent;
  opacity: 0.75; animation: fmSpin 0.6s linear infinite;
}
.btn .fm-spinner, .fm-btn .fm-spinner { width: 14px; height: 14px; border-width: 2px; }

/* ═══ Cards — cinematic glass panels ═══ */
.card {
  background: var(--bg-card);
  border: 1px solid var(--border-primary); border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(255,255,255,0.06);
  position: relative;
  transition:
    transform var(--duration-normal) var(--ease-out),
    box-shadow var(--duration-normal) var(--ease-smooth),
    border-color var(--duration-normal) var(--ease-smooth);
}
.card:hover {
  transform: translateY(-2px);
  border-color: var(--border-secondary);
  box-shadow: var(--shadow-lg), inset 0 1px 0 0 rgba(255,255,255,0.08);
}
:root[data-theme="light"] .card {
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(0,0,0,0.04);
}

/* ═══ Inputs — premium focus state ═══ */
.fm-input {
  padding: 0.6rem 0.85rem; border-radius: var(--radius-md);
  border: 1px solid var(--border-input); background: var(--bg-inset);
  color: var(--text-primary); font-size: 0.875rem; font-family: var(--font-sans);
  transition: border var(--duration-fast) var(--ease-smooth),
              box-shadow var(--duration-fast) var(--ease-smooth),
              background var(--duration-fast) var(--ease-smooth);
}
.fm-input::placeholder { color: var(--text-placeholder, var(--text-muted)); }
.fm-input:not(:disabled):hover { border-color: var(--border-accent); }
.fm-input:focus {
  outline: none; border-color: var(--accent-text);
  background: var(--bg-card);
  box-shadow: 0 0 0 3px var(--accent-bg-subtle), 0 0 20px -4px var(--accent-bg-subtle);
}
.fm-input:disabled, .fm-textarea:disabled {
  opacity: 0.5; cursor: not-allowed;
}
/* Error-state: красная рамка + красный focus-ring; хинт — .fm-field-error */
.fm-input[aria-invalid="true"], .fm-input.fm-input-error,
.fm-textarea[aria-invalid="true"], .fm-textarea.fm-input-error,
select[aria-invalid="true"] {
  border-color: var(--status-error);
}
.fm-input[aria-invalid="true"]:focus, .fm-input.fm-input-error:focus,
.fm-textarea[aria-invalid="true"]:focus, .fm-textarea.fm-input-error:focus,
select[aria-invalid="true"]:focus {
  border-color: var(--status-error);
  box-shadow: 0 0 0 3px rgba(248, 113, 113, 0.18);
}
.fm-field-error, .fm-form-hint-error {
  font-size: var(--text-xs); color: var(--status-error);
  margin-top: var(--space-1); display: block;
}

/* ═══ Grid ═══ */
.grid { display: grid; gap: 1rem; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 768px) { .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } }

/* ═══ Badges — единая система: pill, weight 600, мягкие фоны ~15% альфы ═══ */
.fm-badge { display: inline-flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-2); border-radius: var(--radius-full); font-size: var(--text-xs); font-weight: var(--font-semibold); letter-spacing: 0.02em; }
.fm-badge-ok { background: rgba(16,185,129,0.15); color: var(--accent-text); }
.fm-badge-warn { background: rgba(245,158,11,0.15); color: var(--badge-warn-text, var(--status-warn)); }
.fm-badge-error { background: rgba(248,113,113,0.15); color: var(--badge-error-text, var(--status-error)); }
.fm-badge-info { background: rgba(59,130,246,0.15); color: var(--status-info); }
.fm-badge-muted { background: var(--bg-inset); color: var(--badge-muted-text, var(--text-muted)); }

/* ═══ Toast Notifications ═══
   Z-INDEX LADDER — полная карта слоёв админки (SSOT-комментарий;
   дублируется у орба в avatar.css, инварианты — tests/test_avatar_ux.py
   ::TestCornerStackingInvariants):
     content 1 < orb .fm-avatar-container 50 < mobile-topbar 150
     < sidebar(desktop) 100 / sidebar-drawer(mobile) 300
     < bottom-nav + .fm-bubble(home) 200 ≤ drawer 201
     < modal-overlay/drawer-overlay 900 ≤ tour + onboarding 950
     < command palette .fm-cp-overlay 1000 < fm-toast-container 1200
     < skip-link(a11y) 2000
     < ed-modal 9999 ≤ update-toast(base.html) 9999 < ed-toast 10000.
     (fm-toast-container 1200: тосты-ошибки из модалок/палитры обязаны быть
     видимы — на 500 они тонули под оверлеями 900-1000.)
   Углы: тосты ТОЛЬКО top-right (никогда не конкурируют с орбом в bottom-right
   по месту); орб — единственный постоянный житель bottom-right, все
   транзиентные тосты этого угла (update-toast, ed-toast, page-тосты)
   обязаны быть z ≥ 200 и сами перекрывают орб на время своего показа. */
.fm-toast-container { position: fixed; top: 1rem; right: 1rem; z-index: 1200; display: flex; flex-direction: column; gap: 0.5rem; pointer-events: none; }
.fm-toast-container > * { pointer-events: auto; }
.fm-toast {
  display: flex; align-items: center; gap: 0.625rem;
  padding: 0.875rem 1.125rem; border-radius: var(--radius-md);
  /* b743010 (perf: убрать backdrop-blur) снёс background вместе с blur —
     тост стал ПРОЗРАЧНЫМ и на десктопе читался как «плывущий овал/шар»
     (translateX-анимация + мягкая тень 32px поверх ambient-orb'ов).
     Правило перф-коммита было «blur долой, --glass-bg остаётся» —
     возвращаем плотный фон (0.96, без композитинга). */
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-lg), inset 0 1px 0 0 rgba(255,255,255,0.06);
  font-size: var(--text-sm); color: var(--text-primary); font-weight: 500;
  /* Fade + slideY на ВСЕХ экранах: никакого горизонтального «заплывания»
     (прежде translateX(40px) scale(0.95) жил на десктопе — Y-фикс 5f327b5
     закрыл только ≤1023px). */
  animation: fmToastIn 0.3s var(--ease-out);
  max-width: 380px; position: relative; overflow: hidden;
}
.fm-toast::before { content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; }
.fm-toast-success::before { background: var(--accent-gradient); }
.fm-toast-error::before { background: linear-gradient(180deg, var(--color-rose), var(--color-rose)); }
.fm-toast-info::before { background: linear-gradient(180deg, var(--status-info), var(--status-info)); }
.fm-toast-warning::before { background: linear-gradient(180deg, var(--status-warn), var(--status-warn)); }
/* Иконка — фиксированный КРУГ (border-radius:50% + фикс. размер):
   раньше «голый» цветной SVG-глиф круга на прозрачном тосте при scale
   выглядел одиночным плывущим «шаром». Теперь — чип-круг с лёгкой плашкой. */
.fm-toast-icon {
  flex-shrink: 0; width: 20px; height: 20px;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, currentColor 14%, transparent);
}
.fm-toast-icon svg { width: 12px; height: 12px; }
.fm-toast-success .fm-toast-icon { color: var(--accent-text); }
.fm-toast-error .fm-toast-icon { color: var(--color-rose); }
.fm-toast-info .fm-toast-icon { color: var(--status-info); }
.fm-toast-warning .fm-toast-icon { color: var(--color-amber); }
.fm-toast-body { flex: 1; min-width: 0; }

/* ═══ Retry-toast: причина ошибки + кнопка действия (SOTA-паттерн) ═══ */
.fm-toast-retry { align-items: flex-start; max-width: 440px; }
.fm-toast-retry .fm-toast-msg { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.fm-toast-retry .fm-toast-msg strong { font-weight: 600; }
.fm-toast-retry .fm-toast-reason { font-style: normal; font-size: var(--text-xs); color: var(--text-muted); }
.fm-toast-retry-btn {
  flex-shrink: 0; margin-top: 2px;
  padding: 0.3rem 0.75rem; border-radius: var(--radius-sm);
  border: 1px solid var(--accent-solid); background: transparent;
  color: var(--accent-text); font: inherit; font-size: var(--text-xs); font-weight: 600;
  cursor: pointer; transition: background var(--duration-fast, .15s) ease;
}
.fm-toast-retry-btn:hover { background: color-mix(in srgb, var(--accent-solid) 18%, transparent); }
.fm-toast-retry-btn:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }

/* ═══ prefers-reduced-motion: гасим ВСЕ декоративные анимации глобально ═══
   Уважение к настройке ОС — доступность SOTA-уровня. Функциональные
   переходы (hover, fade) ускоряются до мгновенных, длительные — отключаются.
   Catch-all закрывает 24 CSS-файла с infinite-анимациями (спиннеры/пульсы)
   без правки каждого. */
@media (prefers-reduced-motion: reduce) {
  .fm-orb-1, .fm-orb-2, .fm-orb-3,
  .fm-growo-orb-fallback,
  .fm-conv-more-spinner { animation: none !important; }
  .fm-toast { animation-duration: 0.01s !important; }
  .fm-cine-stagger, .fm-reveal { transition: none !important; }
  * { scroll-behavior: auto !important; }
  /* Catch-all: бесконечные анимации → 1 итерация мгновенно (спиннеры
     останавливаются, но остаются видимыми — состояние загрузки читается) */
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
.fm-toast-title { font-weight: 600; margin-bottom: 0.15rem; }
.fm-toast-msg { font-size: var(--text-xs); color: var(--text-secondary); }
.fm-toast.fade-out { animation: fmToastOut 0.3s cubic-bezier(0.4,0,0.2,1) forwards; }
/* Единая ось Y на всех экранах (desktop + mobile): горизонтального
   «заплывания» больше нет нигде. */
@keyframes fmToastIn { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: translateY(0); } }
@keyframes fmToastOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-12px); } }

/* ═══ Loading Skeletons ═══ */
/* FPS: shimmer — наложение-градиент с translateX (composite), без background-position */
/* color: transparent — плейсхолдер может заменять текст; текст-подмену не показываем */
.fm-skeleton, .fm-skeleton-card {
  position: relative;
  overflow: hidden;
  background: var(--bg-inset);
  color: transparent;
  border-radius: var(--radius-sm);
}
.fm-skeleton::after, .fm-skeleton-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.05), transparent);
  animation: fmShimmer 1.5s ease-in-out infinite;
}
@keyframes fmShimmer { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } }
/* Skeleton shapes (слиты из base.html + growo-pages.css — один канон) */
.fm-skeleton-line { height: 12px; margin-bottom: 8px; border-radius: 6px; }
.fm-skeleton-line:last-child { width: 60%; }
.fm-skeleton-circle { width: 36px; height: 36px; border-radius: 50%; }
.fm-skeleton-block {
  width: 100%; height: 120px;
  border-radius: var(--radius-lg);
  background: var(--bg-inset);
  position: relative; overflow: hidden;
}
.fm-skeleton-block::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg,
    transparent 0%,
    var(--accent-bg-subtle) 30%,
    var(--accent-bg-medium) 50%,
    var(--accent-bg-subtle) 70%,
    transparent 100%);
  animation: fmShimmer 1.8s ease-in-out infinite;
}

/* ═══ Empty States ═══ */
.fm-empty { text-align: center; padding: 3rem 1rem; color: var(--text-muted); }

/* .empty-state — легаси-класс, использовался в 9 страницах без CSS-определения.
   Алиас на fm-empty: одно правило стандартизует вид всех пустых состояний
   (включая JS-генерируемые, куда Jinja-макрос не дотягивается). */
.empty-state {
  text-align: center; padding: 2.5rem 1rem; color: var(--text-muted);
  font-size: 0.9rem;
}
.empty-state svg, .empty-state i {
  width: 40px; height: 40px; opacity: 0.45; margin-bottom: 0.6rem;
  color: var(--text-secondary);
}
.empty-state strong { color: var(--text-secondary); }
/* Микрокопия пустых состояний (время/риск/подсказка): vision-аудит 03.09 —
   12px при opacity .65 на тёмном фоне читаются на грани; .72 сохраняет
   визуальную иерархию, но проходит по контрасту. */
.empty-hint {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  opacity: .72;
}
.fm-empty svg { width: 48px; height: 48px; opacity: 0.3; margin-bottom: 0.75rem; }
.fm-empty-title { font-size: 0.95rem; font-weight: 600; color: var(--text-secondary); margin-bottom: 0.25rem; }
.fm-empty-desc { font-size: 0.85rem; }

/* ═══ Modal ═══
   (мёртвый первый блок .fm-modal-overlay/.fm-modal удалён — канон ниже,
   Plan 13 Phase C; width для bare .fm-modal живёт там же) */

/* ═══ Breadcrumbs ═══ */
.fm-breadcrumb { display: flex; align-items: center; gap: 0.4rem; font-size: 0.8rem; color: var(--text-muted); margin-bottom: 0.75rem; }
.fm-breadcrumb a { color: var(--text-secondary); text-decoration: none; }
.fm-breadcrumb a:hover { color: var(--text-primary); }
.fm-breadcrumb-sep { opacity: 0.4; }

/* ═══ Fade animation ═══ */
.fm-fade-up { animation: fmFadeUp 0.4s var(--ease-out); }
@keyframes fmFadeUp { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }

/* ═══ Tooltip ═══
   (мёртвый navy-вариант [data-tooltip]::after удалён — канон — premium
   glass-блок ниже; фон там задан явно: var(--bg-card-solid)) */

/* ═══ Search Bar ═══ */
.fm-search {
  position: relative; margin-bottom: 1rem;
}
.fm-search input {
  width: 100%; padding: 0.5rem 0.75rem 0.5rem 2.25rem;
  border-radius: var(--radius-sm); border: 1px solid var(--border-secondary);
  background: var(--bg-card-solid); color: var(--text-primary);
  font-size: 0.85rem; font-family: var(--font-sans);
}
.fm-search input:focus { outline: none; border-color: var(--accent-solid); }
.fm-search svg { position: absolute; left: 0.6rem; top: 50%; transform: translateY(-50%); width: 18px; height: 18px; color: var(--text-muted); }

/* ═══ Table ═══
   Монохром: zebra отсутствует сознательно; hover-строка — единственный отклик.
   Header: uppercase-small-muted (вторичный ярлык), ячейки — по 8/12px-сетке. */
.fm-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
.fm-table th {
  text-align: left; padding: var(--space-2) var(--space-3);
  color: var(--text-muted); border-bottom: 1px solid var(--border-primary);
  font-weight: var(--font-semibold); font-size: var(--text-xs);
  text-transform: uppercase; letter-spacing: 0.05em;
}
.fm-table td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-primary);
  transition: background var(--duration-fast) var(--ease-smooth);
}
.fm-table tbody tr:hover td { background: var(--bg-inset); }

/* ═══ Spinner ═══ */
.fm-spinner {
  width: 16px; height: 16px; border: 2px solid var(--border-secondary);
  border-top-color: var(--accent-solid); border-radius: 50%;
  animation: fmSpin 0.6s linear infinite;
}
@keyframes fmSpin { to { transform: rotate(360deg); } }

/* ═══════════════════════════════════════════════════════════════
   Plan 01 Task A4: Reconcile template class names → components.css
   These are aliases/canonical names used by templates that were undefined.
   ═══════════════════════════════════════════════════════════════ */

/* ── Button aliases (fm-btn → btn) ── */
.fm-btn { display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-4); border-radius: var(--radius-md);
  font-size: var(--text-sm); font-weight: var(--font-medium); cursor: pointer;
  border: 1px solid var(--border-secondary); background: var(--bg-card);
  color: var(--text-primary); transition: transform var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out);
  text-decoration: none; white-space: nowrap;
}
.fm-btn:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--bg-card-hover); border-color: var(--border-accent);
  transform: translateY(-1px);
}
.fm-btn:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
.fm-btn:not(:disabled):not([aria-disabled="true"]):active { transform: scale(0.98); }

.fm-btn-primary { background: var(--gradient-brand); color: var(--text-on-accent);
  border-color: transparent; box-shadow: var(--shadow-sm); }
.fm-btn-primary:not(:disabled):not([aria-disabled="true"]):hover {
  box-shadow: var(--shadow-md), var(--underglow-emerald);
  filter: brightness(1.05); transform: translateY(-1px);
}
.fm-btn-primary:not(:disabled):not([aria-disabled="true"]):active { transform: scale(0.98); }

.fm-btn-danger { background: var(--danger-solid, #be123c); color: white;
  border-color: transparent; } /* a11y: rose-700 — белый текст 6.28:1 */
.fm-btn-danger:not(:disabled):not([aria-disabled="true"]):hover {
  filter: brightness(1.1); transform: translateY(-1px);
}

/* Secondary = outline, tertiary = text (контракт вариантов fm-btn) */
.fm-btn-secondary {
  background: transparent; color: var(--text-secondary);
}
.fm-btn-secondary:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--btn-secondary-hover); color: var(--text-primary);
  border-color: var(--border-accent);
}
.fm-btn-ghost {
  background: transparent; border-color: transparent; color: var(--text-secondary);
}
.fm-btn-ghost:not(:disabled):not([aria-disabled="true"]):hover {
  background: var(--bg-inset); border-color: transparent;
  color: var(--text-primary); transform: none;
}

.fm-btn-muted { background: var(--bg-tertiary); color: var(--text-muted);
  border-color: var(--border-primary); }

.fm-btn-sm { padding: var(--space-1) var(--space-2); font-size: var(--text-xs); }
.fm-btn-md { padding: var(--space-3) var(--space-5); font-size: var(--text-base); }

.btn-secondary { background: var(--bg-tertiary); color: var(--text-secondary);
  border-color: var(--border-secondary); }

/* ── Card aliases (fm-card → card) — premium glass, unified with .card ── */
.fm-card {
  background: var(--bg-card);
  border: 1px solid var(--border-primary);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(255,255,255,0.06);
  position: relative;
  transition:
    transform var(--duration-normal) var(--ease-out),
    box-shadow var(--duration-normal) var(--ease-smooth),
    border-color var(--duration-normal) var(--ease-smooth);
}
.fm-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-secondary);
  box-shadow: var(--shadow-lg), inset 0 1px 0 0 rgba(255,255,255,0.08);
}
:root[data-theme="light"] .fm-card {
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(0,0,0,0.04);
}

.fm-card-title { font-size: 1rem; font-weight: 600; color: var(--text-primary);
  margin: 0 0 0.5rem; }

/* ═══ Premium Stat Card — metric with variant underglow + count-up ═══ */
.fm-stat-card {
  background: var(--bg-card);
  border: 1px solid var(--border-primary);
  border-radius: var(--radius-lg);
  padding: var(--space-5) var(--space-6);
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(255,255,255,0.06);
  position: relative;
  overflow: hidden;
  transition:
    transform var(--duration-normal) var(--ease-out),
    box-shadow var(--duration-normal) var(--ease-smooth),
    border-color var(--duration-normal) var(--ease-smooth);
}
/* Underglow pulse — variant-colored ambient depth under the card */
.fm-stat-card::after {
  content: '';
  position: absolute;
  inset: auto -10% -60% -10%;
  height: 60%;
  background: radial-gradient(ellipse 50% 100% at 50% 100%, var(--stat-glow, var(--accent-bg-medium)) 0%, transparent 70%);
  pointer-events: none;
  opacity: 0.7;
  transition: opacity var(--duration-slow) var(--ease-smooth);
}
.fm-stat-card:hover {
  transform: translateY(-2px);
  border-color: var(--border-secondary);
  box-shadow: var(--shadow-lg), inset 0 1px 0 0 rgba(255,255,255,0.08);
}
.fm-stat-card:hover::after { opacity: 1; }
:root[data-theme="light"] .fm-stat-card {
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(0,0,0,0.04);
}

/* Variant underglow colors */
.fm-stat-card[data-variant="emerald"] { --stat-glow: var(--accent-bg-strong); }
.fm-stat-card[data-variant="cyan"]    { --stat-glow: rgba(34,211,238,0.20); }
.fm-stat-card[data-variant="violet"]  { --stat-glow: var(--color-violet); }
.fm-stat-card[data-variant="amber"]   { --stat-glow: var(--status-warn); }
.fm-stat-card[data-variant="rose"]    { --stat-glow: var(--color-rose); }

/* Stat card internals */
.fm-stat-card .fm-stat-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: var(--radius-md);
  background: var(--stat-glow, var(--accent-bg-medium));
  margin-bottom: 0.85rem;
}
.fm-stat-card .fm-stat-icon svg, .fm-stat-card .fm-stat-icon i { width: 20px; height: 20px; color: var(--text-primary); }
.fm-stat-card[data-variant="emerald"] .fm-stat-icon { background: var(--accent-bg-medium); }
.fm-stat-card[data-variant="emerald"] .fm-stat-icon svg,
.fm-stat-card[data-variant="emerald"] .fm-stat-icon i { color: var(--accent-text); }
.fm-stat-card[data-variant="cyan"] .fm-stat-icon { background: rgba(34,211,238,0.12); }
.fm-stat-card[data-variant="cyan"] .fm-stat-icon svg,
.fm-stat-card[data-variant="cyan"] .fm-stat-icon i { color: var(--color-cyan); }
.fm-stat-card[data-variant="violet"] .fm-stat-icon { background: rgba(79, 70, 229, 0.14); }
.fm-stat-card[data-variant="violet"] .fm-stat-icon svg,
.fm-stat-card[data-variant="violet"] .fm-stat-icon i { color: var(--color-violet); }
.fm-stat-card[data-variant="amber"] .fm-stat-icon { background: rgba(245, 158, 11, 0.14); }
.fm-stat-card[data-variant="amber"] .fm-stat-icon svg,
.fm-stat-card[data-variant="amber"] .fm-stat-icon i { color: var(--status-warn); }
.fm-stat-card[data-variant="rose"] .fm-stat-icon { background: rgba(244, 63, 94, 0.14); }
.fm-stat-card[data-variant="rose"] .fm-stat-icon svg,
.fm-stat-card[data-variant="rose"] .fm-stat-icon i { color: var(--color-rose); }

.fm-stat-card .fm-stat-label {
  font-size: var(--text-xs); font-weight: var(--font-medium);
  color: var(--text-tertiary); text-transform: uppercase; letter-spacing: 0.04em;
  margin: 0 0 0.35rem;
}
.fm-stat-card .fm-stat-value {
  font-size: var(--text-3xl); font-weight: var(--font-semibold);
  color: var(--text-primary); margin: 0; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.fm-stat-card .fm-stat-delta {
  font-size: var(--text-xs); margin-top: 0.5rem; display: inline-flex; align-items: center; gap: 0.25rem;
}
.fm-stat-card .fm-stat-delta.up { color: var(--accent-text); }
.fm-stat-card .fm-stat-delta.down { color: var(--color-rose); }
.fm-stat-card .fm-stat-sparkline { margin-top: 0.75rem; height: 32px; opacity: 0.7; }

/* ── Badge aliases (badge → fm-badge) — единая система с .fm-badge ── */
.badge { display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) var(--space-2); border-radius: var(--radius-full);
  font-size: var(--text-xs); font-weight: var(--font-semibold); text-transform: uppercase;
  letter-spacing: 0.04em; }
.badge-ok { background: rgba(16, 185, 129, 0.15); color: var(--accent-text); }
.badge-warn { background: rgba(245, 158, 11, 0.15); color: var(--badge-warn-text, var(--status-warn)); }
.badge-error { background: rgba(248, 113, 113, 0.15); color: var(--badge-error-text, var(--status-error)); }
.badge-neutral { background: var(--bg-tertiary); color: var(--text-muted); }

/* ── Stagger animation delays ── */
@keyframes fm-fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
.fm-delay-1 { animation-delay: 0.05s; animation-fill-mode: both; }
.fm-delay-2 { animation-delay: 0.10s; animation-fill-mode: both; }
.fm-delay-3 { animation-delay: 0.15s; animation-fill-mode: both; }
.fm-delay-4 { animation-delay: 0.20s; animation-fill-mode: both; }
.fm-delay-5 { animation-delay: 0.25s; animation-fill-mode: both; }

/* ── Section headers (canonical definition — see line ~1253 for premium variant) ── */
.section-title { font-size: var(--text-lg); font-weight: var(--font-semibold);
  color: var(--text-primary); letter-spacing: -0.01em; display: flex; align-items: center; gap: 0.5rem; }
.section-header { display: flex; align-items: center; gap: 0.75rem;
  margin: 1.5rem 0 0.75rem; }

/* ── KPI cards (dashboard) ── */
.kpi-card { background: var(--bg-card); border: 1px solid var(--border-primary);
  border-radius: var(--radius-md); padding: var(--space-4); display: flex;
  align-items: center; gap: var(--space-3); transition: transform var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out); }
.kpi-card:hover { border-color: var(--border-accent); box-shadow: var(--shadow-md); transform: translateY(-1px); }
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem; }
.kpi-label { font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase;
  letter-spacing: 0.04em; }
.kpi-value { font-size: 1.5rem; font-weight: var(--font-semibold); color: var(--text-primary); margin: 0.15rem 0; } /* канон 600 — единый с .fm-stat-value/.fm-kpi-value */

/* ── AI Engine panels ── */
.ae-panel { display: none; padding: 1rem 0; }
.ae-panel.active { display: block; }

/* ── Chart container ── */
.chart-box-lg { width: 100%; height: 300px; position: relative; }

/* ── Active nav state ── */
.active { font-weight: 600; color: var(--accent-solid) !important; }

/* ── Success box ── */
.fm-success-box { padding: 0.75rem 1rem; border-radius: var(--radius-sm);
  background: rgba(16, 185, 129, 0.08); border-left: 3px solid var(--status-ok);
  color: var(--text-secondary); font-size: 0.875rem; }

/* ── Empty state ── */
.fm-empty-icon { font-size: 2rem; margin-bottom: 0.5rem; }
.fm-empty-text { color: var(--text-muted); font-size: 0.9rem; }

/* ── Form fields ── */
.fm-field { display: flex; flex-direction: column; gap: 0.25rem; margin-bottom: 0.75rem; }
.fm-label { font-size: 0.8rem; font-weight: 500; color: var(--text-secondary); }
.fm-textarea { width: 100%; padding: 0.5rem; border-radius: var(--radius-sm);
  background: var(--bg-inset); border: 1px solid var(--border-primary);
  color: var(--text-primary); font-family: inherit; font-size: 0.85rem; resize: vertical; }
.fm-row { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* ── Glass card ── */
.fm-glass-card { background: var(--glass-bg, rgba(255,255,255,.04));
  border: 1px solid var(--glass-border); border-radius: var(--radius-md); padding: 1.25rem; }

/* ── Tabs ── */
.fm-tabs { display: flex; gap: 0.25rem; border-bottom: 1px solid var(--border-secondary);
  margin-bottom: 1rem; overflow-x: auto; }
.fm-tab { padding: 0.6rem 1rem; background: transparent; border: none;
  border-bottom: 2px solid transparent; color: var(--text-muted);
  font-size: 0.85rem; font-weight: 500; cursor: pointer; white-space: nowrap;
  transition: color var(--duration-fast), border-color var(--duration-fast); }
.fm-tab:hover { color: var(--text-primary); }
.fm-tab.active, .fm-tab[aria-selected="true"] { color: var(--text-primary);
  border-bottom-color: var(--accent-solid); }

/* ── Form group ── */
.fm-form-group { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1rem; }

/* ── Toggle ── */
.fm-toggle { display: inline-flex; align-items: center; gap: 0.4rem; cursor: pointer; }
.fm-toggle-input { appearance: none; width: 36px; height: 20px; border-radius: 999px;
  background: var(--bg-tertiary); border: 1px solid var(--border-secondary);
  position: relative; cursor: pointer; transition: background var(--duration-fast); }
.fm-toggle-input::after { content: ''; position: absolute; top: 1px; left: 1px;
  width: 16px; height: 16px; border-radius: 50%; background: white;
  transition: transform var(--duration-fast) var(--ease-spring);
  box-shadow: var(--shadow-sm); }
.fm-toggle-input:checked, .fm-toggle-input[aria-checked="true"] {
  background: var(--accent-solid); border-color: var(--accent-solid); }
.fm-toggle-input:checked::after, .fm-toggle-input[aria-checked="true"]::after {
  transform: translateX(16px); }

/* ── Skeleton ── */
/* FPS: shimmer через ::after-градиент с translateX (composite) */
.skeleton { position: relative; overflow: hidden; background: var(--bg-tertiary); border-radius: var(--radius-sm); }
.skeleton::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, var(--bg-card-hover), transparent);
  animation: skeleton-shimmer 1.5s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

/* ── Remaining reconcile classes ── */
.kpi-delta { font-size: 0.75rem; font-weight: 500; }
.fm-error-box { padding: var(--space-3) var(--space-4); border-radius: var(--radius-sm);
  background: rgba(248, 113, 113, 0.10); border-left: 3px solid var(--status-error);
  color: var(--text-secondary); font-size: var(--text-sm); }
.fm-report-tab { padding: 0.5rem 0.75rem; cursor: pointer; border-radius: var(--radius-sm);
  background: transparent; color: var(--text-muted); font-size: 0.85rem; transition: transform 0.15s, opacity 0.15s, background-color 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s; }
.fm-report-tab.active, .fm-report-tab:hover { background: var(--bg-card-hover);
  color: var(--text-primary); }
.tab-btn { padding: 0.5rem 1rem; cursor: pointer; border: none; background: transparent;
  color: var(--text-muted); font-size: 0.85rem; border-bottom: 2px solid transparent; }
.tab-btn.active { color: var(--text-primary); border-bottom-color: var(--accent-solid); }

/* ═══════════════════════════════════════════════════════════════
   Plan 01 Phase B: Component Library v2 — additional styles
   ═══════════════════════════════════════════════════════════════ */

/* ── Alert variants ── */
.fm-alert { border-left: 3px solid var(--text-muted); }
.fm-alert-info { border-left-color: var(--status-info); background: rgba(59,130,246,0.06); }
.fm-alert-success { border-left-color: var(--status-ok); background: rgba(16,185,129,0.06); }
.fm-alert-warn { border-left-color: var(--status-warn); background: rgba(245,158,11,0.06); }
.fm-alert-error { border-left-color: var(--status-error); background: rgba(248, 113, 113, 0.08); }

/* ── Progress bar ── */
.fm-progress { display: block; width: 100%; height: 6px;
  background: var(--bg-tertiary); border-radius: 999px; overflow: hidden; }
.fm-progress-fill { height: 100%; background: var(--gradient-brand);
  transition: width var(--duration-slow) var(--ease-out); border-radius: 999px; }
.fm-progress[data-variant="success"] .fm-progress-fill { background: var(--status-ok); }
.fm-progress[data-variant="warn"] .fm-progress-fill { background: var(--status-warn); }
.fm-progress[data-variant="error"] .fm-progress-fill { background: var(--status-error); }

/* ── Data table improvements ── */
.fm-data-table tbody tr { transition: background var(--duration-fast) var(--ease-out); }
.fm-data-table tbody tr:hover { background: var(--bg-card-hover); }
.fm-data-table th[data-sort]::after { content: '↕'; opacity: 0.3; margin-left: 0.25rem; font-size: 0.7em; }
.fm-data-table th[data-sort="asc"]::after { content: '↑'; opacity: 1; }
.fm-data-table th[data-sort="desc"]::after { content: '↓'; opacity: 1; }

/* ── Dropdown ── */
.fm-dropdown-menu a:hover { background: var(--bg-card-hover); color: var(--text-primary); }

/* ── Page header ── (бокс-модель слита с cinematic-блоком ниже — один владелец) */

/* ── Empty state ── */
.fm-empty { text-align: center; padding: 2.5rem 1rem; }

/* ── Drawer / slide-over (for detail views) ──
   (мёртвый legacy-блок .fm-drawer-backdrop + .fm-drawer[open-тоггл] удалён:
   ни один шаблон/JS его не использует; живой канон — Plan 13 блок ниже
   с .fm-drawer-overlay + .fm-drawer-left/-right, см. _components/ui.html,
   erp.js, marketing.js) */

/* ── Segmented control ── */
.fm-segmented { display: inline-flex; background: var(--bg-tertiary); border-radius: 999px; padding: 2px; }
.fm-segmented button { padding: 0.35rem 0.9rem; border: none; background: transparent;
  color: var(--text-muted); font-size: 0.8rem; font-weight: 500; border-radius: 999px; cursor: pointer;
  transition: transform var(--duration-fast), opacity var(--duration-fast), background-color var(--duration-fast), border-color var(--duration-fast), color var(--duration-fast), box-shadow var(--duration-fast); }
.fm-segmented button.active { background: var(--bg-card-solid); color: var(--text-primary);
  box-shadow: var(--shadow-xs); }

/* ── Popover ── */
.fm-popover { position: absolute; background: var(--bg-card-solid); border: 1px solid var(--border-secondary);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg); padding: 0.75rem; z-index: 150;
  max-width: 300px; font-size: 0.85rem; }

/* ── Code block with copy ── */
.fm-code-block { position: relative; background: var(--bg-inset); border-radius: var(--radius-sm);
  padding: 0.75rem; font-family: var(--font-mono); font-size: 0.8rem; overflow-x: auto;
  color: var(--text-secondary); border: 1px solid var(--border-primary); }
.fm-code-block button { position: absolute; top: 0.4rem; right: 0.4rem; padding: 0.2rem 0.5rem;
  font-size: 0.7rem; background: var(--bg-tertiary); border: 1px solid var(--border-secondary);
  border-radius: 4px; color: var(--text-muted); cursor: pointer; }
.fm-code-block button:hover { color: var(--text-primary); }

/* ── File dropzone ── */
.fm-dropzone { border: 2px dashed var(--border-secondary); border-radius: var(--radius-md);
  padding: 2rem; text-align: center; cursor: pointer; transition: transform var(--duration-fast), opacity var(--duration-fast), background-color var(--duration-fast), border-color var(--duration-fast), color var(--duration-fast), box-shadow var(--duration-fast);
  background: var(--bg-inset); }
.fm-dropzone:hover, .fm-dropzone.dragover { border-color: var(--accent-solid);
  background: var(--accent-bg-medium); }

/* ── Tooltip (via data-tooltip attribute) — premium glass ── */
[data-tooltip] { position: relative; }
[data-tooltip]::after {
  content: attr(data-tooltip); position: absolute; bottom: calc(100% + 6px); left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--bg-card-solid);
  border: 1px solid var(--glass-border);
  color: var(--text-primary); padding: 0.4rem 0.7rem;
  border-radius: var(--radius-sm); font-size: var(--text-xs); white-space: nowrap;
  opacity: 0; pointer-events: none;
  transition: opacity 0.2s var(--ease-smooth), transform 0.2s var(--ease-smooth);
  z-index: 100; box-shadow: var(--shadow-md);
}
[data-tooltip]:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }
/* Tooltip wrapper (with help cursor) */
.fm-tooltip-wrap {
  position: relative; display: inline-flex; align-items: center;
  cursor: help; border-bottom: 1px dotted var(--text-muted);
}
.fm-search { position: relative; }
.fm-search input { width: 100%; padding: 0.5rem 0.75rem 0.5rem 2rem; border-radius: var(--radius-sm);
  background: var(--bg-inset); border: 1px solid var(--border-primary); color: var(--text-primary);
  font-size: 0.85rem; }
.fm-search::before {
  content: ''; position: absolute; left: 0.6rem; top: 50%; transform: translateY(-50%);
  width: 14px; height: 14px; background: var(--text-muted); opacity: 0.5; pointer-events: none;
  /* lucide «search» через mask — цвет управляется background (не emoji) */
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E") no-repeat center / contain;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='m21 21-4.3-4.3'/%3E%3C/svg%3E") no-repeat center / contain;
}

/* ── Command palette (⌘K) ── */
.fm-command-palette { position: fixed; top: 20%; left: 50%; transform: translateX(-50%);
  width: 500px; max-width: 90vw; background: var(--bg-card-solid); border: 1px solid var(--border-secondary);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-2xl); z-index: 300; display: none; }
.fm-command-palette.open { display: block; }
.fm-command-palette input { width: 100%; padding: 1rem; border: none; background: transparent;
  color: var(--text-primary); font-size: 1rem; outline: none; }
.fm-command-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.6rem 1rem;
  cursor: pointer; font-size: 0.85rem; color: var(--text-secondary); }
.fm-command-item:hover, .fm-command-item.selected { background: var(--bg-card-hover); color: var(--text-primary); }

/* ════════════════════════════════════════════════════════════════════
   Plan 13 Phase D — Command Palette (overlay variant)
   ════════════════════════════════════════════════════════════════════ */
.fm-cp-overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(10, 15, 28, 0.6);
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 12vh;
  animation: fmCpFade 0.15s ease-out;
}
@keyframes fmCpFade { from { opacity: 0; } to { opacity: 1; } }

.fm-cp {
  width: 560px; max-width: 92vw;
  max-height: 70vh; overflow: hidden;
  background: var(--bg-card-solid, #ffffff);
  border: 1px solid var(--border-secondary, rgba(0,0,0,0.08));
  border-radius: var(--radius-lg, 16px);
  box-shadow: var(--shadow-2xl, 0 25px 50px -12px rgba(0,0,0,0.25));
  display: flex; flex-direction: column;
  animation: fmCpSlide 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes fmCpSlide {
  from { opacity: 0; transform: translateY(-12px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

.fm-cp-input-wrap {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border-primary, rgba(0,0,0,0.06));
}
.fm-cp-search-icon {
  width: 18px; height: 18px; color: var(--text-muted); flex-shrink: 0;
}
.fm-cp-input {
  flex: 1; border: none; background: transparent;
  color: var(--text-primary); font-size: var(--text-base, 1rem);
  font-family: var(--font-sans); outline: none;
}
.fm-cp-input::placeholder { color: var(--text-muted); }
.fm-cp-kbd {
  font-size: 0.7rem; padding: 2px 6px;
  background: var(--bg-inset, rgba(0,0,0,0.04));
  border: 1px solid var(--border-primary);
  border-radius: 4px; color: var(--text-muted);
  font-family: var(--font-mono);
}

.fm-cp-results {
  flex: 1; overflow-y: auto;
  padding: 0.5rem 0;
}
.fm-cp-results::-webkit-scrollbar { width: 6px; }
.fm-cp-results::-webkit-scrollbar-thumb {
  background: var(--border-secondary); border-radius: 3px;
}

.fm-cp-category {
  padding: 0.5rem 1.25rem 0.25rem;
  font-size: var(--text-xs, 0.75rem); font-weight: var(--font-semibold, 600);
  color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.05em;
}

.fm-cp-item {
  display: flex; align-items: center; gap: 0.75rem;
  padding: 0.6rem 1.25rem; cursor: pointer;
  color: var(--text-secondary);
  transition: background 0.1s ease;
}
.fm-cp-item:hover, .fm-cp-item.selected {
  background: var(--bg-card-hover, rgba(0,0,0,0.03));
  color: var(--text-primary);
}
.fm-cp-item.selected { box-shadow: inset 3px 0 0 var(--accent, var(--status-info)); }
.fm-cp-item-icon {
  width: 16px; height: 16px; flex-shrink: 0;
  color: var(--text-muted);
}
.fm-cp-item.selected .fm-cp-item-icon { color: var(--accent, var(--status-info)); }
.fm-cp-item-label { font-size: var(--text-sm, 0.875rem); }

.fm-cp-empty {
  padding: 2rem 1.25rem; text-align: center;
  color: var(--text-muted); font-size: var(--text-sm, 0.875rem);
}

.fm-cp-footer {
  display: flex; gap: 1rem; justify-content: flex-end;
  padding: 0.6rem 1.25rem;
  border-top: 1px solid var(--border-primary);
  font-size: var(--text-xs, 0.75rem); color: var(--text-muted);
}
.fm-cp-footer kbd {
  font-family: var(--font-mono);
  padding: 1px 4px; margin: 0 1px;
  background: var(--bg-inset, rgba(0,0,0,0.04));
  border: 1px solid var(--border-primary);
  border-radius: 3px;
}

/* Dark mode adjustments */
@media (prefers-color-scheme: dark) {
  .fm-cp { background: var(--bg-card-solid, rgba(15, 23, 42, 0.95)); }
  .fm-cp-item:hover, .fm-cp-item.selected { background: rgba(255,255,255,0.05); }
  .fm-cp-input { color: var(--text-primary, var(--text-primary)); }
}

/* Plan 13 Phase G — skip link visible on focus */
.fm-skip-link:focus {
  position: fixed !important; top: 0; left: 0; right: 0;
  z-index: 2000; padding: 0.75rem 1rem;
  background: var(--accent-solid); color: white;
  text-align: center; text-decoration: none;
  clip: auto !important; height: auto !important; width: auto !important;
}

/* Plan 13 Phase G — improved focus visibility (accent-text читаем в dark) */
*:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: 2px;
  border-radius: 4px;
}
button:focus-visible, a:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible {
  outline-offset: 2px;
}

/* ════════════════════════════════════════════════════════════════════
   Plan 13 Phase C — Styles for new macros
   ════════════════════════════════════════════════════════════════════ */

/* ── Modal ── */
.fm-modal-overlay {
  position: fixed; inset: 0; z-index: 900;
  background: rgba(7, 9, 26, 0.7);
  backdrop-filter: blur(8px) saturate(1.2); -webkit-backdrop-filter: blur(8px) saturate(1.2);
  display: none; align-items: center; justify-content: center;
  padding: 1rem;
}
.fm-modal-overlay.visible { display: flex; animation: fmModalOverlayIn 0.2s var(--ease-out); }
@keyframes fmModalOverlayIn { from { opacity: 0; } to { opacity: 1; } }
.fm-modal-overlay[hidden] { display: none; }
.fm-modal {
  /* width/padding для bare .fm-modal (fmConfirm и др.) — раньше приходили
     из мёртвого первого блока; модификаторы -small/-medium/-large ниже
     переопределяют все три свойства */
  width: 460px; max-width: 90vw; padding: var(--space-6);
  background: var(--glass-bg, rgba(15,23,42,0.85));
  /* FPS: снижен полноэкранный blur модалки */
  backdrop-filter: blur(12px) saturate(120%); -webkit-backdrop-filter: blur(12px) saturate(120%);
  border: 1px solid var(--glass-border, rgba(255,255,255,0.08));
  border-radius: var(--radius-xl, 24px);
  box-shadow: var(--shadow-2xl), inset 0 1px 0 0 rgba(255,255,255,0.06),
              0 0 60px -20px var(--accent-bg-medium);
  max-height: 90vh; overflow-y: auto;
  position: relative;
  /* Unified entrance: fade + scale .97→1, 200ms ease-out (см. fmDrawer*) */
  animation: fmModalIn 0.2s var(--ease-out);
}
.fm-modal-small { width: 100%; max-width: 380px; padding: var(--space-6); }
.fm-modal-medium { width: 100%; max-width: 560px; padding: 1.75rem; }
.fm-modal-large { width: 100%; max-width: 800px; padding: var(--space-8); }
@keyframes fmModalIn {
  from { opacity: 0; transform: scale(0.97); }
  to { opacity: 1; transform: scale(1); }
}
.fm-modal-title { font-size: var(--text-xl, 1.25rem); font-weight: var(--font-semibold); margin: 0 0 1rem; }
.fm-modal-body { font-size: var(--text-sm, 0.875rem); color: var(--text-secondary); line-height: var(--leading-relaxed); }
.fm-modal-footer { display: flex; gap: 0.5rem; justify-content: flex-end; margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--border-primary); }
.fm-modal-close {
  position: absolute; top: 0.75rem; right: 0.75rem;
  background: transparent; border: none; cursor: pointer;
  width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted); font-size: 1.5rem; line-height: 1;
  transition: background var(--duration-fast) var(--ease-smooth),
              color var(--duration-fast) var(--ease-smooth);
}
.fm-modal-close:hover { background: var(--bg-inset, rgba(0,0,0,0.05)); color: var(--text-primary); }

/* ── Drawer (slide-over) ── */
.fm-drawer-overlay {
  position: fixed; inset: 0; z-index: 900;
  background: rgba(10, 15, 28, 0.45);
  /* тот же backdrop-blur, что у .fm-modal-overlay — единый оверлей-слой */
  backdrop-filter: blur(8px) saturate(1.2); -webkit-backdrop-filter: blur(8px) saturate(1.2);
  display: flex;
}
.fm-drawer-overlay[hidden] { display: none; }
.fm-drawer-right { margin-left: auto; animation: fmDrawerRight var(--duration-normal) var(--ease-out); }
.fm-drawer-left { margin-right: auto; animation: fmDrawerLeft var(--duration-normal) var(--ease-out); }
@keyframes fmDrawerRight { from { transform: translateX(100%); } to { transform: translateX(0); } }
@keyframes fmDrawerLeft { from { transform: translateX(-100%); } to { transform: translateX(0); } }
.fm-drawer {
  /* z-index 201 — контракт лестницы (tests/test_avatar_ux.py): nav 200 ≤
     drawer 201 < sidebar-drawer 300. Раньше давал мёртвый legacy-блок. */
  z-index: 201;
  background: var(--bg-card-solid, #ffffff);
  height: 100%; max-width: 90vw;
  display: flex; flex-direction: column;
  box-shadow: -8px 0 32px rgba(0,0,0,0.08);
}
.fm-drawer-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 1.25rem 1.5rem; border-bottom: 1px solid var(--border-primary);
}
.fm-drawer-title { font-size: var(--text-lg, 1.125rem); font-weight: var(--font-semibold); margin: 0; }
.fm-drawer-close {
  background: transparent; border: none; cursor: pointer;
  width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted); font-size: 1.5rem;
  transition: background var(--duration-fast) var(--ease-smooth),
              color var(--duration-fast) var(--ease-smooth);
}
.fm-drawer-close:hover { background: var(--bg-inset); color: var(--text-primary); }
.fm-drawer-body { flex: 1; padding: 1.5rem; overflow-y: auto; }

/* ── Tooltip wrapper ── */
/* Tooltip position variants */
.fm-tooltip-wrap[data-tooltip]::after {
  border: 1px solid var(--glass-border); box-shadow: var(--shadow-md);
  bottom: calc(100% + 6px); transform: translateX(-50%) translateY(4px);
  transition: opacity 0.2s var(--ease-smooth), transform 0.2s var(--ease-smooth);
}
.fm-tooltip-wrap:hover[data-tooltip]::after,
.fm-tooltip-wrap:focus[data-tooltip]::after { opacity: 1; transform: translateX(-50%) translateY(0); }
.fm-tooltip-wrap[data-tooltip-position="bottom"]::after {
  bottom: auto; top: calc(100% + 6px);
}

/* ── Breadcrumb ── */
.fm-breadcrumb-list {
  list-style: none; padding: 0; margin: 0 0 1rem;
  display: flex; align-items: center; gap: 0.4rem;
  font-size: var(--text-sm, 0.875rem);
}
.fm-breadcrumb-link { color: var(--text-muted); text-decoration: none; transition: color 0.15s; }
.fm-breadcrumb-link:hover { color: var(--text-primary); }
.fm-breadcrumb-sep { color: var(--text-muted); opacity: 0.5; }
.fm-breadcrumb-current { color: var(--text-primary); font-weight: var(--font-medium); }

/* ── Badge ── */
.fm-badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: var(--space-1) var(--space-2); border-radius: var(--radius-full);
  font-size: var(--text-xs); font-weight: var(--font-semibold);
  line-height: 1.4; letter-spacing: 0.02em;
}
.fm-badge-neutral { background: var(--bg-inset, rgba(0,0,0,0.05)); color: var(--text-secondary); }
.fm-badge-success { background: rgba(16, 185, 129, 0.15); color: var(--accent-text); }
.fm-badge-warning { background: rgba(245, 158, 11, 0.15); color: var(--badge-warn-text, var(--status-warn)); }
.fm-badge-error { background: rgba(248, 113, 113, 0.15); color: var(--badge-error-text, var(--status-error)); }
.fm-badge-info { background: rgba(59, 130, 246, 0.15); color: var(--status-info); }
.fm-badge-purple { background: rgba(99, 102, 241, 0.15); color: var(--color-violet); }

/* ── Code block ── */
.fm-code-block { position: relative; background: var(--bg-inset, #0d1117); border-radius: 8px; overflow: hidden; }
.fm-code-pre {
  margin: 0; padding: 1rem 1.25rem; overflow-x: auto;
  font-family: var(--font-mono); font-size: var(--text-xs, 0.75rem);
  color: var(--text-secondary); line-height: 1.6;
}
.fm-code-copy {
  position: absolute; top: 0.5rem; right: 0.5rem;
  background: rgba(255,255,255,0.08); border: none; cursor: pointer;
  padding: 4px 8px; border-radius: 4px;
  font-size: var(--text-xs); color: var(--text-secondary);
}
.fm-code-copy:hover { background: rgba(255,255,255,0.15); }

/* ── Dropzone ── */
.fm-dropzone {
  border: 2px dashed var(--border-secondary, rgba(0,0,0,0.1));
  border-radius: var(--radius, 12px);
  padding: 2.5rem 1.5rem; text-align: center;
  transition: transform 0.2s, opacity 0.2s, background-color 0.2s, border-color 0.2s, color 0.2s, box-shadow 0.2s;
  background: var(--bg-inset, rgba(0,0,0,0.02));
}
.fm-dropzone-active {
  border-color: var(--accent, var(--accent-solid));
  background: var(--accent-bg-medium);
  transform: scale(1.01);
}
.fm-dropzone-icon { width: 2.5rem; height: 2.5rem; color: var(--text-muted); margin-bottom: 0.5rem; }
.fm-dropzone-label { margin: 0 0 0.25rem; font-size: var(--text-sm, 0.875rem); color: var(--text-secondary); font-weight: var(--font-medium); }
.fm-dropzone-hint { margin: 0 0 1rem; font-size: var(--text-xs, 0.75rem); color: var(--text-muted); }
.fm-dropzone-input { display: none; }

/* ── State (empty / error / loading) ── */
.fm-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 3rem 1.5rem; text-align: center;
}
.fm-state-icon {
  width: 3rem; height: 3rem; border-radius: 50%;
  background: var(--bg-inset, rgba(0,0,0,0.04));
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted); margin-bottom: 1rem;
}
.fm-state-icon i, .fm-state-icon svg { width: 1.5rem; height: 1.5rem; }
.fm-state-icon-error { background: rgba(248, 113, 113, 0.15); color: var(--status-error); }
.fm-state-title { font-size: var(--text-lg, 1.125rem); font-weight: var(--font-semibold); margin: 0 0 0.5rem; color: var(--text-primary); }
.fm-state-desc { font-size: var(--text-sm, 0.875rem); color: var(--text-muted); margin: 0 0 1.5rem; max-width: 380px; }
.fm-state-loading { gap: 0.75rem; }

/* ════════════════════════════════════════════════════════════════════
   Plan 13 Phase I — Optimistic UI animations
   ════════════════════════════════════════════════════════════════════ */
.fm-optimistic-pending { opacity: 0.75; pointer-events: none; }
.fm-optimistic-success { animation: fmOptSuccess 0.6s ease-out; }
@keyframes fmOptSuccess {
  0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); }
  100% { box-shadow: 0 0 0 12px rgba(16, 185, 129, 0); }
}
.fm-pulse-anim { animation: fmPulse 0.6s ease-out; }
@keyframes fmPulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.02); }
  100% { transform: scale(1); }
}

/* ════════════════════════════════════════════════════════════════════
   Plan 13 Phase J — Product Tour (Shepherd-like, no deps)
   ════════════════════════════════════════════════════════════════════ */
.fm-tour-overlay {
  position: fixed; inset: 0; z-index: 950;
  pointer-events: none;
}
.fm-tour-spotlight {
  position: absolute; border-radius: 8px;
  box-shadow: 0 0 0 5999px rgba(10, 15, 28, 0.35);
  pointer-events: none;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1), background-color 0.3s cubic-bezier(0.16, 1, 0.3, 1), border-color 0.3s cubic-bezier(0.16, 1, 0.3, 1), color 0.3s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.3s cubic-bezier(0.16, 1, 0.3, 1);
}
.fm-tour-popover {
  position: absolute; z-index: 960;
  background: var(--bg-card-solid, #ffffff);
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,0.2);
  padding: 1.25rem 1.5rem;
  max-width: 360px;
  pointer-events: auto;
  animation: fmTourIn 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes fmTourIn {
  from { opacity: 0; transform: translateY(8px) scale(0.96); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Guided Activation: шаг без DOM-цели (страница не совпала/элемента нет) —
   поповер по центру, тур не ломается */
.fm-tour-popover-center {
  left: 50% !important;
  transform: translateX(-50%);
}
.fm-tour-title {
  font-size: var(--text-base); font-weight: var(--font-semibold);
  margin: 0 0 0.5rem; color: var(--text-primary);
  display: flex; align-items: center; gap: 0.5rem;
}
.fm-tour-body {
  font-size: var(--text-sm); color: var(--text-secondary);
  line-height: var(--leading-relaxed); margin: 0 0 1rem;
}
.fm-tour-footer {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.5rem;
}
.fm-tour-progress {
  font-size: var(--text-xs); color: var(--text-muted);
}
.fm-tour-actions { display: flex; gap: 0.4rem; }
.fm-tour-btn-skip {
  background: transparent; border: none; cursor: pointer;
  color: var(--text-muted); font-size: var(--text-xs);
  padding: 0.4rem 0.6rem; border-radius: 4px;
}
.fm-tour-btn-skip:hover { color: var(--text-primary); }

/* ════════════════════════════════════════════════════════════════════
   Plan 14 Bug Fix #7 — Console layout (was inline grid, now responsive)
   ════════════════════════════════════════════════════════════════════ */
.fm-console-layout {
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: 1rem;
  flex: 1;
  min-height: 0;
}
@media (max-width: 768px) {
  .fm-console-layout {
    grid-template-columns: 1fr;
    grid-template-rows: 40vh 1fr;
  }
}

/* ════════════════════════════════════════════════════════════════════
   Plan 15 Phase E — Navigation: advanced section (collapsible <details>)
   ════════════════════════════════════════════════════════════════════ */
.fm-nav-advanced { margin-top: 0.75rem; }
.fm-nav-advanced > summary {
  list-style: none; cursor: pointer;
  padding: 0.5rem 0.75rem;
  font-size: 0.65rem; text-transform: uppercase;
  letter-spacing: 0.08em; color: rgba(255,255,255,0.4);
  font-weight: 600;
  display: flex; align-items: center; gap: 0.4rem;
  user-select: none;
}
.fm-nav-advanced > summary::-webkit-details-marker { display: none; }
.fm-nav-advanced > summary::before {
  content: '▸'; font-size: 0.7rem; transition: transform 0.2s;
}
.fm-nav-advanced[open] > summary::before { transform: rotate(90deg); }
.fm-nav-advanced > summary:hover { color: rgba(255,255,255,0.7); }

/* Nav badge (unread count) */
.fm-nav-badge {
  margin-left: auto;
  min-width: 18px; height: 18px;
  border-radius: 9px;
  background: var(--color-error, var(--status-error));
  color: white; font-size: 10px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  padding: 0 4px;
}

/* Sidebar collapsed: hide advanced details entirely */
.fm-sidebar.collapsed .fm-nav-advanced { display: none; }

/* ════════════════════════════════════════════════════════════════════
   Plan 17: Utility classes (replace common inline styles)
   ════════════════════════════════════════════════════════════════════ */

/* Icon sizing (73 occurrences of display:inline-block;height:1em;width:1em;vertical-align:middle) */
.fm-icon { display: inline-block; width: 1em; height: 1em; vertical-align: middle; flex-shrink: 0; }
.fm-icon-sm { width: 0.85rem; height: 0.85rem; }
.fm-icon-lg { width: 1.5rem; height: 1.5rem; }

/* Text styles */
.fm-text-secondary { color: var(--text-secondary); font-size: var(--text-sm); }
.fm-text-muted { color: var(--text-muted); }
.fm-text-xs-muted { color: var(--text-muted); font-size: var(--text-xs); }
.fm-text-sm { font-size: var(--text-sm); }
.fm-text-lg { font-size: var(--text-lg); }
.fm-text-xl { font-size: var(--text-xl); }
.fm-text-2xl { font-size: var(--text-2xl); }
.fm-font-medium { font-weight: var(--font-medium); }
.fm-font-semibold { font-weight: var(--font-semibold); }

/* Layout helpers */
.fm-mb-1 { margin-bottom: 0.25rem; }
.fm-mb-2 { margin-bottom: 0.5rem; }
.fm-mb-3 { margin-bottom: 0.75rem; }
.fm-mb-4 { margin-bottom: 1rem; }
.fm-mt-2 { margin-top: 0.5rem; }
.fm-w-full { width: 100%; }
.fm-flex-col { display: flex; flex-direction: column; }
.fm-flex-col-gap-4 { display: flex; flex-direction: column; gap: 1rem; }
.fm-flex-col-gap-6 { display: flex; flex-direction: column; gap: 1.5rem; }
.fm-flex-between { display: flex; align-items: center; justify-content: space-between; }
.fm-flex-center { display: flex; align-items: center; justify-content: center; }
.fm-flex-items-center { display: flex; align-items: center; }
.fm-hidden { display: none; }

/* Labels */
.fm-label-text { display: block; font-size: var(--text-sm); margin-bottom: 0.25rem; color: var(--text-secondary); font-weight: var(--font-medium); }

.fm-stat-number { font-size: var(--text-2xl); margin-bottom: 0.5rem; }
.fm-flex-col-gap-2 { display: flex; flex-direction: column; gap: 0.5rem; }
.fm-flex-gap-2 { display: flex; gap: 0.5rem; }
.fm-flex-gap-1 { display: flex; gap: 0.375rem; }
.fm-gap-2 { gap: 0.5rem; }
.fm-p-2 { padding: 0.5rem; }
.fm-p-6 { padding: 1.5rem; }
.fm-px-3-py-2 { padding: 0.6rem 0.9rem; }
.fm-m-0 { margin: 0; }
.fm-text-center { text-align: center; }
.fm-overflow-hidden { overflow: hidden; }

/* ════════════════════════════════════════════════════════════════════
   Plan 17: ai_engine.html utility classes (replace 276 inline styles)
   ════════════════════════════════════════════════════════════════════ */

/* AI Engine specific */
.ae-label-sm { color: var(--text-secondary); font-size: var(--text-sm); }
.ae-label-xs { color: var(--text-secondary); font-size: var(--text-xs); }
.ae-label-muted { color: var(--text-muted); font-size: 0.7rem; }
.ae-input-full { width: 100%; margin-top: 0.25rem; }
.ae-section-title { font-size: var(--text-base); margin-bottom: 0.75rem; }
.ae-section-lg { font-size: var(--text-lg); margin-bottom: 0.5rem; }
.ae-card-body { padding: 1rem; }
.ae-card-pad { padding: 0.5rem 1rem; }
.ae-card-pad-sm { padding: 0.5rem; }
.ae-status-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--text-secondary); margin-left: 0.5rem; }
.ae-status-dot.ok { background: var(--accent-solid); }
.ae-help-text { color: var(--text-secondary); font-size: var(--text-xs); display: block; margin-top: 0.25rem; }
.ae-desc-block { color: var(--text-secondary); font-size: var(--text-sm); margin-bottom: 1rem; }
.ae-toggle-label { font-size: var(--text-sm); color: var(--text-secondary); display: block; }
.ae-toggle-desc { font-size: var(--text-xs); color: var(--text-muted); display: block; }
.ae-test-result { padding: 0.75rem; font-size: var(--text-sm); }
.ae-example-item { padding: 0.5rem 0.75rem; border-radius: 6px; margin-bottom: 0.4rem; font-size: var(--text-sm); }
.ae-intent-row { display: grid; grid-template-columns: auto 90px 1fr auto auto; gap: 0.75rem; align-items: center; padding: 0.6rem 0.8rem; border-radius: 8px; margin-bottom: 0.4rem; font-size: var(--text-sm); }
.ae-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
.ae-grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 1rem; }
.ae-indicator { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--text-secondary); margin-left: 0.5rem; }
.ae-btn-sm { font-size: var(--text-sm); padding: 0.5rem 1rem; }
.ae-margin-top { margin-top: 0.75rem; }
.ae-margin-top-sm { margin-top: 0.25rem; }
.ae-flex-gap { display: flex; gap: 0.5rem; }
.ae-flex-gap-sm { display: flex; gap: 0.25rem; }
.ae-width-full { width: 100%; }
.ae-card:hover { transform: translateY(-1px); border-color: var(--border-secondary); box-shadow: var(--shadow-md); }
:root[data-theme="light"] .ae-card { box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(0,0,0,0.03); }

.ae-col-span-2 { grid-column: span 2; }
.ae-flex-1 { flex: 1; }

.fm-text-base { font-size: var(--text-base); }
.fm-mb-3 { margin-bottom: 0.75rem; }
.fm-font-bold { font-weight: var(--font-bold); }
.fm-font-mono { font-family: var(--font-mono); }
.fm-mt-2 { margin-top: 0.5rem; }

/* Additional utility classes for premium pass */
.fm-label-block { font-size: var(--text-sm); display: block; margin-bottom: 0.25rem; }
.fm-text-xs-muted-2 { font-size: var(--text-xs); color: var(--text-muted); margin-top: 0.25rem; }
.fm-stat-big { font-size: 1.75rem; font-weight: var(--font-bold); margin: 0.25rem 0; }
.fm-progress-track { height: 4px; background: var(--border-primary); border-radius: 2px; overflow: hidden; }
.fm-mb-6 { margin-bottom: 1.5rem; }
.fm-mt-6 { margin-top: 1.5rem; }
.fm-h-12 { height: 48px; }
.fm-h-10 { height: 40px; }
.fm-flex-items-gap-2 { display: flex; align-items: center; gap: 0.5rem; }
.fm-flex-col-gap-3 { display: flex; flex-direction: column; gap: 0.75rem; }
.fm-text-muted-center { color: var(--text-muted); font-size: var(--text-sm); text-align: center; padding: 1rem; }
.fm-font-mono-flex { flex: 1; font-family: var(--font-mono); }
.fm-cursor-pointer { cursor: pointer; }
/* Premium pass batch 4 */
.fm-text-xs { font-size: var(--text-xs); }
.fm-font-medium { font-weight: var(--font-medium); }
.fm-accent-emerald { accent-color: var(--accent-solid); }
.fm-flex-min { flex: 1; min-width: 0; }
.fm-icon-sm-w { width: 0.9rem; }
.fm-hero-title { font-size: 1.75rem; font-weight: var(--font-light); text-align: center; margin-bottom: 0.5rem; }
.fm-center-muted { text-align: center; color: var(--text-muted); margin-bottom: 2rem; }
.fm-click-row { cursor: pointer; display: flex; align-items: center; gap: 0.75rem; padding: 1rem; }
.fm-item-row { display: flex; justify-content: space-between; align-items: center; padding: 0.5rem 0.75rem; background: var(--bg-inset); border-radius: 8px; }
.fm-mb-5 { margin-bottom: 1.25rem; }
.fm-flex-items-gap-3 { display: flex; align-items: center; gap: 0.75rem; }
.fm-icon-sm-wh { width: 0.85rem; height: 0.85rem; }
.fm-p-4 { padding: 2rem 1rem; }
.fm-text-center-mt { text-align: center; margin-top: 1.5rem; }
.fm-click-row-border { cursor: pointer; display: flex; align-items: center; gap: 0.75rem; padding: 1rem; border: 2px solid transparent; }
.fm-text-xl-2 { font-size: 1.5rem; }
.fm-text-left { text-align: left; }
.fm-label-xs-muted { font-size: var(--text-xs); color: var(--text-muted); margin-bottom: 0.3rem; }
.fm-flex-wrap-gap { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.fm-card-img { height: 60px; border-radius: 8px; }
.fm-label-sidebar { display: block; margin-bottom: 0.5rem; font-size: var(--text-sm); font-weight: var(--font-medium); color: rgba(255,255,255,0.7); }
.fm-click-center { cursor: pointer; text-align: center; padding: 1.25rem; border: 2px solid transparent; transition: border-color 0.2s; }
.fm-flex-click { display: flex; align-items: center; gap: 0.5rem; cursor: pointer; }
.fm-chat-layout { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.fm-empty-chat { padding: 2rem; text-align: center; color: var(--text-muted); font-size: var(--text-sm); }
.fm-badge-sm { font-size: var(--text-xs); padding: 0.35rem 0.7rem; }
.fm-input-dark { width: 100%; padding: 0.625rem 0.875rem; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; color: white; }
.fm-btn-ghost-dark { padding: 0.75rem 1rem; background: none; border: none; color: rgba(255,255,255,0.5); cursor: pointer; }
.fm-text-faint { font-size: var(--text-xs); color: rgba(255,255,255,0.35); margin-top: 0.375rem; }
.fm-label-dark { display: block; margin-bottom: 0.375rem; font-size: var(--text-sm); font-weight: var(--font-medium); color: rgba(255,255,255,0.6); }
.fm-input-dark-full { width: 100%; padding: 0.5rem 0.75rem; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; color: white; }
.fm-checkbox-emerald { width: 18px; height: 18px; accent-color: var(--accent-solid); }
.fm-card-mb { padding: 1.5rem; margin-bottom: 1rem; }
.fm-input-dark-2 { width: 100%; padding: 0.625rem 0.875rem; background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; }
.fm-btn-ghost-dark-2 { padding: 0.75rem 1rem; background: none; border: none; color: rgba(255,255,255,0.5); cursor: pointer; font-size: 0.875rem; }
.fm-text-faded { color: rgba(255,255,255,0.5); margin: 0.25rem 0 0; font-size: 0.875rem; }
.fm-text-tiny-faded { font-size: 0.8rem; color: rgba(255,255,255,0.4); }
.fm-btn-emerald { padding: 0.625rem 1.5rem; background: linear-gradient(135deg,var(--accent-solid),#0d9488); border: none; border-radius: 8px; color: white; cursor: pointer; }

.fm-p-1 { padding: 0.4rem; }
.fm-rounded { border-radius: var(--radius-sm); }
.fm-header-row { padding: 0.75rem 1rem; border-bottom: 1px solid var(--border-primary); }
.fm-list-scroll { flex: 1; overflow-y: auto; padding: 0.25rem; }
.fm-msg-area { flex: 1; overflow-y: auto; padding: 1.25rem; display: flex; flex-direction: column; gap: 0.5rem; }
.fm-avatar-circle { width: 36px; height: 36px; border-radius: 50%; background: var(--gradient-brand); display: flex; align-items: center; justify-content: center; color: #fff; font-weight: 600; font-size: 0.875rem; flex-shrink: 0; }
.fm-px-5 { padding: 0 1.25rem; }
.fm-chat-header { padding: 0.75rem 1.25rem; border-bottom: 1px solid var(--border-primary); display: flex; align-items: center; justify-content: space-between; }
.fm-max-w { max-width: 640px; }
.fm-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fm-opacity-30 { opacity: 0.3; }
.fm-chat-input { padding: 0.75rem 1.25rem; border-top: 1px solid var(--border-primary); }

/* ai_engine final batch */
.ae-img-preview { height: 80px; border-radius: 12px; }
.ae-badge-danger { font-size: var(--text-sm); padding: 0.35rem 0.7rem; color: var(--color-error); border: 1px solid var(--color-error); border-radius: 4px; }
.ae-label-margin { margin-top: 0.75rem; font-size: var(--text-sm); color: var(--text-secondary); }
.ae-text-danger { color: var(--color-error); }
.ae-btn-intent { padding: 0.625rem 0.875rem; border-radius: 10px; cursor: pointer; }
.ae-empty-state { text-align: center; color: var(--text-secondary); font-size: var(--text-sm); padding: 2rem; }
.ae-btn-sm-pad { font-size: var(--text-sm); padding: 0.4rem 0.8rem; }

/* ai_engine dynamic badge (replaces inline template literal styles) */
.ae-intent-badge { padding: 2px 8px; border-radius: 6px; font-size: 0.7rem; font-weight: var(--font-semibold); text-transform: uppercase; }
.ae-status-badge { padding: 2px 6px; border-radius: 4px; font-size: 0.7rem; font-weight: var(--font-semibold); }
.ae-provider-card { padding: 0.875rem; border-radius: 12px; cursor: pointer; transition: transform 0.15s, opacity 0.15s, background-color 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s; }
.ae-model-card { padding: 0.75rem; border-radius: 10px; cursor: pointer; }
.ae-rf-badge { font-size: 0.65rem; padding: 1px 6px; border-radius: 4px; }
.ae-event-label { display: flex; align-items: center; gap: 0.25rem; font-size: var(--text-xs); cursor: pointer; padding: 0.125rem 0; }
.ae-event-desc { color: var(--text-muted); font-size: 0.65rem; }
.ae-pattern-row { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--text-secondary); margin-top: 0.3rem; }

/* ═══════════════════════════════════════════════════════════════════════
   PREMIUM UTILITY CLASSES — eliminates 250+ inline styles across templates
   ═══════════════════════════════════════════════════════════════════════ */

/* Text color utilities (68 inline uses → classes) */
.text-primary { color: var(--text-primary) !important; }
.text-secondary { color: var(--text-secondary) !important; }
.text-tertiary { color: var(--text-tertiary) !important; }
.text-muted { color: var(--text-muted) !important; }
.text-emerald { color: var(--accent-text) !important; }
.text-cyan { color: var(--color-cyan) !important; }
.text-violet { color: var(--color-violet) !important; }
.text-amber { color: var(--color-amber) !important; }
.text-rose { color: var(--color-rose) !important; }
.text-center { text-align: center !important; }
.text-right { text-align: right !important; }
.text-left { text-align: left !important; }

/* Font size utilities (30+ inline uses) */
.text-xs { font-size: var(--text-xs) !important; }
.text-sm { font-size: var(--text-sm) !important; }
.text-base { font-size: var(--text-base) !important; }
.text-lg { font-size: var(--text-lg) !important; }
.text-xl { font-size: var(--text-xl) !important; }
.text-2xl { font-size: var(--text-2xl) !important; }
.text-3xl { font-size: var(--text-3xl) !important; }
.text-display { font-size: 2.5rem; font-weight: 200; letter-spacing: -0.04em; font-family: var(--font-display); line-height: 1; }

/* Font weight utilities */
.font-normal { font-weight: var(--font-normal) !important; }
.font-medium { font-weight: var(--font-medium) !important; }
.font-semibold { font-weight: var(--font-semibold) !important; }
.font-bold { font-weight: var(--font-bold) !important; }

/* Margin utilities (top patterns) */
.mt-0 { margin-top: 0 !important; }
.mt-1 { margin-top: var(--space-1) !important; }
.mt-2 { margin-top: var(--space-2) !important; }
.mt-3 { margin-top: var(--space-3) !important; }
.mt-4 { margin-top: var(--space-4) !important; }
.mt-6 { margin-top: var(--space-6) !important; }
.mt-8 { margin-top: var(--space-8) !important; }
.mb-0 { margin-bottom: 0 !important; }
.mb-1 { margin-bottom: var(--space-1) !important; }
.mb-2 { margin-bottom: var(--space-2) !important; }
.mb-3 { margin-bottom: var(--space-3) !important; }
.mb-4 { margin-bottom: var(--space-4) !important; }
.mb-6 { margin-bottom: var(--space-6) !important; }
.mb-8 { margin-bottom: var(--space-8) !important; }

/* Display utilities (37 inline uses) */
.hidden { display: none !important; }
.flex { display: flex !important; }
.inline-flex { display: inline-flex !important; }
.grid { display: grid !important; }
.block { display: block !important; }

/* Flex utilities (14+ inline uses) */
.items-center { align-items: center !important; }
.items-start { align-items: flex-start !important; }
.items-end { align-items: flex-end !important; }
.justify-center { justify-content: center !important; }
.justify-between { justify-content: space-between !important; }
.justify-end { justify-content: flex-end !important; }
.flex-col { flex-direction: column !important; }
.flex-wrap { flex-wrap: wrap !important; }
.flex-1 { flex: 1 !important; }
.gap-1 { gap: var(--space-1) !important; }
.gap-2 { gap: var(--space-2) !important; }
.gap-3 { gap: var(--space-3) !important; }
.gap-4 { gap: var(--space-4) !important; }
.gap-6 { gap: var(--space-6) !important; }

/* Grid utilities (16 inline uses) */
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); }
.grid-auto { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--space-4); }
@media (max-width: 768px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }
  .grid-auto { grid-template-columns: 1fr; }
}

/* Width utilities */
.w-full { width: 100% !important; }
.w-auto { width: auto !important; }
.max-w-prose { max-width: 65ch !important; }
.max-w-md { max-width: 28rem !important; }
.max-w-lg { max-width: 32rem !important; }
.max-w-xl { max-width: 36rem !important; }

/* Badge/chip utilities (replaces 20+ inline badge styles) */
.badge { display: inline-flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-2); border-radius: var(--radius-full); font-size: var(--text-xs); font-weight: var(--font-semibold); border: 1px solid var(--border-secondary); background: var(--bg-inset); color: var(--text-secondary); }
.badge-emerald { background: var(--accent-bg-medium); color: var(--accent-text); border-color: var(--accent-bg-medium); }
.badge-cyan { background: rgba(6, 182, 212, 0.15); color: var(--color-cyan); border-color: rgba(6, 182, 212, 0.25); }
.badge-violet { background: rgba(79, 70, 229, 0.15); color: var(--color-violet); border-color: rgba(79, 70, 229, 0.25); }
.badge-amber { background: rgba(245, 158, 11, 0.15); color: var(--color-amber); border-color: rgba(245, 158, 11, 0.25); }
.badge-rose { background: rgba(244, 63, 94, 0.15); color: var(--color-rose); border-color: rgba(244, 63, 94, 0.25); }

/* Section header utility (replaces 14+ inline) */
.section-header { display: flex; align-items: center; gap: 0.5rem; margin-bottom: var(--space-4); }
.section-title { font-size: var(--text-lg); font-weight: var(--font-semibold); color: var(--text-primary); display: flex; align-items: center; gap: 0.5rem; }
.section-subtitle { font-size: var(--text-sm); color: var(--text-muted); margin-top: var(--space-1); }

/* Empty state centered (replaces 14+ inline) */
.center-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: var(--space-8); text-align: center; color: var(--text-secondary); }

/* Icon sizing (12+ inline uses) */
.icon-sm { width: 1rem; height: 1rem; }
.icon-md { width: 1.25rem; height: 1.25rem; }
.icon-lg { width: 1.5rem; height: 1.5rem; }
.icon-xl { width: 2rem; height: 2rem; }
.ae-pattern-badge { padding: 1px 6px; border-radius: 4px; margin-right: 0.5rem; }
.ae-category-label { font-size: 0.7rem; color: var(--text-secondary); font-weight: var(--font-semibold); margin-bottom: 0.25rem; text-transform: uppercase; }

/* ═══════════════════════════════════════════════════════════════════════
   CINEMATIC PAGE HEADER — universal premium heading for every page
   "Whisper of authority": light-weight gradient text + live status dot
   ЕДИНСТВЕННОЕ определение .fm-page-header (раньше: здесь + :623 + дубли
   в base.html) — flex-модель, отступы shell-пэддинг и position слиты.
   ═══════════════════════════════════════════════════════════════════════ */
.fm-page-header {
  display: flex; justify-content: space-between; align-items: flex-end;
  flex-wrap: wrap; gap: var(--space-4);
  margin-bottom: var(--space-8);
  padding: var(--space-4) var(--space-8) 0;
  max-width: 1440px;
  position: relative;
}
@media (max-width: 768px) { .fm-page-header { padding: var(--space-3) var(--space-4) 0; } }
.fm-page-header-eyebrow {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-muted);
  font-weight: var(--font-medium);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.fm-page-header-eyebrow::before {
  content: '';
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent-text);
  box-shadow: 0 0 12px var(--accent-text);
  animation: fmEyebrowPulse 2.5s ease-in-out infinite;
}
@keyframes fmEyebrowPulse {
  0%, 100% { opacity: 0.6; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.3); }
}
.fm-page-header h1 {
  margin: 0;
  font-size: var(--text-3xl);
  font-weight: 600;                   /* weight-based hierarchy, not gradient (taste-skill) */
  letter-spacing: -0.035em;
  font-family: var(--font-display);
  line-height: 1.1;
  color: var(--text-primary);         /* solid color — no text-fill gradient */
}
.fm-page-header p {
  margin: var(--space-2) 0 0;
  color: var(--text-muted);
  font-size: var(--text-sm);
  max-width: 60ch;
}

/* ═══════════════════════════════════════════════════════════════════════
   CINEMATIC STAT CARD — universal premium metric card
   Huge light-weight number + underglow + icon chip + delta
   ═══════════════════════════════════════════════════════════════════════ */
.fm-metric {
  background: var(--bg-card);
  border: 1px solid var(--border-primary);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  position: relative;
  overflow: hidden;
  box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(255,255,255,0.06);
  transition:
    transform var(--duration-normal) var(--ease-out),
    box-shadow var(--duration-normal) var(--ease-smooth),
    border-color var(--duration-normal) var(--ease-smooth);
}
.fm-metric:hover {
  transform: translateY(-3px);
  border-color: var(--border-secondary);
  box-shadow: var(--shadow-lg), inset 0 1px 0 0 rgba(255,255,255,0.08);
}
/* Underglow by accent — colored shadow beneath the card */
.fm-metric[data-accent="emerald"] { box-shadow: var(--shadow-sm), var(--underglow-emerald), inset 0 1px 0 0 rgba(255,255,255,0.06); }
.fm-metric[data-accent="violet"]  { box-shadow: var(--shadow-sm), var(--underglow-violet), inset 0 1px 0 0 rgba(255,255,255,0.06); }
.fm-metric[data-accent="cyan"]    { box-shadow: var(--shadow-sm), var(--underglow-cyan), inset 0 1px 0 0 rgba(255,255,255,0.06); }
.fm-metric[data-accent="amber"]   { box-shadow: var(--shadow-sm), var(--underglow-amber), inset 0 1px 0 0 rgba(255,255,255,0.06); }
.fm-metric[data-accent="rose"]    { box-shadow: var(--shadow-sm), var(--underglow-rose), inset 0 1px 0 0 rgba(255,255,255,0.06); }
.fm-metric[data-accent="emerald"]:hover { box-shadow: var(--shadow-lg), var(--underglow-emerald), inset 0 1px 0 0 rgba(255,255,255,0.08); }
.fm-metric[data-accent="violet"]:hover  { box-shadow: var(--shadow-lg), var(--underglow-violet), inset 0 1px 0 0 rgba(255,255,255,0.08); }
.fm-metric[data-accent="cyan"]:hover    { box-shadow: var(--shadow-lg), var(--underglow-cyan), inset 0 1px 0 0 rgba(255,255,255,0.08); }
.fm-metric[data-accent="amber"]:hover   { box-shadow: var(--shadow-lg), var(--underglow-amber), inset 0 1px 0 0 rgba(255,255,255,0.08); }
.fm-metric[data-accent="rose"]:hover    { box-shadow: var(--shadow-lg), var(--underglow-rose), inset 0 1px 0 0 rgba(255,255,255,0.08); }
/* Light theme inset = black edge, not white */
:root[data-theme="light"] .fm-metric { box-shadow: var(--shadow-sm), inset 0 1px 0 0 rgba(0,0,0,0.04); }
:root[data-theme="light"] .fm-metric[data-accent="emerald"] { box-shadow: var(--shadow-sm), var(--underglow-emerald), inset 0 1px 0 0 rgba(0,0,0,0.04); }
:root[data-theme="light"] .fm-metric[data-accent="violet"]  { box-shadow: var(--shadow-sm), var(--underglow-violet), inset 0 1px 0 0 rgba(0,0,0,0.04); }
:root[data-theme="light"] .fm-metric[data-accent="cyan"]    { box-shadow: var(--shadow-sm), var(--underglow-cyan), inset 0 1px 0 0 rgba(0,0,0,0.04); }
:root[data-theme="light"] .fm-metric[data-accent="amber"]   { box-shadow: var(--shadow-sm), var(--underglow-amber), inset 0 1px 0 0 rgba(0,0,0,0.04); }
:root[data-theme="light"] .fm-metric[data-accent="rose"]    { box-shadow: var(--shadow-sm), var(--underglow-rose), inset 0 1px 0 0 rgba(0,0,0,0.04); }

.fm-metric-icon {
  width: 40px; height: 40px;
  border-radius: var(--radius-md);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: var(--space-4);
}
.fm-metric[data-accent="emerald"] .fm-metric-icon { background: var(--accent-bg-medium); color: var(--accent-text); }
.fm-metric[data-accent="cyan"] .fm-metric-icon    { background: rgba(6, 182, 212, 0.14); color: var(--color-cyan); }
.fm-metric[data-accent="violet"] .fm-metric-icon  { background: rgba(79, 70, 229, 0.12); color: var(--color-violet); }
.fm-metric[data-accent="amber"] .fm-metric-icon   { background: rgba(245, 158, 11, 0.12); color: var(--color-amber); }
.fm-metric[data-accent="rose"] .fm-metric-icon    { background: rgba(244, 63, 94, 0.12); color: var(--color-rose); }

.fm-metric-label {
  font-size: var(--text-xs); color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.08em;
  margin-bottom: var(--space-2); font-weight: var(--font-medium);
}
.fm-metric-value {
  font-size: var(--text-4xl); font-weight: var(--font-semibold);    /* канон 600 — единый с .fm-stat-value/.fm-kpi-value */
  letter-spacing: -0.035em; font-family: var(--font-display);
  color: var(--text-primary); line-height: 1;
; font-variant-numeric: tabular-nums; }
.fm-metric-delta {
  font-size: var(--text-xs); margin-top: var(--space-3);
  font-weight: var(--font-semibold); display: inline-flex; align-items: center; gap: 4px;
}
.fm-metric-delta.up { color: var(--accent-text); }
.fm-metric-delta.down { color: var(--color-rose); }
.fm-metric-delta.flat { color: var(--text-muted); }

/* ═══════════════════════════════════════════════════════════════════════
   SCROLL REVEAL — universal entrance animation via IntersectionObserver
   Add class .fm-reveal to any element. Pair with growo-reveal.js.
   ═══════════════════════════════════════════════════════════════════════ */
.fm-reveal {
  opacity: 0;
  transform: translateY(24px);
  filter: blur(4px);
  transition:
    opacity 0.7s var(--ease-out),
    transform 0.7s var(--ease-out),
    filter 0.7s var(--ease-out);
  will-change: opacity, transform;
}
.fm-reveal.fm-revealed {
  opacity: 1;
  transform: translateY(0);
  filter: blur(0);
}
/* Stagger children — add .fm-reveal-stagger to a parent container */
.fm-reveal-stagger > .fm-reveal { transition-delay: calc(var(--fm-i, 0) * 80ms); }
@media (prefers-reduced-motion: reduce) {
  .fm-reveal { opacity: 1; transform: none; filter: none; transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════
   PREMIUM NAV ITEM — sidebar links with active glow + sheen
   ═══════════════════════════════════════════════════════════════════════ */
.fm-nav-link {
  position: relative;
  overflow: hidden;
}
.fm-nav-link::before {
  content: '';
  position: absolute;
  top: 0; left: -100%;
  width: 100%; height: 100%;
  background: linear-gradient(90deg, transparent, var(--accent-bg-subtle), transparent);
  transform: skewX(-20deg);
  transition: left 0.6s var(--ease-out);
  pointer-events: none;
}
.fm-nav-link:hover::before { left: 200%; }

/* ════════════════════════════════════════════════════════════════════
   MOBILE ADAPTATION — SYSTEM LAYER (all standalone pages inherit)
   Breakpoint contract (keep consistent; base.html mobile shell ≤1023):
     ≤1280  container padding shrinks (base.html)
     ≤1023  mobile shell: bottom nav + top bar + drawer (base.html)
     ≤900   data tables / dense grids get touch treatment (this block)
     ≤768   single-column grids, page paddings (this file + base.html)
     ≤640   micro adjustments (per-page overrides allowed)
     ≤375   extra-small phones (base.html)
   ════════════════════════════════════════════════════════════════════ */

/* ── .fm-table-wrap: THE wrapper for wide data tables ──
   Usage: <div class="fm-table-wrap"><table class="fm-table">…</table></div>
   Keeps <table> semantics (unlike the bare-table display:block fallback),
   adds momentum touch-scrolling and an edge fade hint on small screens. */
.fm-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  max-width: 100%;
}
.fm-table-wrap table { margin-bottom: 0; }
/* Sticky first column option: add data-sticky-col to the wrapper */
.fm-table-wrap[data-sticky-col] td:first-child,
.fm-table-wrap[data-sticky-col] th:first-child {
  position: sticky; left: 0;
  background: var(--bg-card, var(--bg-card-solid, #fff));
  z-index: 1;
}

/* Touch targets: interactive controls ≥44px hit area on touch screens.
   Visual size can stay smaller — we expand the tappable box via padding. */
@media (hover: none) and (pointer: coarse) {
  .fm-icon-btn, .fm-modal-close, .fm-drawer-close, .fm-more-close,
  .fm-topbar-btn, .fm-avatar-fab, .fm-spa-panel-close,
  .fm-sidebar-toggle, .fm-theme-toggle {
    min-width: 44px; min-height: 44px;
  }
  .fm-tab { padding: 0.75rem 1rem; }
  .fm-toggle-input { width: 44px; height: 24px; }
  .fm-toggle-input::after { width: 20px; height: 20px; }
  .fm-toggle-input:checked::after { transform: translateX(20px); }
}

/* ── ≤900px: dense data surfaces ── */
@media (max-width: 900px) {
  /* Tables: readable data + horizontal scroll inside .fm-table-wrap.
     Bare tables fall back to block+scroll (base.html mobile shell ≤1023). */
  .fm-table, .fm-data-table { font-size: 0.875rem; }
  .fm-table th, .fm-table td { padding: 0.625rem 0.5rem; }
  .fm-table-wrap { margin-inline: calc(var(--space-2, 0.5rem) * -1); padding-inline: var(--space-2, 0.5rem); }

  /* Two-column detail grids collapse early */
  .grid-2 { grid-template-columns: 1fr; }

  /* Drawers (slide-over detail panels) become near-fullscreen */
  .fm-drawer { width: 100%; max-width: 100vw; }

  /* Long action rows wrap instead of overflowing */
  .fm-section-header, .fm-page-header { flex-wrap: wrap; }

  /* Fixed-side layouts (list+detail) stack */
  .fm-split, .fm-master-detail {
    grid-template-columns: 1fr !important;
  }
}

/* ── ≤768px: single column + inputs 16px (no iOS zoom-on-focus) ── */
@media (max-width: 768px) {
  .fm-input, .fm-textarea, select, input[type="text"], input[type="number"],
  input[type="email"], input[type="password"], input[type="tel"], input[type="url"],
  input[type="search"], textarea {
    font-size: max(16px, 1em);
  }
  /* Main data surfaces never below 14px on phones */
  .fm-table, .fm-data-table, .fm-list, .card, .fm-panel { font-size: 0.875rem; }
  .fm-code-pre { font-size: 0.8125rem; }
}

/* ── Viewport meta is centralised in base.html (width=device-width).
      Standalone pages MUST NOT override it with fixed widths. ── */

/* ═════════════════════════════════════════════════════════════════════════
   MOBILE ADAPTATION — SWEEP 2 (ui_artifacts_scan.py: MODAL_CUSTOM /
   FIXED_NO_SAFE / TOUCH_TARGET / plt-table)
   Page-local modal systems (crm / finance / erp / memory / email_domains /
   connectors) get the SAME bottom-sheet geometry on ≤1023 as the system
   .fm-modal (base.html). Only appended here — page CSS keeps its desktop
   look; !important wins because page CSS loads after components.css.
   Analyzer: scripts/ui_artifacts_scan.py (regression contract in
   tests/test_ui_artifacts_scan.py).
   ═════════════════════════════════════════════════════════════════════════ */

@media (max-width: 1023px) {
  /* Overlay-контейнеры: полноэкранный растянутый слой вместо центрирования */
  .crm-modal-overlay,
  .fin-modal,
  .erp-modal,
  .ed-modal-overlay,
  .mem-modal-bg {
    align-items: stretch !important;
    padding: 0 !important;
  }

  /* Карточки модалок → bottom-sheet (зеркально .fm-modal из base.html) */
  .crm-modal,
  .fin-modal-card,
  .erp-modal-card,
  .ed-modal,
  .mem-modal {
    width: 100vw !important;
    max-width: 100vw !important;
    max-height: 100dvh !important;
    border-radius: 0 !important;
    border-left: none !important;
    border-right: none !important;
    overflow-y: auto !important;
  }

  /* connectors: .fm-cn-modal — сам fixed-диалог, центрирован translate */
  .fm-cn-modal {
    top: 0 !important;
    left: 0 !important;
    right: 0 !important;
    bottom: 0 !important;
    transform: none !important;
    width: 100vw !important;
    max-width: 100vw !important;
    max-height: 100dvh !important;
    border-radius: 0 !important;
  }

  /* ae-toast (ai_engine): поднять над нижней навигацией мобильного шелла */
  #ae-toast {
    left: 1rem !important;
    right: 1rem !important;
    bottom: calc(72px + env(safe-area-inset-bottom, 0px)) !important;
    max-width: none !important;
  }
}

/* Touch-таргет ≥44px для кастомных крестиков модалок (системный список —
   в components.css «Touch targets»; этот — дополнение sweep 2) */
@media (hover: none) and (pointer: coarse) {
  .fin-modal-close, .erp-modal-close, .ed-modal-close, .crm-modal-close {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

/* ── .plt-table (platform.html): восстановленные базовые стили таблицы.
   В platform.css правила .plt-table повреждены (битые селекторы) —
   дублируем контракт здесь, пока владелец страницы не починит свой CSS. ── */
.plt-table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.plt-table th {
  text-align: left; padding: 0.625rem 0.5rem; font-weight: 600;
  color: var(--text-muted); border-bottom: 1px solid var(--border-primary);
}
.plt-table td { padding: 0.625rem 0.5rem; border-bottom: 1px solid var(--border-primary); }
.plt-table td strong { color: var(--text-secondary); }

/* ── TEXT WRAP HYGIENE (sweep-3): переносы и overflow текста везде ── */
/* классическая причина горизонтального overflow — flex/grid-дети без min-width */
.fm-split > *, .fm-master-detail > *, .grid-2 > *, .grid-3 > *, .grid-4 > *,
.fm-card, .crm-kpi-card, .crm-panel, .an-wrap > * { min-width: 0; }
/* данные не рвут вёрстку: длинные слова/URL/артикулы переносятся */
.fm-table-wrap td, .fm-table-wrap th, .crm-table-wrap td, .crm-table-wrap th,
.fm-card, .crm-kpi-card, .crm-panel-body, .fm-modal-body, .fm-drawer-body,
.fm-empty, .fm-toast, .fm-growo-ask-input, td, th, .fm-nav-label {
  overflow-wrap: break-word; word-break: break-word; }
/* идентификаторы/URL-ячейки — monospace+break-all на узких */
td.mono, .cell-id, .cell-url { font-family: var(--font-mono, monospace); word-break: break-all; }
/* заголовки панелей — перенос вместо обрезки */
.crm-panel-header h3, .fm-modal-header h3, .fm-drawer-header h3 { overflow-wrap: anywhere; }
/* RU-типографика на узких экранах */
@media (max-width: 768px) {
  p, li, td, th, .fm-card, .crm-kpi-value { hyphens: auto; -webkit-hyphens: auto; }
  h1, h2, h3, h4 { overflow-wrap: anywhere; }
}

/* ═══════════════════════════════════════════════════════════════════════
   ALIGNMENT SYSTEM — единые инварианты выравнивания карточных семейств
   (symmetry pass: KPI / заголовки панелей / футеры / чипы / пустые
   состояния). Правила аддитивны к страничным CSS: компонентный файл
   грузится ПЕРВЫМ, поэтому здесь либо свойства, которых нет на страницах,
   либо селекторы выше специфичностью — без !important.
   Инварианты:
     (a) KPI-карточка = flex-col; последняя строка метрики (тренд/дельта/
         подпись/спарклайн) прижата к низу (margin-top:auto + padding-top
         как минимальный зазор, когда свободного места нет); грид растягивает
         карточки (align-items:stretch — дефолт грида, зафиксирован явно);
     (b) заголовок панели: иконка+текст+действия через 8px-шаг (gap),
         действия прижаты вправо (margin-left:auto последнего ребёнка);
     (c) футер карточки/модалки: primary справа (последний), secondary
         слева, gap 8px;
     (d) чип/бейдж = inline-flex + align-items:center + line-height:1
         (текст всегда отцентрован по вертикали, baseline не «пляшет»);
     (e) списки (диалоги/операторы/клиенты): аватар/иконка центрированы
         по вертикали к тексту (align-items:center — держат свои CSS);
     (f) пустое состояние: иконка+текст центрированы (flex-col + center).
   ═══════════════════════════════════════════════════════════════════════ */

/* ── (a) KPI-карточки: колонка + тренд к низу ──
   .kpi-card (макрос fm_stat) НЕ входит: он горизонтальный (иконка слева
   от блока label+value, align-items:center — единый baseline иконки). */
.fm-kpi-card, .crm-kpi-card, .fin-kpi-card, .sync-kpi-card, .mkt-kpi-card,
.erp-kpi-card, .plt-kpi-card, .fm-stat, .fm-stat-card, .fm-metric {
  display: flex; flex-direction: column; align-items: stretch;
}
/* Гриды метрик: карточки одной строки — одной высоты (фиксация дефолта) */
.fm-kpi-grid, .fm-kpi-row, .crm-kpi-grid, .fin-kpi-grid, .sync-kpi-grid,
.mkt-kpi-grid, .erp-kpi-grid, .plt-kpi-grid, .kpi-grid {
  align-items: stretch;
}
/* Последняя строка метрики прижата к низу карточки:
   margin-top:auto прижимает при растянутой карточке, padding-top
   гарантирует зазор, когда свободного места нет (auto → 0). */
.fm-kpi-card .fm-kpi-delta,
.crm-kpi-card .ag-trend,
.fin-kpi-card .fin-kpi-sub,
.sync-kpi-card .sync-kpi-sub,
.mkt-kpi-card .mkt-kpi-sub,
.erp-kpi-card .erp-kpi-sub,
.plt-kpi-card .plt-kpi-delta,
.fm-stat .fm-stat-sparkline,
.fm-stat-card .fm-stat-sparkline,
.fm-metric .fm-metric-delta {
  margin-top: auto; padding-top: var(--space-2, 0.5rem);
}

/* ── (b) Заголовки панелей: 8px-шаг, действия вправо ── */
.crm-panel-header, .fin-panel-header, .erp-panel-header, .mkt-panel-header,
.sync-panel-header, .fm-panel-header, .fm-section-header, .section-header {
  display: flex; align-items: center; gap: var(--space-2);
}
/* Действия (последний ребёнок не в одиночестве) — прижаты вправо;
   space-between у 2 детей даёт тот же результат, у 3+ (иконка+заголовок+
   действия) без этого правила зазоры распределяются между всеми. */
:is(.crm-panel-header, .fin-panel-header, .erp-panel-header, .mkt-panel-header,
    .sync-panel-header, .fm-panel-header, .fm-section-header, .section-header)
  > *:last-child:not(:only-child) {
  margin-left: auto;
}

/* ── (c) Футеры: primary справа, secondary слева, gap 8px ──
   (в разметке primary — последний ребёнок; justify-end прижимает его
   вправо). .fm-card-footer — канонический класс для футеров карточек. */
.fm-modal-footer, .fm-card-footer,
.crm-modal-footer, .fin-modal-footer, .erp-modal-footer, .mkt-modal-footer {
  display: flex; align-items: center; gap: var(--space-2);
  justify-content: flex-end;
}

/* ── (d) Чипы/бейджи: inline-flex + центрированный текст ── */
.fm-badge, .badge, .crm-badge, .erp-badge,
.fm-panel-chip, .fm-conv-chip, .fm-conv-intent, .fm-asst-chip,
.em-chip, .gm-ms-chip {
  display: inline-flex; align-items: center;
  line-height: 1; vertical-align: middle;
}

/* ── (f) Пустые состояния: иконка+текст центрированы ── */
.fm-empty, .empty-state, .crm-empty, .fin-empty, .mkt-empty, .erp-empty,
.ap-empty, .fm-ag-empty {
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center;
}

/* ── Toast: анимация единая (fade+slideY) на всех экранах — на мобиле
   остаётся только растягивание на ширину экрана, отдельных Y-кадров больше не нужно ── */
@media (max-width: 1023px) {
  .fm-toast-container { align-items: stretch; }
  .fm-toast { max-width: calc(100vw - 1rem); }
}

/* ── Отступы-гигиена: типовые контейнеры без явного padding получают базовый ── */
.crm-panel-body:not([class*="p-0"]):not(.no-pad),
.fm-card > .fm-card-body, .fm-drawer-body, .fm-modal-body {
  padding: var(--space-3);
}
.crm-panel-body > :first-child, .fm-card-body > :first-child,
.fm-drawer-body > :first-child, .fm-modal-body > :first-child { margin-top: 0; }
.crm-panel-body > :last-child, .fm-card-body > :last-child,
.fm-drawer-body > :last-child, .fm-modal-body > :last-child { margin-bottom: 0; }

/* ═══ A11Y & FORMS LAYER (системный — работает на всех страницах через base.html) ═══ */

/* fmBusyGuard (base.html): кнопка, инициировавшая write-fetch (POST/PUT/
   DELETE/PATCH), блокируется до ответа — двойной клик не дублирует запрос.
   pointer-events:none вместо disabled: не ломает layout и обработчики,
   работает и для <a>, и для div-кнопок. Класс ставит/снимает fmBusyGuard. */
.fm-busy-guard {
  pointer-events: none;
  opacity: 0.65;
  cursor: progress;
}
/* Явная busy-кнопка (disabled из обработчика) — тот же визуальный язык */
button[aria-busy="true"], [role="button"][aria-busy="true"] {
  cursor: progress;
  opacity: 0.65;
}

/* Фокус-обводка для полей, где outline сброшен без замены:
   command palette (⌘K) — глобальные компоненты components.css */
.fm-command-palette input:focus-visible,
.fm-cp-input:focus-visible {
  outline: 2px solid var(--accent-text);
  outline-offset: -2px;
}

/* ═══ ALIGNMENT SWEEP-2 — сетка отступов + внутренние компоненты карточек ═══
   Источник фидбека: «alignment и отступы не всегда правильны + в некоторых
   КАРТОЧКАХ не хватает стилей для внутренних компонентов».
   Детекция категорий: scripts/ui_artifacts_scan.py (SPACE_OFF_GRID,
   ICON_TEXT_NOALIGN, GAP_MISMATCH). Блок append-only (sweep-2). */

/* ── Недостающие звенья utility-сетки отступов ──
   (growo-pages.css даёт fm-u-m{b,t}-{2,3,4,6}; 4px-шаг для мелких
   внутренних отступов карточек был недоступен утилитами) ── */
.fm-u-mt-1 { margin-top: var(--space-1); }
.fm-u-mt-5 { margin-top: var(--space-5); }
.fm-u-mb-1 { margin-bottom: var(--space-1); }
.fm-u-p-1  { padding: var(--space-1); }

/* ── Счётчик в заголовке карточки/панели ──
   Раньше — голый span с inline-миксином (font-size/color/padding
   повторялись из страницы в страницу: crm/marketing/bookings/payments/
   email_domains). inline-flex + line-height:1 = чип не раскачивает
   строку заголовка (инвариант чипов из ALIGNMENT SYSTEM). ── */
.fm-count-chip,
.crm-count-chip {
  display: inline-flex;
  align-items: center;
  line-height: 1;
  vertical-align: middle;
  font-size: var(--text-xs);
  font-weight: var(--font-normal);
  color: var(--text-muted);
  background: var(--bg-inset);
  border-radius: var(--radius-full);
  padding: var(--space-1) var(--space-3);
}
/* Пустой счётчик = невидим (иначе «пилюля-призрак» рядом с CTA на чужой вкладке) */
.fm-count-chip:empty,
.crm-count-chip:empty { display: none; }

/* ── Мини-чип статуса (ON/OFF/vN/SUPPRESS) ──
   ai_engine строил их инлайном в JS-строках
   (padding:2px 6px; border-radius:4px; font-size:.7rem — ×N повторов);
   динамический цвет остаётся inline, геометрия — здесь. ── */
.fm-mini-chip {
  display: inline-flex;
  align-items: center;
  line-height: 1;
  vertical-align: middle;
  padding: var(--space-1) var(--space-1);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
}

/* ── Подпись-счётчик рядом с заголовком карточки ──
   ( bookings/marketing: font-weight:400 + muted + 13px inline ) ── */
.fm-count-note {
  font-weight: var(--font-normal);
  color: var(--text-muted);
  font-size: var(--text-sm);
}
