diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..06c7753
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,8 @@
+.git
+.gitignore
+.DS_Store
+node_modules
+*.log
+.env
+.env.local
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..ee8783b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,13 @@
+FROM php:8.2-apache
+
+# Установка PostgreSQL драйвера
+RUN apt-get update && apt-get install -y libpq-dev \
+ && docker-php-ext-install pdo pdo_pgsql \
+ && apt-get clean && rm -rf /var/lib/apt/lists/*
+
+# Включить модули Apache
+RUN a2enmod rewrite headers alias
+
+# Установка рабочей директории
+WORKDIR /var/www/html
+
diff --git a/OLD_CODE/.gitignore b/OLD_CODE/.gitignore
new file mode 100644
index 0000000..9c84dff
--- /dev/null
+++ b/OLD_CODE/.gitignore
@@ -0,0 +1,49 @@
+# IDE и редакторы
+.idea/
+.vscode/
+*.swp
+*.swo
+*~
+.DS_Store
+
+# Зависимости
+/vendor/
+/node_modules/
+
+# Логи
+*.log
+logs/
+
+# Загруженные файлы пользователей
+/uploads/products/*
+!/uploads/products/.gitkeep
+
+# Конфигурационные файлы с секретами (если есть)
+.env
+.env.local
+.env.*.local
+
+# Кэш
+/cache/
+*.cache
+
+# Временные файлы
+/tmp/
+*.tmp
+
+# Скомпилированные CSS
+*.css.map
+
+# База данных SQLite (если используется локально)
+*.db
+*.sqlite
+*.sqlite3
+
+# Файлы резервных копий
+*.bak
+*.backup
+
+# PHP debug/profiling
+.phpunit.result.cache
+phpunit.xml
+
diff --git a/README.md b/OLD_CODE/README.md
similarity index 100%
rename from README.md
rename to OLD_CODE/README.md
diff --git a/admin/index.php b/OLD_CODE/admin/index.php
similarity index 100%
rename from admin/index.php
rename to OLD_CODE/admin/index.php
diff --git a/api/add_to_cart.php b/OLD_CODE/api/add_to_cart.php
similarity index 100%
rename from api/add_to_cart.php
rename to OLD_CODE/api/add_to_cart.php
diff --git a/api/auth.php b/OLD_CODE/api/auth.php
similarity index 100%
rename from api/auth.php
rename to OLD_CODE/api/auth.php
diff --git a/api/cart.php b/OLD_CODE/api/cart.php
similarity index 100%
rename from api/cart.php
rename to OLD_CODE/api/cart.php
diff --git a/api/get_cart.php b/OLD_CODE/api/get_cart.php
similarity index 100%
rename from api/get_cart.php
rename to OLD_CODE/api/get_cart.php
diff --git a/api/get_cart_count.php b/OLD_CODE/api/get_cart_count.php
similarity index 100%
rename from api/get_cart_count.php
rename to OLD_CODE/api/get_cart_count.php
diff --git a/api/get_product.php b/OLD_CODE/api/get_product.php
similarity index 100%
rename from api/get_product.php
rename to OLD_CODE/api/get_product.php
diff --git a/api/process_order.php b/OLD_CODE/api/process_order.php
similarity index 100%
rename from api/process_order.php
rename to OLD_CODE/api/process_order.php
diff --git a/api/register_handler.php b/OLD_CODE/api/register_handler.php
similarity index 100%
rename from api/register_handler.php
rename to OLD_CODE/api/register_handler.php
diff --git a/api/update_cart.php b/OLD_CODE/api/update_cart.php
similarity index 100%
rename from api/update_cart.php
rename to OLD_CODE/api/update_cart.php
diff --git a/assets/img/1 — копия.jpg b/OLD_CODE/assets/img/1 — копия.jpg
similarity index 100%
rename from assets/img/1 — копия.jpg
rename to OLD_CODE/assets/img/1 — копия.jpg
diff --git a/assets/img/1.jpg b/OLD_CODE/assets/img/1.jpg
similarity index 100%
rename from assets/img/1.jpg
rename to OLD_CODE/assets/img/1.jpg
diff --git a/assets/img/100.jpg b/OLD_CODE/assets/img/100.jpg
similarity index 100%
rename from assets/img/100.jpg
rename to OLD_CODE/assets/img/100.jpg
diff --git a/assets/img/11.jpg b/OLD_CODE/assets/img/11.jpg
similarity index 100%
rename from assets/img/11.jpg
rename to OLD_CODE/assets/img/11.jpg
diff --git a/assets/img/111.jpg b/OLD_CODE/assets/img/111.jpg
similarity index 100%
rename from assets/img/111.jpg
rename to OLD_CODE/assets/img/111.jpg
diff --git a/assets/img/11_1.png b/OLD_CODE/assets/img/11_1.png
similarity index 100%
rename from assets/img/11_1.png
rename to OLD_CODE/assets/img/11_1.png
diff --git a/assets/img/1_1.jpg b/OLD_CODE/assets/img/1_1.jpg
similarity index 100%
rename from assets/img/1_1.jpg
rename to OLD_CODE/assets/img/1_1.jpg
diff --git a/assets/img/1_2.jpg b/OLD_CODE/assets/img/1_2.jpg
similarity index 100%
rename from assets/img/1_2.jpg
rename to OLD_CODE/assets/img/1_2.jpg
diff --git a/assets/img/1_2.png b/OLD_CODE/assets/img/1_2.png
similarity index 100%
rename from assets/img/1_2.png
rename to OLD_CODE/assets/img/1_2.png
diff --git a/assets/img/2.jpg b/OLD_CODE/assets/img/2.jpg
similarity index 100%
rename from assets/img/2.jpg
rename to OLD_CODE/assets/img/2.jpg
diff --git a/assets/img/22.jpg b/OLD_CODE/assets/img/22.jpg
similarity index 100%
rename from assets/img/22.jpg
rename to OLD_CODE/assets/img/22.jpg
diff --git a/assets/img/25.jpg b/OLD_CODE/assets/img/25.jpg
similarity index 100%
rename from assets/img/25.jpg
rename to OLD_CODE/assets/img/25.jpg
diff --git a/assets/img/2_2.jpg b/OLD_CODE/assets/img/2_2.jpg
similarity index 100%
rename from assets/img/2_2.jpg
rename to OLD_CODE/assets/img/2_2.jpg
diff --git a/assets/img/2_2.png b/OLD_CODE/assets/img/2_2.png
similarity index 100%
rename from assets/img/2_2.png
rename to OLD_CODE/assets/img/2_2.png
diff --git a/assets/img/3.jpg b/OLD_CODE/assets/img/3.jpg
similarity index 100%
rename from assets/img/3.jpg
rename to OLD_CODE/assets/img/3.jpg
diff --git a/assets/img/3_3.jpg b/OLD_CODE/assets/img/3_3.jpg
similarity index 100%
rename from assets/img/3_3.jpg
rename to OLD_CODE/assets/img/3_3.jpg
diff --git a/assets/img/3_3.png b/OLD_CODE/assets/img/3_3.png
similarity index 100%
rename from assets/img/3_3.png
rename to OLD_CODE/assets/img/3_3.png
diff --git a/assets/img/4.jpg b/OLD_CODE/assets/img/4.jpg
similarity index 100%
rename from assets/img/4.jpg
rename to OLD_CODE/assets/img/4.jpg
diff --git a/assets/img/44.jpg b/OLD_CODE/assets/img/44.jpg
similarity index 100%
rename from assets/img/44.jpg
rename to OLD_CODE/assets/img/44.jpg
diff --git a/assets/img/444 b/OLD_CODE/assets/img/444
similarity index 100%
rename from assets/img/444
rename to OLD_CODE/assets/img/444
diff --git a/assets/img/444 (1).png b/OLD_CODE/assets/img/444 (1).png
similarity index 100%
rename from assets/img/444 (1).png
rename to OLD_CODE/assets/img/444 (1).png
diff --git a/assets/img/444.jpg b/OLD_CODE/assets/img/444.jpg
similarity index 100%
rename from assets/img/444.jpg
rename to OLD_CODE/assets/img/444.jpg
diff --git a/assets/img/444.png b/OLD_CODE/assets/img/444.png
similarity index 100%
rename from assets/img/444.png
rename to OLD_CODE/assets/img/444.png
diff --git a/assets/img/4_1.jpg b/OLD_CODE/assets/img/4_1.jpg
similarity index 100%
rename from assets/img/4_1.jpg
rename to OLD_CODE/assets/img/4_1.jpg
diff --git a/assets/img/5.jpg b/OLD_CODE/assets/img/5.jpg
similarity index 100%
rename from assets/img/5.jpg
rename to OLD_CODE/assets/img/5.jpg
diff --git a/assets/img/5_5.jpg b/OLD_CODE/assets/img/5_5.jpg
similarity index 100%
rename from assets/img/5_5.jpg
rename to OLD_CODE/assets/img/5_5.jpg
diff --git a/assets/img/5_5.png b/OLD_CODE/assets/img/5_5.png
similarity index 100%
rename from assets/img/5_5.png
rename to OLD_CODE/assets/img/5_5.png
diff --git a/assets/img/6.jpg b/OLD_CODE/assets/img/6.jpg
similarity index 100%
rename from assets/img/6.jpg
rename to OLD_CODE/assets/img/6.jpg
diff --git a/assets/img/6_6.jpg b/OLD_CODE/assets/img/6_6.jpg
similarity index 100%
rename from assets/img/6_6.jpg
rename to OLD_CODE/assets/img/6_6.jpg
diff --git a/assets/img/6_6.png b/OLD_CODE/assets/img/6_6.png
similarity index 100%
rename from assets/img/6_6.png
rename to OLD_CODE/assets/img/6_6.png
diff --git a/assets/img/7.jpg b/OLD_CODE/assets/img/7.jpg
similarity index 100%
rename from assets/img/7.jpg
rename to OLD_CODE/assets/img/7.jpg
diff --git a/assets/img/77.jpg b/OLD_CODE/assets/img/77.jpg
similarity index 100%
rename from assets/img/77.jpg
rename to OLD_CODE/assets/img/77.jpg
diff --git a/assets/img/777 (1).png b/OLD_CODE/assets/img/777 (1).png
similarity index 100%
rename from assets/img/777 (1).png
rename to OLD_CODE/assets/img/777 (1).png
diff --git a/assets/img/777.jpg b/OLD_CODE/assets/img/777.jpg
similarity index 100%
rename from assets/img/777.jpg
rename to OLD_CODE/assets/img/777.jpg
diff --git a/assets/img/777.png b/OLD_CODE/assets/img/777.png
similarity index 100%
rename from assets/img/777.png
rename to OLD_CODE/assets/img/777.png
diff --git a/assets/img/7_7.jpg b/OLD_CODE/assets/img/7_7.jpg
similarity index 100%
rename from assets/img/7_7.jpg
rename to OLD_CODE/assets/img/7_7.jpg
diff --git a/assets/img/7_7.png b/OLD_CODE/assets/img/7_7.png
similarity index 100%
rename from assets/img/7_7.png
rename to OLD_CODE/assets/img/7_7.png
diff --git a/assets/img/8.jpg b/OLD_CODE/assets/img/8.jpg
similarity index 100%
rename from assets/img/8.jpg
rename to OLD_CODE/assets/img/8.jpg
diff --git a/assets/img/88.jpg b/OLD_CODE/assets/img/88.jpg
similarity index 100%
rename from assets/img/88.jpg
rename to OLD_CODE/assets/img/88.jpg
diff --git a/assets/img/888 (1).png b/OLD_CODE/assets/img/888 (1).png
similarity index 100%
rename from assets/img/888 (1).png
rename to OLD_CODE/assets/img/888 (1).png
diff --git a/assets/img/888.jpg b/OLD_CODE/assets/img/888.jpg
similarity index 100%
rename from assets/img/888.jpg
rename to OLD_CODE/assets/img/888.jpg
diff --git a/assets/img/888.png b/OLD_CODE/assets/img/888.png
similarity index 100%
rename from assets/img/888.png
rename to OLD_CODE/assets/img/888.png
diff --git a/assets/img/8_8.png b/OLD_CODE/assets/img/8_8.png
similarity index 100%
rename from assets/img/8_8.png
rename to OLD_CODE/assets/img/8_8.png
diff --git a/assets/img/9.jpg b/OLD_CODE/assets/img/9.jpg
similarity index 100%
rename from assets/img/9.jpg
rename to OLD_CODE/assets/img/9.jpg
diff --git a/assets/img/99.jpg b/OLD_CODE/assets/img/99.jpg
similarity index 100%
rename from assets/img/99.jpg
rename to OLD_CODE/assets/img/99.jpg
diff --git a/assets/img/99.png b/OLD_CODE/assets/img/99.png
similarity index 100%
rename from assets/img/99.png
rename to OLD_CODE/assets/img/99.png
diff --git a/assets/img/99_1.jpg b/OLD_CODE/assets/img/99_1.jpg
similarity index 100%
rename from assets/img/99_1.jpg
rename to OLD_CODE/assets/img/99_1.jpg
diff --git a/assets/img/99_2.jpg b/OLD_CODE/assets/img/99_2.jpg
similarity index 100%
rename from assets/img/99_2.jpg
rename to OLD_CODE/assets/img/99_2.jpg
diff --git a/assets/img/99_3.png b/OLD_CODE/assets/img/99_3.png
similarity index 100%
rename from assets/img/99_3.png
rename to OLD_CODE/assets/img/99_3.png
diff --git a/assets/img/9_9.jpg b/OLD_CODE/assets/img/9_9.jpg
similarity index 100%
rename from assets/img/9_9.jpg
rename to OLD_CODE/assets/img/9_9.jpg
diff --git a/assets/img/9_9.png b/OLD_CODE/assets/img/9_9.png
similarity index 100%
rename from assets/img/9_9.png
rename to OLD_CODE/assets/img/9_9.png
diff --git a/assets/img/black.png b/OLD_CODE/assets/img/black.png
similarity index 100%
rename from assets/img/black.png
rename to OLD_CODE/assets/img/black.png
diff --git a/assets/img/black1.png b/OLD_CODE/assets/img/black1.png
similarity index 100%
rename from assets/img/black1.png
rename to OLD_CODE/assets/img/black1.png
diff --git a/assets/img/black2.png b/OLD_CODE/assets/img/black2.png
similarity index 100%
rename from assets/img/black2.png
rename to OLD_CODE/assets/img/black2.png
diff --git a/assets/img/brown.png b/OLD_CODE/assets/img/brown.png
similarity index 100%
rename from assets/img/brown.png
rename to OLD_CODE/assets/img/brown.png
diff --git a/assets/img/brown1.png b/OLD_CODE/assets/img/brown1.png
similarity index 100%
rename from assets/img/brown1.png
rename to OLD_CODE/assets/img/brown1.png
diff --git a/assets/img/brown2.png b/OLD_CODE/assets/img/brown2.png
similarity index 100%
rename from assets/img/brown2.png
rename to OLD_CODE/assets/img/brown2.png
diff --git a/assets/img/chair.PNG b/OLD_CODE/assets/img/chair.PNG
similarity index 100%
rename from assets/img/chair.PNG
rename to OLD_CODE/assets/img/chair.PNG
diff --git a/assets/img/gray.png b/OLD_CODE/assets/img/gray.png
similarity index 100%
rename from assets/img/gray.png
rename to OLD_CODE/assets/img/gray.png
diff --git a/assets/img/gray1.png b/OLD_CODE/assets/img/gray1.png
similarity index 100%
rename from assets/img/gray1.png
rename to OLD_CODE/assets/img/gray1.png
diff --git a/assets/img/gray2.png b/OLD_CODE/assets/img/gray2.png
similarity index 100%
rename from assets/img/gray2.png
rename to OLD_CODE/assets/img/gray2.png
diff --git a/assets/img/диван.jpg b/OLD_CODE/assets/img/диван.jpg
similarity index 100%
rename from assets/img/диван.jpg
rename to OLD_CODE/assets/img/диван.jpg
diff --git a/assets/img/диван_1.jpg b/OLD_CODE/assets/img/диван_1.jpg
similarity index 100%
rename from assets/img/диван_1.jpg
rename to OLD_CODE/assets/img/диван_1.jpg
diff --git a/assets/img/кресло.jpg b/OLD_CODE/assets/img/кресло.jpg
similarity index 100%
rename from assets/img/кресло.jpg
rename to OLD_CODE/assets/img/кресло.jpg
diff --git a/assets/img/кресло_1.jpg b/OLD_CODE/assets/img/кресло_1.jpg
similarity index 100%
rename from assets/img/кресло_1.jpg
rename to OLD_CODE/assets/img/кресло_1.jpg
diff --git a/assets/img/слайдер_1.jpg b/OLD_CODE/assets/img/слайдер_1.jpg
similarity index 100%
rename from assets/img/слайдер_1.jpg
rename to OLD_CODE/assets/img/слайдер_1.jpg
diff --git a/assets/img/слайдер_2.jpg b/OLD_CODE/assets/img/слайдер_2.jpg
similarity index 100%
rename from assets/img/слайдер_2.jpg
rename to OLD_CODE/assets/img/слайдер_2.jpg
diff --git a/assets/img/слайдер_3.jpg b/OLD_CODE/assets/img/слайдер_3.jpg
similarity index 100%
rename from assets/img/слайдер_3.jpg
rename to OLD_CODE/assets/img/слайдер_3.jpg
diff --git a/assets/img/слайдер_4.jpg b/OLD_CODE/assets/img/слайдер_4.jpg
similarity index 100%
rename from assets/img/слайдер_4.jpg
rename to OLD_CODE/assets/img/слайдер_4.jpg
diff --git a/assets/img/слайдер_5.jpg b/OLD_CODE/assets/img/слайдер_5.jpg
similarity index 100%
rename from assets/img/слайдер_5.jpg
rename to OLD_CODE/assets/img/слайдер_5.jpg
diff --git a/assets/img/слайдер_6.jpg b/OLD_CODE/assets/img/слайдер_6.jpg
similarity index 100%
rename from assets/img/слайдер_6.jpg
rename to OLD_CODE/assets/img/слайдер_6.jpg
diff --git a/assets/img/спальня.jpg b/OLD_CODE/assets/img/спальня.jpg
similarity index 100%
rename from assets/img/спальня.jpg
rename to OLD_CODE/assets/img/спальня.jpg
diff --git a/assets/img/стили_оформления.css b/OLD_CODE/assets/img/стили_оформления.css
similarity index 100%
rename from assets/img/стили_оформления.css
rename to OLD_CODE/assets/img/стили_оформления.css
diff --git a/assets/js/checkout.js b/OLD_CODE/assets/js/checkout.js
similarity index 100%
rename from assets/js/checkout.js
rename to OLD_CODE/assets/js/checkout.js
diff --git a/assets/js/profile.js b/OLD_CODE/assets/js/profile.js
similarity index 100%
rename from assets/js/profile.js
rename to OLD_CODE/assets/js/profile.js
diff --git a/assets/less/checkout.less b/OLD_CODE/assets/less/checkout.less
similarity index 100%
rename from assets/less/checkout.less
rename to OLD_CODE/assets/less/checkout.less
diff --git a/assets/less/mixins.less b/OLD_CODE/assets/less/mixins.less
similarity index 100%
rename from assets/less/mixins.less
rename to OLD_CODE/assets/less/mixins.less
diff --git a/assets/less/style.less b/OLD_CODE/assets/less/style.less
similarity index 100%
rename from assets/less/style.less
rename to OLD_CODE/assets/less/style.less
diff --git a/config/check_auth.js b/OLD_CODE/config/check_auth.js
similarity index 100%
rename from config/check_auth.js
rename to OLD_CODE/config/check_auth.js
diff --git a/config/database.php b/OLD_CODE/config/database.php
similarity index 100%
rename from config/database.php
rename to OLD_CODE/config/database.php
diff --git a/img b/OLD_CODE/img
similarity index 100%
rename from img
rename to OLD_CODE/img
diff --git a/img2 b/OLD_CODE/img2
similarity index 100%
rename from img2
rename to OLD_CODE/img2
diff --git a/includes/auth.php b/OLD_CODE/includes/auth.php
similarity index 100%
rename from includes/auth.php
rename to OLD_CODE/includes/auth.php
diff --git a/includes/footer.php b/OLD_CODE/includes/footer.php
similarity index 100%
rename from includes/footer.php
rename to OLD_CODE/includes/footer.php
diff --git a/includes/functions.php b/OLD_CODE/includes/functions.php
similarity index 100%
rename from includes/functions.php
rename to OLD_CODE/includes/functions.php
diff --git a/includes/header.php b/OLD_CODE/includes/header.php
similarity index 100%
rename from includes/header.php
rename to OLD_CODE/includes/header.php
diff --git a/OLD_CODE/migrations/001_initial_schema.sql b/OLD_CODE/migrations/001_initial_schema.sql
new file mode 100644
index 0000000..c57629b
--- /dev/null
+++ b/OLD_CODE/migrations/001_initial_schema.sql
@@ -0,0 +1,73 @@
+-- 001_initial_schema.sql
+-- Создание базовых таблиц для AETERNA
+
+-- Таблица пользователей
+CREATE TABLE IF NOT EXISTS users (
+ user_id SERIAL PRIMARY KEY,
+ email VARCHAR(255) UNIQUE NOT NULL,
+ password_hash VARCHAR(255) NOT NULL,
+ full_name VARCHAR(100) NOT NULL,
+ phone VARCHAR(20),
+ city VARCHAR(100),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ last_login TIMESTAMP,
+ is_active BOOLEAN DEFAULT TRUE,
+ is_admin BOOLEAN DEFAULT FALSE
+);
+
+-- Таблица категорий
+CREATE TABLE IF NOT EXISTS categories (
+ category_id SERIAL PRIMARY KEY,
+ name VARCHAR(100) NOT NULL,
+ slug VARCHAR(100) UNIQUE NOT NULL,
+ parent_id INTEGER REFERENCES categories(category_id) ON DELETE SET NULL,
+ description TEXT,
+ sort_order INTEGER DEFAULT 0,
+ is_active BOOLEAN DEFAULT TRUE,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Таблица подкатегорий
+CREATE TABLE IF NOT EXISTS subcategories (
+ subcategory_id SERIAL PRIMARY KEY,
+ category_id INTEGER REFERENCES categories(category_id) ON DELETE CASCADE,
+ name VARCHAR(100) NOT NULL,
+ slug VARCHAR(100) UNIQUE NOT NULL,
+ description TEXT,
+ sort_order INTEGER DEFAULT 0,
+ is_active BOOLEAN DEFAULT TRUE,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Таблица товаров
+CREATE TABLE IF NOT EXISTS products (
+ product_id SERIAL PRIMARY KEY,
+ category_id INTEGER REFERENCES categories(category_id) ON DELETE SET NULL,
+ name VARCHAR(200) NOT NULL,
+ slug VARCHAR(200) UNIQUE NOT NULL,
+ description TEXT,
+ price DECIMAL(10, 2) NOT NULL,
+ old_price DECIMAL(10, 2),
+ sku VARCHAR(50) UNIQUE,
+ stock_quantity INTEGER DEFAULT 0,
+ is_available BOOLEAN DEFAULT TRUE,
+ is_featured BOOLEAN DEFAULT FALSE,
+ rating DECIMAL(3, 2) DEFAULT 0,
+ review_count INTEGER DEFAULT 0,
+ image_url VARCHAR(500),
+ color VARCHAR(50),
+ material VARCHAR(100),
+ card_size VARCHAR(20) DEFAULT 'small',
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Индексы для быстрого поиска
+CREATE INDEX IF NOT EXISTS idx_products_category ON products(category_id);
+CREATE INDEX IF NOT EXISTS idx_products_available ON products(is_available);
+CREATE INDEX IF NOT EXISTS idx_products_price ON products(price);
+CREATE INDEX IF NOT EXISTS idx_categories_parent ON categories(parent_id);
+CREATE INDEX IF NOT EXISTS idx_categories_active ON categories(is_active);
+
diff --git a/OLD_CODE/migrations/002_add_cart_orders.sql b/OLD_CODE/migrations/002_add_cart_orders.sql
new file mode 100644
index 0000000..e4bf13c
--- /dev/null
+++ b/OLD_CODE/migrations/002_add_cart_orders.sql
@@ -0,0 +1,70 @@
+-- 002_add_cart_orders.sql
+-- Таблицы для корзины и заказов
+
+-- Таблица корзины
+CREATE TABLE IF NOT EXISTS cart (
+ cart_id SERIAL PRIMARY KEY,
+ user_id INTEGER REFERENCES users(user_id) ON DELETE CASCADE,
+ product_id INTEGER REFERENCES products(product_id) ON DELETE CASCADE,
+ quantity INTEGER DEFAULT 1 CHECK (quantity > 0),
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ UNIQUE(user_id, product_id)
+);
+
+-- Таблица заказов
+CREATE TABLE IF NOT EXISTS orders (
+ order_id SERIAL PRIMARY KEY,
+ order_number VARCHAR(50) UNIQUE NOT NULL,
+ user_id INTEGER REFERENCES users(user_id) ON DELETE SET NULL,
+
+ -- Контактная информация
+ customer_name VARCHAR(100) NOT NULL,
+ customer_email VARCHAR(255) NOT NULL,
+ customer_phone VARCHAR(20) NOT NULL,
+
+ -- Адрес доставки
+ delivery_address TEXT NOT NULL,
+ delivery_region VARCHAR(100),
+ postal_code VARCHAR(20),
+
+ -- Способы
+ delivery_method VARCHAR(50) DEFAULT 'courier',
+ payment_method VARCHAR(50) DEFAULT 'card',
+
+ -- Суммы
+ subtotal DECIMAL(10, 2) NOT NULL,
+ discount_amount DECIMAL(10, 2) DEFAULT 0,
+ delivery_price DECIMAL(10, 2) DEFAULT 0,
+ final_amount DECIMAL(10, 2) NOT NULL,
+
+ -- Промокод
+ promo_code VARCHAR(50),
+
+ -- Статус и даты
+ status VARCHAR(30) DEFAULT 'pending',
+ notes TEXT,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ completed_at TIMESTAMP
+);
+
+-- Таблица позиций заказа
+CREATE TABLE IF NOT EXISTS order_items (
+ item_id SERIAL PRIMARY KEY,
+ order_id INTEGER REFERENCES orders(order_id) ON DELETE CASCADE,
+ product_id INTEGER REFERENCES products(product_id) ON DELETE SET NULL,
+ product_name VARCHAR(200) NOT NULL,
+ product_price DECIMAL(10, 2) NOT NULL,
+ quantity INTEGER NOT NULL CHECK (quantity > 0),
+ total_price DECIMAL(10, 2) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Индексы
+CREATE INDEX IF NOT EXISTS idx_cart_user ON cart(user_id);
+CREATE INDEX IF NOT EXISTS idx_orders_user ON orders(user_id);
+CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status);
+CREATE INDEX IF NOT EXISTS idx_orders_created ON orders(created_at);
+CREATE INDEX IF NOT EXISTS idx_order_items_order ON order_items(order_id);
+
diff --git a/OLD_CODE/migrations/003_add_product_fields.sql b/OLD_CODE/migrations/003_add_product_fields.sql
new file mode 100644
index 0000000..3fbb9ba
--- /dev/null
+++ b/OLD_CODE/migrations/003_add_product_fields.sql
@@ -0,0 +1,57 @@
+-- 003_add_product_fields.sql
+-- Добавление дополнительных полей (если таблицы уже существуют)
+
+-- Добавляем поля в products если их нет
+DO $$
+BEGIN
+ -- color
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'products' AND column_name = 'color') THEN
+ ALTER TABLE products ADD COLUMN color VARCHAR(50);
+ END IF;
+
+ -- material
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'products' AND column_name = 'material') THEN
+ ALTER TABLE products ADD COLUMN material VARCHAR(100);
+ END IF;
+
+ -- card_size
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'products' AND column_name = 'card_size') THEN
+ ALTER TABLE products ADD COLUMN card_size VARCHAR(20) DEFAULT 'small';
+ END IF;
+END $$;
+
+-- Добавляем поля в users если их нет
+DO $$
+BEGIN
+ -- city
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'users' AND column_name = 'city') THEN
+ ALTER TABLE users ADD COLUMN city VARCHAR(100);
+ END IF;
+
+ -- last_login
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'users' AND column_name = 'last_login') THEN
+ ALTER TABLE users ADD COLUMN last_login TIMESTAMP;
+ END IF;
+END $$;
+
+-- Добавляем поля в categories если их нет
+DO $$
+BEGIN
+ -- updated_at
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'categories' AND column_name = 'updated_at') THEN
+ ALTER TABLE categories ADD COLUMN updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
+ END IF;
+
+ -- created_at
+ IF NOT EXISTS (SELECT 1 FROM information_schema.columns
+ WHERE table_name = 'categories' AND column_name = 'created_at') THEN
+ ALTER TABLE categories ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
+ END IF;
+END $$;
+
diff --git a/OLD_CODE/migrations/004_grant_admin_to_admin_mail.sql b/OLD_CODE/migrations/004_grant_admin_to_admin_mail.sql
new file mode 100644
index 0000000..2ccf98c
--- /dev/null
+++ b/OLD_CODE/migrations/004_grant_admin_to_admin_mail.sql
@@ -0,0 +1,50 @@
+-- 004_grant_admin_to_admin_mail.sql
+-- Миграция: Назначение прав администратора пользователю admin@mail.ru
+
+-- Обновляем пользователя admin@mail.ru, давая ему права администратора
+UPDATE users
+SET is_admin = TRUE,
+ is_active = TRUE,
+ updated_at = CURRENT_TIMESTAMP
+WHERE email = 'admin@mail.ru';
+
+-- Проверяем результат
+DO $$
+DECLARE
+ updated_count INTEGER;
+ user_info RECORD;
+BEGIN
+ GET DIAGNOSTICS updated_count = ROW_COUNT;
+
+ IF updated_count > 0 THEN
+ -- Получаем информацию об обновленном пользователе
+ SELECT user_id, email, full_name, is_admin, is_active
+ INTO user_info
+ FROM users
+ WHERE email = 'admin@mail.ru';
+
+ RAISE NOTICE 'Пользователь % (ID: %) успешно получил права администратора',
+ user_info.email, user_info.user_id;
+ RAISE NOTICE 'ФИО: %, Админ: %, Активен: %',
+ user_info.full_name, user_info.is_admin, user_info.is_active;
+ ELSE
+ -- Если пользователь не найден, создаем его с правами админа
+ INSERT INTO users (email, password_hash, full_name, phone, city, is_admin, is_active)
+ VALUES (
+ 'admin@mail.ru',
+ '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', -- admin123
+ 'Администратор',
+ '+79129991223',
+ 'Москва',
+ TRUE,
+ TRUE
+ )
+ ON CONFLICT (email) DO UPDATE
+ SET is_admin = TRUE,
+ is_active = TRUE,
+ updated_at = CURRENT_TIMESTAMP;
+
+ RAISE NOTICE 'Пользователь admin@mail.ru создан/обновлен с правами администратора';
+ END IF;
+END $$;
+
diff --git a/OLD_CODE/migrations/grant_admin.php b/OLD_CODE/migrations/grant_admin.php
new file mode 100644
index 0000000..40d7258
--- /dev/null
+++ b/OLD_CODE/migrations/grant_admin.php
@@ -0,0 +1,85 @@
+getConnection();
+ echo "[OK] Подключение к базе данных успешно\n\n";
+
+ $email = 'admin@mail.ru';
+
+ $checkStmt = $db->prepare("SELECT user_id, email, full_name, is_admin, is_active FROM users WHERE email = ?");
+ $checkStmt->execute([$email]);
+ $user = $checkStmt->fetch(PDO::FETCH_ASSOC);
+
+ if ($user) {
+ echo "[INFO] Найден пользователь:\n";
+ echo " Email: {$user['email']}\n";
+ echo " ФИО: {$user['full_name']}\n";
+ echo " Админ: " . ($user['is_admin'] ? 'ДА' : 'НЕТ') . "\n";
+ echo " Активен: " . ($user['is_active'] ? 'ДА' : 'НЕТ') . "\n\n";
+
+ if ($user['is_admin']) {
+ echo "[INFO] Пользователь уже имеет права администратора\n";
+ } else {
+
+ $updateStmt = $db->prepare("
+ UPDATE users
+ SET is_admin = TRUE,
+ is_active = TRUE,
+ updated_at = CURRENT_TIMESTAMP
+ WHERE email = ?
+ ");
+ $updateStmt->execute([$email]);
+
+ echo "[SUCCESS] Права администратора успешно назначены!\n";
+ }
+ } else {
+ echo "[WARN] Пользователь с email $email не найден\n";
+ echo "[INFO] Создаю нового пользователя с правами администратора...\n";
+
+ $password_hash = password_hash('admin123', PASSWORD_DEFAULT);
+
+ $insertStmt = $db->prepare("
+ INSERT INTO users (email, password_hash, full_name, phone, city, is_admin, is_active)
+ VALUES (?, ?, ?, ?, ?, CAST(? AS boolean), TRUE)
+ RETURNING user_id
+ ");
+
+ $insertStmt->execute([
+ $email,
+ $password_hash,
+ 'Администратор',
+ '+79129991223',
+ 'Москва',
+ 'true'
+ ]);
+
+ $user_id = $insertStmt->fetchColumn();
+ echo "[SUCCESS] Пользователь создан с ID: $user_id\n";
+ echo "[INFO] Email: $email\n";
+ echo "[INFO] Пароль по умолчанию: admin123\n";
+ echo "[WARN] Рекомендуется сменить пароль после первого входа!\n";
+ }
+
+ $verifyStmt = $db->prepare("SELECT user_id, email, full_name, is_admin, is_active FROM users WHERE email = ?");
+ $verifyStmt->execute([$email]);
+ $finalUser = $verifyStmt->fetch(PDO::FETCH_ASSOC);
+
+ echo "\n===========================================\n";
+ echo " Итоговый статус:\n";
+ echo "===========================================\n";
+ echo " Email: {$finalUser['email']}\n";
+ echo " ФИО: {$finalUser['full_name']}\n";
+ echo " Админ: " . ($finalUser['is_admin'] ? 'ДА ✓' : 'НЕТ ✗') . "\n";
+ echo " Активен: " . ($finalUser['is_active'] ? 'ДА ✓' : 'НЕТ ✗') . "\n";
+ echo "===========================================\n";
+
+} catch (PDOException $e) {
+ echo "[ERROR] Ошибка: " . $e->getMessage() . "\n";
+ exit(1);
+}
diff --git a/OLD_CODE/migrations/migrate.php b/OLD_CODE/migrations/migrate.php
new file mode 100644
index 0000000..7f009a7
--- /dev/null
+++ b/OLD_CODE/migrations/migrate.php
@@ -0,0 +1,95 @@
+getConnection();
+ echo "[OK] Подключение к базе данных успешно\n\n";
+
+ $db->exec("
+ CREATE TABLE IF NOT EXISTS migrations (
+ id SERIAL PRIMARY KEY,
+ filename VARCHAR(255) NOT NULL UNIQUE,
+ applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+ )
+ ");
+ echo "[OK] Таблица migrations готова\n";
+
+ $stmt = $db->query("SELECT filename FROM migrations ORDER BY filename");
+ $applied = $stmt->fetchAll(PDO::FETCH_COLUMN);
+ echo "[INFO] Уже применено миграций: " . count($applied) . "\n\n";
+
+ $migrationFiles = glob(__DIR__ . '/*.sql');
+ sort($migrationFiles);
+
+ $newMigrations = 0;
+
+ foreach ($migrationFiles as $file) {
+ $filename = basename($file);
+
+ if ($filename === 'seed_data.sql') {
+ continue;
+ }
+
+ if (in_array($filename, $applied)) {
+ echo "[SKIP] $filename (уже применена)\n";
+ continue;
+ }
+
+ echo "[RUN] Применяю $filename... ";
+
+ $sql = file_get_contents($file);
+
+ try {
+ $db->exec($sql);
+
+ $stmt = $db->prepare("INSERT INTO migrations (filename) VALUES (?)");
+ $stmt->execute([$filename]);
+
+ echo "OK\n";
+ $newMigrations++;
+ } catch (PDOException $e) {
+ echo "ОШИБКА!\n";
+ echo " Причина: " . $e->getMessage() . "\n";
+ echo "\n[!] Миграция остановлена из-за ошибки\n";
+ exit(1);
+ }
+ }
+
+ echo "\n-------------------------------------------\n";
+
+ if ($newMigrations > 0) {
+ echo "[SUCCESS] Применено новых миграций: $newMigrations\n";
+ } else {
+ echo "[INFO] Все миграции уже применены\n";
+ }
+
+ $seedFile = __DIR__ . '/seed_data.sql';
+ if (file_exists($seedFile)) {
+ echo "\n[?] Хотите загрузить начальные данные (seed_data.sql)?\n";
+ echo " Запустите: php migrations/migrate.php --seed\n";
+
+ if (isset($argv[1]) && $argv[1] === '--seed') {
+ echo "\n[RUN] Загружаю seed_data.sql... ";
+ try {
+ $sql = file_get_contents($seedFile);
+ $db->exec($sql);
+ echo "OK\n";
+ } catch (PDOException $e) {
+ echo "ОШИБКА: " . $e->getMessage() . "\n";
+ }
+ }
+ }
+
+ echo "\n===========================================\n";
+ echo " Миграции завершены!\n";
+ echo "===========================================\n";
+
+} catch (PDOException $e) {
+ echo "[ERROR] Ошибка подключения к БД: " . $e->getMessage() . "\n";
+ exit(1);
+}
diff --git a/OLD_CODE/migrations/seed_data.sql b/OLD_CODE/migrations/seed_data.sql
new file mode 100644
index 0000000..ca1af50
--- /dev/null
+++ b/OLD_CODE/migrations/seed_data.sql
@@ -0,0 +1,65 @@
+-- seed_data.sql
+-- Начальные данные для AETERNA
+
+-- Администратор (пароль: admin123)
+INSERT INTO users (email, password_hash, full_name, phone, city, is_admin, is_active)
+VALUES (
+ 'admin@aeterna.ru',
+ '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', -- admin123
+ 'Администратор AETERNA',
+ '+79129991223',
+ 'Москва',
+ TRUE,
+ TRUE
+) ON CONFLICT (email) DO NOTHING;
+
+-- Тестовый пользователь (пароль: user123)
+INSERT INTO users (email, password_hash, full_name, phone, city, is_admin, is_active)
+VALUES (
+ 'user@test.com',
+ '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', -- user123
+ 'Тестовый Пользователь',
+ '+79111234567',
+ 'Санкт-Петербург',
+ FALSE,
+ TRUE
+) ON CONFLICT (email) DO NOTHING;
+
+-- Категории
+INSERT INTO categories (name, slug, description, sort_order, is_active) VALUES
+ ('Диваны', 'divany', 'Прямые и угловые диваны для гостиной', 1, TRUE),
+ ('Кресла', 'kresla', 'Кресла для гостиной и офиса', 2, TRUE),
+ ('Кровати', 'krovati', 'Односпальные и двуспальные кровати', 3, TRUE),
+ ('Столы', 'stoly', 'Обеденные и рабочие столы', 4, TRUE),
+ ('Стулья', 'stulya', 'Стулья для кухни и офиса', 5, TRUE),
+ ('Светильники', 'svetilniki', 'Торшеры, люстры и настольные лампы', 6, TRUE)
+ON CONFLICT (slug) DO NOTHING;
+
+-- Товары
+INSERT INTO products (category_id, name, slug, description, price, old_price, sku, stock_quantity, is_available, image_url, color, material, card_size) VALUES
+ (1, 'Светильник MINNIGHT', 'svetilnik-minnight', 'Настольный светильник в современном стиле', 7999, 9999, 'LAMP-MIN-001', 15, TRUE, 'img2/1_2.png', 'Черный', 'Металл', 'small'),
+ (3, 'Кровать MODER', 'krovat-moder', 'Двуспальная кровать с мягким изголовьем', 45999, 55999, 'BED-MOD-001', 5, TRUE, 'img2/3_3.png', 'Серый', 'Дерево/Ткань', 'large'),
+ (6, 'Торшер MARCIA', 'torsher-marcia', 'Напольный торшер с регулируемой высотой', 11999, 14999, 'LAMP-MAR-001', 8, TRUE, 'img2/2_2.png', 'Золотой', 'Металл', 'tall'),
+ (6, 'Светильник POLET', 'svetilnik-polet', 'Подвесной светильник для гостиной', 5499, NULL, 'LAMP-POL-001', 20, TRUE, 'img2/4.jpg', 'Белый', 'Стекло', 'wide'),
+ (4, 'Стол NORD', 'stol-nord', 'Обеденный стол в скандинавском стиле', 23999, 28999, 'TABLE-NOR-001', 7, TRUE, 'img2/5_5.png', 'Натуральный', 'Дерево', 'small1'),
+ (1, 'Диван ROYALTY', 'divan-royalty', 'Роскошный угловой диван с велюровой обивкой', 78999, 95999, 'SOFA-ROY-001', 3, TRUE, 'img2/6_6.png', 'Зеленый', 'Велюр', 'wide2'),
+ (2, 'Кресло MINIMAL', 'kreslo-minimal', 'Кресло в минималистичном стиле', 29999, 35999, 'ARM-MIN-001', 10, TRUE, 'img2/7_7.png', 'Бежевый', 'Ткань', 'wide3'),
+ (4, 'Стол LONKI', 'stol-lonki', 'Журнальный столик с мраморной столешницей', 34999, NULL, 'TABLE-LON-001', 12, TRUE, 'img2/8_8.png', 'Белый мрамор', 'Мрамор/Металл', 'wide2_1'),
+ (1, 'Диван HEMMINS', 'divan-hemmins', 'Большой модульный диван для всей семьи', 89999, 110000, 'SOFA-HEM-001', 2, TRUE, 'img2/9_9.png', 'Темно-серый', 'Ткань', 'full-width')
+ON CONFLICT (slug) DO NOTHING;
+
+-- Выводим статистику
+DO $$
+DECLARE
+ users_count INTEGER;
+ categories_count INTEGER;
+ products_count INTEGER;
+BEGIN
+ SELECT COUNT(*) INTO users_count FROM users;
+ SELECT COUNT(*) INTO categories_count FROM categories;
+ SELECT COUNT(*) INTO products_count FROM products;
+
+ RAISE NOTICE 'Загружено: % пользователей, % категорий, % товаров',
+ users_count, categories_count, products_count;
+END $$;
+
diff --git a/mixins.less b/OLD_CODE/mixins.less
similarity index 100%
rename from mixins.less
rename to OLD_CODE/mixins.less
diff --git a/OLD_CODE/public/admin/index.php b/OLD_CODE/public/admin/index.php
new file mode 100644
index 0000000..72dc1ac
--- /dev/null
+++ b/OLD_CODE/public/admin/index.php
@@ -0,0 +1,797 @@
+alert('Требуется авторизация администратора'); window.location.href = '../login.php';";
+ exit();
+}
+
+$db = Database::getInstance()->getConnection();
+
+$action = $_GET['action'] ?? 'dashboard';
+$message = $_GET['message'] ?? '';
+$error = $_GET['error'] ?? '';
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $post_action = $_POST['action'] ?? '';
+
+ try {
+ if ($post_action === 'add_category') {
+ $name = trim($_POST['name'] ?? '');
+ $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name));
+ $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL;
+ $description = trim($_POST['description'] ?? '');
+ $sort_order = (int)($_POST['sort_order'] ?? 0);
+ $is_active = isset($_POST['is_active']) ? 1 : 0;
+
+ if (empty($name)) {
+ throw new Exception('Название категории обязательно');
+ }
+
+ $stmt = $db->prepare("
+ INSERT INTO categories (name, slug, parent_id, description, sort_order, is_active)
+ VALUES (?, ?, ?, ?, ?, ?)
+ ");
+
+ $result = $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active]);
+
+ if ($result) {
+ header('Location: index.php?action=categories&message=Категория+успешно+добавлена');
+ exit();
+ }
+ }
+
+ if ($post_action === 'edit_category' && isset($_POST['category_id'])) {
+ $category_id = (int)$_POST['category_id'];
+ $name = trim($_POST['name'] ?? '');
+ $parent_id = !empty($_POST['parent_id']) ? (int)$_POST['parent_id'] : NULL;
+ $description = trim($_POST['description'] ?? '');
+ $sort_order = (int)($_POST['sort_order'] ?? 0);
+ $is_active = isset($_POST['is_active']) ? 1 : 0;
+
+ if (empty($name)) {
+ throw new Exception('Название категории обязательно');
+ }
+
+ $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name));
+
+ $stmt = $db->prepare("
+ UPDATE categories SET
+ name = ?,
+ slug = ?,
+ parent_id = ?,
+ description = ?,
+ sort_order = ?,
+ is_active = ?,
+ updated_at = CURRENT_TIMESTAMP
+ WHERE category_id = ?
+ ");
+
+ $stmt->execute([$name, $slug, $parent_id, $description, $sort_order, $is_active, $category_id]);
+
+ header('Location: index.php?action=categories&message=Категория+обновлена');
+ exit();
+ }
+
+ if ($post_action === 'add_product') {
+ $name = trim($_POST['name'] ?? '');
+ $slug = strtolower(preg_replace('/[^a-z0-9]+/i', '-', $name));
+ $category_id = (int)($_POST['category_id'] ?? 0);
+ $description = trim($_POST['description'] ?? '');
+ $price = (float)($_POST['price'] ?? 0);
+ $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL;
+ $sku = trim($_POST['sku'] ?? '');
+ $stock_quantity = (int)($_POST['stock_quantity'] ?? 0);
+ $is_available = isset($_POST['is_available']) ? 1 : 0;
+ $is_featured = isset($_POST['is_featured']) ? 1 : 0;
+ $image_url = trim($_POST['image_url'] ?? '');
+ $color = trim($_POST['color'] ?? '');
+ $material = trim($_POST['material'] ?? '');
+ $card_size = trim($_POST['card_size'] ?? 'small');
+
+ if ($category_id <= 0) {
+ $_SESSION['error'] = 'Выберите корректную категорию';
+ header('Location: index.php?action=add_product');
+ exit();
+ }
+
+ $check_category = $db->prepare("SELECT COUNT(*) FROM categories WHERE category_id = ?");
+ $check_category->execute([$category_id]);
+ if ($check_category->fetchColumn() == 0) {
+ $_SESSION['error'] = 'Выбранная категория не существует';
+ header('Location: index.php?action=add_product');
+ exit();
+ }
+
+ if (empty($name)) throw new Exception('Название товара обязательно');
+ if ($price <= 0) throw new Exception('Цена должна быть больше 0');
+
+ if (empty($sku)) {
+ $sku = 'PROD-' . strtoupper(substr(preg_replace('/[^a-z0-9]/i', '', $name), 0, 6)) . '-' . rand(100, 999);
+ }
+
+ $stmt = $db->prepare("
+ INSERT INTO products (
+ category_id, name, slug, description, price, old_price,
+ sku, stock_quantity, is_available, is_featured, image_url,
+ color, material, card_size
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ ");
+
+ $result = $stmt->execute([
+ $category_id, $name, $slug, $description, $price, $old_price,
+ $sku, $stock_quantity, $is_available, $is_featured, $image_url,
+ $color, $material, $card_size
+ ]);
+
+ if ($result) {
+ $_SESSION['message'] = 'Товар успешно добавлен';
+ header('Location: index.php?action=products');
+ exit();
+ }
+ }
+
+ if ($post_action === 'edit_product' && isset($_POST['product_id'])) {
+ $product_id = (int)$_POST['product_id'];
+ $name = trim($_POST['name'] ?? '');
+ $category_id = (int)($_POST['category_id'] ?? 1);
+ $description = trim($_POST['description'] ?? '');
+ $price = (float)($_POST['price'] ?? 0);
+ $old_price = !empty($_POST['old_price']) ? (float)$_POST['old_price'] : NULL;
+ $stock_quantity = (int)($_POST['stock_quantity'] ?? 0);
+ $is_available = isset($_POST['is_available']) ? 1 : 0;
+ $image_url = trim($_POST['image_url'] ?? '');
+ $color = trim($_POST['color'] ?? '');
+ $material = trim($_POST['material'] ?? '');
+
+ if ($category_id <= 0) {
+
+ $firstCat = $db->query("SELECT category_id FROM categories LIMIT 1")->fetchColumn();
+ $category_id = $firstCat ?: 1;
+ }
+
+ $stmt = $db->prepare("
+ UPDATE products SET
+ name = ?,
+ category_id = ?,
+ description = ?,
+ price = ?,
+ old_price = ?,
+ stock_quantity = ?,
+ is_available = ?,
+ image_url = ?,
+ color = ?,
+ material = ?,
+ updated_at = CURRENT_TIMESTAMP
+ WHERE product_id = ?
+ ");
+
+ $stmt->execute([
+ $name, $category_id, $description, $price, $old_price,
+ $stock_quantity, $is_available, $image_url, $color, $material, $product_id
+ ]);
+
+ header('Location: index.php?action=products&message=Товар+обновлен');
+ exit();
+ }
+
+ if ($post_action === 'delete_category' && isset($_POST['category_id'])) {
+ $categoryId = intval($_POST['category_id']);
+
+ $checkProducts = $db->prepare("SELECT COUNT(*) FROM products WHERE category_id = ?");
+ $checkProducts->execute([$categoryId]);
+ $productCount = $checkProducts->fetchColumn();
+
+ $checkChildren = $db->prepare("SELECT COUNT(*) FROM categories WHERE parent_id = ?");
+ $checkChildren->execute([$categoryId]);
+ $childCount = $checkChildren->fetchColumn();
+
+ if ($productCount > 0) {
+
+ $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?");
+ $stmt->execute([$categoryId]);
+
+ header('Location: index.php?action=categories&message=Категория+скрыта+(содержит+товары)');
+ exit();
+ } elseif ($childCount > 0) {
+
+ $stmt = $db->prepare("UPDATE categories SET is_active = FALSE WHERE category_id = ?");
+ $stmt->execute([$categoryId]);
+
+ header('Location: index.php?action=categories&message=Категория+скрыта+(имеет+дочерние+категории)');
+ exit();
+ } else {
+
+ $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?");
+ $stmt->execute([$categoryId]);
+
+ header('Location: index.php?action=categories&message=Категория+удалена');
+ exit();
+ }
+ }
+ } catch (PDOException $e) {
+ header('Location: index.php?action=' . $action . '&error=' . urlencode('Ошибка БД: ' . $e->getMessage()));
+ exit();
+ } catch (Exception $e) {
+ header('Location: index.php?action=' . $action . '&error=' . urlencode($e->getMessage()));
+ exit();
+ }
+ }
+
+try {
+
+ $stats = [
+ 'total_products' => $db->query("SELECT COUNT(*) FROM products")->fetchColumn(),
+ 'active_products' => $db->query("SELECT COUNT(*) FROM products WHERE is_available = TRUE")->fetchColumn(),
+ 'total_orders' => $db->query("SELECT COUNT(*) FROM orders")->fetchColumn(),
+ 'total_users' => $db->query("SELECT COUNT(*) FROM users")->fetchColumn(),
+ 'revenue' => $db->query("SELECT COALESCE(SUM(final_amount), 0) FROM orders WHERE status = 'completed'")->fetchColumn()
+ ];
+
+ $allCategories = $db->query("SELECT * FROM categories WHERE is_active = TRUE ORDER BY name")->fetchAll();
+
+ $parentCategories = $db->query("SELECT * FROM categories WHERE parent_id IS NULL AND is_active = TRUE ORDER BY name")->fetchAll();
+
+ switch ($action) {
+ case 'products':
+ $showAll = isset($_GET['show_all']) && $_GET['show_all'] == '1';
+ $sql = $showAll
+ ? "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id ORDER BY p.created_at DESC"
+ : "SELECT p.*, c.name as category_name FROM products p LEFT JOIN categories c ON p.category_id = c.category_id WHERE p.is_available = TRUE ORDER BY p.created_at DESC";
+ $data = $db->query($sql)->fetchAll();
+ break;
+
+ case 'categories':
+ $data = $db->query("
+ SELECT c1.*, c2.name as parent_name,
+ (SELECT COUNT(*) FROM products p WHERE p.category_id = c1.category_id) as product_count
+ FROM categories c1
+ LEFT JOIN categories c2 ON c1.parent_id = c2.category_id
+ ORDER BY c1.sort_order, c1.name
+ ")->fetchAll();
+ break;
+
+ case 'orders':
+ $data = $db->query("
+ SELECT o.*, u.email as user_email
+ FROM orders o
+ LEFT JOIN users u ON o.user_id = u.user_id
+ ORDER BY o.created_at DESC
+ LIMIT 50
+ ")->fetchAll();
+ break;
+
+ case 'users':
+ $data = $db->query("SELECT * FROM users ORDER BY created_at DESC LIMIT 50")->fetchAll();
+ break;
+
+ case 'add_product':
+ case 'edit_product':
+ if ($action === 'edit_product' && isset($_GET['id'])) {
+ $productId = (int)$_GET['id'];
+ $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?");
+ $stmt->execute([$productId]);
+ $edit_data = $stmt->fetch();
+ }
+ break;
+
+ case 'add_category':
+ case 'edit_category':
+ if ($action === 'edit_category' && isset($_GET['id'])) {
+ $categoryId = (int)$_GET['id'];
+ $stmt = $db->prepare("SELECT * FROM categories WHERE category_id = ?");
+ $stmt->execute([$categoryId]);
+ $edit_data = $stmt->fetch();
+ }
+ break;
+
+ }
+
+} catch (PDOException $e) {
+ $error = "Ошибка базы данных: " . $e->getMessage();
+}
+?>
+
+
+
+
+
+ AETERNA - Админ-панель
+
+
+
+
+
+
+
+
+
+
+
+ = htmlspecialchars(urldecode($message)) ?>
+
+
+
+
+
+ = htmlspecialchars(urldecode($error)) ?>
+
+
+
+
+
+
Статистика
+
+
+
= $stats['total_products'] ?>
+
Всего товаров
+
+
+
= $stats['active_products'] ?>
+
Активных товаров
+
+
+
= $stats['total_orders'] ?>
+
Заказов
+
+
+
= $stats['total_users'] ?>
+
Пользователей
+
+
+
+
+
+
+
+
+
Управление товарами
+
+
+
+
+
+
+ ID
+ Название
+ Категория
+ Цена
+ На складе
+ Статус
+ Действия
+
+
+
+
+
+ = $product['product_id'] ?>
+ = htmlspecialchars($product['name']) ?>
+ = htmlspecialchars($product['category_name'] ?? 'Без категории') ?>
+ = number_format($product['price'], 0, '', ' ') ?> ₽
+ = $product['stock_quantity'] ?>
+
+ 0): ?>
+ ✓ Доступен
+
+ ✗ Недоступен
+
+ ⚠ Нет на складе
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID
+ Название
+ Slug
+ Родительская
+ Товаров
+ Действия
+
+
+
+
+
+ = $category['category_id'] ?>
+ = htmlspecialchars($category['name']) ?>
+ = htmlspecialchars($category['slug']) ?>
+ = htmlspecialchars($category['parent_name'] ?? '—') ?>
+ = $category['product_count'] ?>
+
+
+
+ Редактировать
+
+
+ 0 ? 'disabled' : '' ?>>
+ Удалить
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Заказы
+
+
+
+ № заказа
+ Клиент
+ Сумма
+ Статус
+ Дата
+ Действия
+
+
+
+
+
+ = htmlspecialchars($order['order_number']) ?>
+ = htmlspecialchars($order['customer_name']) ?>
+ = number_format($order['final_amount'], 0, '', ' ') ?> ₽
+ = htmlspecialchars($order['status']) ?>
+ = date('d.m.Y H:i', strtotime($order['created_at'])) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
Пользователи
+
+
+
+ ID
+ Email
+ ФИО
+ Дата регистрации
+ Статус
+
+
+
+
+
+ = $user['user_id'] ?>
+ = htmlspecialchars($user['email']) ?>
+ = htmlspecialchars($user['full_name']) ?>
+ = date('d.m.Y', strtotime($user['created_at'])) ?>
+
+
+ ✓ Активен
+
+ ✗ Неактивен
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OLD_CODE/public/api/add_to_cart.php b/OLD_CODE/public/api/add_to_cart.php
new file mode 100644
index 0000000..a452dcc
--- /dev/null
+++ b/OLD_CODE/public/api/add_to_cart.php
@@ -0,0 +1,112 @@
+ false, 'message' => 'Требуется авторизация']);
+ exit();
+}
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['product_id'])) {
+ $product_id = intval($_POST['product_id']);
+ $quantity = intval($_POST['quantity'] ?? 1);
+ $user_id = $_SESSION['user_id'] ?? 0;
+
+ if ($user_id == 0) {
+ echo json_encode(['success' => false, 'message' => 'Пользователь не найден']);
+ exit();
+ }
+
+ $db = Database::getInstance()->getConnection();
+
+ try {
+
+ $checkStock = $db->prepare("
+ SELECT stock_quantity, name, price
+ FROM products
+ WHERE product_id = ? AND is_available = TRUE
+ ");
+ $checkStock->execute([$product_id]);
+ $product = $checkStock->fetch();
+
+ if (!$product) {
+ echo json_encode(['success' => false, 'message' => 'Товар не найден']);
+ exit();
+ }
+
+ if ($product['stock_quantity'] < $quantity) {
+ echo json_encode(['success' => false, 'message' => 'Недостаточно товара на складе']);
+ exit();
+ }
+
+ $checkCart = $db->prepare("
+ SELECT cart_id, quantity
+ FROM cart
+ WHERE user_id = ? AND product_id = ?
+ ");
+ $checkCart->execute([$user_id, $product_id]);
+ $cartItem = $checkCart->fetch();
+
+ if ($cartItem) {
+
+ $newQuantity = $cartItem['quantity'] + $quantity;
+
+ if ($newQuantity > $product['stock_quantity']) {
+ echo json_encode(['success' => false, 'message' => 'Превышено доступное количество']);
+ exit();
+ }
+
+ $updateStmt = $db->prepare("
+ UPDATE cart
+ SET quantity = ?, updated_at = CURRENT_TIMESTAMP
+ WHERE cart_id = ?
+ ");
+ $updateStmt->execute([$newQuantity, $cartItem['cart_id']]);
+ } else {
+
+ $insertStmt = $db->prepare("
+ INSERT INTO cart (user_id, product_id, quantity)
+ VALUES (?, ?, ?)
+ ");
+ $insertStmt->execute([$user_id, $product_id, $quantity]);
+ }
+
+ if (!isset($_SESSION['cart'])) {
+ $_SESSION['cart'] = [];
+ }
+
+ if (isset($_SESSION['cart'][$product_id])) {
+ $_SESSION['cart'][$product_id]['quantity'] += $quantity;
+ } else {
+ $_SESSION['cart'][$product_id] = [
+ 'quantity' => $quantity,
+ 'name' => $product['name'],
+ 'price' => $product['price'],
+ 'added_at' => time()
+ ];
+ }
+
+ $cartCountStmt = $db->prepare("
+ SELECT SUM(quantity) as total
+ FROM cart
+ WHERE user_id = ?
+ ");
+ $cartCountStmt->execute([$user_id]);
+ $cart_count = $cartCountStmt->fetchColumn() ?: 0;
+
+ echo json_encode([
+ 'success' => true,
+ 'cart_count' => $cart_count,
+ 'message' => 'Товар добавлен в корзину'
+ ]);
+
+ } catch (PDOException $e) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Ошибка базы данных: ' . $e->getMessage()
+ ]);
+ }
+} else {
+ echo json_encode(['success' => false, 'message' => 'Неверный запрос']);
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/api/auth.php b/OLD_CODE/public/api/auth.php
new file mode 100644
index 0000000..4aac5e4
--- /dev/null
+++ b/OLD_CODE/public/api/auth.php
@@ -0,0 +1,68 @@
+ false, 'message' => 'Заполните все поля']);
+ exit();
+ }
+
+ $db = Database::getInstance()->getConnection();
+
+ try {
+
+ $stmt = $db->prepare("
+ SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active
+ FROM users
+ WHERE email = ?
+ ");
+ $stmt->execute([$email]);
+ $user = $stmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$user) {
+ echo json_encode(['success' => false, 'message' => 'Пользователь не найден']);
+ exit();
+ }
+
+ if (!$user['is_active']) {
+ echo json_encode(['success' => false, 'message' => 'Аккаунт заблокирован']);
+ exit();
+ }
+
+ if (empty($user['password_hash'])) {
+ echo json_encode(['success' => false, 'message' => 'Ошибка: пароль не найден в базе данных']);
+ exit();
+ }
+
+ if (!password_verify($password, $user['password_hash'])) {
+ echo json_encode(['success' => false, 'message' => 'Неверный пароль']);
+ exit();
+ }
+
+ $_SESSION['user_id'] = $user['user_id'];
+ $_SESSION['user_email'] = $user['email'];
+ $_SESSION['full_name'] = $user['full_name'];
+ $_SESSION['user_phone'] = $user['phone'] ?? '';
+ $_SESSION['user_city'] = $user['city'] ?? '';
+ $_SESSION['isLoggedIn'] = true;
+ $_SESSION['isAdmin'] = (bool)$user['is_admin'];
+ $_SESSION['login_time'] = time();
+
+ $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?");
+ $updateStmt->execute([$user['user_id']]);
+
+ echo json_encode(['success' => true, 'redirect' => 'catalog.php']);
+
+ } catch (PDOException $e) {
+ echo json_encode(['success' => false, 'message' => 'Ошибка базы данных']);
+ }
+
+} else {
+ echo json_encode(['success' => false, 'message' => 'Неверный запрос']);
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/api/cart.php b/OLD_CODE/public/api/cart.php
new file mode 100644
index 0000000..cd68d7b
--- /dev/null
+++ b/OLD_CODE/public/api/cart.php
@@ -0,0 +1,127 @@
+ false, 'message' => 'Требуется авторизация']);
+ exit();
+}
+
+$userId = $_SESSION['user_id'] ?? 0;
+$action = $_GET['action'] ?? $_POST['action'] ?? '';
+
+$db = Database::getInstance()->getConnection();
+
+try {
+ switch ($action) {
+ case 'add':
+ $productId = (int)($_POST['product_id'] ?? 0);
+ $quantity = (int)($_POST['quantity'] ?? 1);
+
+ if ($productId <= 0) {
+ echo json_encode(['success' => false, 'message' => 'Неверный ID товара']);
+ exit();
+ }
+
+ $checkProduct = $db->prepare("SELECT product_id, stock_quantity FROM products WHERE product_id = ? AND is_available = TRUE");
+ $checkProduct->execute([$productId]);
+ $product = $checkProduct->fetch();
+
+ if (!$product) {
+ echo json_encode(['success' => false, 'message' => 'Товар не найден']);
+ exit();
+ }
+
+ $checkCart = $db->prepare("SELECT cart_id, quantity FROM cart WHERE user_id = ? AND product_id = ?");
+ $checkCart->execute([$userId, $productId]);
+ $cartItem = $checkCart->fetch();
+
+ if ($cartItem) {
+
+ $newQuantity = $cartItem['quantity'] + $quantity;
+ $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE cart_id = ?");
+ $stmt->execute([$newQuantity, $cartItem['cart_id']]);
+ } else {
+
+ $stmt = $db->prepare("INSERT INTO cart (user_id, product_id, quantity) VALUES (?, ?, ?)");
+ $stmt->execute([$userId, $productId, $quantity]);
+ }
+
+ echo json_encode(['success' => true, 'message' => 'Товар добавлен в корзину']);
+ break;
+
+ case 'update':
+ $productId = (int)($_POST['product_id'] ?? 0);
+ $quantity = (int)($_POST['quantity'] ?? 1);
+
+ if ($quantity <= 0) {
+
+ $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?");
+ $stmt->execute([$userId, $productId]);
+ } else {
+ $stmt = $db->prepare("UPDATE cart SET quantity = ?, updated_at = CURRENT_TIMESTAMP WHERE user_id = ? AND product_id = ?");
+ $stmt->execute([$quantity, $userId, $productId]);
+ }
+
+ echo json_encode(['success' => true, 'message' => 'Корзина обновлена']);
+ break;
+
+ case 'remove':
+ $productId = (int)($_POST['product_id'] ?? 0);
+
+ $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ? AND product_id = ?");
+ $stmt->execute([$userId, $productId]);
+
+ echo json_encode(['success' => true, 'message' => 'Товар удален из корзины']);
+ break;
+
+ case 'get':
+ $stmt = $db->prepare("
+ SELECT c.cart_id, c.product_id, c.quantity, p.name, p.price, p.image_url, p.stock_quantity
+ FROM cart c
+ JOIN products p ON c.product_id = p.product_id
+ WHERE c.user_id = ? AND p.is_available = TRUE
+ ORDER BY c.created_at DESC
+ ");
+ $stmt->execute([$userId]);
+ $items = $stmt->fetchAll();
+
+ $total = 0;
+ foreach ($items as &$item) {
+ $item['subtotal'] = $item['price'] * $item['quantity'];
+ $total += $item['subtotal'];
+ }
+
+ echo json_encode([
+ 'success' => true,
+ 'items' => $items,
+ 'total' => $total,
+ 'count' => array_sum(array_column($items, 'quantity'))
+ ]);
+ break;
+
+ case 'count':
+ $stmt = $db->prepare("SELECT COALESCE(SUM(quantity), 0) FROM cart WHERE user_id = ?");
+ $stmt->execute([$userId]);
+ $count = $stmt->fetchColumn();
+
+ echo json_encode(['success' => true, 'count' => (int)$count]);
+ break;
+
+ case 'clear':
+ $stmt = $db->prepare("DELETE FROM cart WHERE user_id = ?");
+ $stmt->execute([$userId]);
+
+ echo json_encode(['success' => true, 'message' => 'Корзина очищена']);
+ break;
+
+ default:
+ echo json_encode(['success' => false, 'message' => 'Неизвестное действие']);
+ }
+
+} catch (PDOException $e) {
+ echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]);
+}
diff --git a/OLD_CODE/public/api/get_cart.php b/OLD_CODE/public/api/get_cart.php
new file mode 100644
index 0000000..2d43ea4
--- /dev/null
+++ b/OLD_CODE/public/api/get_cart.php
@@ -0,0 +1,61 @@
+ false, 'message' => 'Требуется авторизация']);
+ exit();
+}
+
+$user_id = $_SESSION['user_id'] ?? 0;
+
+if ($user_id == 0) {
+ echo json_encode(['success' => false, 'message' => 'Пользователь не найден']);
+ exit();
+}
+
+$db = Database::getInstance()->getConnection();
+
+try {
+
+ $stmt = $db->prepare("
+ SELECT
+ c.cart_id,
+ c.product_id,
+ c.quantity,
+ p.name,
+ p.price,
+ p.image_url,
+ p.stock_quantity
+ FROM cart c
+ JOIN products p ON c.product_id = p.product_id
+ WHERE c.user_id = ? AND p.is_available = TRUE
+ ORDER BY c.created_at DESC
+ ");
+ $stmt->execute([$user_id]);
+ $cart_items = $stmt->fetchAll();
+
+ $_SESSION['cart'] = [];
+ foreach ($cart_items as $item) {
+ $_SESSION['cart'][$item['product_id']] = [
+ 'quantity' => $item['quantity'],
+ 'name' => $item['name'],
+ 'price' => $item['price'],
+ 'added_at' => time()
+ ];
+ }
+
+ echo json_encode([
+ 'success' => true,
+ 'cart_items' => $cart_items,
+ 'total_items' => count($cart_items)
+ ]);
+
+} catch (PDOException $e) {
+ echo json_encode([
+ 'success' => false,
+ 'message' => 'Ошибка базы данных: ' . $e->getMessage()
+ ]);
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/api/get_cart_count.php b/OLD_CODE/public/api/get_cart_count.php
new file mode 100644
index 0000000..f1d59c2
--- /dev/null
+++ b/OLD_CODE/public/api/get_cart_count.php
@@ -0,0 +1,22 @@
+ false, 'cart_count' => 0]);
+ exit();
+}
+
+$user_id = $_SESSION['user_id'] ?? 0;
+$db = Database::getInstance()->getConnection();
+
+try {
+ $stmt = $db->prepare("SELECT SUM(quantity) as total FROM cart WHERE user_id = ?");
+ $stmt->execute([$user_id]);
+ $cart_count = $stmt->fetchColumn() ?: 0;
+
+ echo json_encode(['success' => true, 'cart_count' => $cart_count]);
+} catch (PDOException $e) {
+ echo json_encode(['success' => false, 'cart_count' => 0]);
+}
\ No newline at end of file
diff --git a/OLD_CODE/public/api/get_product.php b/OLD_CODE/public/api/get_product.php
new file mode 100644
index 0000000..0cd3ca6
--- /dev/null
+++ b/OLD_CODE/public/api/get_product.php
@@ -0,0 +1,32 @@
+ false, 'message' => 'Доступ запрещен']);
+ exit();
+}
+
+if (!isset($_GET['id'])) {
+ echo json_encode(['success' => false, 'message' => 'ID не указан']);
+ exit();
+}
+
+try {
+ $db = Database::getInstance()->getConnection();
+ $product_id = $_GET['id'];
+
+ $stmt = $db->prepare("SELECT * FROM products WHERE product_id = ?");
+ $stmt->execute([$product_id]);
+ $product = $stmt->fetch();
+
+ if ($product) {
+ echo json_encode($product);
+ } else {
+ echo json_encode(['success' => false, 'message' => 'Товар не найден']);
+ }
+
+} catch (PDOException $e) {
+ echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]);
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/api/process_order.php b/OLD_CODE/public/api/process_order.php
new file mode 100644
index 0000000..8c94036
--- /dev/null
+++ b/OLD_CODE/public/api/process_order.php
@@ -0,0 +1,124 @@
+getConnection();
+
+ try {
+ $db->beginTransaction();
+
+ $customer_name = $_POST['full_name'] ?? '';
+ $customer_email = $_POST['email'] ?? '';
+ $customer_phone = $_POST['phone'] ?? '';
+ $delivery_address = $_POST['address'] ?? '';
+ $region = $_POST['region'] ?? '';
+ $payment_method = $_POST['payment'] ?? 'card';
+ $delivery_method = $_POST['delivery'] ?? 'courier';
+ $notes = $_POST['notes'] ?? '';
+ $discount_amount = floatval($_POST['discount'] ?? 0);
+ $delivery_cost = floatval($_POST['delivery_price'] ?? 2000);
+
+ $order_number = 'ORD-' . date('Ymd-His') . '-' . rand(1000, 9999);
+
+ $cartStmt = $db->prepare("
+ SELECT
+ c.product_id,
+ c.quantity,
+ p.name,
+ p.price,
+ p.stock_quantity
+ FROM cart c
+ JOIN products p ON c.product_id = p.product_id
+ WHERE c.user_id = ?
+ ");
+ $cartStmt->execute([$user_id]);
+ $cart_items = $cartStmt->fetchAll();
+
+ if (empty($cart_items)) {
+ throw new Exception('Корзина пуста');
+ }
+
+ $total_amount = 0;
+ foreach ($cart_items as $item) {
+ $total_amount += $item['price'] * $item['quantity'];
+ }
+
+ $final_amount = $total_amount - $discount_amount + $delivery_cost;
+
+ $orderStmt = $db->prepare("
+ INSERT INTO orders (
+ user_id, order_number, total_amount, discount_amount,
+ delivery_cost, final_amount, status, payment_method,
+ delivery_method, delivery_address, customer_name,
+ customer_email, customer_phone, notes
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ RETURNING order_id
+ ");
+
+ $orderStmt->execute([
+ $user_id, $order_number, $total_amount, $discount_amount,
+ $delivery_cost, $final_amount, 'pending', $payment_method,
+ $delivery_method, $delivery_address, $customer_name,
+ $customer_email, $customer_phone, $notes
+ ]);
+
+ $order_id = $orderStmt->fetchColumn();
+
+ foreach ($cart_items as $item) {
+
+ $itemStmt = $db->prepare("
+ INSERT INTO order_items (
+ order_id, product_id, product_name,
+ quantity, unit_price, total_price
+ ) VALUES (?, ?, ?, ?, ?, ?)
+ ");
+
+ $item_total = $item['price'] * $item['quantity'];
+ $itemStmt->execute([
+ $order_id, $item['product_id'], $item['name'],
+ $item['quantity'], $item['price'], $item_total
+ ]);
+
+ $updateStmt = $db->prepare("
+ UPDATE products
+ SET stock_quantity = stock_quantity - ?,
+ updated_at = CURRENT_TIMESTAMP
+ WHERE product_id = ?
+ ");
+ $updateStmt->execute([$item['quantity'], $item['product_id']]);
+ }
+
+ $clearCartStmt = $db->prepare("DELETE FROM cart WHERE user_id = ?");
+ $clearCartStmt->execute([$user_id]);
+
+ unset($_SESSION['cart']);
+
+ $db->commit();
+
+ header('Location: order_success.php?id=' . $order_id);
+ exit();
+
+ } catch (Exception $e) {
+ $db->rollBack();
+ header('Location: checkout.php?error=' . urlencode($e->getMessage()));
+ exit();
+ }
+} else {
+ header('Location: checkout.php');
+ exit();
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/api/register_handler.php b/OLD_CODE/public/api/register_handler.php
new file mode 100644
index 0000000..d1cfb81
--- /dev/null
+++ b/OLD_CODE/public/api/register_handler.php
@@ -0,0 +1,162 @@
+ $full_name,
+ 'city' => $city,
+ 'email' => $email,
+ 'phone' => $phone
+ ];
+ header('Location: ../register.php');
+ exit();
+ }
+
+ $db = Database::getInstance()->getConnection();
+
+ try {
+
+ $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?");
+ $checkStmt->execute([$email]);
+
+ if ($checkStmt->fetch()) {
+ $_SESSION['registration_errors'] = ['Пользователь с таким email уже существует'];
+ $_SESSION['old_data'] = [
+ 'fio' => $full_name,
+ 'city' => $city,
+ 'email' => $email,
+ 'phone' => $phone
+ ];
+ header('Location: ../register.php');
+ exit();
+ }
+
+ $password_hash = password_hash($password, PASSWORD_DEFAULT);
+
+ $is_admin = false;
+ $admin_emails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru'];
+ if (in_array(strtolower($email), $admin_emails)) {
+ $is_admin = true;
+ }
+
+ $stmt = $db->prepare("
+ INSERT INTO users (email, password_hash, full_name, phone, city, is_admin, is_active)
+ VALUES (?, ?, ?, ?, ?, CAST(? AS boolean), TRUE)
+ RETURNING user_id
+ ");
+
+ $stmt->execute([
+ $email,
+ $password_hash,
+ $full_name,
+ $phone,
+ $city,
+ $is_admin ? 'true' : 'false'
+ ]);
+
+ $user_id = $stmt->fetchColumn();
+
+ if (!$user_id) {
+ throw new Exception('Ошибка при создании пользователя: user_id не получен');
+ }
+
+ $verifyStmt = $db->prepare("SELECT user_id, email, password_hash FROM users WHERE user_id = ?");
+ $verifyStmt->execute([$user_id]);
+ $verifyUser = $verifyStmt->fetch(PDO::FETCH_ASSOC);
+
+ if (!$verifyUser) {
+ throw new Exception('Ошибка: пользователь не найден после создания');
+ }
+
+ if (empty($verifyUser['password_hash'])) {
+ throw new Exception('Ошибка: пароль не сохранен');
+ }
+
+ $_SESSION['user_id'] = $user_id;
+ $_SESSION['user_email'] = $email;
+ $_SESSION['full_name'] = $full_name;
+ $_SESSION['user_phone'] = $phone;
+ $_SESSION['user_city'] = $city;
+ $_SESSION['isLoggedIn'] = true;
+ $_SESSION['isAdmin'] = (bool)$is_admin;
+ $_SESSION['login_time'] = time();
+
+ $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?");
+ $updateStmt->execute([$user_id]);
+
+ $_SESSION['registration_success'] = 'Регистрация прошла успешно! ' .
+ ($is_admin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!');
+
+ header('Location: ../catalog.php');
+ exit();
+
+ } catch (PDOException $e) {
+
+ error_log("Registration DB Error: " . $e->getMessage());
+ error_log("SQL State: " . $e->getCode());
+ error_log("Email: " . $email);
+
+ $_SESSION['registration_errors'] = ['Ошибка базы данных: ' . $e->getMessage()];
+ $_SESSION['old_data'] = [
+ 'fio' => $full_name,
+ 'city' => $city,
+ 'email' => $email,
+ 'phone' => $phone
+ ];
+ header('Location: ../register.php');
+ exit();
+ } catch (Exception $e) {
+ error_log("Registration Error: " . $e->getMessage());
+
+ $_SESSION['registration_errors'] = [$e->getMessage()];
+ header('Location: ../register.php');
+ exit();
+ }
+
+} else {
+
+ header('Location: register.php');
+ exit();
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/api/update_cart.php b/OLD_CODE/public/api/update_cart.php
new file mode 100644
index 0000000..0063946
--- /dev/null
+++ b/OLD_CODE/public/api/update_cart.php
@@ -0,0 +1,31 @@
+ false, 'message' => 'Требуется авторизация']);
+ exit();
+}
+
+if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['product_id'])) {
+ $product_id = intval($_POST['product_id']);
+ $quantity = intval($_POST['quantity'] ?? 1);
+ $user_id = $_SESSION['user_id'] ?? 0;
+
+ $db = Database::getInstance()->getConnection();
+
+ try {
+ $stmt = $db->prepare("
+ UPDATE cart
+ SET quantity = ?, updated_at = CURRENT_TIMESTAMP
+ WHERE user_id = ? AND product_id = ?
+ ");
+ $stmt->execute([$quantity, $user_id, $product_id]);
+
+ echo json_encode(['success' => true]);
+
+ } catch (PDOException $e) {
+ echo json_encode(['success' => false, 'message' => 'Ошибка базы данных']);
+ }
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/assets/img/1 — копия.jpg b/OLD_CODE/public/assets/img/1 — копия.jpg
new file mode 100644
index 0000000..68992d6
Binary files /dev/null and b/OLD_CODE/public/assets/img/1 — копия.jpg differ
diff --git a/OLD_CODE/public/assets/img/1.jpg b/OLD_CODE/public/assets/img/1.jpg
new file mode 100644
index 0000000..1df7668
Binary files /dev/null and b/OLD_CODE/public/assets/img/1.jpg differ
diff --git a/OLD_CODE/public/assets/img/100.jpg b/OLD_CODE/public/assets/img/100.jpg
new file mode 100644
index 0000000..646480d
Binary files /dev/null and b/OLD_CODE/public/assets/img/100.jpg differ
diff --git a/OLD_CODE/public/assets/img/11.jpg b/OLD_CODE/public/assets/img/11.jpg
new file mode 100644
index 0000000..3a8270e
Binary files /dev/null and b/OLD_CODE/public/assets/img/11.jpg differ
diff --git a/OLD_CODE/public/assets/img/111.jpg b/OLD_CODE/public/assets/img/111.jpg
new file mode 100644
index 0000000..33dc453
Binary files /dev/null and b/OLD_CODE/public/assets/img/111.jpg differ
diff --git a/OLD_CODE/public/assets/img/11_1.png b/OLD_CODE/public/assets/img/11_1.png
new file mode 100644
index 0000000..4735774
Binary files /dev/null and b/OLD_CODE/public/assets/img/11_1.png differ
diff --git a/OLD_CODE/public/assets/img/1_1.jpg b/OLD_CODE/public/assets/img/1_1.jpg
new file mode 100644
index 0000000..3f9e1a1
Binary files /dev/null and b/OLD_CODE/public/assets/img/1_1.jpg differ
diff --git a/OLD_CODE/public/assets/img/1_2.jpg b/OLD_CODE/public/assets/img/1_2.jpg
new file mode 100644
index 0000000..2d7a54a
Binary files /dev/null and b/OLD_CODE/public/assets/img/1_2.jpg differ
diff --git a/OLD_CODE/public/assets/img/1_2.png b/OLD_CODE/public/assets/img/1_2.png
new file mode 100644
index 0000000..9a8a6c0
Binary files /dev/null and b/OLD_CODE/public/assets/img/1_2.png differ
diff --git a/OLD_CODE/public/assets/img/2.jpg b/OLD_CODE/public/assets/img/2.jpg
new file mode 100644
index 0000000..417df4a
Binary files /dev/null and b/OLD_CODE/public/assets/img/2.jpg differ
diff --git a/OLD_CODE/public/assets/img/22.jpg b/OLD_CODE/public/assets/img/22.jpg
new file mode 100644
index 0000000..f59b320
Binary files /dev/null and b/OLD_CODE/public/assets/img/22.jpg differ
diff --git a/OLD_CODE/public/assets/img/25.jpg b/OLD_CODE/public/assets/img/25.jpg
new file mode 100644
index 0000000..03eddcf
Binary files /dev/null and b/OLD_CODE/public/assets/img/25.jpg differ
diff --git a/OLD_CODE/public/assets/img/2_2.jpg b/OLD_CODE/public/assets/img/2_2.jpg
new file mode 100644
index 0000000..76ba9ba
Binary files /dev/null and b/OLD_CODE/public/assets/img/2_2.jpg differ
diff --git a/OLD_CODE/public/assets/img/2_2.png b/OLD_CODE/public/assets/img/2_2.png
new file mode 100644
index 0000000..8fa6e8c
Binary files /dev/null and b/OLD_CODE/public/assets/img/2_2.png differ
diff --git a/OLD_CODE/public/assets/img/3.jpg b/OLD_CODE/public/assets/img/3.jpg
new file mode 100644
index 0000000..973449d
Binary files /dev/null and b/OLD_CODE/public/assets/img/3.jpg differ
diff --git a/OLD_CODE/public/assets/img/3_3.jpg b/OLD_CODE/public/assets/img/3_3.jpg
new file mode 100644
index 0000000..7e56605
Binary files /dev/null and b/OLD_CODE/public/assets/img/3_3.jpg differ
diff --git a/OLD_CODE/public/assets/img/3_3.png b/OLD_CODE/public/assets/img/3_3.png
new file mode 100644
index 0000000..ba16e91
Binary files /dev/null and b/OLD_CODE/public/assets/img/3_3.png differ
diff --git a/OLD_CODE/public/assets/img/4.jpg b/OLD_CODE/public/assets/img/4.jpg
new file mode 100644
index 0000000..da2945c
Binary files /dev/null and b/OLD_CODE/public/assets/img/4.jpg differ
diff --git a/OLD_CODE/public/assets/img/44.jpg b/OLD_CODE/public/assets/img/44.jpg
new file mode 100644
index 0000000..e38c994
Binary files /dev/null and b/OLD_CODE/public/assets/img/44.jpg differ
diff --git a/OLD_CODE/public/assets/img/444 b/OLD_CODE/public/assets/img/444
new file mode 100644
index 0000000..dc6e3fa
Binary files /dev/null and b/OLD_CODE/public/assets/img/444 differ
diff --git a/OLD_CODE/public/assets/img/444 (1).png b/OLD_CODE/public/assets/img/444 (1).png
new file mode 100644
index 0000000..ddf7e92
Binary files /dev/null and b/OLD_CODE/public/assets/img/444 (1).png differ
diff --git a/OLD_CODE/public/assets/img/444.jpg b/OLD_CODE/public/assets/img/444.jpg
new file mode 100644
index 0000000..dc6e3fa
Binary files /dev/null and b/OLD_CODE/public/assets/img/444.jpg differ
diff --git a/OLD_CODE/public/assets/img/444.png b/OLD_CODE/public/assets/img/444.png
new file mode 100644
index 0000000..cd53804
Binary files /dev/null and b/OLD_CODE/public/assets/img/444.png differ
diff --git a/OLD_CODE/public/assets/img/4_1.jpg b/OLD_CODE/public/assets/img/4_1.jpg
new file mode 100644
index 0000000..69f2236
Binary files /dev/null and b/OLD_CODE/public/assets/img/4_1.jpg differ
diff --git a/OLD_CODE/public/assets/img/5.jpg b/OLD_CODE/public/assets/img/5.jpg
new file mode 100644
index 0000000..456cec1
Binary files /dev/null and b/OLD_CODE/public/assets/img/5.jpg differ
diff --git a/OLD_CODE/public/assets/img/5_5.jpg b/OLD_CODE/public/assets/img/5_5.jpg
new file mode 100644
index 0000000..9ced54f
Binary files /dev/null and b/OLD_CODE/public/assets/img/5_5.jpg differ
diff --git a/OLD_CODE/public/assets/img/5_5.png b/OLD_CODE/public/assets/img/5_5.png
new file mode 100644
index 0000000..369b63b
Binary files /dev/null and b/OLD_CODE/public/assets/img/5_5.png differ
diff --git a/OLD_CODE/public/assets/img/6.jpg b/OLD_CODE/public/assets/img/6.jpg
new file mode 100644
index 0000000..550e17d
Binary files /dev/null and b/OLD_CODE/public/assets/img/6.jpg differ
diff --git a/OLD_CODE/public/assets/img/6_6.jpg b/OLD_CODE/public/assets/img/6_6.jpg
new file mode 100644
index 0000000..0aa5c4b
Binary files /dev/null and b/OLD_CODE/public/assets/img/6_6.jpg differ
diff --git a/OLD_CODE/public/assets/img/6_6.png b/OLD_CODE/public/assets/img/6_6.png
new file mode 100644
index 0000000..af949f9
Binary files /dev/null and b/OLD_CODE/public/assets/img/6_6.png differ
diff --git a/OLD_CODE/public/assets/img/7.jpg b/OLD_CODE/public/assets/img/7.jpg
new file mode 100644
index 0000000..17150c7
Binary files /dev/null and b/OLD_CODE/public/assets/img/7.jpg differ
diff --git a/OLD_CODE/public/assets/img/77.jpg b/OLD_CODE/public/assets/img/77.jpg
new file mode 100644
index 0000000..d9bf304
Binary files /dev/null and b/OLD_CODE/public/assets/img/77.jpg differ
diff --git a/OLD_CODE/public/assets/img/777 (1).png b/OLD_CODE/public/assets/img/777 (1).png
new file mode 100644
index 0000000..6b01d3f
Binary files /dev/null and b/OLD_CODE/public/assets/img/777 (1).png differ
diff --git a/OLD_CODE/public/assets/img/777.jpg b/OLD_CODE/public/assets/img/777.jpg
new file mode 100644
index 0000000..908d164
Binary files /dev/null and b/OLD_CODE/public/assets/img/777.jpg differ
diff --git a/OLD_CODE/public/assets/img/777.png b/OLD_CODE/public/assets/img/777.png
new file mode 100644
index 0000000..41d57c8
Binary files /dev/null and b/OLD_CODE/public/assets/img/777.png differ
diff --git a/OLD_CODE/public/assets/img/7_7.jpg b/OLD_CODE/public/assets/img/7_7.jpg
new file mode 100644
index 0000000..5ee1524
Binary files /dev/null and b/OLD_CODE/public/assets/img/7_7.jpg differ
diff --git a/OLD_CODE/public/assets/img/7_7.png b/OLD_CODE/public/assets/img/7_7.png
new file mode 100644
index 0000000..d50782e
Binary files /dev/null and b/OLD_CODE/public/assets/img/7_7.png differ
diff --git a/OLD_CODE/public/assets/img/8.jpg b/OLD_CODE/public/assets/img/8.jpg
new file mode 100644
index 0000000..8b41c63
Binary files /dev/null and b/OLD_CODE/public/assets/img/8.jpg differ
diff --git a/OLD_CODE/public/assets/img/88.jpg b/OLD_CODE/public/assets/img/88.jpg
new file mode 100644
index 0000000..713eeec
Binary files /dev/null and b/OLD_CODE/public/assets/img/88.jpg differ
diff --git a/OLD_CODE/public/assets/img/888 (1).png b/OLD_CODE/public/assets/img/888 (1).png
new file mode 100644
index 0000000..127e80d
Binary files /dev/null and b/OLD_CODE/public/assets/img/888 (1).png differ
diff --git a/OLD_CODE/public/assets/img/888.jpg b/OLD_CODE/public/assets/img/888.jpg
new file mode 100644
index 0000000..e8f33f7
Binary files /dev/null and b/OLD_CODE/public/assets/img/888.jpg differ
diff --git a/OLD_CODE/public/assets/img/888.png b/OLD_CODE/public/assets/img/888.png
new file mode 100644
index 0000000..35e3403
Binary files /dev/null and b/OLD_CODE/public/assets/img/888.png differ
diff --git a/OLD_CODE/public/assets/img/8_8.png b/OLD_CODE/public/assets/img/8_8.png
new file mode 100644
index 0000000..9f86b2c
Binary files /dev/null and b/OLD_CODE/public/assets/img/8_8.png differ
diff --git a/OLD_CODE/public/assets/img/9.jpg b/OLD_CODE/public/assets/img/9.jpg
new file mode 100644
index 0000000..0b772e3
Binary files /dev/null and b/OLD_CODE/public/assets/img/9.jpg differ
diff --git a/OLD_CODE/public/assets/img/99.jpg b/OLD_CODE/public/assets/img/99.jpg
new file mode 100644
index 0000000..ed309ba
Binary files /dev/null and b/OLD_CODE/public/assets/img/99.jpg differ
diff --git a/OLD_CODE/public/assets/img/99.png b/OLD_CODE/public/assets/img/99.png
new file mode 100644
index 0000000..8fd29b2
Binary files /dev/null and b/OLD_CODE/public/assets/img/99.png differ
diff --git a/OLD_CODE/public/assets/img/99_1.jpg b/OLD_CODE/public/assets/img/99_1.jpg
new file mode 100644
index 0000000..0247358
Binary files /dev/null and b/OLD_CODE/public/assets/img/99_1.jpg differ
diff --git a/OLD_CODE/public/assets/img/99_2.jpg b/OLD_CODE/public/assets/img/99_2.jpg
new file mode 100644
index 0000000..468fd51
Binary files /dev/null and b/OLD_CODE/public/assets/img/99_2.jpg differ
diff --git a/OLD_CODE/public/assets/img/99_3.png b/OLD_CODE/public/assets/img/99_3.png
new file mode 100644
index 0000000..ae2cd8e
Binary files /dev/null and b/OLD_CODE/public/assets/img/99_3.png differ
diff --git a/OLD_CODE/public/assets/img/9_9.jpg b/OLD_CODE/public/assets/img/9_9.jpg
new file mode 100644
index 0000000..a77f2ae
Binary files /dev/null and b/OLD_CODE/public/assets/img/9_9.jpg differ
diff --git a/OLD_CODE/public/assets/img/9_9.png b/OLD_CODE/public/assets/img/9_9.png
new file mode 100644
index 0000000..733a453
Binary files /dev/null and b/OLD_CODE/public/assets/img/9_9.png differ
diff --git a/OLD_CODE/public/assets/img/black.png b/OLD_CODE/public/assets/img/black.png
new file mode 100644
index 0000000..a10af51
Binary files /dev/null and b/OLD_CODE/public/assets/img/black.png differ
diff --git a/OLD_CODE/public/assets/img/black1.png b/OLD_CODE/public/assets/img/black1.png
new file mode 100644
index 0000000..f529bd3
Binary files /dev/null and b/OLD_CODE/public/assets/img/black1.png differ
diff --git a/OLD_CODE/public/assets/img/black2.png b/OLD_CODE/public/assets/img/black2.png
new file mode 100644
index 0000000..75758a2
Binary files /dev/null and b/OLD_CODE/public/assets/img/black2.png differ
diff --git a/OLD_CODE/public/assets/img/brown.png b/OLD_CODE/public/assets/img/brown.png
new file mode 100644
index 0000000..9ef4db4
Binary files /dev/null and b/OLD_CODE/public/assets/img/brown.png differ
diff --git a/OLD_CODE/public/assets/img/brown1.png b/OLD_CODE/public/assets/img/brown1.png
new file mode 100644
index 0000000..0b178f1
Binary files /dev/null and b/OLD_CODE/public/assets/img/brown1.png differ
diff --git a/OLD_CODE/public/assets/img/brown2.png b/OLD_CODE/public/assets/img/brown2.png
new file mode 100644
index 0000000..346b22f
Binary files /dev/null and b/OLD_CODE/public/assets/img/brown2.png differ
diff --git a/OLD_CODE/public/assets/img/chair.PNG b/OLD_CODE/public/assets/img/chair.PNG
new file mode 100644
index 0000000..12af9db
Binary files /dev/null and b/OLD_CODE/public/assets/img/chair.PNG differ
diff --git a/OLD_CODE/public/assets/img/gray.png b/OLD_CODE/public/assets/img/gray.png
new file mode 100644
index 0000000..55ab5bb
Binary files /dev/null and b/OLD_CODE/public/assets/img/gray.png differ
diff --git a/OLD_CODE/public/assets/img/gray1.png b/OLD_CODE/public/assets/img/gray1.png
new file mode 100644
index 0000000..3137e25
Binary files /dev/null and b/OLD_CODE/public/assets/img/gray1.png differ
diff --git a/OLD_CODE/public/assets/img/gray2.png b/OLD_CODE/public/assets/img/gray2.png
new file mode 100644
index 0000000..95b8781
Binary files /dev/null and b/OLD_CODE/public/assets/img/gray2.png differ
diff --git a/OLD_CODE/public/assets/img/диван.jpg b/OLD_CODE/public/assets/img/диван.jpg
new file mode 100644
index 0000000..578d1a3
Binary files /dev/null and b/OLD_CODE/public/assets/img/диван.jpg differ
diff --git a/OLD_CODE/public/assets/img/диван_1.jpg b/OLD_CODE/public/assets/img/диван_1.jpg
new file mode 100644
index 0000000..3618723
Binary files /dev/null and b/OLD_CODE/public/assets/img/диван_1.jpg differ
diff --git a/OLD_CODE/public/assets/img/кресло.jpg b/OLD_CODE/public/assets/img/кресло.jpg
new file mode 100644
index 0000000..6d1c12b
Binary files /dev/null and b/OLD_CODE/public/assets/img/кресло.jpg differ
diff --git a/OLD_CODE/public/assets/img/кресло_1.jpg b/OLD_CODE/public/assets/img/кресло_1.jpg
new file mode 100644
index 0000000..e59b3b1
Binary files /dev/null and b/OLD_CODE/public/assets/img/кресло_1.jpg differ
diff --git a/OLD_CODE/public/assets/img/слайдер_1.jpg b/OLD_CODE/public/assets/img/слайдер_1.jpg
new file mode 100644
index 0000000..255440e
Binary files /dev/null and b/OLD_CODE/public/assets/img/слайдер_1.jpg differ
diff --git a/OLD_CODE/public/assets/img/слайдер_2.jpg b/OLD_CODE/public/assets/img/слайдер_2.jpg
new file mode 100644
index 0000000..9cb6403
Binary files /dev/null and b/OLD_CODE/public/assets/img/слайдер_2.jpg differ
diff --git a/OLD_CODE/public/assets/img/слайдер_3.jpg b/OLD_CODE/public/assets/img/слайдер_3.jpg
new file mode 100644
index 0000000..dc65d0b
Binary files /dev/null and b/OLD_CODE/public/assets/img/слайдер_3.jpg differ
diff --git a/OLD_CODE/public/assets/img/слайдер_4.jpg b/OLD_CODE/public/assets/img/слайдер_4.jpg
new file mode 100644
index 0000000..f6d8d38
Binary files /dev/null and b/OLD_CODE/public/assets/img/слайдер_4.jpg differ
diff --git a/OLD_CODE/public/assets/img/слайдер_5.jpg b/OLD_CODE/public/assets/img/слайдер_5.jpg
new file mode 100644
index 0000000..a9cfbb6
Binary files /dev/null and b/OLD_CODE/public/assets/img/слайдер_5.jpg differ
diff --git a/OLD_CODE/public/assets/img/слайдер_6.jpg b/OLD_CODE/public/assets/img/слайдер_6.jpg
new file mode 100644
index 0000000..0dc28a0
Binary files /dev/null and b/OLD_CODE/public/assets/img/слайдер_6.jpg differ
diff --git a/OLD_CODE/public/assets/img/спальня.jpg b/OLD_CODE/public/assets/img/спальня.jpg
new file mode 100644
index 0000000..f403324
Binary files /dev/null and b/OLD_CODE/public/assets/img/спальня.jpg differ
diff --git a/OLD_CODE/public/assets/img/стили_оформления.css b/OLD_CODE/public/assets/img/стили_оформления.css
new file mode 100644
index 0000000..2e1d09c
--- /dev/null
+++ b/OLD_CODE/public/assets/img/стили_оформления.css
@@ -0,0 +1,61 @@
+
+.error-message {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+}
+
+.form__input.error {
+ border-color: #ff0000;
+}
+
+.form__group {
+ position: relative;
+ margin-bottom: 15px;
+}
+
+.page-messages {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1000;
+ width: 90%;
+ max-width: 500px;
+}
+
+.message {
+ padding: 15px;
+ margin: 10px 0;
+ border-radius: 5px;
+ text-align: center;
+ font-weight: bold;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #453227;
+ border: 1px solid #c8e6c9;
+}
+
+.message.warning {
+ background-color: #fff3e0;
+ color: #ef6c00;
+ border: 1px solid #ffe0b2;
+}
+
+.privacy-error {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+ text-align: center;
+}
diff --git a/OLD_CODE/public/assets/js/checkout.js b/OLD_CODE/public/assets/js/checkout.js
new file mode 100644
index 0000000..45a09f5
--- /dev/null
+++ b/OLD_CODE/public/assets/js/checkout.js
@@ -0,0 +1,306 @@
+
+$(document).ready(function() {
+
+ let cart = {
+ items: [
+ { id: 1, name: 'Кресло OPPORTUNITY', price: 16999, quantity: 1 },
+ { id: 2, name: 'Кресло GOLDEN', price: 19999, quantity: 1 },
+ { id: 3, name: 'Светильник POLET', price: 7999, quantity: 1 }
+ ],
+ delivery: 2000,
+ discount: 0
+ };
+
+ function updateTotal() {
+ let productsTotal = 0;
+ let totalCount = 0;
+
+ $('.products__item').each(function() {
+ const $item = $(this);
+ const price = parseInt($item.data('price'));
+ const quantity = parseInt($item.find('.products__qty-value').text());
+
+ productsTotal += price * quantity;
+ totalCount += quantity;
+ });
+
+ $('.products-total').text(productsTotal + ' ₽');
+ $('.summary-count').text(totalCount);
+ $('.total-count').text(totalCount + ' шт.');
+ $('.cart-count').text(totalCount);
+
+ const finalTotal = productsTotal + cart.delivery - cart.discount;
+ $('.final-total').text(finalTotal + ' ₽');
+ }
+
+ function validateEmail(email) {
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ return emailRegex.test(email);
+ }
+
+ function validateFullName(name) {
+
+ const nameRegex = /^[a-zA-Zа-яА-ЯёЁ\s\-']+$/;
+
+ const words = name.trim().split(/\s+/);
+
+ return nameRegex.test(name) && words.length >= 2;
+ }
+
+ function validatePhone(phone) {
+ const phoneRegex = /^\+7\d{10}$/;
+ return phoneRegex.test(phone);
+ }
+
+ function showMessage(messageId, duration = 5000) {
+ $('.message').hide();
+
+ $(messageId).fadeIn(300);
+
+ if (duration > 0) {
+ setTimeout(() => {
+ $(messageId).fadeOut(300);
+ }, duration);
+ }
+ }
+
+ function showPrivacyError(show) {
+ if (show) {
+ $('#privacy-error').show();
+ } else {
+ $('#privacy-error').hide();
+ }
+ }
+
+ function showFieldError(fieldId, message) {
+ $(fieldId).removeClass('error-input');
+ $(fieldId + '-error').remove();
+
+ if (message) {
+ $(fieldId).addClass('error-input');
+ $(fieldId).after('' + message + '
');
+ }
+ }
+
+ $('#fullname').on('blur', function() {
+ const value = $(this).val().trim();
+ if (value) {
+ if (!validateFullName(value)) {
+ showFieldError('#fullname', 'ФИО должно содержать только буквы и состоять минимум из 2 слов');
+ } else {
+ showFieldError('#fullname', '');
+ }
+ } else {
+ showFieldError('#fullname', '');
+ }
+ });
+
+ $('#email').on('blur', function() {
+ const value = $(this).val().trim();
+ if (value) {
+ if (!validateEmail(value)) {
+ showFieldError('#email', 'Введите корректный email адрес (например: example@mail.ru)');
+ } else {
+ showFieldError('#email', '');
+ }
+ } else {
+ showFieldError('#email', '');
+ }
+ });
+
+ $('#phone').on('blur', function() {
+ const value = $(this).val().trim();
+ if (value) {
+ if (!validatePhone(value)) {
+ showFieldError('#phone', 'Введите номер в формате +7XXXXXXXXXX (10 цифр после +7)');
+ } else {
+ showFieldError('#phone', '');
+ }
+ } else {
+ showFieldError('#phone', '');
+ }
+ });
+
+ $('#region').on('blur', function() {
+ const value = $(this).val().trim();
+ if (!value) {
+ showFieldError('#region', 'Укажите регион доставки');
+ } else {
+ showFieldError('#region', '');
+ }
+ });
+
+ $('#address').on('blur', function() {
+ const value = $(this).val().trim();
+ if (!value) {
+ showFieldError('#address', 'Укажите адрес доставки (улица, дом, квартира)');
+ } else {
+ showFieldError('#address', '');
+ }
+ });
+
+ $('.form__input').on('input', function() {
+ const fieldId = '#' + $(this).attr('id');
+ showFieldError(fieldId, '');
+ });
+
+ $('.products__qty-btn.plus').click(function() {
+ const $qtyValue = $(this).siblings('.products__qty-value');
+ let quantity = parseInt($qtyValue.text());
+ $qtyValue.text(quantity + 1);
+ updateTotal();
+ });
+
+ $('.products__qty-btn.minus').click(function() {
+ const $qtyValue = $(this).siblings('.products__qty-value');
+ let quantity = parseInt($qtyValue.text());
+ if (quantity > 1) {
+ $qtyValue.text(quantity - 1);
+ updateTotal();
+ }
+ });
+
+ $('.remove-from-cart').click(function() {
+ const $productItem = $(this).closest('.products__item');
+ $productItem.fadeOut(300, function() {
+ $(this).remove();
+ updateTotal();
+
+ if ($('.products__item').length === 0) {
+ $('.products__list').html('Корзина пуста
');
+ }
+ });
+ });
+
+ $('.promo__btn').click(function() {
+ const promoCode = $('.promo__input').val().toUpperCase();
+
+ if (promoCode === 'SALE10') {
+ cart.discount = Math.round(parseInt($('.products-total').text()) * 0.1);
+ $('.discount-total').text(cart.discount + ' ₽');
+ showMessage('#form-error', 3000);
+ $('#form-error').text('Промокод применен! Скидка 10%').removeClass('error').addClass('success');
+ } else if (promoCode === 'FREE') {
+ cart.delivery = 0;
+ $('.delivery-price').text('0 ₽');
+ showMessage('#form-error', 3000);
+ $('#form-error').text('Промокод применен! Бесплатная доставка').removeClass('error').addClass('success');
+ } else if (promoCode) {
+ showMessage('#form-error', 3000);
+ $('#form-error').text('Промокод недействителен').removeClass('success').addClass('error');
+ }
+
+ updateTotal();
+ });
+
+ $('input[name="delivery"]').change(function() {
+ if ($(this).val() === 'pickup') {
+ cart.delivery = 0;
+ $('.delivery-price').text('0 ₽');
+ } else {
+ cart.delivery = 2000;
+ $('.delivery-price').text('2000 ₽');
+ }
+ updateTotal();
+ });
+
+ function validateForm() {
+ let isValid = true;
+ let errorMessages = [];
+
+ $('.field-error').remove();
+ $('.form__input').removeClass('error-input');
+
+ const requiredFields = [
+ {
+ id: '#fullname',
+ value: $('#fullname').val().trim(),
+ validator: validateFullName,
+ required: true,
+ message: 'ФИО должно содержать только буквы и состоять минимум из 2 слов'
+ },
+ {
+ id: '#phone',
+ value: $('#phone').val().trim(),
+ validator: validatePhone,
+ required: true,
+ message: 'Введите корректный номер телефона в формате +7XXXXXXXXXX'
+ },
+ {
+ id: '#email',
+ value: $('#email').val().trim(),
+ validator: validateEmail,
+ required: true,
+ message: 'Введите корректный email адрес'
+ },
+ {
+ id: '#region',
+ value: $('#region').val().trim(),
+ validator: (val) => val.length > 0,
+ required: true,
+ message: 'Поле "Регион" обязательно для заполнения'
+ },
+ {
+ id: '#address',
+ value: $('#address').val().trim(),
+ validator: (val) => val.length > 0,
+ required: true,
+ message: 'Поле "Адрес" обязательно для заполнения'
+ }
+ ];
+
+ requiredFields.forEach(field => {
+ if (field.required && (!field.value || !field.validator(field.value))) {
+ isValid = false;
+ errorMessages.push(field.message);
+ showFieldError(field.id, field.message);
+ }
+ });
+
+ if (!$('#privacy-checkbox').is(':checked')) {
+ isValid = false;
+ showPrivacyError(true);
+ errorMessages.push('Необходимо согласие на обработку персональных данных');
+ } else {
+ showPrivacyError(false);
+ }
+
+ if (!isValid && errorMessages.length > 0) {
+ showMessage('#form-error', 5000);
+ $('#form-error').text('Исправьте следующие ошибки: ' + errorMessages.join('; ')).removeClass('success').addClass('error');
+
+ $('html, body').animate({
+ scrollTop: $('.error-input').first().offset().top - 100
+ }, 500);
+ }
+
+ return isValid;
+ }
+
+ $('#submit-order').click(function() {
+ if (!validateForm()) {
+ return;
+ }
+
+ $(this).prop('disabled', true).text('ОБРАБОТКА...');
+
+ setTimeout(() => {
+ showMessage('#order-success', 5000);
+ $(this).prop('disabled', false).text('ОФОРМИТЬ ЗАКАЗ');
+
+ }, 2000);
+ });
+
+ $('#phone').on('input', function() {
+ let phone = $(this).val().replace(/\D/g, '');
+ if (phone.length > 0) {
+ if (phone[0] !== '7' && phone[0] !== '8') {
+ phone = '7' + phone;
+ }
+ phone = '+7' + phone.substring(1, 11);
+ $(this).val(phone);
+ }
+ });
+
+ updateTotal();
+});
diff --git a/OLD_CODE/public/assets/js/profile.js b/OLD_CODE/public/assets/js/profile.js
new file mode 100644
index 0000000..0224b62
--- /dev/null
+++ b/OLD_CODE/public/assets/js/profile.js
@@ -0,0 +1,348 @@
+$(document).ready(function() {
+
+ function showMessage(type, text) {
+ const messageId = type + 'Message';
+ const $message = $('#' + messageId);
+ $message.text(text).fadeIn(300);
+ setTimeout(() => {
+ $message.fadeOut(300);
+ }, 5000);
+ }
+
+ function isAdminEmail(email) {
+ const adminEmails = ['admin@aeterna.ru', 'administrator@aeterna.ru', 'aeterna@mail.ru'];
+ return adminEmails.includes(email.toLowerCase());
+ }
+
+ function validateFIO(fio) {
+ const words = fio.trim().split(/\s+/);
+
+ const hasNoDigits = !/\d/.test(fio);
+ return words.length >= 2 && words.every(word => word.length >= 2) && hasNoDigits;
+ }
+
+ function validateCity(city) {
+ return city.trim().length >= 2 && /^[а-яА-ЯёЁ\s-]+$/.test(city);
+ }
+
+ function validateEmail(email) {
+ const localPart = email.split('@')[0];
+
+ if (/[а-яА-ЯёЁ]/.test(localPart)) {
+ showError('email', 'В тексте перед знаком "@" не должно быть кириллических символов');
+ return false;
+ }
+
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ if (!emailRegex.test(email)) {
+ showError('email', 'Введите корректный email адрес');
+ return false;
+ }
+
+ hideError('email');
+ return true;
+ }
+
+ function validatePhone(phone) {
+ const phoneRegex = /^(\+7|8)[\s-]?\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{2}[\s-]?\d{2}$/;
+ return phoneRegex.test(phone.replace(/\s/g, ''));
+ }
+
+ function validatePassword(password) {
+ return password.length >= 6;
+ }
+
+ function showError(fieldId, message) {
+ $('#' + fieldId).addClass('error');
+ $('#' + fieldId + '-error').text(message).show();
+ }
+
+ function hideError(fieldId) {
+ $('#' + fieldId).removeClass('error');
+ $('#' + fieldId + '-error').hide();
+ }
+
+ function validateForm() {
+ let isValid = true;
+
+ const fio = $('#fio').val();
+ if (!validateFIO(fio)) {
+ if (/\d/.test(fio)) {
+ showError('fio', 'ФИО не должно содержать цифры');
+ } else {
+ showError('fio', 'ФИО должно содержать минимум 2 слова (каждое от 2 символов)');
+ }
+ isValid = false;
+ } else {
+ hideError('fio');
+ }
+
+ const city = $('#city').val();
+ if (!validateCity(city)) {
+ showError('city', 'Укажите корректное название города (только русские буквы)');
+ isValid = false;
+ } else {
+ hideError('city');
+ }
+
+ const email = $('#email').val();
+ if (!validateEmail(email)) {
+ showError('email', 'Введите корректный email адрес');
+ isValid = false;
+ } else {
+ hideError('email');
+ }
+
+ const phone = $('#phone').val();
+ if (!validatePhone(phone)) {
+ showError('phone', 'Введите номер в формате: +7(912)999-12-23');
+ isValid = false;
+ } else {
+ hideError('phone');
+ }
+
+ const password = $('#password').val();
+ if (!validatePassword(password)) {
+ showError('password', 'Пароль должен содержать минимум 6 символов');
+ isValid = false;
+ } else {
+ hideError('password');
+ }
+
+ const confirmPassword = $('#confirm-password').val();
+ if (password !== confirmPassword) {
+ showError('confirm-password', 'Пароли не совпадают');
+ isValid = false;
+ } else {
+ hideError('confirm-password');
+ }
+
+ if (!$('#privacy').is(':checked')) {
+ $('#privacy-error').show();
+ isValid = false;
+ } else {
+ $('#privacy-error').hide();
+ }
+
+ return isValid;
+ }
+
+ $('input').on('blur', function() {
+ const fieldId = $(this).attr('id');
+ const value = $(this).val();
+
+ switch(fieldId) {
+ case 'fio':
+ if (!validateFIO(value)) {
+ if (/\d/.test(value)) {
+ showError(fieldId, 'ФИО не должно содержать цифры');
+ } else {
+ showError(fieldId, 'ФИО должно содержать минимум 2 слова');
+ }
+ } else {
+ hideError(fieldId);
+ }
+ break;
+ case 'city':
+ if (!validateCity(value)) {
+ showError(fieldId, 'Укажите корректное название города');
+ } else {
+ hideError(fieldId);
+ }
+ break;
+ case 'email':
+ if (!validateEmail(value)) {
+ showError(fieldId, 'Введите корректный email адрес');
+ } else {
+ hideError(fieldId);
+ }
+ break;
+ case 'phone':
+ if (!validatePhone(value)) {
+ showError(fieldId, 'Введите номер в формате: +7(912)999-12-23');
+ } else {
+ hideError(fieldId);
+ }
+ break;
+ case 'password':
+ if (!validatePassword(value)) {
+ showError(fieldId, 'Пароль должен содержать минимум 6 символов');
+ } else {
+ hideError(fieldId);
+ }
+ break;
+ case 'confirm-password':
+ const password = $('#password').val();
+ if (value !== password) {
+ showError(fieldId, 'Пароли не совпадают');
+ } else {
+ hideError(fieldId);
+ }
+ break;
+ }
+ });
+
+ $('#registrationForm').on('submit', function(e) {
+ e.preventDefault();
+
+ if (validateForm()) {
+ const email = $('#email').val();
+ const isAdmin = isAdminEmail(email);
+
+ const userData = {
+ email: email,
+ fio: $('#fio').val(),
+ phone: $('#phone').val(),
+ isAdmin: isAdmin,
+ registered: new Date().toISOString()
+ };
+
+ localStorage.setItem('userData', JSON.stringify(userData));
+ localStorage.setItem('isLoggedIn', 'true');
+ localStorage.setItem('isAdmin', isAdmin.toString());
+
+ showMessage('success', 'Регистрация прошла успешно! ' +
+ (isAdmin ? 'Вы зарегистрированы как администратор.' : 'Добро пожаловать в AETERNA!'));
+
+ setTimeout(() => {
+
+ window.location.href = 'cite_mebel.php';
+ }, 2000);
+ } else {
+ showMessage('error', 'Пожалуйста, исправьте ошибки в форме');
+ }
+ });
+
+ $('a[href^="#"]').on('click', function(event) {
+ var target = $(this.getAttribute('href'));
+ if (target.length) {
+ event.preventDefault();
+ $('html, body').stop().animate({
+ scrollTop: target.offset().top
+ }, 1000);
+ }
+ });
+
+ $('.login-btn').on('click', function() {
+ showMessage('warning', 'Переход к форме входа...');
+ setTimeout(() => {
+ window.location.href = 'вход.php';
+ }, 1000);
+ });
+
+ $('.password-link').on('click', function(e) {
+ e.preventDefault();
+ showMessage('warning', 'Функция смены пароля будет доступна после регистрации');
+ });
+
+ $('#phone').on('input', function() {
+ let value = $(this).val().replace(/\D/g, '');
+ if (value.startsWith('7') || value.startsWith('8')) {
+ value = value.substring(1);
+ }
+ if (value.length > 0) {
+ value = '+7(' + value;
+ if (value.length > 6) value = value.substring(0, 6) + ')' + value.substring(6);
+ if (value.length > 10) value = value.substring(0, 10) + '-' + value.substring(10);
+ if (value.length > 13) value = value.substring(0, 13) + '-' + value.substring(13);
+ if (value.length > 16) value = value.substring(0, 16);
+ }
+ $(this).val(value);
+ });
+
+ $('#fio').on('input', function() {
+ let value = $(this).val();
+
+ value = value.replace(/\d/g, '');
+ $(this).val(value);
+ });
+});
+
+$(document).ready(function() {
+
+ if (localStorage.getItem('isLoggedIn') === 'true') {
+ const userData = JSON.parse(localStorage.getItem('userData') || '{}');
+ if (userData.email) {
+ $('#login-email').val(userData.email);
+ }
+ }
+
+ function checkAdminPassword(email, password) {
+
+ const adminAccounts = {
+ 'admin@aeterna.ru': 'admin123',
+ 'administrator@aeterna.ru': 'admin123',
+ 'aeterna@mail.ru': 'admin123'
+ };
+
+ return adminAccounts[email.toLowerCase()] === password;
+ }
+
+ $('#loginForm').on('submit', function(e) {
+ e.preventDefault();
+
+ let isValid = true;
+ const email = $('#login-email').val();
+ const password = $('#login-password').val();
+
+ if (!isValidEmail(email)) {
+ $('#email-error').show();
+ isValid = false;
+ } else {
+ $('#email-error').hide();
+ }
+
+ if (password.length < 6) {
+ $('#password-error').show();
+ isValid = false;
+ } else {
+ $('#password-error').hide();
+ }
+
+ if (isValid) {
+
+ showMessage('success', 'Вы успешно вошли в систему!');
+
+ setTimeout(function() {
+ window.location.href = 'cite_mebel.php';
+ }, 1500);
+ }
+ });
+
+ function showMessage(type, text) {
+ const messageId = type + 'Message';
+ const $message = $('#' + messageId);
+
+ $message.text(text).show();
+
+ setTimeout(function() {
+ $message.fadeOut();
+ }, 3000);
+ }
+
+ $('input').on('focus', function() {
+ $(this).next('.error-message').hide();
+ });
+
+ $('#remember').on('change', function() {
+ if ($(this).is(':checked')) {
+ const email = $('#login-email').val();
+ if (email) {
+ localStorage.setItem('rememberedEmail', email);
+ }
+ } else {
+ localStorage.removeItem('rememberedEmail');
+ }
+ });
+
+ const rememberedEmail = localStorage.getItem('rememberedEmail');
+ if (rememberedEmail) {
+ $('#login-email').val(rememberedEmail);
+ $('#remember').prop('checked', true);
+ }
+
+ $('.forgot-password').on('click', function(e) {
+ e.preventDefault();
+ showMessage('info', 'Для восстановления пароля обратитесь к администратору');
+ });
+});
diff --git a/стили_оформления.less b/OLD_CODE/public/assets/less/checkout.less
similarity index 100%
rename from стили_оформления.less
rename to OLD_CODE/public/assets/less/checkout.less
diff --git a/OLD_CODE/public/assets/less/mixins.less b/OLD_CODE/public/assets/less/mixins.less
new file mode 100644
index 0000000..10638f0
--- /dev/null
+++ b/OLD_CODE/public/assets/less/mixins.less
@@ -0,0 +1,85 @@
+// ===================================
+// === ПЕРЕМЕННЫЕ И МИКСИНЫ AETERNA ===
+// ===================================
+@color-primary: #617365;
+@color-secondary: #D1D1D1;
+@color-accent: #453227;
+@color-text-dark: #333;
+@color-text-light: #fff;
+@color-button: @color-accent;
+@color-beige: #A2A09A;
+
+@font-logo: 'Anek Kannada', sans-serif;
+@font-main: 'Anonymous Pro', monospace;
+@font-heading: 'Playfair Display', serif;
+
+@shadow-light: 0 5px 15px rgba(0, 0, 0, 0.2);
+@shadow-dark: 2px 2px 4px rgba(0, 0, 0, 0.3);
+
+.flex-center(@gap: 0) {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: @gap;
+}
+
+.flex-between() {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+.flex-column() {
+ display: flex;
+ flex-direction: column;
+}
+
+.icon-base(@size: 18px, @hover-scale: 1.1) {
+ cursor: pointer;
+ transition: all 0.3s ease;
+ font-size: @size;
+ &:hover {
+ transform: scale(@hover-scale);
+ }
+}
+
+.image-overlay() {
+ position: absolute;
+ inset: 0;
+ .flex-center(15px);
+ flex-direction: column;
+ text-align: center;
+ background-color: rgba(0, 0, 0, 0.4);
+ padding: 20px;
+ color: @color-text-light;
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
+ transition: all 0.3s ease;
+}
+
+.menu-base() {
+ position: absolute;
+ top: 100%;
+ left: 0;
+ width: 250px;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+ padding: 15px;
+ z-index: 1000;
+ margin-top: 5px;
+ display: none;
+}
+
+.input-base() {
+ width: 100%;
+ padding: 12px 15px;
+ border: 1px solid #ccc;
+ background-color: #fff;
+ font-family: @font-main;
+ font-size: 14px;
+ outline: none;
+ transition: border-color 0.3s ease;
+ &:focus {
+ border-color: @color-primary;
+ }
+}
diff --git a/OLD_CODE/public/assets/less/style.less b/OLD_CODE/public/assets/less/style.less
new file mode 100644
index 0000000..667a7f4
--- /dev/null
+++ b/OLD_CODE/public/assets/less/style.less
@@ -0,0 +1,3177 @@
+@import "mixins.less";
+// =======================
+// === БАЗОВЫЕ СТИЛИ ===
+// =======================
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+html, body {
+ height: 100%;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ font-family: @font-main;
+ background-color: @color-secondary;
+ color: @color-text-dark;
+ line-height: 1.6;
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+}
+
+.container {
+ max-width: 1210px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+ul {
+ list-style: none;
+}
+
+a {
+ text-decoration: none;
+ color: inherit;
+ transition: all 0.3s ease;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: @font-heading;
+ margin: 0;
+}
+
+p, li, span {
+ font-family: @font-main;
+}
+
+// =======================
+// === КОМПОНЕНТЫ ===
+// =======================
+
+.logo, .footer-logo {
+ font: bold 32px/1 @font-logo;
+ letter-spacing: 2px;
+ text-shadow: @shadow-dark;
+ flex-shrink: 0;
+}
+
+.btn {
+ padding: 12px 30px;
+ border: none;
+ cursor: pointer;
+ font-size: 14px;
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+ font-family: @font-main;
+
+ &.primary-btn {
+ background-color: @color-button;
+ color: @color-text-light;
+
+ &:hover {
+ background-color: lighten(@color-button, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+}
+
+.number-circle {
+ .flex-center();
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background-color: @color-button;
+ color: @color-text-light;
+ font-size: 16px;
+ font-weight: bold;
+ flex-shrink: 0;
+}
+
+.breadcrumbs {
+ font-size: 14px;
+ margin-bottom: 20px;
+ color: #666;
+
+ a {
+ color: #666;
+ opacity: 0.7;
+ &:hover { opacity: 1; }
+ }
+
+ .current-page {
+ font-weight: bold;
+ color: @color-text-dark;
+ }
+}
+
+// =======================
+// === ШАПКА САЙТА ===
+// =======================
+.header {
+ background-color: @color-secondary;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+ z-index: 1000;
+
+ &__top, &__bottom {
+ padding: 15px 0;
+ .container {
+ .flex-between();
+ gap: 20px;
+ }
+ }
+
+ &__bottom {
+ padding: 10px 0;
+ border-top: 1px solid rgba(0, 0, 0, 0.05);
+
+ .catalog-link.active-catalog {
+ background-color: rgba(0, 0, 0, 0.08);
+ pointer-events: none;
+ }
+ }
+
+ .search-catalog {
+ .flex-center();
+ border: 2px solid @color-text-dark;
+ background-color: #fff;
+ max-width: 600px;
+ width: 100%;
+ margin: 0 auto;
+ overflow: hidden;
+
+ .catalog-dropdown {
+ position: relative;
+ background-color: #f8f8f8;
+ padding: 10px 15px 10px 25px;
+ font-size: 18px;
+ cursor: pointer;
+ border-right: 1px solid @color-text-dark;
+ .flex-center(10px);
+ width: 200px;
+ flex-shrink: 0;
+
+ &__menu {
+ .menu-base();
+ li {
+ padding: 8px 0;
+ cursor: pointer;
+ transition: color 0.3s;
+ border-bottom: 1px solid #f0f0f0;
+ &:last-child { border-bottom: none; }
+ &:hover { color: @color-accent; }
+ }
+ }
+ &:hover &__menu { display: block; }
+ }
+
+ .search-box {
+ .flex-center();
+ padding: 0 15px;
+ flex-grow: 1;
+ position: relative;
+ font-size: 15px;
+
+ input {
+ border: none;
+ padding: 10px 30px 10px 0;
+ outline: none;
+ font-size: 16px;
+ width: 100%;
+ text-align: left;
+ }
+
+ .search-icon {
+ font-size: 20px;
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }}
+
+ &__icons--top {
+ .flex-center(15px);
+ flex-shrink: 0;
+ .icon { .icon-base(); font-size: 20px;}
+ }
+
+ .nav-list {
+ .flex-center(30px);
+ font-size: 18px;
+ a {
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
+ &:hover { text-shadow: @shadow-dark; }
+ &.active {
+ border-bottom: 2px solid @color-button;
+ padding-bottom: 5px;
+ text-shadow: @shadow-dark;
+ }
+ &[href="#footer"] {
+ cursor: pointer;
+ }
+ }
+ }
+
+ .catalog-link {
+ .flex-center(10px);
+ border-radius: 4px;
+ white-space: nowrap;
+ font-size: 18px;
+ padding: 10px 18px;
+ &:hover { background-color: rgba(0, 0, 0, 0.05); }
+ }
+
+ .header-phone {
+ font-weight: bold;
+ color: @color-button;
+ flex-shrink: 0;
+ }
+}
+
+// =======================
+// === ОСНОВНЫЕ СЕКЦИИ ===
+// =======================
+.hero {
+ padding: 15px 0;
+
+ &__content {
+ .flex-center(50px);
+ min-height: 60vh;
+ align-items: center;
+ }
+
+ &__image-block {
+ position: relative;
+ flex: 0 0 40%;
+ max-width: 600px;
+ height: 600px;
+ .flex-center();
+
+ .hero__circle {
+ position: absolute;
+ width: 450px;
+ height: 450px;
+ background-color: @color-primary;
+ border-radius: 50%;
+ z-index: 1;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ .hero__img {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ z-index: 2;
+ }
+ }
+
+ &__text-block {
+ flex: 0 0 60%;
+ padding-left: 50px;
+
+ h1 {
+ font-size: 42px;
+ font-weight: normal;
+ margin-bottom: 25px;
+ line-height: 1.3;
+ }
+
+ .hero__usp-text {
+ position: relative;
+ padding-left: 50px;
+ margin-bottom: 35px;
+ line-height: 1.7;
+ .flex-center();
+ justify-content: flex-start;
+ min-height: 40px;
+ font-size: 16px;
+
+ &::before {
+ content: "✓";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 32px;
+ height: 32px;
+ border: 2px solid @color-button;
+ background-color: transparent;
+ color: @color-button;
+ border-radius: 50%;
+ .flex-center();
+ font-size: 16px;
+ font-weight: bold;
+ }
+ }
+
+ .btn.primary-btn {
+ margin: 25px 0 0 50px;
+ padding: 14px 35px;
+ font-size: 15px;
+ }
+ }
+}
+
+.advantages {
+ padding: 30px 0 40px;
+
+ &__header {
+ display: flex;
+ align-items: center;
+ gap: 50px;
+ margin-bottom: 40px;
+ h2 {
+ font-size: 32px;
+ font-weight: normal;
+ flex: 0 0 30%;
+ }
+ }
+
+ &__items {
+ flex: 0 0 70%;
+ display: flex;
+ gap: 30px;
+ }
+
+ .advantage-item {
+ flex: 1;
+ text-align: left;
+ position: relative;
+ padding-top: 30px;
+
+ &__number {
+ .number-circle();
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+
+ h4 {
+ font-weight: 600;
+ margin-bottom: 10px;
+ }
+ }
+}
+
+.promo-images {
+ display: flex;
+ gap: 20px;
+ margin-top: 50px;
+
+ .promo-image-col {
+ position: relative;
+ overflow: hidden;
+ border-radius: 8px;
+ flex: 1;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: @shadow-light;
+ .image-overlay-text { background-color: rgba(0, 0, 0, 0.6); }
+ img { transform: scale(1.05); }
+ .image-overlay-text h4,
+ .image-overlay-text .overlay-link { transform: translateY(0); }
+ }
+
+ img {
+ width: 100%;
+ height: 350px;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.5s ease;
+ }
+
+ .image-overlay-text {
+ .image-overlay();
+ h4 {
+ font-size: 24px;
+ text-transform: uppercase;
+ line-height: 1.2;
+ margin-bottom: 15px;
+ transform: translateY(20px);
+ transition: transform 0.3s ease;
+ }
+ }
+
+ .overlay-link {
+ display: inline-block;
+ text-transform: uppercase;
+ font-weight: bold;
+ border-radius: 3px;
+ margin-top: 15px;
+ padding: 10px 25px;
+ background-color: @color-button;
+ color: @color-text-light;
+ font-size: 12px;
+ transform: translateY(20px);
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-button, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+ }
+}
+
+.about {
+ padding: 40px 0 80px;
+
+ &__content {
+ display: flex;
+ align-items: flex-start;
+ gap: 50px;
+ }
+
+ &__column {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ &--left { flex: 0 0 40%; margin-bottom: 30px; }
+ &--right {
+ flex: 0 0 60%;
+ .about__caption {
+ padding-right: 50px;
+ }
+ }
+ }
+
+ &__text-block {
+ margin-bottom: 30px;
+ h2 { margin-bottom: 15px; }
+ }
+
+ &__img {
+ width: 93%;
+ object-fit: cover;
+ display: block;
+ &--small { height: 300px; }
+ &--large { height: 450px; }
+ }
+
+ .text-justified {
+ text-align: justify;
+ color: #555;
+ }
+}
+
+.solutions {
+ padding: 0;
+ background-color: @color-secondary;
+
+ &-slider {
+ position: relative;
+ width: 100%;
+ max-width: 1200px;
+ margin: 40px auto;
+ border-radius: 8px;
+ overflow: hidden;
+
+ &__slides {
+ display: flex;
+ width: 200%;
+ height: 100%;
+ animation: slideLeftRight 10s infinite ease-in-out;
+ }
+
+ &__slide {
+ width: 50%;
+ flex-shrink: 0;
+ position: relative;
+ overflow: hidden;
+ transition: transform 0.5s ease, box-shadow 0.5s ease;
+
+ &:hover {
+ transform: scale(1.02);
+ box-shadow: 0 10px 25px rgba(0,0,0,0.3);
+ .solution-img {
+ transform: scale(1.05);
+ filter: brightness(0.8);
+ }
+ .solution-text-overlay {
+ opacity: 1;
+ transform: translateY(-5px);
+ }
+ .solution-image-link {
+ transform: translateX(-50%) translateY(-6px);
+ background-color: rgba(255,255,255,0.9);
+ color: @color-text-dark;
+ }
+ }
+ }
+
+ .solution-img {
+ width: 100%;
+ height: auto;
+ object-fit: cover;
+ display: block;
+ }
+
+ .solution-text-overlay {
+ position: absolute;
+ top: 15%;
+ left: 8%;
+ color: #493131;
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.6);
+ z-index: 2;
+ opacity: 0.9;
+ transition: opacity 0.5s ease, transform 0.5s ease;
+ h2 {
+ font-size: 35px;
+ text-transform: uppercase;
+ margin-bottom: 10px;
+ }
+ p {
+ font-size: 25px;
+ text-transform: uppercase;
+ }
+ }
+
+ .solution-image-link {
+ position: absolute;
+ bottom: 40px;
+ left: 50%;
+ transform: translateX(-50%);
+ padding: 12px 30px;
+ border: 2px solid @color-text-light;
+ color: #493131;
+ text-transform: uppercase;
+ font-size: 16px;
+ font-weight: bold;
+ background: transparent;
+ transition: 0.4s ease;
+ z-index: 2;
+ &:hover {
+ background: @color-text-light;
+ color: @color-text-dark;
+ transform: translateX(-50%) translateY(-2px);
+ }
+ }
+ }
+}
+
+@keyframes slideLeftRight {
+ 0%, 40% { transform: translateX(0); }
+ 50%, 90% { transform: translateX(-50%); }
+ 100% { transform: translateX(0); }
+}
+
+.stats {
+ padding: 0;
+ margin-top: 20px;
+
+ .container {
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ &__items {
+ display: flex;
+ gap: 20px;
+ .stat-item {
+ text-align: left;
+ .stat-number {
+ font-size: 36px;
+ font-weight: bold;
+ color: @color-text-dark;
+ margin-bottom: 5px;
+ }
+ .stat-label { color: @color-text-dark; }
+ }
+ }
+}
+
+.faq {
+ padding: 50px 0;
+
+ h2 {
+ text-align: left;
+ font-size: 32px;
+ font-weight: normal;
+ margin-bottom: 40px;
+ }
+
+ &__items {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 40px 60px;
+ margin-bottom: 40px;
+ }
+
+ .faq-item {
+ flex: 0 0 calc(50% - 30px);
+ .flex-center(15px);
+ align-items: flex-start;
+ &__content h4 {
+ font-weight: 600;
+ margin-bottom: 10px;
+ }
+ }
+
+ .btn.primary-btn {
+ display: block;
+ width: 100%;
+ margin: 20px auto 80px;
+ }
+}
+
+// =======================
+// === СТИЛИ КАТАЛОГА ===
+// =======================
+.catalog-main {
+ padding: 30px 0 60px;
+ background-color: lighten(@color-secondary, 5%);
+}
+
+.catalog-wrapper {
+ display: flex;
+ gap: 20px;
+}
+
+.catalog-sidebar {
+ flex: 0 0 250px;
+ background-color: #fff;
+ padding: 20px;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+ height: fit-content;
+}
+
+.filter-group {
+ margin-bottom: 30px;
+}
+
+.filter-title {
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 15px;
+ text-transform: uppercase;
+}
+
+.filter-list li {
+ padding: 5px 0;
+ font-size: 16px;
+ a {
+ color: #555;
+ transition: color 0.2s;
+ &:hover { color: @color-accent; }
+ &.active-category {
+ font-weight: bold;
+ color: @color-primary;
+ }
+ }
+}
+
+.price-range {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ width: 100%;
+
+ .range-slider {
+ width: 100%;
+
+ input[type="range"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 5px;
+ background: @color-primary;
+ border-radius: 5px;
+ outline: none;
+ margin: 0;
+
+ &::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 20px;
+ height: 20px;
+ background: @color-accent;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ background: lighten(@color-accent, 10%);
+ }
+ }
+
+ &::-moz-range-thumb {
+ width: 20px;
+ height: 20px;
+ background: @color-accent;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ background: lighten(@color-accent, 10%);
+ }
+ }
+ }
+ }
+
+ .price-display {
+ font-size: 14px;
+ font-weight: bold;
+ text-align: center;
+ color: @color-text-dark;
+ padding: 10px;
+ background: #f8f8f8;
+ border-radius: 4px;
+ }
+}
+
+.filter-options {
+ list-style: none;
+ li {
+ display: flex;
+ align-items: center;
+ padding: 4px 0;
+ font-size: 14px;
+ }
+ label {
+ margin-left: 10px;
+ cursor: pointer;
+ color: #555;
+ }
+ input[type="checkbox"] {
+ width: 15px;
+ height: 15px;
+ cursor: pointer;
+ accent-color: @color-primary;
+ &:checked + label {
+ font-weight: bold;
+ color: @color-primary;
+ }
+ }
+}
+
+.filter-apply-btn {
+ width: 100%;
+ margin-top: 20px;
+}
+
+.catalog-products {
+ flex-grow: 1;
+}
+
+.products-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+}
+
+.product-card {
+ background-color: #fff;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ transition: transform 0.3s ease;
+ box-sizing: border-box;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+ .product-img { transform: scale(1.05); }
+ }
+}
+
+.product-image-container {
+ position: relative;
+ overflow: hidden;
+ margin-bottom: 0;
+ padding: 0;
+ height: 250px;
+ .flex-center();
+}
+
+.product-img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+}
+
+.product-img1 {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+}
+
+.product-discount {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ background-color: @color-button;
+ color: @color-text-light;
+ padding: 3px 8px;
+ font-size: 12px;
+ font-weight: bold;
+ z-index: 10;
+}
+
+.product-wishlist-icon {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ color: #333;
+ font-size: 18px;
+ cursor: pointer;
+ transition: color 0.3s ease;
+ z-index: 10;
+ &:hover { color: @color-accent; }
+}
+
+.product-name {
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 5px;
+}
+
+.product-details {
+ font-size: 13px;
+ color: #777;
+ margin-bottom: 10px;
+ flex-grow: 1;
+}
+
+.product-price {
+ font-size: 18px;
+ font-weight: bold;
+ color: @color-button;
+}
+
+.product-card.small { flex: 0 0 300px; max-width: 300px; height: 200px; }
+.product-card.small1 { flex: 0 0 320px; max-width: 320px; height: 250px;width: 320px; }
+.product-card.large { flex: 0 0 580px; max-width: 580px; height: 380px; }
+.product-card.wide { flex: 0 0 240px; max-width: 240px; height: 250px; }
+.product-card.wide1 { flex: 0 0 350px; max-width: 350px; height: 250px; }
+.product-card.wide2 { flex: 0 0 560px; max-width: 560px; height: 260px; }
+.product-card.wide2_1 { flex: 0 0 560px; max-width: 560px; height: 260px; margin: -280px 0 0; }
+.product-card.wide3 {
+ flex: 0 0 320px; max-width: 320px; height: 540px;
+ .product-image-container { height: 580px; }
+}
+.product-card.wide4 {
+ flex: 0 0 545px; max-width: 545px; margin: -270px 0 0; height: 250px;
+ .product-image-container { padding: 0; justify-content: flex-start; }
+ .product-img { margin-left: 0; align-self: flex-start; object-position: left center; }
+}
+.product-card.tall { flex: 0 0 300px; max-width: 300px; margin: -180px 0 0; height: 430px; }
+.product-card.full-width { flex: 0 0 100%; margin: -20px 0 0; max-width: 900px; height: 300px;}
+
+.product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 300px;
+
+ .product-image-container {
+ height: 100%;
+ padding: 0;
+ margin: 0;
+
+ .product-img1 {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ margin: 0;
+ padding: 0;
+ }
+ }
+}
+
+.product-card.tall .product-image-container,
+.product-card.large .product-image-container { height: 430px; }
+
+// =======================
+// === СТРАНИЦА ТОВАРА ===
+// =======================
+.product__section {
+ display: flex;
+ gap: 0;
+ margin: 30px 0;
+}
+
+.product__gallery, .product__info {
+ flex: 1;
+}
+
+.product__main-image {
+ margin-bottom: 15px;
+}
+
+.product__image {
+ width: 500px;
+ height: 300px;
+ border-radius: 4px;
+}
+
+.product__thumbnails {
+ display: flex;
+ gap: 10px;
+}
+
+.product__thumbnail {
+ border: none;
+ background: none;
+ cursor: pointer;
+ padding: 0;
+}
+
+.product__thumbnail img {
+ width: 245px;
+ height: 150px;
+ object-fit: cover;
+ border-radius: 4px;
+}
+
+.product__title {
+ font-size: 30px;
+ margin-bottom: 35px;
+}
+
+.product__rating {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 30px;
+}
+
+.product__color-selector {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 40px;
+}
+
+.product__color-option {
+ width: 45px;
+ height: 45px;
+ border-radius: 50%;
+ border: 2px solid transparent;
+ cursor: pointer;
+ transition: transform 0.3s ease;
+
+ &:hover{
+ transform: translateY(-2px);
+ }
+}
+
+.product__color-option.active {
+ border-color: @color-primary;
+}
+
+.product__description {
+ margin-bottom: 65px;
+ line-height: 1.5;
+}
+
+.product__details-link {
+ display: inline-block;
+ margin-bottom: 20px;
+ color: @color-primary;
+ font-weight: bold;
+}
+
+.product__purchase {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 35px;
+}
+
+.product__price {
+ font-size: 24px;
+ font-weight: bold;
+}
+
+.product__quantity {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.product__qty-btn {
+ width: 30px;
+ height: 30px;
+ background: @color-button;
+ color: @color-text-light;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ font-weight: bold;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background: lighten(@color-button, 10%);
+ transform: scale(1.1);
+ }
+}
+
+.product__qty-value {
+ font-weight: bold;
+ min-width: 30px;
+ text-align: center;
+}
+
+.product__actions {
+ display: flex;
+ gap: 15px;
+}
+
+.product__btn {
+ flex: 1;
+ padding: 12px 20px;
+ border: none;
+ border-radius: 4px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+}
+
+.product__btn.primary {
+ background: @color-button;
+ color: @color-text-light;
+
+ &:hover {
+ background: lighten(@color-button, 10%);
+ }
+}
+
+.product__btn.secondary {
+ background: transparent;
+ border: 1px solid @color-button;
+ color: @color-button;
+
+ &:hover {
+ background: @color-button;
+ color: @color-text-light;
+ }
+}
+
+.similar {
+ margin: 60px 0;
+}
+
+.similar__title {
+ margin-bottom: 30px;
+ font-size: 28px;
+ font-weight: bold;
+}
+
+.similar__grid {
+ display: flex;
+ gap: 25px;
+ flex-wrap: wrap;
+ justify-content: space-between;
+}
+
+.similar__card {
+ flex: 0 0 calc(33.333% - 17px);
+ min-width: 320px;
+ background: @color-secondary;
+ border-radius: 12px;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+
+ &:hover {
+ transform: translateY(-8px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+ }
+}
+
+.similar__card-image {
+ height: 300px;
+ overflow: hidden;
+ background: white;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ transition: transform 0.3s ease;
+
+ &:hover {
+ transform: scale(1.05);
+ }
+ }
+}
+
+.similar__card-content {
+ padding: 25px;
+}
+
+.similar__card-title {
+ font-weight: bold;
+ margin-bottom: 10px;
+ font-size: 20px;
+ color: @color-text-dark;
+}
+
+.similar__card-description {
+ font-size: 15px;
+ margin-bottom: 15px;
+ color: #666;
+ line-height: 1.5;
+}
+
+.similar__card-price {
+ font-weight: bold;
+ font-size: 22px;
+ color: @color-button;
+}
+
+@media (max-width: 1024px) {
+ .similar {
+ &__card {
+ flex: 0 0 calc(50% - 13px);
+ min-width: 280px;
+ }
+ }
+}
+
+@media (max-width: 768px) {
+ .similar {
+ &__grid {
+ justify-content: center;
+ }
+
+ &__card {
+ flex: 0 0 100%;
+ max-width: 400px;
+ }
+ }
+}
+
+// =======================
+// === КОРЗИНА И ЗАКАЗ ===
+// =======================
+.main__content {
+ display: flex;
+ gap: 40px;
+ margin: 30px 0;
+
+ .products {
+ flex: 1;
+ }
+
+ .order {
+ flex: 0 0 65%;
+ padding: 40px;
+
+ &__header {
+ .flex-between();
+ margin-bottom: 20px;
+ }
+
+ &__title {
+ font-family: @font-logo;
+ font-size: 28px;
+ color: @color-text-dark;
+ margin: 0;
+ }
+
+ &__total {
+ font-weight: bold;
+ color: @color-text-dark;
+ }
+
+ &__section {
+ margin-bottom: 25px;
+ }
+
+ &__section-title {
+ font-family: @font-logo;
+ margin-bottom: 15px;
+ font-size: 18px;
+ color: @color-text-dark;
+ }
+ }
+}
+
+.products {
+ &__title {
+ font-family: @font-logo;
+ margin-bottom: 20px;
+ font-size: 24px;
+ color: @color-text-dark;
+ }
+
+ &__list {
+ .flex-column();
+ gap: 20px;
+ }
+
+ &__item {
+ background-color: @color-secondary;
+ border-radius: 8px;
+ padding: 20px;
+ display: flex;
+ gap: 15px;
+ border: 1px solid @color-secondary;
+ transition: transform 0.3s ease;
+ align-items: flex-start;
+ position: relative;
+
+ &:hover {
+ transform: translateY(-2px);
+ }
+ }
+
+ &__image {
+ width: 300px;
+ height: 200px;
+ border-radius: 4px;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ }
+
+ .product-img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+ }
+
+ &__details {
+ flex: 1;
+ .flex-column();
+ justify-content: space-between;
+ align-items: flex-start;
+ min-height: 200px;
+ }
+
+ &__name {
+ font-weight: bold;
+ margin-bottom: 5px;
+ color: @color-accent;
+ font-size: 18px;
+ font-family: @font-main;
+ }
+
+ &__price {
+ font-weight: bold;
+ font-size: 18px;
+ margin-bottom: 15px;
+ color: @color-text-dark;
+ }
+
+ &__controls {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin-top: auto;
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ &__quantity {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ &__qty-btn {
+ width: 30px;
+ height: 30px;
+ background-color: @color-text-dark;
+ color: @color-text-light;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ .flex-center();
+ font-family: @font-main;
+ font-weight: bold;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+ }
+
+ &__qty-value {
+ font-weight: bold;
+ min-width: 30px;
+ text-align: center;
+ font-size: 16px;
+ }
+
+ &__cart-icon {
+ background-color: transparent;
+ color: @color-text-dark;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ border: 2px solid @color-text-dark;
+ margin-left: 20px;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+
+ i { font-size: 18px; }
+ }
+}
+
+.form {
+ &__group { margin-bottom: 15px; }
+ &__label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: bold;
+ color: #000000;
+ }
+ &__input {
+ width: 100%;
+ padding: 14px 16px;
+ border: 2px solid #ccc;
+ font-family: @font-main;
+ font-size: 15px;
+ transition: border-color 0.3s ease;
+
+ &:focus {
+ border-color: @color-primary;
+ }
+
+ &:hover {
+ border-color: darken(#ccc, 10%);
+ }
+ &::placeholder {
+ font-style: italic;
+ color: #999;
+ }
+ }
+ &__row {
+ display: flex;
+ gap: 20px;
+ justify-content: space-between;
+ }
+ &__input--half {
+ width: 100%;
+ }
+ &__radio-group {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ margin-top: 20px;
+ }
+ &__radio-label {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ color: @color-text-dark;
+ position: relative;
+ padding-left: 30px;
+ flex: 1;
+
+ &:hover {
+ .form__custom-radio {
+ border-color: lighten(@color-accent, 10%);
+ }
+ }
+ }
+ &__radio-input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+ }
+ &__custom-radio {
+ position: absolute;
+ left: 0;
+ height: 20px;
+ width: 20px;
+ background-color: @color-secondary;
+ border: 2px solid @color-accent;
+ border-radius: 50%;
+ transition: border-color 0.3s ease;
+ }
+ &__radio-input:checked ~ &__custom-radio {
+ background-color: @color-accent;
+
+ &:after {
+ content: "";
+ position: absolute;
+ display: block;
+ top: 4px;
+ left: 4px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: white;
+ }
+ }
+}
+
+.divider {
+ height: 1px;
+ background-color: #999;
+ margin: 20px 0;
+}
+
+.promo {
+ display: flex;
+ margin-bottom: 20px;
+
+ &__input {
+ flex: 1;
+ padding: 10px;
+ border: 1px solid #000;
+ background-color: @color-secondary;
+ font-family: @font-main;
+ height: auto;
+ min-height: 48px;
+
+ &:hover {
+ border-color: @color-primary;
+ }
+
+ &::placeholder {
+ font-style: italic;
+ color: #999;
+ }
+ }
+
+ &__btn {
+ background-color: @color-accent;
+ color: @color-secondary;
+ border: none;
+ padding: 10px 60px;
+ cursor: pointer;
+ font-family: @font-main;
+ font-size: 18px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-accent, 10%);
+ transform: translateY(-2px);
+ }
+ }
+}
+
+.summary {
+ margin-bottom: 20px;
+
+ &__item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ color: @color-text-dark;
+
+ &.total {
+ font-weight: bold;
+ font-size: 18px;
+ padding-top: 10px;
+ margin-top: 10px;
+ }
+ }
+}
+
+.order-btn {
+ width: 100%;
+ background-color: @color-accent;
+ color: @color-secondary;
+ border: none;
+ padding: 15px;
+ border-radius: 4px;
+ font-size: 18px;
+ cursor: pointer;
+ margin-bottom: 10px;
+ font-family: @font-main;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-accent, 10%);
+ transform: translateY(-2px);
+ }
+}
+
+.privacy {
+ display: flex;
+ gap: 8px;
+ font-size: 16px;
+ color: #666;
+ margin-bottom: 20px;
+
+ input[type="checkbox"] {
+ width: 18px;
+ height: 18px;
+ cursor: pointer;
+ }
+}
+
+.services {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 24px;
+ margin-bottom: 24px;
+
+ &__title {
+ font-family: @font-logo;
+ margin-bottom: 10px;
+ font-size: 18px;
+ color: @color-text-dark;
+ display: block;
+ width: 100%;
+ }
+
+ &__item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 8px;
+ color: @color-text-dark;
+ width: 100%;
+ }
+}
+
+.cart-icon {
+ position: relative;
+}
+
+.cart-count {
+ position: absolute;
+ top: -8px;
+ right: -8px;
+ background: @color-accent;
+ color: @color-text-light;
+ border-radius: 50%;
+ width: 18px;
+ height: 18px;
+ font-size: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.form__input.error {
+ border-color: #ff4444;
+ box-shadow: 0 0 5px rgba(255, 68, 68, 0.3);
+}
+
+.empty-cart {
+ text-align: center;
+ padding: 40px;
+ color: #666;
+ font-size: 18px;
+}
+
+// =======================
+// === АВТОРИЗАЦИЯ ===
+// =======================
+.profile-page-main {
+ .flex-center();
+ min-height: 80vh;
+ padding: 40px 0;
+ background-color: lighten(@color-secondary, 5%);
+ z-index: 1;
+
+ .profile-container {
+ display: flex;
+ width: 100%;
+ max-width: 1000px;
+ min-height: 600px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+ background-color: @color-text-light;
+ }
+
+ .profile-left-col {
+ flex: 0 0 35%;
+ background-color: @color-primary;
+ color: @color-text-light;
+ display: flex;
+ justify-content: flex-start;
+ align-items: flex-start;
+ padding: 40px;
+ .logo {
+ font-size: 32px;
+ font-weight: normal;
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
+ color: @color-text-light;
+ }
+ }
+
+ .profile-right-col {
+ flex: 0 0 65%;
+ .flex-center();
+ padding: 40px;
+ .profile-form-block {
+ width: 100%;
+ max-width: 400px;
+ h2 {
+ font-size: 28px;
+ font-weight: normal;
+ margin-bottom: 40px;
+ text-align: left;
+ color: @color-text-dark;
+ }
+ }
+ }
+
+ .profile-form {
+ .input-group {
+ margin-bottom: 20px;
+ label {
+ display: block;
+ font-size: 12px;
+ font-weight: bold;
+ color: @color-text-dark;
+ margin-bottom: 5px;
+ text-transform: uppercase;
+ }
+ }
+
+ input[type="text"],
+ input[type="email"],
+ input[type="tel"] {
+ .input-base();
+ }
+
+ .password-link {
+ display: block;
+ text-align: left;
+ font-size: 13px;
+ color: @color-text-dark;
+ text-decoration: underline;
+ margin: 10px 0 20px;
+ &:hover {
+ color: @color-accent;
+ text-decoration: none;
+ }
+ }
+
+ .save-btn {
+ padding: 15px 30px;
+ border: none;
+ cursor: pointer;
+ font-size: 15px;
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+ font-family: @font-main;
+ width: 100%;
+ margin-top: 20px;
+ background-color: @color-primary;
+ color: @color-text-light;
+
+ &:hover {
+ background-color: lighten(@color-primary, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+
+ .auth-actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 25px;
+ padding-top: 20px;
+ border-top: 1px solid #eee;
+
+ .auth-text {
+ font-size: 13px;
+ color: @color-text-dark;
+ }
+
+ .login-btn {
+ background-color: transparent;
+ color: @color-accent;
+ border: 1px solid @color-accent;
+ padding: 10px 25px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: @color-primary;
+ color: @color-text-light;
+ }
+ }
+ }
+ }
+}
+
+// =======================
+// === СЕКЦИЯ УСЛУГ ===
+// =======================
+.services-section {
+ padding: 60px 0;
+ background-color: @color-secondary;
+}
+
+.services__wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: 30px;
+}
+
+.services__top-row {
+ display: flex;
+ gap: 30px;
+ justify-content: center;
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ align-items: center;
+ }
+}
+
+.service-card {
+ border-radius: 8px;
+ padding: 40px;
+ min-height: 200px;
+ text-align: center;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: @shadow-light;
+ }
+
+ &--green {
+ background: @color-primary;
+ color: @color-text-light;
+ flex: 1;
+ max-width: 450px;
+ }
+
+ &--beige {
+ background: @color-beige;
+ color: @color-text-light;
+ width: 100%;
+ max-width: 930px;
+ margin: 0 auto;
+ }
+
+ &__title {
+ font-family: @font-logo;
+ font-size: 24px;
+ font-weight: bold;
+ margin-bottom: 15px;
+ text-transform: uppercase;
+ }
+
+ &__text {
+ font-family: @font-main;
+ font-size: 16px;
+ line-height: 1.6;
+ margin: 0;
+ }
+}
+
+// =======================
+// === ФУТЕР ===
+// =======================
+.footer {
+ background-color: @color-primary;
+ color: black;
+ padding: 40px 0 10px;
+ position: relative;
+ z-index: 1000;
+
+ &::before {
+ content: '';
+ display: block;
+ position: absolute;
+ top: -80px;
+ left: 0;
+ width: 100%;
+ height: 1px;
+ visibility: hidden;
+ }
+
+ &__content {
+ display: flex;
+ gap: 20px;
+ padding-bottom: 30px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+ }
+
+ &__col {
+ flex: 1;
+ &--logo { flex: 1.5; }
+ h5 {
+ margin-bottom: 15px;
+ font-size: 14px;
+ text-transform: uppercase;
+ }
+ ul li {
+ margin-bottom: 8px;
+ a:hover { text-decoration: underline; }
+ }
+ .social-icons,
+ .payment-icons {
+ .flex-center(15px);
+ justify-content: flex-start;
+ margin-top: 10px;
+ }
+ .social-icons .icon {
+ .icon-base(20px, 1.1);
+ color: black;
+ &:hover { color: @color-accent; }
+ }
+ .payment-icons .pay-icon {
+ .icon-base(24px, 1.05);
+ color: black;
+ }
+ }
+
+ .copyright {
+ text-align: center;
+ font-size: 12px;
+ padding-top: 20px;
+ color: rgba(255, 255, 255, 0.6);
+ }
+}
+
+// =======================
+// === ДОСТАВКА ===
+// =======================
+.delivery-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 40px 20px;
+}
+
+.delivery-content h1 {
+ font-family: @font-logo;
+ font-size: 42px;
+ text-align: center;
+ margin-bottom: 50px;
+ color: #453227;
+}
+
+.delivery-section {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 30px;
+ margin-bottom: 60px;
+}
+
+.delivery-card {
+ background: white;
+ padding: 30px;
+ border-radius: 12px;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ text-align: center;
+ transition: transform 0.3s ease;
+ flex: 1;
+ min-width: 350px;
+ max-width: 400px;
+}
+
+.delivery-card:hover {
+ transform: translateY(-5px);
+}
+
+.delivery-icon {
+ font-size: 48px;
+ color: #617365;
+ margin-bottom: 20px;
+}
+
+.delivery-card h3 {
+ font-family: @font-logo;
+ font-size: 24px;
+ margin-bottom: 20px;
+ color: #453227;
+}
+
+.delivery-details {
+ text-align: left;
+}
+
+.detail-item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.detail-label {
+ font-weight: bold;
+ color: #333;
+}
+
+.detail-value {
+ color: #617365;
+ text-align: right;
+}
+
+// =======================
+// === ГАРАНТИЯ ===
+// =======================
+.warranty-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 40px 20px;
+}
+
+.warranty-content h1 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 42px;
+ text-align: center;
+ margin-bottom: 50px;
+ color: #453227;
+}
+
+.warranty-overview {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 25px;
+ margin-bottom: 60px;
+}
+
+.warranty-card {
+ background: white;
+ padding: 30px;
+ border-radius: 12px;
+ text-align: center;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ transition: transform 0.3s ease;
+ flex: 1;
+ min-width: 250px;
+ max-width: 280px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.warranty-card:hover {
+ transform: translateY(-5px);
+}
+
+.warranty-icon {
+ font-size: 48px;
+ color: #617365;
+ margin-bottom: 20px;
+}
+
+.warranty-card h3 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 20px;
+ margin-bottom: 15px;
+ color: #453227;
+}
+
+.warranty-period {
+ font-size: 24px;
+ font-weight: bold;
+ color: #617365;
+ margin-top: auto;
+}
+
+.coverage-section {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 40px;
+ margin-bottom: 60px;
+}
+
+.coverage-covered,
+.coverage-not-covered {
+ flex: 1;
+ min-width: 300px;
+}
+
+.coverage-section h2 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 24px;
+ margin-bottom: 25px;
+ color: #453227;
+}
+
+.coverage-list {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.coverage-item {
+ display: flex;
+ align-items: flex-start;
+ gap: 15px;
+ padding: 20px;
+ border-radius: 8px;
+ background: white;
+ box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+}
+
+.coverage-item.covered i {
+ color: #28a745;
+ font-size: 20px;
+ margin-top: 2px;
+ flex-shrink: 0;
+}
+
+.coverage-item.not-covered i {
+ color: #dc3545;
+ font-size: 20px;
+ margin-top: 2px;
+ flex-shrink: 0;
+}
+
+.coverage-text {
+ flex: 1;
+}
+
+.coverage-item h4 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 16px;
+ margin-bottom: 5px;
+ color: #333;
+}
+
+.card {
+ min-height: 250px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: @color-text-light;
+ text-align: center;
+
+ &--green {
+ background: @color-primary;
+ flex: 0 1 450px;
+ max-width: 450px;
+ }
+
+ &--beige {
+ background: @color-beige;
+ color: @color-text-dark;
+ flex: 0 1 925px;
+ max-width: 925px;
+ }
+}
+
+.design-section {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+ .card { width: 100%; }
+}
+
+// =======================
+// === АДАПТИВНОСТЬ ===
+// =======================
+@media (max-width: 1240px) {
+ .catalog-wrapper { gap: 20px; }
+ .catalog-sidebar { flex: 0 0 200px; }
+ .products-container {
+ gap: 15px;
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .product-card.small1 {
+ margin-top: 100px;
+ }
+
+ .product-card.small,
+ .product-card.small1,
+ .product-card.large,
+ .product-card.wide,
+ .product-card.wide1,
+ .product-card.wide2,
+ .product-card.wide2_1,
+ .product-card.wide4 {
+ flex: 0 0 calc(33.333% - 10px);
+ max-width: calc(33.333% - 10px);
+ height: 180px;
+ margin: 0;
+
+ .product-image-container {
+ height: 180px;
+ }
+ }
+
+ .product-card.wide3 {
+ flex: 0 0 calc(25% - 10px);
+ max-width: calc(25% - 10px);
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 350px;
+ }
+ }
+
+ .product-card.tall {
+ flex: 0 0 calc(25% - 10px);
+ max-width: calc(25% - 10px);
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 300px;
+ }
+ }
+
+ .product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 300px;
+ }
+ }
+
+ .product-card.small { order: 1; }
+ .product-card.large { order: 2; }
+ .product-card.wide { order: 3; }
+
+ .product-card.small1 { order: 11; }
+ .product-card.wide2 { order: 12; }
+ .product-card.wide2_1 { order: 13; }
+
+ .product-card.wide3 { order: 21; }
+ .product-card.tall { order: 22; }
+
+ .product-card.wide3 { order: 31; }
+
+ .product-card.full-width { order: 41; flex-basis: 100%; }
+
+ .main__content {
+ gap: 20px;
+ .products {
+ flex: 0 0 35%;
+ .products__image {
+ width: 250px;
+ height: 180px;
+ }
+ }
+ .order {
+ flex: 0 0 60%;
+ padding: 30px;
+
+ .order__title {
+ font-size: 24px;
+ }
+
+ .order__section-title {
+ font-size: 16px;
+ }
+ }
+ }
+
+ .solutions-slider {
+ &__slide {
+ .solution-text-overlay {
+ top: 10%;
+ left: 5%;
+ h2 {
+ font-size: 26px;
+ margin-bottom: 5px;
+ line-height: 1.2;
+ }
+ p {
+ font-size: 18px;
+ line-height: 1.2;
+ }
+ }
+ .solution-image-link {
+ bottom: 70px;
+ padding: 10px 25px;
+ font-size: 14px;
+ }
+ }
+ }
+
+ .product__image {
+ width: 350px;
+ height: 250px;
+ }
+
+ .product__thumbnail img {
+ width: 170px;
+ height: 120px;
+ }
+}
+
+@media (max-width: 1024px) {
+ .main__content {
+ gap: 25px;
+ .products {
+ flex: 0 0 30%;
+ .products__image {
+ width: 200px;
+ height: 150px;
+ }
+
+ .products__name {
+ font-size: 16px;
+ }
+
+ .products__price {
+ font-size: 16px;
+ }
+ }
+ .order {
+ flex: 0 0 60%;
+ padding: 25px;
+
+ .order__title {
+ font-size: 22px;
+ }
+
+ .form__input {
+ padding: 12px 14px;
+ font-size: 14px;
+ }
+
+ .promo__btn {
+ padding: 10px 40px;
+ font-size: 16px;
+ }
+ }
+ }
+}
+
+@media (max-width: 768px) {
+ .container { padding: 0 15px; }
+
+ .delivery-section {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .delivery-card {
+ min-width: 100%;
+ max-width: 100%;
+ }
+
+ .delivery-content h1 {
+ font-size: 32px;
+ }
+
+ .warranty-overview {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .warranty-card {
+ max-width: 100%;
+ width: 100%;
+ }
+
+ .coverage-section {
+ flex-direction: column;
+ }
+
+ .warranty-content h1 {
+ font-size: 32px;
+ }
+
+ .header__top .container,
+ .header__bottom .container,
+ .hero__content,
+ .advantages__header,
+ .about__content,
+ .advantages__items,
+ .promo-images,
+ .stats__items,
+ .faq__items,
+ .catalog-wrapper,
+ .main__content {
+ flex-direction: column;
+ gap: 30px;
+ }
+
+ .search-catalog {
+ order: 3;
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .nav-list {
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 15px;
+ }
+
+ .hero {
+ &__image-block {
+ flex: none;
+ max-width: 400px;
+ height: 400px;
+ }
+ &__circle {
+ width: 380px;
+ height: 380px;
+ }
+ &__text-block {
+ flex: none;
+ padding-left: 0;
+ text-align: center;
+ h1 { font-size: 32px; }
+ .hero__usp-text {
+ padding-left: 0;
+ justify-content: center;
+ &::before { display: none; }
+ }
+ .btn.primary-btn { margin-left: 0; }
+ }
+ }
+
+ .advantages__header h2,
+ .faq h2 { font-size: 28px; }
+
+ .faq-item,
+ .stat-item {
+ flex: none;
+ .flex-center();
+ text-align: center;
+ }
+
+ .stats .container { justify-content: center; }
+ .catalog-dropdown__menu { width: 200px; }
+
+ .catalog-sidebar { width: 100%; flex: none; }
+ .products-container { gap: 15px; }
+
+ .product-card.small,
+ .product-card.small1,
+ .product-card.large,
+ .product-card.wide,
+ .product-card.wide1,
+ .product-card.wide2,
+ .product-card.wide2_1,
+ .product-card.wide3,
+ .product-card.wide4,
+ .product-card.tall,
+ .product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 250px;
+ margin: 0;
+
+ .product-image-container {
+ height: 200px;
+ }
+ }
+
+ .main__content {
+ flex-direction: column;
+ gap: 20px;
+
+ .products,
+ .order {
+ flex: 0 0 100%;
+ width: 100%;
+ }
+
+ .products {
+ .products__item {
+ flex-direction: column;
+ text-align: center;
+ gap: 15px;
+ }
+
+ .products__image {
+ width: 100%;
+ height: 200px;
+ justify-content: center;
+ }
+
+ .products__details {
+ min-height: auto;
+ align-items: center;
+ }
+
+ .products__controls {
+ justify-content: center;
+ margin-top: 15px;
+ }
+
+ .products__cart-icon {
+ margin-left: 0;
+ }
+ }
+
+ .order {
+ padding: 20px;
+
+ .order__title {
+ font-size: 20px;
+ text-align: center;
+ }
+
+ .order__total {
+ text-align: center;
+ }
+
+ .form__radio-group {
+ flex-direction: column;
+ gap: 15px;
+ }
+
+ .form__radio-label {
+ flex: none;
+ justify-content: flex-start;
+ }
+
+ .promo {
+ flex-direction: column;
+ gap: 10px;
+
+ &__btn {
+ width: 100%;
+ padding: 12px;
+ }
+ }
+
+ .order-btn {
+ padding: 12px;
+ font-size: 16px;
+ }
+
+ .services {
+ flex-direction: column;
+ align-items: center;
+ }
+ }
+ }
+
+ .product-image-container { height: 200px; }
+ .product-card.tall .product-image-container,
+ .product-card.large .product-image-container { height: 250px; }
+
+ .profile-page-main {
+ .profile-container {
+ flex-direction: column;
+ min-height: auto;
+ max-width: 100%;
+ box-shadow: none;
+ }
+ .profile-left-col {
+ flex: none;
+ width: 100%;
+ height: 100px;
+ .flex-center();
+ padding: 0;
+ }
+ .profile-right-col {
+ flex: none;
+ width: 100%;
+ padding: 30px 20px;
+ }
+ .profile-form-block { max-width: 100%; }
+ }
+
+ .form__row { flex-direction: column; }
+ .form__input--half { flex: 0 0 100%; max-width: 100%; }
+ .services { flex-direction: column; align-items: center; }
+
+ .services-section {
+ padding: 40px 0;
+ }
+
+ .service-card {
+ padding: 30px 20px;
+ min-height: 180px;
+
+ &--green,
+ &--beige {
+ max-width: 100%;
+ }
+
+ &__title {
+ font-size: 20px;
+ }
+
+ &__text {
+ font-size: 14px;
+ }
+ }
+ .solutions-slider {
+ margin: 20px auto;
+ &__slide {
+ .solution-text-overlay {
+ top: 8%;
+ left: 4%;
+ h2 {
+ font-size: 20px;
+ margin-bottom: 3px;
+ line-height: 1.1;
+ }
+ p {
+ font-size: 15px;
+ line-height: 1.1;
+ }
+ }
+ .solution-image-link {
+ bottom: 90px;
+ padding: 8px 20px;
+ font-size: 13px;
+ }
+ }
+ }
+}
+
+// Стили для ошибок полей
+.error-input {
+ border-color: #ff4444 !important;
+ box-shadow: 0 0 0 1px #ff4444;
+}
+
+.field-error {
+ color: #ff4444;
+ font-size: 12px;
+ margin-top: 5px;
+ margin-bottom: 10px;
+}
+
+// Стили для сообщений
+.message {
+ padding: 15px;
+ margin: 20px 0;
+ border-radius: 5px;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #2e7d32;
+ border: 1px solid #c8e6c9;
+}
+
+// Добавьте в конец файла
+.access-denied {
+ text-align: center;
+ padding: 80px 20px;
+ background: white;
+ border-radius: 10px;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ margin: 50px 0;
+
+ h2 {
+ color: #dc3545;
+ margin-bottom: 30px;
+ font-size: 28px;
+ }
+
+ p {
+ color: #666;
+ margin-bottom: 40px;
+ font-size: 18px;
+ line-height: 1.6;
+ }
+
+ .btn {
+ margin: 5px;
+ min-width: 200px;
+ }
+}
+// =======================
+// === ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ ===
+// =======================
+
+.user-profile-dropdown {
+ position: relative;
+ display: inline-block;
+
+ &__toggle {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ cursor: pointer;
+ padding: 8px 12px;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ }
+
+ .user-avatar {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ background-color: @color-primary;
+ color: @color-text-light;
+ .flex-center();
+ font-weight: bold;
+ }
+
+ .user-info {
+ display: flex;
+ flex-direction: column;
+
+ .user-email {
+ font-size: 12px;
+ color: #666;
+ max-width: 150px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .user-status {
+ font-size: 10px;
+ padding: 2px 6px;
+ border-radius: 10px;
+ text-transform: uppercase;
+
+ &.admin {
+ background-color: #617365;
+ color: white;
+ }
+
+ &.user {
+ background-color: #28a745;
+ color: white;
+ }
+ }
+ }
+ }
+
+ &__menu {
+ .menu-base();
+ width: 220px;
+ top: 100%;
+ right: 0;
+
+ .user-details {
+ padding: 15px;
+ border-bottom: 1px solid #eee;
+
+ .user-name {
+ font-weight: bold;
+ margin-bottom: 5px;
+ }
+
+ .user-registered {
+ font-size: 11px;
+ color: #999;
+ }
+ }
+
+ ul {
+ padding: 10px 0;
+
+ li {
+ padding: 8px 15px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ transition: background-color 0.3s ease;
+
+ &:hover {
+ background-color: #f5f5f5;
+ }
+
+ &.logout {
+ color: #dc3545;
+ border-top: 1px solid #eee;
+ margin-top: 5px;
+ padding-top: 12px;
+
+ &:hover {
+ background-color: #ffe6e6;
+ }
+ }
+ }
+ }
+ }
+
+ &:hover &__menu {
+ display: block;
+ }
+}
+
+// =======================
+// === КАРТОЧКА ТОВАРА ===
+// =======================
+
+.product-image-container {
+ position: relative;
+ overflow: hidden;
+ margin-bottom: 0;
+ padding: 0;
+ height: 250px;
+ .flex-center();
+
+ &:hover {
+ .product-overlay-info {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+}
+
+.product-overlay-info {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
+ color: white;
+ padding: 15px;
+ opacity: 0;
+ transform: translateY(10px);
+ transition: all 0.3s ease;
+
+ .product-overlay-name {
+ font-weight: bold;
+ font-size: 14px;
+ margin-bottom: 5px;
+ }
+
+ .product-overlay-price {
+ font-size: 16px;
+ font-weight: bold;
+
+ .old-price {
+ text-decoration: line-through;
+ font-size: 12px;
+ color: #ccc;
+ margin-right: 5px;
+ }
+
+ .current-price {
+ color: #ffd700;
+ }
+ }
+
+ .product-overlay-category {
+ font-size: 11px;
+ opacity: 0.8;
+ margin-top: 3px;
+ }
+
+ .product-overlay-stock {
+ font-size: 11px;
+ margin-top: 5px;
+
+ &.out-of-stock {
+ color: #ff6b6b;
+ }
+
+ i {
+ margin-right: 5px;
+ }
+ }
+}
+
+.product-card-details {
+ padding: 15px;
+ background: white;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+
+ .product-card-name {
+ font-weight: bold;
+ font-size: 16px;
+ margin-bottom: 8px;
+ color: @color-text-dark;
+ }
+
+ .product-card-description {
+ font-size: 13px;
+ color: #777;
+ margin-bottom: 10px;
+ flex-grow: 1;
+ }
+
+ .product-card-attributes {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-bottom: 10px;
+
+ .attribute {
+ font-size: 11px;
+ background: #f5f5f5;
+ padding: 3px 8px;
+ border-radius: 12px;
+ color: #666;
+
+ i {
+ margin-right: 3px;
+ }
+ }
+ }
+
+ .product-card-price {
+ margin-bottom: 10px;
+
+ .old-price {
+ text-decoration: line-through;
+ font-size: 14px;
+ color: #999;
+ margin-right: 8px;
+ }
+
+ .current-price {
+ font-size: 18px;
+ font-weight: bold;
+ color: @color-button;
+ }
+ }
+
+ .add-to-cart-btn {
+ width: 100%;
+ padding: 8px;
+ font-size: 14px;
+ }
+
+ .admin-actions {
+ display: flex;
+ gap: 5px;
+ margin-top: 10px;
+
+ .admin-btn {
+ flex: 1;
+ font-size: 12px;
+ padding: 6px;
+
+ &.delete-btn {
+ background: #dc3545;
+
+ &:hover {
+ background: #c82333;
+ }
+ }
+ }
+ }
+}
+
+// =======================
+// === ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ ===
+// =======================
+
+.user-profile-dropdown {
+ position: relative;
+ display: inline-block;
+
+ .user-profile-toggle {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+ padding: 8px 12px;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+
+ .dropdown-arrow {
+ transform: rotate(180deg);
+ }
+ }
+
+ .user-avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #617365 0%, #453227 100%);
+ color: @color-text-light;
+ .flex-center();
+ font-weight: bold;
+ font-size: 16px;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
+ }
+
+ .user-info {
+ display: flex;
+ flex-direction: column;
+
+ .user-email {
+ font-size: 12px;
+ color: #666;
+ max-width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .user-status {
+ font-size: 10px;
+ padding: 2px 8px;
+ border-radius: 12px;
+ text-transform: uppercase;
+ font-weight: bold;
+ text-align: center;
+ margin-top: 2px;
+
+ &.admin {
+ background-color: #617365;
+ color: white;
+ border: 1px solid #617365;
+ }
+
+ &.user {
+ background-color: #28a745;
+ color: white;
+ border: 1px solid #28a745;
+ }
+ }
+ }
+
+ .dropdown-arrow {
+ font-size: 10px;
+ color: #666;
+ transition: transform 0.3s ease;
+ }
+ }
+
+ .user-profile-menu {
+ .menu-base();
+ width: 280px;
+ top: 100%;
+ right: 0;
+ margin-top: 10px;
+ padding: 0;
+ overflow: hidden;
+
+ .user-profile-header {
+ padding: 20px;
+ background: linear-gradient(135deg, #617365 0%, #453227 100%);
+ color: white;
+
+ .user-profile-name {
+ font-weight: bold;
+ margin-bottom: 8px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 16px;
+ }
+
+ .user-profile-details {
+ small {
+ display: block;
+ opacity: 0.8;
+ margin-bottom: 5px;
+ font-size: 11px;
+
+ i {
+ margin-right: 5px;
+ width: 14px;
+ text-align: center;
+ }
+ }
+ }
+ }
+
+ .user-profile-links {
+ list-style: none;
+ padding: 10px 0;
+
+ li {
+ border-bottom: 1px solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ a {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 20px;
+ color: #333;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: #f8f9fa;
+ color: @color-primary;
+ text-decoration: none;
+
+ i {
+ transform: scale(1.1);
+ }
+ }
+
+ i {
+ width: 20px;
+ text-align: center;
+ font-size: 14px;
+ color: #617365;
+ transition: transform 0.3s ease;
+ }
+
+ span {
+ flex-grow: 1;
+ }
+ }
+ }
+
+ .logout-item {
+ border-top: 2px solid #f0f0f0;
+ margin-top: 5px;
+
+ a {
+ color: #dc3545;
+
+ &:hover {
+ background-color: #ffe6e6;
+ color: #c82333;
+
+ i {
+ color: #dc3545;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ &:hover .user-profile-menu {
+ display: block;
+ animation: fadeIn 0.3s ease;
+ }
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+// Для мобильных устройств
+@media (max-width: 768px) {
+ .user-profile-dropdown {
+ .user-profile-toggle {
+ .user-info {
+ display: none;
+ }
+
+ .dropdown-arrow {
+ display: none;
+ }
+ }
+
+ .user-profile-menu {
+ width: 250px;
+ right: -50px;
+ }
+ }
+}
+// Добавьте в конец файла
+.unavailable-product {
+ position: relative;
+ opacity: 0.6;
+ filter: grayscale(0.7);
+
+ &::before {
+ content: "ТОВАР ЗАКОНЧИЛСЯ";
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: rgba(0, 0, 0, 0.85);
+ color: white;
+ padding: 15px 25px;
+ border-radius: 5px;
+ font-weight: bold;
+ font-size: 16px;
+ text-align: center;
+ z-index: 100;
+ white-space: nowrap;
+ pointer-events: none;
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
+ }
+
+ .product-name-overlay {
+ .name, .price {
+ color: #999 !important;
+ text-shadow: none !important;
+ }
+ }
+
+ .add-to-cart-btn {
+ display: none !important;
+ }
+
+ &:hover {
+ transform: none !important;
+ cursor: not-allowed;
+ }
+}
+
+.out-of-stock-badge {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ background: #6c757d;
+ color: white;
+ padding: 5px 10px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: bold;
+ z-index: 10;
+}
+
+// Для админ-таблицы
+.admin-table tr.unavailable {
+ background-color: #f8f9fa !important;
+ opacity: 0.7;
+
+ td {
+ color: #999;
+ }
+}
+
+.status-unavailable {
+ background-color: #6c757d !important;
+ color: white !important;
+}
\ No newline at end of file
diff --git a/OLD_CODE/public/catalog.php b/OLD_CODE/public/catalog.php
new file mode 100644
index 0000000..5b13ae1
--- /dev/null
+++ b/OLD_CODE/public/catalog.php
@@ -0,0 +1,1306 @@
+getConnection();
+
+$category_id = $_GET['category'] ?? 0;
+$search = $_GET['search'] ?? '';
+$min_price = $_GET['min_price'] ?? 0;
+$max_price = $_GET['max_price'] ?? 1000000;
+$colors = isset($_GET['colors']) ? (array)$_GET['colors'] : [];
+$materials = isset($_GET['materials']) ? (array)$_GET['materials'] : [];
+$show_all = isset($_GET['show_all']) && $_GET['show_all'] == '1';
+
+$success_message = $_GET['success'] ?? '';
+$error_message = $_GET['error'] ?? '';
+
+try {
+
+ $user_id = $_SESSION['user_id'] ?? 0;
+ $userStmt = $db->prepare("SELECT * FROM users WHERE user_id = ?");
+ $userStmt->execute([$user_id]);
+ $user = $userStmt->fetch();
+
+ $isAdmin = isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] === true;
+ $userEmail = $_SESSION['user_email'] ?? '';
+ $fullName = $_SESSION['full_name'] ?? $userEmail;
+ $loginTime = $_SESSION['login_time'] ?? time();
+
+ try {
+ $categoriesStmt = $db->prepare("
+ SELECT * FROM categories
+ WHERE is_active = TRUE
+ ORDER BY sort_order, name
+ ");
+ $categoriesStmt->execute();
+ $categories = $categoriesStmt->fetchAll();
+ } catch (PDOException $e) {
+ $categories = [];
+ error_log("Ошибка получения категорий: " . $e->getMessage());
+ }
+
+ $subcategories = [];
+ if ($category_id > 0) {
+ $subStmt = $db->prepare("
+ SELECT * FROM subcategories
+ WHERE category_id = ? AND is_active = TRUE
+ ORDER BY sort_order, name
+ ");
+ $subStmt->execute([$category_id]);
+ $subcategories = $subStmt->fetchAll();
+ }
+
+ $checkColumns = $db->query("
+ SELECT column_name
+ FROM information_schema.columns
+ WHERE table_name = 'products'
+ AND column_name IN ('color', 'material')
+ ");
+ $existingColumns = $checkColumns->fetchAll(PDO::FETCH_COLUMN);
+
+ $hasColorColumn = in_array('color', $existingColumns);
+ $hasMaterialColumn = in_array('material', $existingColumns);
+
+ $availableColors = [];
+ if ($hasColorColumn) {
+ $colorsStmt = $db->query("
+ SELECT DISTINCT color FROM products
+ WHERE color IS NOT NULL AND color != '' AND is_available = TRUE
+ ORDER BY color
+ ");
+ $availableColors = $colorsStmt->fetchAll(PDO::FETCH_COLUMN);
+ }
+
+ $availableMaterials = [];
+ if ($hasMaterialColumn) {
+ $materialsStmt = $db->query("
+ SELECT DISTINCT material FROM products
+ WHERE material IS NOT NULL AND material != '' AND is_available = TRUE
+ ORDER BY material
+ ");
+ $availableMaterials = $materialsStmt->fetchAll(PDO::FETCH_COLUMN);
+ }
+
+ $sql = "SELECT p.*, c.name as category_name
+ FROM products p
+ LEFT JOIN categories c ON p.category_id = c.category_id
+ WHERE 1=1";
+
+ $params = [];
+
+ if (!$show_all && !$isAdmin) {
+ $sql .= " AND p.is_available = TRUE";
+ }
+
+ if ($category_id > 0) {
+ $sql .= " AND p.category_id = ?";
+ $params[] = $category_id;
+ }
+
+ if ($min_price > 0 || $max_price < 1000000) {
+ $sql .= " AND p.price BETWEEN ? AND ?";
+ $params[] = $min_price;
+ $params[] = $max_price;
+ }
+
+ if ($hasColorColumn && !empty($colors)) {
+ $placeholders = implode(',', array_fill(0, count($colors), '?'));
+ $sql .= " AND p.color IN ($placeholders)";
+ $params = array_merge($params, $colors);
+ }
+
+ if ($hasMaterialColumn && !empty($materials)) {
+ $placeholders = implode(',', array_fill(0, count($materials), '?'));
+ $sql .= " AND p.material IN ($placeholders)";
+ $params = array_merge($params, $materials);
+ }
+
+ if (!empty($search)) {
+ $sql .= " AND (p.name LIKE ? OR p.description LIKE ?)";
+ $params[] = "%$search%";
+ $params[] = "%$search%";
+ }
+
+ $sql .= " ORDER BY p.product_id ASC LIMIT 50";
+
+ $stmt = $db->prepare($sql);
+ $stmt->execute($params);
+ $filteredProducts = $stmt->fetchAll();
+
+ $originalSizes = [
+ 1 => 'small',
+ 2 => 'large',
+ 3 => 'tall align-right',
+ 4 => 'wide',
+ 5 => 'small1',
+ 6 => 'wide2',
+ 7 => 'wide3',
+ 8 => 'wide2_1',
+ 9 => 'full-width'
+ ];
+
+ $imgClasses = ['small1', 'wide2', 'wide3', 'wide2_1'];
+
+} catch (PDOException $e) {
+ die("Ошибка базы данных: " . $e->getMessage());
+}
+?>
+
+
+
+
+
+ AETERNA - Каталог
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'Категория успешно добавлена!',
+ 'category_updated' => 'Категория успешно обновлена!',
+ 'category_deleted' => 'Категория успешно удалена!',
+ 'product_added' => 'Товар успешно добавлен!',
+ 'product_updated' => 'Товар успешно обновлен!',
+ 'product_deleted' => 'Товар успешно удален!'
+ ];
+ echo $messages[$success_message] ?? 'Операция выполнена успешно!';
+ ?>
+
+
+
+
+
+ Ошибка: = htmlspecialchars($error_message) ?>
+
+
+
+
+
+
+
+ Панель управления каталогом
+
+ Вы вошли как администратор
+
+
+
+
+
+
+
+
+
+ Добро пожаловать, = htmlspecialchars($fullName) ?> !
+
+
+ Администратор
+
+
+
+
+ Показаны все товары
+
+
+
+
+
+
+
+
+
+
+ Каталог мебели
+
+ ( товаров)
+
+
+
+
+
+ Результаты поиска по запросу: "= htmlspecialchars($search) ?> "
+
+ Очистить поиск
+
+
+
+
+
+
+
+
+ Показаны все товары, включая недоступные. Недоступные товары отмечены серым цветом.
+
+
+
+
+
+
+ ['name' => 'Светильник MINNIGHT', 'price' => 7999, 'image' => 'img2/1_2.png', 'size' => 'small'],
+ 2 => ['name' => 'Кровать MODER', 'price' => 45999, 'image' => 'img2/3_3.png', 'size' => 'large'],
+ 3 => ['name' => 'Торшер MARCIA', 'price' => 11999, 'image' => 'img2/2_2.png', 'size' => 'tall align-right'],
+ 4 => ['name' => 'Светильник POLET', 'price' => 5499, 'image' => 'img2/4.jpg', 'size' => 'wide'],
+ 5 => ['name' => 'Стол NORD', 'price' => 23999, 'image' => 'img2/5_5.png', 'size' => 'small1'],
+ 6 => ['name' => 'Диван ROYALTY', 'price' => 78999, 'image' => 'img2/6_6.png', 'size' => 'wide2'],
+ 7 => ['name' => 'Кресло MINIMAL', 'price' => 29999, 'image' => 'img2/7_7.png', 'size' => 'wide3'],
+ 8 => ['name' => 'Стол LONKI', 'price' => 34999, 'image' => 'img2/8_8.png', 'size' => 'wide2_1'],
+ 9 => ['name' => 'Диван HEMMINS', 'price' => 89999, 'image' => 'img2/9_9.png', 'size' => 'full-width']
+ ];
+
+ if (empty($filteredProducts)) {
+ foreach ($originalProducts as $id => $product): ?>
+
+
+
+
+
+
= $product['name'] ?>
+
= number_format($product['price'], 0, '', ' ') ?> ₽
+
+
+
+
+
+
+
+
+
+
+
+
= htmlspecialchars($product['name']) ?>
+
= number_format($product['price'], 0, '', ' ') ?> ₽
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/check_auth.js b/OLD_CODE/public/check_auth.js
similarity index 100%
rename from public/check_auth.js
rename to OLD_CODE/public/check_auth.js
diff --git a/OLD_CODE/public/checkout.php b/OLD_CODE/public/checkout.php
new file mode 100644
index 0000000..25f26c9
--- /dev/null
+++ b/OLD_CODE/public/checkout.php
@@ -0,0 +1,496 @@
+getConnection();
+
+$cart_items = [];
+$total_amount = 0;
+$total_quantity = 0;
+
+try {
+ $stmt = $db->prepare("
+ SELECT
+ c.cart_id,
+ c.product_id,
+ c.quantity,
+ p.name,
+ p.price,
+ p.image_url,
+ p.stock_quantity
+ FROM cart c
+ JOIN products p ON c.product_id = p.product_id
+ WHERE c.user_id = ? AND p.is_available = TRUE
+ ORDER BY c.created_at DESC
+ ");
+ $stmt->execute([$user_id]);
+ $cart_items = $stmt->fetchAll();
+
+ foreach ($cart_items as $item) {
+ $total_amount += $item['price'] * $item['quantity'];
+ $total_quantity += $item['quantity'];
+ }
+
+} catch (PDOException $e) {
+ $error = "Ошибка загрузки корзины: " . $e->getMessage();
+}
+?>
+
+
+
+
+
+ AETERNA - Оформление заказа
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Товары в корзине
+
+
+
+
+
Ваша корзина пуста
+
+
+
+
+
+
+
+
+
+
+
= htmlspecialchars($item['name']) ?>
+
= number_format($item['price'], 0, '', ' ') ?> ₽
+
+
+ -
+ = $item['quantity'] ?>
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ПРИМЕНИТЬ
+
+
+
+
+ Товары, = $total_quantity ?> шт.
+ = number_format($total_amount, 0, '', ' ') ?> ₽
+
+
+ Скидка
+ 0 ₽
+
+
+
+ Доставка
+ 2000 ₽
+
+
+
+ ИТОГО:
+ = number_format($total_amount + 2000, 0, '', ' ') ?> ₽
+
+
+
+ ОФОРМИТЬ ЗАКАЗ
+
+
+
+ Даю согласие на обработку персональных данных
+
+
+ Необходимо согласие на обработку персональных данных
+
+
+
+
УСЛУГИ
+
+ Доставка
+ 2000 ₽
+
+
+ Сборка
+ 1000 ₽
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/config/check_auth.js b/OLD_CODE/public/config/check_auth.js
similarity index 100%
rename from public/config/check_auth.js
rename to OLD_CODE/public/config/check_auth.js
diff --git a/OLD_CODE/public/config/database.php b/OLD_CODE/public/config/database.php
new file mode 100644
index 0000000..7e3062f
--- /dev/null
+++ b/OLD_CODE/public/config/database.php
@@ -0,0 +1,32 @@
+connection = new PDO(
+ "pgsql:host=185.130.224.177;port=5481;dbname=postgres",
+ "admin",
+ "38feaad2840ccfda0e71243a6faaecfd"
+ );
+ $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $this->connection->exec("SET NAMES 'utf8'");
+ } catch(PDOException $e) {
+ die("Ошибка подключения: " . $e->getMessage());
+ }
+ }
+
+ public static function getInstance() {
+ if (self::$instance == null) {
+ self::$instance = new Database();
+ }
+ return self::$instance;
+ }
+
+ public function getConnection() {
+ return $this->connection;
+ }
+}
+?>
\ No newline at end of file
diff --git a/OLD_CODE/public/delivery.php b/OLD_CODE/public/delivery.php
new file mode 100644
index 0000000..13ca5b9
--- /dev/null
+++ b/OLD_CODE/public/delivery.php
@@ -0,0 +1,174 @@
+
+
+
+
+
+ AETERNA - Доставка и оплата
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ДОСТАВКА И ОПЛАТА
+
+
+
+
+
+
+
Курьерская доставка
+
+
+ Бесплатная доставка:
+ при заказе от 30 000 ₽
+
+
+ В пределах МКАД:
+ 1 500 ₽
+
+
+ За МКАД:
+ 1 500 ₽ + 50 ₽/км
+
+
+ Время доставки:
+ с 9:00 до 21:00
+
+
+
+
+
+
+
+
+
Самовывоз из шоурума
+
+
+ Адрес:
+ г. Москва, ул. Дизайнерская, 15
+
+
+ Стоимость:
+ Бесплатно
+
+
+ Время получения:
+ в течение 2 часов после подтверждения
+
+
+ Парковка:
+ Бесплатная для клиентов
+
+
+
+
+
+
+
+
+
Доставка по России
+
+
+ Стоимость:
+ рассчитывается индивидуально
+
+
+ Сроки:
+ от 3 до 14 дней
+
+
+ Транспортные компании:
+ СДЭК, Boxberry, Деловые Линии
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/footer.php b/OLD_CODE/public/footer.php
similarity index 100%
rename from public/footer.php
rename to OLD_CODE/public/footer.php
diff --git a/OLD_CODE/public/header_common.php b/OLD_CODE/public/header_common.php
new file mode 100644
index 0000000..8654ef6
--- /dev/null
+++ b/OLD_CODE/public/header_common.php
@@ -0,0 +1,159 @@
+
+
+
+
+
+
diff --git a/OLD_CODE/public/img/1 — копия.jpg b/OLD_CODE/public/img/1 — копия.jpg
new file mode 100644
index 0000000..68992d6
Binary files /dev/null and b/OLD_CODE/public/img/1 — копия.jpg differ
diff --git a/OLD_CODE/public/img/1.jpg b/OLD_CODE/public/img/1.jpg
new file mode 100644
index 0000000..1df7668
Binary files /dev/null and b/OLD_CODE/public/img/1.jpg differ
diff --git a/OLD_CODE/public/img/100.jpg b/OLD_CODE/public/img/100.jpg
new file mode 100644
index 0000000..646480d
Binary files /dev/null and b/OLD_CODE/public/img/100.jpg differ
diff --git a/OLD_CODE/public/img/11.jpg b/OLD_CODE/public/img/11.jpg
new file mode 100644
index 0000000..3a8270e
Binary files /dev/null and b/OLD_CODE/public/img/11.jpg differ
diff --git a/OLD_CODE/public/img/111.jpg b/OLD_CODE/public/img/111.jpg
new file mode 100644
index 0000000..33dc453
Binary files /dev/null and b/OLD_CODE/public/img/111.jpg differ
diff --git a/OLD_CODE/public/img/11_1.png b/OLD_CODE/public/img/11_1.png
new file mode 100644
index 0000000..4735774
Binary files /dev/null and b/OLD_CODE/public/img/11_1.png differ
diff --git a/OLD_CODE/public/img/1_1.jpg b/OLD_CODE/public/img/1_1.jpg
new file mode 100644
index 0000000..3f9e1a1
Binary files /dev/null and b/OLD_CODE/public/img/1_1.jpg differ
diff --git a/OLD_CODE/public/img/1_2.jpg b/OLD_CODE/public/img/1_2.jpg
new file mode 100644
index 0000000..2d7a54a
Binary files /dev/null and b/OLD_CODE/public/img/1_2.jpg differ
diff --git a/OLD_CODE/public/img/1_2.png b/OLD_CODE/public/img/1_2.png
new file mode 100644
index 0000000..9a8a6c0
Binary files /dev/null and b/OLD_CODE/public/img/1_2.png differ
diff --git a/OLD_CODE/public/img/2.jpg b/OLD_CODE/public/img/2.jpg
new file mode 100644
index 0000000..417df4a
Binary files /dev/null and b/OLD_CODE/public/img/2.jpg differ
diff --git a/OLD_CODE/public/img/22.jpg b/OLD_CODE/public/img/22.jpg
new file mode 100644
index 0000000..f59b320
Binary files /dev/null and b/OLD_CODE/public/img/22.jpg differ
diff --git a/OLD_CODE/public/img/25.jpg b/OLD_CODE/public/img/25.jpg
new file mode 100644
index 0000000..03eddcf
Binary files /dev/null and b/OLD_CODE/public/img/25.jpg differ
diff --git a/OLD_CODE/public/img/2_2.jpg b/OLD_CODE/public/img/2_2.jpg
new file mode 100644
index 0000000..76ba9ba
Binary files /dev/null and b/OLD_CODE/public/img/2_2.jpg differ
diff --git a/OLD_CODE/public/img/2_2.png b/OLD_CODE/public/img/2_2.png
new file mode 100644
index 0000000..8fa6e8c
Binary files /dev/null and b/OLD_CODE/public/img/2_2.png differ
diff --git a/OLD_CODE/public/img/3.jpg b/OLD_CODE/public/img/3.jpg
new file mode 100644
index 0000000..973449d
Binary files /dev/null and b/OLD_CODE/public/img/3.jpg differ
diff --git a/OLD_CODE/public/img/3_3.jpg b/OLD_CODE/public/img/3_3.jpg
new file mode 100644
index 0000000..7e56605
Binary files /dev/null and b/OLD_CODE/public/img/3_3.jpg differ
diff --git a/OLD_CODE/public/img/3_3.png b/OLD_CODE/public/img/3_3.png
new file mode 100644
index 0000000..ba16e91
Binary files /dev/null and b/OLD_CODE/public/img/3_3.png differ
diff --git a/OLD_CODE/public/img/4.jpg b/OLD_CODE/public/img/4.jpg
new file mode 100644
index 0000000..da2945c
Binary files /dev/null and b/OLD_CODE/public/img/4.jpg differ
diff --git a/OLD_CODE/public/img/44.jpg b/OLD_CODE/public/img/44.jpg
new file mode 100644
index 0000000..e38c994
Binary files /dev/null and b/OLD_CODE/public/img/44.jpg differ
diff --git a/OLD_CODE/public/img/444 b/OLD_CODE/public/img/444
new file mode 100644
index 0000000..dc6e3fa
Binary files /dev/null and b/OLD_CODE/public/img/444 differ
diff --git a/OLD_CODE/public/img/444 (1).png b/OLD_CODE/public/img/444 (1).png
new file mode 100644
index 0000000..ddf7e92
Binary files /dev/null and b/OLD_CODE/public/img/444 (1).png differ
diff --git a/OLD_CODE/public/img/444.jpg b/OLD_CODE/public/img/444.jpg
new file mode 100644
index 0000000..dc6e3fa
Binary files /dev/null and b/OLD_CODE/public/img/444.jpg differ
diff --git a/OLD_CODE/public/img/444.png b/OLD_CODE/public/img/444.png
new file mode 100644
index 0000000..cd53804
Binary files /dev/null and b/OLD_CODE/public/img/444.png differ
diff --git a/OLD_CODE/public/img/4_1.jpg b/OLD_CODE/public/img/4_1.jpg
new file mode 100644
index 0000000..69f2236
Binary files /dev/null and b/OLD_CODE/public/img/4_1.jpg differ
diff --git a/OLD_CODE/public/img/5.jpg b/OLD_CODE/public/img/5.jpg
new file mode 100644
index 0000000..456cec1
Binary files /dev/null and b/OLD_CODE/public/img/5.jpg differ
diff --git a/OLD_CODE/public/img/5_5.jpg b/OLD_CODE/public/img/5_5.jpg
new file mode 100644
index 0000000..9ced54f
Binary files /dev/null and b/OLD_CODE/public/img/5_5.jpg differ
diff --git a/OLD_CODE/public/img/5_5.png b/OLD_CODE/public/img/5_5.png
new file mode 100644
index 0000000..369b63b
Binary files /dev/null and b/OLD_CODE/public/img/5_5.png differ
diff --git a/OLD_CODE/public/img/6.jpg b/OLD_CODE/public/img/6.jpg
new file mode 100644
index 0000000..550e17d
Binary files /dev/null and b/OLD_CODE/public/img/6.jpg differ
diff --git a/OLD_CODE/public/img/6_6.jpg b/OLD_CODE/public/img/6_6.jpg
new file mode 100644
index 0000000..0aa5c4b
Binary files /dev/null and b/OLD_CODE/public/img/6_6.jpg differ
diff --git a/OLD_CODE/public/img/6_6.png b/OLD_CODE/public/img/6_6.png
new file mode 100644
index 0000000..af949f9
Binary files /dev/null and b/OLD_CODE/public/img/6_6.png differ
diff --git a/OLD_CODE/public/img/7.jpg b/OLD_CODE/public/img/7.jpg
new file mode 100644
index 0000000..17150c7
Binary files /dev/null and b/OLD_CODE/public/img/7.jpg differ
diff --git a/OLD_CODE/public/img/77.jpg b/OLD_CODE/public/img/77.jpg
new file mode 100644
index 0000000..d9bf304
Binary files /dev/null and b/OLD_CODE/public/img/77.jpg differ
diff --git a/OLD_CODE/public/img/777 (1).png b/OLD_CODE/public/img/777 (1).png
new file mode 100644
index 0000000..6b01d3f
Binary files /dev/null and b/OLD_CODE/public/img/777 (1).png differ
diff --git a/OLD_CODE/public/img/777.jpg b/OLD_CODE/public/img/777.jpg
new file mode 100644
index 0000000..908d164
Binary files /dev/null and b/OLD_CODE/public/img/777.jpg differ
diff --git a/OLD_CODE/public/img/777.png b/OLD_CODE/public/img/777.png
new file mode 100644
index 0000000..41d57c8
Binary files /dev/null and b/OLD_CODE/public/img/777.png differ
diff --git a/OLD_CODE/public/img/7_7.jpg b/OLD_CODE/public/img/7_7.jpg
new file mode 100644
index 0000000..5ee1524
Binary files /dev/null and b/OLD_CODE/public/img/7_7.jpg differ
diff --git a/OLD_CODE/public/img/7_7.png b/OLD_CODE/public/img/7_7.png
new file mode 100644
index 0000000..d50782e
Binary files /dev/null and b/OLD_CODE/public/img/7_7.png differ
diff --git a/OLD_CODE/public/img/8.jpg b/OLD_CODE/public/img/8.jpg
new file mode 100644
index 0000000..8b41c63
Binary files /dev/null and b/OLD_CODE/public/img/8.jpg differ
diff --git a/OLD_CODE/public/img/88.jpg b/OLD_CODE/public/img/88.jpg
new file mode 100644
index 0000000..713eeec
Binary files /dev/null and b/OLD_CODE/public/img/88.jpg differ
diff --git a/OLD_CODE/public/img/888 (1).png b/OLD_CODE/public/img/888 (1).png
new file mode 100644
index 0000000..127e80d
Binary files /dev/null and b/OLD_CODE/public/img/888 (1).png differ
diff --git a/OLD_CODE/public/img/888.jpg b/OLD_CODE/public/img/888.jpg
new file mode 100644
index 0000000..e8f33f7
Binary files /dev/null and b/OLD_CODE/public/img/888.jpg differ
diff --git a/OLD_CODE/public/img/888.png b/OLD_CODE/public/img/888.png
new file mode 100644
index 0000000..35e3403
Binary files /dev/null and b/OLD_CODE/public/img/888.png differ
diff --git a/OLD_CODE/public/img/8_8.png b/OLD_CODE/public/img/8_8.png
new file mode 100644
index 0000000..9f86b2c
Binary files /dev/null and b/OLD_CODE/public/img/8_8.png differ
diff --git a/OLD_CODE/public/img/9.jpg b/OLD_CODE/public/img/9.jpg
new file mode 100644
index 0000000..0b772e3
Binary files /dev/null and b/OLD_CODE/public/img/9.jpg differ
diff --git a/OLD_CODE/public/img/99.jpg b/OLD_CODE/public/img/99.jpg
new file mode 100644
index 0000000..ed309ba
Binary files /dev/null and b/OLD_CODE/public/img/99.jpg differ
diff --git a/OLD_CODE/public/img/99.png b/OLD_CODE/public/img/99.png
new file mode 100644
index 0000000..8fd29b2
Binary files /dev/null and b/OLD_CODE/public/img/99.png differ
diff --git a/OLD_CODE/public/img/99_1.jpg b/OLD_CODE/public/img/99_1.jpg
new file mode 100644
index 0000000..0247358
Binary files /dev/null and b/OLD_CODE/public/img/99_1.jpg differ
diff --git a/OLD_CODE/public/img/99_2.jpg b/OLD_CODE/public/img/99_2.jpg
new file mode 100644
index 0000000..468fd51
Binary files /dev/null and b/OLD_CODE/public/img/99_2.jpg differ
diff --git a/OLD_CODE/public/img/99_3.png b/OLD_CODE/public/img/99_3.png
new file mode 100644
index 0000000..ae2cd8e
Binary files /dev/null and b/OLD_CODE/public/img/99_3.png differ
diff --git a/OLD_CODE/public/img/9_9.jpg b/OLD_CODE/public/img/9_9.jpg
new file mode 100644
index 0000000..a77f2ae
Binary files /dev/null and b/OLD_CODE/public/img/9_9.jpg differ
diff --git a/OLD_CODE/public/img/9_9.png b/OLD_CODE/public/img/9_9.png
new file mode 100644
index 0000000..733a453
Binary files /dev/null and b/OLD_CODE/public/img/9_9.png differ
diff --git a/OLD_CODE/public/img/black.png b/OLD_CODE/public/img/black.png
new file mode 100644
index 0000000..a10af51
Binary files /dev/null and b/OLD_CODE/public/img/black.png differ
diff --git a/OLD_CODE/public/img/black1.png b/OLD_CODE/public/img/black1.png
new file mode 100644
index 0000000..f529bd3
Binary files /dev/null and b/OLD_CODE/public/img/black1.png differ
diff --git a/OLD_CODE/public/img/black2.png b/OLD_CODE/public/img/black2.png
new file mode 100644
index 0000000..75758a2
Binary files /dev/null and b/OLD_CODE/public/img/black2.png differ
diff --git a/OLD_CODE/public/img/brown.png b/OLD_CODE/public/img/brown.png
new file mode 100644
index 0000000..9ef4db4
Binary files /dev/null and b/OLD_CODE/public/img/brown.png differ
diff --git a/OLD_CODE/public/img/brown1.png b/OLD_CODE/public/img/brown1.png
new file mode 100644
index 0000000..0b178f1
Binary files /dev/null and b/OLD_CODE/public/img/brown1.png differ
diff --git a/OLD_CODE/public/img/brown2.png b/OLD_CODE/public/img/brown2.png
new file mode 100644
index 0000000..346b22f
Binary files /dev/null and b/OLD_CODE/public/img/brown2.png differ
diff --git a/OLD_CODE/public/img/chair.PNG b/OLD_CODE/public/img/chair.PNG
new file mode 100644
index 0000000..12af9db
Binary files /dev/null and b/OLD_CODE/public/img/chair.PNG differ
diff --git a/OLD_CODE/public/img/gray.png b/OLD_CODE/public/img/gray.png
new file mode 100644
index 0000000..55ab5bb
Binary files /dev/null and b/OLD_CODE/public/img/gray.png differ
diff --git a/OLD_CODE/public/img/gray1.png b/OLD_CODE/public/img/gray1.png
new file mode 100644
index 0000000..3137e25
Binary files /dev/null and b/OLD_CODE/public/img/gray1.png differ
diff --git a/OLD_CODE/public/img/gray2.png b/OLD_CODE/public/img/gray2.png
new file mode 100644
index 0000000..95b8781
Binary files /dev/null and b/OLD_CODE/public/img/gray2.png differ
diff --git a/OLD_CODE/public/img/диван.jpg b/OLD_CODE/public/img/диван.jpg
new file mode 100644
index 0000000..578d1a3
Binary files /dev/null and b/OLD_CODE/public/img/диван.jpg differ
diff --git a/OLD_CODE/public/img/диван_1.jpg b/OLD_CODE/public/img/диван_1.jpg
new file mode 100644
index 0000000..3618723
Binary files /dev/null and b/OLD_CODE/public/img/диван_1.jpg differ
diff --git a/OLD_CODE/public/img/кресло.jpg b/OLD_CODE/public/img/кресло.jpg
new file mode 100644
index 0000000..6d1c12b
Binary files /dev/null and b/OLD_CODE/public/img/кресло.jpg differ
diff --git a/OLD_CODE/public/img/кресло_1.jpg b/OLD_CODE/public/img/кресло_1.jpg
new file mode 100644
index 0000000..e59b3b1
Binary files /dev/null and b/OLD_CODE/public/img/кресло_1.jpg differ
diff --git a/OLD_CODE/public/img/слайдер_1.jpg b/OLD_CODE/public/img/слайдер_1.jpg
new file mode 100644
index 0000000..255440e
Binary files /dev/null and b/OLD_CODE/public/img/слайдер_1.jpg differ
diff --git a/OLD_CODE/public/img/слайдер_2.jpg b/OLD_CODE/public/img/слайдер_2.jpg
new file mode 100644
index 0000000..9cb6403
Binary files /dev/null and b/OLD_CODE/public/img/слайдер_2.jpg differ
diff --git a/OLD_CODE/public/img/слайдер_3.jpg b/OLD_CODE/public/img/слайдер_3.jpg
new file mode 100644
index 0000000..dc65d0b
Binary files /dev/null and b/OLD_CODE/public/img/слайдер_3.jpg differ
diff --git a/OLD_CODE/public/img/слайдер_4.jpg b/OLD_CODE/public/img/слайдер_4.jpg
new file mode 100644
index 0000000..f6d8d38
Binary files /dev/null and b/OLD_CODE/public/img/слайдер_4.jpg differ
diff --git a/OLD_CODE/public/img/слайдер_5.jpg b/OLD_CODE/public/img/слайдер_5.jpg
new file mode 100644
index 0000000..a9cfbb6
Binary files /dev/null and b/OLD_CODE/public/img/слайдер_5.jpg differ
diff --git a/OLD_CODE/public/img/слайдер_6.jpg b/OLD_CODE/public/img/слайдер_6.jpg
new file mode 100644
index 0000000..0dc28a0
Binary files /dev/null and b/OLD_CODE/public/img/слайдер_6.jpg differ
diff --git a/OLD_CODE/public/img/спальня.jpg b/OLD_CODE/public/img/спальня.jpg
new file mode 100644
index 0000000..f403324
Binary files /dev/null and b/OLD_CODE/public/img/спальня.jpg differ
diff --git a/OLD_CODE/public/img/стили_оформления.css b/OLD_CODE/public/img/стили_оформления.css
new file mode 100644
index 0000000..2e1d09c
--- /dev/null
+++ b/OLD_CODE/public/img/стили_оформления.css
@@ -0,0 +1,61 @@
+
+.error-message {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+}
+
+.form__input.error {
+ border-color: #ff0000;
+}
+
+.form__group {
+ position: relative;
+ margin-bottom: 15px;
+}
+
+.page-messages {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1000;
+ width: 90%;
+ max-width: 500px;
+}
+
+.message {
+ padding: 15px;
+ margin: 10px 0;
+ border-radius: 5px;
+ text-align: center;
+ font-weight: bold;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #453227;
+ border: 1px solid #c8e6c9;
+}
+
+.message.warning {
+ background-color: #fff3e0;
+ color: #ef6c00;
+ border: 1px solid #ffe0b2;
+}
+
+.privacy-error {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+ text-align: center;
+}
diff --git a/OLD_CODE/public/img2/1 — копия.jpg b/OLD_CODE/public/img2/1 — копия.jpg
new file mode 100644
index 0000000..68992d6
Binary files /dev/null and b/OLD_CODE/public/img2/1 — копия.jpg differ
diff --git a/OLD_CODE/public/img2/1.jpg b/OLD_CODE/public/img2/1.jpg
new file mode 100644
index 0000000..1df7668
Binary files /dev/null and b/OLD_CODE/public/img2/1.jpg differ
diff --git a/OLD_CODE/public/img2/100.jpg b/OLD_CODE/public/img2/100.jpg
new file mode 100644
index 0000000..646480d
Binary files /dev/null and b/OLD_CODE/public/img2/100.jpg differ
diff --git a/OLD_CODE/public/img2/11.jpg b/OLD_CODE/public/img2/11.jpg
new file mode 100644
index 0000000..3a8270e
Binary files /dev/null and b/OLD_CODE/public/img2/11.jpg differ
diff --git a/OLD_CODE/public/img2/111.jpg b/OLD_CODE/public/img2/111.jpg
new file mode 100644
index 0000000..33dc453
Binary files /dev/null and b/OLD_CODE/public/img2/111.jpg differ
diff --git a/OLD_CODE/public/img2/11_1.png b/OLD_CODE/public/img2/11_1.png
new file mode 100644
index 0000000..4735774
Binary files /dev/null and b/OLD_CODE/public/img2/11_1.png differ
diff --git a/OLD_CODE/public/img2/1_1.jpg b/OLD_CODE/public/img2/1_1.jpg
new file mode 100644
index 0000000..3f9e1a1
Binary files /dev/null and b/OLD_CODE/public/img2/1_1.jpg differ
diff --git a/OLD_CODE/public/img2/1_2.jpg b/OLD_CODE/public/img2/1_2.jpg
new file mode 100644
index 0000000..2d7a54a
Binary files /dev/null and b/OLD_CODE/public/img2/1_2.jpg differ
diff --git a/OLD_CODE/public/img2/1_2.png b/OLD_CODE/public/img2/1_2.png
new file mode 100644
index 0000000..9a8a6c0
Binary files /dev/null and b/OLD_CODE/public/img2/1_2.png differ
diff --git a/OLD_CODE/public/img2/2.jpg b/OLD_CODE/public/img2/2.jpg
new file mode 100644
index 0000000..417df4a
Binary files /dev/null and b/OLD_CODE/public/img2/2.jpg differ
diff --git a/OLD_CODE/public/img2/22.jpg b/OLD_CODE/public/img2/22.jpg
new file mode 100644
index 0000000..f59b320
Binary files /dev/null and b/OLD_CODE/public/img2/22.jpg differ
diff --git a/OLD_CODE/public/img2/25.jpg b/OLD_CODE/public/img2/25.jpg
new file mode 100644
index 0000000..03eddcf
Binary files /dev/null and b/OLD_CODE/public/img2/25.jpg differ
diff --git a/OLD_CODE/public/img2/2_2.jpg b/OLD_CODE/public/img2/2_2.jpg
new file mode 100644
index 0000000..76ba9ba
Binary files /dev/null and b/OLD_CODE/public/img2/2_2.jpg differ
diff --git a/OLD_CODE/public/img2/2_2.png b/OLD_CODE/public/img2/2_2.png
new file mode 100644
index 0000000..8fa6e8c
Binary files /dev/null and b/OLD_CODE/public/img2/2_2.png differ
diff --git a/OLD_CODE/public/img2/3.jpg b/OLD_CODE/public/img2/3.jpg
new file mode 100644
index 0000000..973449d
Binary files /dev/null and b/OLD_CODE/public/img2/3.jpg differ
diff --git a/OLD_CODE/public/img2/3_3.jpg b/OLD_CODE/public/img2/3_3.jpg
new file mode 100644
index 0000000..7e56605
Binary files /dev/null and b/OLD_CODE/public/img2/3_3.jpg differ
diff --git a/OLD_CODE/public/img2/3_3.png b/OLD_CODE/public/img2/3_3.png
new file mode 100644
index 0000000..ba16e91
Binary files /dev/null and b/OLD_CODE/public/img2/3_3.png differ
diff --git a/OLD_CODE/public/img2/4.jpg b/OLD_CODE/public/img2/4.jpg
new file mode 100644
index 0000000..da2945c
Binary files /dev/null and b/OLD_CODE/public/img2/4.jpg differ
diff --git a/OLD_CODE/public/img2/44.jpg b/OLD_CODE/public/img2/44.jpg
new file mode 100644
index 0000000..e38c994
Binary files /dev/null and b/OLD_CODE/public/img2/44.jpg differ
diff --git a/OLD_CODE/public/img2/444 b/OLD_CODE/public/img2/444
new file mode 100644
index 0000000..dc6e3fa
Binary files /dev/null and b/OLD_CODE/public/img2/444 differ
diff --git a/OLD_CODE/public/img2/444 (1).png b/OLD_CODE/public/img2/444 (1).png
new file mode 100644
index 0000000..ddf7e92
Binary files /dev/null and b/OLD_CODE/public/img2/444 (1).png differ
diff --git a/OLD_CODE/public/img2/444.jpg b/OLD_CODE/public/img2/444.jpg
new file mode 100644
index 0000000..dc6e3fa
Binary files /dev/null and b/OLD_CODE/public/img2/444.jpg differ
diff --git a/OLD_CODE/public/img2/444.png b/OLD_CODE/public/img2/444.png
new file mode 100644
index 0000000..cd53804
Binary files /dev/null and b/OLD_CODE/public/img2/444.png differ
diff --git a/OLD_CODE/public/img2/4_1.jpg b/OLD_CODE/public/img2/4_1.jpg
new file mode 100644
index 0000000..69f2236
Binary files /dev/null and b/OLD_CODE/public/img2/4_1.jpg differ
diff --git a/OLD_CODE/public/img2/5.jpg b/OLD_CODE/public/img2/5.jpg
new file mode 100644
index 0000000..456cec1
Binary files /dev/null and b/OLD_CODE/public/img2/5.jpg differ
diff --git a/OLD_CODE/public/img2/5_5.jpg b/OLD_CODE/public/img2/5_5.jpg
new file mode 100644
index 0000000..9ced54f
Binary files /dev/null and b/OLD_CODE/public/img2/5_5.jpg differ
diff --git a/OLD_CODE/public/img2/5_5.png b/OLD_CODE/public/img2/5_5.png
new file mode 100644
index 0000000..369b63b
Binary files /dev/null and b/OLD_CODE/public/img2/5_5.png differ
diff --git a/OLD_CODE/public/img2/6.jpg b/OLD_CODE/public/img2/6.jpg
new file mode 100644
index 0000000..550e17d
Binary files /dev/null and b/OLD_CODE/public/img2/6.jpg differ
diff --git a/OLD_CODE/public/img2/6_6.jpg b/OLD_CODE/public/img2/6_6.jpg
new file mode 100644
index 0000000..0aa5c4b
Binary files /dev/null and b/OLD_CODE/public/img2/6_6.jpg differ
diff --git a/OLD_CODE/public/img2/6_6.png b/OLD_CODE/public/img2/6_6.png
new file mode 100644
index 0000000..af949f9
Binary files /dev/null and b/OLD_CODE/public/img2/6_6.png differ
diff --git a/OLD_CODE/public/img2/7.jpg b/OLD_CODE/public/img2/7.jpg
new file mode 100644
index 0000000..17150c7
Binary files /dev/null and b/OLD_CODE/public/img2/7.jpg differ
diff --git a/OLD_CODE/public/img2/77.jpg b/OLD_CODE/public/img2/77.jpg
new file mode 100644
index 0000000..d9bf304
Binary files /dev/null and b/OLD_CODE/public/img2/77.jpg differ
diff --git a/OLD_CODE/public/img2/777 (1).png b/OLD_CODE/public/img2/777 (1).png
new file mode 100644
index 0000000..6b01d3f
Binary files /dev/null and b/OLD_CODE/public/img2/777 (1).png differ
diff --git a/OLD_CODE/public/img2/777.jpg b/OLD_CODE/public/img2/777.jpg
new file mode 100644
index 0000000..908d164
Binary files /dev/null and b/OLD_CODE/public/img2/777.jpg differ
diff --git a/OLD_CODE/public/img2/777.png b/OLD_CODE/public/img2/777.png
new file mode 100644
index 0000000..41d57c8
Binary files /dev/null and b/OLD_CODE/public/img2/777.png differ
diff --git a/OLD_CODE/public/img2/7_7.jpg b/OLD_CODE/public/img2/7_7.jpg
new file mode 100644
index 0000000..5ee1524
Binary files /dev/null and b/OLD_CODE/public/img2/7_7.jpg differ
diff --git a/OLD_CODE/public/img2/7_7.png b/OLD_CODE/public/img2/7_7.png
new file mode 100644
index 0000000..d50782e
Binary files /dev/null and b/OLD_CODE/public/img2/7_7.png differ
diff --git a/OLD_CODE/public/img2/8.jpg b/OLD_CODE/public/img2/8.jpg
new file mode 100644
index 0000000..8b41c63
Binary files /dev/null and b/OLD_CODE/public/img2/8.jpg differ
diff --git a/OLD_CODE/public/img2/88.jpg b/OLD_CODE/public/img2/88.jpg
new file mode 100644
index 0000000..713eeec
Binary files /dev/null and b/OLD_CODE/public/img2/88.jpg differ
diff --git a/OLD_CODE/public/img2/888 (1).png b/OLD_CODE/public/img2/888 (1).png
new file mode 100644
index 0000000..127e80d
Binary files /dev/null and b/OLD_CODE/public/img2/888 (1).png differ
diff --git a/OLD_CODE/public/img2/888.jpg b/OLD_CODE/public/img2/888.jpg
new file mode 100644
index 0000000..e8f33f7
Binary files /dev/null and b/OLD_CODE/public/img2/888.jpg differ
diff --git a/OLD_CODE/public/img2/888.png b/OLD_CODE/public/img2/888.png
new file mode 100644
index 0000000..35e3403
Binary files /dev/null and b/OLD_CODE/public/img2/888.png differ
diff --git a/OLD_CODE/public/img2/8_8.png b/OLD_CODE/public/img2/8_8.png
new file mode 100644
index 0000000..9f86b2c
Binary files /dev/null and b/OLD_CODE/public/img2/8_8.png differ
diff --git a/OLD_CODE/public/img2/9.jpg b/OLD_CODE/public/img2/9.jpg
new file mode 100644
index 0000000..0b772e3
Binary files /dev/null and b/OLD_CODE/public/img2/9.jpg differ
diff --git a/OLD_CODE/public/img2/99.jpg b/OLD_CODE/public/img2/99.jpg
new file mode 100644
index 0000000..ed309ba
Binary files /dev/null and b/OLD_CODE/public/img2/99.jpg differ
diff --git a/OLD_CODE/public/img2/99.png b/OLD_CODE/public/img2/99.png
new file mode 100644
index 0000000..8fd29b2
Binary files /dev/null and b/OLD_CODE/public/img2/99.png differ
diff --git a/OLD_CODE/public/img2/99_1.jpg b/OLD_CODE/public/img2/99_1.jpg
new file mode 100644
index 0000000..0247358
Binary files /dev/null and b/OLD_CODE/public/img2/99_1.jpg differ
diff --git a/OLD_CODE/public/img2/99_2.jpg b/OLD_CODE/public/img2/99_2.jpg
new file mode 100644
index 0000000..468fd51
Binary files /dev/null and b/OLD_CODE/public/img2/99_2.jpg differ
diff --git a/OLD_CODE/public/img2/99_3.png b/OLD_CODE/public/img2/99_3.png
new file mode 100644
index 0000000..ae2cd8e
Binary files /dev/null and b/OLD_CODE/public/img2/99_3.png differ
diff --git a/OLD_CODE/public/img2/9_9.jpg b/OLD_CODE/public/img2/9_9.jpg
new file mode 100644
index 0000000..a77f2ae
Binary files /dev/null and b/OLD_CODE/public/img2/9_9.jpg differ
diff --git a/OLD_CODE/public/img2/9_9.png b/OLD_CODE/public/img2/9_9.png
new file mode 100644
index 0000000..733a453
Binary files /dev/null and b/OLD_CODE/public/img2/9_9.png differ
diff --git a/OLD_CODE/public/img2/black.png b/OLD_CODE/public/img2/black.png
new file mode 100644
index 0000000..a10af51
Binary files /dev/null and b/OLD_CODE/public/img2/black.png differ
diff --git a/OLD_CODE/public/img2/black1.png b/OLD_CODE/public/img2/black1.png
new file mode 100644
index 0000000..f529bd3
Binary files /dev/null and b/OLD_CODE/public/img2/black1.png differ
diff --git a/OLD_CODE/public/img2/black2.png b/OLD_CODE/public/img2/black2.png
new file mode 100644
index 0000000..75758a2
Binary files /dev/null and b/OLD_CODE/public/img2/black2.png differ
diff --git a/OLD_CODE/public/img2/brown.png b/OLD_CODE/public/img2/brown.png
new file mode 100644
index 0000000..9ef4db4
Binary files /dev/null and b/OLD_CODE/public/img2/brown.png differ
diff --git a/OLD_CODE/public/img2/brown1.png b/OLD_CODE/public/img2/brown1.png
new file mode 100644
index 0000000..0b178f1
Binary files /dev/null and b/OLD_CODE/public/img2/brown1.png differ
diff --git a/OLD_CODE/public/img2/brown2.png b/OLD_CODE/public/img2/brown2.png
new file mode 100644
index 0000000..346b22f
Binary files /dev/null and b/OLD_CODE/public/img2/brown2.png differ
diff --git a/OLD_CODE/public/img2/chair.PNG b/OLD_CODE/public/img2/chair.PNG
new file mode 100644
index 0000000..12af9db
Binary files /dev/null and b/OLD_CODE/public/img2/chair.PNG differ
diff --git a/OLD_CODE/public/img2/gray.png b/OLD_CODE/public/img2/gray.png
new file mode 100644
index 0000000..55ab5bb
Binary files /dev/null and b/OLD_CODE/public/img2/gray.png differ
diff --git a/OLD_CODE/public/img2/gray1.png b/OLD_CODE/public/img2/gray1.png
new file mode 100644
index 0000000..3137e25
Binary files /dev/null and b/OLD_CODE/public/img2/gray1.png differ
diff --git a/OLD_CODE/public/img2/gray2.png b/OLD_CODE/public/img2/gray2.png
new file mode 100644
index 0000000..95b8781
Binary files /dev/null and b/OLD_CODE/public/img2/gray2.png differ
diff --git a/OLD_CODE/public/img2/диван.jpg b/OLD_CODE/public/img2/диван.jpg
new file mode 100644
index 0000000..578d1a3
Binary files /dev/null and b/OLD_CODE/public/img2/диван.jpg differ
diff --git a/OLD_CODE/public/img2/диван_1.jpg b/OLD_CODE/public/img2/диван_1.jpg
new file mode 100644
index 0000000..3618723
Binary files /dev/null and b/OLD_CODE/public/img2/диван_1.jpg differ
diff --git a/OLD_CODE/public/img2/кресло.jpg b/OLD_CODE/public/img2/кресло.jpg
new file mode 100644
index 0000000..6d1c12b
Binary files /dev/null and b/OLD_CODE/public/img2/кресло.jpg differ
diff --git a/OLD_CODE/public/img2/кресло_1.jpg b/OLD_CODE/public/img2/кресло_1.jpg
new file mode 100644
index 0000000..e59b3b1
Binary files /dev/null and b/OLD_CODE/public/img2/кресло_1.jpg differ
diff --git a/OLD_CODE/public/img2/слайдер_1.jpg b/OLD_CODE/public/img2/слайдер_1.jpg
new file mode 100644
index 0000000..255440e
Binary files /dev/null and b/OLD_CODE/public/img2/слайдер_1.jpg differ
diff --git a/OLD_CODE/public/img2/слайдер_2.jpg b/OLD_CODE/public/img2/слайдер_2.jpg
new file mode 100644
index 0000000..9cb6403
Binary files /dev/null and b/OLD_CODE/public/img2/слайдер_2.jpg differ
diff --git a/OLD_CODE/public/img2/слайдер_3.jpg b/OLD_CODE/public/img2/слайдер_3.jpg
new file mode 100644
index 0000000..dc65d0b
Binary files /dev/null and b/OLD_CODE/public/img2/слайдер_3.jpg differ
diff --git a/OLD_CODE/public/img2/слайдер_4.jpg b/OLD_CODE/public/img2/слайдер_4.jpg
new file mode 100644
index 0000000..f6d8d38
Binary files /dev/null and b/OLD_CODE/public/img2/слайдер_4.jpg differ
diff --git a/OLD_CODE/public/img2/слайдер_5.jpg b/OLD_CODE/public/img2/слайдер_5.jpg
new file mode 100644
index 0000000..a9cfbb6
Binary files /dev/null and b/OLD_CODE/public/img2/слайдер_5.jpg differ
diff --git a/OLD_CODE/public/img2/слайдер_6.jpg b/OLD_CODE/public/img2/слайдер_6.jpg
new file mode 100644
index 0000000..0dc28a0
Binary files /dev/null and b/OLD_CODE/public/img2/слайдер_6.jpg differ
diff --git a/OLD_CODE/public/img2/спальня.jpg b/OLD_CODE/public/img2/спальня.jpg
new file mode 100644
index 0000000..f403324
Binary files /dev/null and b/OLD_CODE/public/img2/спальня.jpg differ
diff --git a/OLD_CODE/public/img2/стили_оформления.css b/OLD_CODE/public/img2/стили_оформления.css
new file mode 100644
index 0000000..2e1d09c
--- /dev/null
+++ b/OLD_CODE/public/img2/стили_оформления.css
@@ -0,0 +1,61 @@
+
+.error-message {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+}
+
+.form__input.error {
+ border-color: #ff0000;
+}
+
+.form__group {
+ position: relative;
+ margin-bottom: 15px;
+}
+
+.page-messages {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1000;
+ width: 90%;
+ max-width: 500px;
+}
+
+.message {
+ padding: 15px;
+ margin: 10px 0;
+ border-radius: 5px;
+ text-align: center;
+ font-weight: bold;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #453227;
+ border: 1px solid #c8e6c9;
+}
+
+.message.warning {
+ background-color: #fff3e0;
+ color: #ef6c00;
+ border: 1px solid #ffe0b2;
+}
+
+.privacy-error {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+ text-align: center;
+}
diff --git a/OLD_CODE/public/includes/auth.php b/OLD_CODE/public/includes/auth.php
new file mode 100644
index 0000000..5326642
--- /dev/null
+++ b/OLD_CODE/public/includes/auth.php
@@ -0,0 +1,127 @@
+getConnection();
+
+ try {
+ $stmt = $db->prepare("
+ SELECT user_id, email, password_hash, full_name, phone, city, is_admin, is_active
+ FROM users WHERE email = ?
+ ");
+ $stmt->execute([$email]);
+ $user = $stmt->fetch();
+
+ if (!$user) {
+ return ['success' => false, 'message' => 'Пользователь не найден'];
+ }
+
+ if (!$user['is_active']) {
+ return ['success' => false, 'message' => 'Аккаунт заблокирован'];
+ }
+
+ if (!password_verify($password, $user['password_hash'])) {
+ return ['success' => false, 'message' => 'Неверный пароль'];
+ }
+
+ $_SESSION['user_id'] = $user['user_id'];
+ $_SESSION['user_email'] = $user['email'];
+ $_SESSION['full_name'] = $user['full_name'];
+ $_SESSION['user_phone'] = $user['phone'] ?? '';
+ $_SESSION['user_city'] = $user['city'] ?? '';
+ $_SESSION['isLoggedIn'] = true;
+ $_SESSION['isAdmin'] = (bool)$user['is_admin'];
+ $_SESSION['login_time'] = time();
+
+ $updateStmt = $db->prepare("UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE user_id = ?");
+ $updateStmt->execute([$user['user_id']]);
+
+ return ['success' => true, 'user' => $user];
+
+ } catch (PDOException $e) {
+ return ['success' => false, 'message' => 'Ошибка базы данных'];
+ }
+}
+
+function registerUser(array $data): array {
+ $db = Database::getInstance()->getConnection();
+
+ $email = trim($data['email'] ?? '');
+ $password = $data['password'] ?? '';
+ $fullName = trim($data['full_name'] ?? '');
+ $phone = trim($data['phone'] ?? '');
+ $city = trim($data['city'] ?? '');
+
+ if (empty($email) || empty($password) || empty($fullName)) {
+ return ['success' => false, 'message' => 'Заполните все обязательные поля'];
+ }
+
+ if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
+ return ['success' => false, 'message' => 'Некорректный email'];
+ }
+
+ if (strlen($password) < 6) {
+ return ['success' => false, 'message' => 'Пароль должен содержать минимум 6 символов'];
+ }
+
+ try {
+
+ $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?");
+ $checkStmt->execute([$email]);
+
+ if ($checkStmt->fetch()) {
+ return ['success' => false, 'message' => 'Пользователь с таким email уже существует'];
+ }
+
+ $passwordHash = password_hash($password, PASSWORD_DEFAULT);
+
+ $stmt = $db->prepare("
+ INSERT INTO users (email, password_hash, full_name, phone, city, is_active)
+ VALUES (?, ?, ?, ?, ?, TRUE)
+ RETURNING user_id
+ ");
+ $stmt->execute([$email, $passwordHash, $fullName, $phone, $city]);
+ $userId = $stmt->fetchColumn();
+
+ $_SESSION['user_id'] = $userId;
+ $_SESSION['user_email'] = $email;
+ $_SESSION['full_name'] = $fullName;
+ $_SESSION['user_phone'] = $phone;
+ $_SESSION['user_city'] = $city;
+ $_SESSION['isLoggedIn'] = true;
+ $_SESSION['isAdmin'] = false;
+ $_SESSION['login_time'] = time();
+
+ return ['success' => true, 'user_id' => $userId];
+
+ } catch (PDOException $e) {
+ return ['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()];
+ }
+}
+
+function logoutUser(): void {
+ $_SESSION = [];
+
+ if (ini_get("session.use_cookies")) {
+ $params = session_get_cookie_params();
+ setcookie(session_name(), '', time() - 42000,
+ $params["path"], $params["domain"],
+ $params["secure"], $params["httponly"]
+ );
+ }
+
+ session_destroy();
+}
+
+function checkAdminAccess(): bool {
+ if (!isset($_SESSION['isLoggedIn']) || $_SESSION['isLoggedIn'] !== true) {
+ return false;
+ }
+
+ if (!isset($_SESSION['isAdmin']) || $_SESSION['isAdmin'] !== true) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/public/includes/footer.php b/OLD_CODE/public/includes/footer.php
similarity index 100%
rename from public/includes/footer.php
rename to OLD_CODE/public/includes/footer.php
diff --git a/public/includes/functions.php b/OLD_CODE/public/includes/functions.php
similarity index 100%
rename from public/includes/functions.php
rename to OLD_CODE/public/includes/functions.php
diff --git a/public/includes/header.php b/OLD_CODE/public/includes/header.php
similarity index 100%
rename from public/includes/header.php
rename to OLD_CODE/public/includes/header.php
diff --git a/OLD_CODE/public/index.php b/OLD_CODE/public/index.php
new file mode 100644
index 0000000..7d3550f
--- /dev/null
+++ b/OLD_CODE/public/index.php
@@ -0,0 +1,759 @@
+
+
+
+
+
+ AETERNA - Мебель и Интерьер
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ДОБАВЬТЕ ИЗЫСКАННОСТИ В СВОЙ ИНТЕРЬЕР
+
Мы создаем мебель, которая сочетает в себе безупречный дизайн, натуральные материалы, продуманный функционал, чтобы ваш день начинался и заканчивался с комфортом.
+
+
+
ПЕРЕЙТИ В КАТАЛОГ
+
+
ПЕРЕЙТИ В КАТАЛОГ
+
+
+
+
+
+
+
+
+
+
+
+
О НАС
+
Компания AETERNA - российский производитель качественной корпусной и мягкой мебели для дома и офиса. С 2015 года мы успешно реализуем проекты любой сложности, сочетая современные технологии, проверенные материалы и классическое мастерство.
+
+
+
+
+
+
+
Наша сеть включает 30+ российских фабрик, отобранных по строгим стандартам качества. Мы сотрудничаем исключительно с лидерами рынка, чья продукция доказала свое превосходство временем.
+
+
+
+
+
+
+
+
+
+
+
+
ГОТОВОЕ РЕШЕНИЕ ДЛЯ ВАШЕЙ ГОСТИНОЙ
+
УСПЕЙТЕ ЗАКАЗАТЬ СЕЙЧАС
+
+
Подробнее
+
+
+
+
+
+
ГОТОВОЕ РЕШЕНИЕ ДЛЯ ВАШЕЙ СПАЛЬНИ
+
УСПЕЙТЕ ЗАКАЗАТЬ СЕЙЧАС
+
+
Подробнее
+
+
+
+
+
+
+
+
+
+
+
+
30 000+
+
Довольных покупателей
+
+
+
4500+
+
Реализованных заказов
+
+
+
+
+
+
+
+
ОТВЕТЫ НА ВОПРОСЫ
+
+
+
1
+
+
Сколько времени занимает доставка?
+
Доставка готовых позиций занимает 1-3 дня. Мебель на заказ изготавливается от 14 до 45 рабочих дней, в зависимости от сложности. Точные сроки озвучит ваш менеджер при оформлении заказа.
+
+
+
+
2
+
+
Нужно ли вносить предоплату?
+
Да, для запуска заказа в производство необходима предоплата в размере 50-70% от стоимости, в зависимости от изделия. Оставшаяся сумма оплачивается при доставке и приемке мебели.
+
+
+
+
3
+
+
Предоставляется ли рассрочка или кредит?
+
Да, мы сотрудничаем с несколькими банками и предлагаем рассрочку на 6 или 12 месяцев без первоначального взноса, а также кредит на более длительный срок. Все условия уточняйте у вашего менеджера.
+
+
+
+
4
+
+
Что делать, если мебель пришла с дефектом?
+
В этом случае необходимо в течение 7 дней со дня доставки сообщить нам о проблеме, прислать фото/видео дефекта. Мы оперативно решим вопрос о бесплатной замене или ремонте изделия.
+
+
+
+
Задать вопрос
+
+
+
+
+
+
+
+
+
+
+
+ Быстрый вход
+
+
+
+ Войти как Администратор
+
+
+ Войти как Пользователь
+
+
+
+ Для полного функционала перейдите на страницу входа
+
+
+
+
+
+
+
+
+
+
+
+
+
Быстрый вход:
+
+ Войти в аккаунт
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OLD_CODE/public/login.php b/OLD_CODE/public/login.php
new file mode 100644
index 0000000..0d6eeaf
--- /dev/null
+++ b/OLD_CODE/public/login.php
@@ -0,0 +1,294 @@
+
+
+
+
+
+ AETERNA - Вход
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OLD_CODE/public/logout.php b/OLD_CODE/public/logout.php
new file mode 100644
index 0000000..02ef1c7
--- /dev/null
+++ b/OLD_CODE/public/logout.php
@@ -0,0 +1,17 @@
+getConnection();
+
+try {
+
+ $productStmt = $db->prepare("
+ SELECT
+ p.*,
+ c.name as category_name,
+ c.slug as category_slug
+ FROM products p
+ LEFT JOIN categories c ON p.category_id = c.category_id
+ WHERE p.product_id = ? AND p.is_available = TRUE
+ ");
+ $productStmt->execute([$product_id]);
+ $product = $productStmt->fetch();
+
+ if (!$product) {
+ header('Location: catalog.php?error=product_not_found');
+ exit();
+ }
+
+ $similarStmt = $db->prepare("
+ SELECT * FROM products
+ WHERE category_id = ?
+ AND product_id != ?
+ AND is_available = TRUE
+ ORDER BY RANDOM()
+ LIMIT 3
+ ");
+ $similarStmt->execute([$product['category_id'], $product_id]);
+ $similarProducts = $similarStmt->fetchAll();
+
+ $reviewsStmt = $db->prepare("
+ SELECT rating, comment, created_at
+ FROM reviews
+ WHERE product_id = ?
+ ORDER BY created_at DESC
+ LIMIT 5
+ ");
+ $reviewsStmt->execute([$product_id]);
+ $reviews = $reviewsStmt->fetchAll();
+
+} catch (PDOException $e) {
+ die("Ошибка базы данных: " . $e->getMessage());
+}
+
+?>
+
+
+
+
+
+ AETERNA - = htmlspecialchars($product['name']) ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
= htmlspecialchars($product['name']) ?>
+
+
+
+ = 0.5;
+
+ for ($i = 1; $i <= 5; $i++) {
+ if ($i <= $fullStars) {
+ echo '★ ';
+ } elseif ($i == $fullStars + 1 && $hasHalfStar) {
+ echo '★ ';
+ } else {
+ echo '☆ ';
+ }
+ }
+ ?>
+
+
= number_format($rating, 1) ?>
+
(= $product['review_count'] ?> отзывов)
+
+
+
+
+ = number_format($product['price'], 0, '', ' ') ?> ₽
+
+ $product['price']): ?>
+
+ = number_format($product['old_price'], 0, '', ' ') ?> ₽
+
+
+ -= round(($product['old_price'] - $product['price']) / $product['old_price'] * 100) ?>%
+
+
+
+
+
+ 10) {
+ echo ' В наличии';
+ } elseif ($product['stock_quantity'] > 0) {
+ echo ' Осталось мало: ' . $product['stock_quantity'] . ' шт.';
+ } else {
+ echo ' Нет в наличии';
+ }
+ ?>
+
+
+
+
+ Артикул:
+ = $product['sku'] ?? 'N/A' ?>
+
+
+ Категория:
+ = htmlspecialchars($product['category_name'] ?? 'Без категории') ?>
+
+
+ На складе:
+ = $product['stock_quantity'] ?> шт.
+
+
+
+
+ = nl2br(htmlspecialchars($product['description'] ?? 'Описание отсутствует')) ?>
+
+
+ 0): ?>
+
+
+ -
+
+ +
+
+
+
+
+ В корзину
+
+
+ Купить сейчас
+
+
+
+
+
+
+ Уведомить о поступлении
+
+
+
+
+
+
+
+
+
+
+
+
+ Похожие товары
+
+
+
+
+
+
+
+
= htmlspecialchars($similar['name']) ?>
+
+ = number_format($similar['price'], 0, '', ' ') ?> ₽
+
+
+ Подробнее
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OLD_CODE/public/register.php b/OLD_CODE/public/register.php
new file mode 100644
index 0000000..0afc144
--- /dev/null
+++ b/OLD_CODE/public/register.php
@@ -0,0 +1,741 @@
+getConnection();
+
+ try {
+
+ $checkStmt = $db->prepare("SELECT user_id FROM users WHERE email = ?");
+ $checkStmt->execute([$email]);
+
+ if (!$checkStmt->fetch()) {
+
+ $password_hash = password_hash($password, PASSWORD_DEFAULT);
+ $is_admin = ($_GET['quick_register'] == 'admin');
+
+ $stmt = $db->prepare("
+ INSERT INTO users (email, password_hash, full_name, phone, city, is_admin)
+ VALUES (?, ?, ?, ?, ?, ?)
+ RETURNING user_id
+ ");
+
+ $stmt->execute([$email, $password_hash, $full_name, $phone, $city, $is_admin]);
+ $user_id = $stmt->fetchColumn();
+ } else {
+
+ $stmt = $db->prepare("SELECT user_id, is_admin FROM users WHERE email = ?");
+ $stmt->execute([$email]);
+ $user = $stmt->fetch();
+ $user_id = $user['user_id'];
+ $is_admin = $user['is_admin'];
+ }
+
+ $_SESSION['user_id'] = $user_id;
+ $_SESSION['user_email'] = $email;
+ $_SESSION['full_name'] = $full_name;
+ $_SESSION['user_phone'] = $phone;
+ $_SESSION['user_city'] = $city;
+ $_SESSION['isLoggedIn'] = true;
+ $_SESSION['isAdmin'] = $is_admin;
+ $_SESSION['login_time'] = time();
+
+ header('Location: catalog.php');
+ exit();
+
+ } catch (Exception $e) {
+ $registration_errors[] = 'Ошибка быстрой регистрации: ' . $e->getMessage();
+ }
+}
+?>
+
+
+
+
+
+ AETERNA - Регистрация
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Ошибки регистрации:
+
+
+ = htmlspecialchars($error) ?>
+
+
+
+
+
+
+
+ = htmlspecialchars($registration_success) ?>
+
+
+
+
+ Для доступа к каталогу и оформления заказов необходимо зарегистрироваться
+
+
+
+
+
AETERNA
+
+
Присоединяйтесь к нам
+
+ Создайте аккаунт чтобы получить доступ ко всем функциям:
+
+
+ Доступ к каталогу товаров
+ Добавление товаров в корзину
+ Оформление заказов
+ История покупок
+ Специальные предложения
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Quick Admin
+
+
+ Quick User
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OLD_CODE/public/services.php b/OLD_CODE/public/services.php
new file mode 100644
index 0000000..ec1a30d
--- /dev/null
+++ b/OLD_CODE/public/services.php
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+ AETERNA - Услуги
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ДОСТАВКА
+
Стоимость доставки зависит от таких факторов, как: вес, адрес, удаленность от города, дата
+
+
+
СБОРКА
+
Стоимость сборки рассчитывается индивидуально, так как на цену влияет несколько факторов
+
+
+
+
+
ДИЗАЙН‑ПРОЕКТ
+
Предоставляем услугу по составлению дизайн‑проекта. Учитываем индивидуальные пожелания каждого клиента. Работаем с интерьерами различной сложности.
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/style_for_cite.less b/OLD_CODE/public/style_for_cite.less
similarity index 100%
rename from style_for_cite.less
rename to OLD_CODE/public/style_for_cite.less
diff --git a/uploads/products/.gitkeep b/OLD_CODE/public/uploads/products/.gitkeep
similarity index 100%
rename from uploads/products/.gitkeep
rename to OLD_CODE/public/uploads/products/.gitkeep
diff --git a/OLD_CODE/public/uploads/products/product_1765745390_2854.png b/OLD_CODE/public/uploads/products/product_1765745390_2854.png
new file mode 100644
index 0000000..55ab5bb
Binary files /dev/null and b/OLD_CODE/public/uploads/products/product_1765745390_2854.png differ
diff --git a/OLD_CODE/public/uploads/products/product_1765750758_4966.jpg b/OLD_CODE/public/uploads/products/product_1765750758_4966.jpg
new file mode 100644
index 0000000..e59b3b1
Binary files /dev/null and b/OLD_CODE/public/uploads/products/product_1765750758_4966.jpg differ
diff --git a/OLD_CODE/public/warranty.php b/OLD_CODE/public/warranty.php
new file mode 100644
index 0000000..fb39d60
--- /dev/null
+++ b/OLD_CODE/public/warranty.php
@@ -0,0 +1,205 @@
+
+
+
+
+
+ AETERNA - Гарантия
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ГАРАНТИЙНЫЕ ОБЯЗАТЕЛЬСТВА
+
+
+
+
+
+
+
Мягкая мебель
+
18 месяцев
+
+
+
+
+
+
+
Корпусная мебель
+
24 месяца
+
+
+
+
+
+
+
Элементы освещения
+
12 месяцев
+
+
+
+
+
+
+
Фурнитура и механизмы
+
36 месяцев
+
+
+
+
+
+
Что покрывается гарантией
+
+
+
+
+
Производственные дефекты
+
Трещины, сколы, брак материалов
+
+
+
+
+
+
Неисправности механизмов
+
Трансформации, выдвижные системы
+
+
+
+
+
+
Проблемы с фурнитурой
+
Ручки, петли, направляющие
+
+
+
+
+
+
Дефекты покрытия
+
Отслоение шпона, краски, ламинации
+
+
+
+
+
+
+
Что не покрывается гарантией
+
+
+
+
+
Механические повреждения
+
Царапины, вмятины от неправильной эксплуатации
+
+
+
+
+
+
Следы износа
+
Естественное старение материалов
+
+
+
+
+
+
Неправильная сборка
+
Последствия самостоятельного ремонта
+
+
+
+
+
+
Внешние воздействия
+
Повреждения от жидкостей, солнечных лучей
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OLD_CODE/public/стили_оформления.less b/OLD_CODE/public/стили_оформления.less
new file mode 100644
index 0000000..a6fe073
--- /dev/null
+++ b/OLD_CODE/public/стили_оформления.less
@@ -0,0 +1,137 @@
+.error-message {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+}
+
+.form__input.error {
+ border-color: #ff0000;
+}
+
+.form__group {
+ position: relative;
+ margin-bottom: 15px;
+}
+
+.page-messages {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1000;
+ width: 90%;
+ max-width: 500px;
+}
+
+.message {
+ padding: 15px;
+ margin: 10px 0;
+ border-radius: 5px;
+ text-align: center;
+ font-weight: bold;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #453227;
+ border: 1px solid #c8e6c9;
+}
+
+.message.warning {
+ background-color: #fff3e0;
+ color: #ef6c00;
+ border: 1px solid #ffe0b2;
+}
+
+.privacy-error {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+ text-align: center;
+}
+
+.input-group {
+ position: relative;
+ margin-bottom: 20px;
+}
+
+.profile-form input.error {
+ border-color: #ff0000;
+ background-color: #fff5f5;
+}
+
+.privacy-checkbox {
+ margin: 20px 0;
+ text-align: center;
+}
+
+.privacy-checkbox label {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ cursor: pointer;
+ font-size: 14px;
+}
+
+.privacy-checkbox input[type="checkbox"] {
+ margin: 0;
+}
+
+.profile-page-main {
+ padding: 40px 0;
+ min-height: calc(100vh - 200px);
+}
+
+.profile-container {
+ margin: 0 auto;
+ position: relative;
+ z-index: 1;
+}
+
+.input-hint {
+ font-size: 12px;
+ color: #666;
+ margin-top: 5px;
+}
+
+.form-options {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 20px 0;
+}
+
+.remember-me {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ color: #453227;
+}
+
+.remember-me input[type="checkbox"] {
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
+}
+
+.forgot-password {
+ font-size: 14px;
+ color: #453227;
+ text-decoration: underline;
+}
+
+.forgot-password:hover {
+ color: #617365;
+ text-decoration: none;
+}
\ No newline at end of file
diff --git a/OLD_CODE/setup.sh b/OLD_CODE/setup.sh
new file mode 100755
index 0000000..03cd61a
--- /dev/null
+++ b/OLD_CODE/setup.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+#
+# AETERNA - Скрипт настройки проекта
+# Запуск: ./setup.sh
+#
+
+echo "==========================================="
+echo " AETERNA - Настройка проекта"
+echo "==========================================="
+echo ""
+
+PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
+cd "$PROJECT_DIR"
+
+# Проверяем наличие PHP
+if ! command -v php &> /dev/null; then
+ echo "[ERROR] PHP не установлен!"
+ exit 1
+fi
+
+echo "[1/3] Проверка структуры проекта..."
+REQUIRED_DIRS=("public" "admin" "api" "includes" "config" "migrations" "assets" "uploads")
+for dir in "${REQUIRED_DIRS[@]}"; do
+ if [ ! -d "$dir" ]; then
+ mkdir -p "$dir"
+ echo " Создана папка: $dir"
+ fi
+done
+echo " ✓ Структура OK"
+
+echo ""
+echo "[2/3] Запуск миграций базы данных..."
+if [ -f "migrations/migrate.php" ]; then
+ php migrations/migrate.php
+else
+ echo " ⚠ Файл миграций не найден"
+fi
+
+echo ""
+echo "[3/3] Загрузка начальных данных..."
+echo " Загрузить тестовые данные (админ, категории, товары)? (y/n)"
+read -r answer
+if [ "$answer" = "y" ] || [ "$answer" = "Y" ]; then
+ php migrations/migrate.php --seed
+ echo " ✓ Данные загружены"
+else
+ echo " Пропущено"
+fi
+
+echo ""
+echo "==========================================="
+echo " Готово!"
+echo "==========================================="
+echo ""
+echo "Тестовые аккаунты:"
+echo " Админ: admin@aeterna.ru / admin123"
+echo " Пользователь: user@test.com / user123"
+echo ""
+echo "Запуск сервера:"
+echo " php -S localhost:8000 -t public"
+echo ""
diff --git a/OLD_CODE/style_for_cite.less b/OLD_CODE/style_for_cite.less
new file mode 100644
index 0000000..3a52d85
--- /dev/null
+++ b/OLD_CODE/style_for_cite.less
@@ -0,0 +1,3178 @@
+@import "mixins.less";
+@import "стили_оформления.less";
+// =======================
+// === БАЗОВЫЕ СТИЛИ ===
+// =======================
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+html, body {
+ height: 100%;
+}
+
+html {
+ scroll-behavior: smooth;
+}
+
+body {
+ font-family: @font-main;
+ background-color: @color-secondary;
+ color: @color-text-dark;
+ line-height: 1.6;
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+}
+
+.container {
+ max-width: 1210px;
+ margin: 0 auto;
+ padding: 0 20px;
+}
+
+ul {
+ list-style: none;
+}
+
+a {
+ text-decoration: none;
+ color: inherit;
+ transition: all 0.3s ease;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ font-family: @font-heading;
+ margin: 0;
+}
+
+p, li, span {
+ font-family: @font-main;
+}
+
+// =======================
+// === КОМПОНЕНТЫ ===
+// =======================
+
+.logo, .footer-logo {
+ font: bold 32px/1 @font-logo;
+ letter-spacing: 2px;
+ text-shadow: @shadow-dark;
+ flex-shrink: 0;
+}
+
+.btn {
+ padding: 12px 30px;
+ border: none;
+ cursor: pointer;
+ font-size: 14px;
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+ font-family: @font-main;
+
+ &.primary-btn {
+ background-color: @color-button;
+ color: @color-text-light;
+
+ &:hover {
+ background-color: lighten(@color-button, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+}
+
+.number-circle {
+ .flex-center();
+ width: 28px;
+ height: 28px;
+ border-radius: 50%;
+ background-color: @color-button;
+ color: @color-text-light;
+ font-size: 16px;
+ font-weight: bold;
+ flex-shrink: 0;
+}
+
+.breadcrumbs {
+ font-size: 14px;
+ margin-bottom: 20px;
+ color: #666;
+
+ a {
+ color: #666;
+ opacity: 0.7;
+ &:hover { opacity: 1; }
+ }
+
+ .current-page {
+ font-weight: bold;
+ color: @color-text-dark;
+ }
+}
+
+// =======================
+// === ШАПКА САЙТА ===
+// =======================
+.header {
+ background-color: @color-secondary;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+ z-index: 1000;
+
+ &__top, &__bottom {
+ padding: 15px 0;
+ .container {
+ .flex-between();
+ gap: 20px;
+ }
+ }
+
+ &__bottom {
+ padding: 10px 0;
+ border-top: 1px solid rgba(0, 0, 0, 0.05);
+
+ .catalog-link.active-catalog {
+ background-color: rgba(0, 0, 0, 0.08);
+ pointer-events: none;
+ }
+ }
+
+ .search-catalog {
+ .flex-center();
+ border: 2px solid @color-text-dark;
+ background-color: #fff;
+ max-width: 600px;
+ width: 100%;
+ margin: 0 auto;
+ overflow: hidden;
+
+ .catalog-dropdown {
+ position: relative;
+ background-color: #f8f8f8;
+ padding: 10px 15px 10px 25px;
+ font-size: 18px;
+ cursor: pointer;
+ border-right: 1px solid @color-text-dark;
+ .flex-center(10px);
+ width: 200px;
+ flex-shrink: 0;
+
+ &__menu {
+ .menu-base();
+ li {
+ padding: 8px 0;
+ cursor: pointer;
+ transition: color 0.3s;
+ border-bottom: 1px solid #f0f0f0;
+ &:last-child { border-bottom: none; }
+ &:hover { color: @color-accent; }
+ }
+ }
+ &:hover &__menu { display: block; }
+ }
+
+ .search-box {
+ .flex-center();
+ padding: 0 15px;
+ flex-grow: 1;
+ position: relative;
+ font-size: 15px;
+
+ input {
+ border: none;
+ padding: 10px 30px 10px 0;
+ outline: none;
+ font-size: 16px;
+ width: 100%;
+ text-align: left;
+ }
+
+ .search-icon {
+ font-size: 20px;
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+ }}
+
+ &__icons--top {
+ .flex-center(15px);
+ flex-shrink: 0;
+ .icon { .icon-base(); font-size: 20px;}
+ }
+
+ .nav-list {
+ .flex-center(30px);
+ font-size: 18px;
+ a {
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
+ &:hover { text-shadow: @shadow-dark; }
+ &.active {
+ border-bottom: 2px solid @color-button;
+ padding-bottom: 5px;
+ text-shadow: @shadow-dark;
+ }
+ &[href="#footer"] {
+ cursor: pointer;
+ }
+ }
+ }
+
+ .catalog-link {
+ .flex-center(10px);
+ border-radius: 4px;
+ white-space: nowrap;
+ font-size: 18px;
+ padding: 10px 18px;
+ &:hover { background-color: rgba(0, 0, 0, 0.05); }
+ }
+
+ .header-phone {
+ font-weight: bold;
+ color: @color-button;
+ flex-shrink: 0;
+ }
+}
+
+// =======================
+// === ОСНОВНЫЕ СЕКЦИИ ===
+// =======================
+.hero {
+ padding: 15px 0;
+
+ &__content {
+ .flex-center(50px);
+ min-height: 60vh;
+ align-items: center;
+ }
+
+ &__image-block {
+ position: relative;
+ flex: 0 0 40%;
+ max-width: 600px;
+ height: 600px;
+ .flex-center();
+
+ .hero__circle {
+ position: absolute;
+ width: 450px;
+ height: 450px;
+ background-color: @color-primary;
+ border-radius: 50%;
+ z-index: 1;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ }
+
+ .hero__img {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ z-index: 2;
+ }
+ }
+
+ &__text-block {
+ flex: 0 0 60%;
+ padding-left: 50px;
+
+ h1 {
+ font-size: 42px;
+ font-weight: normal;
+ margin-bottom: 25px;
+ line-height: 1.3;
+ }
+
+ .hero__usp-text {
+ position: relative;
+ padding-left: 50px;
+ margin-bottom: 35px;
+ line-height: 1.7;
+ .flex-center();
+ justify-content: flex-start;
+ min-height: 40px;
+ font-size: 16px;
+
+ &::before {
+ content: "✓";
+ position: absolute;
+ left: 0;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 32px;
+ height: 32px;
+ border: 2px solid @color-button;
+ background-color: transparent;
+ color: @color-button;
+ border-radius: 50%;
+ .flex-center();
+ font-size: 16px;
+ font-weight: bold;
+ }
+ }
+
+ .btn.primary-btn {
+ margin: 25px 0 0 50px;
+ padding: 14px 35px;
+ font-size: 15px;
+ }
+ }
+}
+
+.advantages {
+ padding: 30px 0 40px;
+
+ &__header {
+ display: flex;
+ align-items: center;
+ gap: 50px;
+ margin-bottom: 40px;
+ h2 {
+ font-size: 32px;
+ font-weight: normal;
+ flex: 0 0 30%;
+ }
+ }
+
+ &__items {
+ flex: 0 0 70%;
+ display: flex;
+ gap: 30px;
+ }
+
+ .advantage-item {
+ flex: 1;
+ text-align: left;
+ position: relative;
+ padding-top: 30px;
+
+ &__number {
+ .number-circle();
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+
+ h4 {
+ font-weight: 600;
+ margin-bottom: 10px;
+ }
+ }
+}
+
+.promo-images {
+ display: flex;
+ gap: 20px;
+ margin-top: 50px;
+
+ .promo-image-col {
+ position: relative;
+ overflow: hidden;
+ border-radius: 8px;
+ flex: 1;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: @shadow-light;
+ .image-overlay-text { background-color: rgba(0, 0, 0, 0.6); }
+ img { transform: scale(1.05); }
+ .image-overlay-text h4,
+ .image-overlay-text .overlay-link { transform: translateY(0); }
+ }
+
+ img {
+ width: 100%;
+ height: 350px;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.5s ease;
+ }
+
+ .image-overlay-text {
+ .image-overlay();
+ h4 {
+ font-size: 24px;
+ text-transform: uppercase;
+ line-height: 1.2;
+ margin-bottom: 15px;
+ transform: translateY(20px);
+ transition: transform 0.3s ease;
+ }
+ }
+
+ .overlay-link {
+ display: inline-block;
+ text-transform: uppercase;
+ font-weight: bold;
+ border-radius: 3px;
+ margin-top: 15px;
+ padding: 10px 25px;
+ background-color: @color-button;
+ color: @color-text-light;
+ font-size: 12px;
+ transform: translateY(20px);
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-button, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+ }
+}
+
+.about {
+ padding: 40px 0 80px;
+
+ &__content {
+ display: flex;
+ align-items: flex-start;
+ gap: 50px;
+ }
+
+ &__column {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ &--left { flex: 0 0 40%; margin-bottom: 30px; }
+ &--right {
+ flex: 0 0 60%;
+ .about__caption {
+ padding-right: 50px;
+ }
+ }
+ }
+
+ &__text-block {
+ margin-bottom: 30px;
+ h2 { margin-bottom: 15px; }
+ }
+
+ &__img {
+ width: 93%;
+ object-fit: cover;
+ display: block;
+ &--small { height: 300px; }
+ &--large { height: 450px; }
+ }
+
+ .text-justified {
+ text-align: justify;
+ color: #555;
+ }
+}
+
+.solutions {
+ padding: 0;
+ background-color: @color-secondary;
+
+ &-slider {
+ position: relative;
+ width: 100%;
+ max-width: 1200px;
+ margin: 40px auto;
+ border-radius: 8px;
+ overflow: hidden;
+
+ &__slides {
+ display: flex;
+ width: 200%;
+ height: 100%;
+ animation: slideLeftRight 10s infinite ease-in-out;
+ }
+
+ &__slide {
+ width: 50%;
+ flex-shrink: 0;
+ position: relative;
+ overflow: hidden;
+ transition: transform 0.5s ease, box-shadow 0.5s ease;
+
+ &:hover {
+ transform: scale(1.02);
+ box-shadow: 0 10px 25px rgba(0,0,0,0.3);
+ .solution-img {
+ transform: scale(1.05);
+ filter: brightness(0.8);
+ }
+ .solution-text-overlay {
+ opacity: 1;
+ transform: translateY(-5px);
+ }
+ .solution-image-link {
+ transform: translateX(-50%) translateY(-6px);
+ background-color: rgba(255,255,255,0.9);
+ color: @color-text-dark;
+ }
+ }
+ }
+
+ .solution-img {
+ width: 100%;
+ height: auto;
+ object-fit: cover;
+ display: block;
+ }
+
+ .solution-text-overlay {
+ position: absolute;
+ top: 15%;
+ left: 8%;
+ color: #493131;
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.6);
+ z-index: 2;
+ opacity: 0.9;
+ transition: opacity 0.5s ease, transform 0.5s ease;
+ h2 {
+ font-size: 35px;
+ text-transform: uppercase;
+ margin-bottom: 10px;
+ }
+ p {
+ font-size: 25px;
+ text-transform: uppercase;
+ }
+ }
+
+ .solution-image-link {
+ position: absolute;
+ bottom: 40px;
+ left: 50%;
+ transform: translateX(-50%);
+ padding: 12px 30px;
+ border: 2px solid @color-text-light;
+ color: #493131;
+ text-transform: uppercase;
+ font-size: 16px;
+ font-weight: bold;
+ background: transparent;
+ transition: 0.4s ease;
+ z-index: 2;
+ &:hover {
+ background: @color-text-light;
+ color: @color-text-dark;
+ transform: translateX(-50%) translateY(-2px);
+ }
+ }
+ }
+}
+
+@keyframes slideLeftRight {
+ 0%, 40% { transform: translateX(0); }
+ 50%, 90% { transform: translateX(-50%); }
+ 100% { transform: translateX(0); }
+}
+
+.stats {
+ padding: 0;
+ margin-top: 20px;
+
+ .container {
+ display: flex;
+ justify-content: flex-end;
+ }
+
+ &__items {
+ display: flex;
+ gap: 20px;
+ .stat-item {
+ text-align: left;
+ .stat-number {
+ font-size: 36px;
+ font-weight: bold;
+ color: @color-text-dark;
+ margin-bottom: 5px;
+ }
+ .stat-label { color: @color-text-dark; }
+ }
+ }
+}
+
+.faq {
+ padding: 50px 0;
+
+ h2 {
+ text-align: left;
+ font-size: 32px;
+ font-weight: normal;
+ margin-bottom: 40px;
+ }
+
+ &__items {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 40px 60px;
+ margin-bottom: 40px;
+ }
+
+ .faq-item {
+ flex: 0 0 calc(50% - 30px);
+ .flex-center(15px);
+ align-items: flex-start;
+ &__content h4 {
+ font-weight: 600;
+ margin-bottom: 10px;
+ }
+ }
+
+ .btn.primary-btn {
+ display: block;
+ width: 100%;
+ margin: 20px auto 80px;
+ }
+}
+
+// =======================
+// === СТИЛИ КАТАЛОГА ===
+// =======================
+.catalog-main {
+ padding: 30px 0 60px;
+ background-color: lighten(@color-secondary, 5%);
+}
+
+.catalog-wrapper {
+ display: flex;
+ gap: 20px;
+}
+
+.catalog-sidebar {
+ flex: 0 0 250px;
+ background-color: #fff;
+ padding: 20px;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+ height: fit-content;
+}
+
+.filter-group {
+ margin-bottom: 30px;
+}
+
+.filter-title {
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 15px;
+ text-transform: uppercase;
+}
+
+.filter-list li {
+ padding: 5px 0;
+ font-size: 16px;
+ a {
+ color: #555;
+ transition: color 0.2s;
+ &:hover { color: @color-accent; }
+ &.active-category {
+ font-weight: bold;
+ color: @color-primary;
+ }
+ }
+}
+
+.price-range {
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+ width: 100%;
+
+ .range-slider {
+ width: 100%;
+
+ input[type="range"] {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 100%;
+ height: 5px;
+ background: @color-primary;
+ border-radius: 5px;
+ outline: none;
+ margin: 0;
+
+ &::-webkit-slider-thumb {
+ -webkit-appearance: none;
+ appearance: none;
+ width: 20px;
+ height: 20px;
+ background: @color-accent;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ background: lighten(@color-accent, 10%);
+ }
+ }
+
+ &::-moz-range-thumb {
+ width: 20px;
+ height: 20px;
+ background: @color-accent;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ cursor: pointer;
+ box-shadow: 0 2px 4px rgba(0,0,0,0.2);
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ background: lighten(@color-accent, 10%);
+ }
+ }
+ }
+ }
+
+ .price-display {
+ font-size: 14px;
+ font-weight: bold;
+ text-align: center;
+ color: @color-text-dark;
+ padding: 10px;
+ background: #f8f8f8;
+ border-radius: 4px;
+ }
+}
+
+.filter-options {
+ list-style: none;
+ li {
+ display: flex;
+ align-items: center;
+ padding: 4px 0;
+ font-size: 14px;
+ }
+ label {
+ margin-left: 10px;
+ cursor: pointer;
+ color: #555;
+ }
+ input[type="checkbox"] {
+ width: 15px;
+ height: 15px;
+ cursor: pointer;
+ accent-color: @color-primary;
+ &:checked + label {
+ font-weight: bold;
+ color: @color-primary;
+ }
+ }
+}
+
+.filter-apply-btn {
+ width: 100%;
+ margin-top: 20px;
+}
+
+.catalog-products {
+ flex-grow: 1;
+}
+
+.products-container {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 20px;
+}
+
+.product-card {
+ background-color: #fff;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ transition: transform 0.3s ease;
+ box-sizing: border-box;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
+ .product-img { transform: scale(1.05); }
+ }
+}
+
+.product-image-container {
+ position: relative;
+ overflow: hidden;
+ margin-bottom: 0;
+ padding: 0;
+ height: 250px;
+ .flex-center();
+}
+
+.product-img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+}
+
+.product-img1 {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+}
+
+.product-discount {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ background-color: @color-button;
+ color: @color-text-light;
+ padding: 3px 8px;
+ font-size: 12px;
+ font-weight: bold;
+ z-index: 10;
+}
+
+.product-wishlist-icon {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ color: #333;
+ font-size: 18px;
+ cursor: pointer;
+ transition: color 0.3s ease;
+ z-index: 10;
+ &:hover { color: @color-accent; }
+}
+
+.product-name {
+ font-size: 16px;
+ font-weight: bold;
+ margin-bottom: 5px;
+}
+
+.product-details {
+ font-size: 13px;
+ color: #777;
+ margin-bottom: 10px;
+ flex-grow: 1;
+}
+
+.product-price {
+ font-size: 18px;
+ font-weight: bold;
+ color: @color-button;
+}
+
+.product-card.small { flex: 0 0 300px; max-width: 300px; height: 200px; }
+.product-card.small1 { flex: 0 0 320px; max-width: 320px; height: 250px;width: 320px; }
+.product-card.large { flex: 0 0 580px; max-width: 580px; height: 380px; }
+.product-card.wide { flex: 0 0 240px; max-width: 240px; height: 250px; }
+.product-card.wide1 { flex: 0 0 350px; max-width: 350px; height: 250px; }
+.product-card.wide2 { flex: 0 0 560px; max-width: 560px; height: 260px; }
+.product-card.wide2_1 { flex: 0 0 560px; max-width: 560px; height: 260px; margin: -280px 0 0; }
+.product-card.wide3 {
+ flex: 0 0 320px; max-width: 320px; height: 540px;
+ .product-image-container { height: 580px; }
+}
+.product-card.wide4 {
+ flex: 0 0 545px; max-width: 545px; margin: -270px 0 0; height: 250px;
+ .product-image-container { padding: 0; justify-content: flex-start; }
+ .product-img { margin-left: 0; align-self: flex-start; object-position: left center; }
+}
+.product-card.tall { flex: 0 0 300px; max-width: 300px; margin: -180px 0 0; height: 430px; }
+.product-card.full-width { flex: 0 0 100%; margin: -20px 0 0; max-width: 900px; height: 300px;}
+
+.product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 300px;
+
+ .product-image-container {
+ height: 100%;
+ padding: 0;
+ margin: 0;
+
+ .product-img1 {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ margin: 0;
+ padding: 0;
+ }
+ }
+}
+
+.product-card.tall .product-image-container,
+.product-card.large .product-image-container { height: 430px; }
+
+// =======================
+// === СТРАНИЦА ТОВАРА ===
+// =======================
+.product__section {
+ display: flex;
+ gap: 0;
+ margin: 30px 0;
+}
+
+.product__gallery, .product__info {
+ flex: 1;
+}
+
+.product__main-image {
+ margin-bottom: 15px;
+}
+
+.product__image {
+ width: 500px;
+ height: 300px;
+ border-radius: 4px;
+}
+
+.product__thumbnails {
+ display: flex;
+ gap: 10px;
+}
+
+.product__thumbnail {
+ border: none;
+ background: none;
+ cursor: pointer;
+ padding: 0;
+}
+
+.product__thumbnail img {
+ width: 245px;
+ height: 150px;
+ object-fit: cover;
+ border-radius: 4px;
+}
+
+.product__title {
+ font-size: 30px;
+ margin-bottom: 35px;
+}
+
+.product__rating {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ margin-bottom: 30px;
+}
+
+.product__color-selector {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 40px;
+}
+
+.product__color-option {
+ width: 45px;
+ height: 45px;
+ border-radius: 50%;
+ border: 2px solid transparent;
+ cursor: pointer;
+ transition: transform 0.3s ease;
+
+ &:hover{
+ transform: translateY(-2px);
+ }
+}
+
+.product__color-option.active {
+ border-color: @color-primary;
+}
+
+.product__description {
+ margin-bottom: 65px;
+ line-height: 1.5;
+}
+
+.product__details-link {
+ display: inline-block;
+ margin-bottom: 20px;
+ color: @color-primary;
+ font-weight: bold;
+}
+
+.product__purchase {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 35px;
+}
+
+.product__price {
+ font-size: 24px;
+ font-weight: bold;
+}
+
+.product__quantity {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.product__qty-btn {
+ width: 30px;
+ height: 30px;
+ background: @color-button;
+ color: @color-text-light;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ font-weight: bold;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background: lighten(@color-button, 10%);
+ transform: scale(1.1);
+ }
+}
+
+.product__qty-value {
+ font-weight: bold;
+ min-width: 30px;
+ text-align: center;
+}
+
+.product__actions {
+ display: flex;
+ gap: 15px;
+}
+
+.product__btn {
+ flex: 1;
+ padding: 12px 20px;
+ border: none;
+ border-radius: 4px;
+ font-weight: bold;
+ cursor: pointer;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+}
+
+.product__btn.primary {
+ background: @color-button;
+ color: @color-text-light;
+
+ &:hover {
+ background: lighten(@color-button, 10%);
+ }
+}
+
+.product__btn.secondary {
+ background: transparent;
+ border: 1px solid @color-button;
+ color: @color-button;
+
+ &:hover {
+ background: @color-button;
+ color: @color-text-light;
+ }
+}
+
+.similar {
+ margin: 60px 0;
+}
+
+.similar__title {
+ margin-bottom: 30px;
+ font-size: 28px;
+ font-weight: bold;
+}
+
+.similar__grid {
+ display: flex;
+ gap: 25px;
+ flex-wrap: wrap;
+ justify-content: space-between;
+}
+
+.similar__card {
+ flex: 0 0 calc(33.333% - 17px);
+ min-width: 320px;
+ background: @color-secondary;
+ border-radius: 12px;
+ overflow: hidden;
+ transition: all 0.3s ease;
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+
+ &:hover {
+ transform: translateY(-8px);
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+ }
+}
+
+.similar__card-image {
+ height: 300px;
+ overflow: hidden;
+ background: white;
+
+ img {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ transition: transform 0.3s ease;
+
+ &:hover {
+ transform: scale(1.05);
+ }
+ }
+}
+
+.similar__card-content {
+ padding: 25px;
+}
+
+.similar__card-title {
+ font-weight: bold;
+ margin-bottom: 10px;
+ font-size: 20px;
+ color: @color-text-dark;
+}
+
+.similar__card-description {
+ font-size: 15px;
+ margin-bottom: 15px;
+ color: #666;
+ line-height: 1.5;
+}
+
+.similar__card-price {
+ font-weight: bold;
+ font-size: 22px;
+ color: @color-button;
+}
+
+@media (max-width: 1024px) {
+ .similar {
+ &__card {
+ flex: 0 0 calc(50% - 13px);
+ min-width: 280px;
+ }
+ }
+}
+
+@media (max-width: 768px) {
+ .similar {
+ &__grid {
+ justify-content: center;
+ }
+
+ &__card {
+ flex: 0 0 100%;
+ max-width: 400px;
+ }
+ }
+}
+
+// =======================
+// === КОРЗИНА И ЗАКАЗ ===
+// =======================
+.main__content {
+ display: flex;
+ gap: 40px;
+ margin: 30px 0;
+
+ .products {
+ flex: 1;
+ }
+
+ .order {
+ flex: 0 0 65%;
+ padding: 40px;
+
+ &__header {
+ .flex-between();
+ margin-bottom: 20px;
+ }
+
+ &__title {
+ font-family: @font-logo;
+ font-size: 28px;
+ color: @color-text-dark;
+ margin: 0;
+ }
+
+ &__total {
+ font-weight: bold;
+ color: @color-text-dark;
+ }
+
+ &__section {
+ margin-bottom: 25px;
+ }
+
+ &__section-title {
+ font-family: @font-logo;
+ margin-bottom: 15px;
+ font-size: 18px;
+ color: @color-text-dark;
+ }
+ }
+}
+
+.products {
+ &__title {
+ font-family: @font-logo;
+ margin-bottom: 20px;
+ font-size: 24px;
+ color: @color-text-dark;
+ }
+
+ &__list {
+ .flex-column();
+ gap: 20px;
+ }
+
+ &__item {
+ background-color: @color-secondary;
+ border-radius: 8px;
+ padding: 20px;
+ display: flex;
+ gap: 15px;
+ border: 1px solid @color-secondary;
+ transition: transform 0.3s ease;
+ align-items: flex-start;
+ position: relative;
+
+ &:hover {
+ transform: translateY(-2px);
+ }
+ }
+
+ &__image {
+ width: 300px;
+ height: 200px;
+ border-radius: 4px;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ }
+
+ .product-img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ display: block;
+ transition: transform 0.3s ease;
+ margin: 0;
+ }
+
+ &__details {
+ flex: 1;
+ .flex-column();
+ justify-content: space-between;
+ align-items: flex-start;
+ min-height: 200px;
+ }
+
+ &__name {
+ font-weight: bold;
+ margin-bottom: 5px;
+ color: @color-accent;
+ font-size: 18px;
+ font-family: @font-main;
+ }
+
+ &__price {
+ font-weight: bold;
+ font-size: 18px;
+ margin-bottom: 15px;
+ color: @color-text-dark;
+ }
+
+ &__controls {
+ display: flex;
+ align-items: center;
+ gap: 15px;
+ margin-top: auto;
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ &__quantity {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ }
+
+ &__qty-btn {
+ width: 30px;
+ height: 30px;
+ background-color: @color-text-dark;
+ color: @color-text-light;
+ border: none;
+ border-radius: 50%;
+ cursor: pointer;
+ .flex-center();
+ font-family: @font-main;
+ font-weight: bold;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+ }
+
+ &__qty-value {
+ font-weight: bold;
+ min-width: 30px;
+ text-align: center;
+ font-size: 16px;
+ }
+
+ &__cart-icon {
+ background-color: transparent;
+ color: @color-text-dark;
+ width: 40px;
+ height: 40px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ border: 2px solid @color-text-dark;
+ margin-left: 20px;
+
+ &:hover {
+ transform: scale(1.1);
+ }
+
+ i { font-size: 18px; }
+ }
+}
+
+.form {
+ &__group { margin-bottom: 15px; }
+ &__label {
+ display: block;
+ margin-bottom: 5px;
+ font-weight: bold;
+ color: #000000;
+ }
+ &__input {
+ width: 100%;
+ padding: 14px 16px;
+ border: 2px solid #ccc;
+ font-family: @font-main;
+ font-size: 15px;
+ transition: border-color 0.3s ease;
+
+ &:focus {
+ border-color: @color-primary;
+ }
+
+ &:hover {
+ border-color: darken(#ccc, 10%);
+ }
+ &::placeholder {
+ font-style: italic;
+ color: #999;
+ }
+ }
+ &__row {
+ display: flex;
+ gap: 20px;
+ justify-content: space-between;
+ }
+ &__input--half {
+ width: 100%;
+ }
+ &__radio-group {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ margin-top: 20px;
+ }
+ &__radio-label {
+ display: flex;
+ align-items: center;
+ cursor: pointer;
+ color: @color-text-dark;
+ position: relative;
+ padding-left: 30px;
+ flex: 1;
+
+ &:hover {
+ .form__custom-radio {
+ border-color: lighten(@color-accent, 10%);
+ }
+ }
+ }
+ &__radio-input {
+ position: absolute;
+ opacity: 0;
+ cursor: pointer;
+ }
+ &__custom-radio {
+ position: absolute;
+ left: 0;
+ height: 20px;
+ width: 20px;
+ background-color: @color-secondary;
+ border: 2px solid @color-accent;
+ border-radius: 50%;
+ transition: border-color 0.3s ease;
+ }
+ &__radio-input:checked ~ &__custom-radio {
+ background-color: @color-accent;
+
+ &:after {
+ content: "";
+ position: absolute;
+ display: block;
+ top: 4px;
+ left: 4px;
+ width: 8px;
+ height: 8px;
+ border-radius: 50%;
+ background: white;
+ }
+ }
+}
+
+.divider {
+ height: 1px;
+ background-color: #999;
+ margin: 20px 0;
+}
+
+.promo {
+ display: flex;
+ margin-bottom: 20px;
+
+ &__input {
+ flex: 1;
+ padding: 10px;
+ border: 1px solid #000;
+ background-color: @color-secondary;
+ font-family: @font-main;
+ height: auto;
+ min-height: 48px;
+
+ &:hover {
+ border-color: @color-primary;
+ }
+
+ &::placeholder {
+ font-style: italic;
+ color: #999;
+ }
+ }
+
+ &__btn {
+ background-color: @color-accent;
+ color: @color-secondary;
+ border: none;
+ padding: 10px 60px;
+ cursor: pointer;
+ font-family: @font-main;
+ font-size: 18px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-accent, 10%);
+ transform: translateY(-2px);
+ }
+ }
+}
+
+.summary {
+ margin-bottom: 20px;
+
+ &__item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 10px;
+ color: @color-text-dark;
+
+ &.total {
+ font-weight: bold;
+ font-size: 18px;
+ padding-top: 10px;
+ margin-top: 10px;
+ }
+ }
+}
+
+.order-btn {
+ width: 100%;
+ background-color: @color-accent;
+ color: @color-secondary;
+ border: none;
+ padding: 15px;
+ border-radius: 4px;
+ font-size: 18px;
+ cursor: pointer;
+ margin-bottom: 10px;
+ font-family: @font-main;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: lighten(@color-accent, 10%);
+ transform: translateY(-2px);
+ }
+}
+
+.privacy {
+ display: flex;
+ gap: 8px;
+ font-size: 16px;
+ color: #666;
+ margin-bottom: 20px;
+
+ input[type="checkbox"] {
+ width: 18px;
+ height: 18px;
+ cursor: pointer;
+ }
+}
+
+.services {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 24px;
+ margin-bottom: 24px;
+
+ &__title {
+ font-family: @font-logo;
+ margin-bottom: 10px;
+ font-size: 18px;
+ color: @color-text-dark;
+ display: block;
+ width: 100%;
+ }
+
+ &__item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 8px;
+ color: @color-text-dark;
+ width: 100%;
+ }
+}
+
+.cart-icon {
+ position: relative;
+}
+
+.cart-count {
+ position: absolute;
+ top: -8px;
+ right: -8px;
+ background: @color-accent;
+ color: @color-text-light;
+ border-radius: 50%;
+ width: 18px;
+ height: 18px;
+ font-size: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.form__input.error {
+ border-color: #ff4444;
+ box-shadow: 0 0 5px rgba(255, 68, 68, 0.3);
+}
+
+.empty-cart {
+ text-align: center;
+ padding: 40px;
+ color: #666;
+ font-size: 18px;
+}
+
+// =======================
+// === АВТОРИЗАЦИЯ ===
+// =======================
+.profile-page-main {
+ .flex-center();
+ min-height: 80vh;
+ padding: 40px 0;
+ background-color: lighten(@color-secondary, 5%);
+ z-index: 1;
+
+ .profile-container {
+ display: flex;
+ width: 100%;
+ max-width: 1000px;
+ min-height: 600px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+ background-color: @color-text-light;
+ }
+
+ .profile-left-col {
+ flex: 0 0 35%;
+ background-color: @color-primary;
+ color: @color-text-light;
+ display: flex;
+ justify-content: flex-start;
+ align-items: flex-start;
+ padding: 40px;
+ .logo {
+ font-size: 32px;
+ font-weight: normal;
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.4);
+ color: @color-text-light;
+ }
+ }
+
+ .profile-right-col {
+ flex: 0 0 65%;
+ .flex-center();
+ padding: 40px;
+ .profile-form-block {
+ width: 100%;
+ max-width: 400px;
+ h2 {
+ font-size: 28px;
+ font-weight: normal;
+ margin-bottom: 40px;
+ text-align: left;
+ color: @color-text-dark;
+ }
+ }
+ }
+
+ .profile-form {
+ .input-group {
+ margin-bottom: 20px;
+ label {
+ display: block;
+ font-size: 12px;
+ font-weight: bold;
+ color: @color-text-dark;
+ margin-bottom: 5px;
+ text-transform: uppercase;
+ }
+ }
+
+ input[type="text"],
+ input[type="email"],
+ input[type="tel"] {
+ .input-base();
+ }
+
+ .password-link {
+ display: block;
+ text-align: left;
+ font-size: 13px;
+ color: @color-text-dark;
+ text-decoration: underline;
+ margin: 10px 0 20px;
+ &:hover {
+ color: @color-accent;
+ text-decoration: none;
+ }
+ }
+
+ .save-btn {
+ padding: 15px 30px;
+ border: none;
+ cursor: pointer;
+ font-size: 15px;
+ text-transform: uppercase;
+ transition: all 0.3s ease;
+ font-family: @font-main;
+ width: 100%;
+ margin-top: 20px;
+ background-color: @color-primary;
+ color: @color-text-light;
+
+ &:hover {
+ background-color: lighten(@color-primary, 10%);
+ transform: translateY(-2px);
+ box-shadow: @shadow-light;
+ }
+ }
+
+ .auth-actions {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-top: 25px;
+ padding-top: 20px;
+ border-top: 1px solid #eee;
+
+ .auth-text {
+ font-size: 13px;
+ color: @color-text-dark;
+ }
+
+ .login-btn {
+ background-color: transparent;
+ color: @color-accent;
+ border: 1px solid @color-accent;
+ padding: 10px 25px;
+ font-size: 13px;
+ cursor: pointer;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: @color-primary;
+ color: @color-text-light;
+ }
+ }
+ }
+ }
+}
+
+// =======================
+// === СЕКЦИЯ УСЛУГ ===
+// =======================
+.services-section {
+ padding: 60px 0;
+ background-color: @color-secondary;
+}
+
+.services__wrapper {
+ display: flex;
+ flex-direction: column;
+ gap: 30px;
+}
+
+.services__top-row {
+ display: flex;
+ gap: 30px;
+ justify-content: center;
+
+ @media (max-width: 768px) {
+ flex-direction: column;
+ align-items: center;
+ }
+}
+
+.service-card {
+ border-radius: 8px;
+ padding: 40px;
+ min-height: 200px;
+ text-align: center;
+ transition: all 0.3s ease;
+
+ &:hover {
+ transform: translateY(-5px);
+ box-shadow: @shadow-light;
+ }
+
+ &--green {
+ background: @color-primary;
+ color: @color-text-light;
+ flex: 1;
+ max-width: 450px;
+ }
+
+ &--beige {
+ background: @color-beige;
+ color: @color-text-light;
+ width: 100%;
+ max-width: 930px;
+ margin: 0 auto;
+ }
+
+ &__title {
+ font-family: @font-logo;
+ font-size: 24px;
+ font-weight: bold;
+ margin-bottom: 15px;
+ text-transform: uppercase;
+ }
+
+ &__text {
+ font-family: @font-main;
+ font-size: 16px;
+ line-height: 1.6;
+ margin: 0;
+ }
+}
+
+// =======================
+// === ФУТЕР ===
+// =======================
+.footer {
+ background-color: @color-primary;
+ color: black;
+ padding: 40px 0 10px;
+ position: relative;
+ z-index: 1000;
+
+ &::before {
+ content: '';
+ display: block;
+ position: absolute;
+ top: -80px;
+ left: 0;
+ width: 100%;
+ height: 1px;
+ visibility: hidden;
+ }
+
+ &__content {
+ display: flex;
+ gap: 20px;
+ padding-bottom: 30px;
+ border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+ }
+
+ &__col {
+ flex: 1;
+ &--logo { flex: 1.5; }
+ h5 {
+ margin-bottom: 15px;
+ font-size: 14px;
+ text-transform: uppercase;
+ }
+ ul li {
+ margin-bottom: 8px;
+ a:hover { text-decoration: underline; }
+ }
+ .social-icons,
+ .payment-icons {
+ .flex-center(15px);
+ justify-content: flex-start;
+ margin-top: 10px;
+ }
+ .social-icons .icon {
+ .icon-base(20px, 1.1);
+ color: black;
+ &:hover { color: @color-accent; }
+ }
+ .payment-icons .pay-icon {
+ .icon-base(24px, 1.05);
+ color: black;
+ }
+ }
+
+ .copyright {
+ text-align: center;
+ font-size: 12px;
+ padding-top: 20px;
+ color: rgba(255, 255, 255, 0.6);
+ }
+}
+
+// =======================
+// === ДОСТАВКА ===
+// =======================
+.delivery-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 40px 20px;
+}
+
+.delivery-content h1 {
+ font-family: @font-logo;
+ font-size: 42px;
+ text-align: center;
+ margin-bottom: 50px;
+ color: #453227;
+}
+
+.delivery-section {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 30px;
+ margin-bottom: 60px;
+}
+
+.delivery-card {
+ background: white;
+ padding: 30px;
+ border-radius: 12px;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ text-align: center;
+ transition: transform 0.3s ease;
+ flex: 1;
+ min-width: 350px;
+ max-width: 400px;
+}
+
+.delivery-card:hover {
+ transform: translateY(-5px);
+}
+
+.delivery-icon {
+ font-size: 48px;
+ color: #617365;
+ margin-bottom: 20px;
+}
+
+.delivery-card h3 {
+ font-family: @font-logo;
+ font-size: 24px;
+ margin-bottom: 20px;
+ color: #453227;
+}
+
+.delivery-details {
+ text-align: left;
+}
+
+.detail-item {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12px;
+ padding-bottom: 12px;
+ border-bottom: 1px solid #f0f0f0;
+}
+
+.detail-label {
+ font-weight: bold;
+ color: #333;
+}
+
+.detail-value {
+ color: #617365;
+ text-align: right;
+}
+
+// =======================
+// === ГАРАНТИЯ ===
+// =======================
+.warranty-content {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 40px 20px;
+}
+
+.warranty-content h1 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 42px;
+ text-align: center;
+ margin-bottom: 50px;
+ color: #453227;
+}
+
+.warranty-overview {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 25px;
+ margin-bottom: 60px;
+}
+
+.warranty-card {
+ background: white;
+ padding: 30px;
+ border-radius: 12px;
+ text-align: center;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ transition: transform 0.3s ease;
+ flex: 1;
+ min-width: 250px;
+ max-width: 280px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.warranty-card:hover {
+ transform: translateY(-5px);
+}
+
+.warranty-icon {
+ font-size: 48px;
+ color: #617365;
+ margin-bottom: 20px;
+}
+
+.warranty-card h3 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 20px;
+ margin-bottom: 15px;
+ color: #453227;
+}
+
+.warranty-period {
+ font-size: 24px;
+ font-weight: bold;
+ color: #617365;
+ margin-top: auto;
+}
+
+.coverage-section {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 40px;
+ margin-bottom: 60px;
+}
+
+.coverage-covered,
+.coverage-not-covered {
+ flex: 1;
+ min-width: 300px;
+}
+
+.coverage-section h2 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 24px;
+ margin-bottom: 25px;
+ color: #453227;
+}
+
+.coverage-list {
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.coverage-item {
+ display: flex;
+ align-items: flex-start;
+ gap: 15px;
+ padding: 20px;
+ border-radius: 8px;
+ background: white;
+ box-shadow: 0 3px 10px rgba(0,0,0,0.1);
+}
+
+.coverage-item.covered i {
+ color: #28a745;
+ font-size: 20px;
+ margin-top: 2px;
+ flex-shrink: 0;
+}
+
+.coverage-item.not-covered i {
+ color: #dc3545;
+ font-size: 20px;
+ margin-top: 2px;
+ flex-shrink: 0;
+}
+
+.coverage-text {
+ flex: 1;
+}
+
+.coverage-item h4 {
+ font-family: 'Anek Kannada', sans-serif;
+ font-size: 16px;
+ margin-bottom: 5px;
+ color: #333;
+}
+
+.card {
+ min-height: 250px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: @color-text-light;
+ text-align: center;
+
+ &--green {
+ background: @color-primary;
+ flex: 0 1 450px;
+ max-width: 450px;
+ }
+
+ &--beige {
+ background: @color-beige;
+ color: @color-text-dark;
+ flex: 0 1 925px;
+ max-width: 925px;
+ }
+}
+
+.design-section {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 40px;
+ .card { width: 100%; }
+}
+
+// =======================
+// === АДАПТИВНОСТЬ ===
+// =======================
+@media (max-width: 1240px) {
+ .catalog-wrapper { gap: 20px; }
+ .catalog-sidebar { flex: 0 0 200px; }
+ .products-container {
+ gap: 15px;
+ display: flex;
+ flex-wrap: wrap;
+ }
+
+ .product-card.small1 {
+ margin-top: 100px;
+ }
+
+ .product-card.small,
+ .product-card.small1,
+ .product-card.large,
+ .product-card.wide,
+ .product-card.wide1,
+ .product-card.wide2,
+ .product-card.wide2_1,
+ .product-card.wide4 {
+ flex: 0 0 calc(33.333% - 10px);
+ max-width: calc(33.333% - 10px);
+ height: 180px;
+ margin: 0;
+
+ .product-image-container {
+ height: 180px;
+ }
+ }
+
+ .product-card.wide3 {
+ flex: 0 0 calc(25% - 10px);
+ max-width: calc(25% - 10px);
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 350px;
+ }
+ }
+
+ .product-card.tall {
+ flex: 0 0 calc(25% - 10px);
+ max-width: calc(25% - 10px);
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 300px;
+ }
+ }
+
+ .product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 300px;
+ margin: 0;
+
+ .product-image-container {
+ height: 300px;
+ }
+ }
+
+ .product-card.small { order: 1; }
+ .product-card.large { order: 2; }
+ .product-card.wide { order: 3; }
+
+ .product-card.small1 { order: 11; }
+ .product-card.wide2 { order: 12; }
+ .product-card.wide2_1 { order: 13; }
+
+ .product-card.wide3 { order: 21; }
+ .product-card.tall { order: 22; }
+
+ .product-card.wide3 { order: 31; }
+
+ .product-card.full-width { order: 41; flex-basis: 100%; }
+
+ .main__content {
+ gap: 20px;
+ .products {
+ flex: 0 0 35%;
+ .products__image {
+ width: 250px;
+ height: 180px;
+ }
+ }
+ .order {
+ flex: 0 0 60%;
+ padding: 30px;
+
+ .order__title {
+ font-size: 24px;
+ }
+
+ .order__section-title {
+ font-size: 16px;
+ }
+ }
+ }
+
+ .solutions-slider {
+ &__slide {
+ .solution-text-overlay {
+ top: 10%;
+ left: 5%;
+ h2 {
+ font-size: 26px;
+ margin-bottom: 5px;
+ line-height: 1.2;
+ }
+ p {
+ font-size: 18px;
+ line-height: 1.2;
+ }
+ }
+ .solution-image-link {
+ bottom: 70px;
+ padding: 10px 25px;
+ font-size: 14px;
+ }
+ }
+ }
+
+ .product__image {
+ width: 350px;
+ height: 250px;
+ }
+
+ .product__thumbnail img {
+ width: 170px;
+ height: 120px;
+ }
+}
+
+@media (max-width: 1024px) {
+ .main__content {
+ gap: 25px;
+ .products {
+ flex: 0 0 30%;
+ .products__image {
+ width: 200px;
+ height: 150px;
+ }
+
+ .products__name {
+ font-size: 16px;
+ }
+
+ .products__price {
+ font-size: 16px;
+ }
+ }
+ .order {
+ flex: 0 0 60%;
+ padding: 25px;
+
+ .order__title {
+ font-size: 22px;
+ }
+
+ .form__input {
+ padding: 12px 14px;
+ font-size: 14px;
+ }
+
+ .promo__btn {
+ padding: 10px 40px;
+ font-size: 16px;
+ }
+ }
+ }
+}
+
+@media (max-width: 768px) {
+ .container { padding: 0 15px; }
+
+ .delivery-section {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .delivery-card {
+ min-width: 100%;
+ max-width: 100%;
+ }
+
+ .delivery-content h1 {
+ font-size: 32px;
+ }
+
+ .warranty-overview {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .warranty-card {
+ max-width: 100%;
+ width: 100%;
+ }
+
+ .coverage-section {
+ flex-direction: column;
+ }
+
+ .warranty-content h1 {
+ font-size: 32px;
+ }
+
+ .header__top .container,
+ .header__bottom .container,
+ .hero__content,
+ .advantages__header,
+ .about__content,
+ .advantages__items,
+ .promo-images,
+ .stats__items,
+ .faq__items,
+ .catalog-wrapper,
+ .main__content {
+ flex-direction: column;
+ gap: 30px;
+ }
+
+ .search-catalog {
+ order: 3;
+ width: 100%;
+ max-width: 100%;
+ }
+
+ .nav-list {
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 15px;
+ }
+
+ .hero {
+ &__image-block {
+ flex: none;
+ max-width: 400px;
+ height: 400px;
+ }
+ &__circle {
+ width: 380px;
+ height: 380px;
+ }
+ &__text-block {
+ flex: none;
+ padding-left: 0;
+ text-align: center;
+ h1 { font-size: 32px; }
+ .hero__usp-text {
+ padding-left: 0;
+ justify-content: center;
+ &::before { display: none; }
+ }
+ .btn.primary-btn { margin-left: 0; }
+ }
+ }
+
+ .advantages__header h2,
+ .faq h2 { font-size: 28px; }
+
+ .faq-item,
+ .stat-item {
+ flex: none;
+ .flex-center();
+ text-align: center;
+ }
+
+ .stats .container { justify-content: center; }
+ .catalog-dropdown__menu { width: 200px; }
+
+ .catalog-sidebar { width: 100%; flex: none; }
+ .products-container { gap: 15px; }
+
+ .product-card.small,
+ .product-card.small1,
+ .product-card.large,
+ .product-card.wide,
+ .product-card.wide1,
+ .product-card.wide2,
+ .product-card.wide2_1,
+ .product-card.wide3,
+ .product-card.wide4,
+ .product-card.tall,
+ .product-card.full-width {
+ flex: 0 0 100%;
+ max-width: 100%;
+ height: 250px;
+ margin: 0;
+
+ .product-image-container {
+ height: 200px;
+ }
+ }
+
+ .main__content {
+ flex-direction: column;
+ gap: 20px;
+
+ .products,
+ .order {
+ flex: 0 0 100%;
+ width: 100%;
+ }
+
+ .products {
+ .products__item {
+ flex-direction: column;
+ text-align: center;
+ gap: 15px;
+ }
+
+ .products__image {
+ width: 100%;
+ height: 200px;
+ justify-content: center;
+ }
+
+ .products__details {
+ min-height: auto;
+ align-items: center;
+ }
+
+ .products__controls {
+ justify-content: center;
+ margin-top: 15px;
+ }
+
+ .products__cart-icon {
+ margin-left: 0;
+ }
+ }
+
+ .order {
+ padding: 20px;
+
+ .order__title {
+ font-size: 20px;
+ text-align: center;
+ }
+
+ .order__total {
+ text-align: center;
+ }
+
+ .form__radio-group {
+ flex-direction: column;
+ gap: 15px;
+ }
+
+ .form__radio-label {
+ flex: none;
+ justify-content: flex-start;
+ }
+
+ .promo {
+ flex-direction: column;
+ gap: 10px;
+
+ &__btn {
+ width: 100%;
+ padding: 12px;
+ }
+ }
+
+ .order-btn {
+ padding: 12px;
+ font-size: 16px;
+ }
+
+ .services {
+ flex-direction: column;
+ align-items: center;
+ }
+ }
+ }
+
+ .product-image-container { height: 200px; }
+ .product-card.tall .product-image-container,
+ .product-card.large .product-image-container { height: 250px; }
+
+ .profile-page-main {
+ .profile-container {
+ flex-direction: column;
+ min-height: auto;
+ max-width: 100%;
+ box-shadow: none;
+ }
+ .profile-left-col {
+ flex: none;
+ width: 100%;
+ height: 100px;
+ .flex-center();
+ padding: 0;
+ }
+ .profile-right-col {
+ flex: none;
+ width: 100%;
+ padding: 30px 20px;
+ }
+ .profile-form-block { max-width: 100%; }
+ }
+
+ .form__row { flex-direction: column; }
+ .form__input--half { flex: 0 0 100%; max-width: 100%; }
+ .services { flex-direction: column; align-items: center; }
+
+ .services-section {
+ padding: 40px 0;
+ }
+
+ .service-card {
+ padding: 30px 20px;
+ min-height: 180px;
+
+ &--green,
+ &--beige {
+ max-width: 100%;
+ }
+
+ &__title {
+ font-size: 20px;
+ }
+
+ &__text {
+ font-size: 14px;
+ }
+ }
+ .solutions-slider {
+ margin: 20px auto;
+ &__slide {
+ .solution-text-overlay {
+ top: 8%;
+ left: 4%;
+ h2 {
+ font-size: 20px;
+ margin-bottom: 3px;
+ line-height: 1.1;
+ }
+ p {
+ font-size: 15px;
+ line-height: 1.1;
+ }
+ }
+ .solution-image-link {
+ bottom: 90px;
+ padding: 8px 20px;
+ font-size: 13px;
+ }
+ }
+ }
+}
+
+// Стили для ошибок полей
+.error-input {
+ border-color: #ff4444 !important;
+ box-shadow: 0 0 0 1px #ff4444;
+}
+
+.field-error {
+ color: #ff4444;
+ font-size: 12px;
+ margin-top: 5px;
+ margin-bottom: 10px;
+}
+
+// Стили для сообщений
+.message {
+ padding: 15px;
+ margin: 20px 0;
+ border-radius: 5px;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #2e7d32;
+ border: 1px solid #c8e6c9;
+}
+
+// Добавьте в конец файла
+.access-denied {
+ text-align: center;
+ padding: 80px 20px;
+ background: white;
+ border-radius: 10px;
+ box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+ margin: 50px 0;
+
+ h2 {
+ color: #dc3545;
+ margin-bottom: 30px;
+ font-size: 28px;
+ }
+
+ p {
+ color: #666;
+ margin-bottom: 40px;
+ font-size: 18px;
+ line-height: 1.6;
+ }
+
+ .btn {
+ margin: 5px;
+ min-width: 200px;
+ }
+}
+// =======================
+// === ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ ===
+// =======================
+
+.user-profile-dropdown {
+ position: relative;
+ display: inline-block;
+
+ &__toggle {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ cursor: pointer;
+ padding: 8px 12px;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+ }
+
+ .user-avatar {
+ width: 32px;
+ height: 32px;
+ border-radius: 50%;
+ background-color: @color-primary;
+ color: @color-text-light;
+ .flex-center();
+ font-weight: bold;
+ }
+
+ .user-info {
+ display: flex;
+ flex-direction: column;
+
+ .user-email {
+ font-size: 12px;
+ color: #666;
+ max-width: 150px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .user-status {
+ font-size: 10px;
+ padding: 2px 6px;
+ border-radius: 10px;
+ text-transform: uppercase;
+
+ &.admin {
+ background-color: #617365;
+ color: white;
+ }
+
+ &.user {
+ background-color: #28a745;
+ color: white;
+ }
+ }
+ }
+ }
+
+ &__menu {
+ .menu-base();
+ width: 220px;
+ top: 100%;
+ right: 0;
+
+ .user-details {
+ padding: 15px;
+ border-bottom: 1px solid #eee;
+
+ .user-name {
+ font-weight: bold;
+ margin-bottom: 5px;
+ }
+
+ .user-registered {
+ font-size: 11px;
+ color: #999;
+ }
+ }
+
+ ul {
+ padding: 10px 0;
+
+ li {
+ padding: 8px 15px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ transition: background-color 0.3s ease;
+
+ &:hover {
+ background-color: #f5f5f5;
+ }
+
+ &.logout {
+ color: #dc3545;
+ border-top: 1px solid #eee;
+ margin-top: 5px;
+ padding-top: 12px;
+
+ &:hover {
+ background-color: #ffe6e6;
+ }
+ }
+ }
+ }
+ }
+
+ &:hover &__menu {
+ display: block;
+ }
+}
+
+// =======================
+// === КАРТОЧКА ТОВАРА ===
+// =======================
+
+.product-image-container {
+ position: relative;
+ overflow: hidden;
+ margin-bottom: 0;
+ padding: 0;
+ height: 250px;
+ .flex-center();
+
+ &:hover {
+ .product-overlay-info {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+}
+
+.product-overlay-info {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
+ color: white;
+ padding: 15px;
+ opacity: 0;
+ transform: translateY(10px);
+ transition: all 0.3s ease;
+
+ .product-overlay-name {
+ font-weight: bold;
+ font-size: 14px;
+ margin-bottom: 5px;
+ }
+
+ .product-overlay-price {
+ font-size: 16px;
+ font-weight: bold;
+
+ .old-price {
+ text-decoration: line-through;
+ font-size: 12px;
+ color: #ccc;
+ margin-right: 5px;
+ }
+
+ .current-price {
+ color: #ffd700;
+ }
+ }
+
+ .product-overlay-category {
+ font-size: 11px;
+ opacity: 0.8;
+ margin-top: 3px;
+ }
+
+ .product-overlay-stock {
+ font-size: 11px;
+ margin-top: 5px;
+
+ &.out-of-stock {
+ color: #ff6b6b;
+ }
+
+ i {
+ margin-right: 5px;
+ }
+ }
+}
+
+.product-card-details {
+ padding: 15px;
+ background: white;
+ flex-grow: 1;
+ display: flex;
+ flex-direction: column;
+
+ .product-card-name {
+ font-weight: bold;
+ font-size: 16px;
+ margin-bottom: 8px;
+ color: @color-text-dark;
+ }
+
+ .product-card-description {
+ font-size: 13px;
+ color: #777;
+ margin-bottom: 10px;
+ flex-grow: 1;
+ }
+
+ .product-card-attributes {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ margin-bottom: 10px;
+
+ .attribute {
+ font-size: 11px;
+ background: #f5f5f5;
+ padding: 3px 8px;
+ border-radius: 12px;
+ color: #666;
+
+ i {
+ margin-right: 3px;
+ }
+ }
+ }
+
+ .product-card-price {
+ margin-bottom: 10px;
+
+ .old-price {
+ text-decoration: line-through;
+ font-size: 14px;
+ color: #999;
+ margin-right: 8px;
+ }
+
+ .current-price {
+ font-size: 18px;
+ font-weight: bold;
+ color: @color-button;
+ }
+ }
+
+ .add-to-cart-btn {
+ width: 100%;
+ padding: 8px;
+ font-size: 14px;
+ }
+
+ .admin-actions {
+ display: flex;
+ gap: 5px;
+ margin-top: 10px;
+
+ .admin-btn {
+ flex: 1;
+ font-size: 12px;
+ padding: 6px;
+
+ &.delete-btn {
+ background: #dc3545;
+
+ &:hover {
+ background: #c82333;
+ }
+ }
+ }
+ }
+}
+
+// =======================
+// === ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ ===
+// =======================
+
+.user-profile-dropdown {
+ position: relative;
+ display: inline-block;
+
+ .user-profile-toggle {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ cursor: pointer;
+ padding: 8px 12px;
+ border-radius: 4px;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+
+ .dropdown-arrow {
+ transform: rotate(180deg);
+ }
+ }
+
+ .user-avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #617365 0%, #453227 100%);
+ color: @color-text-light;
+ .flex-center();
+ font-weight: bold;
+ font-size: 16px;
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
+ }
+
+ .user-info {
+ display: flex;
+ flex-direction: column;
+
+ .user-email {
+ font-size: 12px;
+ color: #666;
+ max-width: 120px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .user-status {
+ font-size: 10px;
+ padding: 2px 8px;
+ border-radius: 12px;
+ text-transform: uppercase;
+ font-weight: bold;
+ text-align: center;
+ margin-top: 2px;
+
+ &.admin {
+ background-color: #617365;
+ color: white;
+ border: 1px solid #617365;
+ }
+
+ &.user {
+ background-color: #28a745;
+ color: white;
+ border: 1px solid #28a745;
+ }
+ }
+ }
+
+ .dropdown-arrow {
+ font-size: 10px;
+ color: #666;
+ transition: transform 0.3s ease;
+ }
+ }
+
+ .user-profile-menu {
+ .menu-base();
+ width: 280px;
+ top: 100%;
+ right: 0;
+ margin-top: 10px;
+ padding: 0;
+ overflow: hidden;
+
+ .user-profile-header {
+ padding: 20px;
+ background: linear-gradient(135deg, #617365 0%, #453227 100%);
+ color: white;
+
+ .user-profile-name {
+ font-weight: bold;
+ margin-bottom: 8px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 16px;
+ }
+
+ .user-profile-details {
+ small {
+ display: block;
+ opacity: 0.8;
+ margin-bottom: 5px;
+ font-size: 11px;
+
+ i {
+ margin-right: 5px;
+ width: 14px;
+ text-align: center;
+ }
+ }
+ }
+ }
+
+ .user-profile-links {
+ list-style: none;
+ padding: 10px 0;
+
+ li {
+ border-bottom: 1px solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+
+ a {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ padding: 12px 20px;
+ color: #333;
+ transition: all 0.3s ease;
+
+ &:hover {
+ background-color: #f8f9fa;
+ color: @color-primary;
+ text-decoration: none;
+
+ i {
+ transform: scale(1.1);
+ }
+ }
+
+ i {
+ width: 20px;
+ text-align: center;
+ font-size: 14px;
+ color: #617365;
+ transition: transform 0.3s ease;
+ }
+
+ span {
+ flex-grow: 1;
+ }
+ }
+ }
+
+ .logout-item {
+ border-top: 2px solid #f0f0f0;
+ margin-top: 5px;
+
+ a {
+ color: #dc3545;
+
+ &:hover {
+ background-color: #ffe6e6;
+ color: #c82333;
+
+ i {
+ color: #dc3545;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ &:hover .user-profile-menu {
+ display: block;
+ animation: fadeIn 0.3s ease;
+ }
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(-10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+// Для мобильных устройств
+@media (max-width: 768px) {
+ .user-profile-dropdown {
+ .user-profile-toggle {
+ .user-info {
+ display: none;
+ }
+
+ .dropdown-arrow {
+ display: none;
+ }
+ }
+
+ .user-profile-menu {
+ width: 250px;
+ right: -50px;
+ }
+ }
+}
+// Добавьте в конец файла
+.unavailable-product {
+ position: relative;
+ opacity: 0.6;
+ filter: grayscale(0.7);
+
+ &::before {
+ content: "ТОВАР ЗАКОНЧИЛСЯ";
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: rgba(0, 0, 0, 0.85);
+ color: white;
+ padding: 15px 25px;
+ border-radius: 5px;
+ font-weight: bold;
+ font-size: 16px;
+ text-align: center;
+ z-index: 100;
+ white-space: nowrap;
+ pointer-events: none;
+ box-shadow: 0 4px 12px rgba(0,0,0,0.3);
+ }
+
+ .product-name-overlay {
+ .name, .price {
+ color: #999 !important;
+ text-shadow: none !important;
+ }
+ }
+
+ .add-to-cart-btn {
+ display: none !important;
+ }
+
+ &:hover {
+ transform: none !important;
+ cursor: not-allowed;
+ }
+}
+
+.out-of-stock-badge {
+ position: absolute;
+ top: 10px;
+ left: 10px;
+ background: #6c757d;
+ color: white;
+ padding: 5px 10px;
+ border-radius: 4px;
+ font-size: 12px;
+ font-weight: bold;
+ z-index: 10;
+}
+
+// Для админ-таблицы
+.admin-table tr.unavailable {
+ background-color: #f8f9fa !important;
+ opacity: 0.7;
+
+ td {
+ color: #999;
+ }
+}
+
+.status-unavailable {
+ background-color: #6c757d !important;
+ color: white !important;
+}
\ No newline at end of file
diff --git a/OLD_CODE/uploads/products/.gitkeep b/OLD_CODE/uploads/products/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/OLD_CODE/стили_оформления.less b/OLD_CODE/стили_оформления.less
new file mode 100644
index 0000000..a6fe073
--- /dev/null
+++ b/OLD_CODE/стили_оформления.less
@@ -0,0 +1,137 @@
+.error-message {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+}
+
+.form__input.error {
+ border-color: #ff0000;
+}
+
+.form__group {
+ position: relative;
+ margin-bottom: 15px;
+}
+
+.page-messages {
+ position: fixed;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1000;
+ width: 90%;
+ max-width: 500px;
+}
+
+.message {
+ padding: 15px;
+ margin: 10px 0;
+ border-radius: 5px;
+ text-align: center;
+ font-weight: bold;
+ display: none;
+}
+
+.message.error {
+ background-color: #ffebee;
+ color: #c62828;
+ border: 1px solid #ffcdd2;
+}
+
+.message.success {
+ background-color: #e8f5e9;
+ color: #453227;
+ border: 1px solid #c8e6c9;
+}
+
+.message.warning {
+ background-color: #fff3e0;
+ color: #ef6c00;
+ border: 1px solid #ffe0b2;
+}
+
+.privacy-error {
+ color: #ff0000;
+ font-size: 12px;
+ margin-top: 5px;
+ display: none;
+ text-align: center;
+}
+
+.input-group {
+ position: relative;
+ margin-bottom: 20px;
+}
+
+.profile-form input.error {
+ border-color: #ff0000;
+ background-color: #fff5f5;
+}
+
+.privacy-checkbox {
+ margin: 20px 0;
+ text-align: center;
+}
+
+.privacy-checkbox label {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ cursor: pointer;
+ font-size: 14px;
+}
+
+.privacy-checkbox input[type="checkbox"] {
+ margin: 0;
+}
+
+.profile-page-main {
+ padding: 40px 0;
+ min-height: calc(100vh - 200px);
+}
+
+.profile-container {
+ margin: 0 auto;
+ position: relative;
+ z-index: 1;
+}
+
+.input-hint {
+ font-size: 12px;
+ color: #666;
+ margin-top: 5px;
+}
+
+.form-options {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin: 20px 0;
+}
+
+.remember-me {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ color: #453227;
+}
+
+.remember-me input[type="checkbox"] {
+ width: 16px;
+ height: 16px;
+ cursor: pointer;
+}
+
+.forgot-password {
+ font-size: 14px;
+ color: #453227;
+ text-decoration: underline;
+}
+
+.forgot-password:hover {
+ color: #617365;
+ text-decoration: none;
+}
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..01f8f79
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,30 @@
+version: '3.8'
+
+services:
+ apache:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ container_name: cite_practica_apache
+ ports:
+ - "80:80"
+ volumes:
+ # Монтируем папку public как DocumentRoot (динамическое обновление)
+ - ./public:/var/www/html/cite_practica:rw
+ # Монтируем конфигурацию для виртуальных хостов
+ - ./docker/apache/vhosts.conf:/etc/apache2/sites-available/000-default.conf:ro
+ environment:
+ - APACHE_DOCUMENT_ROOT=/var/www/html/cite_practica
+ command: >
+ bash -c "
+ echo '127.0.0.1 admin' >> /etc/hosts &&
+ apache2-foreground
+ "
+ networks:
+ - cite_practica_network
+ restart: unless-stopped
+
+networks:
+ cite_practica_network:
+ driver: bridge
+
diff --git a/docker/apache/entrypoint.sh b/docker/apache/entrypoint.sh
new file mode 100755
index 0000000..5fcc26a
--- /dev/null
+++ b/docker/apache/entrypoint.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+set -e
+
+# Включаем модули Apache
+a2enmod rewrite
+a2enmod headers
+
+# Добавляем admin в hosts
+echo "127.0.0.1 admin" >> /etc/hosts
+
+# Активируем виртуальный хост
+a2ensite 000-default
+
+# Запускаем Apache
+exec apache2-foreground
+
diff --git a/docker/apache/vhosts.conf b/docker/apache/vhosts.conf
new file mode 100644
index 0000000..919b964
--- /dev/null
+++ b/docker/apache/vhosts.conf
@@ -0,0 +1,31 @@
+
+ ServerName admin
+ ServerAlias localhost
+ DocumentRoot /var/www/html
+
+ # Alias для пути /cite_practica/
+ Alias /cite_practica /var/www/html/cite_practica
+
+
+ Options Indexes FollowSymLinks
+ AllowOverride All
+ Require all granted
+
+
+
+ Options Indexes FollowSymLinks
+ AllowOverride All
+ Require all granted
+ DirectoryIndex cite_mebel.php index.php index.html
+
+
+ # Настройка PHP
+
+ SetHandler application/x-httpd-php
+
+
+ # Логи
+ ErrorLog ${APACHE_LOG_DIR}/cite_practica_error.log
+ CustomLog ${APACHE_LOG_DIR}/cite_practica_access.log combined
+
+
diff --git a/public/admin/fix_delete_category.php b/public/admin/fix_delete_category.php
new file mode 100644
index 0000000..e48faec
--- /dev/null
+++ b/public/admin/fix_delete_category.php
@@ -0,0 +1,45 @@
+ false, 'message' => 'Доступ запрещен']);
+ exit();
+}
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $categoryId = $_POST['category_id'] ?? 0;
+
+ if (!$categoryId) {
+ echo json_encode(['success' => false, 'message' => 'Категория не указана']);
+ exit();
+ }
+
+ try {
+ $db = Database::getInstance()->getConnection();
+
+ // Проверяем, есть ли товары в этой категории
+ $checkStmt = $db->prepare("SELECT COUNT(*) FROM products WHERE category_id = ?");
+ $checkStmt->execute([$categoryId]);
+ $productCount = $checkStmt->fetchColumn();
+
+ if ($productCount > 0) {
+ echo json_encode(['success' => false, 'message' => 'Нельзя удалить категорию с товарами. Сначала удалите или переместите товары.']);
+ exit();
+ }
+
+ // Удаляем категорию
+ $stmt = $db->prepare("DELETE FROM categories WHERE category_id = ?");
+ $stmt->execute([$categoryId]);
+
+ echo json_encode(['success' => true, 'message' => 'Категория удалена']);
+ } catch (PDOException $e) {
+ echo json_encode(['success' => false, 'message' => 'Ошибка базы данных: ' . $e->getMessage()]);
+ }
+} else {
+ echo json_encode(['success' => false, 'message' => 'Неверный запрос']);
+}
+
diff --git a/public/admin/index.php b/public/admin/index.php
index 72dc1ac..379815e 100644
--- a/public/admin/index.php
+++ b/public/admin/index.php
@@ -301,6 +301,7 @@ try {
+
AETERNA - Админ-панель
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ДОБАВЬТЕ ИЗЫСКАННОСТИ В СВОЙ ИНТЕРЬЕР
+
Мы создаем мебель, которая сочетает в себе безупречный дизайн, натуральные материалы, продуманный функционал, чтобы ваш день начинался и заканчивался с комфортом.
+
+
+
ПЕРЕЙТИ В КАТАЛОГ
+
+
ПЕРЕЙТИ В КАТАЛОГ
+
+
+
+
+
+
+
+
+
+
+
+
О НАС
+
Компания AETERNA - российский производитель качественной корпусной и мягкой мебели для дома и офиса. С 2015 года мы успешно реализуем проекты любой сложности, сочетая современные технологии, проверенные материалы и классическое мастерство.
+
+
+
+
+
+
+
Наша сеть включает 30+ российских фабрик, отобранных по строгим стандартам качества. Мы сотрудничаем исключительно с лидерами рынка, чья продукция доказала свое превосходство временем.
+
+
+
+
+
+
+
+
+
+
+
+
ГОТОВОЕ РЕШЕНИЕ ДЛЯ ВАШЕЙ ГОСТИНОЙ
+
УСПЕЙТЕ ЗАКАЗАТЬ СЕЙЧАС
+
+
Подробнее
+
+
+
+
+
+
ГОТОВОЕ РЕШЕНИЕ ДЛЯ ВАШЕЙ СПАЛЬНИ
+
УСПЕЙТЕ ЗАКАЗАТЬ СЕЙЧАС
+
+
Подробнее
+
+
+
+
+
+
+
+
+
+
+
+
30 000+
+
Довольных покупателей
+
+
+
4500+
+
Реализованных заказов
+
+
+
+
+
+
+
+
ОТВЕТЫ НА ВОПРОСЫ
+
+
+
1
+
+
Сколько времени занимает доставка?
+
Доставка готовых позиций занимает 1-3 дня. Мебель на заказ изготавливается от 14 до 45 рабочих дней, в зависимости от сложности. Точные сроки озвучит ваш менеджер при оформлении заказа.
+
+
+
+
2
+
+
Нужно ли вносить предоплату?
+
Да, для запуска заказа в производство необходима предоплата в размере 50-70% от стоимости, в зависимости от изделия. Оставшаяся сумма оплачивается при доставке и приемке мебели.
+
+
+
+
3
+
+
Предоставляется ли рассрочка или кредит?
+
Да, мы сотрудничаем с несколькими банками и предлагаем рассрочку на 6 или 12 месяцев без первоначального взноса, а также кредит на более длительный срок. Все условия уточняйте у вашего менеджера.
+
+
+
+
4
+
+
Что делать, если мебель пришла с дефектом?
+
В этом случае необходимо в течение 7 дней со дня доставки сообщить нам о проблеме, прислать фото/видео дефекта. Мы оперативно решим вопрос о бесплатной замене или ремонте изделия.
+
+
+
+
Задать вопрос
+
+
+
+
+
+
+
+
+
+
+
+ Быстрый вход
+
+
+
+ Войти как Администратор
+
+
+ Войти как Пользователь
+
+
+
+ Для полного функционала перейдите на страницу входа
+
+
+
+
+
+
+
+
+
+
+
+
+
Быстрый вход:
+
+ Войти в аккаунт
+
+
+
+
+
+