diff --git a/backend/static/scss_backup_20260115/abstracts/_css-variables.scss b/backend/static/scss_backup_20260115/abstracts/_css-variables.scss
new file mode 100644
index 00000000..65159917
--- /dev/null
+++ b/backend/static/scss_backup_20260115/abstracts/_css-variables.scss
@@ -0,0 +1,197 @@
+// =============================================================================
+// CSS Custom Properties (CSS Variables)
+// =============================================================================
+// CSS переменные, доступные в runtime через var(--variable-name)
+// В отличие от SCSS переменных ($variable), эти работают в браузере
+
+:root {
+ // ========== Цветовая схема ==========
+
+ // Основные цвета приложения
+ --app-primary: #0d6efd;
+ --app-success: #198754;
+ --app-danger: #dc3545;
+ --app-warning: #ffc107;
+ --app-info: #0dcaf0;
+
+ // Фоновые цвета
+ --bg-light: #f8f9fa;
+ --bg-dark: #212529;
+ --bg-card: #ffffff;
+
+ // Цвета текста
+ --text-primary: #212529;
+ --text-secondary: #6c757d;
+ --text-muted: #adb5bd;
+
+ // ========== Размеры и отступы ==========
+
+ // Высота компонентов
+ --navbar-h: 60px;
+ --sidebar-w: 200px;
+ --rightbar-w: 350px;
+
+ // Радиусы скругления
+ --radius-xs: 4px;
+ --radius-sm: 6px;
+ --radius-md: 10px;
+ --radius-lg: 14px;
+ --radius-xl: 18px;
+ --radius-2xl: 24px;
+ --radius-full: 50%;
+
+ // Радиусы компонентов
+ --feed-radius: var(--radius-xl);
+ --card-radius: var(--radius-lg);
+ --button-radius: var(--radius-md);
+ --input-radius: var(--radius-md);
+ --badge-radius: 999px;
+
+ // ========== Унифицированная система отступов (8px grid) ==========
+
+ // Базовая шкала отступов
+ --space-0: 0;
+ --space-1: 0.25rem; // 4px
+ --space-2: 0.5rem; // 8px
+ --space-3: 0.75rem; // 12px
+ --space-4: 1rem; // 16px
+ --space-5: 1.5rem; // 24px
+
+ // Семантические названия (для лучшей читаемости)
+ --space-xs: var(--space-1);
+ --space-sm: var(--space-2);
+ --space-md: var(--space-3);
+ --space-lg: var(--space-4);
+ --space-xl: var(--space-5);
+
+ // Специфичные отступы для компонентов
+ --gap-component: var(--space-3);
+ --gap-section: var(--space-4);
+
+ // Padding карточек и контейнеров
+ --card-padding: var(--space-2);
+ --card-padding-sm: var(--space-1);
+ --card-padding-lg: var(--space-3);
+
+ // Margin между элементами
+ --margin-section: var(--space-3);
+ --margin-block: var(--space-4);
+
+ // Layout отступы (app-layout grid)
+ --layout-gap: var(--space-2);
+ --layout-padding-y: var(--space-3);
+ --layout-padding-x: 0;
+
+ // Старые переменные (deprecated, для обратной совместимости)
+ --spacing-xs: var(--space-1);
+ --spacing-sm: var(--space-2);
+ --spacing-md: var(--space-3);
+ --spacing-lg: var(--space-4);
+ --spacing-xl: var(--space-5);
+
+ // ========== Тени ==========
+
+ --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
+ --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
+ --shadow-md: 0 2px 8px rgba(0, 0, 0, 0.08);
+ --shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.12);
+ --shadow-xl: 0 8px 32px rgba(0, 0, 0, 0.16);
+
+ // Тени компонентов
+ --feed-shadow: var(--shadow-md);
+ --feed-shadow-hover: var(--shadow-lg);
+ --card-shadow: var(--shadow-sm);
+ --dropdown-shadow: var(--shadow-lg);
+ --modal-shadow: var(--shadow-xl);
+
+ // ========== Компоненты Feed ==========
+
+ --feed-gap: 0.75rem;
+
+ // ========== iOS Компоненты ==========
+
+ --ios-overlay-bg: rgba(0, 0, 0, 0.4);
+ --ios-sheet-radius: 24px 24px 0 0;
+ --ios-grip-w: 36px;
+ --ios-grip-h: 5px;
+ --ios-search-radius: var(--radius-md);
+
+ // ========== Аватары ==========
+
+ --avatar-xs: 28px;
+ --avatar-sm: 36px;
+ --avatar-md: 44px;
+ --avatar-lg: 64px;
+ --avatar-xl: 96px;
+
+ // ========== Календарь ==========
+
+ --calendar-day-size: 1.6rem;
+ --calendar-event-radius: 6px;
+ --calendar-wrap-radius: 10px;
+
+ // ========== Переходы и анимации ==========
+
+ --transition-fast: 0.15s ease;
+ --transition-base: 0.2s ease;
+ --transition-slow: 0.3s ease;
+
+ // ========== Z-индексы ==========
+
+ --z-dropdown: 1000;
+ --z-sticky: 1020;
+ --z-fixed: 1030;
+ --z-modal-backdrop: 1040;
+ --z-modal: 1050;
+ --z-popover: 1060;
+ --z-tooltip: 1070;
+
+ // ========== Типографика ==========
+
+ --font-family-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ --font-family-mono: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+
+ --font-size-xs: 0.75rem;
+ --font-size-sm: 0.875rem;
+ --font-size-base: 1rem;
+ --font-size-lg: 1.125rem;
+ --font-size-xl: 1.25rem;
+
+ --font-weight-light: 300;
+ --font-weight-normal: 400;
+ --font-weight-medium: 500;
+ --font-weight-semibold: 600;
+ --font-weight-bold: 700;
+
+ // ========== Границы ==========
+
+ --border-width: 1px;
+ --border-color: #dee2e6;
+ --border-radius: var(--radius-md);
+}
+
+// ========== Вспомогательные классы с переменными ==========
+
+.shadow-sm { box-shadow: var(--shadow-sm); }
+.shadow-md { box-shadow: var(--shadow-md); }
+.shadow-lg { box-shadow: var(--shadow-lg); }
+.shadow-xl { box-shadow: var(--shadow-xl); }
+
+.radius-sm { border-radius: var(--radius-sm); }
+.radius-md { border-radius: var(--radius-md); }
+.radius-lg { border-radius: var(--radius-lg); }
+.radius-xl { border-radius: var(--radius-xl); }
+.radius-full { border-radius: var(--radius-full); }
+
+.transition-fast { transition: all var(--transition-fast); }
+.transition-base { transition: all var(--transition-base); }
+.transition-slow { transition: all var(--transition-slow); }
+
+// ========== Адаптивные переменные ==========
+
+// На мобильных navbar выше (90px вместо 60px)
+@media (max-width: 767.98px) {
+ :root {
+ --navbar-h: 90px;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/abstracts/_index.scss b/backend/static/scss_backup_20260115/abstracts/_index.scss
new file mode 100644
index 00000000..3360c5d0
--- /dev/null
+++ b/backend/static/scss_backup_20260115/abstracts/_index.scss
@@ -0,0 +1,8 @@
+// =============================================================================
+// Index - Centralized Imports
+// =============================================================================
+// Единая точка импорта всех abstracts компонентов
+
+@import "variables";
+@import "css-variables";
+@import "mixins";
diff --git a/backend/static/scss_backup_20260115/abstracts/_mixins.scss b/backend/static/scss_backup_20260115/abstracts/_mixins.scss
new file mode 100644
index 00000000..81f229bd
--- /dev/null
+++ b/backend/static/scss_backup_20260115/abstracts/_mixins.scss
@@ -0,0 +1,378 @@
+// =============================================================================
+// Mixins - Reusable Style Patterns
+// =============================================================================
+// Переиспользуемые паттерны для DRY (Don't Repeat Yourself) подхода
+
+// =============================================================================
+// 1. GLASSMORPHISM EFFECTS
+// =============================================================================
+
+/// Применяет эффект glassmorphism (размытое стекло)
+/// @param {string} $blur - Уровень размытия (по умолчанию $blur-md)
+/// @param {color} $bg - Цвет фона с прозрачностью
+/// @param {color} $border - Цвет границы (опционально)
+@mixin glassmorphism($blur: $blur-md, $bg: $glass-light-bg, $border: null) {
+ backdrop-filter: $blur saturate(180%);
+ -webkit-backdrop-filter: $blur saturate(180%);
+ background: $bg;
+
+ @if $border {
+ border: 1px solid $border;
+ }
+}
+
+/// Glassmorphism для светлой темы
+@mixin glassmorphism-light() {
+ @include glassmorphism($blur-md, $glass-light-bg, $glass-light-border);
+}
+
+/// Glassmorphism для тёмной темы
+@mixin glassmorphism-dark() {
+ @include glassmorphism($blur-md, $glass-dark-bg, $glass-dark-border);
+}
+
+/// Glassmorphism для карточек
+@mixin glassmorphism-card() {
+ @include glassmorphism($blur-md, $card-glass-bg, $card-glass-border);
+ box-shadow: $card-glass-shadow;
+}
+
+// =============================================================================
+// 2. SHADOWS
+// =============================================================================
+
+/// Применяет тень с возможностью hover эффекта
+/// @param {string} $shadow - Базовая тень
+/// @param {string} $shadow-hover - Тень при наведении (опционально)
+@mixin shadow($shadow: $shadow-md, $shadow-hover: null) {
+ box-shadow: $shadow;
+
+ @if $shadow-hover {
+ transition: box-shadow $transition-base;
+
+ &:hover {
+ box-shadow: $shadow-hover;
+ }
+ }
+}
+
+/// Удаляет все тени
+@mixin no-shadow() {
+ box-shadow: none !important;
+}
+
+// =============================================================================
+// 3. BORDER RADIUS
+// =============================================================================
+
+/// Применяет border-radius с единым значением
+/// @param {string} $radius - Размер радиуса
+@mixin radius($radius: $radius-lg) {
+ border-radius: $radius;
+}
+
+/// Скругляет только верхние углы
+@mixin radius-top($radius: $radius-lg) {
+ border-top-left-radius: $radius;
+ border-top-right-radius: $radius;
+}
+
+/// Скругляет только нижние углы
+@mixin radius-bottom($radius: $radius-lg) {
+ border-bottom-left-radius: $radius;
+ border-bottom-right-radius: $radius;
+}
+
+/// Создаёт идеальный круг
+@mixin circle() {
+ border-radius: 50%;
+}
+
+/// Создаёт pill-образную форму (капсула)
+@mixin pill() {
+ border-radius: $radius-pill;
+}
+
+// =============================================================================
+// 4. FLEXBOX UTILITIES
+// =============================================================================
+
+/// Центрирует содержимое по обеим осям
+@mixin flex-center() {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+/// Flexbox с вертикальным центрированием
+@mixin flex-align-center() {
+ display: flex;
+ align-items: center;
+}
+
+/// Flexbox с горизонтальным центрированием
+@mixin flex-justify-center() {
+ display: flex;
+ justify-content: center;
+}
+
+/// Flexbox со space-between
+@mixin flex-between() {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+// =============================================================================
+// 5. POSITION UTILITIES
+// =============================================================================
+
+/// Абсолютное позиционирование по центру
+@mixin absolute-center() {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+}
+
+/// Абсолютное позиционирование с полным покрытием
+@mixin absolute-cover() {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+/// Sticky positioning с поддержкой navbar offset
+/// @param {string} $top - Отступ сверху
+@mixin sticky($top: 0) {
+ position: sticky;
+ top: $top;
+ z-index: $z-sticky;
+}
+
+// =============================================================================
+// 6. TRANSITIONS
+// =============================================================================
+
+/// Применяет transition к указанным свойствам
+/// @param {list} $properties - Список свойств для анимации
+/// @param {string} $duration - Длительность (по умолчанию $transition-base)
+@mixin transition($properties, $duration: $transition-base) {
+ transition-property: $properties;
+ transition-duration: $duration;
+ transition-timing-function: ease;
+}
+
+/// Плавная анимация для всех свойств
+@mixin transition-all($duration: $transition-base) {
+ transition: all $duration;
+}
+
+// =============================================================================
+// 7. SCROLLBAR STYLING
+// =============================================================================
+
+/// Кастомный scrollbar
+/// @param {color} $track-bg - Цвет трека
+/// @param {color} $thumb-bg - Цвет ползунка
+/// @param {string} $width - Ширина scrollbar
+@mixin custom-scrollbar($track-bg: rgba(0, 0, 0, 0.05), $thumb-bg: rgba(0, 0, 0, 0.3), $width: 6px) {
+ scrollbar-width: thin;
+ scrollbar-color: $thumb-bg $track-bg;
+
+ &::-webkit-scrollbar {
+ width: $width;
+ height: $width;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: $track-bg;
+ border-radius: $radius-sm;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: $thumb-bg;
+ border-radius: $radius-sm;
+
+ &:hover {
+ background: rgba($thumb-bg, 0.8);
+ }
+ }
+}
+
+// =============================================================================
+// 8. TEXT UTILITIES
+// =============================================================================
+
+/// Обрезает текст с многоточием
+@mixin text-truncate() {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+/// Ограничивает текст указанным количеством строк
+/// @param {number} $lines - Количество строк
+@mixin text-clamp($lines: 2) {
+ display: -webkit-box;
+ -webkit-line-clamp: $lines;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+}
+
+// =============================================================================
+// 9. HOVER EFFECTS
+// =============================================================================
+
+/// Стандартный hover эффект с opacity
+/// @param {number} $opacity - Прозрачность при наведении
+@mixin hover-opacity($opacity: 0.8) {
+ transition: opacity $transition-fast;
+ cursor: pointer;
+
+ &:hover {
+ opacity: $opacity;
+ }
+}
+
+/// Hover с подсветкой фона
+/// @param {color} $bg - Цвет фона при наведении
+@mixin hover-bg($bg: $gray-50) {
+ transition: background-color $transition-fast;
+ cursor: pointer;
+
+ &:hover {
+ background-color: $bg;
+ }
+}
+
+/// Hover с transform scale
+/// @param {number} $scale - Масштаб при наведении
+@mixin hover-scale($scale: 1.05) {
+ transition: transform $transition-base $ease-smooth;
+ cursor: pointer;
+
+ &:hover {
+ transform: scale($scale);
+ }
+}
+
+// =============================================================================
+// 10. BADGE UTILITIES
+// =============================================================================
+
+/// Создаёт базовый Telegram-style badge
+/// @param {string} $height - Высота badge
+/// @param {string} $radius - Border radius
+@mixin badge-base($height: $badge-height-base, $radius: $badge-radius) {
+ @include flex-center();
+ height: $height;
+ min-width: $height;
+ border-radius: $radius;
+ font-size: $badge-font-size;
+ font-weight: $badge-font-weight;
+ line-height: 1;
+}
+
+/// Badge с тенью
+@mixin badge-shadow() {
+ box-shadow: $badge-shadow;
+
+ &:hover {
+ box-shadow: $badge-shadow-hover;
+ }
+}
+
+// =============================================================================
+// 11. RESPONSIVE UTILITIES
+// =============================================================================
+
+/// Media query для mobile устройств
+@mixin mobile() {
+ @media (max-width: 767.98px) {
+ @content;
+ }
+}
+
+/// Media query для tablet устройств
+@mixin tablet() {
+ @media (min-width: 768px) and (max-width: 991.98px) {
+ @content;
+ }
+}
+
+/// Media query для desktop устройств
+@mixin desktop() {
+ @media (min-width: 992px) {
+ @content;
+ }
+}
+
+/// Media query для больших экранов
+@mixin large-desktop() {
+ @media (min-width: 1200px) {
+ @content;
+ }
+}
+
+// =============================================================================
+// 12. DARK MODE UTILITIES
+// =============================================================================
+
+/// Применяет стили для тёмной темы
+@mixin dark-mode() {
+ [data-bs-theme="dark"] & {
+ @content;
+ }
+}
+
+/// Применяет стили для светлой темы
+@mixin light-mode() {
+ [data-bs-theme="light"] & {
+ @content;
+ }
+}
+
+// =============================================================================
+// 13. ANIMATION UTILITIES
+// =============================================================================
+
+/// Fade-in анимация
+@mixin fade-in($duration: $transition-base) {
+ animation: fadeIn $duration ease-in;
+}
+
+/// Slide-down анимация
+@mixin slide-down($duration: $transition-base) {
+ animation: slideDown $duration $ease-smooth;
+}
+
+/// Pulse анимация
+@mixin pulse($duration: 2s) {
+ animation: pulse $duration infinite;
+}
+
+// =============================================================================
+// 14. FOCUS STATES
+// =============================================================================
+
+/// Bootstrap-style focus ring
+/// @param {color} $color - Цвет focus ring
+@mixin focus-ring($color: var(--bs-primary-rgb)) {
+ &:focus,
+ &:focus-visible {
+ outline: 0;
+ box-shadow: 0 0 0 0.2rem rgba($color, 0.25);
+ }
+}
+
+/// Убирает focus outline
+@mixin no-focus() {
+ &:focus,
+ &:focus-visible {
+ outline: none;
+ box-shadow: none;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/abstracts/_variables.scss b/backend/static/scss_backup_20260115/abstracts/_variables.scss
new file mode 100644
index 00000000..962aa359
--- /dev/null
+++ b/backend/static/scss_backup_20260115/abstracts/_variables.scss
@@ -0,0 +1,223 @@
+// =============================================================================
+// Design Tokens - Centralized Variables
+// =============================================================================
+// Централизованная система переменных для всего проекта
+// Все компоненты должны использовать эти токены вместо hardcoded значений
+
+// =============================================================================
+// 1. ЦВЕТОВАЯ СИСТЕМА
+// =============================================================================
+
+// Telegram colors
+$telegram-blue: #0088cc;
+$telegram-mention-bg: #0088cc;
+
+// Gradient colors
+$gradient-purple-start: #667eea;
+$gradient-purple-end: #764ba2;
+$gradient-pink-start: #f093fb;
+$gradient-pink-end: #f5576c;
+
+// Base colors
+$color-white: #fff;
+$color-black: #000;
+
+// Gray scale
+$gray-50: #f8f9fa;
+$gray-100: #f0f0f0;
+$gray-200: #e3e3e3;
+$gray-300: #dee2e6;
+$gray-400: #ced4da;
+$gray-500: #adb5bd;
+$gray-600: #6c757d;
+$gray-700: #495057;
+$gray-800: #343a40;
+$gray-900: #212529;
+
+// Semantic colors
+$color-danger: #ef4444;
+$color-success-light: #e3f2fd;
+$color-warning-light: #fffbeb;
+
+// =============================================================================
+// 2. SPACING SYSTEM (уже определена в custom-bootstrap.scss)
+// =============================================================================
+// Используем Bootstrap переменные $spacers
+// 0: 0, 1: 4px, 2: 8px, 3: 12px, 4: 16px, 5: 24px
+
+// =============================================================================
+// 3. BORDER RADIUS TOKENS
+// =============================================================================
+
+$radius-xs: 4px; // extra small
+$radius-sm: 6px; // small
+$radius-md: 10px; // medium (most common)
+$radius-lg: 12px; // large
+$radius-xl: 14px; // extra large
+$radius-2xl: 16px; // 2x large
+$radius-3xl: 18px; // 3x large
+$radius-4xl: 20px; // 4x large
+$radius-pill: 999px; // perfect pill shape
+
+// Badge specific (perfect circles)
+$badge-radius: 10px;
+$badge-radius-sm: 9px;
+$badge-radius-lg: 12px;
+$badge-radius-xl: 14px;
+
+// =============================================================================
+// 4. SHADOW TOKENS
+// =============================================================================
+
+$shadow-none: none;
+$shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.06);
+$shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
+$shadow-md: 0 2px 4px rgba(0, 0, 0, 0.1);
+$shadow-lg: 0 2px 8px rgba(0, 0, 0, 0.15);
+$shadow-xl: 0 4px 12px rgba(0, 0, 0, 0.15);
+$shadow-2xl: 0 4px 16px rgba(0, 0, 0, 0.2);
+$shadow-3xl: 0 6px 20px rgba(0, 0, 0, 0.3);
+
+// Badge specific shadows
+$badge-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
+$badge-shadow-hover: 0 3px 6px rgba(0, 0, 0, 0.2);
+$badge-shadow-dark: 0 2px 4px rgba(0, 0, 0, 0.3);
+
+// Context menu shadows
+$context-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+
+// =============================================================================
+// 5. BLUR TOKENS (для backdrop-filter)
+// =============================================================================
+
+$blur-none: blur(0);
+$blur-sm: blur(8px);
+$blur-md: blur(10px);
+$blur-lg: blur(12px);
+$blur-xl: blur(16px);
+
+// =============================================================================
+// 6. OPACITY TOKENS
+// =============================================================================
+
+$opacity-glass-light: 0.1;
+$opacity-glass-medium: 0.15;
+$opacity-glass-high: 0.2;
+
+$opacity-overlay-light: 0.05;
+$opacity-overlay-medium: 0.1;
+$opacity-overlay-dark: 0.3;
+
+$opacity-border-light: 0.08;
+$opacity-border-medium: 0.1;
+$opacity-border-dark: 0.25;
+
+// =============================================================================
+// 7. TRANSITION TOKENS
+// =============================================================================
+
+$transition-fast: 0.15s ease;
+$transition-base: 0.2s ease;
+$transition-medium: 0.3s ease;
+$transition-slow: 0.4s ease;
+
+// Специальные easing функции
+$ease-bounce: cubic-bezier(0.175, 0.885, 0.32, 1.275);
+$ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
+
+// Badge specific
+$badge-transition: transform 0.2s $ease-bounce;
+
+// =============================================================================
+// 8. Z-INDEX TOKENS
+// =============================================================================
+
+$z-base: 1;
+$z-dropdown: 1000;
+$z-sticky: 1020;
+$z-fixed: 1030;
+$z-modal-backdrop: 1040;
+$z-modal: 1050;
+$z-popover: 1060;
+$z-tooltip: 1070;
+$z-notification: 1080;
+
+// =============================================================================
+// 9. SIZE TOKENS (avatars, badges, icons)
+// =============================================================================
+
+// Badge heights
+$badge-height-sm: 18px;
+$badge-height-base: 20px;
+$badge-height-lg: 24px;
+$badge-height-xl: 28px;
+
+// Badge padding
+$badge-padding-x: 7px;
+$badge-padding-y: 2px;
+
+// Avatar sizes
+$avatar-xs: 24px;
+$avatar-sm: 32px;
+$avatar-md: 40px;
+$avatar-lg: 44px;
+$avatar-xl: 48px;
+$avatar-2xl: 56px;
+
+// Icon button sizes
+$btn-icon-sm: 32px;
+$btn-icon-base: 36px;
+$btn-icon-lg: 44px;
+
+// =============================================================================
+// 10. GLASSMORPHISM PRESETS
+// =============================================================================
+
+// Light theme glassmorphism
+$glass-light-bg: rgba(255, 255, 255, 0.1);
+$glass-light-border: rgba(0, 0, 0, 0.08);
+
+// Dark theme glassmorphism
+$glass-dark-bg: rgba(52, 58, 64, 0.95);
+$glass-dark-border: rgba(255, 255, 255, 0.1);
+
+// Card glassmorphism
+$card-glass-bg: rgba(255, 255, 255, 0.05);
+$card-glass-border: rgba(255, 255, 255, 0.1);
+$card-glass-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
+
+// =============================================================================
+// 11. TYPOGRAPHY TOKENS (дополнительные)
+// =============================================================================
+
+$font-weight-normal: 400;
+$font-weight-medium: 500;
+$font-weight-semibold: 600;
+$font-weight-bold: 700;
+
+$font-size-xs: 11px;
+$font-size-sm: 12px;
+$font-size-base: 14px;
+$font-size-md: 16px;
+$font-size-lg: 18px;
+
+// Badge specific
+$badge-font-size: 11px;
+$badge-font-weight: 600;
+
+// =============================================================================
+// 12. LAYOUT TOKENS
+// =============================================================================
+
+// Navbar
+$navbar-height: 56px;
+$navbar-mobile-height: 90px;
+$bottom-navbar-height: 60px;
+
+// Sidebar
+$sidebar-width: 240px;
+$sidebar-collapsed-width: 60px;
+
+// Chat specific
+$chat-composer-height: auto;
+$chat-message-max-width: 70%;
diff --git a/backend/static/scss_backup_20260115/components/BUTTONS_README.md b/backend/static/scss_backup_20260115/components/BUTTONS_README.md
new file mode 100644
index 00000000..92e6cf3d
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/BUTTONS_README.md
@@ -0,0 +1,279 @@
+# Документация: Компонент Buttons
+
+## Обзор
+
+Расширенная система кнопок, дополняющая стандартные кнопки Bootstrap дополнительными вариантами и утилитами.
+
+## Классы кнопок
+
+### 1. Круглые кнопки (`.btn-circle`)
+
+Идеально круглые кнопки для иконок. Автоматически становятся квадратными с `border-radius: 50%`.
+
+#### Базовое использование
+
+```html
+
+
+
+```
+
+#### Размеры
+
+```html
+
+
+
+
+
+
+
+
+```
+
+Или используйте специальные классы:
+```html
+
+
+
+```
+
+#### Состояния
+
+Toggle-кнопки автоматически вращаются при раскрытии:
+
+```html
+
+
+```
+
+### 2. Кнопки с иконками (`.btn-icon`)
+
+Кнопки с иконкой и текстом. На мобильных устройствах текст скрывается.
+
+```html
+
+
+
+
+ Новый документ
+
+```
+
+**Поведение:**
+- Десктоп: иконка + текст
+- Мобильные (< 768px): только иконка (круглая кнопка)
+
+### 3. Кнопки-призраки (`.btn-ghost`)
+
+Прозрачные кнопки без фона, появляется фон при наведении.
+
+```html
+
+
+
+```
+
+### 4. Pill-кнопки (`.btn-pill`)
+
+Максимально скругленные кнопки (`border-radius: 999px`).
+
+```html
+
+
+
+ Узнать больше
+
+```
+
+## Группы кнопок
+
+### Группа круглых кнопок
+
+```html
+
+
+
+
+
+```
+
+## Примеры использования
+
+### Пример 1: Шапка страницы с фильтрами
+
+```html
+
+
Сотрудники
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### Пример 2: Карточка с действиями
+
+```html
+
+
+
Название документа
+
Описание...
+
+
+
+
+
+
+
+
+```
+
+### Пример 3: Навигация с разными размерами
+
+```html
+
+
+
+
+
+
+
+
+
+
+```
+
+## Комбинирование с Bootstrap
+
+Все новые классы полностью совместимы со стандартными классами Bootstrap:
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Миграция со старого кода
+
+### Было (специфичные стили):
+
+```html
+
+```
+
+```css
+.page-filter-toggle {
+ width: 36px !important;
+ height: 36px !important;
+ border-radius: 50% !important;
+ /* ... еще 20 строк CSS ... */
+}
+```
+
+### Стало (универсальный класс):
+
+```html
+
+```
+
+```css
+/* Никаких дополнительных стилей не нужно! */
+```
+
+## CSS переменные
+
+Компонент использует стандартные переменные Bootstrap:
+- `--bs-primary` - основной цвет
+- `--bs-body-color` - цвет текста
+- `--bs-border-color` - цвет границ
+- `--bs-border-radius` - скругление углов
+
+## Поддержка темной темы
+
+Все кнопки автоматически адаптируются под темную тему через `prefers-color-scheme: dark`.
+
+## Доступность
+
+- Все кнопки имеют правильные `aria-label` атрибуты
+- Иконки используют `line-height: 1` для правильного центрирования
+- Фокус-стейты наследуются от Bootstrap
+- Поддержка клавиатурной навигации
+
+## Производительность
+
+- Минимальное использование `!important` (только где абсолютно необходимо)
+- CSS переменные для легкой кастомизации
+- Оптимизированные селекторы
+- Не влияет на другие компоненты
diff --git a/backend/static/scss_backup_20260115/components/_badges-bem.scss b/backend/static/scss_backup_20260115/components/_badges-bem.scss
new file mode 100644
index 00000000..969c4eda
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_badges-bem.scss
@@ -0,0 +1,232 @@
+// =============================================================================
+// Badges Component
+// =============================================================================
+// Notification badges with Telegram-style design
+// Uses design tokens from abstracts/_variables.scss
+
+// =============================================================================
+// 1. BASE COMPONENT
+// =============================================================================
+
+.badge {
+ @include badge-base($badge-height-base, $badge-radius);
+ @include badge-shadow();
+ color: $color-white;
+ background: var(--bs-danger);
+ transition: $badge-transition;
+ user-select: none;
+ padding: 0 6px;
+
+ // Auto-hide when empty
+ &:empty {
+ display: none;
+ }
+
+ // Hide when count is 0
+ &[data-count="0"] {
+ display: none;
+ }
+}
+
+// =============================================================================
+// 2. SIZE MODIFIERS
+// =============================================================================
+
+.badge--sm {
+ @include badge-base($badge-height-sm, $badge-radius-sm);
+ font-size: 10px;
+ padding: 0 5px;
+}
+
+.badge--lg {
+ @include badge-base($badge-height-lg, $badge-radius-lg);
+ font-size: 12px;
+ padding: 0 7px;
+}
+
+.badge--xl {
+ @include badge-base($badge-height-xl, $badge-radius-xl);
+ font-size: 13px;
+ padding: 0 8px;
+}
+
+// =============================================================================
+// 3. COLOR MODIFIERS
+// =============================================================================
+
+.badge--primary {
+ background: var(--bs-primary);
+}
+
+.badge--secondary {
+ background: var(--bs-secondary);
+ opacity: 0.8;
+}
+
+.badge--success {
+ background: var(--bs-success);
+}
+
+.badge--warning {
+ background: var(--bs-warning);
+ color: var(--bs-dark);
+}
+
+.badge--info {
+ background: var(--bs-info);
+}
+
+.badge--mention {
+ background: $telegram-blue;
+}
+
+.badge--muted {
+ background: var(--bs-secondary);
+ opacity: 0.6;
+ color: var(--bs-secondary-color);
+}
+
+// =============================================================================
+// 4. STYLE MODIFIERS
+// =============================================================================
+
+.badge--outlined {
+ background: transparent;
+ border: 2px solid currentColor;
+ color: var(--bs-danger);
+}
+
+.badge--dot {
+ width: 8px;
+ height: 8px;
+ min-width: 8px;
+ padding: 0;
+ @include radius(50%);
+}
+
+.badge--inline {
+ display: inline-flex;
+ vertical-align: middle;
+ margin-left: 4px;
+}
+
+// Premium badge with gradient
+.badge--premium {
+ background: linear-gradient(135deg, $gradient-purple-start 0%, $gradient-purple-end 100%);
+}
+
+.badge--star {
+ background: linear-gradient(135deg, $gradient-pink-start 0%, $gradient-pink-end 100%);
+}
+
+// =============================================================================
+// 5. CONTEXT MODIFIERS
+// =============================================================================
+
+// Badge on avatar
+.badge--avatar {
+ position: absolute;
+ top: 0;
+ right: 0;
+ transform: translate(25%, -25%);
+ z-index: $z-base;
+}
+
+// Badge on button
+.badge--button {
+ position: absolute;
+ top: -6px;
+ right: -6px;
+}
+
+// Interactive badge (clickable)
+.badge--interactive {
+ cursor: pointer;
+ @include transition-all($transition-fast);
+
+ &:hover {
+ transform: scale(1.1);
+ box-shadow: $badge-shadow-hover;
+ }
+
+ &:active {
+ transform: scale(0.95);
+ }
+}
+
+// =============================================================================
+// 6. STATES
+// =============================================================================
+
+.badge.is-hidden {
+ display: none;
+}
+
+.badge.is-animating-in {
+ animation: badge-scale-in 0.2s $ease-bounce;
+}
+
+.badge.is-pulsing {
+ animation: badge-pulse 1.5s infinite;
+}
+
+.badge.is-animating-out {
+ animation: badge-scale-out 0.2s $ease-bounce forwards;
+}
+
+// =============================================================================
+// 7. DARK MODE
+// =============================================================================
+
+[data-bs-theme="dark"] {
+ .badge {
+ box-shadow: $badge-shadow-dark;
+ }
+
+ .badge--outlined {
+ border-width: 1px;
+ }
+
+ .badge--avatar {
+ height: calc($badge-height-base - 2px);
+ min-width: calc($badge-height-base - 2px);
+ }
+}
+
+// =============================================================================
+// 8. ANIMATIONS
+// =============================================================================
+
+@keyframes badge-scale-in {
+ from {
+ transform: scale(0);
+ opacity: 0;
+ }
+ to {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+@keyframes badge-pulse {
+ 0% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.15);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+@keyframes badge-scale-out {
+ from {
+ transform: scale(1);
+ opacity: 1;
+ }
+ to {
+ transform: scale(0);
+ opacity: 0;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_badges-telegram-style.scss b/backend/static/scss_backup_20260115/components/_badges-telegram-style.scss
new file mode 100644
index 00000000..69431de2
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_badges-telegram-style.scss
@@ -0,0 +1,233 @@
+// =============================================================================
+// Telegram-Style Badges
+// =============================================================================
+// Based on Telegram Web K design system (morethanwords/tweb)
+// Perfect circles, smooth animations, professional appearance
+// REFACTORED: использует design tokens из abstracts/_variables.scss
+
+// =============================================================================
+// Base Badge Class
+// =============================================================================
+.badge-telegram {
+ @include badge-base($badge-height-base, $badge-radius);
+ color: $color-white;
+ background: var(--bs-danger);
+ @include badge-shadow();
+ transition: $badge-transition;
+ user-select: none;
+ padding: 0 $badge-padding-x;
+
+ // Auto-hide when empty
+ &:empty {
+ display: none;
+ }
+
+ // Hide when count is 0
+ &[data-count="0"] {
+ display: none;
+ }
+}
+
+// =============================================================================
+// Size Variants
+// =============================================================================
+.badge-telegram-sm {
+ @include badge-base($badge-height-sm, $badge-radius-sm);
+ font-size: 10px;
+ padding: 0 5px;
+}
+
+.badge-telegram-lg {
+ @include badge-base($badge-height-lg, $badge-radius-lg);
+ font-size: 12px;
+ padding: 0 7px;
+}
+
+.badge-telegram-xl {
+ @include badge-base($badge-height-xl, $badge-radius-xl);
+ font-size: 13px;
+ padding: 0 8px;
+}
+
+// =============================================================================
+// Color Variants
+// =============================================================================
+.badge-telegram-primary {
+ background: var(--bs-primary);
+}
+
+.badge-telegram-muted {
+ background: var(--bs-secondary);
+ opacity: 0.8;
+}
+
+.badge-telegram-success {
+ background: var(--bs-success);
+}
+
+.badge-telegram-warning {
+ background: var(--bs-warning);
+ color: var(--bs-dark);
+}
+
+.badge-telegram-info {
+ background: var(--bs-info);
+}
+
+.badge-telegram-mention {
+ background: $telegram-blue;
+}
+
+// =============================================================================
+// Animations
+// =============================================================================
+@keyframes badge-scale-in {
+ from {
+ transform: scale(0);
+ opacity: 0;
+ }
+ to {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+@keyframes badge-pulse {
+ 0% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.15);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+@keyframes badge-scale-out {
+ from {
+ transform: scale(1);
+ opacity: 1;
+ }
+ to {
+ transform: scale(0);
+ opacity: 0;
+ }
+}
+
+// Animation Classes
+.badge-telegram.animate-in {
+ animation: badge-scale-in 0.2s $ease-bounce;
+}
+
+.badge-telegram.pulse {
+ animation: badge-pulse 0.6s $badge-transition;
+}
+
+.badge-telegram.animate-out {
+ animation: badge-scale-out 0.2s $badge-transition;
+}
+
+// =============================================================================
+// Positioning Variants
+// =============================================================================
+// On avatar
+.badge-telegram-avatar {
+ position: absolute;
+ bottom: -2px;
+ right: -2px;
+ border: 2px solid white;
+}
+
+// On button/icon
+.badge-telegram-button {
+ position: absolute;
+ top: -6px;
+ right: -10px;
+ z-index: 1;
+}
+
+// Inline with text
+.badge-telegram-inline {
+ position: relative;
+ top: -1px;
+ margin-left: 4px;
+}
+
+// =============================================================================
+// Special Effects
+// =============================================================================
+// Dot badge (no number)
+.badge-telegram-dot {
+ width: 8px;
+ height: 8px;
+ min-width: 8px;
+ padding: 0;
+ border-radius: 50%;
+}
+
+// Interactive badge (hoverable)
+.badge-telegram-interactive {
+ cursor: pointer;
+ transition: all 0.2s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2);
+ }
+
+ &:active {
+ transform: scale(0.95);
+ }
+}
+
+// Premium badge (gradient)
+.badge-telegram-premium {
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+}
+
+// Star badge (for favorites)
+.badge-telegram-star {
+ background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
+}
+
+// =============================================================================
+// Responsive Design
+// =============================================================================
+@media (max-width: 576px) {
+ .badge-telegram {
+ height: calc($badge-height-base - 2px);
+ min-width: calc($badge-height-base - 2px);
+ font-size: calc($badge-font-size - 1px);
+ padding: 0 calc($badge-padding-x - 1px);
+ }
+}
+
+// =============================================================================
+// Dark Theme Support
+// =============================================================================
+@media (prefers-color-scheme: dark) {
+ .badge-telegram {
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
+ }
+
+ .badge-telegram-avatar {
+ border-color: var(--bs-dark);
+ }
+}
+
+// =============================================================================
+// Utilities
+// =============================================================================
+// Hide badge class (for JavaScript manipulation)
+.badge-telegram-hidden {
+ display: none !important;
+}
+
+// Badge with border
+.badge-telegram-outlined {
+ background: transparent;
+ color: var(--bs-danger);
+ border: 2px solid var(--bs-danger);
+ box-shadow: none;
+}
diff --git a/backend/static/scss_backup_20260115/components/_buttons.scss b/backend/static/scss_backup_20260115/components/_buttons.scss
new file mode 100644
index 00000000..c3df7b91
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_buttons.scss
@@ -0,0 +1,193 @@
+// =============================================================================
+// Custom Button Styles (SCSS)
+// =============================================================================
+// Расширение стандартных кнопок Bootstrap с дополнительными вариантами:
+// - .btn-circle - круглая кнопка
+// - .btn-icon - кнопка с иконкой и текстом
+// - .btn-ghost - кнопка-призрак
+// - .btn-pill - максимально скругленная кнопка
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+// Размеры круглых кнопок (используем значения, кратные 4px)
+$btn-circle-size-sm: 32px;
+$btn-circle-size-md: 36px;
+$btn-circle-size-lg: 44px;
+
+// Размеры шрифтов
+$btn-circle-font-sm: 0.875rem;
+$btn-circle-font-md: 1rem;
+$btn-circle-font-lg: 1.25rem;
+
+// Отступы
+$btn-icon-gap: var(--space-2); // 8px
+$btn-circle-mobile-size: 36px;
+$btn-circle-mobile-padding: var(--space-2); // 8px
+
+// Переходы
+$btn-transition: all 0.2s ease;
+$btn-toggle-transition: transform 0.3s ease;
+
+// =============================================================================
+// КРУГЛЫЕ КНОПКИ
+// =============================================================================
+
+// Миксин для размеров круглых кнопок (DRY)
+@mixin btn-circle-size($size, $font-size) {
+ width: $size !important;
+ height: $size !important;
+ min-width: $size !important;
+ max-width: $size !important;
+ min-height: $size !important;
+ max-height: $size !important;
+ font-size: $font-size;
+}
+
+// Базовый класс для круглых кнопок
+.btn-circle {
+ border-radius: 50% !important;
+ padding: 0 !important;
+ display: inline-flex !important;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ aspect-ratio: 1 / 1;
+ overflow: hidden;
+ line-height: 1;
+
+ // Иконка внутри круглой кнопки
+ i {
+ line-height: 1;
+ display: inline-block;
+ }
+}
+
+// Размеры круглых кнопок
+.btn-circle.btn-sm,
+.btn-circle-sm {
+ @include btn-circle-size($btn-circle-size-sm, $btn-circle-font-sm);
+}
+
+.btn-circle:not(.btn-sm):not(.btn-lg),
+.btn-circle-md {
+ @include btn-circle-size($btn-circle-size-md, $btn-circle-font-md);
+}
+
+.btn-circle.btn-lg,
+.btn-circle-lg {
+ @include btn-circle-size($btn-circle-size-lg, $btn-circle-font-lg);
+}
+
+// =============================================================================
+// КНОПКИ С ИКОНКАМИ
+// =============================================================================
+
+// Кнопка с иконкой и текстом
+.btn-icon {
+ display: inline-flex;
+ align-items: center;
+ gap: $btn-icon-gap;
+
+ i {
+ line-height: 1;
+ }
+}
+
+// Адаптив: только иконка на мобильных
+@media (max-width: 767.98px) {
+ .btn-icon {
+ .btn-text {
+ display: none;
+ }
+
+ // Если это не круглая кнопка, делаем её круглой на мобильных
+ &:not(.btn-circle) {
+ border-radius: 50% !important;
+ padding: $btn-circle-mobile-padding !important;
+ width: $btn-circle-mobile-size;
+ height: $btn-circle-mobile-size;
+ justify-content: center;
+ }
+ }
+}
+
+// =============================================================================
+// ДОПОЛНИТЕЛЬНЫЕ ВАРИАНТЫ
+// =============================================================================
+
+// Кнопка-призрак (без фона, только border при hover)
+.btn-ghost {
+ background: transparent;
+ border: 1px solid transparent;
+ color: var(--bs-body-color);
+ transition: $btn-transition;
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-body-color), transparent 90%);
+ border-color: var(--bs-border-color);
+ color: var(--bs-body-color);
+ }
+
+ &:active {
+ background: color-mix(in srgb, var(--bs-body-color), transparent 85%);
+ }
+}
+
+// Pill-кнопки (максимально скругленные)
+.btn-pill {
+ border-radius: 999px !important;
+}
+
+// =============================================================================
+// СОСТОЯНИЯ
+// =============================================================================
+
+// Активное состояние для toggle-кнопок
+.btn-circle[aria-expanded="true"],
+.btn-circle.active {
+ background-color: var(--bs-primary) !important;
+ border-color: var(--bs-primary) !important;
+ color: white !important;
+}
+
+// Анимация вращения для toggle-кнопок
+.btn-circle[aria-expanded="true"] {
+ transform: rotate(180deg);
+ transition: $btn-toggle-transition;
+}
+
+.btn-circle[aria-expanded="false"] {
+ transform: rotate(0deg);
+ transition: $btn-toggle-transition;
+}
+
+// =============================================================================
+// ГРУППЫ КРУГЛЫХ КНОПОК
+// =============================================================================
+
+// Группа круглых кнопок с небольшим отступом
+.btn-circle-group {
+ display: flex;
+ gap: var(--space-2);
+ align-items: center;
+
+ .btn-circle {
+ margin: 0;
+ }
+}
+
+// =============================================================================
+// ТЕМНАЯ ТЕМА
+// =============================================================================
+
+@media (prefers-color-scheme: dark) {
+ .btn-ghost {
+ color: var(--bs-body-color);
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-body-color), transparent 92%);
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_card-list.scss b/backend/static/scss_backup_20260115/components/_card-list.scss
new file mode 100644
index 00000000..26d2ec21
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_card-list.scss
@@ -0,0 +1,317 @@
+// =============================================================================
+// Card List Component (SCSS)
+// =============================================================================
+// Универсальные стили для карточек в списках: новости, заявления, документы
+// Классы feed-* применяются для любых типов контента
+//
+// Использование:
+// - .card — контейнер карточки
+// - .card-header — шапка карточки (аватар + мета)
+// - .card-body — тело карточки
+// - .card-actions — кнопки действий
+// - .card-list — контейнер потока карточек
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+// Карточки
+$card-icon-size: 42px;
+$card-icon-size-sm: 36px;
+$card-icon-size-compact: 32px;
+$card-icon-border-radius: 9999px;
+
+// Переходы
+$card-transition: box-shadow 0.18s ease, transform 0.18s ease, border-color 0.18s ease;
+$card-action-transition: background 0.2s ease, color 0.2s ease;
+
+// Тени
+$card-hover-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+
+// Границы
+$card-highlighted-border: 3px solid var(--bs-primary);
+
+// Отступы
+$feed-title-margin: var(--space-1) 0;
+
+// =============================================================================
+// ЗАГОЛОВОК СЕКЦИИ
+// =============================================================================
+
+.section-header {
+ display: flex;
+ align-items: center;
+ gap: var(--gap-component);
+ margin-bottom: var(--space-3);
+
+ .title {
+ font-weight: 800;
+ letter-spacing: 0.2px;
+ margin: 0;
+ }
+}
+
+// =============================================================================
+// КОНТЕЙНЕР ПОТОКА КАРТОЧЕК
+// =============================================================================
+
+.card-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+}
+
+// =============================================================================
+// БАЗОВАЯ КАРТОЧКА
+// =============================================================================
+
+.card {
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+ border-radius: var(--feed-radius, 18px);
+ background: var(--bs-body-bg);
+ box-shadow: var(--feed-shadow, 0 2px 8px rgba(0, 0, 0, 0.08));
+ transition: $card-transition;
+ overflow: hidden;
+
+ &:hover {
+ box-shadow: $card-hover-shadow;
+ transform: translateY(-1px);
+ }
+
+ // Вариации карточек
+ &.compact {
+ .card-header {
+ padding: var(--space-1) var(--card-padding-sm);
+ }
+
+ .card-body {
+ padding: var(--space-1) var(--card-padding-sm);
+ }
+
+ .card-icon {
+ width: $card-icon-size-compact;
+ height: $card-icon-size-compact;
+ }
+ }
+
+ &.borderless {
+ border: none;
+ box-shadow: none;
+ border-radius: 0;
+ border-bottom: 1px solid var(--bs-border-color);
+
+ &:hover {
+ transform: none;
+ box-shadow: none;
+ background: var(--bs-tertiary-bg);
+ }
+ }
+
+ &.highlighted {
+ border-left: $card-highlighted-border;
+ background: color-mix(in srgb, var(--bs-primary), transparent 95%);
+ }
+}
+
+// =============================================================================
+// ШАПКА КАРТОЧКИ
+// =============================================================================
+
+.card-header {
+ display: flex;
+ align-items: center;
+ gap: var(--gap-component);
+ padding: var(--card-padding);
+ padding-bottom: var(--space-1);
+}
+
+// Аватар
+.card-icon {
+ width: $card-icon-size;
+ height: $card-icon-size;
+ border-radius: $card-icon-border-radius;
+ overflow: hidden;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ background: var(--bs-tertiary-bg);
+ display: grid;
+ place-items: center;
+ flex: 0 0 auto;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+}
+
+// Мета-информация
+.card-meta {
+ line-height: 1.2;
+ flex: 1;
+ min-width: 0; /* для корректного text-overflow */
+}
+
+.card-title {
+ font-weight: 700;
+ color: var(--bs-body-color);
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.card-subtitle {
+ font-size: 0.82rem;
+ color: var(--bs-secondary-color);
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+// Значок закрепления
+.feed-pin {
+ margin-left: auto;
+ font-size: 0.75rem;
+ padding: var(--space-1);
+ border-radius: 999px;
+ background: #fff3cd;
+ color: #664d03;
+ border: 1px solid #ffe69c;
+ flex-shrink: 0;
+
+ [data-bs-theme="dark"] & {
+ background: #3b2e04;
+ color: #ffda6a;
+ border-color: #4f3f0a;
+ }
+}
+
+// =============================================================================
+// ТЕЛО КАРТОЧКИ
+// =============================================================================
+
+.card-body {
+ padding: var(--space-1) var(--card-padding);
+ padding-bottom: var(--space-1);
+ position: relative;
+}
+
+.feed-title {
+ font: 700 1.3rem/1.5 var(--bs-body-font-family);
+ margin: $feed-title-margin;
+ color: #4b4b4b;
+
+ [data-bs-theme="dark"] & {
+ color: var(--bs-body-color);
+ }
+}
+
+.feed-text {
+ font-size: 0.95rem;
+ line-height: 1.6;
+ color: var(--bs-body-color);
+ margin: 0;
+}
+
+// =============================================================================
+// ИЗОБРАЖЕНИЕ В КАРТОЧКЕ
+// =============================================================================
+
+.feed-img {
+ position: relative;
+ border-top: 1px solid var(--bs-border-color);
+ background: var(--bs-tertiary-bg);
+
+ img {
+ display: block;
+ width: 100%;
+ height: auto;
+ aspect-ratio: 16/9;
+ object-fit: cover;
+ }
+}
+
+// =============================================================================
+// ДЕЙСТВИЯ (ЛАЙКИ, КОММЕНТАРИИ)
+// =============================================================================
+
+.card-actions {
+ display: flex;
+ align-items: center;
+ gap: var(--space-1);
+ padding: var(--card-padding);
+ padding-top: var(--space-2);
+ border-top: 1px solid var(--bs-border-color);
+ position: relative;
+ z-index: 2;
+}
+
+.feed-action {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-1);
+ padding: var(--space-1);
+ border-radius: var(--radius-md, 10px);
+ background: transparent;
+ border: none;
+ color: var(--bs-secondary-color);
+ font-size: 0.875rem;
+ cursor: pointer;
+ transition: $card-action-transition;
+
+ &:hover {
+ background: var(--bs-tertiary-bg);
+ color: var(--bs-body-color);
+ }
+
+ &.active {
+ color: var(--bs-primary);
+ font-weight: 600;
+ }
+
+ i {
+ font-size: 1rem;
+ }
+}
+
+// =============================================================================
+// ФУТЕР КАРТОЧКИ
+// =============================================================================
+
+.feed-footer {
+ padding: var(--space-2) var(--card-padding);
+ border-top: 1px solid var(--bs-border-color);
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ
+// =============================================================================
+
+@media (max-width: 576px) {
+ .section-header {
+ gap: var(--space-2);
+ flex-wrap: wrap;
+ }
+
+ .card-header {
+ padding: var(--space-2);
+ padding-bottom: var(--space-1);
+ }
+
+ .card-icon {
+ width: $card-icon-size-sm;
+ height: $card-icon-size-sm;
+ }
+
+ .feed-title {
+ font-size: 1.1rem;
+ }
+
+ .card-actions {
+ padding: var(--space-2);
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_cards.scss b/backend/static/scss_backup_20260115/components/_cards.scss
new file mode 100644
index 00000000..bb9cf1b2
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_cards.scss
@@ -0,0 +1,341 @@
+// =============================================================================
+// Cards Component
+// =============================================================================
+// Glassmorphism карточки с поддержкой тёмной темы
+
+// =============================================================================
+// 1. БАЗОВЫЕ СТИЛИ КАРТОЧКИ
+// =============================================================================
+
+.card {
+ // Применяем glassmorphism эффект
+ @include glassmorphism-card();
+
+ // Прозрачный фон
+ --bs-card-bg: transparent;
+ background: $glass-light-bg !important;
+
+ // Тонкая рамка
+ border: 1px solid $glass-light-border !important;
+
+ // Плавные переходы
+ @include transition-all($transition-medium);
+ overflow: hidden;
+
+ // Hover эффект - усиливаем glassmorphism
+ &:hover {
+ background: rgba(255, 255, 255, 0.15) !important;
+ border-color: rgba(0, 0, 0, 0.12) !important;
+ backdrop-filter: $blur-lg saturate(200%);
+ -webkit-backdrop-filter: $blur-lg saturate(200%);
+ box-shadow: 0 12px 48px 0 rgba(0, 0, 0, 0.15);
+ transform: translateY(-2px);
+ }
+}
+
+// =============================================================================
+// 2. ТЁМНАЯ ТЕМА
+// =============================================================================
+
+[data-bs-theme="dark"] {
+ .card {
+ --bs-card-bg: transparent;
+ --bs-card-border-color: $glass-dark-border;
+ background: transparent !important;
+ border-color: $glass-dark-border !important;
+
+ &:hover {
+ background: rgba(255, 255, 255, 0.03) !important;
+ border-color: rgba(255, 255, 255, 0.15) !important;
+ }
+ }
+}
+
+// =============================================================================
+// 3. LAYOUT КОМПОНЕНТЫ КАРТОЧЕК
+// =============================================================================
+
+// Контейнер списка карточек
+.card-list {
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+}
+
+// Заголовок секции
+.section-header {
+ @include flex-align-center();
+ gap: var(--gap-component, 1rem);
+ margin-bottom: var(--space-3, 0.75rem);
+
+ .title {
+ font-weight: 800;
+ letter-spacing: 0.2px;
+ margin: 0;
+ }
+}
+
+// =============================================================================
+// 4. СТРУКТУРА КАРТОЧКИ
+// =============================================================================
+
+// Card header
+.card-header {
+ @include flex-align-center();
+ gap: var(--gap-component, 1rem);
+ padding: var(--card-padding, 1rem);
+ padding-bottom: var(--space-1, 0.25rem);
+ background: transparent;
+ border-bottom: none;
+}
+
+// Иконка/аватар в карточке
+.card-icon {
+ width: 42px;
+ height: 42px;
+ @include circle();
+ overflow: hidden;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ background: var(--bs-tertiary-bg);
+ @include flex-center();
+ flex: 0 0 auto;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+}
+
+// Метаинформация
+.card-meta {
+ line-height: 1.2;
+ flex: 1;
+ min-width: 0;
+}
+
+// Заголовок карточки
+.card-title {
+ font-weight: 700;
+ color: var(--bs-body-color);
+ @include text-truncate();
+ display: block;
+ margin-bottom: 0;
+}
+
+// Подзаголовок
+.card-subtitle {
+ font-size: 0.82rem;
+ color: var(--bs-secondary-color);
+ @include text-truncate();
+ display: block;
+ margin-bottom: 0;
+}
+
+// Тело карточки
+.card-body {
+ padding: var(--space-1, 0.25rem) var(--card-padding, 1rem);
+ padding-bottom: var(--space-1, 0.25rem);
+ position: relative;
+}
+
+// =============================================================================
+// 5. ДЕЙСТВИЯ КАРТОЧКИ (CARD ACTIONS)
+// =============================================================================
+
+.card-actions {
+ @include flex-align-center();
+ gap: var(--space-1, 0.25rem);
+ padding: var(--card-padding, 1rem);
+ padding-top: var(--space-2, 0.5rem);
+ border-top: 1px solid var(--bs-border-color);
+ position: relative;
+ z-index: $z-base;
+
+ // Активные кнопки в actions
+ .btn,
+ button {
+ &.active,
+ &.is-liked {
+ color: var(--bs-primary) !important;
+ font-weight: 600;
+ }
+ }
+}
+
+// =============================================================================
+// 6. ВАРИАЦИИ КАРТОЧЕК
+// =============================================================================
+
+// Компактная карточка
+.card.compact {
+ .card-header {
+ padding: var(--space-1, 0.25rem) var(--card-padding-sm, 0.5rem);
+ }
+
+ .card-body {
+ padding: var(--space-1, 0.25rem) var(--card-padding-sm, 0.5rem);
+ }
+
+ .card-icon {
+ width: 32px;
+ height: 32px;
+ }
+}
+
+// Карточка без рамки
+.card.borderless {
+ border: none;
+ @include no-shadow();
+ border-radius: 0;
+ border-bottom: 1px solid var(--bs-border-color);
+
+ &:hover {
+ transform: none;
+ @include no-shadow();
+ background: var(--bs-tertiary-bg);
+ }
+}
+
+// Выделенная карточка
+.card.highlighted {
+ border-left: 3px solid var(--bs-primary);
+ background: color-mix(in srgb, var(--bs-primary), transparent 95%);
+}
+
+// =============================================================================
+// 7. RESPONSIVE
+// =============================================================================
+
+@include mobile() {
+ .section-header {
+ gap: var(--space-2, 0.5rem);
+ flex-wrap: wrap;
+ }
+
+ .card-header {
+ padding: var(--space-2, 0.5rem);
+ padding-bottom: var(--space-1, 0.25rem);
+ }
+
+ .card-icon {
+ width: 36px;
+ height: 36px;
+ }
+
+ .card-actions {
+ padding: var(--space-2, 0.5rem);
+ }
+}
+
+// =============================================================================
+// 8. СТИЛИ КНОПОК (из custom-bootstrap.scss)
+// =============================================================================
+
+// Базовые стили для ВСЕХ кнопок - полностью прозрачные
+.btn {
+ background: transparent !important;
+ border: none !important;
+ color: var(--bs-secondary-color);
+ font-weight: 500;
+ @include transition(color, $transition-fast);
+
+ &:hover:not(:disabled) {
+ color: var(--bs-body-color);
+ }
+
+ &:active:not(:disabled) {
+ color: var(--bs-body-color);
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
+// Primary кнопка (единственная с цветным фоном)
+.btn-primary {
+ color: $color-white !important;
+ background: rgba(13, 110, 253, 0.7) !important;
+
+ &:hover:not(:disabled) {
+ background: rgba(13, 110, 253, 0.85) !important;
+ box-shadow: 0 4px 16px rgba(13, 110, 253, 0.3);
+ }
+
+ &:active:not(:disabled) {
+ background: rgba(13, 110, 253, 0.95) !important;
+ }
+}
+
+// Secondary, outline, ghost - все прозрачные
+.btn-secondary,
+.btn-outline-primary,
+.btn-outline-secondary,
+.btn-ghost {
+ background: transparent !important;
+ color: var(--bs-secondary-color);
+
+ &:hover:not(:disabled) {
+ background: transparent !important;
+ color: var(--bs-body-color);
+ }
+
+ &:active:not(:disabled) {
+ background: transparent !important;
+ }
+}
+
+// Особый цвет для outline-primary
+.btn-outline-primary {
+ color: var(--bs-primary);
+
+ &:hover:not(:disabled) {
+ color: var(--bs-primary);
+ background: transparent !important;
+ }
+}
+
+// Кнопки в тёмной теме
+[data-bs-theme="dark"] {
+ .btn {
+ &:hover:not(:disabled),
+ &:active:not(:disabled) {
+ background: transparent !important;
+ }
+ }
+
+ .btn-primary {
+ background: rgba(13, 110, 253, 0.6) !important;
+
+ &:hover:not(:disabled) {
+ background: rgba(13, 110, 253, 0.75) !important;
+ }
+
+ &:active:not(:disabled) {
+ background: rgba(13, 110, 253, 0.85) !important;
+ }
+ }
+
+ .btn-secondary,
+ .btn-outline-primary,
+ .btn-outline-secondary,
+ .btn-ghost {
+ &:hover:not(:disabled),
+ &:active:not(:disabled) {
+ background: transparent !important;
+ }
+ }
+}
+
+// =============================================================================
+// 9. УТИЛИТАРНЫЕ КЛАССЫ
+// =============================================================================
+
+// Моноширинный шрифт для дат, цифр, кодов
+.text-mono {
+ font-variant-numeric: tabular-nums;
+ font-family: ui-monospace, 'SF Mono', SFMono-Regular, 'Consolas', 'Liberation Mono', 'Menlo', 'Courier', monospace;
+}
diff --git a/backend/static/scss_backup_20260115/components/_comments.scss b/backend/static/scss_backup_20260115/components/_comments.scss
new file mode 100644
index 00000000..bb17b850
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_comments.scss
@@ -0,0 +1,152 @@
+// =============================================================================
+// Comments Component
+// =============================================================================
+// Единый стиль для комментариев во всех местах приложения:
+// - В карточках постов (_feed_cards.html)
+// - На странице деталей поста (post_detail.html)
+// - В модальном окне (postDetailModal.js)
+
+.comment-item {
+ padding: 0.5rem 0; // py-2
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+
+ .comment-header {
+ font-size: 0.875rem; // small
+ margin-bottom: 0.25rem;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+
+ .comment-author {
+ font-weight: 600; // fw-semibold
+ text-decoration: none;
+ color: inherit;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+
+ .comment-separator {
+ color: var(--bs-secondary);
+ margin: 0 0.25rem;
+ }
+
+ .comment-date {
+ color: var(--bs-secondary);
+ }
+
+ .badge {
+ font-size: 0.7rem;
+ padding: 0.15rem 0.4rem;
+ }
+ }
+
+ .comment-body {
+ font-size: 0.875rem; // small
+ line-height: 1.5;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ background: var(--bs-tertiary-bg);
+ padding: 0.5rem 0.75rem;
+ border-radius: 12px;
+ max-width: 80%;
+ }
+
+ // Комментарии автора поста справа
+ &.comment-item--author {
+ align-items: flex-end;
+
+ .comment-header {
+ flex-direction: row-reverse;
+
+ .comment-separator {
+ order: 0;
+ }
+
+ .comment-date {
+ order: -1;
+ }
+ }
+
+ .comment-body {
+ background: var(--bs-primary-bg-subtle, rgba(13, 110, 253, 0.1));
+ border: 1px solid var(--bs-primary-border-subtle, rgba(13, 110, 253, 0.2));
+ }
+ }
+}
+
+// Контейнер для списка комментариев
+.comments-list {
+ margin-bottom: 1rem;
+}
+
+// Заголовок секции комментариев
+.comments-section-header {
+ display: flex;
+ align-items: center;
+ margin-bottom: 0.5rem;
+
+ .comments-icon {
+ font-size: 1.5rem;
+ color: var(--bs-primary);
+ margin-right: 0.5rem;
+ }
+
+ .comments-title {
+ margin-bottom: 0;
+ }
+
+ .comments-count {
+ font-size: 0.875rem;
+ color: var(--bs-secondary);
+ margin-left: 0.5rem;
+ }
+}
+
+// Обёртка для комментариев с sticky формой
+.comments-section-wrapper {
+ position: relative;
+}
+
+// Скроллируемая область с комментариями
+.comments-scrollable {
+ max-height: 400px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding-bottom: 1rem;
+
+ // Firefox скроллбар
+ scrollbar-width: thin;
+ scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
+
+ // Стилизация скроллбара (Chrome, Safari, Edge)
+ &::-webkit-scrollbar {
+ width: 8px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: rgba(0, 0, 0, 0.15);
+ border-radius: 4px;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.25);
+ }
+ }
+}
+
+// Sticky форма для комментариев
+.comment-form-sticky {
+ position: sticky;
+ bottom: 0;
+ background: var(--bs-body-bg);
+ z-index: 10;
+ border-top: 1px solid var(--bs-border-color);
+ padding-top: 1rem;
+}
diff --git a/backend/static/scss_backup_20260115/components/_common.scss b/backend/static/scss_backup_20260115/components/_common.scss
new file mode 100644
index 00000000..01a2a543
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_common.scss
@@ -0,0 +1,327 @@
+/**
+ * _common.scss
+ * Общие переиспользуемые классы для всех компонентов
+ * Избегает дублирования между компонентами
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ BUTTONS
+────────────────────────────────────────────────────────────── */
+
+/* Иконочная кнопка */
+.btn-icon {
+ width: 36px;
+ height: 36px;
+ display: inline-grid;
+ place-items: center;
+ border: 1px solid var(--bs-border-color);
+ border-radius: var(--button-radius, 10px);
+ background: transparent;
+ color: var(--bs-body-color);
+ cursor: pointer;
+ transition: all var(--transition-fast, 0.15s);
+
+ &:hover {
+ background: var(--bs-tertiary-bg);
+ border-color: var(--bs-border-color);
+ }
+
+ &--primary {
+ color: var(--bs-primary);
+ }
+
+ &--danger {
+ color: var(--bs-danger);
+ }
+
+ &--success {
+ color: var(--bs-success);
+ }
+
+ &:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ BADGES
+────────────────────────────────────────────────────────────── */
+
+/* Бейдж подтверждения */
+.badge-acked {
+ background: color-mix(in srgb, var(--bs-success) 20%, transparent);
+ color: var(--bs-success);
+ border: 1px solid color-mix(in srgb, var(--bs-success) 30%, transparent);
+ padding: 0.28rem 0.55rem;
+ border-radius: var(--badge-radius, 999px);
+ font-size: 0.8rem;
+ font-weight: 500;
+
+ [data-bs-theme="dark"] & {
+ background: color-mix(in srgb, var(--bs-success) 15%, #000);
+ color: color-mix(in srgb, var(--bs-success) 80%, #fff);
+ border-color: color-mix(in srgb, var(--bs-success) 25%, transparent);
+ }
+}
+
+/* Бейдж статуса */
+.badge-status {
+ padding: var(--space-1);
+ border-radius: var(--badge-radius, 999px);
+ font-size: 0.75rem;
+ font-weight: 600;
+ border: 1px solid;
+
+ &--pending {
+ background: color-mix(in srgb, var(--bs-warning) 15%, transparent);
+ color: var(--bs-warning);
+ border-color: color-mix(in srgb, var(--bs-warning) 30%, transparent);
+ }
+
+ &--approved {
+ background: color-mix(in srgb, var(--bs-success) 15%, transparent);
+ color: var(--bs-success);
+ border-color: color-mix(in srgb, var(--bs-success) 30%, transparent);
+ }
+
+ &--rejected {
+ background: color-mix(in srgb, var(--bs-danger) 15%, transparent);
+ color: var(--bs-danger);
+ border-color: color-mix(in srgb, var(--bs-danger) 30%, transparent);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ PINNED BADGE (централизованный)
+────────────────────────────────────────────────────────────── */
+.chat-pinned-badge {
+ position: absolute;
+ background: var(--bs-warning);
+ color: white;
+ @include circle();
+ @include flex-center();
+ z-index: 1;
+
+ // Размер по умолчанию (средний)
+ width: 22px;
+ height: 22px;
+ top: 6px;
+ right: 6px;
+ font-size: 0.75rem;
+
+ // Маленький вариант (для списка чатов)
+ &--sm {
+ width: 20px;
+ height: 20px;
+ top: 4px;
+ right: 4px;
+ font-size: 0.7rem;
+ }
+
+ // Большой вариант (для детального чата)
+ &--lg {
+ width: 24px;
+ height: 24px;
+ top: 8px;
+ right: 8px;
+ font-size: 0.8rem;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ AVATARS
+────────────────────────────────────────────────────────────── */
+
+.avatar {
+ border-radius: 50%;
+ overflow: hidden;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--bs-tertiary-bg);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ flex-shrink: 0;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+
+ i {
+ color: var(--bs-secondary-color);
+ }
+}
+
+/* Размеры */
+.avatar-xs {
+ width: var(--avatar-xs, 28px);
+ height: var(--avatar-xs, 28px);
+}
+
+.avatar-sm {
+ width: var(--avatar-sm, 36px);
+ height: var(--avatar-sm, 36px);
+}
+
+.avatar-md {
+ width: var(--avatar-md, 44px);
+ height: var(--avatar-md, 44px);
+}
+
+.avatar-lg {
+ width: var(--avatar-lg, 64px);
+ height: var(--avatar-lg, 64px);
+}
+
+.avatar-xl {
+ width: var(--avatar-xl, 96px);
+ height: var(--avatar-xl, 96px);
+}
+
+/* ─────────────────────────────────────────────────────────────
+ FEED AUTHOR & META
+────────────────────────────────────────────────────────────── */
+
+.card-title {
+ font-weight: 700;
+ color: var(--bs-body-color);
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.card-subtitle {
+ font-size: 0.82rem;
+ color: var(--bs-secondary-color);
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ a {
+ color: inherit;
+ text-decoration: none;
+
+ &:hover {
+ color: var(--bs-primary);
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ AVATARS (Centralized)
+────────────────────────────────────────────────────────────── */
+
+.chat-avatar,
+.avatar {
+ @include circle();
+ overflow: hidden;
+ flex-shrink: 0;
+ background: var(--bs-tertiary-bg);
+ border: 1px solid var(--bs-border-color);
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+}
+
+// Size variants
+.chat-avatar,
+.avatar {
+ width: $avatar-md;
+ height: $avatar-md;
+}
+
+.chat-avatar--sm,
+.avatar--sm {
+ width: $avatar-sm;
+ height: $avatar-sm;
+}
+
+.chat-avatar--lg,
+.avatar--lg {
+ width: $avatar-lg;
+ height: $avatar-lg;
+}
+
+.chat-avatar--xl,
+.avatar--xl {
+ width: $avatar-xl;
+ height: $avatar-xl;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHIPS
+────────────────────────────────────────────────────────────── */
+
+.chip {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-1);
+ padding: var(--space-1);
+ border-radius: var(--badge-radius, 999px);
+ background: var(--bs-tertiary-bg);
+ border: 1px solid var(--bs-border-color);
+ font-size: 0.82rem;
+ color: var(--bs-body-color);
+}
+
+.chip-remove {
+ cursor: pointer;
+ color: var(--bs-danger);
+ font-weight: 700;
+ line-height: 1;
+
+ &:hover {
+ color: color-mix(in srgb, var(--bs-danger) 80%, #000);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ UTILITIES
+────────────────────────────────────────────────────────────── */
+
+/* Текст с многоточием */
+.text-truncate-2 {
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.text-truncate-3 {
+ display: -webkit-box;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+/* Кастомный scrollbar */
+.custom-scrollbar {
+ &::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: color-mix(in srgb, var(--bs-border-color) 70%, transparent);
+ border-radius: 10px;
+
+ &:hover {
+ background: var(--bs-border-color);
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_department-controls.scss b/backend/static/scss_backup_20260115/components/_department-controls.scss
new file mode 100644
index 00000000..8d69f3dc
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_department-controls.scss
@@ -0,0 +1,26 @@
+// =============================================================================
+// Department Controls (SCSS)
+// =============================================================================
+// Стили для модального управления отделом
+
+// =============================================================================
+// MODAL Z-INDEX OVERRIDES
+// =============================================================================
+
+// Модалки поверх всего
+.modal-backdrop.show {
+ z-index: 3000 !important;
+}
+
+.modal.show {
+ z-index: 3010 !important;
+}
+
+.modal-dialog {
+ pointer-events: auto !important;
+}
+
+// Портальный dropdown автокомплита ролей
+.role-portal {
+ z-index: 1800 !important;
+}
diff --git a/backend/static/scss_backup_20260115/components/_document-list.scss b/backend/static/scss_backup_20260115/components/_document-list.scss
new file mode 100644
index 00000000..3c770b8c
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_document-list.scss
@@ -0,0 +1,248 @@
+// =============================================================================
+// Document List Styles (SCSS)
+// =============================================================================
+// Стили списка документов, recipient picker, и подтверждений
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$doc-icon-size: 28px;
+$doc-row-padding: var(--space-2);
+$doc-border-unacked-width: 3px;
+$recipient-avatar-size: 26px;
+$card-icon-size: 32px;
+
+// Цвета
+$doc-hover-primary: 4%;
+$doc-unacked-bg: 8%;
+$doc-unacked-hover: 15%;
+
+// =============================================================================
+// СПИСОК ДОКУМЕНТОВ
+// =============================================================================
+
+#docList.card-list {
+ display: block;
+ gap: 0 !important;
+}
+
+#docList .doc-row {
+ padding: $doc-row-padding !important;
+ margin: 0 !important;
+ border-bottom: 1px solid var(--bs-border-color);
+ transition: background-color 0.2s ease;
+ cursor: pointer;
+
+ &:hover {
+ background-color: color-mix(in srgb, var(--bs-primary) $doc-hover-primary, transparent);
+ }
+
+ &.doc-unacked {
+ background-color: color-mix(in srgb, var(--bs-warning) $doc-unacked-bg, transparent);
+ border-left: $doc-border-unacked-width solid var(--bs-warning);
+ padding-left: calc($doc-row-padding - $doc-border-unacked-width) !important;
+
+ &:hover {
+ background-color: color-mix(in srgb, var(--bs-warning) $doc-unacked-hover, transparent);
+ }
+ }
+
+ &:last-child {
+ border-bottom: 0;
+ }
+}
+
+// =============================================================================
+// ЗАГОЛОВОК ДОКУМЕНТА
+// =============================================================================
+
+#docList .card-header {
+ display: grid;
+ grid-template-columns: $doc-icon-size 1fr auto;
+ align-items: center;
+ gap: 0.75rem;
+ margin: 0;
+ padding: 0 !important;
+}
+
+#docList .feed-ico {
+ width: $doc-icon-size;
+ height: $doc-icon-size;
+ display: grid;
+ place-items: center;
+ border-radius: 8px;
+ background: color-mix(in srgb, var(--bs-body-bg) 90%, transparent);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 30%);
+ color: var(--bs-primary);
+}
+
+// =============================================================================
+// ДЕЙСТВИЯ С ДОКУМЕНТАМИ
+// =============================================================================
+
+.doc-actions {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ flex-wrap: wrap;
+}
+
+// =============================================================================
+// SCOPE SWITCH
+// =============================================================================
+
+.scope-switch .btn {
+ min-height: 36px;
+ border-radius: 999px;
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ: МОБИЛЬНЫЕ
+// =============================================================================
+
+@media (max-width: 576px) {
+ #docList .card-header {
+ grid-template-columns: $doc-icon-size 1fr;
+ gap: 0.5rem;
+ }
+
+ .doc-actions {
+ grid-column: 2;
+ margin-top: 0.5rem;
+ justify-content: flex-start;
+
+ .btn,
+ .btn-icon {
+ font-size: 0.85rem;
+ padding: 0.35rem 0.65rem;
+ }
+ }
+}
+
+// =============================================================================
+// RECIPIENT PICKER
+// =============================================================================
+
+.recipient-picker {
+ border: 1px solid var(--bs-border-color);
+ border-radius: 12px;
+ padding: var(--space-2);
+ background: var(--bs-body-bg);
+}
+
+.recipient-picker .rp-selected {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--space-1);
+ margin-bottom: var(--space-1);
+}
+
+.recipient-picker .rp-chip {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-1);
+ border: 1px solid var(--bs-border-color);
+ border-radius: 999px;
+ padding: var(--space-1);
+ font-size: 0.85rem;
+
+ button {
+ border: 0;
+ background: transparent;
+ padding: 0 var(--space-1);
+ line-height: 1;
+ }
+}
+
+.recipient-picker .rp-search {
+ position: relative;
+
+ input {
+ width: 100%;
+ }
+}
+
+.recipient-picker .rp-results {
+ margin-top: 0.5rem;
+ max-height: 220px;
+ overflow: auto;
+ border: 1px solid var(--bs-border-color);
+ border-radius: 10px;
+}
+
+.recipient-picker .rp-item {
+ display: flex;
+ align-items: center;
+ gap: var(--space-1);
+ padding: var(--space-1);
+ border-bottom: 1px solid var(--bs-border-color);
+
+ &:last-child {
+ border-bottom: 0;
+ }
+
+ small {
+ color: var(--bs-secondary-color);
+ }
+}
+
+.recipient-picker .rp-empty {
+ padding: var(--space-1);
+ text-align: center;
+ color: var(--bs-secondary-color);
+}
+
+.recipient-picker .rp-avatar {
+ width: $recipient-avatar-size;
+ height: $recipient-avatar-size;
+ border-radius: 50%;
+ background: color-mix(in srgb, var(--bs-primary) 12%, transparent);
+ display: inline-grid;
+ place-items: center;
+ font-size: 0.7rem;
+}
+
+.recipient-block[hidden] {
+ display: none !important;
+}
+
+// =============================================================================
+// ACKNOWLEDGMENTS (ПОДТВЕРЖДЕНИЯ)
+// =============================================================================
+
+.acks-list {
+ max-height: 50vh;
+ overflow: auto;
+ margin: 0;
+ padding-left: 1.1rem;
+}
+
+.acks-empty {
+ color: var(--bs-secondary-color);
+}
+
+.acks-more {
+ margin-top: 0.5rem;
+}
+
+// =============================================================================
+// ИКОНКИ
+// =============================================================================
+
+.card-icon {
+ width: $card-icon-size;
+ height: $card-icon-size;
+ flex: 0 0 $card-icon-size;
+ border-radius: 50%;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.rp-avatar {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
diff --git a/backend/static/scss_backup_20260115/components/_feed-specific.scss b/backend/static/scss_backup_20260115/components/_feed-specific.scss
new file mode 100644
index 00000000..b96d4f77
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_feed-specific.scss
@@ -0,0 +1,134 @@
+// =============================================================================
+// Feed-Specific Styles (SCSS)
+// =============================================================================
+// Стили, специфичные для постов в ленте новостей
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$feed-pin-bg-light: #fff3cd;
+$feed-pin-color-light: #664d03;
+$feed-pin-border-light: #ffe69c;
+$feed-pin-bg-dark: #3b2e04;
+$feed-pin-color-dark: #ffda6a;
+$feed-pin-border-dark: #4f3f0a;
+
+$feed-title-color-light: #4b4b4b;
+
+// =============================================================================
+// ЗНАЧОК ЗАКРЕПЛЕНИЯ
+// =============================================================================
+
+.feed-pin {
+ margin-left: auto;
+ font-size: 0.75rem;
+ padding: var(--space-1, 0.25rem);
+ border-radius: 999px;
+ background: $feed-pin-bg-light;
+ color: $feed-pin-color-light;
+ border: 1px solid $feed-pin-border-light;
+ flex-shrink: 0;
+
+ [data-bs-theme="dark"] & {
+ background: $feed-pin-bg-dark;
+ color: $feed-pin-color-dark;
+ border-color: $feed-pin-border-dark;
+ }
+}
+
+// =============================================================================
+// ЗАГОЛОВОК ПОСТА
+// =============================================================================
+
+.feed-title {
+ font: 700 1.3rem/1.5 var(--bs-body-font-family);
+ margin: var(--space-1, 0.25rem) 0;
+ color: $feed-title-color-light;
+
+ [data-bs-theme="dark"] & {
+ color: var(--bs-body-color);
+ }
+}
+
+// =============================================================================
+// ТЕКСТ ПОСТА
+// =============================================================================
+
+.feed-text {
+ font-size: 0.95rem;
+ line-height: 1.6;
+ color: var(--bs-body-color);
+ margin: 0;
+}
+
+// =============================================================================
+// ИЗОБРАЖЕНИЕ ПОСТА
+// =============================================================================
+
+.feed-img {
+ position: relative;
+ border-top: 1px solid var(--bs-border-color);
+ background: var(--bs-tertiary-bg);
+
+ img {
+ display: block;
+ width: 100%;
+ height: auto;
+ aspect-ratio: 16/9;
+ object-fit: cover;
+ }
+}
+
+// =============================================================================
+// КНОПКИ ДЕЙСТВИЙ (ЛАЙКИ, КОММЕНТАРИИ)
+// =============================================================================
+
+.feed-action {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-1, 0.25rem);
+ padding: var(--space-1, 0.25rem);
+ border-radius: var(--radius-md, 10px);
+ background: transparent;
+ border: none;
+ color: var(--bs-secondary-color);
+ font-size: 0.875rem;
+ cursor: pointer;
+ transition: background 0.2s ease, color 0.2s ease;
+
+ &:hover {
+ background: var(--bs-tertiary-bg);
+ color: var(--bs-body-color);
+ }
+
+ &.active {
+ color: var(--bs-primary);
+ font-weight: 600;
+ }
+
+ i {
+ font-size: 1rem;
+ }
+}
+
+// =============================================================================
+// ФУТЕР ПОСТА
+// =============================================================================
+
+.feed-footer {
+ padding: var(--space-2, 0.5rem) var(--card-padding, 1rem);
+ border-top: 1px solid var(--bs-border-color);
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ
+// =============================================================================
+
+@media (max-width: 576px) {
+ .feed-title {
+ font-size: 1.1rem;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_ios-components.scss b/backend/static/scss_backup_20260115/components/_ios-components.scss
new file mode 100644
index 00000000..076f5fd7
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_ios-components.scss
@@ -0,0 +1,546 @@
+// =============================================================================
+// iOS-style Components (SCSS)
+// =============================================================================
+// iOS-style компоненты: карточки, списки, аккордеоны, badges
+//
+// Зависимости:
+// - variables.css (--feed-radius, --feed-shadow, --navbar-h)
+// - common.css (.chip определён там)
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+// Карточки
+$ios-card-border-radius: var(--feed-radius);
+$ios-card-transition: box-shadow 0.18s ease, transform 0.18s ease, border-color 0.18s ease;
+$ios-card-hover-transform: translateY(-1px);
+
+// Аватар
+$avatar-size: 132px;
+$avatar-border-radius: 28px;
+$avatar-font-size: 3rem;
+
+// Списки
+$ios-list-border-radius: 14px;
+$ios-cell-gap: 0.75rem;
+$ios-cell-padding: 0.85rem 1rem;
+
+// Badges
+$badge-border-radius: 999px;
+$badge-font-size: 0.8rem;
+$badge-icon-size: 0.95rem;
+
+// Аккордеон
+$ios-acc-border-radius: 14px;
+
+// Collapse
+$collapse-transition: height 0.35s ease;
+$collapse-caret-transition: transform 0.25s ease;
+
+// Контейнер
+$container-xxl-max-width: 1820px;
+
+// =============================================================================
+// МИКСИНЫ
+// =============================================================================
+
+// Миксин для цветовых badge-ов
+@mixin badge-variant($color) {
+ background: color-mix(in srgb, var(--bs-#{$color}) 15%, var(--bs-body-bg));
+ color: color-mix(in srgb, var(--bs-#{$color}) 60%, black 0%);
+ border: 1px solid color-mix(in srgb, var(--bs-#{$color}) 35%, transparent);
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-#{$color}) 20%, var(--bs-body-bg));
+ }
+}
+
+// =============================================================================
+// BASE CARD
+// =============================================================================
+
+.ios-card {
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+ border-radius: $ios-card-border-radius;
+ background: var(--bs-body-bg);
+ box-shadow: var(--feed-shadow);
+ transition: $ios-card-transition;
+ overflow: hidden;
+
+ &:hover {
+ box-shadow: var(--feed-shadow-hover);
+ transform: $ios-card-hover-transform;
+ }
+}
+
+// =============================================================================
+// HEADER
+// =============================================================================
+
+.ios-header {
+ position: sticky;
+ top: var(--navbar-h, 0px);
+ z-index: 5;
+ padding: var(--space-2) 0;
+ backdrop-filter: saturate(180%) blur(12px);
+ background: color-mix(in srgb, var(--bs-body-bg) 85%, transparent);
+ border-bottom: none !important;
+}
+
+.ios-title {
+ font-weight: 800;
+ letter-spacing: -0.01em;
+}
+
+.row.g-ios {
+ align-items: flex-start;
+}
+
+// =============================================================================
+// AVATAR
+// =============================================================================
+
+.ios-ava,
+.ios-ava--ph {
+ display: grid;
+ place-items: center;
+ background: var(--bs-tertiary-bg);
+ color: var(--bs-secondary-color);
+ font-size: $avatar-font-size;
+ line-height: 1;
+ width: 100%;
+ height: 100%;
+ border-radius: $avatar-border-radius;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+}
+
+.ava-wrap {
+ position: relative;
+ width: $avatar-size;
+ height: $avatar-size;
+ margin: 0 auto var(--space-2);
+ display: block;
+}
+
+// =============================================================================
+// NAME & ROLE
+// =============================================================================
+
+.ios-name {
+ font-weight: 800;
+ font-size: 1.25rem;
+}
+
+.ios-role {
+ font-size: 0.9rem;
+ color: var(--bs-secondary-color);
+}
+
+// =============================================================================
+// CHIPS
+// =============================================================================
+
+// Base .chip определён в common.css
+.chips {
+ display: flex;
+ flex-wrap: wrap;
+ gap: var(--space-1);
+}
+
+// =============================================================================
+// COLLAPSE TRIGGERS
+// =============================================================================
+
+.ios-collapse-trigger {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--space-2);
+ padding: var(--space-1) var(--space-2);
+ cursor: pointer;
+ border-radius: $ios-list-border-radius;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ background: color-mix(in srgb, var(--bs-body-bg) 94%, transparent);
+ color: var(--bs-body-color);
+}
+
+.ios-collapse-caret {
+ transition: $collapse-caret-transition;
+}
+
+.ios-collapse-trigger[aria-expanded="true"] .ios-collapse-caret {
+ transform: rotate(180deg);
+}
+
+.ios-collapse-trigger + .collapse {
+ margin-top: 0 !important;
+
+ > .ios-list,
+ > .chips {
+ margin-top: 0.5rem;
+ }
+}
+
+.collapsing {
+ overflow: hidden;
+ transition: $collapse-transition;
+}
+
+// =============================================================================
+// LISTS
+// =============================================================================
+
+.ios-list {
+ border-radius: $ios-list-border-radius;
+ overflow: hidden;
+ background: var(--bs-body-bg);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+}
+
+.ios-cell {
+ display: flex;
+ align-items: center;
+ gap: $ios-cell-gap;
+ padding: $ios-cell-padding;
+ border-bottom: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+ flex-wrap: wrap;
+
+ &:last-child {
+ border-bottom: 0;
+ }
+
+ i {
+ width: 1.25rem;
+ text-align: center;
+ opacity: 0.9;
+ }
+
+ a {
+ text-decoration: none;
+ color: inherit;
+ }
+
+ // Departments
+ &.dept-item {
+ justify-content: space-between;
+
+ > .d-flex {
+ flex: 0 1 auto;
+ flex-wrap: wrap;
+ justify-content: flex-end;
+ gap: 0.35rem 0.5rem;
+ max-width: 100%;
+ }
+
+ &.is-editing .dept-role {
+ display: none !important;
+ }
+ }
+
+ &.dept-head {
+ border-left: 0;
+ background: transparent;
+ }
+}
+
+.ios-section-title {
+ font-weight: 700;
+ font-size: 1rem;
+ margin-bottom: 0.5rem;
+}
+
+.rounded-ios {
+ border-radius: $ios-list-border-radius !important;
+}
+
+// =============================================================================
+// DEPARTMENTS LIST
+// =============================================================================
+
+.dept-line {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ min-width: 0;
+}
+
+.dept-name {
+ font-weight: 700;
+}
+
+.dept-role {
+ color: var(--bs-secondary-color);
+}
+
+// =============================================================================
+// BADGES (HEAD & GEAR)
+// =============================================================================
+
+.badge-head,
+.badge-gear {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-1);
+ padding: var(--space-1);
+ border-radius: $badge-border-radius;
+ font-weight: 700;
+ font-size: $badge-font-size;
+ line-height: 1;
+ white-space: nowrap;
+ flex: 0 0 auto;
+
+ .bi {
+ font-size: $badge-icon-size;
+ line-height: 1;
+ }
+}
+
+.badge-head {
+ @include badge-variant(warning);
+}
+
+.badge-gear {
+ @include badge-variant(primary);
+ cursor: pointer;
+}
+
+// Скрытие текста на мобильных
+@media (max-width: 420px) {
+ .badge-head .lbl,
+ .badge-gear .lbl {
+ display: none;
+ }
+}
+
+@media (max-width: 576px) {
+ .badge-head .lbl,
+ .badge-gear .lbl {
+ display: none;
+ }
+}
+
+// =============================================================================
+// ACCORDION (IOS-ACC)
+// =============================================================================
+
+.ios-acc {
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ border-radius: $ios-acc-border-radius;
+ background: var(--bs-body-bg);
+ overflow: hidden;
+
+ & + & {
+ margin-top: var(--space-2);
+ }
+
+ .ios-collapse-trigger {
+ border: 0;
+ border-radius: 0;
+ background: transparent;
+ width: 100%;
+ padding: var(--space-2);
+
+ &:focus {
+ box-shadow: none;
+ }
+
+ & + .collapse {
+ margin-top: 0 !important;
+ }
+ }
+
+ .collapse {
+ margin: 0 !important;
+ }
+
+ .ios-list {
+ border: 0;
+ border-radius: 0;
+ }
+
+ .chips {
+ margin: 0;
+ }
+
+ .ios-acc-body {
+ padding: var(--space-2);
+ border-top: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ }
+
+ .ios-collapse-trigger + .collapse {
+ margin-top: 0 !important;
+ }
+
+ .ios-acc-body {
+ border-top: 0;
+ }
+}
+
+// =============================================================================
+// ACTIVITY BLOCK
+// =============================================================================
+
+#activity {
+ .p-4 {
+ padding: 0 !important;
+ }
+
+ .ios-section-title {
+ padding: var(--space-2) var(--space-2) var(--space-1) !important;
+ margin: 0 !important;
+ }
+
+ .activity-feed {
+ margin: 0 !important;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+
+ .card {
+ width: 100% !important;
+ max-width: none !important;
+ border: 0 !important;
+ box-shadow: none !important;
+ border-radius: 0 !important;
+ margin: 0 !important;
+ }
+
+ .card-list {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ }
+
+ .row > * {
+ flex: 0 0 100% !important;
+ max-width: 100% !important;
+ }
+ }
+
+ .card-actions {
+ border-top: 0 !important;
+ }
+
+ .collapse .bg-body-tertiary.border {
+ border: 0 !important;
+ }
+}
+
+// =============================================================================
+// SKILLS UI
+// =============================================================================
+
+#skillsBlock[data-editable="1"] {
+ .chip.chip-add {
+ display: inline-flex;
+ align-items: center;
+ cursor: pointer;
+ border-style: dashed;
+
+ &.pulse {
+ transform: scale(0.97);
+ transition: transform 0.15s ease;
+ }
+
+ .bi {
+ font-size: 0.95rem;
+ }
+ }
+
+ .chip.chip-skill:hover {
+ .lbl {
+ opacity: 0;
+ }
+
+ .chip-del-btn,
+ &:focus-within .chip-del-btn {
+ visibility: visible;
+ opacity: 1;
+ }
+ }
+}
+
+.chip.chip-skill {
+ position: relative;
+ padding: 0.35rem 0.65rem;
+
+ .lbl {
+ transition: opacity 0.15s ease;
+ }
+
+ .chip-del-btn {
+ position: absolute;
+ inset: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: transparent;
+ border: 0;
+ padding: 0;
+ margin: 0;
+ cursor: pointer;
+ color: var(--bs-danger);
+ font-size: 1rem;
+ line-height: 1;
+ visibility: hidden;
+ opacity: 0;
+ transition: opacity 0.15s ease;
+ z-index: 1;
+
+ .bi {
+ pointer-events: none;
+ }
+ }
+}
+
+.skills-empty {
+ color: var(--bs-secondary-color);
+ font-size: 0.875rem;
+ margin-right: 0.25rem;
+}
+
+// =============================================================================
+// DEPT INLINE EDITOR
+// =============================================================================
+
+.dept-edit-btn {
+ width: 32px;
+ height: 32px;
+ padding: 0;
+ display: grid;
+ place-items: center;
+ border-radius: $badge-border-radius;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 30%);
+ background: color-mix(in srgb, var(--bs-body-bg) 94%, transparent);
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-body-bg) 88%, transparent);
+ }
+}
+
+.dept-editor-wrap {
+ flex: 0 0 100%;
+ width: 100%;
+ margin-top: 0.5rem;
+}
+
+.dept-editor form {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+}
+
+.dept-role-select {
+ min-width: 180px;
+}
+
+// =============================================================================
+// CONTAINER
+// =============================================================================
+
+.container-xxl {
+ max-width: $container-xxl-max-width;
+ padding-inline: var(--bs-gutter-x, var(--space-2));
+}
diff --git a/backend/static/scss_backup_20260115/components/_ios-search.scss b/backend/static/scss_backup_20260115/components/_ios-search.scss
new file mode 100644
index 00000000..8f095452
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_ios-search.scss
@@ -0,0 +1,251 @@
+// =============================================================================
+// iOS-style Search Component (SCSS)
+// =============================================================================
+// Поле поиска в стиле iOS с иконкой лупы и кнопкой очистки
+// Переиспользуемый компонент для различных страниц списков
+//
+// HTML структура:
+//
+//
+//
+//
+//
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+// Размеры (default)
+$ios-search-height: 40px;
+$ios-search-max-width: 420px;
+$ios-search-border-radius: 14px;
+$ios-search-font-size: 15px;
+
+// Размеры sm
+$ios-search-height-sm: 34px;
+$ios-search-border-radius-sm: 12px;
+$ios-search-font-size-sm: 14px;
+
+// Размеры lg
+$ios-search-height-lg: 48px;
+$ios-search-border-radius-lg: 16px;
+$ios-search-font-size-lg: 16px;
+
+// Размеры mobile
+$ios-search-height-mobile: 38px;
+$ios-search-font-size-mobile: 14px;
+
+// Отступы
+$ios-search-padding-left: 36px;
+$ios-search-padding-right: 36px;
+$ios-search-icon-left: 10px;
+$ios-search-clear-right: 4px;
+
+$ios-search-padding-left-sm: 32px;
+$ios-search-padding-right-sm: 32px;
+$ios-search-icon-left-sm: 8px;
+$ios-search-clear-right-sm: 3px;
+
+$ios-search-padding-left-lg: 42px;
+$ios-search-padding-right-lg: 42px;
+$ios-search-icon-left-lg: 12px;
+$ios-search-clear-right-lg: 6px;
+
+// Иконки
+$ios-search-icon-size: 0.95rem;
+$ios-search-icon-size-sm: 0.85rem;
+$ios-search-icon-size-lg: 1.1rem;
+$ios-search-clear-icon-size: 0.9rem;
+
+// Переходы
+$ios-search-transition: box-shadow 0.2s ease, border-color 0.2s ease, background 0.2s ease;
+$ios-search-btn-transition: background 0.2s ease;
+
+// =============================================================================
+// МИКСИНЫ
+// =============================================================================
+
+// Миксин для скрытия нативного крестика браузера
+@mixin hide-search-controls {
+ &::-webkit-search-cancel-button,
+ &::-webkit-search-decoration {
+ display: none;
+ -webkit-appearance: none;
+ }
+
+ &::-ms-clear {
+ display: none;
+ }
+}
+
+// =============================================================================
+// БАЗОВЫЕ СТИЛИ
+// =============================================================================
+
+// Контейнер поиска
+.ios-search {
+ position: relative;
+ width: 100%;
+ max-width: $ios-search-max-width;
+}
+
+// Поле ввода
+.ios-search-input {
+ width: 100%;
+ height: $ios-search-height;
+ padding: var(--space-1) $ios-search-padding-right var(--space-1) $ios-search-padding-left;
+ border-radius: $ios-search-border-radius;
+ border: 1px solid var(--bs-border-color);
+ background: color-mix(in srgb, var(--bs-body-bg), #000 4%);
+ font-size: $ios-search-font-size;
+ outline: none;
+ transition: $ios-search-transition;
+
+ // Скрываем нативный крестик браузера
+ @include hide-search-controls;
+
+ // Placeholder
+ &::placeholder {
+ color: var(--bs-secondary-color);
+ opacity: 0.6;
+ }
+
+ // Фокус
+ &:focus {
+ border-color: var(--bs-primary);
+ box-shadow: 0 0 0 3px rgba(var(--bs-primary-rgb), 0.15);
+ background: var(--bs-body-bg);
+ }
+
+ // Темная тема
+ [data-bs-theme="dark"] & {
+ background: color-mix(in srgb, var(--bs-body-bg), #fff 6%);
+ }
+}
+
+// =============================================================================
+// ИКОНКА ПОИСКА (ЛУПА)
+// =============================================================================
+
+.ios-search > .bi-search {
+ position: absolute;
+ left: $ios-search-icon-left;
+ top: 50%;
+ transform: translateY(-50%);
+ opacity: 0.55;
+ pointer-events: none;
+ font-size: $ios-search-icon-size;
+ color: var(--bs-body-color);
+}
+
+// =============================================================================
+// КНОПКА ОЧИСТКИ
+// =============================================================================
+
+.ios-search-clear {
+ position: absolute;
+ right: $ios-search-clear-right;
+ top: 50%;
+ transform: translateY(-50%);
+ border: 0;
+ background: transparent;
+ padding: var(--space-1);
+ display: none;
+ cursor: pointer;
+ border-radius: 50%;
+ transition: $ios-search-btn-transition;
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-body-color), transparent 90%);
+ }
+
+ &:active {
+ background: color-mix(in srgb, var(--bs-body-color), transparent 85%);
+ }
+
+ .bi-x-lg {
+ opacity: 0.6;
+ font-size: $ios-search-clear-icon-size;
+ color: var(--bs-body-color);
+ }
+}
+
+// Показываем кнопку очистки когда есть текст
+.ios-search-input:not(:placeholder-shown) ~ .ios-search-clear {
+ display: block;
+}
+
+// =============================================================================
+// ВАРИАЦИИ РАЗМЕРОВ
+// =============================================================================
+
+// Маленький размер
+.ios-search.sm {
+ .ios-search-input {
+ height: $ios-search-height-sm;
+ font-size: $ios-search-font-size-sm;
+ padding: var(--space-1) $ios-search-padding-right-sm var(--space-1) $ios-search-padding-left-sm;
+ border-radius: $ios-search-border-radius-sm;
+ }
+
+ > .bi-search {
+ left: $ios-search-icon-left-sm;
+ font-size: $ios-search-icon-size-sm;
+ }
+
+ .ios-search-clear {
+ right: $ios-search-clear-right-sm;
+ padding: var(--space-1);
+ }
+}
+
+// Большой размер
+.ios-search.lg {
+ .ios-search-input {
+ height: $ios-search-height-lg;
+ font-size: $ios-search-font-size-lg;
+ padding: var(--space-2) $ios-search-padding-right-lg var(--space-2) $ios-search-padding-left-lg;
+ border-radius: $ios-search-border-radius-lg;
+ }
+
+ > .bi-search {
+ left: $ios-search-icon-left-lg;
+ font-size: $ios-search-icon-size-lg;
+ }
+
+ .ios-search-clear {
+ right: $ios-search-clear-right-lg;
+ padding: var(--space-1);
+ }
+}
+
+// =============================================================================
+// ВАРИАЦИЯ: ТОЛЬКО ИКОНКА БЕЗ КНОПКИ ОЧИСТКИ
+// =============================================================================
+
+.ios-search.icon-only {
+ .ios-search-input {
+ padding-right: var(--space-3);
+ }
+
+ .ios-search-clear {
+ display: none !important;
+ }
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ
+// =============================================================================
+
+@media (max-width: 576px) {
+ .ios-search {
+ max-width: 100%;
+
+ .ios-search-input {
+ height: $ios-search-height-mobile;
+ font-size: $ios-search-font-size-mobile;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_join-scroller.scss b/backend/static/scss_backup_20260115/components/_join-scroller.scss
new file mode 100644
index 00000000..ef0c5f74
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_join-scroller.scss
@@ -0,0 +1,219 @@
+// =============================================================================
+// Join Scroller Component (SCSS)
+// =============================================================================
+// Горизонтальная прокручиваемая лента новых сотрудников с hover-эффектами
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$join-base-size: 56px; // базовый размер аватара
+$join-multiplier: 4; // множитель при раскрытии
+$join-multiplier-mobile: 3.2; // множитель на мобильных
+$join-gap: 0.9rem;
+$join-padding: 0.25rem;
+$join-transition-duration: 0.22s;
+
+// =============================================================================
+// КОНТЕЙНЕР
+// =============================================================================
+
+.join-wrap {
+ padding: var(--space-2);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+ border-radius: var(--feed-radius);
+ background: var(--bs-body-bg);
+ box-shadow: var(--feed-shadow);
+}
+
+// =============================================================================
+// ГОРИЗОНТАЛЬНАЯ ЛЕНТА
+// =============================================================================
+
+.join-scroller {
+ position: relative;
+ overflow-x: auto;
+ overflow-y: visible; // для инфо-блока
+ scrollbar-width: none; // Firefox
+ -ms-overflow-style: none; // IE/Edge
+
+ // Градиентная маска по краям
+ mask-image: linear-gradient(
+ to right,
+ transparent 0%,
+ black 40px,
+ black calc(100% - 40px),
+ transparent 100%
+ );
+ -webkit-mask-image: linear-gradient(
+ to right,
+ transparent 0%,
+ black 40px,
+ black calc(100% - 40px),
+ transparent 100%
+ );
+
+ &::-webkit-scrollbar {
+ display: none; // Chrome/Safari
+ }
+}
+
+.join-rail {
+ display: flex;
+ flex-wrap: nowrap;
+ align-items: flex-start;
+ justify-content: center;
+ gap: $join-gap;
+ padding: $join-padding;
+ min-width: 100%;
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .join-scroller {
+ scroll-behavior: auto !important;
+ }
+}
+
+// =============================================================================
+// ЭЛЕМЕНТ ЛЕНТЫ
+// =============================================================================
+
+.join-item {
+ --base: #{$join-base-size};
+ --mult: #{$join-multiplier};
+ --size: var(--base);
+
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: var(--size);
+ flex: 0 0 var(--size);
+ transition: width $join-transition-duration ease, flex-basis $join-transition-duration ease;
+
+ &:hover,
+ &:focus-within {
+ --size: calc(var(--base) * var(--mult));
+ z-index: 2;
+ }
+
+ // Отключение hover при перетаскивании
+ &.no-hover {
+ &:hover,
+ &:focus-within {
+ --size: var(--base);
+ z-index: auto;
+ }
+
+ .join-info {
+ max-height: 0;
+ opacity: 0;
+ transform: translateY(-4px);
+ }
+ }
+}
+
+// =============================================================================
+// АВАТАР
+// =============================================================================
+
+.join-ava {
+ width: var(--size);
+ height: var(--size);
+ border-radius: 999px;
+ overflow: hidden;
+ display: grid;
+ place-items: center;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ background: var(--bs-tertiary-bg);
+ transition: width $join-transition-duration ease,
+ height $join-transition-duration ease,
+ box-shadow $join-transition-duration ease,
+ border-color $join-transition-duration ease;
+ will-change: width, height;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ background: var(--bs-tertiary-bg);
+ }
+
+ .bi {
+ font-size: 1.2rem;
+ opacity: 0.65;
+ }
+
+ .join-item:hover &,
+ .join-item:focus-within & {
+ box-shadow: var(--feed-shadow-hover);
+ border-color: color-mix(in srgb, var(--bs-border-color), var(--bs-primary) 30%);
+ }
+}
+
+// =============================================================================
+// ИНФО-БЛОК
+// =============================================================================
+
+.join-info {
+ width: 100%;
+ overflow: hidden;
+ max-height: 0;
+ opacity: 0;
+ transform: translateY(-4px);
+ transition: max-height 0.24s ease, opacity 0.18s ease, transform 0.18s ease;
+
+ .join-item:hover &,
+ .join-item:focus-within & {
+ max-height: 320px; // с запасом для навыков
+ opacity: 1;
+ transform: translateY(0);
+ }
+
+ .name {
+ font-weight: 800;
+ line-height: 1.2;
+ margin-top: 0.5rem;
+ text-align: center;
+ }
+
+ .sub {
+ font-size: 0.9rem;
+ color: var(--bs-secondary-color);
+ text-align: center;
+ }
+
+ .skills-line {
+ font-size: 0.9rem;
+ text-align: center;
+ margin-top: 0.35rem;
+ word-break: break-word;
+ white-space: normal;
+
+ b {
+ font-weight: 800;
+ }
+ }
+
+ .link {
+ display: inline-block;
+ margin-top: 0.35rem;
+ font-size: 0.9rem;
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+ }
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ
+// =============================================================================
+
+@media (max-width: 480px) {
+ .join-item {
+ --mult: #{$join-multiplier-mobile};
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_layout-spacing.scss b/backend/static/scss_backup_20260115/components/_layout-spacing.scss
new file mode 100644
index 00000000..47b9c716
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_layout-spacing.scss
@@ -0,0 +1,42 @@
+/**
+ * layout-spacing.scss
+ *
+ * Централизованное управление отступами в app-layout
+ * Все отступы контролируются через CSS переменные в variables.css
+ *
+ * ПРИНЦИП: Контейнеры занимают 100% пространства ячейки (без padding).
+ * Все отступы между колонками управляются ТОЛЬКО через grid gap.
+ *
+ * Переменные для настройки (в variables.css):
+ * --layout-gap: расстояние между sidebar, main, rightbar (по умолчанию 16px)
+ * --layout-padding-y: вертикальные отступы layout (по умолчанию 24px)
+ * --layout-padding-x: горизонтальные отступы layout (по умолчанию 0)
+ *
+ * Примеры изменения отступов:
+ *
+ * Увеличить расстояние между колонками до 24px:
+ * :root { --layout-gap: var(--space-3); }
+ *
+ * Уменьшить расстояние между колонками до 8px:
+ * :root { --layout-gap: var(--space-1); }
+ *
+ * Уменьшить вертикальные отступы до 16px:
+ * :root { --layout-padding-y: var(--space-2); }
+ *
+ * Убрать вертикальные отступы:
+ * :root { --layout-padding-y: 0; }
+ */
+
+/* =====================================
+ APP LAYOUT SPACING
+===================================== */
+
+// Применяем вертикальные отступы к layout
+.app-layout {
+ padding-top: var(--layout-padding-y);
+ padding-bottom: var(--layout-padding-y);
+}
+
+// Горизонтальные отступы управляются через container-xxl px-2 px-lg-3 в base.html
+// Grid gap между колонками управляется через --layout-gap в base-app.scss
+// Колонки (sidebar, main, rightbar) НЕ имеют собственных padding - занимают 100% ячейки
diff --git a/backend/static/scss_backup_20260115/components/_list-view.scss b/backend/static/scss_backup_20260115/components/_list-view.scss
new file mode 100644
index 00000000..fa44d79f
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_list-view.scss
@@ -0,0 +1,148 @@
+// =============================================================================
+// List View Component (SCSS)
+// =============================================================================
+// Универсальные стили для списочных представлений (сотрудники, отделы)
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$list-row-py: var(--space-1); // 8px вертикальные отступы
+$list-row-px: var(--space-2); // 16px горизонтальные отступы
+$list-gap: var(--space-2); // 16px расстояние внутри строки
+$list-avatar-size: 56px; // размер аватара
+
+// =============================================================================
+// ТОКЕНЫ
+// =============================================================================
+
+.list-view {
+ --list-row-py: #{$list-row-py};
+ --list-row-px: #{$list-row-px};
+ --list-gap: #{$list-gap};
+ --list-avatar: #{$list-avatar-size};
+}
+
+// =============================================================================
+// КОНТЕЙНЕР СПИСКОВ
+// =============================================================================
+
+.list-view {
+ background: transparent;
+ padding: 0;
+
+ // Убираем gap от card-list
+ &.card-list {
+ display: block;
+ gap: 0 !important;
+ }
+}
+
+// =============================================================================
+// СТРОКИ СПИСКОВ
+// =============================================================================
+
+.list-view .list-row {
+ padding: var(--list-row-py) var(--list-row-px) !important;
+ margin: 0 !important;
+ border-bottom: 1px solid var(--bs-border-color);
+
+ &:last-of-type {
+ border-bottom: 0;
+ }
+}
+
+// =============================================================================
+// ШАПКА СТРОКИ
+// =============================================================================
+
+.list-view .list-row .card-header {
+ display: flex;
+ align-items: center;
+ gap: var(--list-gap);
+ min-height: var(--list-avatar);
+ margin: 0;
+ padding: 0 !important;
+}
+
+// Шапка с аватаром: grid layout
+.list-view .list-row:has(.card-icon) .card-header {
+ display: grid;
+ grid-template-columns: var(--list-avatar) 1fr auto;
+}
+
+// =============================================================================
+// АВАТАР
+// =============================================================================
+
+.list-view .list-row .card-icon {
+ width: var(--list-avatar);
+ height: var(--list-avatar);
+ border-radius: 50%;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: color-mix(in srgb, var(--bs-secondary-bg), transparent 30%);
+ flex: none;
+
+ img {
+ display: block;
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ object-position: center;
+ }
+
+ i {
+ font-size: 1.5rem;
+ line-height: 1;
+ opacity: 0.6;
+ }
+}
+
+// =============================================================================
+// КОНТЕНТ
+// =============================================================================
+
+.list-view .list-row .card-meta {
+ margin: 0;
+ padding: 0;
+ min-width: 0;
+}
+
+.list-view .card-title {
+ line-height: 1.25;
+}
+
+.emp-pos {
+ color: var(--bs-secondary-color);
+}
+
+.list-view .card-subtitle {
+ margin-top: var(--space-1);
+}
+
+// =============================================================================
+// ДЕЙСТВИЯ СПРАВА
+// =============================================================================
+
+.emp-actions {
+ justify-self: end;
+}
+
+// =============================================================================
+// УБИРАЕМ НЕНУЖНЫЕ ОТСТУПЫ
+// =============================================================================
+
+.list-view .list-row .card-actions {
+ padding: 0 !important;
+}
+
+.list-view .list-row .card-body {
+ padding: 0 !important;
+
+ &:empty {
+ display: none !important;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_logout-modal.scss b/backend/static/scss_backup_20260115/components/_logout-modal.scss
new file mode 100644
index 00000000..e55e59a2
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_logout-modal.scss
@@ -0,0 +1,182 @@
+// =============================================================================
+// Logout Modal (iOS-style) (SCSS)
+// =============================================================================
+// iOS-style модальное окно выхода с анимациями
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$ios-avatar-size: 64px;
+$ios-icon-size: 56px;
+$ios-btn-min-height: 48px;
+$ios-border-radius: 16px;
+$ios-border-radius-desktop: 18px;
+$ios-grip-width: 36px;
+$ios-grip-height: 4px;
+
+// =============================================================================
+// OVERLAY
+// =============================================================================
+
+.ios-overlay {
+ position: fixed;
+ inset: 0;
+ z-index: 1080;
+ background: color-mix(in srgb, var(--bs-body-bg), #000 35%);
+ backdrop-filter: blur(10px) saturate(110%);
+ display: grid;
+ place-items: end center; // bottom sheet по умолчанию
+
+ @media (min-width: 992px) {
+ place-items: center; // центрируем на десктопе
+ }
+}
+
+// =============================================================================
+// SHEET / CARD
+// =============================================================================
+
+.ios-sheet {
+ width: 100%;
+ max-width: 560px;
+ background: color-mix(in srgb, var(--bs-body-bg), #fff 6%);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 30%);
+ border-radius: $ios-border-radius $ios-border-radius 0 0;
+ box-shadow: 0 12px 48px rgba(0, 0, 0, 0.28);
+ animation: slideUp 0.28s ease both;
+
+ @media (min-width: 992px) {
+ border-radius: $ios-border-radius-desktop;
+ animation: popIn 0.18s ease both;
+ }
+}
+
+// Грип-бар как в iOS
+.ios-grip {
+ width: $ios-grip-width;
+ height: $ios-grip-height;
+ border-radius: 999px;
+ background: color-mix(in srgb, var(--bs-body-color), transparent 70%);
+ margin: var(--space-1) auto;
+}
+
+// =============================================================================
+// CONTENT
+// =============================================================================
+
+.ios-body {
+ padding: var(--space-2) var(--space-3) var(--space-3);
+
+ @media (min-width: 992px) {
+ padding: var(--space-3);
+ }
+}
+
+.ios-title {
+ margin: 0.25rem 0;
+ text-align: center;
+ font-weight: 800;
+ letter-spacing: 0.2px;
+}
+
+.ios-sub {
+ text-align: center;
+ color: var(--bs-secondary-color);
+ margin: 0 0 1rem;
+}
+
+// =============================================================================
+// AVATAR & ICON
+// =============================================================================
+
+.ios-ava {
+ width: $ios-avatar-size;
+ height: $ios-avatar-size;
+ border-radius: 999px;
+ overflow: hidden;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ background: var(--bs-tertiary-bg);
+ display: grid;
+ place-items: center;
+ margin: 0.25rem auto 0.75rem;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ }
+}
+
+.ios-ico {
+ width: $ios-icon-size;
+ height: $ios-icon-size;
+ border-radius: 14px;
+ background: color-mix(in srgb, var(--bs-danger), #000 12%);
+ color: #fff;
+ display: grid;
+ place-items: center;
+ margin: 0.25rem auto 0.75rem;
+}
+
+// =============================================================================
+// BUTTONS
+// =============================================================================
+
+.ios-actions {
+ display: grid;
+ gap: 0.6rem;
+}
+
+.ios-btn {
+ min-height: $ios-btn-min-height;
+ border-radius: 12px;
+ font-weight: 700;
+
+ &-danger {
+ background: var(--bs-danger);
+ border-color: var(--bs-danger);
+ color: #fff;
+
+ &:hover {
+ filter: brightness(1.02);
+ }
+ }
+
+ &-ghost {
+ background: color-mix(in srgb, var(--bs-body-bg), #fff 6%);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 20%);
+ color: var(--bs-body-color);
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-body-bg), #fff 9%);
+ }
+ }
+}
+
+// =============================================================================
+// ANIMATIONS
+// =============================================================================
+
+@keyframes slideUp {
+ from {
+ transform: translateY(16px);
+ opacity: 0;
+ }
+ to {
+ transform: translateY(0);
+ opacity: 1;
+ }
+}
+
+@keyframes popIn {
+ from {
+ transform: scale(0.98);
+ opacity: 0;
+ }
+ to {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_modal-overrides.scss b/backend/static/scss_backup_20260115/components/_modal-overrides.scss
new file mode 100644
index 00000000..2d8557ce
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_modal-overrides.scss
@@ -0,0 +1,29 @@
+// =============================================================================
+// Modal Overrides (SCSS)
+// =============================================================================
+// Z-index corrections для модальных окон
+
+// =============================================================================
+// MODAL Z-INDEX
+// =============================================================================
+
+.modal {
+ z-index: 1080 !important;
+
+ &.show {
+ z-index: 1080 !important;
+ }
+
+ // Не даём просвечивать через backdrop
+ .modal-content {
+ background-color: var(--bs-body-bg);
+ }
+}
+
+.modal-backdrop {
+ z-index: 1075 !important;
+
+ &.show {
+ z-index: 1075 !important;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_modals.scss b/backend/static/scss_backup_20260115/components/_modals.scss
new file mode 100644
index 00000000..335f0134
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_modals.scss
@@ -0,0 +1,40 @@
+// =============================================================================
+// Стили для модальных окон
+// =============================================================================
+
+// Скругление углов для всех модальных окон
+.modal-content {
+ border-radius: 1rem !important; // Соответствует карточкам Bootstrap (16px)
+}
+
+// Убираем скроллбар у modal-content
+.modal-dialog {
+ .modal-content {
+ overflow: hidden; // Скрываем скроллбар
+ }
+}
+
+// Специальные стили для модального окна поста
+#postDetailModal {
+ .modal-dialog {
+ max-width: 800px !important;
+ width: 100%;
+ margin: 1.75rem auto;
+ }
+
+ .modal-body {
+ max-height: 85vh;
+ overflow-y: auto;
+ padding: 0;
+ background: var(--bs-body-bg) !important; // Непрозрачный фон
+
+ // Скрываем скроллбар
+ scrollbar-width: none; // Firefox
+ -ms-overflow-style: none; // IE и Edge
+
+ // Chrome, Safari, Edge
+ &::-webkit-scrollbar {
+ display: none;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_navbar.scss b/backend/static/scss_backup_20260115/components/_navbar.scss
new file mode 100644
index 00000000..e6c582ed
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_navbar.scss
@@ -0,0 +1,262 @@
+/**
+ * navbar.scss
+ * Стили навбара: меню-тогглер, поиск, уведомления
+ */
+
+/* =====================================
+ NAVBAR BASE
+===================================== */
+
+// Navbar overflow visible для dropdown
+.app-navbar {
+ overflow: visible !important;
+
+ .container-fluid {
+ overflow: visible !important;
+ }
+}
+
+/* =====================================
+ MOBILE NAVBAR HEIGHT
+===================================== */
+
+// Увеличенная высота navbar для мобильных устройств
+@media (max-width: 767.98px) {
+ .app-navbar {
+ min-height: 90px;
+
+ .container-fluid {
+ min-height: 64px;
+ padding-top: 0.75rem;
+ padding-bottom: 0.75rem;
+ }
+ }
+}
+
+/* =====================================
+ MENU TOGGLE (гамбургер)
+===================================== */
+
+// Кнопка «гамбургера» — без круга/рамки
+.menu-toggle {
+ padding: 0;
+ border: 0;
+ background: transparent;
+ line-height: 1;
+ color: #fff;
+
+ &:focus {
+ outline: none;
+ box-shadow: none;
+ }
+}
+
+/* =====================================
+ DROPDOWN AVATAR
+===================================== */
+
+// Спрятать стрелочку у dropdown-аватара
+.dropdown-toggle.no-caret::after {
+ display: none !important;
+}
+
+/* =====================================
+ MOBILE SEARCH OVERLAY
+===================================== */
+
+.mobile-search-overlay {
+ position: fixed;
+ top: var(--navbar-h);
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 1030;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.3s ease;
+
+ &.active {
+ opacity: 1;
+ pointer-events: auto;
+ }
+}
+
+// Светлая тема - забеливание
+[data-bs-theme="light"] .mobile-search-overlay {
+ background-color: rgba(255, 255, 255, 0.85);
+}
+
+// Темная тема - затемнение
+[data-bs-theme="dark"] .mobile-search-overlay {
+ background-color: rgba(0, 0, 0, 0.7);
+}
+
+/* =====================================
+ BOTTOM NAVBAR (только для мобильных)
+===================================== */
+
+.bottom-navbar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: var(--bs-primary);
+ border-top: 0.5px solid var(--bs-border-color);
+ z-index: 1040;
+ padding: 0;
+ box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.08);
+ backdrop-filter: blur(10px);
+ -webkit-backdrop-filter: blur(10px);
+}
+
+// Темная тема
+[data-bs-theme="dark"] .bottom-navbar {
+ background-color: var(--bs-tertiary-bg);
+ border-top-color: var(--bs-border-color);
+ box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.3);
+}
+
+.bottom-navbar-container {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ height: 60px;
+ padding: 0 8px;
+ max-width: 100%;
+}
+
+.bottom-nav-item {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ flex: 1;
+ height: 100%;
+ color: rgba(255, 255, 255, 0.7);
+ text-decoration: none;
+ border: none;
+ background: transparent;
+ padding: 4px 8px;
+ transition: all 0.2s ease;
+ position: relative;
+ cursor: pointer;
+
+ &:hover,
+ &:focus,
+ &:active {
+ color: #fff;
+ background: rgba(255, 255, 255, 0.1);
+ outline: none;
+ }
+
+ i {
+ font-size: 1.4rem;
+ margin-bottom: 2px;
+ line-height: 1;
+ }
+}
+
+// Темная тема - другой цвет кнопок
+[data-bs-theme="dark"] .bottom-nav-item {
+ color: var(--bs-secondary-color);
+
+ &:hover,
+ &:focus,
+ &:active {
+ color: var(--bs-emphasis-color);
+ background: var(--bs-secondary-bg);
+ }
+}
+
+.bottom-nav-label {
+ font-size: 0.65rem;
+ font-weight: 500;
+ text-align: center;
+ line-height: 1;
+ margin-top: 2px;
+}
+
+/* =====================================
+ BOTTOM NAV BADGE
+===================================== */
+
+// Иконка с бейджем для уведомлений
+.bottom-nav-icon-wrapper {
+ position: relative;
+ display: inline-block;
+}
+
+.bottom-nav-badge {
+ position: absolute;
+ top: -6px;
+ right: -10px;
+ background: var(--bs-danger);
+ color: #fff;
+ border-radius: 10px; // Telegram использует фиксированный radius для круглых бэйджей
+ padding: 0 6px;
+ font-size: 11px;
+ font-weight: 600;
+ min-width: 20px;
+ height: 20px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ line-height: 1;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); // Более заметная тень
+ transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275),
+ background-color 0.2s ease;
+ z-index: 10;
+
+ // Мигание при новом сообщении
+ &.pulse {
+ animation: badge-pulse 0.6s ease-out;
+ }
+
+ // Серый для замьюченных чатов
+ &.badge-muted {
+ background: var(--bs-secondary);
+ }
+
+ &:empty {
+ display: none;
+ }
+}
+
+@keyframes badge-pulse {
+ 0% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.15);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+/* =====================================
+ MOBILE LAYOUT
+===================================== */
+
+// Padding для body, чтобы контент не перекрывался нижней панелью
+@media (max-width: 767.98px) {
+ body {
+ padding-bottom: 60px;
+ }
+
+ // Скрыть bottom navbar на странице чата - композер заменяет навигацию
+ .chat-container ~ .bottom-navbar,
+ .chat-page ~ .bottom-navbar,
+ body:has(.chat-container) .bottom-navbar,
+ body:has(.chat-page) .bottom-navbar {
+ display: none;
+ }
+
+ // Убрать padding, когда navbar скрыт
+ body:has(.chat-container),
+ body:has(.chat-page) {
+ padding-bottom: 0;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_notifications.scss b/backend/static/scss_backup_20260115/components/_notifications.scss
new file mode 100644
index 00000000..ce708738
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_notifications.scss
@@ -0,0 +1,471 @@
+// =============================================================================
+// Notifications System Styles (SCSS)
+// =============================================================================
+// Стили для системы уведомлений: колокольчик, dropdown, toast, страница списка
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+// Колокольчик
+$bell-dot-size: 16px;
+$bell-dot-font-size: 9px;
+$bell-dot-offset-top: -4px;
+$bell-dot-offset-right: -6px;
+
+// Dropdown
+$notification-dropdown-width: 360px;
+$notification-dropdown-max-height: 500px;
+$notification-dropdown-border-radius: 12px;
+$notification-dropdown-body-max-height: 300px;
+
+// Элементы уведомлений
+$notification-item-padding: 12px 16px;
+$notification-icon-size: 36px;
+$notification-unread-badge-size: 8px;
+
+// Цвета
+$notification-danger: #dc3545;
+$notification-primary: #0d6efd;
+$notification-unread-bg-light: #f0f7ff;
+$notification-unread-bg-dark: #1a3a52;
+
+// Переходы
+$notification-transition: background-color 0.2s;
+
+// =============================================================================
+// КОЛОКОЛЬЧИК В NAVBAR
+// =============================================================================
+
+.bell-wrapper {
+ position: relative;
+ display: inline-block;
+}
+
+.bell-dot {
+ position: absolute;
+ top: $bell-dot-offset-top;
+ right: $bell-dot-offset-right;
+ min-width: $bell-dot-size;
+ height: $bell-dot-size;
+ padding: 0 4px;
+ background-color: $notification-danger;
+ color: white;
+ border-radius: calc($bell-dot-size / 2);
+ font-size: $bell-dot-font-size;
+ font-weight: 700;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1;
+ box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3);
+}
+
+// =============================================================================
+// DROPDOWN МЕНЮ УВЕДОМЛЕНИЙ
+// =============================================================================
+
+.notification-dropdown-menu {
+ position: fixed;
+ width: $notification-dropdown-width;
+ max-height: $notification-dropdown-max-height;
+ background: white;
+ border-radius: $notification-dropdown-border-radius;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
+ z-index: 10000;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+
+ [data-bs-theme="dark"] & {
+ background: #2b3035;
+ color: #dee2e6;
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
+ }
+}
+
+// Заголовок
+.notification-dropdown-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12px 16px;
+ border-bottom: 1px solid #e9ecef;
+ background: #f8f9fa;
+
+ [data-bs-theme="dark"] & {
+ background: #1f2327;
+ border-bottom-color: #3d4349;
+ }
+}
+
+// Тело с прокруткой
+.notification-dropdown-body {
+ flex: 1;
+ overflow-y: auto;
+ max-height: $notification-dropdown-body-max-height;
+ scroll-behavior: smooth;
+ -webkit-overflow-scrolling: touch;
+ scrollbar-width: thin;
+ scrollbar-gutter: stable both-edges;
+ overscroll-behavior: contain;
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 70%) transparent;
+
+ &:hover {
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 55%) transparent;
+ }
+
+ // Webkit scrollbar
+ &::-webkit-scrollbar {
+ width: 10px;
+ height: 10px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ margin-block: 0;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 75%);
+ border-radius: 999px;
+ border: 3px solid transparent;
+ background-clip: padding-box;
+ }
+
+ &:hover::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 55%);
+ }
+
+ // Темная тема scrollbar
+ [data-bs-theme="dark"] & {
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 78%) transparent;
+
+ &:hover {
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 60%) transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 78%);
+ }
+
+ &:hover::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 60%);
+ }
+ }
+
+ // Скрытие scrollbar на тач-устройствах
+ @media (hover: none), (pointer: coarse) {
+ scrollbar-width: none;
+
+ &::-webkit-scrollbar {
+ display: none;
+ }
+ }
+}
+
+// Разделитель
+.notification-dropdown-divider {
+ height: 1px;
+ background: #e9ecef;
+ margin: 0;
+
+ [data-bs-theme="dark"] & {
+ background: #3d4349;
+ }
+}
+
+// Секция
+.notification-dropdown-section {
+ padding: 8px 0;
+}
+
+// =============================================================================
+// ЭЛЕМЕНТЫ СПИСКА УВЕДОМЛЕНИЙ
+// =============================================================================
+
+.notification-item {
+ display: flex;
+ gap: 12px;
+ padding: $notification-item-padding;
+ cursor: pointer;
+ transition: $notification-transition;
+ position: relative;
+ border-bottom: 1px solid #e9ecef;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ &:hover {
+ background-color: #f8f9fa;
+ }
+
+ &.unread {
+ background-color: $notification-unread-bg-light;
+
+ &:hover {
+ background-color: #e6f2ff;
+ }
+ }
+
+ // Темная тема
+ [data-bs-theme="dark"] & {
+ border-bottom-color: #3d4349;
+
+ &:hover {
+ background-color: #343a40;
+ }
+
+ &.unread {
+ background-color: $notification-unread-bg-dark;
+
+ &:hover {
+ background-color: #1e4260;
+ }
+ }
+ }
+}
+
+// Иконка уведомления
+.notification-icon {
+ flex-shrink: 0;
+ width: $notification-icon-size;
+ height: $notification-icon-size;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 20px;
+}
+
+// Контент уведомления
+.notification-content {
+ flex: 1;
+ min-width: 0;
+}
+
+.notification-title {
+ font-weight: 600;
+ font-size: 14px;
+ margin-bottom: 4px;
+ color: #212529;
+
+ [data-bs-theme="dark"] & {
+ color: #dee2e6;
+ }
+}
+
+.notification-message {
+ font-size: 13px;
+ color: #6c757d;
+ margin-bottom: 4px;
+
+ [data-bs-theme="dark"] & {
+ color: #adb5bd;
+ }
+}
+
+.notification-time {
+ font-size: 11px;
+ color: #adb5bd;
+
+ [data-bs-theme="dark"] & {
+ color: #6c757d;
+ }
+}
+
+// Значок непрочитанного
+.notification-unread-badge {
+ flex-shrink: 0;
+ width: $notification-unread-badge-size;
+ height: $notification-unread-badge-size;
+ background-color: $notification-primary;
+ border-radius: 50%;
+ margin-left: 8px;
+ align-self: center;
+}
+
+// =============================================================================
+// ПУСТОЕ СОСТОЯНИЕ
+// =============================================================================
+
+.notification-empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 48px 24px;
+ color: #adb5bd;
+ text-align: center;
+
+ i {
+ font-size: 48px;
+ margin-bottom: 12px;
+ }
+
+ div {
+ font-size: 14px;
+ }
+
+ [data-bs-theme="dark"] & {
+ color: #6c757d;
+ }
+}
+
+.extra-small {
+ font-size: 0.7rem;
+}
+
+// =============================================================================
+// TOAST УВЕДОМЛЕНИЯ (FALLBACK)
+// =============================================================================
+
+.toast-container {
+ z-index: 9999;
+}
+
+.toast {
+ min-width: 300px;
+}
+
+// =============================================================================
+// СТРАНИЦА СПИСКА УВЕДОМЛЕНИЙ
+// =============================================================================
+
+// Карточки уведомлений - прочитанные
+.notification-read {
+ opacity: 0.7;
+
+ .card {
+ background-color: #f8f9fa;
+ }
+
+ [data-bs-theme="dark"] & {
+ opacity: 0.65;
+
+ .card {
+ background-color: #1f2327 !important;
+ border-color: #3d4349 !important;
+ }
+ }
+}
+
+// Карточки уведомлений - непрочитанные
+.notification-unread {
+ border-left: 4px solid var(--bs-primary);
+
+ .card {
+ background-color: #ffffff;
+ }
+
+ [data-bs-theme="dark"] .card {
+ background-color: #2b3035;
+ border-color: #3d4349;
+ }
+}
+
+// Иконки категорий (для страницы списка)
+.notification-icon {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.5rem;
+}
+
+// =============================================================================
+// ТЕМНАЯ ТЕМА ДЛЯ СТРАНИЦЫ СПИСКА
+// =============================================================================
+
+[data-bs-theme="dark"] {
+ .card {
+ background-color: #2b3035;
+ border-color: #3d4349;
+ color: #dee2e6;
+ }
+
+ .card-body {
+ color: #dee2e6;
+ }
+
+ .text-muted {
+ color: #adb5bd !important;
+ }
+
+ // Кнопки
+ .btn-outline-primary {
+ color: #6ea8fe;
+ border-color: #6ea8fe;
+
+ &:hover {
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+ color: #fff;
+ }
+ }
+
+ .btn-outline-secondary {
+ color: #adb5bd;
+ border-color: #6c757d;
+
+ &:hover {
+ background-color: #6c757d;
+ border-color: #6c757d;
+ color: #fff;
+ }
+ }
+
+ .btn-outline-danger {
+ color: #ea868f;
+ border-color: #ea868f;
+
+ &:hover {
+ background-color: #dc3545;
+ border-color: #dc3545;
+ color: #fff;
+ }
+ }
+
+ // Формы
+ .form-select,
+ .form-control {
+ background-color: #1f2327;
+ border-color: #3d4349;
+ color: #dee2e6;
+
+ &:focus {
+ background-color: #2b3035;
+ border-color: #6ea8fe;
+ color: #dee2e6;
+ }
+ }
+
+ // Пагинация
+ .pagination {
+ .page-link {
+ background-color: #2b3035;
+ border-color: #3d4349;
+ color: #6ea8fe;
+
+ &:hover {
+ background-color: #343a40;
+ border-color: #3d4349;
+ color: #9ec5fe;
+ }
+ }
+
+ .page-item.active .page-link {
+ background-color: #0d6efd;
+ border-color: #0d6efd;
+ color: #fff;
+ }
+
+ .page-item.disabled .page-link {
+ background-color: #1f2327;
+ border-color: #3d4349;
+ color: #6c757d;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_page-header.scss b/backend/static/scss_backup_20260115/components/_page-header.scss
new file mode 100644
index 00000000..467d08cc
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_page-header.scss
@@ -0,0 +1,477 @@
+/**
+ * _page-header.scss
+ * Универсальная шапка для страниц списков с:
+ * - Полупрозрачным фоном (sticky positioning)
+ * - Иконкой и заголовком
+ * - Счётчиком элементов
+ * - Переключателем области (Мои/Все)
+ * - Кнопкой фильтров
+ * - Кнопкой создания (вытянутая на десктопе, иконка на мобильных)
+ * - Поиском iOS-стиль
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ ОСНОВНОЙ КОНТЕЙНЕР ШАПКИ
+────────────────────────────────────────────────────────────── */
+.page-header {
+ position: sticky;
+ top: var(--navbar-h, 60px);
+ z-index: 10;
+ padding: var(--space-2) 0;
+ margin-bottom: var(--space-3);
+
+ /* Полупрозрачный фон с градиентом */
+ background: linear-gradient(
+ to bottom,
+ color-mix(in srgb, var(--bs-body-bg) 90%, transparent) 0%,
+ color-mix(in srgb, var(--bs-body-bg) 85%, transparent) 30%,
+ color-mix(in srgb, var(--bs-body-bg) 70%, transparent) 50%,
+ color-mix(in srgb, var(--bs-body-bg) 40%, transparent) 70%,
+ transparent 100%
+ );
+
+ @include transition((background, box-shadow), $transition-fast);
+
+ &::before {
+ content: '';
+ @include absolute-cover();
+ backdrop-filter: saturate(180%) $blur-lg;
+ -webkit-backdrop-filter: saturate(180%) $blur-lg;
+ mask-image: linear-gradient(
+ to bottom,
+ black 0%,
+ black 30%,
+ rgba(0, 0, 0, 0.7) 50%,
+ rgba(0, 0, 0, 0.4) 70%,
+ transparent 100%
+ );
+ -webkit-mask-image: linear-gradient(
+ to bottom,
+ black 0%,
+ black 30%,
+ rgba(0, 0, 0, 0.7) 50%,
+ rgba(0, 0, 0, 0.4) 70%,
+ transparent 100%
+ );
+ pointer-events: none;
+ z-index: -1;
+ }
+
+ > * {
+ position: relative;
+ z-index: $z-base;
+ }
+
+ /* При скролле - более выраженный фон */
+ &.scrolled {
+ background: linear-gradient(
+ to bottom,
+ color-mix(in srgb, var(--bs-body-bg) 95%, transparent) 0%,
+ color-mix(in srgb, var(--bs-body-bg) 90%, transparent) 30%,
+ color-mix(in srgb, var(--bs-body-bg) 75%, transparent) 50%,
+ color-mix(in srgb, var(--bs-body-bg) 45%, transparent) 70%,
+ transparent 100%
+ );
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
+ }
+
+ /* Кнопка создания в виде карточки */
+ .card {
+ margin-top: var(--space-2);
+ width: 100%;
+
+ button.dept-row,
+ a.dept-row {
+ cursor: pointer;
+ transition: background-color 0.2s ease;
+ width: 100%;
+ padding: var(--space-1) var(--space-2);
+ text-align: center;
+
+ .card-title {
+ font-weight: 700;
+ color: var(--bs-body-color);
+ }
+
+ i {
+ color: var(--bs-primary);
+ }
+
+ &:hover {
+ background-color: var(--bs-light);
+ }
+ }
+ }
+
+ /* Адаптивность */
+ .d-flex.align-items-center {
+ flex-wrap: wrap;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT AVATAR WITH TYPE BADGE
+────────────────────────────────────────────────────────────── */
+.chat-avatar-wrapper {
+ position: relative;
+ width: 48px;
+ height: 48px;
+ flex-shrink: 0;
+}
+
+.chat-avatar {
+ width: 100%;
+ height: 100%;
+ border-radius: 12px;
+ object-fit: cover;
+ display: block;
+ border: 1px solid var(--bs-border-color);
+}
+
+.chat-type-badge {
+ position: absolute;
+ bottom: -2px;
+ right: -2px;
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ background: var(--bs-primary);
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 10px;
+ border: 2px solid var(--bs-body-bg);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+
+ i {
+ line-height: 1;
+ }
+
+ [data-bs-theme="dark"] & {
+ border-color: var(--bs-body-bg);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ TOP BAR (заголовок + действия)
+────────────────────────────────────────────────────────────── */
+.page-header-top {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--space-2);
+ width: 100%;
+}
+
+.page-header-title {
+ display: flex;
+ align-items: center;
+ gap: var(--space-2);
+ flex: 1;
+ min-width: 0;
+
+ h1 {
+ font-size: 1.5rem;
+ font-weight: 700;
+ margin: 0;
+ color: var(--bs-body-color);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ i {
+ font-size: 1.75rem;
+ flex-shrink: 0;
+ }
+}
+
+.page-header-actions {
+ display: flex;
+ align-items: center;
+ gap: var(--space-1);
+ flex-shrink: 0;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ЗАГОЛОВОК И СЧЁТЧИК
+────────────────────────────────────────────────────────────── */
+.page-title {
+ font-weight: 800;
+ font-size: 1.75rem;
+ letter-spacing: -0.01em;
+ line-height: 1.2;
+ color: var(--bs-body-color);
+ flex-shrink: 0;
+}
+
+.page-count {
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+ white-space: nowrap;
+ flex-shrink: 0;
+
+ .count-value {
+ font-weight: 600;
+ color: var(--bs-body-color);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ПЕРЕКЛЮЧАТЕЛЬ ОБЛАСТИ (МОИ/ВСЕ)
+────────────────────────────────────────────────────────────── */
+.page-scope-switch {
+ flex-shrink: 0;
+
+ .btn {
+ min-width: 60px;
+ font-size: 0.875rem;
+ border-radius: 999px;
+ padding: 0.375rem 0.75rem;
+ transition: all 0.2s ease;
+
+ &:first-child {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+
+ &:last-child {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ }
+
+ &.active {
+ background-color: var(--bs-primary);
+ border-color: var(--bs-primary);
+ color: white;
+ font-weight: 600;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ КНОПКА ФИЛЬТРОВ
+────────────────────────────────────────────────────────────── */
+.page-filter-toggle {
+ &:hover {
+ background-color: color-mix(in srgb, var(--bs-primary), transparent 85%);
+ border-color: var(--bs-primary);
+ color: var(--bs-primary);
+ }
+
+ &[aria-expanded="true"] {
+ background-color: var(--bs-primary);
+ border-color: var(--bs-primary);
+ color: white;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ КНОПКА СОЗДАНИЯ
+────────────────────────────────────────────────────────────── */
+.page-create-btn {
+ font-weight: 600;
+ font-size: 0.875rem;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ transition: all 0.2s ease;
+
+ &:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
+ }
+
+ &:active {
+ transform: translateY(0);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ПОИСК
+────────────────────────────────────────────────────────────── */
+.page-search {
+ flex-shrink: 1;
+ min-width: 200px;
+ max-width: 400px;
+ flex-grow: 1;
+
+ .ios-search {
+ width: 100%;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ БЛОК ФИЛЬТРОВ
+────────────────────────────────────────────────────────────── */
+.page-filters-collapse {
+ margin-top: var(--space-2);
+ width: 100%;
+}
+
+.page-filters {
+ border-radius: var(--radius-lg, 14px);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+ background: var(--bs-body-bg);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
+ padding: var(--space-3);
+ animation: slideDown 0.3s ease;
+
+ .btn {
+ white-space: nowrap;
+ min-width: fit-content;
+ }
+
+ .d-flex.gap-2 {
+ flex-wrap: wrap;
+ }
+}
+
+@keyframes slideDown {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ АДАПТИВНОСТЬ
+────────────────────────────────────────────────────────────── */
+
+/* Планшеты */
+@media (max-width: 991.98px) {
+ .page-title {
+ font-size: 1.5rem;
+ }
+
+ .page-header {
+ padding: var(--space-2) 0;
+ }
+
+ .page-search {
+ flex-basis: 100%;
+ max-width: none;
+ margin-top: var(--space-2);
+ order: 10;
+ }
+
+ .page-filter-toggle {
+ order: 11;
+ margin-top: var(--space-2);
+ margin-left: auto;
+ margin-right: 0 !important;
+ }
+}
+
+@media (max-width: 767.98px) {
+ .page-header-title {
+ h1 {
+ font-size: 1.25rem;
+ }
+
+ i {
+ font-size: 1.5rem;
+ }
+ }
+}
+
+/* Мобильные */
+@media (max-width: 575.98px) {
+ .page-header {
+ margin-bottom: var(--space-2);
+ padding: var(--space-1) 0;
+ top: var(--navbar-h, 60px);
+ }
+
+ .page-title {
+ font-size: 1.125rem;
+ font-weight: 700;
+ }
+
+ .page-count {
+ font-size: 0.7rem;
+ }
+
+ .page-scope-switch {
+ gap: 0.25rem;
+
+ .btn {
+ min-width: auto;
+ font-size: 0.7rem;
+ padding: 0.2rem 0.4rem;
+ }
+ }
+
+ .page-filters {
+ margin-top: 0.5rem;
+
+ .btn {
+ padding: 0.4rem 0.75rem;
+ font-size: 0.85rem;
+ }
+ }
+
+ .page-search {
+ margin-top: 0.5rem;
+ }
+
+ @media (max-width: 480px) {
+ .page-count {
+ display: none;
+ }
+
+ .page-header .card {
+ margin-top: 0;
+ width: 100%;
+
+ button.dept-row,
+ a.dept-row {
+ padding: var(--space-1) var(--space-1);
+ font-size: 0.9rem;
+ }
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ТЕМНАЯ ТЕМА
+────────────────────────────────────────────────────────────── */
+@media (prefers-color-scheme: dark) {
+ .page-header {
+ background: linear-gradient(
+ to bottom,
+ color-mix(in srgb, var(--bs-body-bg) 85%, transparent) 0%,
+ color-mix(in srgb, var(--bs-body-bg) 80%, transparent) 45%,
+ color-mix(in srgb, var(--bs-body-bg) 65%, transparent) 50%,
+ color-mix(in srgb, var(--bs-body-bg) 35%, transparent) 70%,
+ transparent 100%
+ );
+ border-bottom-color: color-mix(in srgb, var(--bs-border-color), transparent 60%);
+
+ &.scrolled {
+ background: linear-gradient(
+ to bottom,
+ color-mix(in srgb, var(--bs-body-bg) 90%, transparent) 0%,
+ color-mix(in srgb, var(--bs-body-bg) 80%, transparent) 30%,
+ color-mix(in srgb, var(--bs-body-bg) 72%, transparent) 50%,
+ color-mix(in srgb, var(--bs-body-bg) 40%, transparent) 70%,
+ transparent 100%
+ );
+ }
+
+ .card {
+ button.dept-row:hover,
+ a.dept-row:hover {
+ background-color: color-mix(in srgb, var(--bs-body-bg) 95%, white);
+ }
+ }
+ }
+
+ .page-filters {
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_post-form.scss b/backend/static/scss_backup_20260115/components/_post-form.scss
new file mode 100644
index 00000000..a8269c9c
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_post-form.scss
@@ -0,0 +1,20 @@
+// =============================================================================
+// Post Form Component (SCSS)
+// =============================================================================
+// Стили формы создания/редактирования поста
+
+// =============================================================================
+// AUTOGROW TEXTAREA
+// =============================================================================
+
+textarea.autogrow {
+ overflow: hidden; // без скроллов до достижения max-height
+ resize: none; // убираем ручной ресайз
+ min-height: 120px;
+ max-height: 70vh; // не занимаем весь экран
+
+ // Когда достигли max-height - включаем скролл
+ &.is-max {
+ overflow-y: auto;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_recipientPicker.scss b/backend/static/scss_backup_20260115/components/_recipientPicker.scss
new file mode 100644
index 00000000..4e6ce0fe
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_recipientPicker.scss
@@ -0,0 +1,353 @@
+// =============================================================================
+// Recipient Picker (Email-style) Styles (SCSS)
+// =============================================================================
+// Компонент выбора получателей в стиле email-клиента
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$recipient-avatar-size: 32px;
+$recipient-avatar-size-mobile: 28px;
+$recipient-label-width: 80px;
+$recipient-chip-padding: 0.25rem 0.5rem;
+$recipient-chip-padding-mobile: 0.2rem 0.4rem;
+
+// Цвета
+$chip-primary-color: var(--bs-primary);
+$chip-primary-hover: var(--bs-primary-dark, #0056b3);
+$chip-secondary-color: var(--bs-secondary);
+$chip-secondary-hover: var(--bs-secondary-dark, #5a6268);
+
+// =============================================================================
+// ОСНОВНОЙ КОНТЕЙНЕР
+// =============================================================================
+
+.recipient-picker-email {
+ font-size: 0.9375rem;
+}
+
+// =============================================================================
+// СТРОКИ ПОЛУЧАТЕЛЕЙ (To/CC/Отделы)
+// =============================================================================
+
+.recipient-row {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.75rem;
+ padding: 0.75rem 0;
+ border-bottom: 1px solid var(--bs-border-color);
+
+ &:last-child {
+ border-bottom: none;
+ }
+}
+
+// =============================================================================
+// МЕТКА (To:/CC:/Отделы:)
+// =============================================================================
+
+.recipient-label {
+ min-width: $recipient-label-width;
+ padding-top: 0.5rem;
+ color: var(--bs-secondary);
+ font-weight: 500;
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ margin: 0;
+
+ i {
+ font-size: 1.1em;
+ }
+}
+
+// =============================================================================
+// ПОЛЕ ВВОДА
+// =============================================================================
+
+.recipient-field {
+ flex: 1;
+ display: flex;
+ align-items: flex-start;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+}
+
+// =============================================================================
+// WRAPPER ДЛЯ CHIPS + INPUT
+// =============================================================================
+
+.recipient-input-wrapper {
+ flex: 1;
+ min-width: 300px;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.375rem;
+ padding: 0.375rem 0.5rem;
+ background: var(--bs-body-bg);
+ border: 1px solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
+ position: relative;
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+
+ &:focus-within {
+ border-color: $chip-primary-color;
+ box-shadow: 0 0 0 0.15rem rgba(var(--bs-primary-rgb), 0.15);
+ }
+}
+
+// =============================================================================
+// INPUT ВНУТРИ WRAPPER
+// =============================================================================
+
+.recipient-input {
+ flex: 1;
+ min-width: 200px;
+ border: none;
+ outline: none;
+ padding: 0.25rem;
+ font-size: inherit;
+ background: transparent;
+
+ &::placeholder {
+ color: var(--bs-secondary-color);
+ opacity: 0.7;
+ }
+}
+
+// =============================================================================
+// CHIPS (ВЫБРАННЫЕ ПОЛЬЗОВАТЕЛИ/ОТДЕЛЫ)
+// =============================================================================
+
+.recipient-chip {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.375rem;
+ padding: $recipient-chip-padding;
+ background: $chip-primary-color;
+ color: white;
+ border-radius: 1rem;
+ font-size: 0.875rem;
+ white-space: nowrap;
+ transition: background-color 0.15s;
+
+ &:hover {
+ background: $chip-primary-hover;
+ }
+
+ &.chip-cc {
+ background: $chip-secondary-color;
+
+ &:hover {
+ background: $chip-secondary-hover;
+ }
+ }
+}
+
+.chip-remove {
+ background: none;
+ border: none;
+ padding: 0;
+ color: white;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ opacity: 0.8;
+ transition: opacity 0.15s;
+
+ &:hover {
+ opacity: 1;
+ }
+
+ i {
+ font-size: 1.1em;
+ line-height: 1;
+ }
+}
+
+// Chips для отделов
+.recipient-chips {
+ display: inline-flex;
+ flex-wrap: wrap;
+ gap: 0.375rem;
+ align-items: center;
+}
+
+// =============================================================================
+// DROPDOWN С AUTOCOMPLETE
+// =============================================================================
+
+.recipient-dropdown {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ right: 0;
+ margin-top: 0.25rem;
+ background: white;
+ border: 1px solid var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
+ box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+ max-height: 300px;
+ overflow-y: auto;
+ z-index: 1050;
+}
+
+.dropdown-item-user {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.625rem 1rem;
+ cursor: pointer;
+ transition: background-color 0.15s;
+
+ &:hover {
+ background-color: var(--bs-light);
+ }
+}
+
+.dropdown-item-empty {
+ padding: 0.75rem 1rem;
+ color: var(--bs-secondary);
+ text-align: center;
+ font-size: 0.875rem;
+}
+
+// =============================================================================
+// АВАТАР ПОЛЬЗОВАТЕЛЯ
+// =============================================================================
+
+.user-avatar-small {
+ width: $recipient-avatar-size;
+ height: $recipient-avatar-size;
+ border-radius: 50%;
+ background: $chip-primary-color;
+ color: white;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 600;
+ font-size: 0.75rem;
+ flex-shrink: 0;
+ overflow: hidden;
+}
+
+.user-avatar-img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: 50%;
+}
+
+.user-avatar-placeholder {
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: $chip-primary-color;
+ color: white;
+ font-weight: 600;
+ font-size: 0.75rem;
+}
+
+// =============================================================================
+// ИНФОРМАЦИЯ О ПОЛЬЗОВАТЕЛЕ
+// =============================================================================
+
+.user-info {
+ flex: 1;
+ min-width: 0;
+}
+
+.user-name {
+ font-weight: 500;
+ color: var(--bs-body-color);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.user-subtitle {
+ font-size: 0.8125rem;
+ color: var(--bs-secondary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+// =============================================================================
+// ПОДСКАЗКИ
+// =============================================================================
+
+.alert-sm {
+ padding: 0.5rem 0.75rem;
+ margin-top: 0.75rem;
+ font-size: 0.875rem;
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ: ПЛАНШЕТЫ
+// =============================================================================
+
+@media (max-width: 768px) {
+ .recipient-row {
+ flex-direction: column;
+ gap: 0.5rem;
+ }
+
+ .recipient-label {
+ min-width: auto;
+ padding-top: 0;
+ }
+
+ .recipient-input-wrapper {
+ min-width: 100%;
+ }
+
+ .recipient-input {
+ min-width: 150px;
+ }
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ: МОБИЛЬНЫЕ
+// =============================================================================
+
+@media (max-width: 576px) {
+ .recipient-chip {
+ font-size: 0.8125rem;
+ padding: $recipient-chip-padding-mobile;
+ }
+
+ .user-avatar-small {
+ width: $recipient-avatar-size-mobile;
+ height: $recipient-avatar-size-mobile;
+ font-size: 0.7rem;
+ }
+
+ .dropdown-item-user {
+ padding: 0.5rem 0.75rem;
+ }
+}
+
+// =============================================================================
+// ТЕМНАЯ ТЕМА
+// =============================================================================
+
+@media (prefers-color-scheme: dark) {
+ .recipient-input-wrapper {
+ background: var(--bs-dark);
+ border-color: var(--bs-gray-700);
+ }
+
+ .recipient-dropdown {
+ background: var(--bs-dark);
+ border-color: var(--bs-gray-700);
+ }
+
+ .dropdown-item-user:hover {
+ background-color: var(--bs-gray-800);
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_request-detail.scss b/backend/static/scss_backup_20260115/components/_request-detail.scss
new file mode 100644
index 00000000..c749be01
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_request-detail.scss
@@ -0,0 +1,225 @@
+// =============================================================================
+// Request Detail Styles (SCSS)
+// =============================================================================
+// Стили для страницы детального просмотра заявления
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$req-detail-icon-size: 48px;
+$req-detail-icon-size-mobile: 40px;
+$req-detail-padding: 1rem 1.25rem;
+$req-detail-padding-mobile: 0.75rem 1rem;
+$req-info-label-width: 140px;
+
+// =============================================================================
+// ЗАГОЛОВОК КАРТОЧКИ
+// =============================================================================
+
+.request-detail-card .req-detail-header {
+ padding: $req-detail-padding;
+ border-bottom: 1px solid var(--bs-border-color);
+ background: var(--bs-body-bg);
+}
+
+.request-detail-card .req-detail-row {
+ display: flex;
+ align-items: flex-start;
+ gap: 1rem;
+}
+
+.request-detail-card .req-detail-icon {
+ flex-shrink: 0;
+
+ .card-icon {
+ width: $req-detail-icon-size;
+ height: $req-detail-icon-size;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--bs-tertiary-bg);
+ border-radius: 0.5rem;
+ font-size: 1.5rem;
+ }
+}
+
+.request-detail-card .req-detail-content {
+ flex: 1;
+ min-width: 0;
+
+ h1 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ margin: 0;
+ line-height: 1.3;
+ }
+}
+
+.request-detail-card .req-detail-actions {
+ display: flex;
+ gap: 0.5rem;
+ flex-shrink: 0;
+}
+
+// =============================================================================
+// ИНФОРМАЦИОННЫЕ БЛОКИ
+// =============================================================================
+
+.req-info-block {
+ display: flex;
+ padding: 0.75rem 0;
+ border-bottom: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 50%);
+
+ &:last-child {
+ border-bottom: none;
+ padding-bottom: 0;
+ }
+
+ &:first-child {
+ padding-top: 0;
+ }
+}
+
+.req-info-label {
+ flex: 0 0 $req-info-label-width;
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+ font-weight: 500;
+}
+
+.req-info-value {
+ flex: 1;
+ min-width: 0;
+ font-size: 0.9375rem;
+}
+
+.req-comment-text {
+ padding: 0.75rem 1rem;
+ background: var(--bs-tertiary-bg);
+ border-radius: 0.375rem;
+ line-height: 1.5;
+}
+
+// =============================================================================
+// СЕКЦИЯ КОММЕНТАРИЕВ
+// =============================================================================
+
+#comments-section {
+ position: sticky;
+ top: 1rem;
+ display: flex;
+ flex-direction: column;
+ max-height: 80vh;
+ overflow: visible;
+
+ .card-header {
+ background: var(--bs-body-bg);
+ padding: 0.75rem 1rem;
+ font-size: 0.9375rem;
+ }
+
+ .card-body {
+ flex: 1;
+ min-height: 100px;
+ overflow-y: auto;
+ overflow-x: visible;
+ }
+
+ .list-group-item {
+ padding: 0.75rem 1rem;
+ border-left: 0;
+ border-right: 0;
+
+ &:first-child {
+ border-top: 0;
+ }
+ }
+
+ .card-footer {
+ padding: 0.75rem 1rem;
+ position: relative;
+ z-index: 100;
+ overflow: visible;
+ flex-shrink: 0;
+ border-top: 1px solid var(--bs-border-color);
+
+ .message-field {
+ background: var(--bs-tertiary-bg);
+ }
+ }
+
+ .dropdown {
+ position: static;
+ }
+
+ .dropdown-menu {
+ z-index: 2000 !important;
+ position: fixed !important;
+ max-height: 350px;
+ overflow-y: auto;
+ width: auto !important;
+ min-width: 300px;
+ }
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ: ПЛАНШЕТЫ
+// =============================================================================
+
+@media (max-width: 992px) {
+ .request-detail-card .req-detail-row {
+ flex-wrap: wrap;
+ }
+
+ .request-detail-card .req-detail-content {
+ flex: 1 1 calc(100% - 64px);
+ }
+
+ .request-detail-card .req-detail-actions {
+ width: 100%;
+ margin-top: 0.75rem;
+ }
+
+ #comments-section {
+ position: static;
+ }
+
+ .req-info-block {
+ flex-direction: column;
+ gap: 0.25rem;
+ }
+
+ .req-info-label {
+ flex: none;
+ font-size: 0.75rem;
+ }
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ: МОБИЛЬНЫЕ
+// =============================================================================
+
+@media (max-width: 576px) {
+ .request-detail-card .req-detail-header {
+ padding: $req-detail-padding-mobile;
+ }
+
+ .request-detail-card .req-detail-icon .card-icon {
+ width: $req-detail-icon-size-mobile;
+ height: $req-detail-icon-size-mobile;
+ font-size: 1.25rem;
+ }
+
+ .request-detail-card .req-detail-content h1 {
+ font-size: 1.1rem;
+ }
+
+ .request-detail-card .req-detail-actions {
+ flex-direction: column;
+
+ .btn {
+ width: 100%;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_request-list.scss b/backend/static/scss_backup_20260115/components/_request-list.scss
new file mode 100644
index 00000000..aaee9363
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_request-list.scss
@@ -0,0 +1,545 @@
+// =============================================================================
+// Request List Styles (SCSS)
+// =============================================================================
+// Табличный вид списка заявлений с адаптивным дизайном
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+// Размеры колонок таблицы
+$req-icon-size: 48px;
+$req-icon-size-tablet: 42px;
+$req-icon-size-mobile: 36px;
+$req-icon-size-compact: 32px;
+
+// Отступы
+$req-row-padding: 0.75rem 1rem;
+$req-row-padding-mobile: 1rem 0.75rem;
+$req-row-padding-compact: 0.625rem;
+$req-cell-gap: 0.75rem;
+$req-cell-gap-mobile: 0.75rem;
+
+// Переходы
+$req-hover-transition: background-color 0.15s ease;
+
+// =============================================================================
+// КОНТЕЙНЕР СПИСКА
+// =============================================================================
+
+#reqList.card {
+ display: block;
+ gap: 0;
+ padding: 0;
+}
+
+// =============================================================================
+// ЗАГОЛОВОК ТАБЛИЦЫ
+// =============================================================================
+
+#reqList .req-table-header {
+ position: sticky;
+ top: 0;
+ z-index: 10;
+ background: var(--bs-body-bg);
+ border-bottom: 2px solid var(--bs-border-color);
+
+ .req-table-row {
+ padding: 0.625rem 1rem;
+ }
+
+ h6 {
+ font-size: 0.75rem;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ color: var(--bs-secondary-color);
+ margin: 0;
+ }
+
+ .req-cell {
+ align-items: center;
+ }
+
+ // Выравнивание заголовков
+ .req-cell-title h6,
+ .req-cell-author h6 {
+ text-align: left;
+ }
+
+ .req-cell-dates h6,
+ .req-cell-status h6,
+ .req-cell-created h6,
+ .req-cell-actions h6 {
+ text-align: center;
+ }
+}
+
+// =============================================================================
+// СТРОКА ЗАЯВЛЕНИЯ
+// =============================================================================
+
+#reqList .req-row {
+ padding: 0;
+ margin: 0;
+ border-bottom: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 50%);
+ transition: $req-hover-transition;
+
+ &:hover {
+ background-color: color-mix(in srgb, var(--bs-primary) 3%, transparent);
+ }
+
+ &:last-child {
+ border-bottom: 0;
+ }
+}
+
+// =============================================================================
+// ТАБЛИЧНАЯ СЕТКА
+// =============================================================================
+
+#reqList .req-table-row {
+ display: grid;
+ grid-template-columns:
+ $req-icon-size // Иконка
+ minmax(200px, 2fr) // Заголовок (расширяемая)
+ minmax(120px, 1fr) // Автор
+ 100px // Даты
+ 110px // Статус
+ 80px // Создано
+ 80px; // Действия
+ gap: $req-cell-gap;
+ align-items: start;
+ padding: $req-row-padding;
+}
+
+// =============================================================================
+// ЯЧЕЙКИ ТАБЛИЦЫ
+// =============================================================================
+
+#reqList .req-cell {
+ min-width: 0; // Для корректного word-wrap
+ display: flex;
+ align-items: center;
+}
+
+#reqList .req-cell-content {
+ width: 100%;
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ word-break: break-word;
+ hyphens: auto;
+ line-height: 1.4;
+}
+
+// =============================================================================
+// СПЕЦИФИЧНЫЕ СТИЛИ ЯЧЕЕК
+// =============================================================================
+
+#reqList .req-cell-icon {
+ justify-content: center;
+
+ .card-icon {
+ width: 38px;
+ height: 38px;
+ flex-shrink: 0;
+ }
+}
+
+#reqList .req-cell-title {
+ font-size: 0.9rem;
+
+ strong {
+ display: block;
+ margin-bottom: 0.125rem;
+ }
+
+ .badge {
+ font-size: 0.7rem;
+ padding: 0.2rem 0.4rem;
+ }
+}
+
+#reqList .req-cell-author {
+ font-size: 0.875rem;
+}
+
+#reqList .req-cell-dates {
+ font-size: 0.8rem;
+ font-variant-numeric: tabular-nums;
+ line-height: 1.3;
+}
+
+#reqList .req-cell-status {
+ justify-content: flex-start;
+
+ .badge {
+ font-size: 0.7rem;
+ padding: 0.25rem 0.5rem;
+ white-space: nowrap;
+ }
+}
+
+#reqList .req-cell-created {
+ font-size: 0.75rem;
+ text-align: center;
+}
+
+#reqList .req-cell-actions {
+ justify-content: center;
+ gap: 0.25rem;
+
+ .req-cell-content {
+ display: flex;
+ gap: 0.25rem;
+ justify-content: center;
+ }
+}
+
+// =============================================================================
+// ФУТЕР С КОММЕНТАРИЯМИ
+// =============================================================================
+
+#reqList .req-footer {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 1rem;
+ margin-left: calc($req-icon-size + $req-cell-gap);
+ border-top: none;
+ background: transparent;
+}
+
+#reqList .comments-block {
+ margin: 0;
+ padding: 1rem;
+ margin-left: calc($req-icon-size + $req-cell-gap);
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ: ПЛАНШЕТЫ
+// =============================================================================
+
+@media (max-width: 992px) {
+ #reqList .req-table-header .req-table-row,
+ #reqList .req-table-row {
+ grid-template-columns:
+ $req-icon-size-tablet // Иконка
+ minmax(150px, 2fr) // Заголовок
+ minmax(100px, 1fr) // Автор
+ 90px // Даты
+ 100px // Статус
+ 70px; // Создано
+ }
+
+ // Скрываем колонку действий в заголовке
+ #reqList .req-table-header .req-cell-actions {
+ display: none;
+ }
+
+ // Но кнопки остаются видимыми
+ #reqList .req-cell-actions {
+ grid-column: 6;
+ display: flex !important;
+ justify-content: flex-end;
+ }
+}
+
+// =============================================================================
+// АДАПТИВНОСТЬ: МОБИЛЬНЫЕ
+// =============================================================================
+
+@media (max-width: 768px) {
+ // Скрываем заголовок таблицы
+ #reqList .req-table-header {
+ display: none;
+ }
+
+ // Переходим на flexbox
+ #reqList .req-table-row {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ padding: $req-row-padding-mobile;
+ gap: $req-cell-gap-mobile;
+ align-items: flex-start;
+ }
+
+ // Сброс для ячеек
+ #reqList .req-cell {
+ display: block;
+ min-width: 0;
+ }
+
+ #reqList .req-cell-content {
+ width: 100%;
+ }
+
+ // Иконка слева сверху
+ #reqList .req-cell-icon {
+ flex: 0 0 $req-icon-size-mobile;
+ padding-top: 0.25rem;
+
+ .card-icon {
+ width: $req-icon-size-compact;
+ height: $req-icon-size-compact;
+ }
+ }
+
+ // Заголовок занимает оставшуюся ширину
+ #reqList .req-cell-title {
+ flex: 1 1 calc(100% - 48px);
+ font-size: 0.9rem;
+
+ strong {
+ display: block;
+ margin-bottom: 0.25rem;
+ font-size: 0.95rem;
+ }
+
+ .badge {
+ display: inline-block;
+ font-size: 0.7rem;
+ padding: 0.2rem 0.4rem;
+ }
+
+ .small {
+ display: block;
+ font-size: 0.8rem;
+ margin-top: 0.25rem;
+ }
+ }
+
+ // Остальная информация
+ #reqList .req-cell-author,
+ #reqList .req-cell-dates,
+ #reqList .req-cell-status {
+ flex: 0 1 auto;
+ font-size: 0.8rem;
+ }
+
+ #reqList .req-cell-dates {
+ white-space: nowrap;
+
+ br {
+ display: none;
+ }
+ }
+
+ #reqList .req-cell-status .badge {
+ font-size: 0.7rem;
+ padding: 0.25rem 0.5rem;
+ white-space: nowrap;
+ }
+
+ // Скрываем дату создания
+ #reqList .req-cell-created {
+ display: none;
+ }
+
+ // Кнопки действий на отдельной строке
+ #reqList .req-cell-actions {
+ display: flex !important;
+ flex: 1 1 100%;
+ gap: 0.5rem;
+ padding-top: 0.75rem;
+ border-top: 1px solid var(--bs-border-color-translucent);
+ margin: 0;
+
+ .req-cell-content {
+ display: flex;
+ gap: 0.5rem;
+ flex-wrap: wrap;
+ width: 100%;
+ }
+
+ .btn {
+ padding: 0.5rem 0.75rem;
+ font-size: 0.85rem;
+ }
+ }
+
+ // Футер на полную ширину
+ #reqList .req-footer {
+ flex: 1 1 100%;
+ margin-left: 0;
+ padding: 0.75rem 0;
+ border-top: 1px solid var(--bs-border-color-translucent);
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem;
+
+ .btn {
+ padding: 0.4rem 0.6rem;
+ font-size: 0.8rem;
+ }
+ }
+
+ // Блок комментариев
+ #reqList .comments-block {
+ margin-left: 0;
+ padding: 0.75rem;
+ }
+
+ // Строка без hover
+ #reqList .req-row {
+ padding: 0;
+ border-bottom: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 50%);
+
+ &:hover {
+ background-color: transparent;
+ }
+
+ &:last-child {
+ border-bottom: 0;
+ }
+ }
+}
+
+// =============================================================================
+// КОМПАКТНЫЙ РЕЖИМ
+// =============================================================================
+
+@media (max-width: 576px) {
+ #reqList .req-table-row {
+ padding: $req-row-padding-compact;
+ }
+
+ #reqList .req-cell-title .small {
+ display: none; // Скрываем превью
+ }
+
+ #reqList .req-cell-dates {
+ br {
+ display: none;
+ }
+
+ .req-cell-content::after {
+ content: ' — ';
+ }
+ }
+}
+
+// =============================================================================
+// AJAX-РЕЖИМ: REQ-ITEM
+// =============================================================================
+
+.req-item {
+ border-bottom: 1px solid var(--bs-border-color);
+ padding: 1rem;
+ transition: background-color 0.2s;
+
+ &:hover {
+ background-color: var(--bs-light);
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+}
+
+.req-header {
+ margin-bottom: 0.75rem;
+}
+
+.req-title-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.75rem;
+ margin-bottom: 0.5rem;
+}
+
+.req-link {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ text-decoration: none;
+ color: var(--bs-body-color);
+ font-weight: 500;
+ flex: 1;
+ min-width: 0;
+
+ &:hover {
+ color: var(--bs-primary);
+ }
+
+ strong {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+}
+
+.req-meta {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 1rem;
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+
+ > span {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ }
+}
+
+.req-comment {
+ margin: 0.5rem 0;
+ padding: 0.5rem;
+ background-color: var(--bs-light);
+ border-radius: 0.375rem;
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+}
+
+.req-footer {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.75rem;
+ align-items: center;
+ padding-top: 0.75rem;
+ border-top: 1px solid var(--bs-border-color-translucent);
+ font-size: 0.875rem;
+}
+
+.req-approver,
+.req-recipients {
+ display: flex;
+ align-items: center;
+ gap: 0.25rem;
+ color: var(--bs-secondary-color);
+}
+
+// =============================================================================
+// BADGE СТАТУСЫ
+// =============================================================================
+
+.badge-warning {
+ background-color: #ffc107;
+ color: #000;
+}
+
+.badge-success {
+ background-color: #198754;
+ color: #fff;
+}
+
+.badge-danger {
+ background-color: #dc3545;
+ color: #fff;
+}
+
+.badge-secondary {
+ background-color: #6c757d;
+ color: #fff;
+}
+
+// =============================================================================
+// ВСПОМОГАТЕЛЬНЫЕ
+// =============================================================================
+
+.load-more-trigger {
+ visibility: hidden;
+}
diff --git a/backend/static/scss_backup_20260115/components/_rightbar-calendar.scss b/backend/static/scss_backup_20260115/components/_rightbar-calendar.scss
new file mode 100644
index 00000000..6f1ec4fc
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_rightbar-calendar.scss
@@ -0,0 +1,331 @@
+/**
+ * rightbar-calendar.scss
+ * Стили для компонента правой панели с календарем
+ * Включает стили для FullCalendar, вертикальной ленты недели и модалов событий
+ */
+
+/* =====================================
+ БАЗА КАЛЕНДАРЯ
+===================================== */
+
+.calendar-wrap {
+ min-height: 360px;
+ border-radius: 10px;
+ overflow: hidden;
+ background: var(--bs-body-bg);
+ box-shadow: inset 0 1px 3px color-mix(in srgb, var(--bs-body-color), transparent 92%);
+ border: 0;
+}
+
+.rightbar-card {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ border-radius: 16px;
+ overflow: hidden;
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+ background: var(--bs-body-bg);
+ box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 8px 24px rgba(0,0,0,.08);
+ min-height: 0;
+
+ .card-header {
+ flex: 0 0 auto;
+ background: var(--bs-tertiary-bg);
+ border-bottom: 1px solid var(--bs-border-color);
+ padding: var(--space-1) var(--space-2);
+ }
+
+ .card-body {
+ flex: 1 1 auto;
+ min-height: 0;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+ padding: var(--space-2);
+ }
+}
+
+// Поддержка многострочного header при длинных названиях отделов
+.min-w-0 {
+ min-width: 0;
+}
+
+/* =====================================
+ DESKTOP STICKY LAYOUT
+===================================== */
+
+// На десктопе rightbar становится sticky с фиксированной высотой
+// Высота = 100vh - navbar - 2*отступ (сверху и снизу)
+// top = navbar + отступ сверху
+// Не перемещается с основным скролом страницы, скролл только внутри .card-body
+@media (min-width: 992px) {
+ .rightbar {
+ position: sticky;
+ top: calc(var(--navbar-h) + var(--layout-padding-y, 12px));
+ height: calc(100dvh - var(--navbar-h) - 2 * var(--layout-padding-y, 12px));
+ overflow: hidden;
+ // padding управляется через Bootstrap классы в шаблоне (px-0, py-3 и т.д.)
+ }
+}
+
+/* =====================================
+ FULLCALENDAR — КОМПАКТНО
+===================================== */
+
+.fc {
+ font-size: 0.7rem;
+ --fc-border-color: var(--bs-border-color);
+ --fc-page-bg-color: transparent;
+ --fc-neutral-bg-color: transparent;
+ --fc-today-bg-color: color-mix(in srgb, var(--bs-primary), transparent 85%);
+ --fc-event-bg-color: var(--bs-primary);
+ --fc-event-border-color: var(--bs-primary);
+ --fc-event-text-color: var(--bs-body-bg);
+
+ // Убираем границы
+ .fc-theme-standard .fc-scrollgrid {
+ border: 0 !important;
+ }
+
+ .fc-theme-standard td,
+ .fc-theme-standard th {
+ border: 0 !important;
+ }
+
+ // Toolbar
+ .fc-toolbar {
+ padding: var(--space-2);
+ background: var(--bs-tertiary-bg);
+ border-bottom: 1px solid var(--bs-border-color);
+ justify-content: space-between;
+ }
+
+ .fc-toolbar-title {
+ font-size: 1rem;
+ font-weight: 600;
+ color: var(--bs-body-color);
+ }
+
+ .fc-button {
+ border-radius: 8px;
+ font-size: .82rem;
+ padding: var(--space-1);
+ background: transparent;
+ border: none;
+ color: var(--bs-primary);
+
+ &:hover {
+ background: rgba(var(--bs-primary-rgb), .1);
+ }
+ }
+
+ // Day cells
+ .fc-daygrid-day-frame {
+ padding: 2px 3px !important;
+ }
+
+ .fc-daygrid-day-number {
+ font-size: .82rem;
+ width: 100%;
+ height: 1.6rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: 600;
+ color: var(--bs-body-color);
+ text-decoration: none !important;
+ }
+
+ .fc-day-today {
+ background: none !important;
+
+ .fc-daygrid-day-number {
+ color: var(--bs-primary);
+ font-weight: 700;
+ border: 1px solid var(--bs-primary);
+ border-radius: 50%;
+ }
+ }
+
+ .fc-day-other .fc-daygrid-day-number {
+ opacity: .4;
+ }
+
+ // Events
+ .fc-daygrid-day-events {
+ padding: 0 2px 2px !important;
+ row-gap: 2px !important;
+ }
+
+ .fc-daygrid-event-harness {
+ margin: 0 0 2px 0 !important;
+ }
+
+ .fc-daygrid-event {
+ border-radius: 6px;
+ padding: var(--space-1) !important;
+ line-height: 1.02 !important;
+ background: color-mix(in srgb, var(--bs-primary), var(--bs-body-bg) 75%);
+ border: 1px solid color-mix(in srgb, var(--bs-primary), transparent 60%);
+ color: var(--bs-body-color);
+
+ .fc-event-time {
+ display: none !important;
+ }
+
+ .fc-event-title {
+ font-size: .62rem !important;
+ line-height: 1.02 !important;
+ letter-spacing: -0.2px;
+ font-weight: 600;
+ font-family: "Arial Narrow","Roboto Condensed",system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
+ display: -webkit-box !important;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ overflow: hidden !important;
+ white-space: normal !important;
+ text-overflow: ellipsis;
+ max-height: calc(1.02em * 3);
+ }
+ }
+}
+
+/* =====================================
+ ВЕРТИКАЛЬНАЯ ЛЕНТА НЕДЕЛИ
+===================================== */
+
+.week-strip-header {
+ margin-top: var(--space-2);
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ color: var(--bs-secondary-color);
+ font-size: .8rem;
+}
+
+.week-vertical {
+ margin-top: var(--space-1);
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-1);
+
+ .week-row {
+ display: grid;
+ grid-template-columns: 56px 1fr;
+ align-items: start;
+ gap: var(--space-1);
+ padding: var(--space-1);
+ border-radius: 12px;
+ background: color-mix(in srgb, var(--bs-primary), var(--bs-body-bg) 86%);
+ border: 1px solid color-mix(in srgb, var(--bs-primary), transparent 70%);
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-primary), var(--bs-body-bg) 82%);
+ }
+ }
+
+ .content {
+ .title {
+ font-size: .8rem;
+ font-weight: 600;
+ color: var(--bs-body-color);
+ display: -webkit-box;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: normal;
+ }
+
+ .meta {
+ margin-top: .15rem;
+ font-size: .72rem;
+ color: var(--bs-secondary-color);
+ }
+ }
+}
+
+.date-badge {
+ display: grid;
+ place-items: center;
+ border-radius: 10px;
+ padding: .35rem .25rem;
+ background: color-mix(in srgb, var(--bs-primary), var(--bs-body-bg) 92%);
+ border: 1px solid color-mix(in srgb, var(--bs-primary), transparent 75%);
+ text-align: center;
+ line-height: 1.05;
+
+ .dow {
+ font-size: .7rem;
+ font-weight: 700;
+ color: var(--bs-primary);
+ text-transform: uppercase;
+ }
+
+ .md {
+ font-size: .74rem;
+ font-weight: 700;
+ color: var(--bs-body-color);
+ }
+}
+
+/* =====================================
+ OFFCANVAS (МОБАЙЛ)
+===================================== */
+
+#rightbarOffcanvas {
+ height: 100dvh;
+ height: 100svh;
+
+ .offcanvas-body {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-1);
+ height: calc(100dvh - var(--rb-offcanvas-head, 56px));
+ height: calc(100svh - var(--rb-offcanvas-head, 56px));
+ min-height: 0;
+ overflow-y: auto;
+ -webkit-overflow-scrolling: touch;
+ overscroll-behavior: contain;
+ }
+
+ .calendar-wrap {
+ flex: 0 0 auto;
+ }
+
+ .week-vertical {
+ flex: 0 0 auto;
+ }
+}
+
+/* =====================================
+ COLOR PICKER (PALETTE)
+===================================== */
+
+.color-swatch {
+ width: 26px;
+ height: 26px;
+ border: 1px solid var(--bs-border-color);
+ border-radius: 9999px;
+ padding: 0;
+ cursor: pointer;
+ background: transparent;
+
+ &.active {
+ outline: 2px solid var(--bs-primary);
+ outline-offset: 2px;
+ }
+}
+
+/* =====================================
+ EVENT DETAILS MODAL
+===================================== */
+
+.color-dot {
+ width: 12px;
+ height: 12px;
+ border-radius: 9999px;
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 6px;
+ border: 1px solid #00000022;
+}
diff --git a/backend/static/scss_backup_20260115/components/_sidebar.scss b/backend/static/scss_backup_20260115/components/_sidebar.scss
new file mode 100644
index 00000000..2287c10e
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_sidebar.scss
@@ -0,0 +1,198 @@
+/**
+ * _sidebar.scss
+ * Стили левого сайдбара: навигация, активные элементы, переключатель темы
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ SIDEBAR LAYOUT
+────────────────────────────────────────────────────────────── */
+/* Offcanvas остаётся как есть (липкий ≥ lg) */
+#sidebar {
+ --bs-offcanvas-border-color: transparent;
+ --bs-offcanvas-border-width: 0;
+ --bs-offcanvas-border-radius: 0;
+ border: 0 !important;
+ border-radius: 0 !important;
+ box-shadow: none !important;
+ background: var(--bs-body-bg);
+}
+
+/* На десктопе sidebar становится sticky с фиксированной высотой
+ Высота = 100vh - navbar - 2*отступ (сверху и снизу)
+ top = navbar + отступ сверху
+ Не перемещается с основным скролом страницы, имеет свой внутренний скролл */
+@media (min-width: 992px) {
+ #sidebar.offcanvas-lg {
+ position: sticky;
+ top: calc(var(--navbar-h, 60px) + var(--layout-padding-y, 12px));
+ height: calc(100dvh - var(--navbar-h, 60px) - 2 * var(--layout-padding-y, 12px));
+ align-self: start;
+ overflow: auto;
+ border-right: .5px solid var(--bs-border-color);
+ transform: none !important;
+ visibility: visible !important;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ NAVIGATION SECTIONS
+────────────────────────────────────────────────────────────── */
+.side-section {
+ margin: var(--space-1) 0 var(--space-2);
+}
+
+.side-hd {
+ font-size: .78rem;
+ font-weight: 800;
+ letter-spacing: .03em;
+ text-transform: uppercase;
+ color: var(--bs-secondary-color);
+ padding: var(--space-1);
+ margin: 0 0 var(--space-1) var(--space-1);
+}
+
+.side-nav {
+ display: flex;
+ flex-direction: column;
+ gap: .15rem;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ NAV LINKS
+────────────────────────────────────────────────────────────── */
+.side-nav {
+ .nav-link {
+ position: relative;
+ display: flex;
+ align-items: center;
+ gap: .6rem;
+ padding: .48rem .55rem;
+ border-radius: $radius-md;
+ color: var(--bs-body-color);
+ text-decoration: none;
+ border: 0;
+ background: transparent !important;
+ line-height: 1.15;
+ @include transition((background, color, transform, box-shadow), $transition-fast);
+ outline: none;
+
+ /* мягкий ховер */
+ &:hover {
+ color: var(--bs-primary);
+ background: color-mix(in srgb, var(--bs-primary) 10%, transparent);
+ }
+
+ /* видимая клавиатурная фокусировка */
+ &:focus-visible {
+ @include focus-ring();
+ }
+
+ /* активная «пилюля» + тонкий индикатор слева */
+ &.active {
+ color: var(--bs-primary);
+ font-weight: 800;
+ background: color-mix(in srgb, var(--bs-primary) 16%, transparent);
+
+ &::before {
+ content: "";
+ position: absolute;
+ left: -6px;
+ top: 8px;
+ bottom: 8px;
+ width: 3px;
+ border-radius: 2px;
+ background: var(--bs-primary);
+ }
+ }
+
+ /* «отключённый» пункт выглядит реально disabled */
+ &.disabled {
+ opacity: .5;
+ pointer-events: none;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ICONS & BADGES
+────────────────────────────────────────────────────────────── */
+.side-icon {
+ width: 1.35rem;
+ height: 1.35rem;
+ display: inline-grid;
+ place-items: center;
+ flex: 0 0 auto;
+
+ > i {
+ font-size: 1.1rem;
+ line-height: 1;
+ }
+}
+
+.icon-wrap {
+ position: relative;
+ display: inline-grid;
+ place-items: center;
+}
+
+.nav-unread {
+ position: absolute;
+ top: -4px;
+ right: -8px;
+ min-width: 16px;
+ height: 16px;
+ padding: 0 var(--space-1);
+ border-radius: 9999px;
+ font-size: 10px;
+ line-height: 16px;
+ font-weight: 700;
+ background: var(--bs-danger);
+ color: #fff;
+ border: 1px solid rgba(255, 255, 255, .6);
+
+ [data-bs-theme="dark"] & {
+ border-color: rgba(0, 0, 0, .25);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ THEME SWITCHER BUTTON
+────────────────────────────────────────────────────────────── */
+.btn-theme {
+ display: inline-flex;
+ align-items: center;
+ gap: .5rem;
+ min-height: 36px;
+ padding: .35rem .75rem;
+ border-radius: 999px;
+ background: var(--bs-tertiary-bg);
+ color: var(--bs-body-color);
+ border: 1px solid var(--bs-border-color);
+ transition: transform .08s ease, background-color .25s ease, border-color .25s ease;
+
+ &:hover {
+ transform: translateY(-1px);
+ background: color-mix(in srgb, var(--bs-tertiary-bg) 90%, var(--bs-primary) 10%);
+ border-color: color-mix(in srgb, var(--bs-border-color), var(--bs-primary) 30%);
+ }
+
+ &:focus-visible {
+ outline: 0;
+ box-shadow: 0 0 0 2px rgba(var(--bs-primary-rgb), .25);
+ }
+
+ .bi {
+ font-size: 1rem;
+ line-height: 1;
+ }
+
+ .mode-label {
+ font-weight: 700;
+ font-size: .85rem;
+ opacity: .9;
+
+ @media (max-width: 576px) {
+ display: none;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/_spacing-utils.scss b/backend/static/scss_backup_20260115/components/_spacing-utils.scss
new file mode 100644
index 00000000..26b83f55
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_spacing-utils.scss
@@ -0,0 +1,136 @@
+/**
+ * spacing-utils.scss
+ * Утилиты для точного контроля отступов
+ *
+ * Использование CSS переменных из variables.css для унифицированных отступов
+ */
+
+/* =====================================
+ GAP UTILITIES
+===================================== */
+
+// Gap для flex/grid контейнеров
+.gap-component {
+ gap: var(--gap-component); // 16px - стандартный gap между элементами
+}
+
+.gap-section {
+ gap: var(--gap-section); // 24px - gap между секциями
+}
+
+.gap-1 {
+ gap: var(--space-1); // 8px
+}
+
+.gap-2 {
+ gap: var(--space-2); // 16px
+}
+
+.gap-3 {
+ gap: var(--space-3); // 24px
+}
+
+.gap-4 {
+ gap: var(--space-4); // 32px
+}
+
+/* =====================================
+ MARGIN UTILITIES
+===================================== */
+
+// Margin bottom для секций и блоков
+.mb-section {
+ margin-bottom: var(--margin-section); // 24px - между секциями
+}
+
+.mb-block {
+ margin-bottom: var(--margin-block); // 32px - между блоками
+}
+
+// Margin на всех сторонах
+.my-section {
+ margin-block: var(--margin-section); // 24px сверху/снизу
+}
+
+.my-block {
+ margin-block: var(--margin-block); // 32px сверху/снизу
+}
+
+/* =====================================
+ PADDING UTILITIES
+===================================== */
+
+// Padding для карточек
+.p-card {
+ padding: var(--card-padding); // 16px со всех сторон
+}
+
+.p-card-sm {
+ padding: var(--card-padding-sm); // 8px со всех сторон
+}
+
+.p-card-lg {
+ padding: var(--card-padding-lg); // 24px со всех сторон
+}
+
+// Padding по осям
+.px-card {
+ padding-inline: var(--card-padding); // 16px лево/право
+}
+
+.py-card {
+ padding-block: var(--card-padding); // 16px верх/низ
+}
+
+.px-card-sm {
+ padding-inline: var(--card-padding-sm); // 8px лево/право
+}
+
+.py-card-sm {
+ padding-block: var(--card-padding-sm); // 8px верх/низ
+}
+
+.px-card-lg {
+ padding-inline: var(--card-padding-lg); // 24px лево/право
+}
+
+.py-card-lg {
+ padding-block: var(--card-padding-lg); // 24px верх/низ
+}
+
+/* =====================================
+ RESPONSIVE UTILITIES
+===================================== */
+
+// Адаптивный gap для мобильных
+@media (max-width: 576px) {
+ .gap-component-mobile {
+ gap: var(--space-1); // 8px на мобильных
+ }
+
+ .p-card-mobile {
+ padding: var(--card-padding-sm); // 8px на мобильных
+ }
+}
+
+/* =====================================
+ КОМБИНИРОВАННЫЕ КЛАССЫ
+===================================== */
+
+// Стандартная секция с отступами
+.section-spacing {
+ margin-bottom: var(--margin-section); // 24px снизу
+ padding: var(--card-padding); // 16px внутри
+}
+
+// Компактная секция
+.section-spacing-sm {
+ margin-bottom: var(--space-2); // 16px снизу
+ padding: var(--card-padding-sm); // 8px внутри
+}
+
+// Просторная секция
+.section-spacing-lg {
+ margin-bottom: var(--margin-block); // 32px снизу
+ padding: var(--card-padding-lg); // 24px внутри
+}
diff --git a/backend/static/scss_backup_20260115/components/_team-wheel.scss b/backend/static/scss_backup_20260115/components/_team-wheel.scss
new file mode 100644
index 00000000..702513b1
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/_team-wheel.scss
@@ -0,0 +1,210 @@
+// =============================================================================
+// Team Wheel Component (SCSS)
+// =============================================================================
+// Круговой прокручиваемый виджет сотрудников
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+$wheel-size: 200px;
+$ava-size: 52px;
+$arc-width: 4px;
+
+// =============================================================================
+// CSS ПЕРЕМЕННЫЕ
+// =============================================================================
+
+:root {
+ --wheel-size: #{$wheel-size};
+ --ava-size: #{$ava-size};
+ --ring-bg: radial-gradient(
+ ellipse at center,
+ var(--bs-body-bg),
+ color-mix(in srgb, var(--bs-body-bg) 85%, var(--bs-secondary-bg, #f7f7f9) 15%)
+ );
+ --ring-border: var(--bs-border-color, rgba(0, 0, 0, 0.125));
+ --shadow-inset: 0 8px 24px rgba(0, 0, 0, 0.06) inset;
+ --shadow-out: 0 4px 12px rgba(0, 0, 0, 0.05);
+ --arc-width: #{$arc-width};
+ --arc-track: color-mix(in srgb, var(--bs-secondary-color) 30%, transparent);
+ --arc-prog: var(--bs-primary);
+}
+
+// =============================================================================
+// TEAM WRAP & WHEEL
+// =============================================================================
+
+.team-wrap {
+ width: var(--wheel-size);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-inline: auto;
+}
+
+.team-wheel {
+ position: relative;
+ width: var(--wheel-size);
+ height: var(--wheel-size);
+ border-radius: 50%;
+ overflow: hidden;
+ background: var(--ring-bg);
+ border: 1px solid var(--ring-border);
+ box-shadow: var(--shadow-inset);
+ user-select: none;
+ touch-action: none;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+// =============================================================================
+// WHEEL LAYOUT
+// =============================================================================
+
+.wheel-plane {
+ position: absolute;
+ inset: 0;
+}
+
+.wheel-columns {
+ position: absolute;
+ inset: 10px var(--space-1);
+ display: flex;
+ gap: var(--space-1);
+ justify-content: space-between;
+ align-items: flex-start;
+ will-change: transform;
+}
+
+.wheel-col {
+ width: calc(25% - 6px);
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-1);
+ align-items: center;
+
+ &.col-2 {
+ margin-top: calc(var(--ava-size) * 0.5);
+ }
+
+ &.col-3 {
+ margin-top: calc(var(--ava-size) * 1);
+ }
+
+ &.col-4 {
+ margin-top: calc(var(--ava-size) * 1.5);
+ }
+}
+
+// =============================================================================
+// WHEEL ITEMS
+// =============================================================================
+
+.wheel-item {
+ background: transparent;
+ border: 0;
+ padding: 0;
+ width: var(--ava-size);
+ height: var(--ava-size);
+ border-radius: 50%;
+ cursor: pointer;
+ box-shadow: var(--shadow-out);
+
+ .ava {
+ width: 100%;
+ height: 100%;
+ border-radius: 50%;
+ overflow: hidden;
+ display: grid;
+ place-items: center;
+ background: var(--bs-tertiary-bg);
+ border: 1px solid var(--bs-border-color);
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ }
+
+ .bi {
+ font-size: 1.2rem;
+ opacity: 0.5;
+ }
+ }
+
+ &:active {
+ transform: scale(0.96);
+ }
+}
+
+// =============================================================================
+// PROGRESS RING
+// =============================================================================
+
+.progress-ring {
+ position: absolute;
+ inset: -1px;
+ transform: rotate(-90deg);
+ pointer-events: none;
+}
+
+.progress-ring__circle {
+ stroke: var(--arc-track);
+ fill: none;
+ stroke-width: var(--arc-width);
+ stroke-linecap: round;
+}
+
+.progress-ring__prog {
+ stroke: var(--arc-prog);
+ fill: none;
+ stroke-width: var(--arc-width);
+ stroke-linecap: round;
+ transition: stroke-dashoffset 0.35s;
+}
+
+// =============================================================================
+// CONTROLS
+// =============================================================================
+
+.team-controls {
+ margin-top: var(--space-2);
+ display: flex;
+ gap: var(--space-1);
+ align-items: center;
+}
+
+.team-nav {
+ padding: var(--space-1);
+ border: 1px solid var(--bs-border-color);
+ background: var(--bs-body-bg);
+ border-radius: 8px;
+
+ &:active:not(:disabled) {
+ transform: scale(0.96);
+ }
+
+ &:disabled {
+ opacity: 0.4;
+ cursor: not-allowed;
+ }
+}
+
+.team-dots {
+ display: flex;
+ gap: 6px;
+ align-items: center;
+}
+
+.team-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: color-mix(in srgb, var(--bs-secondary-color), transparent 70%);
+
+ &.active {
+ background: var(--bs-primary);
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_chat-date-groups.scss b/backend/static/scss_backup_20260115/components/chat/_chat-date-groups.scss
new file mode 100644
index 00000000..41ad1bcc
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_chat-date-groups.scss
@@ -0,0 +1,183 @@
+/**
+ * _chat-date-groups.scss
+ * Стили для группировки сообщений по датам
+ * Основано на Telegram Web архитектуре
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ MESSAGE DATE GROUP
+────────────────────────────────────────────────────────────── */
+.message-date-group {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ STICKY DATE HEADER
+────────────────────────────────────────────────────────────── */
+.sticky-date {
+ position: sticky;
+ top: 56px;
+ z-index: 2;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 12px 16px;
+ margin: 0;
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: var(--bs-secondary);
+ text-align: center;
+ background-color: transparent;
+ pointer-events: none;
+ transition: opacity 0.15s ease, background-color 0.2s ease;
+
+ span {
+ display: inline-block;
+ padding: 6px 12px;
+ border-radius: 12px;
+ background-color: var(--bs-light);
+ pointer-events: all;
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
+ transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.15s ease;
+ }
+
+ &.interactive span {
+ cursor: pointer;
+ user-select: none;
+
+ &:hover {
+ background-color: var(--bs-primary);
+ color: white;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ transform: translateY(-1px);
+ }
+
+ &:active {
+ transform: translateY(0);
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
+ }
+
+ &:focus-visible {
+ outline: 2px solid var(--bs-primary);
+ outline-offset: 2px;
+ }
+ }
+
+ &.is-sticky span {
+ background-color: rgba(255, 255, 255, 0.95);
+ backdrop-filter: blur(10px);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MESSAGES CONTAINER
+────────────────────────────────────────────────────────────── */
+.messages-container {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ gap: 0;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ LOADING STATE
+────────────────────────────────────────────────────────────── */
+.message-date-group.loading .sticky-date span {
+ animation: pulse 1.5s ease-in-out infinite;
+ background: linear-gradient(
+ 90deg,
+ var(--bs-light) 25%,
+ rgba(0, 0, 0, 0.05) 50%,
+ var(--bs-light) 75%
+ );
+ background-size: 200% 100%;
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ background-position: 200% 0;
+ }
+ 50% {
+ background-position: 0 0;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ RESPONSIVE DESIGN
+────────────────────────────────────────────────────────────── */
+@media (max-width: 576px) {
+ .sticky-date {
+ top: 48px;
+ padding: 10px 12px;
+ font-size: 0.8125rem;
+
+ span {
+ padding: 5px 10px;
+ border-radius: 10px;
+ }
+ }
+}
+
+@media (min-width: 577px) and (max-width: 992px) {
+ .sticky-date {
+ top: 52px;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ DARK MODE SUPPORT
+────────────────────────────────────────────────────────────── */
+@media (prefers-color-scheme: dark) {
+ .sticky-date {
+ color: var(--bs-light);
+
+ span {
+ background-color: rgba(52, 58, 64, 0.95);
+ color: var(--bs-light);
+ }
+
+ &.interactive span:hover {
+ background-color: var(--bs-primary);
+ color: white;
+ }
+
+ &.is-sticky span {
+ background-color: rgba(52, 58, 64, 0.98);
+ backdrop-filter: blur(10px);
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ACCESSIBILITY
+────────────────────────────────────────────────────────────── */
+@media (prefers-contrast: high) {
+ .sticky-date span {
+ border: 1px solid currentColor;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .sticky-date,
+ .sticky-date span {
+ transition: none;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ PRINT STYLES
+────────────────────────────────────────────────────────────── */
+@media print {
+ .sticky-date {
+ position: static;
+ page-break-inside: avoid;
+
+ &.interactive span {
+ cursor: default;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_chat-detail.scss b/backend/static/scss_backup_20260115/components/chat/_chat-detail.scss
new file mode 100644
index 00000000..4de8eed3
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_chat-detail.scss
@@ -0,0 +1,901 @@
+/**
+ * chat-detail.scss
+ * Стили детального чата: scroll, bubbles, composer
+ * Layout вынесен в layout/_chat-layout.scss
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT PAGE CONTAINER
+────────────────────────────────────────────────────────────── */
+.chat-page {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ // Учитываем высоту navbar сверху
+ height: calc(100vh - var(--navbar-h, 60px));
+ overflow: hidden;
+}
+
+.chat-header {
+ flex-shrink: 0;
+ z-index: $z-dropdown - 1;
+ background: var(--bs-body-bg);
+ border-bottom: 1px solid var(--bs-border-color);
+ padding: var(--space-3) var(--space-4);
+
+ &-content {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: var(--space-3);
+ }
+
+ &-title {
+ display: flex;
+ align-items: center;
+ gap: var(--space-3);
+ flex: 1;
+ min-width: 0;
+
+ h1 {
+ font-size: 1.25rem;
+ font-weight: 600;
+ margin: 0;
+ color: var(--bs-body-color);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
+
+ i {
+ font-size: 1.5rem;
+ color: var(--bs-primary);
+ flex-shrink: 0;
+ }
+ }
+
+ &-actions {
+ display: flex;
+ align-items: center;
+ gap: var(--space-2);
+ flex-shrink: 0;
+ }
+}
+
+// Mobile стили для header
+@media (max-width: 767.98px) {
+ .chat-header {
+ padding: var(--space-2) var(--space-3);
+
+ &-title {
+ gap: var(--space-2);
+
+ h1 {
+ font-size: 1.125rem;
+ }
+
+ i {
+ font-size: 1.25rem;
+ }
+ }
+
+ &-actions {
+ gap: var(--space-1);
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT CONTAINER (основной контейнер чата)
+────────────────────────────────────────────────────────────── */
+.chat-container {
+ // Естественный размер контента, не растягиваем
+ flex: 1 1 auto;
+
+ // Вертикальный flex для: alerts → messages → typing
+ display: flex;
+ flex-direction: column;
+
+ // Критично для работы overflow в дочерних элементах
+ min-height: 0;
+
+ // Предотвращает переполнение, scroll делегируется .chat-messages-scroll
+ overflow: hidden;
+
+ // Для позиционирования scroll-to-bottom кнопки
+ position: relative;
+
+ // Опциональный background для тестирования layout
+ // background: var(--bs-body-bg);
+
+ // Alerts внутри контейнера не должны сжиматься
+ > .alert {
+ flex-shrink: 0;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT MESSAGES SCROLL (основной контейнер сообщений)
+────────────────────────────────────────────────────────────── */
+.chat-messages-scroll {
+ flex: 1 0 0;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: var(--space-3);
+ min-height: 0;
+ scroll-behavior: smooth;
+ -webkit-overflow-scrolling: touch;
+ scrollbar-width: thin;
+ scrollbar-gutter: stable;
+ overscroll-behavior: contain;
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 70%) transparent;
+
+ &:hover {
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 55%) transparent;
+ }
+
+ // Кастомный скроллбар для WebKit
+ &::-webkit-scrollbar {
+ width: 8px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 75%);
+ border-radius: 4px;
+ }
+
+ &:hover::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 55%);
+ }
+}
+
+// Алиас для совместимости
+.chat-scroll {
+ @extend .chat-messages-scroll;
+}
+
+.chat-scroll {
+ @include custom-scrollbar(color-mix(in srgb, var(--bs-body-color), transparent 75%));
+
+ &:hover {
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 55%) transparent;
+ }
+}
+
+[data-bs-theme="dark"] .chat-scroll {
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 78%) transparent;
+
+ &:hover {
+ scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 60%) transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 78%);
+ }
+
+ &:hover::-webkit-scrollbar-thumb {
+ background-color: color-mix(in srgb, var(--bs-body-color), transparent 60%);
+ }
+}
+
+@media (hover: none), (pointer: coarse) {
+ .chat-scroll {
+ scrollbar-width: none;
+ }
+
+ .chat-scroll::-webkit-scrollbar {
+ display: none;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT COMPOSER WRAPPER & COMPOSER (Modern Messenger Style)
+────────────────────────────────────────────────────────────── */
+// TODO: Проблема с пустым пространством под композером на широких экранах
+// При изменении ширины окна высота navbar меняется, но calc(100vh - var(--navbar-h))
+// не всегда корректно работает. Нужно найти более надежное решение для прижатия
+// композера к низу страницы независимо от размера viewport.
+.chat-composer-wrapper {
+ flex-shrink: 0;
+ margin-top: auto; // Прижимаем к низу chat-page
+ position: relative;
+ z-index: $z-base;
+ background: var(--bs-body-bg);
+ border-top: 1px solid var(--bs-border-color);
+ padding: var(--space-2);
+ padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
+}
+
+// Mobile стили для composer - фиксируем внизу экрана (замена bottom navbar)
+@media (max-width: 767.98px) {
+ .chat-composer-wrapper {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ padding: var(--space-2) var(--space-2);
+ padding-bottom: calc(var(--space-2) + env(safe-area-inset-bottom));
+ border-top: 1px solid var(--bs-border-color);
+ background: var(--bs-body-bg);
+ z-index: 1020; // Над контентом, но под модалами
+ }
+
+ // Уменьшенный padding для мобильных + компенсация высоты фиксированного composer
+ .chat-messages-scroll {
+ padding: var(--space-2);
+ padding-bottom: calc(70px + env(safe-area-inset-bottom)); // Высота composer
+ }
+}
+
+.composer-wrap {
+ display: flex;
+ flex-direction: column;
+ gap: var(--space-1);
+}
+
+.message-field {
+ background: color-mix(in srgb, var(--bs-body-bg) 96%, transparent);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 30%);
+}
+
+.message-input {
+ max-height: 180px;
+}
+
+// Стили кнопок наследуются из custom-bootstrap.scss (glassmorphism)
+.btn-send {
+ box-shadow: 0 4px 16px rgba(var(--bs-primary-rgb), 0.35);
+}
+
+.message-emoji .dropdown-menu {
+ background: var(--bs-body-bg);
+}
+
+/* Превью вложений */
+.attachment-preview {
+ padding: var(--space-1) 0;
+ max-height: 200px;
+ overflow-y: auto;
+ max-width: 100%;
+ width: 100%;
+}
+
+.attachment-item {
+ background: var(--bs-secondary-bg);
+ @include transition(background-color, $transition-fast);
+ max-width: 100%; // Ограничиваем ширину контейнера
+}
+
+/* Обрезка текста в форме загрузки файлов */
+.attachment-item .flex-grow-1 {
+ min-width: 0; // Важно для flex-элементов с text-truncate внутри
+ overflow: hidden; // Предотвращаем выход контента за границы
+}
+
+.attachment-item .text-truncate {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ min-width: 0;
+}
+
+/* Вложения в сообщениях */
+.bubble .attachment-item {
+ background: transparent;
+ padding: 0;
+ margin-bottom: 8px;
+
+ // Медиа-элементы (изображения и видео) - минимальные отступы
+ &.attachment-item--media {
+ margin-bottom: 0;
+
+ a {
+ display: block;
+ padding: 0;
+ line-height: 0;
+ }
+ }
+}
+
+// Стили только для ссылок на файлы (документы)
+.bubble .attachment-item:not(.attachment-item--media) a {
+ display: flex;
+ align-items: center;
+ gap: 0.5rem;
+ padding: 0.5rem 0.75rem;
+ border-radius: $radius-sm;
+ text-decoration: none;
+ border: none;
+ @include transition-all($transition-fast);
+ max-width: 100%;
+ word-break: break-word;
+}
+
+// Attachment links in regular messages (other person)
+.bubble-other .attachment-item a {
+ background: rgba(0, 0, 0, 0.05);
+ color: inherit;
+}
+
+.bubble-other .attachment-item a:hover {
+ background: rgba(0, 0, 0, 0.08);
+}
+
+// Attachment links in own messages
+.bubble-me .attachment-item a {
+ background: rgba(255, 255, 255, 0.15);
+ color: rgba(255, 255, 255, 0.95);
+}
+
+.bubble-me .attachment-item a:hover {
+ background: rgba(255, 255, 255, 0.25);
+}
+
+// Icons in attachments
+.bubble .attachment-item a i {
+ font-size: 1.1rem;
+ flex-shrink: 0;
+}
+
+.bubble-me .attachment-item a i {
+ color: rgba(255, 255, 255, 0.9);
+}
+
+// Text truncation for file names
+.bubble .attachment-item a span {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ min-width: 0; // Important for flex items
+}
+
+.message-attachments video,
+.message-attachments img,
+.message-attachments audio {
+ max-width: 100%;
+ width: auto;
+ border-radius: $radius-sm;
+}
+
+// TODO: Исследовать почему у медиа остаются большие отступы
+// Возможные причины: кэш браузера, конфликты с Bootstrap, line-height на родителях
+// Попробовать: добавить !important, проверить в DevTools computed styles
+// Убираем верхний отступ если вложение - только медиа без текста
+.message-attachments:has(.attachment-item--media):not(:has(.attachment-item:not(.attachment-item--media))) {
+ margin-top: 0.25rem; // Уменьшенный отступ для медиа (вместо mt-2 = 0.5rem)
+}
+
+.chat-media {
+ display: block;
+ width: auto;
+ max-width: min(640px, 85vw);
+ max-height: 520px;
+ border-radius: $radius-md;
+ background: rgba(0, 0, 0, 0.08);
+ content-visibility: auto;
+ vertical-align: top;
+}
+
+// Telegram approach: изображения с aspect-ratio занимают полную ширину контейнера
+// Это позволяет браузеру резервировать место до загрузки → нет скачка скролла
+.chat-media--image[style*="aspect-ratio"] {
+ width: 100% !important;
+ height: auto !important;
+}
+
+// Убираем этот конфликтующий селектор - заменяем на более специфичный
+.message-attachments .attachment-item:not(.attachment-item--media) > a,
+.message-attachments .attachment-item:not(.attachment-item--media) > video,
+.message-attachments .attachment-item:not(.attachment-item--media) > img {
+ display: inline-flex;
+ max-width: 100%;
+}
+
+.chat-media--video {
+ background: #000;
+ object-fit: contain;
+}
+
+.chat-media--image {
+ object-fit: cover;
+}
+
+.message-pending .chat-media {
+ min-width: 90px;
+ min-height: 64px;
+}
+
+.message-pending .bubble {
+ position: relative;
+ opacity: 0.8;
+}
+
+.message-pending .message-status {
+ color: rgba(255, 255, 255, 0.8);
+}
+
+/* Состояния сообщений */
+.message-failed {
+ opacity: 0.6;
+
+ .bubble {
+ border: 1px solid var(--bs-danger);
+ background: color-mix(in srgb, var(--bs-danger) 10%, transparent);
+ }
+}
+
+.message-highlighted {
+ animation: messageHighlight 1s ease-in-out;
+
+ .bubble {
+ background: color-mix(in srgb, var(--bs-warning) 20%, var(--bs-secondary-bg)) !important;
+ }
+}
+
+@keyframes messageHighlight {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.02);
+ }
+}
+
+/* Режим выделения сообщений */
+.selection-mode {
+ .msg {
+ cursor: pointer;
+ transition: background-color $transition-fast;
+
+ &:hover {
+ background: var(--bs-tertiary-bg);
+ }
+
+ &.selected {
+ background: color-mix(in srgb, var(--bs-primary) 10%, transparent);
+ }
+ }
+
+ .msg-select-checkbox {
+ position: absolute;
+ left: var(--space-1);
+ top: 50%;
+ transform: translateY(-50%);
+ width: 24px;
+ height: 24px;
+ border: 2px solid var(--bs-border-color);
+ @include radius(50%);
+ background: var(--bs-body-bg);
+ cursor: pointer;
+ transition: all $transition-fast;
+ @include flex-center();
+ z-index: 2;
+
+ &::after {
+ content: '\f26b'; // Bootstrap icon checkmark
+ font-family: 'bootstrap-icons';
+ color: #fff;
+ font-size: 12px;
+ opacity: 0;
+ transform: scale(0);
+ transition: all $transition-fast;
+ }
+
+ &.selected {
+ background: var(--bs-primary);
+ border-color: var(--bs-primary);
+
+ &::after {
+ opacity: 1;
+ transform: scale(1);
+ }
+ }
+ }
+}
+
+.bubble-other .message-status {
+ color: rgba(0, 0, 0, 0.5);
+}
+
+.message-attachments .text-secondary {
+ color: inherit;
+ opacity: 0.7;
+}
+
+.bubble-me .message-attachments .text-secondary {
+ color: rgba(255, 255, 255, 0.9) !important;
+ opacity: 1;
+}
+
+.bubble-me .message-attachments .fw-semibold {
+ color: rgba(255, 255, 255, 0.95) !important;
+}
+
+.bubble-me .message-attachments i {
+ color: rgba(255, 255, 255, 0.9) !important;
+}
+
+.history-loader {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ padding: 0.75rem 0;
+ color: var(--bs-secondary-color);
+}
+
+.history-loader .spinner-border {
+ width: 1rem;
+ height: 1rem;
+}
+
+/* Выпадающее меню вложений */
+.dropdown-menu {
+ min-width: 200px;
+ border-radius: $radius-md;
+ @include shadow($shadow-md);
+ padding: 8px;
+}
+
+.dropdown-item {
+ border-radius: $radius-sm;
+ padding: 10px 12px;
+ @include transition(background-color, $transition-fast);
+}
+
+.dropdown-item:hover {
+ background: var(--bs-secondary-bg);
+}
+
+.dropdown-item i {
+ width: 24px;
+}
+
+.composer-tools {
+ display: flex;
+ gap: var(--space-1);
+ align-items: center;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ TYPING INDICATOR
+────────────────────────────────────────────────────────────── */
+.chat-typing-indicator {
+ padding: var(--space-2) var(--space-3);
+ display: flex;
+ align-items: center;
+ gap: var(--space-2);
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+ font-style: italic;
+ background: var(--bs-body-bg);
+ border-top: 1px solid var(--bs-border-color);
+ flex-shrink: 0;
+
+ &.d-none {
+ display: none !important;
+ }
+}
+
+.typing-dots {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+
+ span {
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: var(--bs-secondary-color);
+ opacity: 0.6;
+ animation: typingBounce 1.4s infinite both;
+
+ &:nth-child(2) {
+ animation-delay: 0.2s;
+ }
+
+ &:nth-child(3) {
+ animation-delay: 0.4s;
+ }
+ }
+}
+
+@keyframes typingBounce {
+ 0%, 60%, 100% {
+ transform: translateY(0);
+ }
+ 30% {
+ transform: translateY(-8px);
+ }
+}
+
+.typing-text {
+ font-size: 0.875rem;
+ color: var(--bs-secondary-color);
+}
+
+/* ─────────────────────────────────────────────────────────────
+ HISTORY LOADER
+────────────────────────────────────────────────────────────── */
+.history-loader {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--space-2);
+ padding: var(--space-3) 0;
+ color: var(--bs-secondary-color);
+ font-size: 0.875rem;
+
+ .spinner-border {
+ width: 1rem;
+ height: 1rem;
+ border-width: 2px;
+ }
+
+ &.d-none {
+ display: none !important;
+ }
+}
+
+.initial-loader {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: var(--space-5) 0;
+ color: var(--bs-secondary-color);
+
+ .spinner-border {
+ width: 3rem;
+ height: 3rem;
+ }
+
+ p {
+ margin-top: var(--space-3);
+ font-size: 1rem;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ SCROLL TO BOTTOM BUTTON
+────────────────────────────────────────────────────────────── */
+.scroll-to-bottom {
+ position: fixed;
+ right: var(--space-3);
+ bottom: calc(var(--space-3) + 80px);
+ z-index: $z-dropdown;
+ display: none;
+ width: 44px;
+ height: 44px;
+ @include circle();
+ padding: 0 !important;
+ border: none !important;
+ background: var(--bs-primary) !important;
+ color: #fff !important;
+ @include shadow($shadow-lg, rgba(var(--bs-primary-rgb), 0.25));
+ @include transition((transform, box-shadow), $transition-fast);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ opacity: 0;
+ pointer-events: none;
+
+ i {
+ font-size: 1.25rem;
+ }
+
+ &:hover {
+ transform: scale(1.08);
+ box-shadow: 0 6px 20px rgba(var(--bs-primary-rgb), 0.35) !important;
+ }
+
+ &:active {
+ transform: scale(0.95);
+ }
+}
+
+.scroll-to-bottom.show {
+ display: inline-flex;
+ opacity: 1;
+ pointer-events: auto;
+ animation: fadeInUp 0.3s ease;
+}
+
+/* Badge непрочитанных на кнопке скролла */
+.scroll-to-bottom {
+ position: relative; // Для позиционирования badge
+
+ .unread-badge {
+ position: absolute;
+ top: -6px;
+ right: -6px;
+ min-width: 20px;
+ height: 20px;
+ padding: 0 6px;
+ @include flex-center();
+ @include radius($badge-radius);
+ background: var(--bs-danger);
+ color: #fff;
+ font-size: 11px;
+ font-weight: 600;
+ line-height: 1;
+ @include shadow($shadow-md);
+ transition: opacity $transition-fast, transform $transition-fast;
+ z-index: 1;
+
+ // Скрытое состояние
+ &.badge-hidden {
+ opacity: 0;
+ transform: scale(0.5);
+ pointer-events: none;
+ }
+ }
+
+ // Когда есть непрочитанные
+ &.has-unread {
+ .unread-badge {
+ opacity: 1;
+ transform: scale(1);
+ animation: badgePulse 2s ease-in-out infinite;
+ }
+ }
+}
+
+@keyframes badgePulse {
+ 0%, 100% {
+ box-shadow: 0 2px 8px rgba(var(--bs-danger-rgb), 0.3);
+ }
+ 50% {
+ box-shadow: 0 2px 12px rgba(var(--bs-danger-rgb), 0.5);
+ }
+}
+
+@keyframes fadeInUp {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+// Mobile стили для scroll button
+@media (max-width: 767.98px) {
+ .scroll-to-bottom {
+ right: var(--space-2);
+ bottom: calc(var(--space-2) + 70px); // Учитываем composer на мобилке
+ width: 40px;
+ height: 40px;
+
+ i {
+ font-size: 1.125rem;
+ }
+
+ .unread-badge {
+ top: -4px;
+ right: -4px;
+ min-width: 18px;
+ height: 18px;
+ font-size: 10px;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MESSAGES LAYOUT
+────────────────────────────────────────────────────────────── */
+// Выравнивание аватара по низу сообщения
+.d-flex.msg {
+ align-items: flex-end;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ BUBBLES & AVATARS
+────────────────────────────────────────────────────────────── */
+.bubble {
+ border-radius: $radius-lg;
+ padding: var(--space-1) var(--space-2);
+ word-break: break-word;
+ white-space: pre-line; /* Сохраняет \n, но схлопывает пробелы из HTML */
+ max-width: 70%; /* Ограничиваем ширину bubble */
+ @include shadow($shadow-xs);
+ user-select: text; /* Разрешаем выделение текста */
+ cursor: text; /* Курсор текстового выделения */
+
+ // Наследование white-space для вложенных элементов
+ > div {
+ white-space: inherit;
+ }
+
+ // Специально для голосований - схлопываем whitespace
+ .poll-widget,
+ .poll-question,
+ .poll-options,
+ .poll-option,
+ .poll-footer {
+ white-space: normal;
+ }
+}
+
+.bubble-me {
+ background: color-mix(in srgb, var(--bs-primary) 92%, #fff 0%);
+ color: #fff;
+}
+
+.bubble-other {
+ background: var(--bs-secondary-bg);
+ color: var(--bs-body-color);
+}
+
+.mini-ava {
+ width: 32px;
+ height: 32px;
+ flex-shrink: 0; /* Не сжимать аватар */
+ border-radius: 50%;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: var(--bs-tertiary-bg);
+ border: 1px solid var(--bs-border-color);
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover; /* Кадрируем без деформации */
+ display: block;
+ }
+
+ i {
+ font-size: 20px;
+ color: var(--bs-secondary-color);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ DIVIDERS (день / непрочитанные)
+────────────────────────────────────────────────────────────── */
+.day-divider,
+.unread-divider {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--space-1);
+ margin: var(--space-1) 0 var(--space-2);
+ font-size: 0.85rem;
+ line-height: 1;
+ font-weight: 700;
+ pointer-events: none;
+ user-select: none;
+}
+
+.day-divider::before,
+.day-divider::after,
+.unread-divider::before,
+.unread-divider::after {
+ content: "";
+ flex: 1 1 auto;
+ height: 1px;
+ background: color-mix(in srgb, var(--bs-border-color), transparent 30%);
+}
+
+.day-divider > span,
+.unread-divider > span {
+ flex: 0 0 auto;
+ padding: 0 var(--space-1);
+ background: transparent;
+}
+
+.day-divider {
+ color: var(--bs-secondary-color);
+}
+
+.unread-divider {
+ color: var(--bs-danger);
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_chat-enhanced.scss b/backend/static/scss_backup_20260115/components/chat/_chat-enhanced.scss
new file mode 100644
index 00000000..cf37029d
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_chat-enhanced.scss
@@ -0,0 +1,298 @@
+/**
+ * _chat-enhanced.scss
+ * Enhanced chat features: replies, forwards, reactions, attachments
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ REPLY PREVIEW
+────────────────────────────────────────────────────────────── */
+.reply-preview {
+ font-size: 0.85rem;
+ padding: 4px 8px;
+ background: rgba(0, 0, 0, 0.05);
+ border-left: 3px solid var(--bs-primary);
+ border-radius: $radius-xs;
+
+ i {
+ color: var(--bs-primary);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ FORWARD INFO
+────────────────────────────────────────────────────────────── */
+.forward-info {
+ font-size: 0.85rem;
+ color: var(--bs-secondary);
+ font-style: italic;
+
+ i {
+ color: var(--bs-info);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MESSAGE ACTIONS (shown on hover)
+────────────────────────────────────────────────────────────── */
+.msg {
+ position: relative;
+
+ &:hover .message-actions {
+ opacity: 1;
+ }
+
+ &:hover .quick-reactions {
+ opacity: 1;
+ pointer-events: all;
+ }
+
+ &.new {
+ animation: slideIn 0.3s ease-out;
+ }
+
+ &.system-message {
+ justify-content: center !important;
+
+ .bubble {
+ background: #f8f9fa;
+ border: 1px dashed #dee2e6;
+ color: #6c757d;
+ text-align: center;
+ font-size: 0.9rem;
+ font-style: italic;
+ }
+ }
+
+ .bubble {
+ em.text-muted {
+ font-size: 0.9rem;
+ opacity: 0.7;
+ }
+
+ .bi-pencil-fill {
+ font-size: 0.7rem;
+ opacity: 0.6;
+ }
+
+ .bi-pin-angle-fill {
+ color: var(--bs-warning);
+ font-size: 1rem;
+ }
+ }
+}
+
+.message-actions {
+ position: absolute;
+ top: -12px;
+ right: 10px;
+ background: white;
+ border: 1px solid #dee2e6;
+ border-radius: $radius-pill;
+ padding: 2px 4px;
+ @include shadow($shadow-sm);
+ opacity: 0;
+ @include transition(opacity, $transition-fast);
+ z-index: 10;
+
+ .btn {
+ padding: 2px 6px;
+ font-size: 0.85rem;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ REACTIONS
+────────────────────────────────────────────────────────────── */
+.reactions {
+ display: flex;
+ gap: 4px;
+ flex-wrap: wrap;
+}
+
+.reaction-btn {
+ border: 1px solid #dee2e6;
+ background: white;
+ border-radius: $radius-md;
+ padding: 2px 8px;
+ font-size: 0.9rem;
+ cursor: pointer;
+ @include transition-all($transition-fast);
+
+ &:hover {
+ background: #f8f9fa;
+ transform: scale(1.1);
+ }
+
+ &.active {
+ background: #e3f2fd;
+ border-color: var(--bs-primary);
+ }
+
+ .count {
+ font-size: 0.75rem;
+ color: #666;
+ margin-left: 2px;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ QUICK REACTIONS (on hover)
+────────────────────────────────────────────────────────────── */
+.quick-reactions {
+ position: absolute;
+ bottom: -20px;
+ left: 50%;
+ transform: translateX(-50%);
+ background: white;
+ border: 1px solid #dee2e6;
+ border-radius: $radius-pill;
+ padding: 4px 8px;
+ @include shadow($shadow-md);
+ opacity: 0;
+ pointer-events: none;
+ @include transition(opacity, $transition-fast);
+ z-index: 20;
+ display: flex;
+ gap: 4px;
+
+ button {
+ border: none;
+ background: transparent;
+ font-size: 1.1rem;
+ padding: 4px 8px;
+ cursor: pointer;
+ border-radius: $radius-sm;
+ @include transition(background, $transition-fast);
+
+ &:hover {
+ background: #f0f0f0;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ATTACHMENTS
+────────────────────────────────────────────────────────────── */
+.attachments {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+}
+
+.attachment-image {
+ max-width: 200px;
+ max-height: 200px;
+ border-radius: $radius-sm;
+ cursor: pointer;
+ @include transition(transform, $transition-fast);
+
+ &:hover {
+ transform: scale(1.05);
+ }
+}
+
+.attachment-file {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 6px 12px;
+ background: rgba(0, 0, 0, 0.05);
+ border-radius: $radius-sm;
+ text-decoration: none;
+ color: inherit;
+ font-size: 0.9rem;
+
+ &:hover {
+ background: rgba(0, 0, 0, 0.1);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT LIST ITEMS
+────────────────────────────────────────────────────────────── */
+.chat-list-item {
+ position: relative;
+
+ &.pinned {
+ background: #fffbeb;
+ border-left: 4px solid var(--bs-warning);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ BADGES & INDICATORS
+────────────────────────────────────────────────────────────── */
+.mention-badge {
+ background: #ef4444;
+ color: white;
+ border-radius: 12px;
+ padding: 2px 8px;
+ font-size: 0.75rem;
+ font-weight: bold;
+}
+
+.thread-indicator {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 0.85rem;
+ color: var(--bs-primary);
+ cursor: pointer;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ INDICATORS
+────────────────────────────────────────────────────────────── */
+#typing {
+ padding: 4px 12px;
+ font-style: italic;
+}
+
+#editing-indicator,
+#reply-indicator {
+ margin-bottom: 8px;
+ border-radius: 8px;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ANIMATIONS
+────────────────────────────────────────────────────────────── */
+@keyframes slideIn {
+ from {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MOBILE RESPONSIVE
+────────────────────────────────────────────────────────────── */
+@media (max-width: 768px) {
+ .message-actions {
+ position: static;
+ opacity: 1;
+ margin-top: 8px;
+ }
+
+ .quick-reactions {
+ position: static;
+ transform: none;
+ opacity: 1;
+ pointer-events: all;
+ margin-top: 8px;
+ justify-content: center;
+ }
+
+ .attachment-image {
+ max-width: 150px;
+ max-height: 150px;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_chat-list-enhanced.scss b/backend/static/scss_backup_20260115/components/chat/_chat-list-enhanced.scss
new file mode 100644
index 00000000..90a5271b
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_chat-list-enhanced.scss
@@ -0,0 +1,320 @@
+/**
+ * _chat-list-enhanced.scss
+ * Enhanced chat list with context menus, animations, avatars
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ CONTEXT MENU
+────────────────────────────────────────────────────────────── */
+.context-menu {
+ position: absolute;
+ background: white;
+ border: 1px solid #dee2e6;
+ border-radius: $radius-sm;
+ @include shadow($shadow-md);
+ padding: 4px 0;
+ min-width: 200px;
+ z-index: 9999;
+
+ button {
+ width: 100%;
+ border: none;
+ background: transparent;
+ padding: 8px 16px;
+ text-align: left;
+ cursor: pointer;
+ font-size: 0.9rem;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+
+ &:hover {
+ background: #f8f9fa;
+ }
+ }
+
+ hr {
+ margin: 4px 0;
+ border-color: #dee2e6;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT ROW
+────────────────────────────────────────────────────────────── */
+.chat-row {
+ border-top: 1px solid var(--bs-border-color);
+ overflow: hidden;
+ min-height: 60px;
+
+ &.updated {
+ background: #e3f2fd;
+ @include transition(background, $transition-medium);
+ }
+
+ &.pinned {
+ background: #fffbeb;
+ border-left: 4px solid var(--bs-warning);
+ }
+
+ .flex-grow-1 {
+ min-width: 0;
+ overflow: hidden;
+
+ a,
+ .card-title {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 100%;
+ }
+ }
+
+ [data-last-preview],
+ .card-subtitle {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 100%;
+ }
+
+ &:hover .chat-actions-menu .btn {
+ opacity: 1;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT SECTION
+────────────────────────────────────────────────────────────── */
+.chat-section {
+ overflow: visible !important;
+ position: relative;
+ z-index: 1;
+
+ &:has(.dropdown-menu.show) {
+ z-index: 1000;
+ }
+
+ .card-header {
+ text-align: center;
+ border-bottom: 1px solid var(--bs-border-color);
+
+ .card-icon {
+ display: none;
+ }
+
+ .card-meta {
+ width: 100%;
+ text-align: center;
+ }
+ }
+
+ .list-chats {
+ overflow: visible !important;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT AVATARS - КРУГЛЫЕ!
+────────────────────────────────────────────────────────────── */
+.chat-avatar,
+.card-icon img,
+.chat-list-wrapper .card-icon,
+.chat-row .card-icon,
+.chat-section .card-icon {
+ border-radius: 50% !important;
+}
+
+.chat-avatar,
+.card-icon img {
+ width: 44px !important;
+ height: 44px !important;
+ object-fit: cover;
+ border: 2px solid var(--bs-border-color);
+}
+
+.chat-list-wrapper .card-icon,
+.chat-row .card-icon {
+ width: 44px !important;
+ height: 44px !important;
+ min-width: 44px;
+ min-height: 44px;
+ border-radius: 50% !important;
+ overflow: hidden;
+}
+
+.chat-avatar-group {
+ display: flex;
+ align-items: center;
+
+ img {
+ margin-left: -8px;
+ border: 2px solid white;
+ border-radius: 50% !important;
+
+ &:first-child {
+ margin-left: 0;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT ACTIONS MENU
+────────────────────────────────────────────────────────────── */
+.chat-actions-menu {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+
+ .btn {
+ opacity: 0;
+ @include transition(opacity, $transition-fast);
+
+ &:focus,
+ &[aria-expanded="true"] {
+ opacity: 1;
+ }
+ }
+
+ .dropdown-menu {
+ font-size: 0.9rem;
+ min-width: 200px;
+ z-index: 9999;
+ position: fixed !important;
+ }
+
+ .dropdown-item {
+ padding: 0.5rem 1rem;
+
+ i {
+ width: 20px;
+ text-align: center;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT TYPE SIDEBAR
+────────────────────────────────────────────────────────────── */
+:root {
+ --chat-sidebar-offset: 120px;
+}
+
+.chat-type-sidebar {
+ flex-shrink: 0;
+ align-self: flex-start;
+ position: sticky;
+ top: calc(var(--navbar-h, 60px) + var(--chat-sidebar-offset, 120px));
+
+ .card {
+ max-height: calc(100vh - var(--navbar-h, 60px) - var(--chat-sidebar-offset, 120px) - 24px);
+ overflow-y: auto;
+ }
+}
+
+.chat-type-btn {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 0.35rem;
+ position: relative;
+ cursor: pointer;
+ @include transition((background-color, opacity), $transition-fast);
+
+ &[style*="display: none"] {
+ display: none !important;
+ }
+
+ &:hover {
+ background-color: var(--bs-light) !important;
+ }
+
+ &.active {
+ background-color: var(--bs-primary) !important;
+ color: white !important;
+
+ i {
+ color: white;
+ }
+
+ .badge {
+ background-color: rgba(255, 255, 255, 0.3) !important;
+ color: white !important;
+ border-color: white !important;
+ }
+ }
+
+ .badge {
+ position: absolute;
+ top: 0.25rem;
+ right: 0.25rem;
+ min-width: 1.25rem;
+ height: 1.25rem;
+ padding: 0.15rem 0.3rem;
+ border-radius: 50%;
+ font-size: 0.65rem;
+ line-height: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MOBILE VERSION
+────────────────────────────────────────────────────────────── */
+@media (max-width: 768px) {
+ .chat-list-wrapper {
+ flex-direction: column !important;
+ }
+
+ .chat-type-sidebar {
+ width: 100% !important;
+ order: -1;
+ position: static;
+
+ .card {
+ max-height: none;
+ overflow: hidden;
+ padding: 0.25rem 0.5rem;
+ width: 100%;
+ }
+
+ .list-group {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ gap: 0.5rem;
+ width: 100%;
+ overflow-x: auto;
+ overflow-y: hidden;
+ padding: 0 0.25rem 0.25rem;
+ scrollbar-width: thin;
+ scroll-snap-type: x proximity;
+ -webkit-overflow-scrolling: touch;
+ }
+ }
+
+ .chat-type-btn {
+ flex: 0 0 auto;
+ min-width: 60px;
+ max-width: 80px;
+ padding: 0.5rem 0.25rem !important;
+ border-radius: 0.75rem !important;
+ border: 1px solid var(--bs-border-color) !important;
+ scroll-snap-align: start;
+
+ i {
+ font-size: 1.25rem !important;
+ }
+
+ .badge {
+ font-size: 0.6rem;
+ min-width: 1.1rem;
+ height: 1.1rem;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_chat-new-messages-indicator.scss b/backend/static/scss_backup_20260115/components/chat/_chat-new-messages-indicator.scss
new file mode 100644
index 00000000..f9f3c6f7
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_chat-new-messages-indicator.scss
@@ -0,0 +1,149 @@
+/**
+ * _chat-new-messages-indicator.scss
+ * Индикатор новых сообщений в чате
+ * Кнопка для прокрутки к новым сообщениям
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ NEW MESSAGES INDICATOR
+────────────────────────────────────────────────────────────── */
+.new-messages-indicator {
+ position: absolute;
+ bottom: 20px;
+ right: 20px;
+ z-index: 1000;
+ padding: 10px 16px;
+ min-width: 180px;
+ background: var(--bs-primary, #0d6efd);
+ color: white;
+ border: none;
+ border-radius: 24px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ font-size: 14px;
+ font-weight: 500;
+ opacity: 0;
+ transform: translateY(10px);
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ pointer-events: none;
+ display: none;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ cursor: pointer;
+
+ &.show {
+ opacity: 1;
+ transform: translateY(0);
+ pointer-events: all;
+ animation: pulse 0.6s ease-in-out;
+ }
+
+ &:hover {
+ background: var(--bs-primary-dark, #0a58ca);
+ box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
+ transform: translateY(-2px);
+ }
+
+ &:active {
+ transform: translateY(0) scale(0.98);
+ }
+
+ svg {
+ width: 20px;
+ height: 20px;
+ flex-shrink: 0;
+ }
+
+ .badge {
+ display: inline-block;
+ min-width: 20px;
+ padding: 2px 6px;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 1;
+ text-align: center;
+ white-space: nowrap;
+ vertical-align: baseline;
+ border-radius: 10px;
+ background-color: rgba(255, 255, 255, 0.3);
+ color: white;
+ margin: 0 4px;
+ }
+
+ /* Варианты расположения */
+ &.left {
+ right: auto;
+ left: 20px;
+ }
+
+ &.center {
+ left: 50%;
+ right: auto;
+ transform: translateX(-50%) translateY(10px);
+
+ &.show {
+ transform: translateX(-50%) translateY(0);
+ }
+
+ &:hover {
+ transform: translateX(-50%) translateY(-2px);
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHAT SCROLL CONTAINER
+────────────────────────────────────────────────────────────── */
+#chatScroll {
+ position: relative;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ANIMATIONS
+────────────────────────────────────────────────────────────── */
+@keyframes pulse {
+ 0%, 100% {
+ transform: scale(1);
+ }
+ 50% {
+ transform: scale(1.05);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ RESPONSIVE
+────────────────────────────────────────────────────────────── */
+@media (max-width: 768px) {
+ .new-messages-indicator {
+ bottom: 15px;
+ right: 15px;
+ min-width: 160px;
+ padding: 8px 14px;
+ font-size: 13px;
+
+ svg {
+ width: 18px;
+ height: 18px;
+ }
+
+ .badge {
+ font-size: 11px;
+ min-width: 18px;
+ padding: 2px 5px;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ DARK THEME
+────────────────────────────────────────────────────────────── */
+@media (prefers-color-scheme: dark) {
+ .new-messages-indicator {
+ background: #1a73e8;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
+
+ &:hover {
+ background: #1557b0;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_chat-polls.scss b/backend/static/scss_backup_20260115/components/chat/_chat-polls.scss
new file mode 100644
index 00000000..827d4cc8
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_chat-polls.scss
@@ -0,0 +1,187 @@
+/**
+ * _chat-polls.scss
+ * Стили для голосований в чате
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ POLL MODAL
+────────────────────────────────────────────────────────────── */
+#pollModal .modal-dialog {
+ display: flex;
+ align-items: center;
+ min-height: calc(100% - 1rem);
+
+ @media (min-width: 576px) {
+ min-height: calc(100% - 3.5rem);
+ max-width: 500px;
+ margin: 1.75rem auto;
+ }
+}
+
+#pollModal .remove-option {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+#pollOptions .input-group-text {
+ min-width: 40px;
+ justify-content: center;
+ font-weight: 600;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ POLL WIDGET
+────────────────────────────────────────────────────────────── */
+.poll-widget {
+ padding: 1rem;
+ background: var(--bs-secondary-bg);
+ border-radius: $radius-sm;
+ margin: 0.5rem 0;
+}
+
+.poll-question {
+ font-size: 1.1rem;
+ color: var(--bs-body-color);
+ font-weight: 400;
+}
+
+.poll-option {
+ position: relative;
+
+ &.voted {
+ background: rgba(var(--bs-success-rgb), 0.1);
+ padding: 0.5rem;
+ border-radius: $radius-xs;
+
+ .progress-bar {
+ background-color: var(--bs-success);
+ }
+ }
+}
+
+.btn-poll-option {
+ @include transition-all($transition-fast);
+
+ &:hover {
+ background: var(--bs-primary);
+ color: white;
+ border-color: var(--bs-primary);
+ transform: translateX(4px);
+ }
+}
+
+.poll-option-result {
+ .progress {
+ background-color: rgba(0, 0, 0, 0.1);
+ }
+
+ .progress-bar {
+ background-color: var(--bs-primary);
+ @include transition(width, $transition-slow);
+ }
+}
+
+.poll-footer {
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ padding-top: 0.75rem;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ POLL IN MESSAGE BUBBLES
+────────────────────────────────────────────────────────────── */
+.message-bubble .poll-widget {
+ max-width: 500px;
+}
+
+/* Голосования в сообщениях других пользователей */
+.bubble-other .poll-widget {
+ background: var(--bs-secondary-bg);
+}
+
+/* Голосования в своих сообщениях */
+.bubble-me {
+ .poll-widget {
+ background: rgba(255, 255, 255, 0.15);
+ }
+
+ .poll-question {
+ color: #fff;
+ }
+
+ .poll-option-result {
+ .progress {
+ background-color: rgba(255, 255, 255, 0.2);
+ }
+
+ .progress-bar {
+ background-color: rgba(255, 255, 255, 0.6);
+ }
+ }
+
+ .poll-footer {
+ border-top-color: rgba(255, 255, 255, 0.2);
+ }
+
+ .poll-voters-list {
+ background: rgba(255, 255, 255, 0.1);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ POLL VOTERS
+────────────────────────────────────────────────────────────── */
+.poll-voters {
+ margin-top: 0.5rem;
+}
+
+.poll-voters-toggle {
+ cursor: pointer;
+ transition: color 0.2s;
+
+ &:hover {
+ color: var(--bs-primary) !important;
+ text-decoration: underline !important;
+ }
+
+ i {
+ transition: transform 0.2s;
+ font-size: 0.75rem;
+ }
+}
+
+.poll-voters-list {
+ animation: slideDown 0.2s ease-out;
+ background: rgba(0, 0, 0, 0.03);
+ padding: 0.5rem 1rem;
+ border-radius: 0.25rem;
+ margin-top: 0.5rem;
+
+ [data-bs-theme="dark"] & {
+ background: rgba(255, 255, 255, 0.05);
+ }
+}
+
+.voter-item {
+ padding: 0.25rem 0;
+ display: flex;
+ align-items: center;
+
+ i {
+ opacity: 0.6;
+ font-size: 0.875rem;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ANIMATIONS
+────────────────────────────────────────────────────────────── */
+@keyframes slideDown {
+ from {
+ opacity: 0;
+ transform: translateY(-5px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_message-context-menu.scss b/backend/static/scss_backup_20260115/components/chat/_message-context-menu.scss
new file mode 100644
index 00000000..fa67ab0d
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_message-context-menu.scss
@@ -0,0 +1,343 @@
+/**
+ * _message-context-menu.scss
+ * Контекстное меню сообщений (long-press / right-click)
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ MESSAGE INTERACTIVE
+────────────────────────────────────────────────────────────── */
+[data-message-id] {
+ cursor: pointer;
+ user-select: none;
+ -webkit-user-select: none;
+ -webkit-touch-callout: none;
+ position: relative;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CONTEXT MENU
+────────────────────────────────────────────────────────────── */
+.message-context-menu {
+ position: fixed;
+ z-index: 9999;
+ background: #ffffff; // Явно белый для светлой темы
+ border-radius: var(--radius-lg);
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
+ min-width: 280px;
+ max-width: 320px;
+ opacity: 0;
+ transform: scale(0.9);
+ transition: opacity 0.2s ease, transform 0.2s ease;
+ overflow: hidden;
+
+ &.show {
+ opacity: 1;
+ transform: scale(1);
+ }
+
+ // Мобильное позиционирование больше не отличается - убрано
+ // (контекстное меню позиционируется одинаково на всех устройствах)
+
+ // Backdrop для мобильных
+ &::before {
+ content: '';
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.4);
+ z-index: -1;
+ opacity: 0;
+ transition: opacity 0.2s ease;
+ pointer-events: none;
+ }
+
+ &.show::before {
+ opacity: 1;
+ }
+
+ // На десктопе backdrop не нужен
+ @media (hover: hover) and (pointer: fine) {
+ &::before {
+ display: none;
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MESSAGE HIGHLIGHT
+────────────────────────────────────────────────────────────── */
+.message-highlighted {
+ background-color: color-mix(in srgb, var(--bs-primary), transparent 92%) !important;
+ transition: background-color 0.2s ease;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ QUICK REACTIONS (TELEGRAM-STYLE)
+────────────────────────────────────────────────────────────── */
+// Floating панель с реакциями (отдельно от меню)
+.quick-reactions-panel {
+ position: fixed;
+ z-index: 10000; // Выше чем меню (9999)
+ background: #ffffff; // Явно белый для светлой темы
+ border-radius: 24px;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
+ width: 280px; // Фиксированная ширина как у меню
+ opacity: 0;
+ transform: translateY(10px) scale(0.95);
+ transition: opacity 0.2s ease, transform 0.2s ease, height 0.3s ease;
+ pointer-events: none; // Не блокирует клики когда невидима
+ overflow: hidden; // Для плавной анимации высоты
+
+ &.show {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ pointer-events: auto;
+ }
+}
+
+.quick-reactions-wrapper {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 6px 8px;
+}
+
+.quick-reactions-list {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ flex-wrap: wrap; // Переносим смайлики на новые строки
+ overflow-x: auto;
+ overflow-y: hidden;
+ max-width: 100%;
+ padding: 4px 0;
+
+ // Скрываем scrollbar
+ scrollbar-width: none;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+}
+
+.quick-reaction-btn {
+ flex-shrink: 0;
+ width: 36px;
+ height: 36px;
+ border: none;
+ background: transparent;
+ border-radius: 50%;
+ font-size: 24px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.15s cubic-bezier(0.34, 1.56, 0.64, 1);
+ position: relative;
+
+ &:hover {
+ transform: scale(1.25);
+ background: var(--bs-secondary-bg);
+ }
+
+ &:active {
+ transform: scale(1.1);
+ }
+
+ // Кнопка "показать больше реакций"
+ // TODO: Изменить серый фон на белый для светлой темы (должен совпадать с quick-reaction-btn) и кнопка раскрытия меню со смайликами при белой теме сливается с фоном (не меняется от цвета темы)
+ &.quick-reaction-btn-more {
+ opacity: 0.6;
+ font-size: 20px;
+
+ i {
+ transition: transform 0.3s ease;
+ }
+
+ &:hover {
+ opacity: 1;
+ transform: scale(1.25);
+
+ i {
+ transform: translateY(3px);
+ }
+ }
+
+ &.expanded i {
+ transform: rotate(180deg);
+ }
+ }
+
+ // Анимация появления по очереди
+ opacity: 0;
+ animation: reactionItemAppear 0.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
+
+ @for $i from 1 through 10 {
+ &:nth-child(#{$i}) {
+ animation-delay: #{$i * 0.03}s;
+ }
+ }
+}
+
+@keyframes reactionItemAppear {
+ from {
+ opacity: 0;
+ transform: scale(0.5) translateY(8px);
+ }
+ to {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MENU ACTIONS
+────────────────────────────────────────────────────────────── */
+.menu-actions {
+ padding: var(--space-2) 0;
+}
+
+.menu-action {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ gap: var(--space-3);
+ padding: var(--space-3) var(--space-4);
+ border: none;
+ background: transparent;
+ cursor: pointer;
+ transition: background-color 0.15s ease;
+ font-size: 15px;
+ color: var(--bs-body-color);
+ text-align: left;
+
+ &:hover {
+ background-color: var(--bs-tertiary-bg);
+ }
+
+ &:active {
+ background-color: var(--bs-secondary-bg);
+ }
+
+ i {
+ font-size: 18px;
+ width: 24px;
+ text-align: center;
+ color: var(--bs-secondary-color);
+ }
+
+ span {
+ flex: 1;
+ font-weight: 500;
+ }
+}
+
+.menu-action-danger {
+ color: var(--bs-danger);
+
+ i {
+ color: var(--bs-danger);
+ }
+
+ &:hover {
+ background-color: color-mix(in srgb, var(--bs-danger), transparent 95%);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ TOAST NOTIFICATION
+────────────────────────────────────────────────────────────── */
+.context-menu-toast {
+ position: fixed;
+ bottom: 80px;
+ left: 50%;
+ transform: translateX(-50%) translateY(20px);
+ background: rgba(0, 0, 0, 0.85);
+ color: white;
+ padding: var(--space-3) calc(var(--space-3) * 2);
+ border-radius: var(--badge-radius);
+ font-size: 14px;
+ font-weight: 500;
+ z-index: 10000;
+ opacity: 0;
+ transition: opacity 0.3s ease, transform 0.3s ease;
+ pointer-events: none;
+ white-space: nowrap;
+
+ &.show {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ DARK THEME
+────────────────────────────────────────────────────────────── */
+[data-bs-theme="dark"] {
+ .message-context-menu {
+ background: #2b2d31;
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
+ }
+
+ .message-highlighted {
+ background-color: rgba(88, 101, 242, 0.15) !important;
+ }
+
+ .quick-reactions-panel {
+ background: #2b2d31;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
+ }
+
+ .quick-reaction-btn {
+ &:hover {
+ background: rgba(255, 255, 255, 0.1);
+ }
+ }
+
+ .menu-action {
+ color: #dbdee1;
+
+ &:hover {
+ background-color: #35373c;
+ }
+
+ &:active {
+ background-color: #3f4147;
+ }
+
+ i {
+ color: #b5bac1;
+ }
+ }
+
+ .menu-action-danger {
+ color: #f23f43;
+
+ i {
+ color: #f23f43;
+ }
+
+ &:hover {
+ background-color: rgba(242, 63, 67, 0.1);
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ UTILITIES
+────────────────────────────────────────────────────────────── */
+.message-context-menu-enabled .reaction-button.add-reaction {
+ display: none !important;
+}
+
+@keyframes vibrate {
+ 0%, 100% { transform: translateX(0); }
+ 25% { transform: translateX(-2px); }
+ 75% { transform: translateX(2px); }
+}
+
+.message-vibrating {
+ animation: vibrate 0.1s linear;
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_message-inputs.scss b/backend/static/scss_backup_20260115/components/chat/_message-inputs.scss
new file mode 100644
index 00000000..1012e42c
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_message-inputs.scss
@@ -0,0 +1,234 @@
+/**
+ * message-inputs.scss
+ * Унифицированные стили для полей ввода сообщений и комментариев
+ */
+
+$message-bg-default: transparent;
+$message-bg-focused: transparent;
+
+.message-field {
+ display: flex;
+ align-items: center;
+ gap: var(--space-1);
+ width: 100%;
+ padding: 0.35rem 0.4rem;
+ border: 1px solid var(--bs-border-color);
+ border-radius: 999px;
+ background: $message-bg-default;
+ transition: border-color 0.15s ease, box-shadow 0.15s ease, background-color 0.15s ease;
+ --message-action-size: 42px;
+ flex-wrap: nowrap; // Важно: запрещаем перенос элементов на новую строку
+}
+
+.message-field:focus-within {
+ border-color: var(--bs-primary);
+ box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.15);
+ background: $message-bg-focused;
+}
+
+.message-field--stacked {
+ align-items: stretch;
+ flex-direction: column;
+ border-radius: 24px;
+ padding: 0.75rem;
+ gap: var(--space-1);
+}
+
+.message-field--compact {
+ padding: 0.25rem 0.3rem;
+ border-radius: 24px;
+ --message-action-size: 36px;
+}
+
+.message-input,
+.composer-textarea {
+ flex: 1 1 auto;
+ min-width: 0; // Важно: позволяет сжиматься ниже размера контента
+ border: none !important;
+ background: transparent !important;
+ resize: none;
+ padding: 0.5rem 0.75rem;
+ line-height: 1.4;
+ font-size: 1rem;
+ color: inherit;
+ scrollbar-width: none;
+ box-shadow: none !important;
+ outline: none !important;
+ // Высота управляется через textareaAutoExpand.js для rows="1"
+ // Для остальных textarea используется стандартное поведение
+}
+
+.message-field--compact .message-input {
+ font-size: 0.95rem;
+ // min-height удален - управляется textareaAutoExpand.js
+}
+
+.message-field--stacked .message-input {
+ min-height: 96px;
+ padding: 0.35rem 0;
+}
+
+.message-input:focus {
+ outline: none;
+ box-shadow: none;
+}
+
+.message-input::-webkit-scrollbar {
+ display: none;
+}
+
+// Кнопки действий в формах сообщений
+// Размеры и форма определяются здесь, стили (цвета, эффекты) - в custom-bootstrap.scss
+.message-icon-btn,
+.btn-attachment,
+.btn-send,
+.message-send,
+.btn-emoji {
+ width: var(--message-action-size, 42px) !important;
+ min-width: var(--message-action-size, 42px) !important;
+ height: var(--message-action-size, 42px) !important;
+ border-radius: 50% !important;
+ display: inline-flex !important;
+ align-items: center;
+ justify-content: center;
+ padding: 0 !important;
+ aspect-ratio: 1 / 1;
+ flex: 0 0 auto;
+ line-height: 1;
+ font-size: 1.05rem;
+ --bs-btn-padding-x: 0 !important;
+ --bs-btn-padding-y: 0 !important;
+ --bs-btn-border-radius: 50% !important;
+ box-sizing: border-box;
+}
+
+// Кнопка отправки - дополнительная тень
+.message-send,
+.btn-send {
+ box-shadow: 0 4px 12px rgba(var(--bs-primary-rgb), 0.2);
+}
+
+.message-attach {
+ position: relative;
+}
+
+.message-attach .dropdown-menu {
+ margin-top: 0.35rem;
+ border-radius: 16px;
+ padding: 0.5rem;
+}
+
+.message-emoji .dropdown-menu {
+ min-width: 260px;
+ padding: 0;
+ border-radius: 16px;
+ overflow: hidden;
+}
+
+.chat-emoji-picker {
+ width: min(340px, 90vw);
+ max-width: 360px;
+ height: 340px;
+ border: none;
+ outline: none;
+
+ // Основные переменные для светлой и тёмной темы
+ --background-color: var(--bs-body-bg);
+ --text-color: var(--bs-body-color);
+ --category-font-color: var(--bs-secondary-color);
+ --hover-color: var(--bs-secondary-bg);
+ --button-active-background: var(--bs-primary-bg-subtle, var(--bs-primary));
+ --button-hover-background: var(--bs-secondary-bg);
+ --focus-indicator: var(--bs-primary);
+ --border-color: color-mix(in srgb, var(--bs-border-color), transparent 25%);
+ --input-border-color: color-mix(in srgb, var(--bs-border-color), transparent 30%);
+ --input-placeholder-color: var(--bs-secondary-color);
+ --input-focus-border-color: var(--bs-primary);
+ --indicator-color: var(--bs-primary);
+
+ // RGB переменные для emoji-picker-element (для тёмной темы)
+ --rgb-background: var(--bs-body-bg-rgb);
+ --rgb-color: var(--bs-body-color-rgb);
+ --rgb-accent: var(--bs-primary-rgb);
+ --rgb-input: var(--bs-body-bg-rgb);
+
+ // Скроллбар для светлой темы по умолчанию
+ --scrollbar-color: rgba(0, 0, 0, 0.3);
+ --scrollbar-background: rgba(0, 0, 0, 0.05);
+
+ // Скрываем кнопку выбора тона кожи
+ button.favorites {
+ display: none !important;
+ }
+
+ // Кастомный скроллбар для внутренней панели
+ ::part(tabpanel) {
+ scrollbar-width: thin;
+ scrollbar-color: var(--scrollbar-color) var(--scrollbar-background);
+ }
+
+ ::part(tabpanel)::-webkit-scrollbar {
+ width: 8px;
+ }
+
+ ::part(tabpanel)::-webkit-scrollbar-track {
+ background: var(--scrollbar-background);
+ }
+
+ ::part(tabpanel)::-webkit-scrollbar-thumb {
+ background: var(--scrollbar-color);
+ border-radius: 4px;
+ }
+
+ ::part(tabpanel)::-webkit-scrollbar-thumb:hover {
+ background: rgba(var(--bs-body-color-rgb), 0.4);
+ }
+}
+
+// Дополнительные стили для тёмной темы
+[data-bs-theme="dark"] {
+ .chat-emoji-picker {
+ // Явно устанавливаем цвета для тёмной темы
+ --background-color: var(--bs-body-bg);
+ --text-color: var(--bs-body-color);
+ --secondary-text-color: var(--bs-secondary-color);
+ --category-emoji-size: 1.125rem;
+
+ // Скроллбар для темной темы
+ --scrollbar-color: rgba(255, 255, 255, 0.3);
+ --scrollbar-background: rgba(255, 255, 255, 0.05);
+ }
+}
+
+.message-field--solo {
+ display: block;
+ border-radius: 24px;
+ padding: 0.75rem 1rem;
+}
+
+.message-field--solo .message-input {
+ width: 100%;
+ min-height: 120px;
+ padding: 0;
+}
+
+@media (max-width: 576px) {
+ .message-field {
+ // Уменьшаем размеры кнопок на мобильных
+ --message-action-size: 38px;
+ padding: 0.3rem 0.35rem;
+ gap: 0.25rem;
+ }
+
+ .message-field--compact {
+ --message-action-size: 32px;
+ padding: 0.2rem 0.25rem;
+ }
+
+ .message-input,
+ .composer-textarea {
+ // Уменьшаем отступы для экономии места
+ padding: 0.4rem 0.5rem;
+ font-size: 0.95rem;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_message-reactions.scss b/backend/static/scss_backup_20260115/components/chat/_message-reactions.scss
new file mode 100644
index 00000000..8b175808
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_message-reactions.scss
@@ -0,0 +1,335 @@
+/**
+ * _message-reactions.scss
+ * Реакции на сообщения (эмодзи)
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ REACTIONS CONTAINER
+────────────────────────────────────────────────────────────── */
+.message-reactions {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px; // Увеличен gap для лучшего дыхания
+ margin-top: var(--space-2);
+ align-items: center;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ REACTION BUTTON
+────────────────────────────────────────────────────────────── */
+.reaction-button {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 4px 8px;
+ border: 1px solid var(--bs-border-color);
+ border-radius: 12px; // Скругленные края как таблетка
+ background: var(--bs-body-bg); // Контрастный фон (белый/черный в зависимости от темы)
+ cursor: pointer;
+ transition: all 0.2s ease;
+ font-size: 14px;
+ line-height: 1;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); // Легкая тень для отделения от фона
+
+ &:hover {
+ background: var(--bs-secondary-bg);
+ border-color: color-mix(in srgb, var(--bs-border-color), var(--bs-body-color) 30%);
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ }
+
+ // Активная реакция (пользователь уже отреагировал)
+ &.active {
+ background: #e7f3ff; // Непрозрачный светло-голубой вместо полупрозрачного
+ border-color: var(--bs-primary);
+ color: var(--bs-primary);
+ box-shadow: 0 2px 4px rgba(var(--bs-primary-rgb), 0.2);
+
+ &:hover {
+ background: #d0e9ff; // Чуть темнее при hover
+ }
+
+ .count {
+ color: var(--bs-primary);
+ font-weight: 600; // Жирнее для активных
+ }
+ }
+
+ // Эмодзи внутри кнопки
+ .emoji {
+ font-size: 16px;
+ line-height: 1;
+ }
+
+ // Счётчик реакций
+ .count {
+ font-size: 12px;
+ font-weight: 500;
+ color: var(--bs-body-color);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ADD REACTION BUTTON
+────────────────────────────────────────────────────────────── */
+.reaction-button.add-reaction {
+ opacity: 0;
+ transition: opacity 0.2s ease;
+ border-style: dashed;
+
+ &:hover {
+ opacity: 1;
+ border-style: solid;
+ }
+}
+
+// Показывать кнопку добавления при наведении на сообщение (только на десктопе без контекстного меню)
+@media (hover: hover) and (pointer: fine) {
+ [data-message-id]:not(.message-context-menu-enabled):hover .reaction-button.add-reaction,
+ .message-reactions:hover .reaction-button.add-reaction {
+ opacity: 1;
+ }
+}
+
+// Если есть хотя бы одна реакция, всегда показывать кнопку добавления
+.message-reactions:has(.reaction-button:not(.add-reaction)) .add-reaction {
+ opacity: 1;
+}
+
+// Полностью скрыть кнопку "+" если включено контекстное меню
+.message-context-menu-enabled .reaction-button.add-reaction {
+ display: none;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ EMOJI PICKER
+────────────────────────────────────────────────────────────── */
+.emoji-picker {
+ background: var(--bs-body-bg);
+ border: 1px solid var(--bs-border-color);
+ border-radius: var(--radius-md);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ padding: var(--space-2);
+ min-width: 200px;
+}
+
+.emoji-picker-grid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 4px;
+}
+
+.emoji-picker-button {
+ width: 40px;
+ height: 40px;
+ border: 1px solid transparent;
+ border-radius: var(--radius-sm);
+ background: transparent;
+ cursor: pointer;
+ font-size: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.15s ease;
+
+ &:hover {
+ background: var(--bs-tertiary-bg);
+ border-color: var(--bs-border-color);
+ transform: scale(1.1);
+ }
+
+ &:active {
+ transform: scale(0.95);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ANIMATIONS
+────────────────────────────────────────────────────────────── */
+@keyframes reactionPop {
+ 0% {
+ transform: scale(0);
+ opacity: 0;
+ }
+ 50% {
+ transform: scale(1.2);
+ }
+ 100% {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
+
+.reaction-button.new {
+ animation: reactionPop 0.3s ease;
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MOBILE RESPONSIVE
+────────────────────────────────────────────────────────────── */
+@media (max-width: 576px) {
+ .reaction-button {
+ padding: 3px 6px;
+ font-size: 12px;
+
+ .emoji {
+ font-size: 14px;
+ }
+
+ .count {
+ font-size: 11px;
+ }
+ }
+
+ .emoji-picker-grid {
+ grid-template-columns: repeat(6, 1fr);
+ }
+
+ .emoji-picker-button {
+ width: 36px;
+ height: 36px;
+ font-size: 20px;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ DARK THEME
+────────────────────────────────────────────────────────────── */
+[data-bs-theme="dark"] {
+ .reaction-button {
+ background: #2b3035; // Темнее чем bubble для контраста
+ border-color: #495057;
+ color: #f8f9fa;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
+
+ &:hover {
+ background: #343a40;
+ border-color: #6c757d;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
+ }
+
+ &.active {
+ background: #0d3c61;
+ border-color: #0d6efd;
+ color: #4dabf7;
+ box-shadow: 0 2px 4px rgba(13, 110, 253, 0.3);
+
+ &:hover {
+ background: #0a4a7d;
+ }
+
+ .count {
+ color: #4dabf7;
+ font-weight: 600;
+ }
+ }
+ }
+
+ .emoji-picker {
+ background: #212529;
+ border-color: #495057;
+ }
+
+ .emoji-picker-button:hover {
+ background: #343a40;
+ border-color: #495057;
+ }
+
+ .reaction-users-popup {
+ background: #2b3035;
+ border-color: #495057;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
+
+ .reaction-users-header {
+ border-bottom-color: #495057;
+ }
+
+ .user-name {
+ color: #f8f9fa;
+
+ &:hover {
+ background: #343a40;
+ }
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ REACTION USERS POPUP
+────────────────────────────────────────────────────────────── */
+.reaction-users-popup {
+ position: fixed;
+ z-index: 9999;
+ background: var(--bs-body-bg);
+ border: 1px solid var(--bs-border-color);
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+ min-width: 180px;
+ max-width: 280px;
+ opacity: 0;
+ transform: translateY(-4px);
+ transition: opacity 0.2s ease, transform 0.2s ease;
+ pointer-events: none;
+
+ &.show {
+ opacity: 1;
+ transform: translateY(0);
+ pointer-events: all;
+ }
+}
+
+.reaction-users-header {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 12px 16px;
+ border-bottom: 1px solid var(--bs-border-color);
+ font-weight: 600;
+
+ .reaction-emoji {
+ font-size: 20px;
+ }
+
+ .reaction-count {
+ color: var(--bs-secondary);
+ font-size: 14px;
+ }
+}
+
+.reaction-users-list {
+ max-height: 200px;
+ overflow-y: auto;
+ padding: 4px;
+
+ &::-webkit-scrollbar {
+ width: 6px;
+ }
+
+ &::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ background: var(--bs-border-color);
+ border-radius: 3px;
+
+ &:hover {
+ background: var(--bs-secondary);
+ }
+ }
+}
+
+.user-name {
+ padding: 8px 12px;
+ color: var(--bs-body-color);
+ font-size: 14px;
+ border-radius: 6px;
+ transition: background-color 0.15s ease;
+
+ &:hover {
+ background: var(--bs-secondary-bg);
+ }
+
+ &:not(:last-child) {
+ margin-bottom: 2px;
+ }
+}
diff --git a/backend/static/scss_backup_20260115/components/chat/_message-selection.scss b/backend/static/scss_backup_20260115/components/chat/_message-selection.scss
new file mode 100644
index 00000000..6fbe819e
--- /dev/null
+++ b/backend/static/scss_backup_20260115/components/chat/_message-selection.scss
@@ -0,0 +1,292 @@
+/**
+ * _message-selection.scss
+ * Стили для режима выделения сообщений
+ */
+
+/* ─────────────────────────────────────────────────────────────
+ SELECTION MODE
+────────────────────────────────────────────────────────────── */
+.selection-mode .msg {
+ cursor: pointer;
+ transition: background-color 0.2s;
+ position: relative;
+ padding-left: 40px !important;
+
+ &.justify-content-end {
+ padding-left: 0 !important;
+ padding-right: 40px !important;
+ }
+
+ &:hover {
+ background-color: rgba(0, 123, 255, 0.05);
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ CHECKBOX
+────────────────────────────────────────────────────────────── */
+.msg-select-checkbox {
+ position: absolute;
+ left: 8px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 24px;
+ height: 24px;
+ border: 2px solid var(--bs-border-color);
+ border-radius: 50%;
+ background: var(--bs-body-bg);
+ display: none;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.2s;
+ z-index: 10;
+ flex-shrink: 0;
+
+ .selection-mode & {
+ display: flex;
+ }
+
+ &:hover {
+ border-color: var(--bs-primary);
+ background: color-mix(in srgb, var(--bs-primary), transparent 90%);
+ }
+
+ &.selected {
+ background: var(--bs-primary);
+ border-color: var(--bs-primary);
+
+ &::after {
+ content: '✓';
+ color: white;
+ font-size: 14px;
+ font-weight: bold;
+ }
+ }
+}
+
+.msg.justify-content-end .msg-select-checkbox {
+ left: auto;
+ right: 8px;
+}
+
+.msg.selected {
+ background-color: color-mix(in srgb, var(--bs-primary), transparent 90%);
+}
+
+/* ─────────────────────────────────────────────────────────────
+ ACTIONS BAR
+────────────────────────────────────────────────────────────── */
+.selection-actions-bar {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: var(--bs-body-bg);
+ border-top: 2px solid var(--bs-primary);
+ padding: 12px 20px;
+ display: none;
+ align-items: center;
+ justify-content: space-between;
+ box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
+ z-index: $z-modal;
+ animation: slideUp 0.3s ease-out;
+
+ &.active {
+ display: flex;
+ }
+}
+
+@keyframes slideUp {
+ from {
+ transform: translateY(100%);
+ }
+ to {
+ transform: translateY(0);
+ }
+}
+
+.selection-count {
+ font-weight: 600;
+ color: var(--bs-primary);
+ font-size: 16px;
+}
+
+.selection-actions {
+ display: flex;
+ gap: 10px;
+
+ .btn {
+ padding: 8px 20px;
+ font-weight: 500;
+ border-radius: var(--button-radius);
+ transition: all 0.2s;
+
+ &:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ FORWARD MODAL
+────────────────────────────────────────────────────────────── */
+.chat-forward-modal {
+ .modal-dialog {
+ max-width: 500px;
+ }
+}
+
+.chat-list-item {
+ padding: 12px 16px;
+ border-bottom: 1px solid var(--bs-border-color);
+ cursor: pointer;
+ transition: background-color 0.2s;
+ display: flex;
+ align-items: center;
+ gap: 12px;
+
+ &:hover {
+ background-color: var(--bs-tertiary-bg);
+ }
+
+ &:last-child {
+ border-bottom: none;
+ }
+}
+
+.chat-list-avatar {
+ width: 48px;
+ height: 48px;
+ border-radius: 50%;
+ background: var(--bs-tertiary-bg);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 20px;
+ color: var(--bs-secondary-color);
+ flex-shrink: 0;
+ overflow: hidden;
+ position: relative;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+}
+
+.chat-list-info {
+ flex: 1;
+ min-width: 0;
+}
+
+.chat-list-name {
+ font-weight: 600;
+ color: var(--bs-body-color);
+ margin-bottom: 2px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.chat-list-subtitle {
+ font-size: 13px;
+ color: var(--bs-secondary-color);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.chat-list-loading,
+.chat-list-empty {
+ padding: 40px 20px;
+ text-align: center;
+ color: var(--bs-secondary-color);
+}
+
+/* ─────────────────────────────────────────────────────────────
+ SEARCH
+────────────────────────────────────────────────────────────── */
+.chat-forward-search {
+ padding: 12px 16px;
+ border-bottom: 1px solid var(--bs-border-color);
+
+ input {
+ width: 100%;
+ padding: 8px 12px;
+ border: 1px solid var(--bs-border-color);
+ border-radius: var(--radius-md);
+ font-size: 14px;
+ background: var(--bs-body-bg);
+ color: var(--bs-body-color);
+
+ &:focus {
+ outline: none;
+ border-color: var(--bs-primary);
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--bs-primary), transparent 90%);
+ }
+
+ &::placeholder {
+ color: var(--bs-secondary-color);
+ }
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ FORWARDED INDICATOR
+────────────────────────────────────────────────────────────── */
+.forwarded-indicator {
+ font-size: 12px;
+ color: var(--bs-secondary-color);
+ margin-bottom: 4px;
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-style: italic;
+
+ i {
+ font-size: 14px;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────────
+ MOBILE RESPONSIVE
+────────────────────────────────────────────────────────────── */
+@media (max-width: 768px) {
+ .selection-actions-bar {
+ padding: 10px 15px;
+ }
+
+ .selection-count {
+ font-size: 14px;
+ }
+
+ .selection-actions .btn {
+ padding: 6px 16px;
+ font-size: 14px;
+ }
+
+ .msg-select-checkbox {
+ width: 20px;
+ height: 20px;
+ left: 5px;
+ }
+
+ .msg.justify-content-end .msg-select-checkbox {
+ right: 5px;
+ }
+
+ .selection-mode .msg {
+ padding-left: 32px !important;
+
+ &.justify-content-end {
+ padding-left: 0 !important;
+ padding-right: 32px !important;
+ }
+ }
+}
diff --git a/backend/static/scss_backup_20260115/custom-bootstrap.scss b/backend/static/scss_backup_20260115/custom-bootstrap.scss
new file mode 100644
index 00000000..5bca1e5e
--- /dev/null
+++ b/backend/static/scss_backup_20260115/custom-bootstrap.scss
@@ -0,0 +1,201 @@
+// =============================================================================
+// Custom Bootstrap Configuration
+// =============================================================================
+// Этот файл переопределяет переменные Bootstrap ДО его компиляции
+// Результат: полностью кастомизированный Bootstrap с нашей системой отступов
+
+// =============================================================================
+// 1. ИМПОРТ НАШИХ ПЕРЕМЕННЫХ
+// =============================================================================
+// Сначала импортируем наши CSS переменные (для справки)
+// Реальные значения ниже в SCSS переменных
+
+// =============================================================================
+// 2. ПЕРЕОПРЕДЕЛЕНИЕ BOOTSTRAP ПЕРЕМЕННЫХ
+// =============================================================================
+
+// ──────────────────────────────────────────────────────────────
+// 2.1 Система отступов (8px grid)
+// ──────────────────────────────────────────────────────────────
+// Bootstrap использует $spacer для всех utility классов (.p-*, .m-* и т.д.)
+// Переопределяем его на нашу 8px сетку
+
+$spacer: 1rem !default; // 16px - базовое значение
+
+// Переопределение всей шкалы spacing
+$spacers: (
+ 0: 0, // 0px
+ 1: 0.25rem, // 4px - var(--space-1)
+ 2: 0.5rem, // 8px - var(--space-2)
+ 3: 0.75rem, // 12px - var(--space-3)
+ 4: 1rem, // 16px - var(--space-4)
+ 5: 1.5rem, // 24px - var(--space-5)
+) !default;
+
+// ──────────────────────────────────────────────────────────────
+// 2.2 Grid система
+// ──────────────────────────────────────────────────────────────
+$grid-gutter-width: 0.5rem !default; // 8px - var(--space-2)
+
+// ──────────────────────────────────────────────────────────────
+// 2.3 Компоненты - Padding
+// ──────────────────────────────────────────────────────────────
+// Переопределяем padding для всех Bootstrap компонентов
+
+// Cards
+$card-spacer-y: 1rem !default; // var(--space-2)
+$card-spacer-x: 1rem !default; // var(--space-2)
+
+// Alerts
+$alert-padding-y: 1rem !default; // var(--space-2)
+$alert-padding-x: 1rem !default; // var(--space-2)
+
+// Buttons
+$btn-padding-y: 0.5rem !default; // var(--space-1)
+$btn-padding-x: 1rem !default; // var(--space-2)
+
+$btn-padding-y-sm: 0.5rem !default; // var(--space-1)
+$btn-padding-x-sm: 0.5rem !default; // var(--space-1)
+
+$btn-padding-y-lg: 1rem !default; // var(--space-2)
+$btn-padding-x-lg: 1.5rem !default; // var(--space-3)
+
+// Form controls
+$input-padding-y: 0.5rem !default; // var(--space-1)
+$input-padding-x: 1rem !default; // var(--space-2)
+
+$input-padding-y-sm: 0.5rem !default; // var(--space-1)
+$input-padding-x-sm: 0.5rem !default; // var(--space-1)
+
+$input-padding-y-lg: 1rem !default; // var(--space-2)
+$input-padding-x-lg: 1.5rem !default; // var(--space-3)
+
+// Modals
+$modal-inner-padding: 1rem !default; // var(--space-2)
+$modal-header-padding-y: 1rem !default; // var(--space-2)
+$modal-header-padding-x: 1rem !default; // var(--space-2)
+
+// Dropdowns
+$dropdown-padding-x: 0 !default;
+$dropdown-padding-y: 8px !default; // var(--space-1)
+$dropdown-item-padding-y: 8px !default; // var(--space-1)
+$dropdown-item-padding-x: 16px !default; // var(--space-2)
+
+// Navs
+$nav-link-padding-y: 8px !default; // var(--space-1)
+$nav-link-padding-x: 16px !default; // var(--space-2)
+
+// Navbar
+$navbar-padding-y: 8px !default; // var(--space-1)
+$navbar-padding-x: 16px !default; // var(--space-2)
+
+// Pagination
+$pagination-padding-y: 8px !default; // var(--space-1)
+$pagination-padding-x: 16px !default; // var(--space-2)
+
+$pagination-padding-y-sm: 8px !default; // var(--space-1)
+$pagination-padding-x-sm: 8px !default; // var(--space-1)
+
+$pagination-padding-y-lg: 16px !default; // var(--space-2)
+$pagination-padding-x-lg: 24px !default; // var(--space-3)
+
+// List groups
+$list-group-item-padding-y: 1rem !default; // var(--space-2)
+$list-group-item-padding-x: 1rem !default; // var(--space-2)
+
+// Breadcrumbs
+$breadcrumb-padding-y: 0.5rem !default; // var(--space-1)
+$breadcrumb-padding-x: 1rem !default; // var(--space-2)
+
+// Toasts
+$toast-padding-x: 1rem !default; // var(--space-2)
+$toast-padding-y: 0.5rem !default; // var(--space-1)
+
+// Offcanvas
+$offcanvas-padding-y: 1rem !default; // var(--space-2)
+$offcanvas-padding-x: 1rem !default; // var(--space-2)
+
+// Badges
+$badge-padding-y: 0.5rem !default; // var(--space-1)
+$badge-padding-x: 0.5rem !default; // var(--space-1)
+
+// ──────────────────────────────────────────────────────────────
+// 2.4 Cards - переопределяем стили карточек (GLASSMORPHISM)
+// ──────────────────────────────────────────────────────────────
+$card-border-radius: 18px !default;
+$card-border-width: 1px !default;
+$card-border-color: rgba(255, 255, 255, 0.1) !default; // Светлая граница для glassmorphism
+$card-bg: rgba(255, 255, 255, 0.05) !default; // Полупрозрачный для эффекта стекла
+$card-box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37) !default; // Глубокая тень
+
+// Card header/footer
+$card-cap-padding-y: 1rem !default;
+$card-cap-padding-x: 1rem !default;
+$card-cap-bg: transparent !default; // Прозрачный header/footer
+$card-cap-color: null !default;
+
+// ──────────────────────────────────────────────────────────────
+// 2.5 Дополнительные настройки (опционально)
+// ──────────────────────────────────────────────────────────────
+
+// Border radius (если хотите унифицировать)
+// $border-radius: 10px !default; // var(--radius-md)
+// $border-radius-sm: 6px !default; // var(--radius-sm)
+// $border-radius-lg: 14px !default; // var(--radius-lg)
+
+// =============================================================================
+// 3. ИМПОРТ ABSTRACTS (Design Tokens & Mixins)
+// =============================================================================
+// Импортируем переменные и миксины ДО Bootstrap
+@import "abstracts/variables";
+@import "abstracts/mixins";
+
+// =============================================================================
+// 4. ИМПОРТ BOOTSTRAP
+// =============================================================================
+// Импортируем Bootstrap ПОСЛЕ переопределения переменных
+@import "../node_modules/bootstrap/scss/bootstrap";
+
+// =============================================================================
+// 4.5 CSS ПЕРЕМЕННЫЕ (RUNTIME)
+// =============================================================================
+// CSS custom properties для использования в браузере
+@import "abstracts/css-variables";
+
+// =============================================================================
+// 5. КАСТОМНЫЕ КОМПОНЕНТЫ
+// =============================================================================
+
+// Layout
+@import "layout/chat-layout";
+
+// Базовые компоненты
+@import "components/common";
+@import "components/navbar";
+@import "components/sidebar";
+@import "components/page-header";
+@import "components/cards";
+
+// Badge компоненты
+@import "components/badges-bem";
+
+// Чат компоненты (в подпапке chat/)
+@import "components/chat/message-inputs";
+@import "components/chat/chat-detail";
+@import "components/chat/chat-date-groups";
+@import "components/chat/chat-list-enhanced";
+@import "components/chat/chat-enhanced";
+@import "components/chat/chat-polls";
+@import "components/chat/chat-new-messages-indicator";
+@import "components/chat/message-selection";
+@import "components/chat/message-context-menu";
+@import "components/chat/message-reactions";
+
+// Дополнительные компоненты
+@import "components/comments";
+@import "components/modals";
+
+// Остальные компоненты (загружаются напрямую из CSS - не мигрировано)
+// TODO: Мигрировать buttons, card-list, document-list, request-list,
+// ios-search, feed-specific, base-app, request-detail
+
diff --git a/backend/static/scss_backup_20260115/layout/_base-app.scss b/backend/static/scss_backup_20260115/layout/_base-app.scss
new file mode 100644
index 00000000..e68c0451
--- /dev/null
+++ b/backend/static/scss_backup_20260115/layout/_base-app.scss
@@ -0,0 +1,397 @@
+// =============================================================================
+// Base App Layout & Styles (SCSS)
+// =============================================================================
+// Базовые стили приложения: layout, navbar, sidebar, формы, feed-элементы
+//
+// Зависимости:
+// - Bootstrap custom build
+// - CSS переменные из abstracts/_css-variables.scss
+
+// =============================================================================
+// ПЕРЕМЕННЫЕ
+// =============================================================================
+
+// Цвета
+$primary-light: #007AFF;
+$primary-dark: #0A84FF;
+$link-hover-light: #0062CC;
+$link-hover-dark: #59AFFF;
+
+// Фоны темной темы
+$dark-bg: #1C1C1E;
+$dark-color: #F2F2F7;
+$dark-border: #3A3A3C;
+$dark-tertiary-bg: #2C2C2E;
+
+// Типографика
+$font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+$font-size-base: 17px;
+
+// Размеры компонентов
+$btn-border-radius: 10px;
+$btn-min-height: 44px;
+$form-control-border-radius: 10px;
+$form-control-height: 44px;
+$dropdown-border-radius: 13px;
+
+// Переходы
+$btn-transition: background-color 0.3s, transform 0.1s;
+$form-transition: box-shadow 0.2s ease, border-color 0.2s ease;
+$ghost-btn-transition: background 0.2s ease;
+
+// Тени
+$dropdown-shadow: 0 6px 24px rgba(0, 0, 0, 0.12);
+
+// Navbar
+$navbar-border-width: 0.5px;
+
+// =============================================================================
+// ЦВЕТОВАЯ СХЕМА
+// =============================================================================
+
+:root {
+ --bs-primary: #{$primary-light};
+ --bs-link-color: var(--bs-primary);
+ --bs-link-hover-color: #{$link-hover-light};
+}
+
+[data-bs-theme="dark"] {
+ --bs-body-bg: #{$dark-bg};
+ --bs-body-color: #{$dark-color};
+ --bs-border-color: #{$dark-border};
+ --bs-tertiary-bg: #{$dark-tertiary-bg};
+ --bs-primary: #{$primary-dark};
+ --bs-link-color: var(--bs-primary);
+ --bs-link-hover-color: #{$link-hover-dark};
+}
+
+// =============================================================================
+// BODY & БАЗОВЫЕ СТИЛИ
+// =============================================================================
+
+body {
+ font-family: $font-family-base;
+ font-size: $font-size-base;
+ padding-top: var(--navbar-h);
+ overflow-x: hidden;
+ background-color: var(--bs-body-bg);
+
+ // Safe area для iOS
+ @supports(padding-top: env(safe-area-inset-top)) {
+ padding-top: calc(var(--navbar-h) + env(safe-area-inset-top));
+ }
+}
+
+// =============================================================================
+// ФОРМЫ И КНОПКИ (БАЗОВЫЕ ПЕРЕОПРЕДЕЛЕНИЯ)
+// =============================================================================
+
+.btn {
+ border-radius: $btn-border-radius;
+ min-height: $btn-min-height;
+ transition: $btn-transition;
+
+ &:hover {
+ transform: scale(1.02);
+ }
+}
+
+.form-control {
+ border-radius: $form-control-border-radius;
+ height: $form-control-height;
+ font-size: $font-size-base;
+
+ &:focus {
+ box-shadow: 0 0 0 2px rgba(var(--bs-primary-rgb), 0.25);
+ border-color: var(--bs-primary);
+ }
+}
+
+.dropdown-menu {
+ border-radius: $dropdown-border-radius;
+ box-shadow: $dropdown-shadow;
+}
+
+// =============================================================================
+// NAVBAR
+// =============================================================================
+
+.app-navbar {
+ position: fixed;
+ inset: 0 0 auto 0;
+ z-index: 1030;
+ border-bottom: $navbar-border-width solid var(--bs-border-color);
+}
+
+// =============================================================================
+// LAYOUT GRID SYSTEM
+// =============================================================================
+
+.app-layout {
+ display: block;
+}
+
+// Адаптивный контейнер
+.content-container {
+ width: 100%;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+// Мобильные устройства
+@media (max-width: 991.98px) {
+ .content-container {
+ padding-left: var(--bs-gutter-x, 0.75rem);
+ padding-right: var(--bs-gutter-x, 0.75rem);
+ }
+}
+
+// Десктоп с grid layout
+@media (min-width: 992px) {
+ // При наличии сайдбаров убираем padding и max-width
+ .app-layout.with-sidebar,
+ .app-layout.with-rightbar {
+ .content-container {
+ max-width: none;
+ padding-left: 0;
+ padding-right: 0;
+ }
+ }
+
+ // Grid: sidebar + content + rightbar
+ .app-layout.with-sidebar.with-rightbar {
+ display: grid;
+ grid-template-columns: var(--sidebar-w) 1fr var(--rightbar-w);
+ gap: var(--layout-gap);
+ align-items: start;
+ }
+
+ // Grid: sidebar + content
+ .app-layout.with-sidebar:not(.with-rightbar) {
+ display: grid;
+ grid-template-columns: var(--sidebar-w) 1fr;
+ gap: var(--layout-gap);
+ align-items: start;
+ }
+
+ // Без сайдбаров - стандартный container
+ .app-layout:not(.with-sidebar):not(.with-rightbar) {
+ .content-container {
+ padding-left: var(--bs-gutter-x, 0.75rem);
+ padding-right: var(--bs-gutter-x, 0.75rem);
+ max-width: 960px;
+ }
+ }
+
+ // Компенсация для .row внутри grid-layout
+ .app-layout.with-sidebar,
+ .app-layout.with-rightbar {
+ .content-container > .row {
+ margin-left: 0;
+ margin-right: 0;
+
+ > [class*="col-"] {
+ padding-left: calc(var(--bs-gutter-x) * 0.5);
+ padding-right: calc(var(--bs-gutter-x) * 0.5);
+ }
+ }
+
+ // Карточки внутри колонок
+ .container > .row > [class*="col-"] {
+ > .card,
+ > section.card {
+ max-width: 100%;
+ min-width: 0;
+ overflow: hidden;
+ }
+ }
+ }
+}
+
+// Breakpoints для max-width
+@media (min-width: 1200px) {
+ .app-layout:not(.with-sidebar):not(.with-rightbar) .content-container {
+ max-width: 1140px;
+ }
+}
+
+@media (min-width: 1400px) {
+ .app-layout:not(.with-sidebar):not(.with-rightbar) .content-container {
+ max-width: 1320px;
+ }
+}
+
+// =============================================================================
+// SIDEBAR
+// =============================================================================
+
+#sidebar {
+ --bs-offcanvas-width: var(--sidebar-w);
+ border-radius: 0 13px 13px 0;
+
+ @media (min-width: 992px) {
+ &.offcanvas-lg {
+ position: sticky;
+ top: var(--navbar-h);
+ height: calc(100dvh - var(--navbar-h));
+ align-self: start;
+ overflow: auto;
+ border-right: $navbar-border-width solid var(--bs-border-color);
+ background: var(--bs-body-bg);
+ transform: none !important;
+ visibility: visible !important;
+ }
+ }
+}
+
+// =============================================================================
+// NOTIFICATION BELL
+// =============================================================================
+
+.bell-wrapper {
+ position: relative;
+ line-height: 1;
+ display: inline-block;
+}
+
+.bell-dot {
+ position: absolute;
+ top: -2px;
+ right: -2px;
+ width: 9px;
+ height: 9px;
+ border-radius: 999px;
+ background: var(--bs-danger);
+ color: #fff;
+ font-size: 7px;
+ line-height: 9px;
+ font-weight: 700;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.65);
+}
+
+// =============================================================================
+// BUTTONS & GHOST BUTTONS
+// =============================================================================
+
+.btn-ghost {
+ background: color-mix(in srgb, var(--bs-body-bg) 94%, transparent);
+ color: var(--bs-body-color);
+ padding: var(--space-1);
+ border-radius: 999px;
+ font-size: 0.9rem;
+ transition: $ghost-btn-transition;
+
+ &:hover {
+ background: color-mix(in srgb, var(--bs-body-bg) 88%, transparent);
+ }
+
+ .bi {
+ font-size: 1rem;
+ margin-right: 0.35rem;
+ vertical-align: -2px;
+ }
+
+ // Текст кнопок с toggle (Скрыть/Показать)
+ .txt-close {
+ display: none;
+ }
+
+ &[aria-expanded="true"] {
+ .txt-open {
+ display: none;
+ }
+
+ .txt-close {
+ display: inline;
+ }
+ }
+}
+
+// =============================================================================
+// FEED ELEMENTS
+// =============================================================================
+
+// Блоки типа "Новые сотрудники"
+.feed-new {
+ border-radius: var(--feed-radius);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
+ background: var(--bs-body-bg);
+ box-shadow: var(--feed-shadow);
+ padding: var(--card-padding);
+}
+
+// Z-index для stretched-link
+.card-body .stretched-link::after,
+.feed-img .stretched-link::after {
+ z-index: 1;
+}
+
+.collapse {
+ position: relative;
+ z-index: 2;
+}
+
+// =============================================================================
+// ALPHA HEADERS (буквенные разделители)
+// =============================================================================
+
+.alpha-header {
+ position: sticky;
+ top: calc(var(--navbar-h) + var(--space-1));
+ z-index: 1;
+ background: color-mix(in srgb, var(--bs-body-bg) 92%, transparent);
+ backdrop-filter: blur(6px);
+ border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 30%);
+ color: var(--bs-secondary-color);
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-1);
+ padding: var(--space-1);
+ border-radius: 999px;
+ font-weight: 700;
+ font-size: 0.85rem;
+ margin: var(--space-1) 0 var(--space-1) var(--space-1);
+}
+
+.alpha-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 999px;
+ background: var(--bs-primary);
+ opacity: 0.6;
+}
+
+// =============================================================================
+// ACTION BUTTONS
+// =============================================================================
+
+.action-btn {
+ min-height: unset;
+ padding: var(--space-1);
+
+ .bi {
+ font-size: 1rem;
+ }
+}
+
+// =============================================================================
+// TEXT UTILITIES
+// =============================================================================
+
+// Переносим длинные слова/ссылки
+.feed-text,
+.feed-full {
+ overflow-wrap: anywhere;
+ width: 100%;
+ margin-right: 0;
+ padding-right: 0;
+}
+
+// Z-index для кнопки "Подробнее"
+.readmore-toggle {
+ position: relative;
+ z-index: 2;
+}
diff --git a/backend/static/scss_backup_20260115/layout/_chat-layout.scss b/backend/static/scss_backup_20260115/layout/_chat-layout.scss
new file mode 100644
index 00000000..3f9672ca
--- /dev/null
+++ b/backend/static/scss_backup_20260115/layout/_chat-layout.scss
@@ -0,0 +1,61 @@
+// =============================================================================
+// Chat Layout
+// =============================================================================
+// Глобальная структура страниц чата (не специфичные компоненты)
+
+// =============================================================================
+// 1. MAIN CONTAINER
+// =============================================================================
+
+main.main {
+ padding-bottom: 0 !important;
+}
+
+// Специальное правило для страниц чата в grid layout
+// Ограничиваем высоту main, чтобы не ломать grid и rightbar
+@media (min-width: 992px) {
+ .app-layout.with-rightbar main.main:has(.chat-page),
+ .app-layout.with-sidebar main.main:has(.chat-page) {
+ max-height: calc(100vh - var(--navbar-h, 60px) - 2 * var(--layout-padding-y, 12px));
+ overflow: hidden;
+ }
+}
+
+// =============================================================================
+// 2. CHAT PAGE STRUCTURE
+// =============================================================================
+
+// Root контейнер страницы чата
+@supports (height: 100svh) {
+ .chat-root {
+ height: calc(100svh - var(--navbar-h));
+ }
+}
+
+.chat-root > .row {
+ height: 100%;
+ min-height: 0;
+}
+
+// Column layout
+.chat-col {
+ display: flex;
+ flex-direction: column;
+ height: 93%;
+ min-height: 0;
+}
+
+// =============================================================================
+// 3. CHAT BOX CONTAINER
+// =============================================================================
+
+.card.chat-box {
+ position: relative;
+ flex: 1 1 auto;
+ min-height: 0;
+ display: grid;
+ grid-template-rows: 1fr auto; /* messages + composer */
+ overflow: hidden;
+ margin-bottom: 0;
+ background: var(--bs-body-bg);
+}
diff --git a/backend/static/scss_backup_20260115/main.scss b/backend/static/scss_backup_20260115/main.scss
new file mode 100644
index 00000000..a6c7c5c2
--- /dev/null
+++ b/backend/static/scss_backup_20260115/main.scss
@@ -0,0 +1,85 @@
+// =============================================================================
+// Main Application SCSS
+// =============================================================================
+// Главный файл для сборки всех стилей приложения (кроме Bootstrap)
+// Компилируется в css/app.css
+
+// =============================================================================
+// 1. ABSTRACTS - Переменные, миксины, функции
+// =============================================================================
+@import 'abstracts/index';
+
+// =============================================================================
+// 2. LAYOUT - Структура приложения
+// =============================================================================
+@import 'layout/base-app';
+@import 'layout/chat-layout';
+
+// =============================================================================
+// 3. COMPONENTS - Переиспользуемые компоненты
+// =============================================================================
+
+// Базовые компоненты
+@import 'components/buttons';
+@import 'components/cards';
+@import 'components/modals';
+@import 'components/navbar';
+@import 'components/sidebar';
+@import 'components/page-header';
+@import 'components/common';
+
+// Spacing и layout utilities
+@import 'components/layout-spacing';
+@import 'components/spacing-utils';
+
+// iOS-стиль компоненты
+@import 'components/ios-search';
+@import 'components/ios-components';
+
+// Бейджи
+@import 'components/badges-bem';
+@import 'components/badges-telegram-style';
+
+// Комментарии
+@import 'components/comments';
+
+// Списки и уведомления
+@import 'components/card-list';
+@import 'components/notifications';
+
+// Заявления и документы
+@import 'components/request-list';
+@import 'components/request-detail';
+@import 'components/document-list';
+@import 'components/recipientPicker';
+@import 'components/list-view';
+
+// Feed компоненты
+@import 'components/feed-specific';
+@import 'components/join-scroller';
+@import 'components/post-form';
+
+// Модальные окна
+@import 'components/modal-overrides';
+@import 'components/logout-modal';
+
+// Employees компоненты
+@import 'components/department-controls';
+@import 'components/team-wheel';
+
+// Календарь и rightbar
+@import 'components/rightbar-calendar';
+
+// =============================================================================
+// 4. UTILITIES - Вспомогательные классы
+// =============================================================================
+// @import 'utilities/spacing-utils';
+// @import 'utilities/index';
+
+// =============================================================================
+// ПРИМЕЧАНИЯ
+// =============================================================================
+// - Bootstrap подключается отдельно через bootstrap-custom.css
+// - CSS переменные (--variable) определены в abstracts/_css-variables.scss
+// - SCSS переменные ($variable) определены в abstracts/_variables.scss
+// - Порядок импортов критичен для CSS каскада
diff --git a/docs/reports/SCSS_ARCHITECTURE_AUDIT.md b/docs/reports/SCSS_ARCHITECTURE_AUDIT.md
new file mode 100644
index 00000000..edcf2273
--- /dev/null
+++ b/docs/reports/SCSS_ARCHITECTURE_AUDIT.md
@@ -0,0 +1,461 @@
+# Аудит архитектуры backend/static/scss
+
+**Дата:** 15 января 2026
+**Аудитор:** GitHub Copilot
+**Статус:** ⚠️ Требуется улучшение
+
+## 📊 Общая оценка: 7/10
+
+### ✅ Сильные стороны (7 баллов)
+
+1. **Хорошая структура папок** (9/10)
+ - ✅ Логичное разделение: abstracts, layout, components, utilities
+ - ✅ Подпапка chat для chat компонентов
+ - ✅ Понятная организация
+
+2. **Именование файлов** (8/10)
+ - ✅ Префикс `_` для partials
+ - ✅ Kebab-case naming
+ - ✅ Понятные имена
+
+3. **Документация** (7/10)
+ - ✅ Есть BUTTONS_README.md
+ - ✅ Комментарии в main.scss
+ - ⚠️ Нет общего README в scss/
+
+4. **Модульность** (9/10)
+ - ✅ 30 компонентов в components/
+ - ✅ 10 chat модулей в components/chat/
+ - ✅ Разделение abstracts
+
+## ⚠️ Проблемы и недостатки (3 балла снижения)
+
+### 🔴 Критические проблемы
+
+#### 1. Дублирование импортов компонентов (CRITICAL)
+
+**Проблема:** Многие компоненты импортируются дважды:
+- Один раз в `main.scss` → компилируется в `app.css`
+- Второй раз в `custom-bootstrap.scss` → компилируется в `bootstrap-custom.css`
+
+**Дублированные импорты:**
+```scss
+// В main.scss:
+@import 'components/common';
+@import 'components/navbar';
+@import 'components/sidebar';
+@import 'components/page-header';
+@import 'components/cards';
+@import 'components/modals';
+@import 'components/comments';
+
+// И ЕЩЕ РАЗ в custom-bootstrap.scss:
+@import "components/common";
+@import "components/navbar";
+@import "components/sidebar";
+@import "components/page-header";
+@import "components/cards";
+@import "components/modals";
+@import "components/comments";
+```
+
+**Последствия:**
+- ❌ Эти стили дублируются в `app.css` И `bootstrap-custom.css`
+- ❌ Увеличенный размер файлов
+- ❌ Повторяющиеся селекторы
+- ❌ Потенциальные конфликты специфичности
+
+**Затронутые компоненты:**
+1. common
+2. navbar
+3. sidebar
+4. page-header
+4. cards
+5. badges-bem
+6. modals
+7. comments
+
+**Размер дублирования:** ~1,500-2,000 строк SCSS дублируются!
+
+#### 2. Chat компоненты ТОЛЬКО в bootstrap-custom.css
+
+**Проблема:** Все 10 chat компонентов импортируются ТОЛЬКО в `custom-bootstrap.scss`:
+
+```scss
+// Чат компоненты (в подпапке chat/)
+@import "components/chat/message-inputs";
+@import "components/chat/chat-detail";
+@import "components/chat/chat-date-groups";
+@import "components/chat/chat-list-enhanced";
+@import "components/chat/chat-enhanced";
+@import "components/chat/chat-polls";
+@import "components/chat/chat-new-messages-indicator";
+@import "components/chat/message-selection";
+@import "components/chat/message-context-menu";
+@import "components/chat/message-reactions";
+```
+
+**Последствия:**
+- ❌ Chat стили попадают в `bootstrap-custom.css` (301 KB)
+- ❌ Нелогично - chat не относится к Bootstrap
+- ❌ Сложнее поддерживать - непонятно где искать
+
+#### 3. Устаревший TODO комментарий
+
+В `custom-bootstrap.scss` строки 197-199:
+```scss
+// Остальные компоненты (загружаются напрямую из CSS - не мигрировано)
+// TODO: Мигрировать buttons, card-list, document-list, request-list,
+// ios-search, feed-specific, base-app, request-detail
+```
+
+**Проблема:** Эти компоненты УЖЕ мигрированы и импортируются в `main.scss`!
+
+### 🟡 Средние проблемы
+
+#### 4. Пустая папка utilities/
+
+```
+scss/utilities/ - ПУСТО
+```
+
+В `main.scss` закомментированы импорты:
+```scss
+// @import 'utilities/spacing-utils';
+// @import 'utilities/index';
+```
+
+**Проблема:**
+- Папка существует но не используется
+- spacing-utils лежит в components/, а не utilities/
+- Запутанная структура
+
+#### 5. Нет главного README.md в scss/
+
+**Отсутствует:** `backend/static/scss/README.md`
+
+Есть только:
+- `components/BUTTONS_README.md` - документация одного компонента
+- Нет общего описания архитектуры
+
+#### 6. Layout компоненты в custom-bootstrap.scss
+
+```scss
+// Layout
+@import "layout/chat-layout";
+```
+
+И в main.scss:
+```scss
+@import 'layout/base-app';
+@import 'layout/chat-layout'; // ДУБЛЬ!
+```
+
+**chat-layout импортируется дважды!**
+
+### 🟢 Мелкие замечания
+
+#### 7. Несогласованность комментариев
+
+В `main.scss`:
+```scss
+// 4. UTILITIES - Вспомогательные классы
+// @import 'utilities/spacing-utils';
+// @import 'utilities/index';
+```
+
+Но `_spacing-utils.scss` находится в `components/`, не в `utilities/`!
+
+#### 8. Размер custom-bootstrap.scss
+
+202 строки, из них:
+- ~70 строк - переопределения переменных Bootstrap
+- ~30 строк - импорты компонентов (многие дублируются)
+- ~100 строк - комментарии
+
+Файл становится перегруженным.
+
+## 📈 Статистика
+
+### Размеры
+- **Всего SCSS файлов:** 51
+- **Всего строк SCSS:** 11,394
+- **Компонентов в components/:** 30
+- **Компонентов в components/chat/:** 10
+- **Layout файлов:** 2
+- **Abstracts файлов:** 4
+
+### Импорты
+- **Импортов в main.scss:** 30
+- **Импортов в custom-bootstrap.scss:** 25
+- **Дублированных импортов:** 8 компонентов
+
+### Compiled размеры
+- **app.css:** 95 KB
+- **bootstrap-custom.css:** 301 KB
+- **Дубликаты в обоих:** ~15-20 KB
+
+## 🎯 Рекомендации по улучшению
+
+### Приоритет 1: Устранить дублирование (CRITICAL)
+
+#### Решение A: Разделить компоненты по назначению
+
+**app.css** (main.scss):
+- Все application-specific компоненты
+- Layout (base-app, chat-layout)
+- Components (buttons, cards, modals, etc.)
+- Chat components
+- Spacing utilities
+
+**bootstrap-custom.css** (custom-bootstrap.scss):
+- ТОЛЬКО переопределения Bootstrap переменных
+- ТОЛЬКО импорт Bootstrap
+- CSS variables (abstracts/css-variables)
+- Убрать ВСЕ импорты компонентов
+
+#### Решение B: Создать отдельный chat.css
+
+**chat.css** (новый entry point):
+- Все chat компоненты
+- Chat layout
+- Подключать только на страницах чата
+
+### Приоритет 2: Очистить custom-bootstrap.scss
+
+**Удалить из custom-bootstrap.scss:**
+```scss
+// ❌ УДАЛИТЬ ВСЕ ЭТО:
+@import "layout/chat-layout";
+@import "components/common";
+@import "components/navbar";
+@import "components/sidebar";
+@import "components/page-header";
+@import "components/cards";
+@import "components/badges-bem";
+@import "components/chat/..."; // все 10 импортов
+@import "components/comments";
+@import "components/modals";
+```
+
+**Оставить только:**
+```scss
+// 1. Переопределение Bootstrap переменных
+$spacer: 1rem;
+$spacers: (...);
+// и т.д.
+
+// 2. Импорт наших abstracts
+@import "abstracts/variables";
+@import "abstracts/mixins";
+
+// 3. Импорт Bootstrap
+@import "../node_modules/bootstrap/scss/bootstrap";
+
+// 4. CSS переменные
+@import "abstracts/css-variables";
+
+// ВСЕ! Никаких компонентов!
+```
+
+### Приоритет 3: Переместить spacing-utils
+
+```bash
+# Переместить из components/ в utilities/
+mv scss/components/_spacing-utils.scss scss/utilities/
+mv scss/components/_layout-spacing.scss scss/utilities/
+```
+
+Раскомментировать в main.scss:
+```scss
+// 4. UTILITIES - Вспомогательные классы
+@import 'utilities/layout-spacing';
+@import 'utilities/spacing-utils';
+```
+
+### Приоритет 4: Документация
+
+Создать `scss/README.md`:
+```markdown
+# SCSS Architecture
+
+## Structure
+- abstracts/ - Variables, mixins, functions
+- layout/ - Page layouts
+- components/ - Reusable components
+- utilities/ - Utility classes
+
+## Build
+- main.scss → app.css (application styles)
+- bootstrap-custom.scss → bootstrap-custom.css (Bootstrap only)
+
+## Components
+[список всех компонентов]
+```
+
+### Приоритет 5: Удалить устаревшие TODO
+
+Удалить из custom-bootstrap.scss:
+```scss
+// Остальные компоненты (загружаются напрямую из CSS - не мигрировано)
+// TODO: Мигрировать buttons, card-list, document-list, request-list,
+// ios-search, feed-specific, base-app, request-detail
+```
+
+Все эти компоненты УЖЕ в main.scss!
+
+## 📋 План действий (по шагам)
+
+### Шаг 1: Backup текущего состояния
+```bash
+cp scss/custom-bootstrap.scss scss/custom-bootstrap.scss.backup
+cp scss/main.scss scss/main.scss.backup
+```
+
+### Шаг 2: Очистить custom-bootstrap.scss
+Удалить все импорты компонентов, оставить только:
+- Переопределения переменных Bootstrap
+- Импорт abstracts
+- Импорт Bootstrap
+- Импорт css-variables
+
+### Шаг 3: Переместить chat в main.scss
+Добавить в main.scss все chat компоненты:
+```scss
+// Chat компоненты
+@import 'components/chat/message-inputs';
+@import 'components/chat/chat-detail';
+// ... все 10 компонентов
+```
+
+### Шаг 4: Переместить spacing в utilities
+```bash
+mv scss/components/_spacing-utils.scss scss/utilities/
+mv scss/components/_layout-spacing.scss scss/utilities/
+```
+
+### Шаг 5: Обновить импорты в main.scss
+```scss
+// Utilities
+@import 'utilities/layout-spacing';
+@import 'utilities/spacing-utils';
+```
+
+### Шаг 6: Пересобрать CSS
+```bash
+npm run build:app
+npm run build:bootstrap
+```
+
+### Шаг 7: Проверить размеры
+```bash
+ls -lh css/app.css css/bootstrap-custom.css
+```
+
+**Ожидаемый результат:**
+- app.css: увеличится на ~15-20 KB (добавятся chat компоненты)
+- bootstrap-custom.css: уменьшится на ~15-20 KB (удалятся дубли)
+
+### Шаг 8: Создать документацию
+Создать `scss/README.md` с описанием архитектуры
+
+### Шаг 9: Тестирование
+1. Проверить главную страницу
+2. Проверить страницы с чатом
+3. Проверить все компоненты
+
+## 📊 Ожидаемые улучшения
+
+После рефакторинга:
+
+### До:
+```
+app.css: 95 KB (без chat, с дублями)
+bootstrap-custom.css: 301 KB (с chat, с дублями)
+Дублирование: ~15-20 KB
+```
+
+### После:
+```
+app.css: ~110 KB (с chat, без дублей)
+bootstrap-custom.css: ~280 KB (только Bootstrap, без дублей)
+Дублирование: 0 KB
+Экономия: ~6-7% от общего размера
+```
+
+### Преимущества:
+- ✅ Нет дубликатов кода
+- ✅ Чистое разделение ответственности
+- ✅ Логичная структура
+- ✅ Легче поддерживать
+- ✅ Меньший итоговый размер
+
+## 🎓 Best Practices нарушения
+
+### ❌ Текущие нарушения:
+
+1. **DRY (Don't Repeat Yourself)** - дублирование 8 компонентов
+2. **Separation of Concerns** - chat компоненты в bootstrap файле
+3. **Single Responsibility** - custom-bootstrap делает слишком много
+4. **Clear Architecture** - utilities/ пуста, spacing в components/
+
+### ✅ После рефакторинга:
+
+1. **DRY** - каждый компонент импортируется один раз
+2. **Separation of Concerns** - четкое разделение: Bootstrap отдельно, app отдельно
+3. **Single Responsibility** - каждый файл имеет одну четкую цель
+4. **Clear Architecture** - логичная структура папок
+
+## 💡 Дополнительные рекомендации
+
+### 1. Рассмотреть переход на @use/@forward
+SCSS @import deprecated, современный подход:
+```scss
+@use 'abstracts/variables' as vars;
+@use 'components/buttons';
+```
+
+### 2. Создать index.scss в папках
+```scss
+// components/chat/_index.scss
+@forward 'message-inputs';
+@forward 'chat-detail';
+// ...
+
+// Использование:
+@import 'components/chat'; // импортирует все
+```
+
+### 3. Добавить linter
+```bash
+npm install -D stylelint stylelint-config-sass-guidelines
+```
+
+### 4. Создать style guide
+Документировать:
+- Naming conventions
+- File organization
+- Import order
+- Variables usage
+
+## 🏁 Заключение
+
+**Текущая архитектура:** 7/10 - Хорошая база, но есть критические проблемы
+
+**Основные проблемы:**
+1. Дублирование импортов (CRITICAL)
+2. Chat компоненты в bootstrap-custom (HIGH)
+3. Неиспользуемая utilities/ папка (MEDIUM)
+
+**Действия:**
+1. Срочно устранить дублирование
+2. Переорганизовать структуру
+3. Создать документацию
+
+**После рефакторинга ожидается:** 9/10 - Чистая, поддерживаемая архитектура
+
+---
+
+**Дата:** 15 января 2026
+**Статус:** Требуется рефакторинг
+**Приоритет:** HIGH
diff --git a/docs/reports/SCSS_REORGANIZATION_PLAN.md b/docs/reports/SCSS_REORGANIZATION_PLAN.md
new file mode 100644
index 00000000..1db57c6f
--- /dev/null
+++ b/docs/reports/SCSS_REORGANIZATION_PLAN.md
@@ -0,0 +1,1412 @@
+# План реорганизации SCSS архитектуры
+
+**Дата:** 15 января 2026
+**Статус:** 📋 План
+**Приоритет:** HIGH
+**Время выполнения:** 6-8 часов (с Bootstrap) / 40-60 часов (без Bootstrap)
+
+## 🎯 Цель
+
+Преобразовать хаотичную структуру в чистую, поддерживаемую архитектуру с четкой категоризацией и переиспользуемыми компонентами.
+
+### ⚠️ КРИТИЧЕСКОЕ РЕШЕНИЕ: Bootstrap или нет?
+
+**Пользователь запросил:** Полный отказ от Bootstrap в пользу собственных стилей.
+
+**Это означает:**
+- ❌ Удалить зависимость от Bootstrap (~301 KB CSS)
+- ✅ Написать свою систему: Grid, Buttons, Forms, Modals, Cards, Utilities
+- ⏱️ Увеличение времени реализации с 8 часов до **40-60 часов**
+- 🎨 Полный контроль над кодом и стилями
+- 📦 Уменьшение итогового размера бандла
+- 🔧 Необходимость поддержки своего UI Kit
+
+**См. раздел "БОНУСНЫЙ ЭТАП: Отказ от Bootstrap" в конце документа.**
+
+---
+
+## 📊 Целевая архитектура
+
+### Feature-based структура (подходит под Django структуру):
+
+```
+scss/
+├── abstracts/ # ✅ Оставить как есть
+│ ├── _variables.scss # SCSS переменные
+│ ├── _css-variables.scss # CSS custom properties
+│ ├── _mixins.scss # Миксины
+│ └── _index.scss # Экспорт
+│
+├── core/ # ⭐ НОВАЯ ПАПКА - UI Kit
+│ ├── _buttons.scss # Кнопки
+│ ├── _forms.scss # Формы и инпуты
+│ ├── _badges.scss # Один badge компонент (объединить 2)
+│ ├── _cards.scss # Карточки
+│ ├── _lists.scss # ОДИН базовый список
+│ ├── _modals.scss # ОДИН modal (объединить 2)
+│ ├── _avatars.scss # Аватары
+│ ├── _search.scss # Поиск (вместо ios-search)
+│ └── _comments.scss # Комментарии
+│
+├── layout/ # Структура приложения
+│ ├── _grid.scss # App grid (из base-app.scss)
+│ ├── _header.scss # Navbar + page-header (объединить)
+│ ├── _sidebar.scss # ✅ Оставить
+│ └── _rightbar.scss # Rightbar + calendar (объединить)
+│
+├── features/ # ⭐ НОВАЯ ПАПКА - Feature-specific
+│ ├── feed/
+│ │ ├── _layout.scss # Feed layout
+│ │ ├── _post-card.scss # Карточка поста
+│ │ └── _post-form.scss # ✅ Переместить
+│ ├── requests/
+│ │ ├── _list.scss # Список заявок
+│ │ ├── _detail.scss # Детали заявки
+│ │ └── _picker.scss # Recipient picker
+│ ├── documents/
+│ │ └── _list.scss # Список документов
+│ ├── employees/
+│ │ ├── _controls.scss # Department controls
+│ │ └── _team-viz.scss # Team visualization (team-wheel)
+│ ├── notifications/
+│ │ └── _center.scss # Notification center
+│ └── chat/ # ✅ Оставить подпапку
+│ └── ... # 10 файлов как есть
+│
+└── utilities/ # Utility классы
+ └── _spacing.scss # Объединить spacing-utils + layout-spacing
+```
+
+---
+
+## 📋 Этапы выполнения
+
+### **Этап 0: Подготовка (30 мин)**
+
+#### 0.1 Создать backup
+```bash
+cd backend/static
+cp -r scss scss_backup_$(date +%Y%m%d)
+git add -A
+git commit -m "backup: SCSS before reorganization"
+```
+
+#### 0.2 Создать новые папки
+```bash
+cd scss
+mkdir -p core features utilities
+mkdir -p features/{feed,requests,documents,employees,notifications}
+```
+
+#### 0.3 Создать tracking файл
+```bash
+# Создать файл для отслеживания прогресса
+touch REORGANIZATION_PROGRESS.md
+```
+
+---
+
+### **Этап 1: Аудит и группировка (1 час)**
+
+#### 1.1 Создать матрицу миграции
+
+Создать `MIGRATION_MATRIX.md`:
+
+```markdown
+| Старый файл | Новое расположение | Статус | Требуется слияние |
+|-------------|-------------------|--------|-------------------|
+| _buttons.scss | core/_buttons.scss | ⏳ | Нет |
+| _badges-bem.scss | core/_badges.scss | ⏳ | Да (с telegram) |
+| _badges-telegram-style.scss | core/_badges.scss | ⏳ | Да (с bem) |
+| _ios-search.scss | core/_search.scss | ⏳ | Нет |
+| ... | ... | ... | ... |
+```
+
+#### 1.2 Проанализировать зависимости
+```bash
+# Найти все импорты
+grep -r "@import" main.scss custom-bootstrap.scss
+
+# Найти использование классов в шаблонах
+grep -r "class=" templates/ | grep -E "(ios-|badge-|card-list)"
+```
+
+---
+
+### **Этап 2: Core UI Kit (2 часа)**
+
+#### 2.1 Простые перемещения (без изменений)
+
+```bash
+# Buttons - просто переместить
+mv components/_buttons.scss core/_buttons.scss
+
+# Cards - переместить
+mv components/_cards.scss core/_cards.scss
+
+# Comments - переместить
+mv components/_comments.scss core/_comments.scss
+
+# Common - переместить
+mv components/_common.scss core/_common.scss
+```
+
+#### 2.2 Переименование файлов
+
+```bash
+# iOS-search → search
+mv components/_ios-search.scss core/_search.scss
+
+# iOS-components разобрать на части или переименовать
+mv components/_ios-components.scss core/_ui-elements.scss
+```
+
+**Задача:** Открыть `_ios-components.scss`, посмотреть что там, возможно разбить на несколько файлов.
+
+#### 2.3 Объединение badges (ВАЖНО!)
+
+**Шаги:**
+1. Открыть `_badges-bem.scss` и `_badges-telegram-style.scss`
+2. Проанализировать что можно объединить
+3. Создать единый `core/_badges.scss`:
+
+```scss
+// core/_badges.scss
+
+// ===== BASE BADGE =====
+.badge {
+ // Общие стили
+}
+
+// ===== BEM VARIANT =====
+.badge--bem {
+ // BEM специфичные стили
+}
+
+// ===== TELEGRAM VARIANT =====
+.badge--telegram {
+ // Telegram специфичные стили
+}
+
+// ===== STATUS VARIANTS =====
+.badge--success { }
+.badge--danger { }
+.badge--pending { }
+```
+
+4. Удалить старые файлы
+5. Обновить импорты
+
+#### 2.4 Объединение modals
+
+```bash
+# Объединить modal-overrides в modals
+cat components/_modal-overrides.scss >> components/_modals.scss
+mv components/_modals.scss core/_modals.scss
+rm components/_modal-overrides.scss
+```
+
+**Почистить дубли** в объединенном файле!
+
+#### 2.5 Создать core/_lists.scss
+
+Проанализировать:
+- `_card-list.scss` - общие стили списков
+- `_list-view.scss` - view стили
+
+Объединить общее в `core/_lists.scss`:
+
+```scss
+// core/_lists.scss
+
+// ===== BASE LIST =====
+.list {
+ // Базовые стили списка
+}
+
+// ===== LIST ITEM =====
+.list__item {
+ // Стили элемента списка
+}
+
+// ===== VARIANTS =====
+.list--compact { }
+.list--cards { }
+```
+
+---
+
+### **Этап 3: Layout реорганизация (1.5 часа)**
+
+#### 3.1 Создать layout/_grid.scss
+
+```bash
+# Переместить base-app
+mv layout/_base-app.scss layout/_grid.scss
+```
+
+Внутри файла переименовать классы:
+- `.app-layout` → `.app-grid`
+- Улучшить документацию
+
+#### 3.2 Объединить header компоненты
+
+**Анализ:**
+- `_navbar.scss` - навигация
+- `_page-header.scss` - заголовок страницы
+
+**Варианты:**
+
+**A) Объединить в один файл:**
+```bash
+cat components/_navbar.scss components/_page-header.scss > layout/_header.scss
+```
+
+**B) Оставить раздельно но переименовать:**
+```bash
+mv components/_navbar.scss layout/_navbar.scss
+mv components/_page-header.scss layout/_page-header.scss
+```
+
+**Рекомендация:** Вариант B (раздельно), но добавить комментарий что это части header'а.
+
+#### 3.3 Rightbar + Calendar
+
+```bash
+# Переместить rightbar-calendar
+mv components/_rightbar-calendar.scss layout/_rightbar.scss
+```
+
+Внутри переименовать классы:
+- `.rightbar-card` → `.rightbar__card`
+- `.calendar-wrap` → `.rightbar__calendar`
+
+---
+
+### **Этап 4: Features организация (2 часа)**
+
+#### 4.1 Feed feature
+
+```bash
+# Создать feed папку
+mkdir -p features/feed
+
+# Переместить компоненты
+mv components/_feed-specific.scss features/feed/_layout.scss
+mv components/_post-form.scss features/feed/_post-form.scss
+mv components/_join-scroller.scss features/feed/_members-scroller.scss
+
+# Если есть feed-header или подобное - тоже сюда
+```
+
+Создать `features/feed/_index.scss`:
+```scss
+@forward 'layout';
+@forward 'post-form';
+@forward 'members-scroller';
+```
+
+#### 4.2 Requests feature
+
+```bash
+mkdir -p features/requests
+
+mv components/_request-list.scss features/requests/_list.scss
+mv components/_request-detail.scss features/requests/_detail.scss
+mv components/_recipientPicker.scss features/requests/_recipient-picker.scss
+```
+
+Создать `features/requests/_index.scss`:
+```scss
+@forward 'list';
+@forward 'detail';
+@forward 'recipient-picker';
+```
+
+#### 4.3 Documents feature
+
+```bash
+mkdir -p features/documents
+
+mv components/_document-list.scss features/documents/_list.scss
+```
+
+Создать `features/documents/_index.scss`:
+```scss
+@forward 'list';
+```
+
+#### 4.4 Employees feature
+
+```bash
+mkdir -p features/employees
+
+mv components/_department-controls.scss features/employees/_controls.scss
+mv components/_team-wheel.scss features/employees/_team-viz.scss
+```
+
+Переименовать внутри `_team-viz.scss`:
+- `.team-wheel` → `.team-viz`
+- Обновить комментарии
+
+Создать `features/employees/_index.scss`:
+```scss
+@forward 'controls';
+@forward 'team-viz';
+```
+
+#### 4.5 Notifications feature
+
+```bash
+mkdir -p features/notifications
+
+mv components/_notifications.scss features/notifications/_center.scss
+```
+
+Создать `features/notifications/_index.scss`:
+```scss
+@forward 'center';
+```
+
+#### 4.6 Chat feature (оставить как есть)
+
+```bash
+# Chat уже в подпапке - оставить
+# features/chat/ уже существует как components/chat/
+# Просто переместить папку целиком
+mv components/chat features/chat
+```
+
+#### 4.7 Logout modal (куда деть?)
+
+**Варианты:**
+1. В `features/auth/_logout-modal.scss`
+2. В `core/_modals.scss` (добавить специфичные стили)
+3. Удалить если можно использовать общий modal
+
+**Рекомендация:** Вариант 2 - добавить `.modal--logout` в core модалы.
+
+```bash
+# Слить с core/modals
+cat components/_logout-modal.scss >> core/_modals.scss
+rm components/_logout-modal.scss
+```
+
+---
+
+### **Этап 5: Utilities (30 мин)**
+
+#### 5.1 Объединить spacing
+
+```bash
+# Объединить два spacing файла
+cat components/_layout-spacing.scss components/_spacing-utils.scss > utilities/_spacing.scss
+
+# Почистить дубли в объединенном файле
+# Удалить старые
+rm components/_layout-spacing.scss
+rm components/_spacing-utils.scss
+```
+
+#### 5.2 Проверить пустую utilities папку
+
+```bash
+# Удалить старую пустую папку если осталась
+rmdir utilities/ 2>/dev/null || true
+```
+
+---
+
+### **Этап 6: Обновление импортов (1.5 часа)**
+
+#### 6.1 Создать новый main.scss
+
+Создать `main.scss.new`:
+
+```scss
+// =============================================================================
+// Main Application SCSS
+// =============================================================================
+// Главный файл для сборки всех стилей приложения (кроме Bootstrap)
+// Компилируется в css/app.css
+
+// =============================================================================
+// 1. ABSTRACTS - Переменные, миксины, функции
+// =============================================================================
+@import 'abstracts/index';
+
+// =============================================================================
+// 2. CORE - UI Kit компоненты
+// =============================================================================
+@import 'core/buttons';
+@import 'core/forms';
+@import 'core/badges';
+@import 'core/cards';
+@import 'core/lists';
+@import 'core/modals';
+@import 'core/avatars';
+@import 'core/search';
+@import 'core/comments';
+@import 'core/common';
+
+// =============================================================================
+// 3. LAYOUT - Структура приложения
+// =============================================================================
+@import 'layout/grid';
+@import 'layout/navbar';
+@import 'layout/page-header';
+@import 'layout/sidebar';
+@import 'layout/rightbar';
+
+// =============================================================================
+// 4. UTILITIES - Вспомогательные классы
+// =============================================================================
+@import 'utilities/spacing';
+
+// =============================================================================
+// 5. FEATURES - Feature-specific стили
+// =============================================================================
+
+// Feed
+@import 'features/feed/layout';
+@import 'features/feed/post-form';
+@import 'features/feed/members-scroller';
+
+// Requests
+@import 'features/requests/list';
+@import 'features/requests/detail';
+@import 'features/requests/recipient-picker';
+
+// Documents
+@import 'features/documents/list';
+
+// Employees
+@import 'features/employees/controls';
+@import 'features/employees/team-viz';
+
+// Notifications
+@import 'features/notifications/center';
+
+// Chat
+@import 'features/chat/message-inputs';
+@import 'features/chat/chat-detail';
+@import 'features/chat/chat-date-groups';
+@import 'features/chat/chat-list-enhanced';
+@import 'features/chat/chat-enhanced';
+@import 'features/chat/chat-polls';
+@import 'features/chat/chat-new-messages-indicator';
+@import 'features/chat/message-selection';
+@import 'features/chat/message-context-menu';
+@import 'features/chat/message-reactions';
+
+// =============================================================================
+// ПРИМЕЧАНИЯ
+// =============================================================================
+// - Bootstrap подключается отдельно через bootstrap-custom.css
+// - CSS переменные (--variable) определены в abstracts/_css-variables.scss
+// - SCSS переменные ($variable) определены в abstracts/_variables.scss
+// - Порядок импортов критичен для CSS каскада
+// - Core компоненты = переиспользуемые UI элементы
+// - Features = специфичные для конкретных функций приложения
+```
+
+#### 6.2 Очистить custom-bootstrap.scss
+
+Создать `custom-bootstrap.scss.new`:
+
+```scss
+// =============================================================================
+// Custom Bootstrap Configuration
+// =============================================================================
+// Этот файл переопределяет переменные Bootstrap ДО его компиляции
+
+// =============================================================================
+// 1. ПЕРЕОПРЕДЕЛЕНИЕ BOOTSTRAP ПЕРЕМЕННЫХ
+// =============================================================================
+
+// Система отступов (8px grid)
+$spacer: 1rem !default;
+$spacers: (
+ 0: 0,
+ 1: 0.25rem, // 4px
+ 2: 0.5rem, // 8px
+ 3: 0.75rem, // 12px
+ 4: 1rem, // 16px
+ 5: 1.5rem, // 24px
+) !default;
+
+// Grid
+$grid-gutter-width: 0.5rem !default;
+
+// Cards
+$card-spacer-y: 1rem !default;
+$card-spacer-x: 1rem !default;
+$card-border-radius: 14px !default;
+
+// Buttons
+$btn-padding-y: 0.5rem !default;
+$btn-padding-x: 1rem !default;
+
+// Inputs
+$input-padding-y: 0.5rem !default;
+$input-padding-x: 1rem !default;
+
+// =============================================================================
+// 2. ИМПОРТ ABSTRACTS
+// =============================================================================
+@import "abstracts/variables";
+@import "abstracts/mixins";
+
+// =============================================================================
+// 3. ИМПОРТ BOOTSTRAP
+// =============================================================================
+@import "../node_modules/bootstrap/scss/bootstrap";
+
+// =============================================================================
+// 4. CSS ПЕРЕМЕННЫЕ (RUNTIME)
+// =============================================================================
+@import "abstracts/css-variables";
+
+// =============================================================================
+// ВСЕ! Никаких компонентов здесь!
+// Все компоненты в main.scss → app.css
+// =============================================================================
+```
+
+#### 6.3 Тестовая компиляция
+
+```bash
+cd backend/static
+
+# Backup старых файлов
+mv scss/main.scss scss/main.scss.old
+mv scss/custom-bootstrap.scss scss/custom-bootstrap.scss.old
+
+# Применить новые
+mv scss/main.scss.new scss/main.scss
+mv scss/custom-bootstrap.scss.new scss/custom-bootstrap.scss
+
+# Попробовать собрать
+npm run build:app 2>&1 | tee build_errors.log
+
+# Если ошибки - смотреть build_errors.log
+```
+
+#### 6.4 Исправление ошибок импортов
+
+```bash
+# Найти все missing imports
+grep -i "can't find" build_errors.log
+
+# Найти старые пути в файлах
+grep -r "@import.*components/" scss/
+
+# Исправить пути
+```
+
+---
+
+### **Этап 7: Cleanup (30 мин)**
+
+#### 7.1 Удалить старую components папку
+
+```bash
+# Проверить что components пуста
+ls -la scss/components/
+
+# Если пусто - удалить
+rm -rf scss/components/
+
+# Оставить только .gitkeep или удалить совсем
+```
+
+#### 7.2 Удалить BUTTONS_README.md из старого места
+
+```bash
+# Переместить в новое место
+mv scss/components/BUTTONS_README.md docs/guides/BUTTONS_COMPONENT.md
+
+# Или в core папку
+mv scss/components/BUTTONS_README.md scss/core/README_BUTTONS.md
+```
+
+#### 7.3 Проверить дубликаты
+
+```bash
+# Найти дублирующиеся селекторы
+grep -r "^\.badge" scss/ | sort | uniq -d
+
+# Найти дублирующиеся @import
+grep -r "@import" scss/main.scss scss/custom-bootstrap.scss | sort | uniq -d
+```
+
+---
+
+### **Этап 8: Тестирование (1 час)**
+
+#### 8.1 Сборка финальных CSS
+
+```bash
+# Собрать все
+npm run build:app
+npm run build:bootstrap
+
+# Проверить размеры
+ls -lh css/app.css css/bootstrap-custom.css
+
+# Сравнить с backup
+ls -lh css_backup/app.css css_backup/bootstrap-custom.css
+```
+
+#### 8.2 Визуальное тестирование
+
+**Проверить страницы:**
+1. Главная / feed
+2. Список заявок
+3. Детали заявки
+4. Список документов
+5. Список сотрудников
+6. Уведомления
+7. Чат
+8. Logout modal
+9. Search
+10. Forms
+
+**Чек-лист для каждой страницы:**
+- [ ] Стили загружаются
+- [ ] Нет визуальных багов
+- [ ] Кнопки работают
+- [ ] Формы выглядят нормально
+- [ ] Responsive работает
+
+#### 8.3 Проверка консоли браузера
+
+```javascript
+// В DevTools Console
+// Проверить нет ли 404 на CSS
+// Проверить размер загруженных CSS
+performance.getEntriesByType('resource')
+ .filter(r => r.name.includes('.css'))
+```
+
+---
+
+### **Этап 9: Документация (30 мин)**
+
+#### 9.1 Создать scss/README.md
+
+```markdown
+# SCSS Architecture
+
+## Structure
+
+### Core (UI Kit)
+Переиспользуемые UI компоненты: buttons, cards, badges, modals, etc.
+
+### Layout
+Структура приложения: grid, header, sidebar, rightbar.
+
+### Features
+Feature-specific стили, организованные по функциям приложения.
+
+### Utilities
+Utility классы: spacing, helpers, etc.
+
+## Build
+`npm run build:app` - компилирует main.scss → app.css
+`npm run build:bootstrap` - компилирует bootstrap-custom.scss → bootstrap-custom.css
+
+## Adding New Components
+1. Core component → `core/_component.scss`
+2. Feature component → `features/feature/_component.scss`
+3. Add import to `main.scss`
+4. Run `npm run build:app`
+```
+
+#### 9.2 Обновить docs/guides/SCSS_QUICK_REFERENCE.md
+
+Обновить пути и структуру в quick reference.
+
+#### 9.3 Создать отчет о реорганизации
+
+`docs/reports/SCSS_REORGANIZATION_COMPLETE.md` с:
+- Что было изменено
+- Новая структура
+- Метрики (файлы, размеры, время)
+
+---
+
+### **Этап 10: Git commit (15 мин)**
+
+```bash
+# Добавить все изменения
+git add -A
+
+# Коммит
+git commit -m "refactor: Complete SCSS architecture reorganization
+
+- Restructured 51 SCSS files into logical categories
+- Created core/ (UI Kit), layout/, features/, utilities/ folders
+- Merged duplicate components: badges (2→1), modals (2→1), spacing (2→1)
+- Renamed files: ios-search→search, team-wheel→team-viz, etc.
+- Cleaned custom-bootstrap.scss from component imports
+- Moved chat components from bootstrap to main.scss
+- Updated all imports in main.scss and custom-bootstrap.scss
+
+Structure:
+- core/ (9 files) - Reusable UI components
+- layout/ (5 files) - App structure
+- features/ (16 files in 6 folders) - Feature-specific styles
+- utilities/ (1 file) - Utility classes
+
+Benefits:
+- Clear categorization
+- No duplicate imports
+- Logical feature grouping
+- Easier maintenance
+- Clean architecture
+
+Breaking changes: None (CSS class names unchanged)
+"
+
+# Push
+git push
+```
+
+---
+
+## 📊 Метрики успеха
+
+### До реорганизации:
+```
+components/ - 30 файлов (хаос)
+layout/ - 2 файла
+utilities/ - пуста
+Дублирующиеся импорты: 8 компонентов
+Странные названия: ios-, telegram-, -specific, team-wheel
+```
+
+### После реорганизации:
+```
+core/ - 9-10 файлов (UI Kit)
+layout/ - 4-5 файлов (структура)
+features/ - 16 файлов в 6 папках (по функциям)
+utilities/ - 1 файл (spacing)
+Дублирующиеся импорты: 0
+Понятные названия: search, badges, team-viz
+```
+
+### Улучшения:
+- ✅ Четкая категоризация
+- ✅ Нет дубликатов
+- ✅ Логичная группировка
+- ✅ Легче найти нужный файл
+- ✅ Понятные названия
+- ✅ Масштабируемая структура
+
+---
+
+## ⚠️ Риски и как их минимизировать
+
+### Риск 1: Сломать стили
+**Минимизация:**
+- Делать backup перед каждым этапом
+- Тестировать после каждого этапа
+- Не менять CSS классы, только структуру файлов
+- Использовать git для отката
+
+### Риск 2: Забыть обновить импорт
+**Минимизация:**
+- Вести матрицу миграции
+- Проверять build errors
+- Grep поиск старых путей
+- Тестовая компиляция после каждого шага
+
+### Риск 3: Потерять изменения
+**Минимизация:**
+- Git commit после каждого этапа
+- Backup папка
+- Документировать прогресс
+
+### Риск 4: Слишком долго
+**Минимизация:**
+- Разбить на этапы
+- Можно делать частями (по 2-3 этапа в день)
+- Приоритет: сначала core, потом features
+
+---
+
+## 🎯 Альтернативный подход (если мало времени)
+
+### Минимальный рефакторинг (2 часа):
+
+1. **Убрать дубликаты из custom-bootstrap** (30 мин)
+2. **Переместить chat в main.scss** (15 мин)
+3. **Объединить badges** (20 мин)
+4. **Объединить modals** (15 мин)
+5. **Объединить spacing** (20 мин)
+6. **Переименовать ios-* файлы** (20 мин)
+
+Остальное оставить как есть. Будет лучше но не идеально.
+
+---
+
+## 📚 Дополнительные ресурсы
+
+- [Sass Guidelines](https://sass-guidelin.es/) - best practices
+- [7-1 Pattern](https://sass-guidelin.es/#the-7-1-pattern) - архитектура
+- [ITCSS](https://www.xfive.co/blog/itcss-scalable-maintainable-css-architecture/) - методология
+- [Atomic Design](https://atomicdesign.bradfrost.com/) - для вдохновения
+
+---
+
+---
+
+## 🚨 БОНУСНЫЙ ЭТАП: Полный отказ от Bootstrap
+
+**⚠️ ВНИМАНИЕ:** Этот этап увеличивает время реализации в 5-7 раз!
+
+### Зачем отказываться от Bootstrap?
+
+**Плюсы:**
+- ✅ Полный контроль над кодом
+- ✅ Уменьшение размера бандла (~300 KB → ~100 KB)
+- ✅ Нет неиспользуемого кода
+- ✅ Точная семантика под наше приложение
+- ✅ Легче кастомизация
+- ✅ Современный CSS (Grid, Custom Properties, Container Queries)
+
+**Минусы:**
+- ❌ Нужно написать свой UI Kit с нуля
+- ❌ Время: 40-60 часов вместо 8 часов
+- ❌ Нужно поддерживать свой код
+- ❌ Протестировать все компоненты
+- ❌ Обеспечить кроссбраузерность
+- ❌ Документировать систему
+
+### Что нужно переписать?
+
+**Bootstrap предоставляет (~180 компонентов):**
+
+1. **Grid System** - 12-колоночная сетка
+2. **Typography** - заголовки, параграфы, списки
+3. **Buttons** - 9 вариантов кнопок + sizes + states
+4. **Forms** - inputs, selects, checkboxes, radio, validation
+5. **Cards** - карточки с header/body/footer
+6. **Modals** - модальные окна с backdrop
+7. **Alerts** - уведомления
+8. **Badges** - бейджи
+9. **Breadcrumbs** - хлебные крошки
+10. **Dropdowns** - выпадающие меню
+11. **Navbar** - навигация
+12. **Pagination** - пагинация
+13. **Progress** - прогресс-бары
+14. **Spinners** - загрузчики
+15. **Tooltips** - подсказки
+16. **Popovers** - всплывающие окна
+17. **Utilities** - margin, padding, flex, display, colors...
+
+**Используется в проекте (по grep):**
+```bash
+# Найти что реально используется
+grep -r "class=" templates/ | grep -oE '\.(btn|card|modal|form-|input-|alert|badge|nav|dropdown|pagination|container|row|col-|d-|m-|p-|text-|bg-|border-)' | sort | uniq -c
+```
+
+### Этап 0: Аудит использования Bootstrap (4 часа)
+
+#### 0.1 Собрать статистику использования
+
+```bash
+cd backend
+
+# Создать скрипт для анализа
+cat > analyze_bootstrap_usage.py << 'EOF'
+import re
+from pathlib import Path
+from collections import Counter
+
+# Bootstrap классы
+BS_PATTERNS = [
+ r'\bbtn-\w+', r'\bcard-\w+', r'\bmodal-\w+', r'\bform-\w+',
+ r'\balert-\w+', r'\bbadge-\w+', r'\bnav-\w+', r'\bcol-\w+',
+ r'\brow\b', r'\bcontainer\b', r'\bd-\w+', r'\bm[tblrxy]?-\d',
+ r'\bp[tblrxy]?-\d', r'\btext-\w+', r'\bbg-\w+', r'\bborder-\w+'
+]
+
+templates_dir = Path('templates')
+all_classes = Counter()
+
+for html_file in templates_dir.rglob('*.html'):
+ content = html_file.read_text(encoding='utf-8')
+ for pattern in BS_PATTERNS:
+ matches = re.findall(pattern, content)
+ all_classes.update(matches)
+
+print("=== TOP 50 BOOTSTRAP CLASSES ===")
+for cls, count in all_classes.most_common(50):
+ print(f"{cls:30} - {count:4} uses")
+
+print(f"\n=== TOTAL: {len(all_classes)} unique Bootstrap classes ===")
+EOF
+
+.venv/Scripts/python analyze_bootstrap_usage.py > bootstrap_usage_report.txt
+```
+
+#### 0.2 Создать матрицу замены
+
+`BOOTSTRAP_REPLACEMENT_MATRIX.md`:
+
+```markdown
+| Bootstrap класс | Использований | Наш класс | Статус |
+|-----------------|---------------|-----------|--------|
+| .btn-primary | 150 | .button--primary | ⏳ |
+| .card | 120 | .card | ⏳ |
+| .modal | 45 | .modal | ⏳ |
+| .form-control | 200 | .input | ⏳ |
+| .container | 80 | .container | ⏳ |
+| .row | 100 | .grid | ⏳ |
+| .col-* | 300 | .grid__col | ⏳ |
+```
+
+#### 0.3 Оценить объем работы
+
+```bash
+# Посчитать templates с Bootstrap
+find templates/ -name "*.html" -exec grep -l "btn\|card\|modal\|form-control" {} \; | wc -l
+
+# Посчитать строк кода
+find templates/ -name "*.html" | xargs wc -l
+```
+
+### Этап B1: Создать свою Grid систему (6 часов)
+
+#### B1.1 Создать core/_grid.scss
+
+```scss
+// core/_grid.scss
+
+// =============================================================================
+// GRID SYSTEM
+// =============================================================================
+// Своя grid система на CSS Grid (не flexbox как Bootstrap)
+
+// Переменные
+$grid-columns: 12;
+$grid-gap: 1rem;
+$grid-container-max: 1200px;
+
+// Container
+.container {
+ width: 100%;
+ max-width: $grid-container-max;
+ margin: 0 auto;
+ padding: 0 1rem;
+}
+
+.container--fluid {
+ max-width: 100%;
+}
+
+// Grid
+.grid {
+ display: grid;
+ grid-template-columns: repeat($grid-columns, 1fr);
+ gap: $grid-gap;
+
+ // Responsive gaps
+ &--gap-sm { gap: 0.5rem; }
+ &--gap-lg { gap: 2rem; }
+}
+
+// Grid columns
+@for $i from 1 through $grid-columns {
+ .grid__col-#{$i} {
+ grid-column: span $i;
+ }
+}
+
+// Responsive
+@media (max-width: 768px) {
+ .grid__col-12-mobile {
+ grid-column: span 12;
+ }
+}
+
+// Auto-fit grid
+.grid--auto {
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+}
+```
+
+#### B1.2 Создать миграционный скрипт
+
+```python
+# scripts/replace_bootstrap_grid.py
+import re
+from pathlib import Path
+
+def replace_bootstrap_grid(content):
+ # .row → .grid
+ content = re.sub(r'\brow\b', 'grid', content)
+
+ # .col-{n} → .grid__col-{n}
+ content = re.sub(r'\bcol-(\d+)', r'grid__col-\1', content)
+
+ # .container → .container (оставить)
+
+ return content
+
+templates_dir = Path('templates')
+for html_file in templates_dir.rglob('*.html'):
+ content = html_file.read_text(encoding='utf-8')
+ new_content = replace_bootstrap_grid(content)
+ if content != new_content:
+ html_file.write_text(new_content, encoding='utf-8')
+ print(f"Updated: {html_file}")
+```
+
+### Этап B2: Создать свою Button систему (4 часа)
+
+```scss
+// core/_buttons.scss
+
+.button {
+ // Base styles
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0.5rem 1rem;
+ border: none;
+ border-radius: 0.375rem;
+ font-size: 1rem;
+ font-weight: 500;
+ line-height: 1.5;
+ cursor: pointer;
+ transition: all 0.2s;
+
+ &:hover { opacity: 0.85; }
+ &:active { transform: scale(0.98); }
+ &:disabled { opacity: 0.5; cursor: not-allowed; }
+
+ // Variants
+ &--primary { background: var(--color-primary); color: white; }
+ &--secondary { background: var(--color-secondary); color: white; }
+ &--success { background: var(--color-success); color: white; }
+ &--danger { background: var(--color-danger); color: white; }
+ &--outline { background: transparent; border: 1px solid currentColor; }
+
+ // Sizes
+ &--sm { padding: 0.25rem 0.5rem; font-size: 0.875rem; }
+ &--lg { padding: 0.75rem 1.5rem; font-size: 1.125rem; }
+
+ // Full width
+ &--block { width: 100%; }
+}
+
+// Миграция: .btn-primary → .button.button--primary
+```
+
+### Этап B3: Создать Form систему (8 часов)
+
+```scss
+// core/_forms.scss
+
+.form-group {
+ margin-bottom: 1rem;
+}
+
+.label {
+ display: block;
+ margin-bottom: 0.25rem;
+ font-weight: 500;
+ font-size: 0.875rem;
+}
+
+.input,
+.textarea,
+.select {
+ width: 100%;
+ padding: 0.5rem 0.75rem;
+ border: 1px solid var(--color-border);
+ border-radius: 0.375rem;
+ font-size: 1rem;
+ transition: border-color 0.2s;
+
+ &:focus {
+ outline: none;
+ border-color: var(--color-primary);
+ box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.1);
+ }
+
+ &--error {
+ border-color: var(--color-danger);
+ }
+
+ &:disabled {
+ background: var(--color-gray-100);
+ cursor: not-allowed;
+ }
+}
+
+.textarea {
+ resize: vertical;
+ min-height: 100px;
+}
+
+.checkbox,
+.radio {
+ // Кастомные checkbox/radio
+ appearance: none;
+ width: 1.25rem;
+ height: 1.25rem;
+ border: 2px solid var(--color-border);
+ border-radius: 0.25rem;
+ cursor: pointer;
+
+ &:checked {
+ background: var(--color-primary);
+ border-color: var(--color-primary);
+ }
+}
+
+.radio {
+ border-radius: 50%;
+}
+```
+
+### Этап B4: Utilities система (4 часа)
+
+```scss
+// utilities/_spacing.scss
+
+// Margin и Padding генератор
+$spacers: (
+ 0: 0,
+ 1: 0.25rem,
+ 2: 0.5rem,
+ 3: 0.75rem,
+ 4: 1rem,
+ 5: 1.5rem,
+ 6: 2rem,
+);
+
+@each $key, $value in $spacers {
+ // Margin
+ .m-#{$key} { margin: $value; }
+ .mt-#{$key} { margin-top: $value; }
+ .mb-#{$key} { margin-bottom: $value; }
+ .ml-#{$key} { margin-left: $value; }
+ .mr-#{$key} { margin-right: $value; }
+ .mx-#{$key} { margin-left: $value; margin-right: $value; }
+ .my-#{$key} { margin-top: $value; margin-bottom: $value; }
+
+ // Padding
+ .p-#{$key} { padding: $value; }
+ .pt-#{$key} { padding-top: $value; }
+ .pb-#{$key} { padding-bottom: $value; }
+ .pl-#{$key} { padding-left: $value; }
+ .pr-#{$key} { padding-right: $value; }
+ .px-#{$key} { padding-left: $value; padding-right: $value; }
+ .py-#{$key} { padding-top: $value; padding-bottom: $value; }
+}
+
+// Display utilities
+.d-none { display: none; }
+.d-block { display: block; }
+.d-flex { display: flex; }
+.d-grid { display: grid; }
+.d-inline { display: inline; }
+.d-inline-block { display: inline-block; }
+
+// Flexbox utilities
+.flex-row { flex-direction: row; }
+.flex-column { flex-direction: column; }
+.justify-center { justify-content: center; }
+.justify-between { justify-content: space-between; }
+.justify-end { justify-content: flex-end; }
+.align-center { align-items: center; }
+.align-start { align-items: flex-start; }
+.gap-1 { gap: 0.25rem; }
+.gap-2 { gap: 0.5rem; }
+.gap-3 { gap: 1rem; }
+
+// Text utilities
+.text-left { text-align: left; }
+.text-center { text-align: center; }
+.text-right { text-align: right; }
+.text-bold { font-weight: bold; }
+.text-sm { font-size: 0.875rem; }
+.text-lg { font-size: 1.125rem; }
+```
+
+### Этап B5: Cards, Modals, Alerts (6 часов)
+
+Написать свои версии этих компонентов.
+
+### Этап B6: Массовая замена в templates (12 часов)
+
+```python
+# scripts/migrate_all_bootstrap_classes.py
+
+REPLACEMENTS = {
+ # Buttons
+ r'\bbtn\b': 'button',
+ r'\bbtn-primary\b': 'button--primary',
+ r'\bbtn-secondary\b': 'button--secondary',
+ r'\bbtn-sm\b': 'button--sm',
+ r'\bbtn-lg\b': 'button--lg',
+
+ # Forms
+ r'\bform-control\b': 'input',
+ r'\bform-group\b': 'form-group',
+ r'\bform-label\b': 'label',
+
+ # Grid
+ r'\brow\b': 'grid',
+ r'\bcol-(\d+)': r'grid__col-\1',
+
+ # Cards
+ r'\bcard\b': 'card',
+ r'\bcard-body\b': 'card__body',
+ r'\bcard-header\b': 'card__header',
+
+ # Utilities
+ r'\bd-flex\b': 'd-flex',
+ r'\bjustify-content-center\b': 'justify-center',
+ # ... еще сотни замен
+}
+
+def migrate_template(filepath):
+ content = filepath.read_text(encoding='utf-8')
+ for old, new in REPLACEMENTS.items():
+ content = re.sub(old, new, content)
+ filepath.write_text(content, encoding='utf-8')
+
+# Запустить на всех templates
+for html_file in Path('templates').rglob('*.html'):
+ migrate_template(html_file)
+```
+
+### Этап B7: Удаление Bootstrap (1 час)
+
+```bash
+# Удалить из package.json
+npm uninstall bootstrap
+
+# Удалить custom-bootstrap.scss
+rm scss/custom-bootstrap.scss
+
+# Удалить из templates
+grep -r "bootstrap-custom.css" templates/
+# Заменить на только app.css
+
+# Обновить build скрипты
+# Оставить только npm run build:app
+```
+
+### Этап B8: Тестирование (8 часов)
+
+Протестировать каждую страницу:
+- Визуальная регрессия
+- Responsive
+- Кроссбраузерность
+- Формы работают
+- Модалы открываются
+- И т.д.
+
+---
+
+## 📊 Сравнение подходов
+
+### Вариант А: С Bootstrap (рекомендуется сейчас)
+
+**Плюсы:**
+- ⏱️ Быстро: 6-8 часов
+- ✅ Проверенное решение
+- ✅ Хорошая документация
+- ✅ Обновления безопасности
+- ✅ Кроссбраузерность из коробки
+
+**Минусы:**
+- 📦 Размер бандла: ~300 KB
+- 🔧 Ограничения кастомизации
+- 📚 Неиспользуемый код
+
+**Итоговый размер:**
+- bootstrap-custom.css: ~280 KB
+- app.css: ~95 KB
+- **ИТОГО: ~375 KB**
+
+### Вариант Б: Без Bootstrap (требует времени)
+
+**Плюсы:**
+- 📦 Размер бандла: ~100 KB (в 3 раза меньше!)
+- 🎨 Полный контроль
+- 🚀 Только нужный код
+- 💅 Современный CSS
+
+**Минусы:**
+- ⏱️ Долго: 40-60 часов
+- 🔧 Нужна поддержка
+- 🐛 Больше багов
+- 📚 Нужна документация
+
+**Итоговый размер:**
+- app.css: ~100 KB
+- **ИТОГО: ~100 KB**
+
+---
+
+## 🎯 Рекомендуемая стратегия
+
+### Поэтапный отказ от Bootstrap:
+
+1. **Этап 1-10 (6-8 часов):** Реорганизация SCSS с Bootstrap
+2. **Использовать проект 2-3 месяца**
+3. **Этап B (40-60 часов):** Постепенная замена Bootstrap своими стилями
+ - Сначала Grid → готово за выходные
+ - Потом Buttons → неделя
+ - Потом Forms → неделя
+ - Постепенно все остальное
+4. **Тестирование на продакшене**
+5. **Удаление Bootstrap когда все заменено**
+
+**Преимущества поэтапного подхода:**
+- ✅ Не ломаем текущий проект
+- ✅ Можно тестировать части
+- ✅ Откатиться легко
+- ✅ Меньше риска
+
+---
+
+## 🤔 Мое мнение
+
+**Для корпоративного Django приложения:**
+
+👍 **ЗА отказ от Bootstrap:**
+- Полный контроль над кодом
+- Меньше размер
+- Современные CSS возможности
+- Нет jQuery зависимостей (если используете Bootstrap JS)
+
+👎 **ПРОТИВ отказа от Bootstrap:**
+- Огромная работа (40-60 часов)
+- Нужно поддерживать свой код
+- Риск багов
+- Уже работает хорошо
+
+**Мой совет:**
+1. Сейчас сделать реорганизацию С Bootstrap (8 часов)
+2. Использовать 1-2 месяца
+3. Если реально чувствуете ограничения - начать постепенно заменять
+4. Если все работает нормально - оставить Bootstrap
+
+**Большинство крупных проектов используют Bootstrap/Tailwind/Foundation** - это нормально и правильно.
+
+---
+
+**Готов начать? Какой вариант выбираем?**
+
+**A)** Реорганизация с Bootstrap (8 часов, безопасно)
+**Б)** Полный отказ от Bootstrap (60 часов, амбициозно)
+**В)** Поэтапная замена (8 часов сейчас + 40 часов потом)