/* =============================================================================
   BanketPro · Polish PRO
   Production-grade унификация: focus-states, borders, padding, transitions.
   Подключается ПОСЛЕ всех остальных CSS — перекрывает мелкие неконсистентности.
   Палитра не меняется. Шрифт не меняется.

   АРХИТЕКТУРА СЛОЁВ CSS (порядок подключения см. base.html) — НАМЕРЕННАЯ:
     tokens.css         — источник истины: переменные/палитра/scale.
     components.css      — БАЗОВЫЕ примитивы (.bp-btn/.bp-card/.bp-table/...).
     polish-pro.css      — РЕФАЙНМЕНТ-слой: осознанно переопределяет ряд базовых
                           значений примитивов (padding/border/typography/states)
                           до «прод-грейд» вида. Это не дубль-ошибка, а слой:
                           базовые правила в components.css, финальная доводка тут.
     production-fixes.css — поэкранные/кросс-каттинг фиксы, подключается ПОСЛЕДНИМ.
   Полное «схлопывание» слоёв в один файл осознанно НЕ делается без visual-
   regression тулинга — риск визуальных регрессий на 100+ шаблонах выше выгоды.
   ============================================================================= */

/* ═══ 1. FOCUS RINGS — единый стиль для всего проекта ═══════════════════════
   Принцип: 2px solid var(--accent) outline + 2px offset, тонкий glow.
   Это значительно заметнее tab-навигации, чем дефолтный браузерный.
   Применяется только для :focus-visible (клавиатура), не для click.
   =========================================================================== */
:where(.bp-app, .bp-public) :focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
  box-shadow: 0 0 0 4px color-mix(in oklab, var(--accent) 18%, transparent);
  transition: box-shadow var(--dur-fast) var(--ease-out),
              outline-offset var(--dur-fast) var(--ease-out);
}

/* Inputs / textareas / selects — особый focus с цветной рамкой + glow */
.bp-input:focus-visible,
.bp-textarea:focus-visible,
.bp-select:focus-visible,
input[type="text"]:focus-visible,
input[type="email"]:focus-visible,
input[type="password"]:focus-visible,
input[type="tel"]:focus-visible,
input[type="search"]:focus-visible,
input[type="date"]:focus-visible,
input[type="time"]:focus-visible,
input[type="datetime-local"]:focus-visible,
input[type="number"]:focus-visible,
input[type="url"]:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: none !important;
  border-color: var(--accent) !important;
  box-shadow:
    0 0 0 4px color-mix(in oklab, var(--accent) 14%, transparent),
    0 1px 2px rgba(0,0,0,.04) inset !important;
}

/* Также при mouse-focus у инпутов — мягкий ring (не agressive) */
.bp-input:focus,
.bp-textarea:focus,
.bp-select:focus,
input:focus,
textarea:focus,
select:focus {
  border-color: var(--accent);
  box-shadow:
    0 0 0 3px color-mix(in oklab, var(--accent) 12%, transparent);
  outline: none;
}

/* Стандартный transition на все интерактивные поля — без него focus резкий */
.bp-input, .bp-textarea, .bp-select, input, textarea, select {
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
  /* Защита от случайного наследования декораций (line-through из status-text
     или underline в a-родителе) — это давало визуальную «полоску» сквозь
     значение в `<select>`. */
  text-decoration: none;
  text-underline-offset: 0;
}

/* ═══ 2. INPUT POLISH — высота, padding, типографика ════════════════════════
   ВАЖНО: `height: auto` критично — без него фиксированная `height: var(--input-h)`
   из components.css = 32px не вмещает line-height 1.4 × 14px = 19.6px текста +
   2 × 8px padding + 2px border (всего 37.6px). Descender'ы у «р», «у», «д»,
   etc. вылезают за нижний border и выглядят как «полоска сквозь текст».
   Минимум 38px = безопасный target для font-size 14 + line-height 1.4. */
.bp-input, .bp-select, input[type="text"], input[type="email"],
input[type="password"], input[type="tel"], input[type="search"],
input[type="date"], input[type="time"], input[type="number"], input[type="url"] {
  height: auto;
  min-height: 38px;
  padding: 8px 12px;
  font-size: 14px;
  line-height: 1.4;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-elev);
  color: var(--fg);
  font-family: inherit;
  width: 100%;
}
.bp-textarea, textarea {
  min-height: 80px;
  padding: 10px 12px;
  font-size: 14px;
  line-height: 1.5;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--bg-elev);
  color: var(--fg);
  font-family: inherit;
  width: 100%;
  resize: vertical;
}

/* Disabled state */
.bp-input:disabled, .bp-textarea:disabled, .bp-select:disabled,
input:disabled, textarea:disabled, select:disabled {
  background: var(--bg-subtle);
  color: var(--fg-muted);
  cursor: not-allowed;
  opacity: 0.85;
}

/* Error state — красная рамка + лёгкий glow */
.bp-input.is-invalid, .bp-textarea.is-invalid, .bp-select.is-invalid,
.bp-field--error .bp-input, .bp-field--error .bp-textarea, .bp-field--error .bp-select,
input.is-invalid, textarea.is-invalid {
  border-color: var(--danger) !important;
  background: color-mix(in oklab, var(--danger) 4%, var(--bg-elev));
}
.bp-input.is-invalid:focus, .bp-textarea.is-invalid:focus, .bp-select.is-invalid:focus,
.bp-field--error .bp-input:focus, input.is-invalid:focus, textarea.is-invalid:focus {
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--danger) 18%, transparent) !important;
}

/* Success state — мягкая зелёная рамка */
.bp-input.is-valid, .bp-field--success .bp-input {
  border-color: var(--ok);
}

/* ═══ 3. LABEL POLISH ═══════════════════════════════════════════════════════ */
.bp-field { display: flex; flex-direction: column; gap: 6px; }
.bp-field__label,
label.bp-field__label,
.bp-form label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--fg);
  line-height: 1.3;
  margin-bottom: 0;
}
/* Required marker (asterisk) — унифицированная стилизация */
.bp-field--required > .bp-field__label::after,
.bp-field__label.is-required::after {
  content: '*';
  color: var(--danger);
  margin-left: 2px;
  font-weight: 700;
}
/* Если в шаблоне используется inline <span style="color:var(--danger);">*</span> —
   немного облагородим визуально (без размера, но с правильным spacing) */
.bp-field__label span[style*="--danger"],
.bp-field__label span[style*="color:var(--danger)"] {
  margin-left: 2px;
  font-weight: 700;
  letter-spacing: 0;
}
/* Поле disabled → label slightly faded */
.bp-field:has(input:disabled, textarea:disabled, select:disabled) .bp-field__label {
  color: var(--fg-muted);
}

/* Опциональный маркер у label — «— необязательно» рядом с подписью поля */
.bp-field__optional {
  color: var(--fg-subtle);
  font-weight: 400;
  font-size: 12px;
  margin-left: 4px;
  letter-spacing: 0;
}

/* Field hint — единая стилизация */
.bp-field__hint, .form-text {
  font-size: 12px;
  color: var(--fg-muted);
  line-height: 1.4;
  margin-top: 4px;
}
.bp-field__error,
.bp-form .errorlist,
.bp-form ul.errorlist {
  font-size: 12px;
  color: var(--danger);
  line-height: 1.4;
  margin-top: 4px;
  list-style: none;
  padding: 0;
}
.bp-form .errorlist li { padding: 0; }

/* ═══ 4. BUTTON POLISH ══════════════════════════════════════════════════════ */
.bp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--btn-h, 30px);
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.005em;
  line-height: 1.2;
  border-radius: var(--radius-md);
  border: 1px solid var(--border-strong);
  background: var(--bg-elev);
  color: var(--fg);
  cursor: pointer;
  text-decoration: none;
  user-select: none;
  white-space: nowrap;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
  position: relative;
}
.bp-btn:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--bg-hover);
  border-color: var(--fg-faint);
}
.bp-btn:active:not(:disabled):not([aria-disabled="true"]) {
  transform: scale(0.97);
  background: var(--bg-sunken);
}
.bp-btn:disabled, .bp-btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

.bp-btn--sm { min-height: var(--btn-h-sm, 26px); padding: 4px 10px; font-size: 12.5px; }
.bp-btn--lg { min-height: var(--btn-h-lg, 36px); padding: 10px 18px; font-size: 14px; }
.bp-btn--icon { padding: 0; width: var(--btn-h, 30px); aspect-ratio: 1; }
.bp-btn--icon.bp-btn--sm { width: var(--btn-h-sm, 26px); }
.bp-btn--icon.bp-btn--lg { width: var(--btn-h-lg, 36px); }
.bp-btn--block { width: 100%; }

/* Accent button — индиго fill */
.bp-btn--accent {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}
.bp-btn--accent:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
}
.bp-btn--accent:active:not(:disabled):not([aria-disabled="true"]) {
  background: var(--accent-press);
  border-color: var(--accent-press);
}

/* Ghost button — прозрачный */
.bp-btn--ghost {
  background: transparent;
  border-color: transparent;
}
.bp-btn--ghost:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--bg-hover);
}

/* Danger button */
.bp-btn--danger {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
.bp-btn--danger:hover:not(:disabled):not([aria-disabled="true"]) {
  background: var(--danger-strong);
  border-color: var(--danger-strong);
}

/* ═══ 5. CARD POLISH ════════════════════════════════════════════════════════ */
.bp-card {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out);
}
.bp-card__head {
  padding: 14px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  border-bottom: 1px solid var(--border);
  min-height: 50px;
}
.bp-card__title { font-size: 14px; font-weight: 600; letter-spacing: -0.005em; }
.bp-card__body { padding: 16px; }
.bp-card__foot {
  padding: 12px 16px;
  border-top: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  background: var(--bg-subtle);
}

/* ═══ 6. PAGE HEAD — единый ритм ════════════════════════════════════════════ */
.bp-page__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border);
}
.bp-page__head-text { flex: 1; min-width: 0; }
.bp-page__title {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.022em;
  line-height: 1.2;
  margin: 0;
}
.bp-page__sub {
  font-size: 13.5px;
  color: var(--fg-muted);
  margin: 6px 0 0;
  line-height: 1.5;
}
.bp-page__head-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* ─── Mobile (<= 480px): стек title→subtitle→actions, action-кнопки растягиваются ─
   До этого правила .bp-page__head был flex-wrap: wrap без media query, и при
   узкой ширине title сжимался до ~30px → H1 ломался по одному слову на строку.
   Audit (Subagent B, VIS-CR1): затронуты ВСЕ list pages. */
@media (max-width: 480px) {
  .bp-page__head {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .bp-page__head-actions {
    width: 100%;
    justify-content: stretch;
  }
  .bp-page__head-actions > .bp-btn { flex: 1 0 auto; min-width: 0; }
  .bp-page__title { font-size: 20px; }
  .bp-page__sub { font-size: 13px; }
}

/* ─── Mobile (<= 768px): tap targets ≥ 44px (WCAG 2.5.5) ────────────────────
   Tokens декларируют --tap-min: 44px, но --btn-h-sm = 26px (desktop ok,
   mobile нет). На phones bump small buttons до --tap-min для thumb
   accuracy. Audit (Subagent B, VIS-CR3). */
@media (max-width: 768px) {
  .bp-btn--sm {
    min-height: var(--tap-min);
    padding-top: 8px;
    padding-bottom: 8px;
  }
  .bp-btn--icon.bp-btn--sm {
    width: var(--tap-min);
    height: var(--tap-min);
  }
}

/* ─── Settings tabs — скрываем горизонтальный scrollbar когда tabs влезают
   (но оставляем scroll-возможность для очень узких экранов). Без этого
   браузер рендерит тонкую серую полоску у правого края на чуть-overflow. */
.bp-tabs--settings {
  scrollbar-width: none;       /* Firefox */
  -ms-overflow-style: none;    /* IE 10+ */
}
.bp-tabs--settings::-webkit-scrollbar {
  display: none;               /* Chrome, Safari, Edge */
}

/* ─── Empty-state inside table — sticky к viewport (VIS-CR2) ─────────────────
   Когда .bp-empty рендерится внутри <td colspan> в bp-table с
   min-width: max-content, контейнер empty наследует широкую ширину таблицы и
   CTA-кнопка прячется за горизонтальным scroll. Решение:
   1. Если таблица содержит empty (:has) — снимаем min-width (нечего scroll'ить).
   2. Сам .bp-empty становится sticky к viewport как backup.
   Применяется только на mobile (<= 760px). */
@media (max-width: 760px) {
  .bp-table:has(.bp-empty) {
    min-width: 0 !important;
    width: 100%;
  }
  .bp-table .bp-empty {
    position: sticky;
    left: 0;
    width: calc(100vw - 48px);
    max-width: 100%;
    box-sizing: border-box;
    margin: 0 auto;
  }
}

/* ═══ 7. TOOLBAR — все фильтры и поиски выровнены по baseline ═══════════════ */
.bp-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}
.bp-toolbar .bp-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 12px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  min-height: var(--input-h, 38px);
  min-width: 220px;
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out);
}
.bp-toolbar .bp-search:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 12%, transparent);
}
.bp-toolbar .bp-search input {
  border: 0;
  background: transparent;
  outline: none;
  flex: 1;
  font-size: 13.5px;
  min-height: 32px;
  box-shadow: none !important;
}
.bp-toolbar .bp-search input:focus { box-shadow: none !important; border: 0; }

/* ═══ 8. CHIPS / CHIP BUTTONS — единый ритм ═════════════════════════════════ */
.bp-chips {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.bp-chipbtn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 12px;
  font-size: 12px;
  font-weight: 500;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--bg-elev);
  color: var(--fg-muted);
  cursor: pointer;
  text-decoration: none;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color var(--dur-fast) var(--ease-out),
    color var(--dur-fast) var(--ease-out);
}
.bp-chipbtn:hover:not(.is-active):not(:disabled) {
  background: var(--bg-hover);
  border-color: var(--fg-faint);
  color: var(--fg);
}
.bp-chipbtn.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
}

/* ═══ 9. MODAL POLISH — entry animation + consistent paddings ═══════════════ */
.bp-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(15, 15, 15, 0.45);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: bp-modal-bg 240ms var(--ease-out);
}
.bp-modal-overlay[hidden] { display: none; }
.bp-modal {
  background: var(--bg-elev);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-pop);
  max-width: 100%;
  max-height: calc(100vh - 48px);
  overflow: auto;
  display: flex;
  flex-direction: column;
  animation: bp-modal-pop 280ms var(--ease-out);
}
.bp-modal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--border);
}
.bp-modal__title {
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.bp-modal__sub {
  font-size: 13px;
  color: var(--fg-muted);
  margin-top: 4px;
  line-height: 1.4;
}
.bp-modal__body { padding: 16px 20px; flex: 1; }
.bp-modal__foot {
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  background: var(--bg-subtle);
}
@keyframes bp-modal-bg { from { opacity: 0; } to { opacity: 1; } }
@keyframes bp-modal-pop {
  from { opacity: 0; transform: translateY(12px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Mobile (≤780, shell-брейк): диалог → bottom-sheet для ОБЕИХ систем оверлеев.
   ВАЖНО по каскаду: глобальная система модалок (_partials/modals.html) содержит
   template-scoped <style>, который грузится ПОСЛЕ всех linked-CSS и задаёт
   `.bp-modal-overlay{align-items:flex-start; padding:80px...}` + `.bp-modal` без
   max-height (top-aligned диалог, чей footer уезжал под таб-бар на узких
   экранах). Чтобы выиграть каскад без правки шаблонов, поднимаем специфичность
   через `body ...` (0,1,1 / 0,2,1) — это перебивает плоские `.bp-modal-overlay`
   (0,1,0) независимо от порядка подключения. max-height резервирует место под
   таб-бар + safe-area; padding-top сохраняем небольшим, чтобы шит не лип к топбару. */
@media (max-width: 780px) {
  body .bp-modal-overlay { padding: 12px 0 0; align-items: flex-end; }
  body .bp-modal-overlay > .bp-modal {
    width: 100%;
    max-width: 100%;
    max-height: calc(100dvh - var(--mobile-tabbar-h) - env(safe-area-inset-bottom, 0px) - 8px);
    overflow: auto;
    border-radius: var(--radius-xl, 16px) var(--radius-xl, 16px) 0 0;
  }
}

/* ═══ 10. TABLE — row hover + paddings ══════════════════════════════════════ */
.bp-table { width: 100%; border-collapse: collapse; }
.bp-table th, .bp-table td { padding: 11px 14px; vertical-align: middle; font-size: 13.5px; }
.bp-table thead th {
  background: var(--bg-subtle);
  font-weight: 600;
  font-size: 12px;
  color: var(--fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  border-bottom: 1px solid var(--border);
}
.bp-table tbody tr { border-bottom: 1px solid var(--border); transition: background-color var(--dur-fast) var(--ease-out); }
.bp-table tbody tr:last-child { border-bottom: none; }
.bp-table tbody tr:hover { background: var(--bg-hover); }
.bp-th--right, .bp-td--right { text-align: right; }
.bp-th--center, .bp-td--center { text-align: center; }

/* ═══ 11. SCROLL-REVEAL для CRM-страниц ═════════════════════════════════════
   Те же hooks как на landing — `.bp-reveal` ставится автоматически на:
   - .bp-page__head
   - .bp-card в основном контенте
   - .bp-metric (для dashboard 4-метрики)
   Triggering в motion.js через IntersectionObserver.
   =========================================================================== */
body.bp-has-shell .bp-card,
body.bp-has-shell .bp-metric,
body.bp-has-shell .bp-table-wrap {
  /* Базовая позиция уже задана в motion.css через .bp-reveal — здесь только
     fallback на случай если IntersectionObserver недоступен. */
  animation-fill-mode: both;
}

/* Hover-lift для интерактивных карточек (clickable cards) */
.bp-card.is-clickable,
.bp-card[role="link"],
.bp-card[data-href],
.bp-event-card,
.bp-task-card,
.bp-client-card {
  cursor: pointer;
  transition:
    border-color var(--dur-fast) var(--ease-out),
    box-shadow var(--dur-fast) var(--ease-out),
    transform var(--dur-fast) var(--ease-out);
}
.bp-card.is-clickable:hover,
.bp-card[role="link"]:hover,
.bp-card[data-href]:hover,
.bp-event-card:hover,
.bp-task-card:hover,
.bp-client-card:hover {
  transform: translateY(-2px);
  border-color: color-mix(in oklab, var(--accent) 32%, var(--border));
  box-shadow: 0 8px 24px -12px rgba(79, 70, 229, 0.22);
}

/* ═══ 12. ALERTS — единые radius + shadow ═══════════════════════════════════ */
.bp-alert {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 12px 14px;
  border-radius: var(--radius-md);
  font-size: 13.5px;
  line-height: 1.5;
  border: 1px solid var(--border);
  background: var(--bg-elev);
}
.bp-alert--info    { background: var(--info-soft); border-color: color-mix(in oklab, var(--info) 25%, var(--border)); color: var(--info-strong); }
.bp-alert--ok      { background: var(--ok-soft);   border-color: color-mix(in oklab, var(--ok) 25%, var(--border));   color: var(--ok-strong); }
.bp-alert--warn    { background: var(--warn-soft); border-color: color-mix(in oklab, var(--warn) 25%, var(--border)); color: var(--warn-strong); }
.bp-alert--danger,
.bp-alert--error   { background: var(--danger-soft); border-color: color-mix(in oklab, var(--danger) 25%, var(--border)); color: var(--danger-strong); }

/* ═══ 13. EMPTY STATE polish ═════════════════════════════════════════════════ */
.bp-empty,
.bp-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 48px 24px;
  text-align: center;
  color: var(--fg-muted);
}
.bp-empty__icon,
.bp-empty-state__icon {
  width: 48px;
  height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-subtle);
  border-radius: 50%;
  color: var(--fg-subtle);
  animation: bp-float 4s ease-in-out infinite;
}
@keyframes bp-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}
.bp-empty__title { font-size: 15px; font-weight: 600; color: var(--fg); margin: 4px 0 0; }
.bp-empty__desc { font-size: 13px; color: var(--fg-muted); max-width: 320px; line-height: 1.55; }

/* ═══ 14. CRM page entry animation — staggered fade-up ═══════════════════════
   Базовое поведение задано в motion.css. Здесь полирую timing.
   =========================================================================== */
body.bp-has-shell main.bp-main-scroll > .page-shell {
  animation: bp-page-fade-up 360ms var(--ease-out) both;
}
@keyframes bp-page-fade-up {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ═══ 15. CHECKBOX / RADIO — компактные, кликабельные ═══════════════════════ */
input[type="checkbox"], input[type="radio"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
  accent-color: var(--accent);
  margin: 0;
  flex-shrink: 0;
}
input[type="checkbox"]:disabled, input[type="radio"]:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}
/* Click target расширение на родителя — для mobile UX */
label:has(> input[type="checkbox"]),
label:has(> input[type="radio"]) {
  cursor: pointer;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* ═══ 16. AVATAR — стандарт размеров и shadow ═══════════════════════════════ */
.bp-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 600;
  color: #fff;
  background: var(--accent);
  flex-shrink: 0;
}
.bp-avatar--sm { width: 24px; height: 24px; font-size: 10px; }
.bp-avatar--lg { width: 40px; height: 40px; font-size: 14px; }

/* ═══ 17. PROGRESS BARS — единый style ══════════════════════════════════════ */
.bp-progress {
  height: 4px;
  background: var(--bg-subtle);
  border-radius: 999px;
  overflow: hidden;
}
.bp-progress__bar,
.bp-progress__fill {
  height: 100%;
  background: var(--accent);
  border-radius: 999px;
  transition: width var(--dur-med) var(--ease-out);
}

/* ═══ 18. BREADCRUMB ═════════════════════════════════════════════════════════ */
.bp-breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--fg-muted);
  margin-bottom: 6px;
}
.bp-breadcrumb a {
  color: var(--fg-muted);
  text-decoration: none;
  transition: color var(--dur-fast) var(--ease-out);
}
.bp-breadcrumb a:hover { color: var(--accent); }

/* ═══ 19. LINKS — везде унифицированный hover ═══════════════════════════════ */
.bp-app a:not(.bp-btn):not(.bp-nav__item):not(.bp-chipbtn):not(.bp-menu__item),
.bp-public a:not(.bp-btn):not(.bp-nav__item):not(.bp-chipbtn):not(.bp-menu__item) {
  transition: color var(--dur-fast) var(--ease-out),
              text-decoration-color var(--dur-fast) var(--ease-out);
}

/* ═══ 20. SCROLLBAR — тонкий, mostly invisible ══════════════════════════════ */
.bp-app *::-webkit-scrollbar,
.bp-main-scroll::-webkit-scrollbar { width: 8px; height: 8px; }
.bp-app *::-webkit-scrollbar-track { background: transparent; }
.bp-app *::-webkit-scrollbar-thumb {
  background: var(--border-strong);
  border-radius: 4px;
  border: 2px solid transparent;
  background-clip: padding-box;
}
.bp-app *::-webkit-scrollbar-thumb:hover {
  background: var(--fg-faint);
  background-clip: padding-box;
  border: 2px solid transparent;
}

/* ═══ 21. PROFILE / DETAIL pages — header polish ════════════════════════════ */
.bp-detail__head {
  display: flex;
  align-items: flex-start;
  gap: 16px;
  padding: 20px;
  background: linear-gradient(180deg, var(--bg-elev), var(--bg));
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  margin-bottom: 16px;
}

/* ═══ 22. KEYBOARD NAVIGATION — visible state ═══════════════════════════════ */
.bp-nav__item:focus-visible,
.bp-menu__item:focus-visible,
.bp-chipbtn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-md);
}

/* ═══ 23. TOOLTIPS via title attribute polish (CSS-only hint via :hover) ════ */
[data-bp-tooltip] {
  position: relative;
}
[data-bp-tooltip]::after {
  content: attr(data-bp-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  padding: 4px 8px;
  background: var(--fg);
  color: var(--bg-elev);
  font-size: 11px;
  white-space: nowrap;
  border-radius: 4px;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-out);
  z-index: 1000;
}
[data-bp-tooltip]:hover::after { opacity: 1; }

/* ═══ 24. RESPECT REDUCED MOTION ════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* ═══ 25. FORM ANIMATIONS — invalid shake, focus glow pulse ════════════════ */
@keyframes bp-shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-3px); }
  40%, 60% { transform: translateX(3px); }
}
.bp-input.is-invalid:focus,
.bp-textarea.is-invalid:focus,
.bp-field--error .bp-input:focus {
  animation: bp-shake 320ms var(--ease-out);
}

/* Submit-once protection — кнопка subtle disabled state */
.bp-form button[type="submit"][aria-busy="true"],
.bp-form button[type="submit"].is-loading {
  opacity: 0.7;
  pointer-events: none;
  position: relative;
}
.bp-form button[type="submit"].is-loading::after {
  content: '';
  position: absolute;
  right: 12px;
  top: 50%;
  width: 14px;
  height: 14px;
  margin-top: -7px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: bp-spin 0.7s linear infinite;
}
@keyframes bp-spin { to { transform: rotate(360deg); } }

/* ═══ 26. SECTIONS DIVIDER (между group полей в форме) ══════════════════════ */
.bp-form__section {
  border-top: 1px solid var(--border);
  margin-top: 20px;
  padding-top: 20px;
}
.bp-form__section:first-child { border-top: 0; margin-top: 0; padding-top: 0; }
.bp-form__section-title {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-bottom: 12px;
}

/* ═══ 27. MISSING COMPONENTS (по результатам аудита Opus) ══════════════════ */
/* .bp-check — checkbox/radio inline-flex container — был не определён */
.bp-check {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 28px;
  cursor: pointer;
  font-size: 13.5px;
}
.bp-check__label {
  color: var(--fg);
  cursor: pointer;
  line-height: 1.3;
}
.bp-check input[type="checkbox"],
.bp-check input[type="radio"] {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  margin: 0;
  flex-shrink: 0;
}
@media (max-width: 640px) {
  .bp-check { min-height: 32px; }
}

/* .bp-select--sm — компактный вариант селекта */
.bp-select--sm {
  min-height: var(--input-h-sm, 30px);
  padding: 0 28px 0 8px;
  font-size: 12.5px;
  background-position: right 6px center;
}

/* Native date/time inputs polish — calendar icon visible + hover */
input[type="date"], input[type="time"], input[type="datetime-local"] {
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  color-scheme: light;
}
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  opacity: 0.55;
  cursor: pointer;
  padding: 2px;
  transition: opacity var(--dur-fast) var(--ease-out);
}
input[type="date"]:hover::-webkit-calendar-picker-indicator,
input[type="time"]:hover::-webkit-calendar-picker-indicator {
  opacity: 0.9;
}

/* File input polish — button аналогичен bp-btn */
input[type="file"] {
  padding: 6px 10px;
  font-size: 13px;
}
input[type="file"]::file-selector-button {
  font: inherit;
  padding: 4px 10px;
  margin-right: 10px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--bg-subtle);
  color: var(--fg);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
input[type="file"]::file-selector-button:hover {
  background: var(--bg-hover);
  border-color: var(--fg-faint);
}

/* Placeholder contrast — теперь var(--fg-subtle) вместо faint, проходит WCAG 3:1 */
.bp-input::placeholder,
.bp-textarea::placeholder,
input::placeholder,
textarea::placeholder {
  color: var(--fg-subtle) !important;
  opacity: 1 !important;
}

/* ═══ 28. SPACING UNIFICATION (по результатам spacing audit Opus) ══════════
   Заменяет ~200 inline-overrides и 5 дублированных компонент-определений.
   =========================================================================== */

/* Cards: density tiers — one rule replaces 30+ inline paddings */
.bp-card__head { padding: var(--sp-3) var(--sp-4) !important; }
.bp-card__body { padding: var(--sp-4) !important; }
.bp-card__foot { padding: var(--sp-3) var(--sp-4) !important; }
.bp-card--compact .bp-card__head,
.bp-card--compact .bp-card__body { padding: var(--sp-3) !important; }
.bp-card--spacious .bp-card__head { padding: var(--sp-5) var(--sp-6) !important; }
.bp-card--spacious .bp-card__body { padding: var(--sp-6) !important; }

/* Tables: уникальное row padding, без per-page оверрайдов */
.bp-table th, .bp-table td {
  padding: var(--sp-3) var(--sp-4);
  line-height: 1.45;
}
.bp-table--compact th, .bp-table--compact td {
  padding: var(--sp-2) var(--sp-3);
}

/* Toolbars: gap/margin локед */
.bp-toolbar {
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
  align-items: center;
  flex-wrap: wrap;
}

/* Tabs: единый bottom rhythm. Явно глушим Y-overflow — overflow-x: auto из
   components.css + сумма border-bottom + line-height иногда даёт scrollHeight
   на 1-2px больше clientHeight, и Chrome рисует тонкий вертикальный
   скроллбар-артефакт справа от tabs. Y-скролл здесь никогда не нужен. */
.bp-tabs {
  margin-bottom: var(--sp-5);
  gap: var(--sp-6);
  overflow-y: hidden;
  scrollbar-width: none;
}
.bp-tabs::-webkit-scrollbar { display: none; }

/* Section gaps внутри .bp-page — auto-cascade */
.bp-page > * + * { margin-top: var(--sp-4); }
.bp-page > .bp-toolbar + .bp-card,
.bp-page > .bp-toolbar + .bp-table-wrap,
.bp-page > .bp-page__head + * { margin-top: 0; }

/* Page-head meta row (для menu/dish list pages с дополнительными chips) */
.bp-page__meta-row {
  margin-top: var(--sp-2);
  display: flex;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

/* Empty state — единый источник истины */
.bp-empty {
  padding: var(--sp-8) var(--sp-6);
  gap: var(--sp-3);
}
.bp-empty--compact {
  padding: var(--sp-6) var(--sp-4);
  gap: var(--sp-2);
}

/* Pagination wrapper */
.bp-pagination-wrap {
  padding-top: var(--sp-3);
}

/* Forms: единый gap (12 вместо смешения 12/14) */
.bp-form { gap: var(--sp-3); }
.bp-form__row { gap: var(--sp-3); }

/* Modals: locked к scale */
.bp-modal__head { padding: var(--sp-4) var(--sp-5); }
.bp-modal__body { padding: var(--sp-5); }
.bp-modal__foot { padding: var(--sp-3) var(--sp-5); }

/* Grid gaps */
.bp-dashboard-grid { gap: var(--sp-4); }
.bp-event-cols { gap: var(--sp-4); }
.bp-dash-2col { gap: var(--sp-3); }
.bp-grid-4, .bp-grid-3, .bp-grid-2 { gap: var(--sp-3); }

/* ═══ 29. .is-disabled (для anchor-кнопок которые pseudo-disabled) ═════════ */
.bp-btn.is-disabled,
a.bp-btn[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: auto;
}
.bp-btn.is-disabled:hover { background: var(--bg-elev); border-color: var(--border-strong); transform: none; }

/* ═══ 30. AUTH PAGES — editorial airy rhythm ═══════════════════════════════
   Цель: дать форме воздух — крупный заголовок, generous vertical gaps,
   refined alt-foot с разделителем. Aside не трогаем. См. /accounts/login
   и т.д. — компоновка должна выглядеть просторно, не «впритык». */

/* Form-side container — шире (380→460), padding щедрее */
.bp-auth__form {
  padding: 72px 56px;
}
.bp-auth__form-inner {
  max-width: 460px;
}

/* Title — крупнее и весомее, чтобы держать air */
.bp-auth__title {
  font-size: 32px;
  font-weight: 650;
  letter-spacing: -0.022em;
  line-height: 1.12;
  margin: 0;
}
.bp-auth__sub {
  margin-top: 10px;
  font-size: 14.5px;
  color: var(--fg-muted);
  line-height: 1.55;
  max-width: 38ch;
}

/* Воздух между header (H1/sub/errors/OAuth) и формой */
.bp-auth__form-inner > form,
.bp-auth__form-inner > .bp-form {
  margin-top: 28px;
}

/* Field-to-field gap — на auth-страницах щедрее (20 вместо tight 14) */
.bp-auth .bp-form,
.bp-auth__form-inner .bp-form {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.bp-auth .bp-form .bp-field {
  gap: 8px;  /* label↔input */
}
.bp-auth .bp-form .bp-form__row,
.bp-auth .bp-form .bp-form-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 16px;
}

/* Primary submit — приподнять над полями, чтобы дышал */
.bp-auth .bp-form > button[type="submit"],
.bp-auth .bp-form > .bp-btn--accent,
.bp-auth .bp-form > .bp-btn--lg {
  margin-top: 8px;
}

/* OAuth-блок: воздух выше (после H1/errors) и ниже (перед формой) */
.bp-auth__form-inner > .bp-oauth-grid,
.bp-auth__form-inner > div > .bp-oauth-grid {
  margin-top: 28px;
}
.bp-auth__form-inner > .bp-auth__divider,
.bp-auth__form-inner > div > .bp-auth__divider {
  margin: 22px 0 6px;
  color: var(--fg-subtle);
}

/* OAuth (когда include выводит и grid и divider) — partial вставляет
   grid, потом divider; следующий после divider элемент (форма) — добавляем gap */
.bp-auth__divider + form,
.bp-auth__divider + .bp-form {
  margin-top: 4px;  /* divider уже даёт нижний margin */
}

/* «Запомнить email» / forgot-row — больше воздуха */
.bp-auth__row-between {
  margin-top: 4px;
  margin-bottom: 4px;
}

/* Alt-foot — с разделителем + щедрый отступ */
.bp-auth__alt-foot {
  margin-top: 36px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
  text-align: center;
  font-size: 13.5px;
  color: var(--fg-muted);
}
.bp-auth__alt-foot a {
  color: var(--accent);
  font-weight: 500;
  text-decoration: none;
}
.bp-auth__alt-foot a:hover { text-decoration: underline; }

/* Success-блоки в reset_done/reset_complete — больше воздуха */
.bp-auth__form-inner .bp-auth__success {
  margin-top: 24px;
  margin-bottom: 24px;
}

/* Mobile: скейлим padding, но рhythm сохраняем */
@media (max-width: 900px) {
  .bp-auth__form { padding: 36px 24px; }
  .bp-auth__title { font-size: 28px; }
  .bp-auth__form-inner > form,
  .bp-auth__form-inner > .bp-form {
    margin-top: 22px;
  }
  .bp-auth__mobile-foot {
    display: flex;
    justify-content: center;
    gap: 14px;
    margin-top: 24px;
    font-size: 12px;
    color: var(--fg-subtle);
  }
  .bp-auth__mobile-foot a { color: var(--fg-muted); text-decoration: none; }
  .bp-auth__mobile-foot a:hover { color: var(--accent); }
}
.bp-auth__mobile-foot { display: none; }
@media (max-width: 900px) { .bp-auth__mobile-foot { display: flex; } }

/* ═══ 30b. 2FA SECURITY CARD — симметричный блок Apple Settings-style ════════
   Header: описание слева, чип статуса + trigger справа.
   Form (раскрытая): два поля в одну строку, footer-actions справа.
   Используется на /profile/?tab=security. ===================================== */
.bp-2fa-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.bp-2fa-card__head-text {
  flex: 1 1 320px;
  min-width: 240px;
}
.bp-2fa-card__sub {
  font-size: 13px;
  margin-top: 2px;
}
.bp-2fa-card__head-aside {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* Развёрнутая форма disable — на всю ширину карточки, 2-col grid */
.bp-2fa-disable {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.bp-2fa-disable__hint {
  margin: 0;
  font-size: 13px;
  color: var(--fg-muted);
}
.bp-2fa-disable__hint em {
  font-style: normal;
  color: var(--fg-subtle);
  font-size: 12px;
  text-transform: lowercase;
  letter-spacing: 0.03em;
  padding: 0 4px;
}
.bp-2fa-disable__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
@media (max-width: 640px) {
  .bp-2fa-disable__grid { grid-template-columns: 1fr; }
}

/* Variant для смены пароля: три поля в одну колонку — длинный
   placeholder «Минимум 8 символов» удобнее читать в полную ширину,
   а пользователь не сравнивает поля бок-о-бок. */
.bp-2fa-disable--password .bp-2fa-disable__grid {
  grid-template-columns: 1fr;
  max-width: 480px;
}
.bp-2fa-disable--password { border-top: 0; padding-top: 0; margin-top: 18px; }
.bp-2fa-disable__actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  margin-top: 4px;
}
.bp-2fa-disable__actions .bp-btn {
  align-self: auto;
}

/* Если кнопок в header-aside больше одной и они переехали на новую строку
   на узком экране — двигаем chip отдельной строкой над кнопкой, чтобы не было
   эффекта «плавающего» chip между двумя действиями. */
@media (max-width: 480px) {
  .bp-2fa-card__head-aside { width: 100%; justify-content: flex-start; }
}

/* ═══ 31. PRINT — компактная вёрстка ════════════════════════════════════════ */
@media print {
  .bp-sidebar, .bp-topbar, .bp-toolbar, .bp-page__head-actions,
  .bp-bulk-bar, .bp-progress-top, .bp-feedback,
  .bp-cookie-banner, .bp-pwa-install-banner { display: none !important; }
  .bp-card { box-shadow: none; border: 1px solid #ddd; }
  body { background: #fff; color: #000; }
}

/* ═══ 30c. OAUTH BUTTONS — provider-color, 2-col grid ═══════════════════════
   Используются в templates/_partials/oauth_buttons.html на login и register.
   Старые `.bp-auth__oauth` / `.bp-auth__oauth-btn` (v4-extras.css) больше
   не подключены к этим страницам, но остаются для back-compat. =============== */
.bp-oauth-grid {
  display: grid;
  /* Остался один провайдер (Яндекс ID) — компактная кнопка по центру:
     одна колонка на всю ширину + justify-items:center → кнопка по содержимому,
     с равными отступами слева и справа. */
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  gap: 10px;
  margin: 14px 0;
}
.bp-oauth-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 44px;
  padding: 0 16px;
  background: var(--bg-elev, #fff);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--fg);
  font: 500 14px/1 inherit;
  letter-spacing: -0.005em;
  text-decoration: none;
  transition: background 150ms ease, border-color 150ms ease, transform 100ms ease;
  min-width: 0; /* пара к minmax(0, 1fr) — позволяет label обрезаться ellipsis'ом */
  overflow: hidden;
}
.bp-oauth-btn:hover:not(.is-disabled) {
  background: var(--bg-subtle);
  border-color: var(--border-strong);
}
.bp-oauth-btn:active:not(.is-disabled) {
  transform: scale(0.98);
}
.bp-oauth-btn:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.bp-oauth-btn.is-disabled {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: auto; /* permit hover-title для пояснения, click нейтрализован JS */
}
.bp-oauth-btn__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
}
.bp-oauth-btn__label {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bp-oauth-btn__soon {
  color: var(--fg-subtle);
  font-size: 11px;
  font-weight: 400;
}
@media (max-width: 480px) {
  .bp-oauth-grid { grid-template-columns: 1fr; }
}

