/* ============================================================
   Usability Lab — Design System v2
   ------------------------------------------------------------
   1. Tokens         — палитра, размеры, тени, анимация
   2. Base           — reset, body, ссылки, фокус
   3. App shell      — sidebar + main + topbar (mobile)
   4. Page header    — заголовок + breadcrumb + actions
   5. Components     — buttons, fields, cards, badges, stats,
                       tables→cards, alerts, toasts, copy-link
   6. Pages          — login, error, replay
   7. Animations     — fade-in, lift, slide
   8. Mobile         — drawer-sidebar, card-tables, нюансы
   ============================================================ */


/* ─── 1. TOKENS ──────────────────────────────────────────── */

:root {
  /* Палитра — нейтральный фон, акцент indigo. */
  --color-bg:           #f7f8fa;
  --color-surface:      #ffffff;
  --color-surface-alt:  #f1f3f7;
  --color-surface-2:    #fbfcfd;
  --color-border:       #e5e7eb;
  --color-border-strong:#d1d5db;
  --color-text:         #0f172a;
  --color-text-muted:   #64748b;
  --color-text-soft:    #94a3b8;

  --color-accent:        #4f46e5;
  --color-accent-hover:  #4338ca;
  --color-accent-active: #3730a3;
  --color-accent-soft:   #eef2ff;
  --color-accent-text:   #3730a3;

  --color-green:         #16a34a;
  --color-green-bg:      #dcfce7;
  --color-green-text:    #14532d;

  --color-red:           #dc2626;
  --color-red-bg:        #fef2f2;
  --color-red-text:      #991b1b;

  --color-yellow-bg:     #fef3c7;
  --color-yellow-text:   #92400e;

  --color-purple-bg:     #ede9fe;
  --color-purple-text:   #5b21b6;

  /* Радиусы */
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-pill: 999px;

  /* Тени — слоистые, как у Tailwind */
  --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.05), 0 1px 3px rgba(15, 23, 42, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(15, 23, 42, 0.06), 0 2px 4px -1px rgba(15, 23, 42, 0.04);
  --shadow-lg: 0 10px 15px -3px rgba(15, 23, 42, 0.07), 0 4px 6px -2px rgba(15, 23, 42, 0.05);
  --shadow-focus: 0 0 0 3px var(--color-accent-soft);

  /* Spacing (4px base) */
  --s-1:  4px;  --s-2:  8px;  --s-3: 12px;  --s-4: 16px;
  --s-5: 20px;  --s-6: 24px;  --s-8: 32px;  --s-10: 40px;
  --s-12: 48px; --s-16: 64px;

  /* Типографика */
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --font-mono: "JetBrains Mono", "SF Mono", Consolas, Menlo, monospace;
  --text-xs:  12px;
  --text-sm:  13px;
  --text-base:14px;
  --text-lg:  16px;
  --text-xl:  20px;
  --text-2xl: 24px;
  --text-3xl: 30px;

  /* Анимация */
  --ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out:    cubic-bezier(0.16, 1, 0.3, 1);
  --t-fast:      120ms;
  --t-base:      200ms;
  --t-slow:      300ms;

  /* Layout */
  --sidebar-w: 240px;
  --topbar-h:  56px;

  /* Backwards-compat (для уже существующих inline style="...var(--accent)..." и т.п.) */
  --bg: var(--color-bg);
  --surface: var(--color-surface);
  --border: var(--color-border);
  --text: var(--color-text);
  --muted: var(--color-text-muted);
  --accent: var(--color-accent);
  --accent-hover: var(--color-accent-hover);
  --green: var(--color-green);
  --green-bg: var(--color-green-bg);
  --gray-bg: var(--color-surface-alt);
  --red: var(--color-red);
  --r: var(--r-md);
  --sp: var(--s-4);
  --fs-sm: var(--text-sm);
  --fs-base: var(--text-base);
  --fs-lg: var(--text-lg);
  --fs-xl: var(--text-xl);
  --fs-2xl: var(--text-2xl);
}


/* ─── 2. BASE ────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color: var(--color-accent);
  text-decoration: none;
  transition: color var(--t-fast) var(--ease);
}
a:hover { color: var(--color-accent-hover); }

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--color-surface-alt);
  padding: 1px 6px;
  border-radius: var(--r-xs);
  color: var(--color-text);
}

:focus-visible {
  outline: none;
  box-shadow: var(--shadow-focus);
  border-radius: var(--r-sm);
}


/* ─── 3. APP SHELL ───────────────────────────────────────── */
/*
  Layout:
   ┌──────────────┬───────────────────┐
   │   sidebar    │       main        │
   │   (240px)    │  (page content)   │
   └──────────────┴───────────────────┘
  На мобиле sidebar становится off-canvas drawer'ом.
*/

body.page-admin {
  display: flex;
  min-height: 100vh;
}

.app-sidebar {
  width: var(--sidebar-w);
  flex-shrink: 0;
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  z-index: 50;
}
.app-sidebar-brand {
  padding: var(--s-5) var(--s-5) var(--s-4);
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-weight: 600;
  font-size: var(--text-lg);
  color: var(--color-text);
  border-bottom: 1px solid var(--color-border);
}
.app-sidebar-brand-mark {
  width: 28px;
  height: auto;
  flex-shrink: 0;
  display: block;
}
.app-sidebar-brand-tag {
  font-size: var(--text-xs);
  font-weight: 500;
  color: var(--color-text-muted);
  background: var(--color-surface-alt);
  padding: 2px var(--s-2);
  border-radius: var(--r-pill);
  margin-left: auto;
}
.app-sidebar-nav {
  flex: 1;
  padding: var(--s-3) var(--s-3);
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow-y: auto;
}
.app-sidebar-nav a {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: 500;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.app-sidebar-nav a:hover {
  background: var(--color-surface-alt);
  color: var(--color-text);
}
.app-sidebar-nav a.active {
  background: var(--color-accent-soft);
  color: var(--color-accent-text);
}
.app-sidebar-nav a svg {
  width: 18px; height: 18px;
  flex-shrink: 0;
  stroke: currentColor;
}
.app-sidebar-section {
  margin-top: var(--s-4);
  margin-bottom: var(--s-1);
  padding: 0 var(--s-3);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-text-soft);
}
.app-sidebar-footer {
  border-top: 1px solid var(--color-border);
  padding: var(--s-3);
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-size: var(--text-sm);
}
.app-sidebar-user {
  flex: 1;
  min-width: 0;
}
.app-sidebar-user-name {
  font-weight: 500;
  color: var(--color-text);
  text-decoration: none;
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.app-sidebar-user-role {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}
.app-sidebar-logout {
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}

.app-main {
  flex: 1;
  min-width: 0;
  padding: var(--s-8) var(--s-8) var(--s-12);
}

/* Topbar — на десктопе скрыт, на мобиле появляется с гамбургером */
.app-topbar {
  display: none;
  align-items: center;
  gap: var(--s-3);
  height: var(--topbar-h);
  padding: 0 var(--s-4);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: 30;
}
.app-topbar-hamburger {
  background: none;
  border: none;
  padding: var(--s-2);
  cursor: pointer;
  border-radius: var(--r-md);
  color: var(--color-text);
  transition: background-color var(--t-fast) var(--ease);
}
.app-topbar-hamburger:hover { background: var(--color-surface-alt); }
.app-topbar-hamburger svg { width: 20px; height: 20px; }
.app-topbar-title {
  font-weight: 600;
  font-size: var(--text-base);
}

.app-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.4);
  z-index: 40;
  opacity: 0;
  transition: opacity var(--t-base) var(--ease);
}
.app-backdrop.visible {
  display: block;
  opacity: 1;
}


/* ─── 4. PAGE HEADER ─────────────────────────────────────── */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-bottom: var(--s-6);
  animation: fadeInUp var(--t-slow) var(--ease-out) both;
}
.page-header-info { min-width: 0; }
.page-header-breadcrumb {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-bottom: var(--s-2);
}
.page-header-breadcrumb a {
  color: var(--color-text-muted);
}
.page-header-breadcrumb a:hover { color: var(--color-text); }
.page-header-breadcrumb-sep { color: var(--color-text-soft); }
/* Крошка-ссылка/-span содержит иконку + текст — выравниваем по центру.
   Иконка приглушена, чтобы не перетягивать внимание с текста (Group C). */
.page-header-breadcrumb a,
.page-header-breadcrumb > span {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
}
.page-header-breadcrumb svg { opacity: 0.7; }
.page-header h1 {
  margin: 0;
  font-size: var(--text-3xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--color-text);
}
.page-header-sub {
  margin: var(--s-2) 0 0;
  color: var(--color-text-muted);
  font-size: var(--text-base);
}
.page-header-actions {
  display: flex;
  gap: var(--s-2);
  flex-shrink: 0;
}

.section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  flex-wrap: wrap;
  margin: var(--s-10) 0 var(--s-3);
}
.section-header h2 {
  margin: 0;
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--color-text);
  letter-spacing: -0.01em;
}
.section-header-hint {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.app-main h1 {
  margin: 0 0 var(--s-6);
  font-size: var(--text-3xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--color-text);
  animation: fadeInUp var(--t-slow) var(--ease-out) both;
}
.app-main h2 {
  margin: var(--s-10) 0 var(--s-3);
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.01em;
}
.app-main h2:first-child { margin-top: 0; }
.app-main h3 {
  margin: var(--s-6) 0 var(--s-2);
  font-size: var(--text-lg);
  font-weight: 600;
}

/* Старый .container поддержан для login/error страниц */
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: var(--s-8) var(--s-6);
  animation: fadeIn var(--t-slow) var(--ease-out) both;
}


/* ─── 5. COMPONENTS ──────────────────────────────────────── */

/* 5.1 Buttons -------------------------------------------- */
.btn-primary, .btn-secondary, .btn-link {
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  border-radius: var(--r-md);
  padding: var(--s-2) var(--s-4);
  border: 1px solid transparent;
  transition: all var(--t-fast) var(--ease);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  text-align: center;
  min-height: 38px;
  line-height: 1.4;
  user-select: none;
}
.btn-primary {
  background: var(--color-accent);
  color: #fff;
  box-shadow: var(--shadow-xs);
}
.btn-primary:hover {
  background: var(--color-accent-hover);
  color: #fff;
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.btn-primary:active {
  background: var(--color-accent-active);
  transform: translateY(0);
  box-shadow: var(--shadow-xs);
}
.btn-secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border-color: var(--color-border);
}
.btn-secondary:hover {
  background: var(--color-surface-alt);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}
.btn-secondary:active {
  background: var(--color-border);
}
.btn-link {
  background: transparent;
  color: var(--color-accent);
  padding: 0;
  border: none;
  min-height: 0;
  font-weight: 500;
  cursor: pointer;
  text-decoration: none;
}
.btn-link:hover { color: var(--color-accent-hover); }
/* Модификатор для destructive-действий (отозвать, удалить, отключить) */
.btn-link.btn-link-danger { color: var(--color-red); }
.btn-link.btn-link-danger:hover { color: var(--color-red-text); }

/* Опасное действие — сплошная красная кнопка.
   Используется на «Удалить безвозвратно», «Отозвать» и т.п. вместо
   btn-primary (раньше destructive-кнопки ошибочно были индиго). */
.btn-danger {
  background: var(--color-red);
  color: #fff;
  border: 1px solid var(--color-red);
  border-radius: var(--r-md);
  padding: var(--s-2) var(--s-4);
  font-size: var(--text-sm);
  font-weight: 500;
  cursor: pointer;
  transition: all var(--t-fast) var(--ease);
}
.btn-danger:hover {
  background: var(--color-red-text);
  border-color: var(--color-red-text);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.btn-danger:active { transform: translateY(0); }
.btn-danger:focus { outline: none; box-shadow: var(--shadow-focus); }

/* Copy-link — заметная кнопка с feedback */
.copy-link {
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  text-align: center;
  line-height: 1.4;
  background: var(--color-surface);
  color: var(--color-accent);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  padding: var(--s-2) var(--s-3);
  min-height: 36px;
  transition: all var(--t-fast) var(--ease);
}
.copy-link:hover {
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
  color: var(--color-accent-hover);
  transform: translateY(-1px);
  box-shadow: var(--shadow-xs);
}
.copy-link--ok {
  background: var(--color-green-bg) !important;
  color: var(--color-green-text) !important;
  border-color: var(--color-green) !important;
  animation: pop var(--t-base) var(--ease-out);
}
.copy-link--fail {
  background: var(--color-red-bg) !important;
  color: var(--color-red) !important;
  border-color: var(--color-red) !important;
  animation: shake 0.3s var(--ease);
}

/* 5.1b Icons --------------------------------------------- */
/* SVG-иконки рендерятся макросом _macros/icons.html.
   Цвет наследуется от текста (stroke=currentColor). */
.icon {
  display: inline-block;
  vertical-align: middle;
  flex-shrink: 0;
}

/* 5.2 Form fields --------------------------------------- */
.field { display: block; margin-bottom: var(--s-4); }
.field > span {
  display: block;
  margin-bottom: var(--s-1);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-text);
}
.field input:not([type="checkbox"]):not([type="radio"]),
.field textarea,
.field select {
  width: 100%;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  background: var(--color-surface);
  font: inherit;
  color: var(--color-text);
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
  min-height: 40px;
}
.field input::placeholder { color: var(--color-text-soft); }
.field input:focus,
.field textarea:focus,
.field select:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: var(--shadow-focus);
}

/* Чекбоксы / радио — нормального размера, перекрашиваем в акцент. */
.field input[type="checkbox"],
.field input[type="radio"] {
  width: 18px;
  height: 18px;
  margin: 0;
  cursor: pointer;
  accent-color: var(--color-accent);
}
/* File input: стилизуем нативную кнопку под себя. */
.field input[type="file"] {
  padding: 6px;
  background: var(--color-surface);
  cursor: pointer;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.field input[type="file"]::file-selector-button {
  background: var(--color-surface-alt);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--r-sm);
  padding: 4px 14px;
  margin-right: var(--s-3);
  font: inherit;
  font-weight: 500;
  font-size: var(--text-sm);
  cursor: pointer;
  transition: all var(--t-fast) var(--ease);
}
.field input[type="file"]::file-selector-button:hover {
  background: var(--color-accent-soft);
  border-color: var(--color-accent);
  color: var(--color-accent-text);
}
.field-wide { flex: 1 1 320px; }

.form-inline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: flex-end;
  background: var(--color-surface);
  padding: var(--s-5);
  border-radius: var(--r-lg);
  border: 1px solid var(--color-border);
  margin-bottom: var(--s-6);
  box-shadow: var(--shadow-xs);
}
.form-inline .field { margin: 0; }

.form-stack {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  max-width: 400px;
  background: var(--color-surface);
  padding: var(--s-6);
  border-radius: var(--r-lg);
  border: 1px solid var(--color-border);
  box-shadow: var(--shadow-sm);
}
.form-stack .field { margin: 0; }
.form-stack button { align-self: flex-start; }

/* 5.3 Alerts -------------------------------------------- */
/* Inline-баннеры: error (red), success (green), warning (yellow),
   info (accent). Базовая геометрия общая, отличается только палитра. */
.alert, .alert-success, .alert-warning, .alert-info {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  margin-bottom: var(--s-4);
  font-size: var(--text-sm);
  border: 1px solid transparent;
  animation: fadeInUp var(--t-base) var(--ease-out);
}
.alert {
  background: var(--color-red-bg);
  color: var(--color-red-text);
  border-color: rgba(220, 38, 38, 0.2);
}
.alert-success {
  background: var(--color-green-bg);
  color: var(--color-green-text);
  border-color: rgba(22, 163, 74, 0.2);
  padding: var(--s-4) var(--s-5);
}
.alert-warning {
  background: var(--color-yellow-bg);
  color: var(--color-yellow-text);
  border-color: color-mix(in srgb, var(--color-yellow-text) 30%, transparent);
}
.alert-info {
  background: var(--color-accent-soft);
  color: var(--color-accent-text);
  border-color: color-mix(in srgb, var(--color-accent) 30%, transparent);
}
.token-box {
  display: flex;
  gap: var(--s-2);
  align-items: center;
  margin-top: var(--s-3);
  flex-wrap: wrap;
}
.token-box code {
  flex: 1 1 240px;
  background: var(--color-surface);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--color-border);
  word-break: break-all;
}

/* 5.4 Cards & action-row -------------------------------- */
.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  align-items: center;
  margin: var(--s-4) 0 var(--s-6);
  padding: var(--s-3) var(--s-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
}
.csv-export-row {
  display: flex;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin-bottom: var(--s-6);
}
.csv-export-row a { text-decoration: none; }

/* 5.5 Tables (desktop) ---------------------------------- */
table.data {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
}
table.data th, table.data td {
  padding: var(--s-3) var(--s-4);
  text-align: left;
  border-bottom: 1px solid var(--color-border);
  vertical-align: top;
}
table.data th {
  background: var(--color-surface-2);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-text-muted);
  font-weight: 600;
}
table.data tbody tr:last-child td { border-bottom: none; }
table.data tbody tr { transition: background-color var(--t-fast) var(--ease); }
table.data tbody tr:hover { background: var(--color-surface-2); }
table.data tr.row-muted { color: var(--color-text-muted); }
table.data tr.row-muted strong { color: var(--color-text-muted); }

table.env-table th {
  width: 180px;
  background: var(--color-surface);
  color: var(--color-text);
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  font-size: var(--text-sm);
}
table.env-table td { word-break: break-word; }

/* 5.6 Badges -------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--s-2);
  border-radius: var(--r-pill);
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 1.6;
}
.badge-green { background: var(--color-green-bg); color: var(--color-green-text); }
.badge-gray  { background: var(--color-surface-alt); color: var(--color-text-muted); }
.badge-violet{ background: rgba(79, 70, 229, 0.12); color: var(--color-accent); }

/* 5.6b Owner groups (admin: «Все прототипы») ------------- */
.owner-group { margin-top: var(--s-6); }
.owner-group:first-of-type { margin-top: var(--s-4); }
.owner-group__header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  margin-bottom: var(--s-2);
}
.owner-group__header h2 {
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* 5.7 Stats --------------------------------------------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--s-4);
  margin-bottom: var(--s-6);
}
.stat {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  padding: var(--s-5);
  box-shadow: var(--shadow-xs);
  transition: transform var(--t-base) var(--ease-out),
              box-shadow var(--t-base) var(--ease-out);
}
.stat:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.stat-val {
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.1;
  color: var(--color-text);
}
.stat-lbl {
  color: var(--color-text-muted);
  margin-top: var(--s-2);
  font-size: var(--text-sm);
  font-weight: 500;
}
.stat-sub {
  color: var(--color-text-soft);
  font-size: var(--text-xs);
  margin-top: var(--s-1);
}

/* 5.8 Список прототипов на дашборде --------------------- */
.proto-list { list-style: none; padding: 0; margin: 0; }
.proto-list li {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-2);
  transition: transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
.proto-list li:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.proto-list a { font-weight: 500; }

/* 5.9 Empty state --------------------------------------- */
.empty-state {
  text-align: center;
  padding: var(--s-12) var(--s-6);
  background: var(--color-surface);
  border: 1px dashed var(--color-border);
  border-radius: var(--r-lg);
  color: var(--color-text-muted);
}
.empty-state-icon {
  width: 48px; height: 48px;
  margin: 0 auto var(--s-3);
  color: var(--color-text-soft);
  opacity: 0.6;
}
.empty-state-title {
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--color-text);
  margin-bottom: var(--s-1);
}
.empty-state-illustration {
  width: 320px;
  max-width: 100%;
  height: auto;
  margin: 0 auto var(--s-4);
  display: block;
}

/* 5.9b Study cards — список исследований проекта (Group C, C2a) -- */
.study-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--s-3);
  margin: var(--s-4) 0 var(--s-6);
}
.study-card {
  display: block;
  padding: var(--s-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  transition: border-color var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease);
}
a.study-card:hover {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-md);
}
.study-card-name {
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: var(--s-2);
}
.study-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
/* Locked-карточка: серый фон, пунктир, замок — Study виден по имени, но
   содержимое недоступно (информационная прозрачность, C2a). */
.study-card--locked {
  background: var(--color-surface-alt);
  border-style: dashed;
  box-shadow: none;
}
.study-card--locked .study-card-name {
  display: flex;
  align-items: center;
  gap: var(--s-1);
  font-weight: 500;
  color: var(--color-text-muted);
}
.study-card-locked-note {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin: 0 0 var(--s-3);
}

/* 5.10 Cell actions (на десктопе) ----------------------- */
td.actions-cell { white-space: nowrap; }
td.actions-cell .copy-link { margin-right: var(--s-2); }
td.actions-cell .copy-link + .btn-link,
td.actions-cell .copy-link + a.btn-link { margin-left: var(--s-1); }

/* Действия-ссылки (несколько inline-ссылок в одной ячейке).
   Разделяем `·` между ними и слегка отличаем от обычных btn-link'ов. */
.action-link {
  font: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--color-accent);
  font-weight: 500;
  transition: color var(--t-fast) var(--ease);
}
.action-link:hover { color: var(--color-accent-hover); text-decoration: underline; }
.action-links { display: inline; }
.action-links > * { display: inline; }
.action-links > * + *::before {
  content: "·";
  margin: 0 var(--s-2);
  color: var(--color-text-soft);
  font-weight: normal;
}

/* 5.11 Timeline ----------------------------------------- */
.timeline-table td { vertical-align: top; }
.timeline-badge {
  display: inline-block;
  min-width: 60px;
  text-align: center;
  margin-right: var(--s-2);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
  padding: 2px var(--s-2);
}
.timeline-badge-click    { background: var(--color-accent-soft); color: var(--color-accent-text); }
.timeline-badge-key      { background: var(--color-purple-bg);   color: var(--color-purple-text); }
.timeline-badge-input    { background: var(--color-green-bg);    color: var(--color-green-text); }
.timeline-badge-pageview { background: var(--color-yellow-bg);   color: var(--color-yellow-text); }

/* 5.12 Top clicks --------------------------------------- */
.top-clicks-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--s-3);
  margin-bottom: var(--s-6);
}
.top-clicks-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  padding: var(--s-4);
  box-shadow: var(--shadow-xs);
  transition: transform var(--t-base) var(--ease-out),
              box-shadow var(--t-base) var(--ease-out);
}
.top-clicks-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.top-clicks-head {
  margin-bottom: var(--s-2);
  display: flex;
  gap: var(--s-2);
  align-items: center;
}
.top-clicks-list { padding-left: 0; margin: 0; list-style: none; }
.top-clicks-list li {
  display: grid;
  grid-template-columns: 36px 1fr;
  gap: 4px var(--s-3);
  align-items: baseline;
  padding: var(--s-2) 0;
  border-bottom: 1px solid var(--color-border);
}
.top-clicks-list li:last-child { border-bottom: none; }
.top-clicks-count {
  grid-row: 1 / span 2;
  align-self: start;
  margin-top: 2px;
  text-align: right;
  font-weight: 700;
  color: var(--color-accent);
  font-size: var(--text-lg);
  font-variant-numeric: tabular-nums;
}
.top-clicks-text {
  font-size: var(--text-base);
  word-break: break-word;
}
.top-clicks-list li > .muted.small {
  grid-column: 2;
  word-break: break-all;
}

/* 5.13 Toast notifications ------------------------------ */
.toast-container {
  position: fixed;
  bottom: var(--s-4);
  right: var(--s-4);
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  max-width: 360px;
  pointer-events: none;
}
.toast {
  background: var(--color-text);
  color: #fff;
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  font-size: var(--text-sm);
  display: flex;
  align-items: center;
  gap: var(--s-2);
  animation: toastIn var(--t-base) var(--ease-out);
  pointer-events: auto;
}
.toast--ok { background: var(--color-green-text); }
.toast--fail { background: var(--color-red); }
.toast.hide { animation: toastOut var(--t-base) var(--ease) forwards; }

/* 5.14 Modal / Dialog ----------------------------------- */
/* Универсальный модальный компонент на нативном <dialog>.
   Открытие/закрытие — window.ulabModal или dialog.showModal()/close().
   Esc и focus-trap работают из коробки. Макрос — _macros/components.html. */
dialog.modal {
  border: none;
  border-radius: var(--r-lg);
  padding: 0;
  background: var(--color-surface);
  box-shadow: var(--shadow-lg);
  max-width: 500px;
  width: calc(100vw - var(--s-8));
  color: var(--color-text);
}
dialog.modal--sm { max-width: 380px; }
dialog.modal--lg { max-width: 720px; }
dialog.modal::backdrop {
  background: color-mix(in srgb, var(--color-text) 40%, transparent);
  backdrop-filter: blur(2px);
}
.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--color-border);
}
.modal-title {
  font-size: var(--text-lg);
  font-weight: 600;
  margin: 0;
}
.modal-close {
  background: transparent;
  border: none;
  cursor: pointer;
  padding: var(--s-1);
  color: var(--color-text-muted);
  border-radius: var(--r-sm);
  display: inline-flex;
  transition: all var(--t-fast) var(--ease);
}
.modal-close:hover {
  background: var(--color-surface-alt);
  color: var(--color-text);
}
.modal-body {
  padding: var(--s-5);
  font-size: var(--text-base);
  line-height: 1.5;
}
.modal-footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--s-2);
  padding: var(--s-4) var(--s-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-alt);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}

/* 5.15 Layout & utilities -------------------------------- */
/* Маленький набор классов вместо повторяющихся inline-style.
   Вертикальный ритм по-хорошему живёт в компонентах — mt-* здесь
   как переходный костыль до Phase 3.5 (IA Refresh). */
.app-shell-content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
/* <form> с inline-кнопкой действия в ячейке таблицы / ряду действий. */
.form-inline-action { display: inline; }
/* Поле с inline-раскладкой (чекбокс/радио + подпись в строку). */
.field-inline {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.is-hidden { display: none; }
.mt-1 { margin-top: var(--s-1); }
.mt-2 { margin-top: var(--s-2); }
.mt-3 { margin-top: var(--s-3); }
.mt-4 { margin-top: var(--s-4); }
.mt-6 { margin-top: var(--s-6); }
.p-4  { padding: var(--s-4); }


/* ─── 6. PAGES ───────────────────────────────────────────── */

/* Login */
.page-login {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-4);
  background:
    radial-gradient(ellipse at top, var(--color-accent-soft), transparent 60%),
    var(--color-bg);
}
.login-shell { width: 100%; max-width: 380px; }
.login-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-xl);
  padding: var(--s-8);
  box-shadow: var(--shadow-lg);
  animation: fadeInUp var(--t-slow) var(--ease-out);
}
.login-title {
  margin: 0 0 var(--s-1);
  font-size: var(--text-2xl);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.login-wordmark {
  display: block;
  width: 240px;
  max-width: 100%;
  height: auto;
  margin: 0 auto var(--s-3);
}
.login-sub { margin: 0 0 var(--s-6); color: var(--color-text-muted); }
.login-note { margin: var(--s-4) 0 0; color: var(--color-text-muted); font-size: var(--text-xs); }
.login-card .btn-primary { width: 100%; margin-top: var(--s-2); }

/* Error */
.page-error {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-4);
}
.error-shell { max-width: 480px; width: 100%; }
.error-card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-xl);
  padding: var(--s-10);
  text-align: center;
  box-shadow: var(--shadow-md);
  animation: fadeInUp var(--t-slow) var(--ease-out);
}
.error-card h1 { margin: 0 0 var(--s-3); font-size: var(--text-2xl); font-weight: 700; }

/* ─── 7. ANIMATIONS ──────────────────────────────────────── */

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.05); }
  100% { transform: scale(1); }
}
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}
@keyframes toastIn {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes toastOut {
  to { opacity: 0; transform: translateY(10px); }
}
@keyframes slideInRight {
  from { transform: translateX(100%); }
  to   { transform: translateX(0); }
}
@keyframes slideOutRight {
  to { transform: translateX(100%); }
}

/* Сетка карточек в фид появляется стопкой с лёгкой задержкой между ними */
.stat-grid > .stat { animation: fadeInUp var(--t-slow) var(--ease-out) both; }
.stat-grid > .stat:nth-child(1) { animation-delay: 0ms; }
.stat-grid > .stat:nth-child(2) { animation-delay: 60ms; }
.stat-grid > .stat:nth-child(3) { animation-delay: 120ms; }
.stat-grid > .stat:nth-child(4) { animation-delay: 180ms; }
.stat-grid > .stat:nth-child(5) { animation-delay: 240ms; }


/* ─── 8. MOBILE (max-width: 900px) ───────────────────────── */

@media (max-width: 900px) {
  body.page-admin {
    flex-direction: column;
  }

  /* Topbar появляется */
  .app-topbar { display: flex; }

  /* Sidebar становится off-canvas */
  .app-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    transform: translateX(-100%);
    transition: transform var(--t-base) var(--ease);
    box-shadow: var(--shadow-lg);
    height: 100vh;
  }
  body.sidebar-open .app-sidebar { transform: translateX(0); }
  body.sidebar-open .app-backdrop { display: block; opacity: 1; }

  .app-main { padding: var(--s-4) var(--s-3) var(--s-8); }

  .page-header { gap: var(--s-2); }
  .page-header h1 { font-size: var(--text-2xl); }
  .page-header-actions { width: 100%; }
  .page-header-actions .btn-primary,
  .page-header-actions .btn-secondary { flex: 1; }

  .app-main h2 { font-size: var(--text-lg); margin: var(--s-6) 0 var(--s-2); }
  .app-main h3 { font-size: var(--text-base); }

  /* Формы: один столбец */
  .form-inline {
    flex-direction: column;
    align-items: stretch;
    padding: var(--s-4);
    gap: var(--s-3);
  }
  .form-inline .field,
  .form-inline .field-wide { flex: 1 1 auto; width: 100%; }
  .form-inline button { width: 100%; }

  .form-stack { padding: var(--s-5); }

  .action-row { flex-direction: column; align-items: stretch; }
  .action-row > * { width: 100%; text-align: center; }
  .csv-export-row { flex-direction: column; }
  .csv-export-row a { width: 100%; text-align: center; }

  /* Таблицы → карточки */
  table.data {
    display: block;
    width: 100%;
    background: transparent;
    border: none;
    box-shadow: none;
    overflow: visible;
  }
  table.data thead { display: none; }
  table.data tbody { display: block; }
  table.data tr {
    display: block;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--r-lg);
    box-shadow: var(--shadow-xs);
    padding: var(--s-3) var(--s-4);
    margin-bottom: var(--s-3);
    animation: fadeInUp var(--t-base) var(--ease-out) both;
  }
  table.data tbody tr:hover { background: var(--color-surface); }
  table.data tr.row-muted { opacity: 0.55; }
  table.data td {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--s-3);
    padding: var(--s-1) 0;
    border-bottom: none;
    text-align: right;
    font-size: var(--text-base);
    min-width: 0;
    word-break: break-word;
  }
  table.data td::before {
    content: attr(data-label);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    font-weight: 500;
    text-align: left;
    flex-shrink: 0;
  }
  table.data td[data-label=""]::before,
  table.data td:not([data-label])::before { content: none; }

  table.data tr > td:first-child {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
    font-size: var(--text-lg);
    font-weight: 600;
    padding: 0 0 var(--s-2);
    margin-bottom: var(--s-2);
    border-bottom: 1px solid var(--color-border);
  }
  table.data tr > td:first-child::before { display: none; }

  table.data td.actions-cell {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-start;
    gap: var(--s-2);
    padding: var(--s-3) 0 0;
    margin-top: var(--s-2);
    border-top: 1px solid var(--color-border);
    text-align: left;
    white-space: normal;
  }
  table.data td.actions-cell::before { display: none; }
  table.data td.actions-cell > * { margin: 0; }
  table.data td.actions-cell .copy-link { flex: 1 1 auto; min-width: 140px; }

  /* env-table остаётся таблицей */
  table.env-table { display: table; background: var(--color-surface);
                    border: 1px solid var(--color-border); border-radius: var(--r-lg);
                    box-shadow: var(--shadow-xs); overflow: hidden; }
  table.env-table thead { display: table-header-group; }
  table.env-table tbody { display: table-row-group; }
  table.env-table tr {
    display: table-row; background: transparent; border: none;
    border-radius: 0; box-shadow: none; padding: 0; margin: 0;
  }
  table.env-table th, table.env-table td {
    display: table-cell;
    border-bottom: 1px solid var(--color-border);
    padding: var(--s-2) var(--s-3);
    white-space: normal;
    text-align: left;
    font-size: var(--text-sm);
  }
  table.env-table th::before, table.env-table td::before { display: none; }
  table.env-table th { width: 110px; font-size: var(--text-xs); }

  /* Stat-grid: чуть плотнее */
  .stat-grid { gap: var(--s-3); }
  .stat { padding: var(--s-4); }
  .stat-val { font-size: 26px; }

  /* Login / error на мобиле */
  .login-card, .error-card { padding: var(--s-6); border-radius: var(--r-lg); }

  /* Heatmap infobar */
  #ulab-heatmap-infobar { font-size: var(--text-xs); }
}

/* ============================================================
 * 6. Replay page — плеер + таймлайн действий
 *    Страница занимает ровно вьюпорт: скролл только внутри таймлайна,
 *    плеер пересчитывается под доступное место (см. replay.js).
 * ============================================================ */
/* Пиним сам body к вьюпорту: иначе min-height:100vh + длинный таймлайн
   растягивают body, а flex:1 у .app-main делает height:100vh бесполезным. */
body.page-replay {
  height: 100vh;
  overflow: hidden;
}
body.page-replay .app-main {
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: var(--s-4) var(--s-6);
}
body.page-replay .app-main > .replay-crumbs,
body.page-replay .replay-header,
body.page-replay .replay-toolbar { flex: 0 0 auto; margin: 0; }
.replay-crumbs { margin: 0; }

.replay-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-3);
}
.replay-header__title {
  margin: 0 0 2px;
  font-size: var(--text-xl);
  line-height: 1.1;
}
.replay-header > div p { margin: 0; }
.replay-header__stats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  font-variant-numeric: tabular-nums;
}
.replay-header__stats > span:first-child {
  background: var(--color-surface-alt);
  padding: 4px var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--color-border);
  font-size: var(--text-sm);
}

.replay-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--s-3);
}
.replay-filters {
  display: flex;
  gap: var(--s-1);
  flex-wrap: wrap;
}
.replay-chip {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text-muted);
  padding: 4px var(--s-3);
  border-radius: var(--r-pill);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}
.replay-chip:hover { background: var(--color-surface-alt); color: var(--color-text); }
.replay-chip.active {
  background: var(--color-accent);
  color: #fff;
  border-color: var(--color-accent);
}
.replay-jump {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.replay-followlabel {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}
.replay-followlabel input { accent-color: var(--color-accent); }

.replay-wrap {
  display: flex;
  gap: var(--s-3);
  align-items: stretch;
  flex: 1 1 auto;
  min-height: 0;
}
.replay-player-col {
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}
.replay-player-wrap {
  flex: 1 1 auto;
  min-height: 0;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  padding: var(--s-2);
  box-shadow: var(--shadow-xs);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.replay-timeline {
  flex: 0 0 340px;
  height: 100%;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.replay-events {
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-y: auto;
  flex: 1 1 auto;
  scroll-behavior: smooth;
}
.replay-event {
  display: grid;
  grid-template-columns: 56px 24px 1fr;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--color-border);
  cursor: pointer;
  outline: none;
  transition: background var(--t-fast);
}
.replay-event:hover { background: var(--color-surface-alt); }
.replay-event:focus-visible { background: var(--color-surface-alt); box-shadow: inset 2px 0 0 var(--color-accent); }
.replay-event.is-active {
  background: rgba(79, 70, 229, 0.10);
  box-shadow: inset 3px 0 0 var(--color-accent);
}
.replay-event__time {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  padding-top: 1px;
}
.replay-event__icon {
  font-size: 16px;
  line-height: 1.2;
  text-align: center;
}
.replay-event__body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.replay-event__title {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}
.replay-event__label {
  font-size: var(--text-sm);
  color: var(--color-text);
  word-break: break-word;
}
.replay-event__detail {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, monospace);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Цветные акценты по типу события */
.replay-event--click    .replay-event__icon { color: #16a34a; }
.replay-event--input    .replay-event__icon { color: var(--color-accent); }
.replay-event--key      .replay-event__icon { color: #f59e0b; }
.replay-event--pageview .replay-event__icon { color: #0891b2; }

#replayPlayer {
  display: flex;
  justify-content: center;
  align-items: center;
}
#replayPlayer .rr-player {
  margin: 0 auto;
  border-radius: var(--r-md);
  overflow: hidden;
}

/* ── HUD: мышь + клавиатура (input-оверлей) ───────────── */
.replay-hud {
  flex: 0 0 auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  padding: var(--s-2) var(--s-3);
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
}

/* Мышь */
.hud-mouse {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex: 0 0 auto;
}
.hud-mouse-body {
  position: relative;
  width: 34px;
  height: 50px;
  border: 2px solid var(--color-border-strong);
  border-radius: 17px;
  background: var(--color-surface-alt);
}
.hud-mouse-btn {
  position: absolute;
  top: 0;
  width: 50%;
  height: 46%;
  transition: background var(--t-fast), box-shadow var(--t-fast);
}
.hud-mouse-btn--left {
  left: 0;
  border-radius: 15px 0 0 0;
  border-right: 1px solid var(--color-border-strong);
}
.hud-mouse-btn--right {
  right: 0;
  border-radius: 0 15px 0 0;
}
.hud-mouse-wheel {
  position: absolute;
  top: 10px;
  left: 50%;
  transform: translateX(-50%);
  width: 4px;
  height: 10px;
  border-radius: 2px;
  background: var(--color-border-strong);
}
.hud-mouse-btn.hud-active {
  background: var(--color-accent);
  box-shadow: 0 0 12px 2px rgba(79, 70, 229, 0.55);
}
.hud-cap {
  font-size: 10px;
  color: var(--color-text-muted);
}

/* Клавиатура */
.hud-keyboard {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex: 0 0 auto;
}
.hud-keyboard__main {
  display: flex;
  flex-direction: column;
  gap: 5px;
}
.kbd-row {
  display: flex;
  gap: 5px;
}
.kbd-key {
  min-width: 32px;
  height: 26px;
  padding: 0 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 500;
  color: var(--color-text-muted);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-bottom-width: 2px;
  border-radius: 6px;
  transition: background var(--t-fast), color var(--t-fast),
              box-shadow var(--t-fast), transform var(--t-fast);
  user-select: none;
  white-space: nowrap;
}
.kbd-key--wide { min-width: 78px; }
.kbd-key--mod { color: var(--color-accent); }
.kbd-key--typing { min-width: 72px; font-style: italic; }
.kbd-key.hud-active {
  background: var(--color-accent);
  color: #fff;
  border-color: var(--color-accent);
  box-shadow: 0 0 12px 2px rgba(79, 70, 229, 0.5);
  transform: translateY(1px);
}
.kbd-arrows {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

/* Подпись текущего действия */
.hud-caption {
  flex: 1 1 200px;
  min-width: 0;
  font-size: var(--text-sm);
  color: var(--color-text);
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--r-md);
  padding: var(--s-2) var(--s-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Единая панель управления (всё под плеером) ──────────── */
.replay-controls {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  padding: var(--s-2) var(--s-4);
}

/* Полоса прогресса */
.rc-progress-row {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}
.rc-time {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  min-width: 42px;
  text-align: center;
}
.rc-progress {
  position: relative;
  flex: 1 1 auto;
  height: 16px;
  display: flex;
  align-items: center;
  cursor: pointer;
  touch-action: none;
}
.rc-progress::before {
  content: "";
  position: absolute;
  left: 0; right: 0;
  height: 6px;
  border-radius: 3px;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
}
.rc-progress__fill {
  position: absolute;
  left: 0;
  width: 0%;
  height: 6px;
  border-radius: 3px;
  background: var(--color-accent);
}
.rc-progress__knob {
  position: absolute;
  left: 0;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--color-accent);
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  transform: translateX(-50%);
}

/* Ряд кнопок — по центру */
.rc-buttons {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}
.rc-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-width: 34px;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  color: var(--color-text);
  font-size: var(--text-sm);
  padding: 6px var(--s-3);
  border-radius: var(--r-pill);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast),
              border-color var(--t-fast);
}
.rc-btn:hover { background: var(--color-border); }
.rc-btn.active {
  background: var(--color-accent);
  color: #fff;
  border-color: var(--color-accent);
}
/* Главная кнопка плей — крупнее, акцентная */
.rc-btn--play {
  font-size: var(--text-lg);
  min-width: 46px;
  padding: 6px var(--s-4);
  background: var(--color-accent);
  color: #fff;
  border-color: var(--color-accent);
}
.rc-btn--play:hover { background: var(--color-accent-hover); }

/* Кнопки-тумблеры оверлеев: ● виден / ○ скрыт */
.rc-btn.off { opacity: 0.6; }
#fsTimeline::before, #fsKeyboard::before { content: "● "; color: var(--color-accent); }
#fsTimeline.off::before, #fsKeyboard.off::before { content: "○ "; color: var(--color-text-muted); }
.rc-exit {
  background: rgba(220, 38, 38, 0.1);
  border-color: rgba(220, 38, 38, 0.35);
  color: var(--color-red);
}
.rc-exit:hover { background: rgba(220, 38, 38, 0.18); }
.rc-sep {
  width: 1px;
  align-self: stretch;
  background: var(--color-border);
  margin: 2px 2px;
}

/* Переключатель скорости */
.rc-speeds {
  display: inline-flex;
  gap: 2px;
  background: var(--color-surface-alt);
  border: 1px solid var(--color-border);
  border-radius: var(--r-pill);
  padding: 2px;
}
.rc-speed {
  border: none;
  background: transparent;
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  padding: 4px 9px;
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: background var(--t-fast), color var(--t-fast);
}
.rc-speed:hover { color: var(--color-text); }
.rc-speed.active {
  background: var(--color-accent);
  color: #fff;
}

.rc-follow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  white-space: nowrap;
}
.rc-follow input { accent-color: var(--color-accent); }
/* fs-only кнопки видны только в полноэкранном режиме */
.rc-fsonly { display: none; }
.replay-wrap.is-fs .rc-fsonly { display: inline-flex; }

/* ── Полноэкранный режим ──────────────────────────────────
   Фуллскрин = класс .is-fs на .replay-wrap (псевдо-фуллскрин
   position:fixed — надёжно, без Fullscreen API). Таймлайн и
   клавиатура — полупрозрачные оверлеи, ярче при наведении. */
.replay-wrap.is-fs {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #0c0c12;
  padding: var(--s-2);
  gap: var(--s-2);
}
.replay-wrap.is-fs .replay-player-wrap {
  background: transparent;
  border: none;
  border-radius: 0;
  box-shadow: none;
  padding: 0;
}
/* Панель управления остаётся в потоке под плеером и поверх оверлеев */
.replay-wrap.is-fs .replay-controls {
  position: relative;
  z-index: 300;
}

/* Таймлайн — узкий полупрозрачный оверлей справа */
.replay-wrap.is-fs .replay-timeline {
  position: absolute;
  top: var(--s-2);
  right: var(--s-2);
  bottom: 64px;
  width: 300px;
  height: auto;
  z-index: 100;
  border: 1px solid rgba(0, 0, 0, 0.06);
  border-radius: var(--r-lg);
  background: rgba(255, 255, 255, 0.96);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
  opacity: 0.5;
  transition: opacity var(--t-fast);
}
/* Клавиатура+мышь — полупрозрачный оверлей слева снизу */
.replay-wrap.is-fs .replay-hud {
  position: absolute;
  left: var(--s-2);
  bottom: 64px;
  z-index: 100;
  border-radius: var(--r-lg);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
  opacity: 0.5;
  transition: opacity var(--t-fast);
}
/* При наведении оверлеи становятся непрозрачными */
.replay-wrap.is-fs .replay-timeline:hover,
.replay-wrap.is-fs .replay-hud:hover { opacity: 1; }

/* Скрытие отдельных оверлеев — только в фуллскрине.
   Вне фуллскрина таймлайн и клавиатура видны всегда. */
.replay-wrap.is-fs.fs-hide-timeline .replay-timeline { display: none; }
.replay-wrap.is-fs.fs-hide-keyboard .replay-hud { display: none; }

/* ── Вспышка клика поверх записи ──────────────────────────
   ripple вставляется в .replayer-wrapper (координаты записи),
   масштабируется вместе с прототипом. Двойной клик — красный. */
.ulab-click-ripple {
  position: absolute;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
  z-index: 50;
  background: rgba(79, 70, 229, 0.30);
  border: 3px solid rgba(79, 70, 229, 0.85);
  animation: ulab-ripple 0.55s ease-out forwards;
}
.ulab-click-ripple--dbl {
  background: rgba(220, 38, 38, 0.32);
  border-color: rgba(220, 38, 38, 0.9);
}
@keyframes ulab-ripple {
  0%   { width: 22px;  height: 22px;  opacity: 0.7; }
  100% { width: 130px; height: 130px; opacity: 0; }
}

/* ── Попап горячих клавиш ─────────────────────────────────── */
.replay-help {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(12, 12, 18, 0.55);
  backdrop-filter: blur(2px);
}
.replay-help[hidden] { display: none; }
.replay-help__card {
  background: var(--color-surface);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--s-5) var(--s-6);
  max-width: 460px;
  width: calc(100% - 48px);
}
.replay-help__card h3 { margin: 0 0 var(--s-3); }
.replay-help__list {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 8px var(--s-4);
  margin: 0 0 var(--s-4);
}
.replay-help__list dt {
  font-weight: 600;
  white-space: nowrap;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--text-sm);
  color: var(--color-accent);
}
.replay-help__list dd {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-text);
}

/* ── Адаптив: невысокие экраны (ноутбуки 1080p, iPad landscape) ── */
@media (max-height: 880px) {
  body.page-replay .app-main { padding: var(--s-3) var(--s-5); }
  .replay-header__title { font-size: var(--text-lg); }
  .hud-mouse-body { width: 28px; height: 42px; border-radius: 14px; }
  .kbd-key { height: 22px; min-width: 28px; font-size: 10px; padding: 0 5px; }
  .kbd-key--wide { min-width: 62px; }
  .kbd-key--typing { min-width: 60px; }
  .replay-hud { gap: var(--s-3); padding: 6px var(--s-3); }
}

/* ── Адаптив: узкие экраны (планшет portrait, телефон) ──
   Здесь fit-to-screen отключаем — страница может скроллиться. */
@media (max-width: 1080px) {
  .replay-timeline { flex-basis: 280px; }
}
@media (max-width: 860px) {
  body.page-replay { height: auto; overflow: visible; }
  body.page-replay .app-main {
    overflow: visible;
  }
  .replay-wrap { flex-direction: column; }
  .replay-player-wrap { min-height: 320px; }
  .replay-timeline {
    flex: 0 0 auto;
    height: auto;
    max-height: 380px;
  }
  .replay-header { align-items: flex-start; }
  .replay-controls { justify-content: center; }
  .replay-hud { justify-content: center; }
}

/* ── Кастомный file-input (Phase 2.9.1) ──
   Нативный <input type=file> спрятан, но фокусируем (не display:none —
   иначе ломается required-валидация формы). Видимая кнопка + имя файла. */
.file-input-native {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.file-input-row {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
}
.file-input-pick {
  padding: 5px 12px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--r-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font: inherit;
  cursor: pointer;
}
.file-input-pick:hover { background: var(--color-surface-alt); }
.file-input-name { color: var(--color-text-muted); font-size: var(--text-sm); }
.file-input-name.has-file { color: var(--color-text); font-weight: 500; }
.file-input-clear {
  padding: 2px 6px;
  border: none;
  background: none;
  color: var(--color-accent);
  font: inherit;
  cursor: pointer;
}

/* ── Подсветка строки, созданной через AJAX (Phase 2.9.2) ── */
@keyframes just-created-fade {
  from { background-color: var(--color-green-bg); }
  to   { background-color: transparent; }
}
.just-created { animation: just-created-fade 2s ease-out; }

/* ── Пакетное создание magic-ссылок (Phase 2.9.2, Wave B) ── */
.batch-block { margin-top: var(--s-6); }
.batch-block h2 { margin-bottom: var(--s-1); }

.batch-table input {
  width: 100%;
  box-sizing: border-box;
  padding: 5px 8px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--r-sm);
  font: inherit;
}
.batch-table input:focus {
  outline: none;
  border-color: var(--color-accent);
}
.batch-table .batch-input--error {
  border-color: var(--color-red);
  background: var(--color-red-bg);
}
.batch-table .actions-cell { width: 36px; text-align: center; }
.batch-row-del {
  color: var(--color-red);
  font-size: var(--text-base);
  line-height: 1;
}

.batch-footer {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--color-border);
}
.batch-footer .btn-primary { margin-left: auto; }

/* ── Выбор типа прототипа (Phase 3, Wave B) ── */
.kind-options {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
}
.kind-option {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--text-sm);
  cursor: pointer;
}
.kind-option--disabled {
  cursor: not-allowed;
  opacity: 0.6;
}
