From a34c9f07a728fd0ea12bb2ad43a8841957cd235e Mon Sep 17 00:00:00 2001 From: root Date: Sun, 5 Jul 2026 14:42:58 +0000 Subject: [PATCH] Revert "UI redesign: CS2 gambling aesthetic, glassmorphism, responsive layout, enhanced sounds, admin panel overhaul" This reverts commit 4b0fc594b44260f6b0d0405ee4cae69afc89f85c. --- static/css/style.css | 4938 ++++++++++++++++++++++++++---- static/js/app.js | 233 +- static/js/sounds.js | 522 ++-- templates/_activity_sidebar.html | 255 +- templates/achievements.html | 327 +- templates/activity.html | 246 +- templates/admin/base.html | 410 ++- templates/admin/cases.html | 246 +- templates/admin/dashboard.html | 6 +- templates/admin/user_detail.html | 87 +- templates/admin/users.html | 37 +- templates/case_detail.html | 1118 +++---- templates/cases.html | 268 +- templates/contracts.html | 753 +++-- templates/crash.html | 532 +++- templates/index.html | 45 +- templates/inventory.html | 781 +++-- templates/login.html | 52 +- templates/profile.html | 130 +- templates/register.html | 56 +- templates/upgrade.html | 819 +++-- 21 files changed, 9157 insertions(+), 2704 deletions(-) diff --git a/static/css/style.css b/static/css/style.css index f7b1662..9137fdc 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -3,599 +3,4487 @@ *, *::before, *::after { margin:0; padding:0; box-sizing:border-box; } :root { - --primary: #f59e0b; - --primary-hover: #d97706; - --primary-glow: rgba(245,158,11,0.35); - --primary-subtle: rgba(245,158,11,0.12); - --success: #22c55e; - --danger: #ef4444; - --info: #3b82f6; - --warning: #f59e0b; - --bg-deep: #07080b; - --bg-dark: #0b0d12; - --bg-card: #111318; - --bg-surface: #181b24; - --bg-elevated: #1e2230; - --bg-hover: rgba(255,255,255,0.04); - --text: #e8e6e3; - --text-dim: #9498a8; - --text-muted: #5c6070; - --border: rgba(255,255,255,0.06); - --border-light: rgba(255,255,255,0.10); - --shadow-sm: 0 1px 3px rgba(0,0,0,0.3); - --shadow-md: 0 4px 12px rgba(0,0,0,0.4); - --shadow-lg: 0 8px 32px rgba(0,0,0,0.5); - --shadow-xl: 0 16px 48px rgba(0,0,0,0.6); - --radius-sm: 6px; - --radius-md: 10px; - --radius-lg: 14px; - --radius-xl: 18px; - --transition: 0.2s cubic-bezier(0.4,0,0.2,1); - --transition-slow: 0.4s cubic-bezier(0.4,0,0.2,1); - --font-display: 'Russo One', sans-serif; - --font-body: 'Rajdhani', sans-serif; - --rarity-consumer: #b0b0b0; - --rarity-industrial: #5e98d9; - --rarity-mil-spec: #4b69ff; - --rarity-restricted: #8847ff; - --rarity-classified: #d32ce6; - --rarity-covert: #eb4b4b; - --rarity-rare-special: #ffd700; - --rarity-extraordinary: #ffd700; - --z-dropdown: 100; - --z-sticky: 200; - --z-overlay: 300; - --z-modal: 400; - --z-toast: 500; - --z-tooltip: 600; + --primary: #f59e0b; + --primary-hover: #d97706; + --primary-glow: rgba(245,158,11,0.25); + --success: #10b981; + --danger: #ef4444; + --warning: #f59e0b; + --bg-deep: #08090d; + --bg-dark: #0b0c10; + --bg-card: #13141a; + --bg-surface: #1a1b23; + --bg-elevated: #21222c; + --text: #e8e6e3; + --text-dim: #8a8a9a; + --text-muted: #5a5a6a; + --border: rgba(255,255,255,0.06); + --border-light: rgba(255,255,255,0.1); + + --rarity-consumer: #b0b0b0; + --rarity-industrial: #5e98d9; + --rarity-mil-spec: #4b69ff; + --rarity-restricted: #8847ff; + --rarity-classified: #d32ce6; + --rarity-covert: #eb4b4b; + --rarity-rare-special: #ffd700; + --rarity-extraordinary: #ffd700; + --rarity-contraband: #ffaa00; + + /* backwards compat */ + --primary-color: var(--primary); + --primary-hover: #d97706; + --success-color: var(--success); + --danger-color: var(--danger); + --warning-color: var(--warning); + --bg-dark: var(--bg-deep); + --bg-card: #13141a; + --bg-light: var(--bg-surface); + --text-primary: var(--text); + --text-secondary: var(--text-dim); + --border-color: var(--border); + + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; + --radius-xl: 20px; + + --transition: 0.2s cubic-bezier(0.4,0,0.2,1); } body { - font-family: var(--font-body); - background: var(--bg-deep); - color: var(--text); - line-height: 1.6; - min-height: 100vh; - overflow-x: hidden; - -webkit-font-smoothing: antialiased; + font-family: 'Rajdhani', sans-serif; + background: var(--bg-deep); + color: var(--text); + line-height: 1.6; + min-height: 100vh; + overflow-x: hidden; } -h1, h2, h3, h4, h5, h6, .logo, .nav-link, .btn, .display-font { - font-family: var(--font-display); - letter-spacing: 0.03em; +h1, h2, h3, h4, h5, h6, .logo, .nav-link, .btn { + font-family: 'Russo One', sans-serif; + letter-spacing: 0.03em; } ::selection { background: var(--primary); color: #000; } -::-webkit-scrollbar { width: 5px; height: 5px; } +::-webkit-scrollbar { width: 5px; } ::-webkit-scrollbar-track { background: transparent; } -::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.1); border-radius: 3px; } -::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.2); } +::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: var(--text-muted); } -.container { max-width: 1200px; margin: 0 auto; padding: 0 20px; width: 100%; } +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 20px; + width: 100%; +} -/* ── Navbar ── */ +/* Навигация */ .navbar { - background: rgba(7,8,11,0.92); - backdrop-filter: blur(16px); - -webkit-backdrop-filter: blur(16px); - border-bottom: 1px solid var(--border); - padding: 0.6rem 0; - position: sticky; - top: 0; - z-index: var(--z-sticky); + background: rgba(11,12,16,0.85); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-bottom: 1px solid var(--border); + padding: 0.7rem 0; + position: sticky; + top: 0; + z-index: 100; } -.navbar .container { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; } + +.navbar .container { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 0.5rem; +} + .logo { - font-size: 1.15rem; font-weight: 700; color: var(--text); - text-decoration: none; text-transform: uppercase; letter-spacing: 0.08em; - display: flex; align-items: center; gap: 0.4rem; white-space: nowrap; + font-size: 1.2rem; + font-weight: 700; + color: var(--text); + text-decoration: none; + text-transform: uppercase; + letter-spacing: 0.08em; } -.logo span { color: var(--primary); } -.logo:hover { opacity: 0.85; } -.nav-links { display: flex; align-items: center; gap: 0.15rem; flex-wrap: wrap; } + +.logo:hover { + color: var(--primary-color); +} + +.nav-links { + display: flex; + align-items: center; + gap: 0.25rem; + flex-wrap: wrap; +} + .nav-link { - color: var(--text-dim); text-decoration: none; - padding: 0.4rem 0.7rem; border-radius: var(--radius-sm); - transition: all var(--transition); font-size: 0.78rem; - text-transform: uppercase; letter-spacing: 0.06em; font-weight: 500; - white-space: nowrap; position: relative; + color: var(--text-secondary); + text-decoration: none; + padding: 0.4rem 0.65rem; + border-radius: 6px; + transition: all 0.2s; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.06em; + font-weight: 500; } -.nav-link::after { - content: ''; position: absolute; bottom: 2px; left: 50%; transform: translateX(-50%) scaleX(0); - width: 60%; height: 2px; background: var(--primary); border-radius: 1px; - transition: transform var(--transition); + +.nav-link:hover { + color: var(--text-primary); + background: rgba(255,255,255,0.04); } -.nav-link:hover { color: var(--text); background: var(--bg-hover); } -.nav-link:hover::after { transform: translateX(-50%) scaleX(1); } -.nav-link.active { color: #000; background: var(--primary); font-weight: 600; } -.nav-link.active::after { display: none; } + +.nav-link.active { + color: #000; + background: var(--primary); + font-weight: 600; + box-shadow: 0 0 12px var(--primary-glow); +} + .user-balance { - padding: 0.35rem 0.7rem; background: rgba(0,0,0,0.3); - border: 1px solid rgba(245,158,11,0.25); border-radius: var(--radius-sm); - font-weight: 600; color: var(--primary); font-size: 0.8rem; - font-family: var(--font-body); white-space: nowrap; - display: flex; align-items: center; gap: 0.3rem; -} -.user-balance::before { content: '⟠'; font-size: 0.7rem; } -.mobile-toggle { display: none; background: none; border: none; color: var(--text); font-size: 1.3rem; cursor: pointer; padding: 0.3rem; } - -@media (max-width: 768px) { - .mobile-toggle { display: block; } - .nav-links { - display: none; position: absolute; top: 100%; left: 0; right: 0; - background: rgba(7,8,11,0.98); backdrop-filter: blur(16px); - flex-direction: column; padding: 0.5rem; border-bottom: 1px solid var(--border); - gap: 0.15rem; z-index: var(--z-dropdown); - } - .nav-links.open { display: flex; } - .nav-link { width: 100%; padding: 0.6rem 0.8rem; } - .nav-links .btn, .nav-links .user-balance { width: 100%; justify-content: center; } - .navbar .container { position: relative; } + padding: 0.4rem 0.65rem; + background: rgba(0,0,0,0.3); + border: 1px solid rgba(245, 158, 11, 0.2); + border-radius: 6px; + font-weight: 600; + color: var(--primary-color); + font-size: 0.8rem; + font-family: 'Rajdhani', sans-serif; } -/* ── Buttons ── */ +/* Кнопки */ .btn { - padding: 0.5rem 1.1rem; border: none; border-radius: var(--radius-sm); - font-size: 0.78rem; font-weight: 600; cursor: pointer; - text-decoration: none; display: inline-flex; align-items: center; - gap: 0.4rem; transition: all var(--transition); white-space: nowrap; - text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.2; - position: relative; overflow: hidden; + padding: 0.5rem 1.1rem; + border: none; + border-radius: var(--radius-sm); + font-size: 0.78rem; + font-weight: 600; + cursor: pointer; + text-decoration: none; + display: inline-flex; + align-items: center; + gap: 0.35rem; + transition: all var(--transition); + white-space: nowrap; + text-transform: uppercase; + letter-spacing: 0.06em; + line-height: 1.2; } -.btn::after { content: ''; position: absolute; inset: 0; background: rgba(255,255,255,0); transition: background var(--transition); } -.btn:hover::after { background: rgba(255,255,255,0.08); } -.btn:active::after { background: rgba(255,255,255,0.12); } + .btn-primary { - background: linear-gradient(135deg, var(--primary), #d97706); color: #000; - box-shadow: 0 2px 12px var(--primary-glow); + background: linear-gradient(135deg, var(--primary), #d97706); + color: #000; } -.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 4px 20px rgba(245,158,11,0.4); } -.btn-primary:disabled { opacity: 0.35; cursor: not-allowed; transform: none; box-shadow: none; background: var(--text-muted); color: var(--text-dim); } + +.btn-primary:hover { + transform: translateY(-1px); + box-shadow: 0 4px 20px var(--primary-glow); +} + +.btn-primary:disabled { + opacity: 0.3; + cursor: not-allowed; + transform: none; + box-shadow: none; +} + .btn-outline { - background: transparent; color: var(--text-dim); border: 1px solid var(--border-light); -} -.btn-outline:hover { color: var(--text); border-color: rgba(255,255,255,0.18); background: var(--bg-hover); } -.btn-ghost { background: transparent; color: var(--text-dim); border: none; } -.btn-ghost:hover { color: var(--text); background: var(--bg-hover); } -.btn-success { background: var(--success); color: #000; } -.btn-success:hover { box-shadow: 0 4px 15px rgba(34,197,94,0.3); transform: translateY(-1px); } -.btn-danger { background: var(--danger); color: #fff; } -.btn-danger:hover { box-shadow: 0 4px 15px rgba(239,68,68,0.3); transform: translateY(-1px); } -.btn-large { padding: 0.65rem 2rem; font-size: 0.9rem; } -.btn-sm { padding: 0.3rem 0.65rem; font-size: 0.7rem; } -.btn-block { width: 100%; justify-content: center; } -.btn-icon { - width: 36px; height: 36px; padding: 0; display: flex; - align-items: center; justify-content: center; font-size: 1rem; - background: var(--primary-subtle); border: 1px solid rgba(245,158,11,0.2); - color: var(--primary); border-radius: var(--radius-sm); cursor: pointer; - transition: all var(--transition); flex-shrink: 0; -} -.btn-icon:hover { background: rgba(245,158,11,0.2); border-color: rgba(245,158,11,0.35); transform: scale(1.05); } -.btn-icon:disabled { opacity: 0.3; cursor: not-allowed; transform: none; } - -/* ── Cards ── */ -.card { - background: var(--bg-card); - border: 1px solid var(--border); - border-radius: var(--radius-md); - padding: 1.25rem; - transition: all var(--transition); -} -.card:hover { border-color: rgba(255,255,255,0.08); } -.card-hover:hover { - transform: translateY(-2px); - box-shadow: var(--shadow-md); - border-color: rgba(245,158,11,0.15); -} -.card-glass { - background: rgba(17,19,24,0.7); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid rgba(255,255,255,0.06); -} -.card-glow { position: relative; overflow: hidden; } -.card-glow::before { - content: ''; position: absolute; top: -50%; left: -50%; width: 200%; height: 200%; - background: conic-gradient(from 0deg, transparent, var(--primary-glow), transparent, transparent); - animation: glowRotate 4s linear infinite; opacity: 0; transition: opacity var(--transition-slow); -} -.card-glow:hover::before { opacity: 1; } -.card-glow > * { position: relative; z-index: 1; } -@keyframes glowRotate { to { transform: rotate(360deg); } } - -/* ── Forms ── */ -.form-group { margin-bottom: 1rem; } -.form-label { - display: block; font-size: 0.8rem; font-weight: 600; color: var(--text-dim); - margin-bottom: 0.35rem; text-transform: uppercase; letter-spacing: 0.05em; -} -.form-input, .form-select, .form-textarea { - width: 100%; padding: 0.55rem 0.8rem; font-size: 0.9rem; - background: var(--bg-dark); border: 1px solid var(--border-light); - border-radius: var(--radius-sm); color: var(--text); - font-family: var(--font-body); transition: border-color var(--transition), box-shadow var(--transition); - outline: none; -} -.form-input:focus, .form-select:focus, .form-textarea:focus { - border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-glow); -} -.form-input::placeholder { color: var(--text-muted); } -.form-error { color: var(--danger); font-size: 0.8rem; margin-top: 0.25rem; } -.form-hint { color: var(--text-muted); font-size: 0.78rem; margin-top: 0.2rem; } -.form-checkbox { - display: flex; align-items: center; gap: 0.5rem; cursor: pointer; - font-size: 0.9rem; -} -.form-checkbox input[type="checkbox"] { - width: 18px; height: 18px; accent-color: var(--primary); cursor: pointer; + background: transparent; + color: var(--text-dim); + border: 1px solid var(--border); } -/* ── Grids ── */ -.grid { display: grid; gap: 1rem; } -.grid-2 { grid-template-columns: repeat(2, 1fr); } -.grid-3 { grid-template-columns: repeat(3, 1fr); } -.grid-4 { grid-template-columns: repeat(4, 1fr); } -.grid-auto { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); } -.grid-auto-sm { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); } -@media (max-width: 768px) { - .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; } +.btn-outline:hover { + color: var(--text-primary); + border-color: rgba(255,255,255,0.12); + background: rgba(255,255,255,0.03); } -/* ── Hero ── */ +.btn-large { + padding: 0.65rem 2rem; + font-size: 0.95rem; +} + +.btn-block { + width: 100%; +} + +.btn-fast { + width: 40px; + height: 40px; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.1rem; + background: rgba(245,158,11,0.1); + border: 1px solid rgba(245,158,11,0.25); + color: #f59e0b; + border-radius: 8px; + cursor: pointer; + transition: background 0.2s, border-color 0.2s, transform 0.15s; + flex-shrink: 0; +} +.btn-fast:hover:not(:disabled) { + background: rgba(245,158,11,0.2); + border-color: rgba(245,158,11,0.4); + transform: scale(1.05); +} +.btn-fast:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.btn-sm { + padding: 0.25rem 0.65rem; + font-size: 0.7rem; +} + +.btn-success { + background: var(--success-color); + color: #0a0b0e; + border: none; +} + +.btn-success:hover { + background: #059669; + box-shadow: 0 4px 15px rgba(16, 185, 129, 0.25); +} + +/* Главная страница */ .hero { - padding: 4rem 0; text-align: center; - position: relative; overflow: hidden; + padding: 4rem 0; + text-align: center; + position: relative; } + .hero::before { - content: ''; position: absolute; top: -40%; left: 50%; transform: translateX(-50%); - width: 700px; height: 700px; - background: radial-gradient(circle, rgba(245,158,11,0.05) 0%, transparent 65%); - pointer-events: none; + content: ''; + position: absolute; + top: -50%; + left: 50%; + transform: translateX(-50%); + width: 600px; + height: 600px; + background: radial-gradient(circle, rgba(245, 158, 11, 0.04) 0%, transparent 70%); + pointer-events: none; } + .hero h1 { - font-size: clamp(2rem, 5vw, 3.5rem); margin-bottom: 0.75rem; - background: linear-gradient(135deg, var(--primary), #fbbf24); - -webkit-background-clip: text; -webkit-text-fill-color: transparent; - background-clip: text; position: relative; text-wrap: balance; + font-size: 3rem; + margin-bottom: 1rem; + background: linear-gradient(135deg, var(--primary-color), #d97706); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + position: relative; } + .hero-subtitle { - font-size: clamp(1rem, 2.5vw, 1.3rem); color: var(--text-dim); - margin-bottom: 2.5rem; position: relative; -} -.hero-actions { display: flex; gap: 0.75rem; justify-content: center; flex-wrap: wrap; } - -/* ── Section ── */ -.section { padding: 2.5rem 0; } -.section-title { - font-size: 1.5rem; margin-bottom: 0.3rem; text-wrap: balance; -} -.section-subtitle { color: var(--text-dim); font-size: 0.95rem; margin-bottom: 1.5rem; } -.section-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.25rem; flex-wrap: wrap; gap: 0.75rem; } -.section-tabs { - display: flex; gap: 0.25rem; flex-wrap: wrap; - padding: 0.25rem; background: var(--bg-dark); border-radius: var(--radius-sm); -} -.section-tab { - padding: 0.35rem 0.8rem; border: none; background: transparent; - color: var(--text-dim); font-size: 0.78rem; font-weight: 500; - cursor: pointer; border-radius: 4px; transition: all var(--transition); - font-family: var(--font-body); text-transform: uppercase; letter-spacing: 0.04em; -} -.section-tab:hover { color: var(--text); background: var(--bg-hover); } -.section-tab.active { background: var(--primary); color: #000; font-weight: 600; } - -/* ── Case Card ── */ -.case-card { - background: var(--bg-card); - border: 1px solid var(--border); - border-radius: var(--radius-md); - overflow: hidden; - transition: all var(--transition-slow); - cursor: pointer; - position: relative; -} -.case-card:hover { - transform: translateY(-4px); - box-shadow: 0 8px 30px rgba(0,0,0,0.5); - border-color: rgba(245,158,11,0.2); -} -.case-card-image { - width: 100%; aspect-ratio: 1; object-fit: contain; - padding: 1.5rem; background: linear-gradient(135deg, var(--bg-dark) 0%, var(--bg-card) 100%); - display: flex; align-items: center; justify-content: center; - position: relative; -} -.case-card-image img { max-width: 85%; max-height: 85%; transition: transform var(--transition-slow); filter: drop-shadow(0 4px 8px rgba(0,0,0,0.4)); } -.case-card:hover .case-card-image img { transform: scale(1.08) rotate(-3deg); } -.case-card-body { padding: 0.85rem 1rem; } -.case-card-name { font-family: var(--font-display); font-size: 0.9rem; margin-bottom: 0.2rem; } -.case-card-desc { color: var(--text-dim); font-size: 0.8rem; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } -.case-card-footer { - display: flex; align-items: center; justify-content: space-between; - padding: 0.65rem 1rem; border-top: 1px solid var(--border); -} -.case-card-price { - font-family: var(--font-display); font-size: 0.95rem; color: var(--primary); - display: flex; align-items: center; gap: 0.3rem; -} -.case-card-price span { font-size: 0.7rem; color: var(--text-muted); font-family: var(--font-body); } -.case-card-rarity { - display: flex; gap: 3px; -} -.case-card-rarity-dot { - width: 8px; height: 8px; border-radius: 50%; opacity: 0.6; + font-size: 1.25rem; + color: var(--text-secondary); + margin-bottom: 3rem; + position: relative; } -/* ── Modal ── */ -.modal-overlay { - position: fixed; inset: 0; background: rgba(0,0,0,0.7); - backdrop-filter: blur(4px); z-index: var(--z-overlay); - display: flex; align-items: center; justify-content: center; - animation: fadeIn 0.2s ease; padding: 1rem; -} -@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } -.modal { - background: var(--bg-surface); border: 1px solid var(--border-light); - border-radius: var(--radius-lg); width: 100%; max-width: 500px; - max-height: 90vh; overflow-y: auto; - animation: modalSlideIn 0.25s ease; box-shadow: var(--shadow-xl); -} -@keyframes modalSlideIn { from { transform: translateY(20px) scale(0.97); opacity: 0; } to { transform: translateY(0) scale(1); opacity: 1; } } -.modal-header { - display: flex; align-items: center; justify-content: space-between; - padding: 1rem 1.25rem; border-bottom: 1px solid var(--border); -} -.modal-title { font-family: var(--font-display); font-size: 1rem; } -.modal-close { - background: none; border: none; color: var(--text-dim); font-size: 1.3rem; - cursor: pointer; padding: 0.2rem; line-height: 1; transition: color var(--transition); -} -.modal-close:hover { color: var(--text); } -.modal-body { padding: 1.25rem; } -.modal-footer { - display: flex; align-items: center; justify-content: flex-end; gap: 0.5rem; - padding: 1rem 1.25rem; border-top: 1px solid var(--border); +.features { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin: 3rem 0; } -/* ── Table ── */ -.table-wrap { overflow-x: auto; } -table { - width: 100%; border-collapse: collapse; font-size: 0.85rem; +.feature-card { + background: var(--bg-card); + padding: 1.75rem 1.5rem; + border-radius: 10px; + text-align: center; + border: 1px solid var(--border-color); + transition: all 0.25s; } -th, td { - padding: 0.6rem 0.8rem; text-align: left; border-bottom: 1px solid var(--border); - white-space: nowrap; -} -th { - color: var(--text-dim); font-weight: 600; text-transform: uppercase; - letter-spacing: 0.05em; font-size: 0.72rem; -} -tr:hover td { background: var(--bg-hover); } -/* ── Badge ── */ -.badge { - display: inline-flex; align-items: center; gap: 0.25rem; - padding: 0.15rem 0.5rem; border-radius: 4px; - font-size: 0.7rem; font-weight: 600; text-transform: uppercase; - letter-spacing: 0.03em; +.feature-card:hover { + border-color: rgba(245, 158, 11, 0.15); + transform: translateY(-2px); + box-shadow: 0 8px 30px rgba(0,0,0,0.3); +} + +.feature-icon { + font-size: 2.5rem; + margin-bottom: 0.75rem; +} + +.feature-card h3 { + margin-bottom: 0.5rem; + font-size: 0.95rem; + text-transform: uppercase; + letter-spacing: 0.06em; +} + +.feature-card p { + color: var(--text-secondary); + font-size: 0.85rem; +} + +.hero-actions { + display: flex; + gap: 0.75rem; + justify-content: center; + margin-top: 2rem; +} + +/* Карточка профиля */ +.profile-card, +.auth-card, +.page-card { + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + border-radius: 10px; + padding: 1.5rem; + backdrop-filter: blur(8px); +} + +.form-input { + width: 100%; + padding: 0.55rem 0.7rem; + background: rgba(0,0,0,0.3); + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-primary); + font-size: 0.9rem; + font-family: 'Rajdhani', sans-serif; + outline: none; + transition: border-color 0.2s; + box-sizing: border-box; +} + +.form-input:focus { + border-color: rgba(245, 158, 11, 0.3); +} + +.form-label { + font-size: 0.8rem; + color: var(--text-secondary); + margin-bottom: 0.3rem; + display: block; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.stat-value { + font-family: 'Russo One', sans-serif; + color: var(--primary-color); +} + +/* Формы авторизации */ +.auth-container { + display: flex; + align-items: center; + justify-content: center; + min-height: calc(100vh - 73px); + padding: 2rem; +} + +.auth-card { + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + padding: 2rem; + border-radius: 10px; + width: 100%; + max-width: 400px; + backdrop-filter: blur(8px); +} + +.auth-card h2 { + text-align: center; + margin-bottom: 1.5rem; + font-size: 1.25rem; + text-transform: uppercase; + letter-spacing: 0.06em; +} + +.auth-form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.form-group { + display: flex; + flex-direction: column; + gap: 0.3rem; +} + +.form-group label { + font-weight: 600; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--text-secondary); +} + +.form-group input { + padding: 0.55rem 0.7rem; + background: rgba(0,0,0,0.3); + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-primary); + font-size: 0.9rem; + font-family: 'Rajdhani', sans-serif; + outline: none; + transition: border-color 0.2s; +} + +.form-group input:focus { + border-color: rgba(245, 158, 11, 0.3); +} + +.form-group small { + color: var(--text-secondary); + font-size: 0.75rem; +} + +.error-message { + background: rgba(239, 68, 68, 0.08); + border: 1px solid rgba(239, 68, 68, 0.3); + color: var(--danger-color); + padding: 0.6rem 0.75rem; + border-radius: 6px; + text-align: center; + font-size: 0.85rem; +} + +.auth-footer { + text-align: center; + margin-top: 1.25rem; + color: var(--text-secondary); + font-size: 0.85rem; +} + +.auth-footer a { + color: var(--primary-color); + text-decoration: none; + font-weight: 600; +} + +.auth-footer a:hover { + text-decoration: underline; +} + +/* Профиль */ +.profile-container { + padding: 2rem 0; +} + +.profile-header { + margin-bottom: 2rem; +} + +.profile-header h1 { + font-size: 2rem; + margin-bottom: 0.5rem; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +.profile-subtitle { + color: var(--text-secondary); + font-size: 0.9rem; +} + +.stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-bottom: 2rem; } -.badge-yellow { background: rgba(245,158,11,0.15); color: var(--primary); } -.badge-green { background: rgba(34,197,94,0.15); color: var(--success); } -.badge-red { background: rgba(239,68,68,0.15); color: var(--danger); } -.badge-blue { background: rgba(59,130,246,0.15); color: var(--info); } -.badge-purple { background: rgba(136,71,255,0.15); color: #a78bfa; } -/* ── Stats ── */ -.stats-grid { display: grid; gap: 0.75rem; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); } .stat-card { - background: var(--bg-card); border: 1px solid var(--border); - border-radius: var(--radius-md); padding: 1rem 1.15rem; + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + padding: 1.25rem 1rem; + border-radius: 10px; + text-align: center; + transition: border-color 0.2s; } -.stat-value { font-family: var(--font-display); font-size: 1.4rem; color: var(--primary); } -.stat-label { font-size: 0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; margin-top: 0.15rem; } -/* ── Filters ── */ -.filter-bar { - display: flex; gap: 0.5rem; flex-wrap: wrap; align-items: center; - padding: 0.75rem; background: var(--bg-dark); border-radius: var(--radius-md); - margin-bottom: 1rem; +.stat-card:hover { + border-color: rgba(245, 158, 11, 0.12); } -.filter-bar .form-input { width: auto; min-width: 160px; flex: 1; } -.filter-chip { - padding: 0.25rem 0.65rem; background: transparent; border: 1px solid var(--border-light); - color: var(--text-dim); border-radius: 4px; font-size: 0.75rem; cursor: pointer; - transition: all var(--transition); font-family: var(--font-body); -} -.filter-chip:hover { border-color: rgba(255,255,255,0.2); color: var(--text); } -.filter-chip.active { background: var(--primary-subtle); border-color: var(--primary); color: var(--primary); } -/* ── Loading ── */ -.spinner { - width: 32px; height: 32px; border: 3px solid var(--border); - border-top-color: var(--primary); border-radius: 50%; - animation: spin 0.7s linear infinite; +.stat-value { + font-size: 1.75rem; + font-weight: 700; + color: var(--primary-color); + font-family: 'Russo One', sans-serif; } -@keyframes spin { to { transform: rotate(360deg); } } -.spinner-sm { width: 18px; height: 18px; border-width: 2px; } -.loading-dots { display: flex; gap: 4px; align-items: center; } -.loading-dots span { - width: 6px; height: 6px; border-radius: 50%; background: var(--primary); - animation: dotBounce 1.2s ease-in-out infinite; -} -.loading-dots span:nth-child(2) { animation-delay: 0.15s; } -.loading-dots span:nth-child(3) { animation-delay: 0.3s; } -@keyframes dotBounce { 0%,80%,100% { transform: scale(0.5); opacity: 0.5; } 40% { transform: scale(1); opacity: 1; } } -/* ── Toast / Notification ── */ -.toast-container { - position: fixed; top: 1rem; right: 1rem; z-index: var(--z-toast); - display: flex; flex-direction: column; gap: 0.5rem; pointer-events: none; +.stat-label { + color: var(--text-secondary); + margin-top: 0.35rem; + font-size: 0.8rem; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.profile-sections { + display: grid; + gap: 2rem; +} + +.section h2 { + margin-bottom: 1rem; + font-size: 1rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: #c8c6d0; +} + +.items-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 0.75rem; +} + +.item-card { + background: rgba(14, 15, 19, 0.9); + padding: 0.75rem 0.85rem; + border-radius: 8px; + border-left: 3px solid; + border: 1px solid var(--border-color); + border-left-width: 3px; + transition: border-color 0.2s; +} + +.item-card:hover { + border-color: rgba(255,255,255,0.08); + border-left-width: 4px; +} + +.item-name { + font-weight: 600; + margin-bottom: 0.35rem; + word-break: break-word; + font-size: 0.8rem; +} + +.item-details { + display: flex; + justify-content: space-between; + font-size: 0.7rem; + color: var(--text-secondary); +} + +.history-list { + display: flex; + flex-direction: column; + gap: 0.4rem; +} + +.history-item { + background: rgba(14, 15, 19, 0.9); + border: 1px solid var(--border-color); + padding: 0.75rem 0.85rem; + border-radius: 8px; + display: flex; + align-items: center; + gap: 0.75rem; + transition: border-color 0.2s; +} + +.history-item:hover { + border-color: rgba(255,255,255,0.08); +} + +.history-icon { + font-size: 1.25rem; + flex-shrink: 0; +} + +.history-content { + flex: 1; + min-width: 0; +} + +.history-title { + font-weight: 600; + margin-bottom: 0.2rem; + font-size: 0.85rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.history-meta { + display: flex; + gap: 0.75rem; + font-size: 0.7rem; + color: var(--text-secondary); + flex-wrap: wrap; } -.toast { - pointer-events: auto; padding: 0.65rem 1rem; border-radius: var(--radius-sm); - background: var(--bg-surface); border: 1px solid var(--border-light); - box-shadow: var(--shadow-lg); font-size: 0.85rem; - display: flex; align-items: center; gap: 0.5rem; - animation: toastIn 0.25s ease; max-width: 360px; -} -@keyframes toastIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } -.toast-success { border-left: 3px solid var(--success); } -.toast-error { border-left: 3px solid var(--danger); } -.toast-info { border-left: 3px solid var(--info); } -.toast-warning { border-left: 3px solid var(--warning); } -/* ── Empty state ── */ .empty-state { - text-align: center; padding: 3rem 1rem; color: var(--text-dim); + color: var(--text-secondary); + text-align: center; + padding: 2rem; + font-size: 0.85rem; } -.empty-state-icon { font-size: 2.5rem; margin-bottom: 0.75rem; opacity: 0.5; } -.empty-state-title { font-family: var(--font-display); font-size: 1.1rem; color: var(--text); margin-bottom: 0.3rem; } -.empty-state-desc { font-size: 0.9rem; margin-bottom: 1rem; } -/* ── Rarity colors ── */ -.rarity-consumer { color: var(--rarity-consumer); } -.rarity-industrial { color: var(--rarity-industrial); } -.rarity-mil-spec { color: var(--rarity-mil-spec); } +/* Кейсы */ +.cases-container { + padding: 1.5rem 0; +} + +.cases-container h1 { + font-size: 1.5rem; + text-transform: uppercase; + letter-spacing: 0.05em; + margin-bottom: 0.25rem; +} + +.page-subtitle { + color: var(--text-secondary); + margin-bottom: 1.5rem; + font-size: 0.85rem; +} + +.cases-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 1rem; +} + +.case-card { + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + padding: 1.25rem 1rem; + border-radius: 10px; + cursor: pointer; + transition: all 0.25s; +} + +.case-card:hover { + transform: translateY(-3px); + border-color: rgba(245, 158, 11, 0.15); + box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3); +} + +.case-icon { + font-size: 2.5rem; + text-align: center; + margin-bottom: 0.75rem; +} + +.case-card h3 { + text-align: center; + margin-bottom: 0.75rem; + font-size: 0.9rem; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.case-stats { + text-align: center; + color: var(--text-secondary); + margin-bottom: 0.5rem; + font-size: 0.75rem; +} + +.case-rarities { + display: flex; + flex-wrap: wrap; + gap: 0.2rem; + justify-content: center; + margin-bottom: 0.75rem; +} + +.rarity-badge { + padding: 0.2rem 0.4rem; + border-radius: 3px; + font-size: 0.65rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +/* Модальные окна */ +.modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.8); + backdrop-filter: blur(4px); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; +} + +.modal-content { + background: rgba(20, 21, 26, 0.95); + border: 1px solid var(--border-color); + padding: 1.5rem; + border-radius: 10px; + text-align: center; + min-width: 300px; + max-width: 500px; + backdrop-filter: blur(8px); +} + +.case-animation { + padding: 1.5rem; +} + +.spinner { + width: 40px; + height: 40px; + border: 3px solid rgba(255,255,255,0.06); + border-top-color: var(--primary-color); + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 0 auto 0.75rem; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.case-result, .contract-result { + padding: 0.75rem; +} + +.result-icon { + font-size: 3rem; + margin-bottom: 0.75rem; +} + +.result-title { + font-size: 1.1rem; + font-weight: 700; + margin-bottom: 0.5rem; +} + +.result-item-name { + color: var(--text-secondary); + font-size: 0.85rem; +} + +/* Контракты */ +.contracts-container { + padding: 1.5rem 0; +} + +.contracts-info { + margin-bottom: 1.5rem; +} + +.info-card { + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + padding: 1.25rem; + border-radius: 10px; +} + +.info-card h3 { + margin-bottom: 0.75rem; + font-size: 0.95rem; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.info-card ol { + padding-left: 1.25rem; + color: var(--text-secondary); + font-size: 0.85rem; +} + +.info-card li { + margin-bottom: 0.4rem; +} + +.contracts-groups { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.contract-group { + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + border-radius: 10px; + overflow: hidden; +} + +.group-header { + padding: 1rem 1.25rem; + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} + +.group-header h3 { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.group-type { + padding: 0.2rem 0.45rem; + background: rgba(0,0,0,0.3); + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 0.7rem; + color: var(--text-secondary); +} + +.group-count { + color: var(--text-secondary); + font-size: 0.8rem; +} + +.group-items { + padding: 0.75rem; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); + gap: 0.4rem; + max-height: 400px; + overflow-y: auto; +} + +.contract-item { + background: rgba(14, 15, 19, 0.9); + border: 1px solid var(--border-color); + padding: 0.6rem 0.75rem; + border-radius: 8px; + display: flex; + align-items: center; + gap: 0.75rem; + cursor: pointer; + transition: all 0.2s; + border: 2px solid transparent; +} + +.contract-item:hover { + background: var(--bg-light); +} + +.contract-item.selected { + border-color: var(--primary-color); + background: rgba(79, 70, 229, 0.1); +} + +.item-checkbox { + width: 20px; + height: 20px; + border: 2px solid var(--border-color); + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; +} + +.contract-item.selected .item-checkbox { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.contract-item.selected .item-checkbox::after { + content: "✓"; + color: white; + font-size: 14px; +} + +.contract-slot { + background: rgba(0, 0, 0, 0.3); + border: 1px solid #8b7355; + border-radius: 4px; + padding: 10px; + min-height: 70px; +} + +#contractScribble { + width: 100%; + padding: 10px; + background: transparent; + border: 1px dashed #8b7355; + color: #d4c5a9; + font-family: 'Brush Script MT', cursive; + font-size: 18px; + text-align: center; + margin-bottom: 15px; + outline: none; +} + +#contractScribble:focus { + border-color: #d4c5a9; +} + +/* Контракт в стиле CS:GO */ +.contract-paper { + background: #1a1a1a; + background-image: + linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px); + background-size: 20px 20px; + border: 2px solid #8b7355; + border-radius: 4px; + padding: 30px; + position: relative; + box-shadow: + inset 0 0 50px rgba(0, 0, 0, 0.5), + 0 10px 30px rgba(0, 0, 0, 0.5); +} + +.contract-paper::before { + content: ''; + position: absolute; + top: 10px; + left: 10px; + right: 10px; + bottom: 10px; + border: 1px solid rgba(139, 115, 85, 0.3); + pointer-events: none; +} + +.contract-header { + text-align: center; + margin-bottom: 30px; + border-bottom: 2px solid #8b7355; + padding-bottom: 15px; +} + +.contract-header h2 { + color: #d4c5a9; + text-transform: uppercase; + letter-spacing: 3px; + font-size: 24px; + text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); +} + +.contract-items-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 15px; + margin: 30px 0; +} + +.contract-slot.filled { + background: rgba(139, 115, 85, 0.2); + border-color: #d4c5a9; +} + +.contract-slot-content { + font-family: 'Courier New', monospace; + color: #d4c5a9; + font-size: 11px; + line-height: 1.4; + word-break: break-word; +} + +.contract-signature-line { + margin-top: 30px; + border-top: 1px solid #8b7355; + padding-top: 20px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.contract-signature { + font-family: 'Brush Script MT', cursive; + color: #8b7355; + font-size: 20px; +} + +.contract-stamp { + width: 80px; + height: 80px; + border: 3px double #8b7355; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + color: #8b7355; + transform: rotate(-15deg); + opacity: 0; + transition: all 0.5s; +} + +.contract-stamp.active { + opacity: 1; + transform: rotate(-15deg) scale(1.1); +} + +/* GLOW эффекты для редкостей */ +.glow-consumer-grade { box-shadow: 0 0 40px rgba(176, 176, 176, 0.6); } +.glow-industrial-grade { box-shadow: 0 0 40px rgba(94, 152, 217, 0.6); } +.glow-mil-spec, .glow-mil-spec-grade { box-shadow: 0 0 40px rgba(75, 105, 255, 0.6); } +.glow-restricted { box-shadow: 0 0 40px rgba(136, 71, 255, 0.6); } +.glow-classified { box-shadow: 0 0 40px rgba(211, 44, 230, 0.6); } +.glow-covert { box-shadow: 0 0 40px rgba(235, 75, 75, 0.6); } +.glow-rare-special-item, .glow-extraordinary { box-shadow: 0 0 40px rgba(255, 215, 0, 0.6); } + +.item-info { + flex: 1; + min-width: 0; +} + +.item-info .item-name { + font-size: 0.9rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.item-meta { + font-size: 0.8rem; + color: var(--text-secondary); +} + +.group-footer { + padding: 1rem 1.5rem; + border-top: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} + +.selected-count { + color: var(--text-secondary); +} + +.empty-state-large { + text-align: center; + padding: 4rem; +} + +.empty-icon { + font-size: 4rem; + margin-bottom: 1rem; +} + +.empty-state-large h3 { + margin-bottom: 0.5rem; +} + +.empty-state-large p { + color: var(--text-secondary); + margin-bottom: 2rem; +} + +/* Редкости */ +.rarity-consumer-grade { border-left-color: var(--rarity-consumer); } +.rarity-industrial-grade { border-left-color: var(--rarity-industrial); } +.rarity-mil-spec, .rarity-mil-spec-grade { border-left-color: var(--rarity-mil-spec); } +.rarity-restricted { border-left-color: var(--rarity-restricted); } +.rarity-classified { border-left-color: var(--rarity-classified); } +.rarity-covert { border-left-color: var(--rarity-covert); } +.rarity-rare-special-item, .rarity-extraordinary { border-left-color: var(--rarity-rare-special); } +.rarity-contraband { border-left-color: var(--rarity-contraband); } + +.rarity-consumer-grade { color: var(--rarity-consumer); } +.rarity-industrial-grade { color: var(--rarity-industrial); } +.rarity-mil-spec, .rarity-mil-spec-grade { color: var(--rarity-mil-spec); } .rarity-restricted { color: var(--rarity-restricted); } .rarity-classified { color: var(--rarity-classified); } .rarity-covert { color: var(--rarity-covert); } -.rarity-rare-special { color: var(--rarity-rare-special); } -.bg-rarity-consumer { background: rgba(176,176,176,0.12); } -.bg-rarity-industrial { background: rgba(94,152,217,0.12); } -.bg-rarity-mil-spec { background: rgba(75,105,255,0.12); } -.bg-rarity-restricted { background: rgba(136,71,255,0.12); } -.bg-rarity-classified { background: rgba(211,44,230,0.12); } -.bg-rarity-covert { background: rgba(235,75,75,0.12); } -.bg-rarity-rare-special { background: rgba(255,215,0,0.12); } -.glow-rarity-covert { box-shadow: 0 0 20px rgba(235,75,75,0.2); } -.glow-rarity-rare-special { box-shadow: 0 0 20px rgba(255,215,0,0.25); } +.rarity-rare-special-item, .rarity-extraordinary { color: var(--rarity-rare-special); } -/* ── Admin Layout ── */ -.admin-body { display: flex; min-height: 100vh; } -.admin-sidebar { - width: 240px; background: var(--bg-dark); border-right: 1px solid var(--border); - display: flex; flex-direction: column; flex-shrink: 0; - position: sticky; top: 0; height: 100vh; overflow-y: auto; +.rarity-badge.rarity-consumer-grade { background: var(--rarity-consumer); color: black; } +.rarity-badge.rarity-industrial-grade { background: var(--rarity-industrial); color: white; } +.rarity-badge.rarity-mil-spec { background: var(--rarity-mil-spec); color: white; } +.rarity-badge.rarity-restricted { background: var(--rarity-restricted); color: white; } +.rarity-badge.rarity-classified { background: var(--rarity-classified); color: white; } +.rarity-badge.rarity-covert { background: var(--rarity-covert); color: white; } +.rarity-badge.rarity-rare-special-item { background: var(--rarity-rare-special); color: black; } + +/* Инвентарь */ +.inventory-container { + padding: 1.5rem 0; } -.admin-sidebar-brand { - padding: 1rem 1.15rem; border-bottom: 1px solid var(--border); - font-family: var(--font-display); font-size: 1rem; - display: flex; align-items: center; gap: 0.4rem; + +.inventory-filters { + display: flex; + gap: 0.75rem; + margin-bottom: 1rem; + flex-wrap: wrap; } -.admin-sidebar-brand span { color: var(--primary); } -.admin-sidebar-nav { padding: 0.5rem; flex: 1; } -.admin-sidebar-link { - display: flex; align-items: center; gap: 0.5rem; - padding: 0.5rem 0.75rem; color: var(--text-dim); text-decoration: none; - border-radius: var(--radius-sm); transition: all var(--transition); - font-size: 0.85rem; + +.filter-select { + padding: 0.4rem 0.7rem; + background: rgba(0,0,0,0.3); + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-primary); + cursor: pointer; + font-family: 'Rajdhani', sans-serif; + font-size: 0.8rem; + outline: none; } -.admin-sidebar-link:hover { color: var(--text); background: var(--bg-hover); } -.admin-sidebar-link.active { color: var(--primary); background: var(--primary-subtle); } -.admin-sidebar-footer { padding: 0.75rem; border-top: 1px solid var(--border); } -.admin-main { flex: 1; min-width: 0; display: flex; flex-direction: column; } -.admin-topbar { - display: flex; align-items: center; justify-content: space-between; - padding: 0.75rem 1.5rem; border-bottom: 1px solid var(--border); - background: var(--bg-dark); flex-wrap: wrap; gap: 0.5rem; + +.filter-select:focus { + border-color: rgba(245, 158, 11, 0.3); } -.admin-topbar-title { font-family: var(--font-display); font-size: 1.1rem; } -.admin-topbar-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; } -.admin-content { padding: 1.5rem; flex: 1; } -.a-card { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 1.15rem; } -.a-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.75rem; margin-bottom: 1.25rem; } -.a-stat { background: var(--bg-card); border: 1px solid var(--border); border-radius: var(--radius-md); padding: 0.9rem 1rem; } -.a-stat-value { font-family: var(--font-display); font-size: 1.3rem; color: var(--primary); } -.a-stat-label { font-size: 0.72rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; margin-top: 0.1rem; } -.a-table { width: 100%; } -.a-btn { padding: 0.4rem 0.85rem; border: none; border-radius: var(--radius-sm); font-size: 0.75rem; font-weight: 600; cursor: pointer; text-transform: uppercase; letter-spacing: 0.04em; transition: all var(--transition); font-family: var(--font-body); } -.a-btn-primary { background: var(--primary); color: #000; } -.a-btn-primary:hover { box-shadow: 0 4px 12px var(--primary-glow); } -.a-btn-danger { background: var(--danger); color: #fff; } -.a-btn-success { background: var(--success); color: #000; } -.a-btn-outline { background: transparent; border: 1px solid var(--border-light); color: var(--text-dim); } -.a-btn-outline:hover { color: var(--text); border-color: rgba(255,255,255,0.2); } -.a-input { - width: 100%; padding: 0.4rem 0.7rem; font-size: 0.85rem; - background: var(--bg-dark); border: 1px solid var(--border-light); - border-radius: var(--radius-sm); color: var(--text); outline: none; - font-family: var(--font-body); transition: border-color var(--transition); + +.inventory-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 0.85rem; } -.a-input:focus { border-color: var(--primary); } -.a-badge { display: inline-flex; padding: 0.1rem 0.45rem; border-radius: 4px; font-size: 0.65rem; font-weight: 600; text-transform: uppercase; } -.a-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.7); z-index: var(--z-overlay); display: flex; align-items: center; justify-content: center; padding: 1rem; animation: fadeIn 0.15s ease; } -.a-modal { background: var(--bg-surface); border: 1px solid var(--border-light); border-radius: var(--radius-lg); width: 100%; max-width: 520px; max-height: 85vh; overflow-y: auto; animation: modalSlideIn 0.2s ease; box-shadow: var(--shadow-xl); } -.a-modal-header { display: flex; align-items: center; justify-content: space-between; padding: 0.85rem 1.15rem; border-bottom: 1px solid var(--border); } -.a-modal-title { font-family: var(--font-display); font-size: 0.95rem; } -.a-modal-close { background: none; border: none; color: var(--text-dim); font-size: 1.2rem; cursor: pointer; padding: 0.1rem; line-height: 1; transition: color var(--transition); } -.a-modal-close:hover { color: var(--text); } -.a-modal-body { padding: 1.15rem; } -.a-modal-footer { display: flex; justify-content: flex-end; gap: 0.5rem; padding: 0.85rem 1.15rem; border-top: 1px solid var(--border); } + +.inventory-grid-detailed { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); + gap: 12px; +} + +.inventory-skin-card { + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + border-radius: 8px; + padding: 10px; + cursor: pointer; + transition: all 0.25s; + border: 1px solid var(--border-color); + position: relative; +} + +.inventory-skin-card:hover { + border-color: rgba(245, 158, 11, 0.15); +} + +.inventory-item { + background: rgba(20, 21, 26, 0.8); + border: 1px solid var(--border-color); + border-radius: 8px; + overflow: hidden; +} + +.inventory-item-header { + padding: 0.65rem 0.75rem; + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} + +.inventory-skin-card.selected { + border-color: var(--primary-color); + box-shadow: 0 0 15px rgba(245, 158, 11, 0.1); +} + +.inventory-skin-card .skin-image-container { + width: 100%; + height: 110px; + display: flex; + align-items: center; + justify-content: center; + margin-bottom: 8px; + background: rgba(0,0,0,0.2); + border-radius: 4px; +} + +.inventory-skin-card .skin-image { + max-width: 100%; + max-height: 110px; + object-fit: contain; +} + +.inventory-skin-card .item-checkbox { + position: absolute; + top: 8px; + right: 8px; + width: 20px; + height: 20px; + border: 2px solid var(--border-color); + border-radius: 4px; + background: var(--bg-dark); +} + +.inventory-skin-card.selected .item-checkbox { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.inventory-skin-card.selected .item-checkbox::after { + content: "✓"; + color: white; + font-size: 14px; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; +} + +.inventory-item-body { + padding: 0.75rem; +} + +.inventory-item-footer { + padding: 0.75rem; + border-top: 1px solid var(--border-color); + font-size: 0.85rem; + color: var(--text-secondary); +} + +.item-type-badge { + padding: 0.25rem 0.5rem; + background: var(--bg-light); + border-radius: 4px; + font-size: 0.75rem; +} + +.skin-info { + font-size: 12px; +} + +.skin-name { + font-weight: 500; + margin-bottom: 4px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.skin-details { + display: flex; + justify-content: space-between; + color: var(--text-secondary); + font-size: 11px; +} + +/* Кейс открытие */ +.case-opening-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.95); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + pointer-events: all; +} + +.case-scroll-container { + width: 100%; + max-width: 900px; + height: 280px; + position: relative; + overflow: hidden; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + border-radius: 12px; + border: 2px solid var(--border-color); + margin: 0 auto; +} + +.case-scroll-track { + display: flex; + position: absolute; + top: 5%; + transform: translateY(50%); + will-change: left; + transition: none; + left: 0; +} + +.scroll-item { + width: 200px; + height: 240px; + margin: 0 10px; + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background: var(--bg-card); + border-radius: 8px; + padding: 15px; + border: 2px solid transparent; + box-sizing: border-box; +} + +.scroll-item img { + width: 140px; + height: 110px; + object-fit: contain; + margin-bottom: 10px; + pointer-events: none; +} + +.scroll-item-name { + font-size: 11px; + text-align: center; + word-break: break-word; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + width: 100%; +} + +.scroll-item-rarity { + font-size: 10px; + margin-top: 5px; + text-align: center; +} + +.case-center-indicator { + position: absolute; + left: 50%; + top: 0; + bottom: 0; + width: 4px; + background: linear-gradient(to bottom, transparent, #ffd700, #ffd700, transparent); + transform: translateX(-50%); + z-index: 10; + box-shadow: 0 0 30px #ffd700; + pointer-events: none; +} + +.case-center-indicator::before, +.case-center-indicator::after { + content: ''; + position: absolute; + left: -8px; + width: 20px; + height: 20px; + background: #ffd700; + clip-path: polygon(50% 0%, 0% 100%, 100% 100%); +} + +.case-center-indicator::before { + top: -2px; + transform: rotate(180deg); +} + +.case-center-indicator::after { + bottom: -2px; +} + +.case-result-display { + margin-top: 20px; + text-align: center; + animation: fadeInUp 0.5s; +} + +.case-card-link { + text-decoration: none; + color: inherit; + display: block; +} + +.case-card-link:hover .case-card { + transform: translateY(-4px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +/* Карточки предметов */ +.skin-image { + width: 100%; + height: auto; + border-radius: 4px; + margin-bottom: 8px; +} + +.skin-card { + position: relative; + overflow: hidden; + transition: all 0.3s; +} + +.skin-card:hover { + transform: translateY(-2px); +} + +.skin-card .skin-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(135deg, transparent 0%, rgba(255, 255, 255, 0.1) 100%); + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; +} + +.skin-card:hover .skin-overlay { + opacity: 1; +} + +/* Анимации */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes typewriter { + from { width: 0; } + to { width: 100%; } +} + +@keyframes blink { + 0%, 100% { border-color: transparent; } + 50% { border-color: #d4c5a9; } +} + +.typewriter-text { + overflow: hidden; + border-right: 2px solid #d4c5a9; + white-space: nowrap; + animation: + typewriter 1s steps(40) 1, + blink 0.75s step-end infinite; +} + +/* Модальные окна с запретом закрытия */ +.modal-locked { + pointer-events: all; +} + +.modal-locked .modal-content { + pointer-events: auto; +} + +.modal-loading { + cursor: wait; +} + +.spinner-large { + width: 60px; + height: 60px; + border: 5px solid var(--border-color); + border-top-color: var(--primary-color); + border-radius: 50%; + animation: spin 1s linear infinite; + margin: 20px auto; +} + +/* ===== СТИЛИ ДЛЯ CASE_DETAIL ===== */ +.case-detail-container { + padding: 1rem 0; + width: 100%; + overflow-x: hidden; +} + +.back-link { + color: var(--text-secondary); + text-decoration: none; + display: inline-block; + margin-bottom: 0.75rem; + font-size: 0.9rem; +} + +.back-link:hover { + color: var(--text-primary); +} + +.case-header { + display: flex; + flex-direction: column; + margin-bottom: 1rem; +} + +.case-title-row { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 0.75rem; + margin-bottom: 0.75rem; +} + +.case-title-row h1 { + font-size: 1.5rem; + margin: 0; + word-break: break-word; +} + +.case-info-badge { + display: flex; + align-items: center; + gap: 0.75rem; + flex-wrap: wrap; +} + +.case-price-tag { + background: var(--bg-card); + padding: 0.4rem 0.8rem; + border-radius: 8px; + border: 1px solid var(--success-color); + color: var(--success-color); + font-weight: bold; + font-size: 0.9rem; +} + +.case-subtitle { + color: var(--text-secondary); + font-size: 0.85rem; +} + +.opening-controls { + display: flex; + align-items: center; + gap: 0.75rem; + flex-wrap: wrap; + background: var(--bg-card); + padding: 0.75rem 1rem; + border-radius: 12px; +} + +.total-price-display { + font-size: 1rem; + font-weight: bold; + color: var(--success-color); + margin-left: auto; +} + +.total-price-display span { + color: var(--text-secondary); + font-size: 0.8rem; + font-weight: normal; +} + +.count-selector { + display: flex; + align-items: center; + gap: 0.5rem; + flex-wrap: wrap; +} + +.count-selector label { + color: var(--text-secondary); + font-size: 0.85rem; +} + +.count-buttons { + display: flex; + gap: 0.3rem; + flex-wrap: wrap; +} + +.count-btn { + padding: 0.3rem 0.7rem; + background: var(--bg-dark); + border: 1px solid var(--border-color); + color: var(--text-primary); + border-radius: 6px; + cursor: pointer; + font-size: 0.8rem; + transition: all 0.2s; + min-width: 40px; +} + +.count-btn.active { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.case-opening-section { + background: var(--bg-card); + border-radius: 12px; + padding: 1rem; + margin-bottom: 1rem; +} + +.opening-animation-container { + width: 100%; +} + +/* Speed lines overlay for scroll */ +.scroll-speed-lines { + position: absolute; + inset: 0; + z-index: 5; + pointer-events: none; + background: repeating-linear-gradient( + 90deg, + transparent 0px, + rgba(255,255,255,0.015) 2px, + transparent 4px, + transparent 40px + ); + animation: speedLinesMove 0.4s linear infinite; +} + +@keyframes speedLinesMove { + from { transform: translateX(0); } + to { transform: translateX(40px); } +} + +/* Flash overlay on stop */ +.scroll-flash { + position: absolute; + inset: 0; + z-index: 15; + pointer-events: none; + opacity: 0; + transition: opacity 0.1s; + border-radius: 6px; +} + +.scroll-flash.burst { + opacity: 1; +} + +.scroll-flash.gold { + background: radial-gradient(ellipse at center, rgba(255,215,0,0.4) 0%, transparent 70%); +} + +.scroll-flash.blue { + background: radial-gradient(ellipse at center, rgba(75,105,255,0.4) 0%, transparent 70%); +} + +.scroll-flash.purple { + background: radial-gradient(ellipse at center, rgba(136,71,255,0.4) 0%, transparent 70%); +} + +.scroll-flash.pink { + background: radial-gradient(ellipse at center, rgba(211,44,230,0.4) 0%, transparent 70%); +} + +.scroll-flash.red { + background: radial-gradient(ellipse at center, rgba(235,75,75,0.4) 0%, transparent 70%); +} + +/* Particle burst */ +.particle-burst { + position: absolute; + inset: 0; + z-index: 20; + pointer-events: none; + overflow: hidden; +} + +.particle-burst .pt { + position: absolute; + width: 4px; + height: 4px; + border-radius: 50%; + animation: ptFly 0.8s ease-out forwards; +} + +@keyframes ptFly { + 0% { + opacity: 1; + transform: translate(0, 0) scale(1); + } + 100% { + opacity: 0; + transform: translate(var(--px), var(--py)) scale(0); + } +} + +/* Slot machine (3 vertical reels) */ +.slot-machine { + position: relative; + width: 100%; + max-width: 660px; + margin: 0 auto; + padding: 20px 10px 10px; + background: linear-gradient(135deg, #1a1a2e 0%, #0d0d1a 100%); + border-radius: 16px; + border: 2px solid rgba(255,255,255,0.06); + box-shadow: 0 0 60px rgba(0,0,0,0.5), inset 0 0 40px rgba(0,0,0,0.3); +} + +.slot-reels { + display: flex; + justify-content: center; + gap: 8px; + position: relative; + z-index: 2; +} + +.slot-reel { + width: 160px; + height: 240px; + overflow: hidden; + border-radius: 8px; + background: rgba(0,0,0,0.4); + border: 2px solid rgba(255,255,255,0.08); + position: relative; +} + +.slot-track { + display: flex; + flex-direction: column; + will-change: transform; +} + +.slot-item { + width: 100%; + height: 80px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + border-bottom: 1px solid rgba(255,255,255,0.04); + border-left: 3px solid; + box-sizing: border-box; + padding: 4px; + transition: background 0.3s, box-shadow 0.3s; + flex-shrink: 0; +} + +.slot-item img { + width: 50px; + height: 40px; + object-fit: contain; + pointer-events: none; +} + +.slot-item-name { + font-size: 8px; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; + margin-top: 2px; + color: var(--text-secondary); +} + +.slot-item-hit { + background: rgba(255,215,0,0.12); + box-shadow: inset 0 0 20px rgba(255,215,0,0.15); +} + +.slot-win-line { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: calc(100% - 40px); + height: 80px; + border: 2px solid rgba(255,215,0,0.5); + border-radius: 6px; + z-index: 5; + pointer-events: none; + box-shadow: 0 0 20px rgba(255,215,0,0.15), inset 0 0 20px rgba(255,215,0,0.05); +} + +.slot-win-line::before, +.slot-win-line::after { + content: ''; + position: absolute; + left: -4px; + width: calc(100% + 8px); + height: 2px; + background: linear-gradient(90deg, transparent, #ffd700, transparent); +} + +.slot-win-line::before { top: -2px; } +.slot-win-line::after { bottom: -2px; } + +.slot-frame-glow { + position: absolute; + inset: -4px; + border-radius: 18px; + border: 3px solid transparent; + z-index: 1; + pointer-events: none; + transition: all 0.8s; +} + +.slot-result-display { + text-align: center; + margin-top: 12px; + position: relative; + z-index: 10; +} + +.slot-win-banner, .slot-lose-banner { + padding: 12px 20px; + border-radius: 10px; +} + +.slot-win-banner { + background: rgba(255,215,0,0.1); + border: 1px solid rgba(255,215,0,0.3); + animation: slotBannerIn 0.5s ease-out; +} + +.slot-lose-banner { + background: rgba(239,68,68,0.08); + border: 1px solid rgba(239,68,68,0.2); + animation: slotBannerIn 0.5s ease-out; +} + +.slot-win-title { + font-family: 'Russo One', sans-serif; + font-size: 1.4rem; + color: #ffd700; + text-shadow: 0 0 20px rgba(255,215,0,0.4); + letter-spacing: 0.06em; +} + +.slot-win-subtitle, .slot-lose-subtitle { + font-size: 0.85rem; + color: var(--text-secondary); + margin-top: 4px; +} + +.slot-lose-title { + font-family: 'Russo One', sans-serif; + font-size: 1.1rem; + color: var(--danger-color); +} + +@keyframes slotBannerIn { + from { opacity: 0; transform: translateY(20px) scale(0.95); } + to { opacity: 1; transform: translateY(0) scale(1); } +} + +/* Slot activation badges */ +.slot-badge { + position: absolute; + top: 2px; + right: 2px; + font-size: 0.6rem; + line-height: 1; + z-index: 5; + pointer-events: none; + filter: drop-shadow(0 0 3px rgba(0,0,0,0.8)); +} +.slot-badge-extra_spin, +.slot-badge-free_spin, +.slot-badge-guaranteed, +.slot-badge-double, +.slot-badge-quintuple { + padding: 1px 3px; + border-radius: 3px; + font-size: 0.55rem; + font-weight: 700; +} +.slot-badge-extra_spin { color: #8b5cf6; } +.slot-badge-free_spin { color: #10b981; } +.slot-badge-guaranteed { color: #3b82f6; } +.slot-badge-double { color: #f59e0b; } +.slot-badge-quintuple { color: #ef4444; } + +/* Slot activation legend */ +.slot-legend { + margin-top: 14px; + padding: 16px; + background: linear-gradient(135deg, rgba(30,28,45,0.98) 0%, rgba(25,23,40,0.98) 100%); + border: 1px solid rgba(255,255,255,0.12); + border-radius: 10px; + position: relative; + overflow: hidden; + box-shadow: inset 0 1px 0 rgba(255,255,255,0.06), 0 4px 24px rgba(0,0,0,0.5); +} +.slot-legend::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(245,158,11,0.5), transparent); +} +.slot-legend::after { + content: ''; + position: absolute; + bottom: 0; left: 25%; right: 25%; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(245,158,11,0.2), transparent); +} +.slot-legend-header { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + margin-bottom: 14px; + position: relative; +} +.slot-legend-header::after { + content: ''; + position: absolute; + bottom: -6px; + left: 30%; + right: 30%; + height: 1px; + background: linear-gradient(90deg, transparent, rgba(245,158,11,0.25), transparent); +} +.slot-legend-symbol { + font-size: 0.6rem; + color: rgba(245,158,11,0.4); + letter-spacing: 6px; +} +.slot-legend-label { + font-family: 'Russo One', sans-serif; + font-size: 0.7rem; + color: rgba(245,158,11,0.7); + text-transform: uppercase; + letter-spacing: 0.2em; +} +.slot-legend-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 8px; +} +.slot-legend-card { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + padding: 12px 4px 10px; + border-radius: 8px; + background: rgba(255,255,255,0.06); + border: 1px solid rgba(255,255,255,0.08); + cursor: default; + transition: background 0.25s, border-color 0.25s, transform 0.2s, box-shadow 0.25s; + position: relative; +} +.slot-legend-card:hover { + background: rgba(255,255,255,0.1); + border-color: rgba(255,255,255,0.18); + transform: translateY(-3px); + box-shadow: 0 4px 16px rgba(0,0,0,0.4); +} +.slot-legend-card[data-act="extra_spin"] { + background: rgba(139,92,246,0.1); + border-color: rgba(139,92,246,0.18); +} +.slot-legend-card[data-act="extra_spin"]:hover { + background: rgba(139,92,246,0.18); + border-color: rgba(139,92,246,0.3); + box-shadow: 0 4px 20px rgba(139,92,246,0.2); +} +.slot-legend-card[data-act="double"] { + background: rgba(245,158,11,0.1); + border-color: rgba(245,158,11,0.18); +} +.slot-legend-card[data-act="double"]:hover { + background: rgba(245,158,11,0.18); + border-color: rgba(245,158,11,0.3); + box-shadow: 0 4px 20px rgba(245,158,11,0.2); +} +.slot-legend-card[data-act="quintuple"] { + background: rgba(239,68,68,0.1); + border-color: rgba(239,68,68,0.18); +} +.slot-legend-card[data-act="quintuple"]:hover { + background: rgba(239,68,68,0.18); + border-color: rgba(239,68,68,0.3); + box-shadow: 0 4px 20px rgba(239,68,68,0.2); +} +.slot-legend-card[data-act="guaranteed"] { + background: rgba(59,130,246,0.1); + border-color: rgba(59,130,246,0.18); +} +.slot-legend-card[data-act="guaranteed"]:hover { + background: rgba(59,130,246,0.18); + border-color: rgba(59,130,246,0.3); + box-shadow: 0 4px 20px rgba(59,130,246,0.2); +} +.slot-legend-card[data-act="free_spin"] { + background: rgba(16,185,129,0.1); + border-color: rgba(16,185,129,0.18); +} +.slot-legend-card[data-act="free_spin"]:hover { + background: rgba(16,185,129,0.18); + border-color: rgba(16,185,129,0.3); + box-shadow: 0 4px 20px rgba(16,185,129,0.2); +} +.slc-icon { + font-size: 1.1rem; + line-height: 1; + font-family: 'Russo One', sans-serif; + font-weight: 700; + filter: drop-shadow(0 0 8px currentColor); + transition: transform 0.25s, filter 0.25s; +} +.slot-legend-card:hover .slc-icon { + transform: scale(1.2); + filter: drop-shadow(0 0 14px currentColor); +} +.slc-name { + font-family: 'Russo One', sans-serif; + font-size: 0.6rem; + color: #fff; + text-transform: uppercase; + letter-spacing: 0.08em; + white-space: nowrap; + transition: color 0.2s; +} +.slc-desc { + font-family: 'Rajdhani', sans-serif; + font-size: 0.6rem; + color: rgba(255,255,255,0.5); + text-align: center; + line-height: 1.2; + transition: color 0.25s; +} +.slot-legend-card:hover .slc-desc { + color: rgba(255,255,255,0.75); +} + +/* Slot machine style frame */ +.scroll-container-full { + position: relative; + width: 100%; + height: 220px; + max-height: 220px; + overflow: hidden; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + border-radius: 8px; + border: 2px solid var(--border-color); + box-shadow: + inset 0 0 60px rgba(0,0,0,0.4), + 0 0 30px rgba(0,0,0,0.3); +} + +.scroll-container-full::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; + height: 30px; + background: linear-gradient(to bottom, rgba(0,0,0,0.7), transparent); + z-index: 8; + pointer-events: none; +} + +.scroll-container-full::after { + content: ''; + position: absolute; + bottom: 0; left: 0; right: 0; + height: 30px; + background: linear-gradient(to top, rgba(0,0,0,0.7), transparent); + z-index: 8; + pointer-events: none; +} + +/* Target highlight ring */ +.target-highlight-ring { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 130px; + height: 200px; + border: 2px solid transparent; + border-radius: 10px; + z-index: 9; + pointer-events: none; + transition: all 0.3s; +} + +.target-highlight-ring.glow { + border-color: #ffd700; + box-shadow: 0 0 30px rgba(255,215,0,0.3), inset 0 0 30px rgba(255,215,0,0.1); +} + +.scroll-track-full { + display: flex; + position: absolute; + top: 0; + left: 0; + height: 100%; + will-change: transform; + transform: translateZ(0); + backface-visibility: hidden; +} + +.scroll-item-full { + width: 120px; + height: 190px; + margin: 8px 8px; + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: center; + background: var(--bg-card); + border-radius: 8px; + padding: 8px 4px; + border: 2px solid transparent; + box-sizing: border-box; +} + +.scroll-item-full img { + width: 80px; + height: 70px; + object-fit: contain; +} + +.scroll-item-name-full { + font-size: 9px; + text-align: center; + margin-top: 4px; + word-break: break-word; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + width: 100%; +} + +.scroll-item-rarity-full { + font-size: 8px; + margin-top: 3px; + font-weight: bold; +} + +.center-indicator-full { + position: absolute; + left: 50%; + top: 0; + bottom: 0; + width: 3px; + background: linear-gradient(to bottom, transparent, #ffd700, #ffd700, transparent); + transform: translateX(-50%); + z-index: 10; + box-shadow: 0 0 20px #ffd700; + pointer-events: none; +} + +/* МНОЖЕСТВЕННЫЕ СКРОЛЛЫ */ +.multi-scroll-grid { + display: grid; + gap: 0.75rem; + width: 100%; +} + +.scroll-wrapper-full { + width: 100%; + text-align: center; +} + +.scroll-container-mini { + width: 100%; + height: 150px; + max-height: 150px; + position: relative; + overflow: hidden; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + border-radius: 8px; + border: 2px solid var(--border-color); + box-shadow: + inset 0 0 30px rgba(0,0,0,0.3), + 0 0 15px rgba(0,0,0,0.2); +} + +.scroll-container-mini::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; + height: 20px; + background: linear-gradient(to bottom, rgba(0,0,0,0.6), transparent); + z-index: 8; + pointer-events: none; +} + +.scroll-container-mini::after { + content: ''; + position: absolute; + bottom: 0; left: 0; right: 0; + height: 20px; + background: linear-gradient(to top, rgba(0,0,0,0.6), transparent); + z-index: 8; + pointer-events: none; +} + +.mini-target-ring { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 80px; + height: 140px; + border: 2px solid transparent; + border-radius: 6px; + z-index: 9; + pointer-events: none; + transition: all 0.3s; +} + +.mini-target-ring.glow { + border-color: #ffd700; + box-shadow: 0 0 20px rgba(255,215,0,0.25), inset 0 0 20px rgba(255,215,0,0.08); +} + +.scroll-track-mini { + display: flex; + position: absolute; + top: 0; + left: 0; + height: 100%; + will-change: transform; + transform: translateZ(0); +} + +.scroll-item-mini { + width: 70px; + height: 130px; + margin: 6px 6px; + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: center; + background: var(--bg-card); + border-radius: 6px; + padding: 5px 3px; + border: 2px solid transparent; + box-sizing: border-box; +} + +.scroll-item-mini img { + width: 45px; + height: 45px; + object-fit: contain; +} + +.scroll-item-name-mini { + font-size: 7px; + text-align: center; + margin-top: 3px; + word-break: break-word; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.center-indicator-mini { + position: absolute; + left: 50%; + top: 0; + bottom: 0; + width: 2px; + background: #ffd700; + transform: translateX(-50%); + z-index: 10; + box-shadow: 0 0 15px #ffd700; + pointer-events: none; +} + +.scroll-label { + margin-top: 0.3rem; + font-size: 0.7rem; + color: var(--text-secondary); +} + +/* Результаты */ +.results-grid-compact { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + margin-top: 0.75rem; +} + +.result-item-compact { + background: var(--bg-dark); + padding: 0.4rem; + border-radius: 6px; + display: flex; + align-items: center; + gap: 0.4rem; + border-left: 3px solid; + flex: 1 0 auto; + min-width: 160px; +} + +.result-item-compact img { + width: 35px; + height: 30px; + object-fit: contain; +} + +/* Enhanced result cards */ +.case-results-header { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 0.75rem; +} + +.case-results-title { + font-family: 'Russo One', sans-serif; + font-size: 1rem; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +.case-results-actions { + display: flex; + gap: 0.4rem; +} + +.results-grid-enhanced { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + gap: 0.5rem; +} + +.result-card-enhanced { + background: var(--bg-dark); + border-radius: 8px; + overflow: hidden; + position: relative; + border: 1px solid var(--border-color); + transition: all 0.25s; + opacity: 0; + animation: fadeInUp 0.4s ease-out forwards; +} + +.result-card-enhanced:hover { + transform: translateY(-2px); + border-color: var(--glow, var(--primary-color)); + box-shadow: 0 4px 16px rgba(0,0,0,0.3); +} + +.result-card-glow { + position: absolute; + inset: 0; + opacity: 0.3; + pointer-events: none; +} + +.result-card-enhanced img { + width: 100%; + height: 70px; + object-fit: contain; + padding: 0.5rem 0.5rem 0; + display: block; + position: relative; + z-index: 1; +} + +.result-card-body { + padding: 0.35rem 0.5rem 0.4rem; + position: relative; + z-index: 1; +} + +.result-name-enhanced { + font-size: 0.65rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 0.1rem; +} + +.result-meta-enhanced { + font-size: 0.55rem; + color: var(--text-secondary); + margin-bottom: 0.25rem; +} + +.result-footer-enhanced { + display: flex; + justify-content: space-between; + align-items: center; +} + +.result-price-enhanced { + font-size: 0.75rem; + color: var(--success-color); + font-weight: bold; +} + +.result-count-badge { + position: absolute; + top: 4px; + right: 4px; + background: var(--primary-color); + color: white; + border-radius: 50%; + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; + font-size: 9px; + font-weight: bold; + z-index: 2; +} + +.result-info-compact { + flex: 1; + min-width: 0; +} + +.result-name-compact { + font-size: 10px; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.result-meta-compact { + display: flex; + gap: 0.5rem; + font-size: 9px; + color: var(--text-secondary); + flex-wrap: wrap; +} + +.result-count-badge { + background: var(--primary-color); + color: white; + border-radius: 50%; + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; + font-size: 9px; + font-weight: bold; + margin-left: 3px; +} + +.btn-sell-result { + padding: 2px 6px; + background: transparent; + border: 1px solid var(--danger-color); + color: var(--danger-color); + border-radius: 4px; + cursor: pointer; + font-size: 8px; +} + +.btn-sell-result:hover { + background: var(--danger-color); + color: white; +} + +/* Список предметов в кейсе */ +.case-items-section { + margin-top: 1rem; +} + +.case-items-section h2 { + font-size: 1.2rem; + margin-bottom: 0.75rem; +} + +.rarity-filters { + display: flex; + flex-wrap: wrap; + gap: 0.3rem; + margin-bottom: 0.75rem; +} + +.filter-btn { + padding: 0.25rem 0.6rem; + background: var(--bg-card); + border: 1px solid var(--border-color); + color: var(--text-secondary); + border-radius: 20px; + cursor: pointer; + font-size: 0.7rem; + transition: all 0.2s; +} + +.filter-btn.active { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +.filter-btn:hover { + background: var(--bg-light); +} + +.rarity-section { + margin-bottom: 0.75rem; +} + +.rarity-section h3 { + font-size: 0.9rem; + margin-bottom: 0.4rem; + padding-bottom: 0.2rem; + border-bottom: 2px solid; + display: flex; + align-items: center; + gap: 0.4rem; +} + +.rarity-count { + font-size: 0.7rem; + color: var(--text-secondary); + font-weight: normal; +} + +.items-grid-compact { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + gap: 0.4rem; +} + +.item-card-compact { + background: var(--bg-card); + border-radius: 6px; + padding: 0.4rem; + border-left: 3px solid; + cursor: pointer; + transition: all 0.2s; +} + +.item-card-compact:hover { + transform: translateY(-1px); + background: var(--bg-light); +} + +.item-card-compact img { + width: 100%; + height: 60px; + object-fit: contain; + margin-bottom: 0.2rem; +} + +.item-name-compact { + font-size: 9px; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 0.2rem; +} + +.item-meta-compact { + display: flex; + justify-content: space-between; + font-size: 8px; + color: var(--text-secondary); + flex-wrap: wrap; +} + +.item-price-compact { + font-size: 9px; + font-weight: bold; + color: var(--success-color); + margin-top: 0.2rem; +} + +/* ===== СТИЛИ ДЛЯ UPGRADE ===== */ +.upgrade-container { + padding: 0.75rem 0; + width: 100%; + overflow-x: hidden; +} + +.upgrade-header { + text-align: center; + margin-bottom: 1rem; +} + +.upgrade-header h1 { + font-size: 1.5rem; + background: linear-gradient(135deg, #ffd700, #ff6b6b); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + margin-bottom: 0.25rem; +} + +.upgrade-header p { + font-size: 0.85rem; + color: var(--text-secondary); +} + +.upgrade-layout { + display: grid; + grid-template-columns: 280px 1fr 280px; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.inventory-panel, .target-panel { + background: var(--bg-card); + border-radius: 12px; + border: 1px solid var(--border-color); + display: flex; + flex-direction: column; + max-height: 500px; +} + +.panel-header, .target-header { + padding: 0.75rem; + border-bottom: 1px solid var(--border-color); + background: var(--bg-card); + border-radius: 12px 12px 0 0; +} + +.panel-title { + font-size: 0.95rem; + font-weight: 600; + display: flex; + justify-content: space-between; + align-items: center; +} + +.inventory-list, .target-list { + flex: 1; + overflow-y: auto; + padding: 0.4rem; + display: flex; + flex-direction: column; + gap: 0.4rem; +} + +.inventory-item-card, .target-item-card { + background: var(--bg-dark); + border-radius: 8px; + padding: 0.5rem; + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + border: 2px solid transparent; + transition: all 0.2s; +} + +.inventory-item-card:hover, .target-item-card:hover { + background: var(--bg-light); + border-color: var(--primary-color); +} + +.inventory-item-card.selected, .target-item-card.selected { + border-color: #ffd700; + background: rgba(255, 215, 0, 0.1); + box-shadow: 0 0 15px rgba(255, 215, 0, 0.2); +} + +.inventory-item-card.disabled, .target-item-card.disabled { + opacity: 0.5; + cursor: not-allowed; + pointer-events: none; +} + +.inventory-item-card img, .target-item-card img { + width: 45px; + height: 40px; + object-fit: contain; + background: var(--bg-card); + border-radius: 4px; + padding: 3px; +} + +.inventory-item-info, .target-item-info { + flex: 1; + min-width: 0; +} + +.inventory-item-name, .target-item-name { + font-size: 0.75rem; + font-weight: 500; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-bottom: 0.15rem; +} + +.inventory-item-meta, .target-item-meta { + display: flex; + justify-content: space-between; + font-size: 0.65rem; + color: var(--text-secondary); +} + +.inventory-item-price, .target-item-price { + color: var(--success-color); + font-weight: bold; +} + +.wheel-panel { + background: var(--bg-card); + border-radius: 12px; + padding: 1rem; + border: 1px solid var(--border-color); + display: flex; + flex-direction: column; + align-items: center; +} + +.selected-items-display { + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + margin-bottom: 0.75rem; + width: 100%; +} + +.selected-item-mini { + text-align: center; + flex: 1; + min-width: 0; +} + +.selected-item-mini img { + width: 60px; + height: 50px; + object-fit: contain; + background: var(--bg-dark); + border-radius: 6px; + padding: 5px; +} + +.selected-item-mini-name { + font-size: 0.65rem; + margin-top: 0.2rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.selected-item-mini-price { + font-size: 0.7rem; + color: var(--success-color); + font-weight: bold; +} + +.arrow-icon { + font-size: 1.2rem; + color: var(--primary-color); +} + +.wheel-container { + position: relative; + width: 220px; + height: 220px; + margin: 0.5rem 0; +} + +.wheel { + width: 100%; + height: 100%; + border-radius: 50%; + background: conic-gradient( + from 0deg, + #10b981 0deg, + #10b981 calc(var(--probability) * 3.6deg / 2), + #2d1b1b calc(var(--probability) * 3.6deg / 2), + #2d1b1b calc(360deg - var(--probability) * 3.6deg / 2), + #10b981 calc(360deg - var(--probability) * 3.6deg / 2), + #10b981 360deg + ); + border: 3px solid var(--border-color); + box-shadow: 0 0 30px rgba(0,0,0,0.5); +} + +.wheel-pointer { + position: absolute; + top: -10px; + left: 50%; + transform: translateX(-50%); + width: 0; + height: 0; + border-left: 12px solid transparent; + border-right: 12px solid transparent; + border-top: 24px solid #ffd700; + filter: drop-shadow(0 0 6px #ffd700); + z-index: 10; +} + +.wheel-center { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 40px; + height: 40px; + background: var(--bg-card); + border-radius: 50%; + border: 2px solid #ffd700; + display: flex; + align-items: center; + justify-content: center; + font-weight: bold; + font-size: 0.8rem; + color: #ffd700; + z-index: 5; +} + +.upgrade-actions { + display: flex; + align-items: center; + gap: 0.5rem; + margin-top: 0.5rem; +} + +.upgrade-btn { + padding: 0.6rem 1.5rem; + font-size: 1rem; + flex: 1; +} + +.quick-btn { + width: 38px; + height: 38px; + border-radius: 8px; + border: 1px solid var(--border-color); + background: var(--bg-dark); + color: var(--text-secondary); + font-size: 1.1rem; + cursor: pointer; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} + +.quick-btn:hover { + border-color: var(--primary-color); + color: var(--primary-color); +} + +.quick-btn.active { + background: var(--primary-color); + color: #fff; + border-color: var(--primary-color); + box-shadow: 0 0 12px rgba(245, 158, 11, 0.4); +} + +.inv-filter-bar { + display: flex; + gap: 0.3rem; + align-items: center; + margin-top: 0.4rem; +} + +.inv-search-input { + flex: 1; + padding: 0.35rem 0.5rem; + background: var(--bg-dark); + border: 1px solid var(--border-color); + border-radius: 5px; + color: var(--text-primary); + font-size: 0.75rem; + min-width: 0; +} + +.inv-search-input:focus { + outline: none; + border-color: var(--primary-color); +} + +.inv-sort-group { + display: flex; + gap: 2px; + flex-shrink: 0; +} + +.inv-sort-btn { + padding: 0.3rem 0.4rem; + background: var(--bg-dark); + border: 1px solid var(--border-color); + color: var(--text-secondary); + border-radius: 4px; + cursor: pointer; + font-size: 0.7rem; + transition: all 0.15s; + line-height: 1; +} + +.inv-sort-btn.active { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +.inv-sort-btn:hover { + border-color: var(--primary-color); +} + +.target-search-input { + width: 100%; + padding: 0.5rem; + background: var(--bg-dark); + border: 1px solid var(--border-color); + border-radius: 6px; + color: var(--text-primary); + margin-bottom: 0.4rem; + font-size: 0.85rem; +} + +.target-search-input:focus { + outline: none; + border-color: var(--primary-color); +} + +.sort-controls { + display: flex; + gap: 0.3rem; +} + +.sort-btn { + flex: 1; + padding: 0.3rem; + background: var(--bg-dark); + border: 1px solid var(--border-color); + color: var(--text-secondary); + border-radius: 4px; + cursor: pointer; + font-size: 0.65rem; +} + +.sort-btn.active { + background: var(--primary-color); + color: white; + border-color: var(--primary-color); +} + +/* История апгрейдов */ +.history-section { + background: var(--bg-card); + border-radius: 12px; + padding: 1rem; + border: 1px solid var(--border-color); +} + +.history-title { + font-size: 1rem; + margin-bottom: 0.75rem; + display: flex; + align-items: center; + gap: 0.4rem; +} + +.history-count { + font-size: 0.65rem; + color: var(--text-secondary); + background: var(--bg-dark); + padding: 0.1rem 0.45rem; + border-radius: 10px; + font-weight: normal; +} + +.history-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 0.5rem; +} + +.history-card { + background: var(--bg-dark); + border-radius: 8px; + padding: 0.4rem 0.5rem; + display: flex; + align-items: center; + gap: 0.4rem; + transition: all 0.2s; +} + +.history-card:hover { + background: var(--bg-light); +} + +.history-card.success { + border-left: 3px solid #10b981; +} + +.history-card.fail { + border-left: 3px solid #ef4444; +} + +.history-card img { + width: 36px; + height: 30px; + object-fit: contain; + flex-shrink: 0; +} + +.history-info { + flex: 1; + min-width: 0; +} + +.history-names { + font-size: 0.7rem; + margin-bottom: 0.15rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.history-meta { + display: flex; + justify-content: space-between; + font-size: 0.6rem; + color: var(--text-secondary); +} + +.history-result { + font-weight: bold; +} + +.history-result.success { + color: #10b981; +} + +.history-result.fail { + color: #ef4444; +} + +/* ===== СТИЛИ ДЛЯ CASES ===== */ +.cases-sections { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.section-tab { + font-size: 1.2rem; + margin-bottom: 0.75rem; + padding-bottom: 0.4rem; + border-bottom: 2px solid var(--primary-color); + display: inline-block; +} + +.section-cases { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 1rem; +} + +.case-card-new { + background: var(--bg-card); + border-radius: 10px; + overflow: hidden; + transition: all 0.3s; + text-decoration: none; + color: inherit; + display: block; + border: 1px solid var(--border-color); +} + +.case-card-new:hover { + transform: translateY(-4px); + box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4); + border-color: var(--primary-color); +} + +.case-image { + width: 100%; + height: 120px; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + display: flex; + align-items: center; + justify-content: center; + position: relative; +} + +.case-image img { + max-width: 70%; + max-height: 90px; + object-fit: contain; +} + +.case-price-badge { + position: absolute; + top: 8px; + right: 8px; + background: var(--bg-dark); + padding: 0.2rem 0.5rem; + border-radius: 20px; + font-size: 0.75rem; + font-weight: bold; + color: var(--success-color); + border: 1px solid var(--success-color); +} + +.case-info { + padding: 0.75rem; +} + +.case-title { + font-size: 0.95rem; + font-weight: 600; + margin-bottom: 0.3rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.case-description { + font-size: 0.75rem; + color: var(--text-secondary); + margin-bottom: 0.5rem; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +.case-stats { + display: flex; + justify-content: space-between; + font-size: 0.7rem; + color: var(--text-secondary); + margin-bottom: 0.5rem; +} + +.case-rarities-mini { + display: flex; + gap: 0.2rem; + flex-wrap: wrap; +} + +.rarity-dot { + width: 8px; + height: 8px; + border-radius: 50%; +} + +.case-footer { + display: flex; + align-items: center; + justify-content: space-between; + padding-top: 0.5rem; + border-top: 1px solid var(--border-color); +} + +.case-price { + font-weight: bold; + color: var(--success-color); + font-size: 0.85rem; +} + +.btn-open { + padding: 0.3rem 0.8rem; + background: var(--primary-color); + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + font-size: 0.75rem; +} + +.btn-open:hover { + background: var(--primary-hover); +} + +/* ===== АДАПТИВНОСТЬ ===== */ +@media (max-width: 1000px) { + .upgrade-layout { + grid-template-columns: 1fr; + gap: 0.75rem; + } + + .inventory-panel, .target-panel { + max-height: 350px; + } + + .wheel-container { + width: 200px; + height: 200px; + } +} + @media (max-width: 768px) { - .admin-sidebar { width: 60px; } - .admin-sidebar-brand span, .admin-sidebar-link span { display: none; } - .admin-sidebar-link { justify-content: center; padding: 0.6rem; } - .admin-sidebar-footer { display: none; } + .container { + padding: 0 12px; + } + + .navbar .container { + flex-direction: column; + align-items: stretch; + } + + .logo { + text-align: center; + } + + .nav-links { + justify-content: center; + gap: 0.25rem; + } + + .nav-link { + padding: 0.4rem 0.5rem; + font-size: 0.8rem; + } + + .user-balance { + font-size: 0.8rem; + padding: 0.4rem 0.5rem; + } + + .hero h1 { + font-size: 2rem; + } + + .hero-subtitle { + font-size: 1rem; + } + + .btn { + padding: 0.4rem 0.8rem; + font-size: 0.85rem; + } + + .btn-large { + padding: 0.6rem 1.2rem; + } + + /* Кейсы */ + .case-title-row h1 { + font-size: 1.2rem; + } + + .opening-controls { + flex-direction: column; + align-items: stretch; + } + + .total-price-display { + margin-left: 0; + text-align: center; + } + + .count-selector { + justify-content: center; + } + + .count-buttons { + justify-content: center; + } + + .scroll-container-full { + height: 190px; + } + + .scroll-item-full { + width: 100px; + height: 165px; + margin: 5px 5px; + } + + .scroll-item-full img { + width: 65px; + height: 55px; + } + + .scroll-container-mini { + height: 130px; + } + + .scroll-item-mini { + width: 60px; + height: 115px; + margin: 4px 4px; + } + + .scroll-item-mini img { + width: 40px; + height: 40px; + } + + .items-grid-compact { + grid-template-columns: repeat(3, 1fr); + } + + .multi-scroll-grid { + grid-template-columns: repeat(2, 1fr) !important; + } + + /* Контракты */ + .contract-items-grid { + grid-template-columns: repeat(2, 1fr); + } + + .case-scroll-container { + height: 250px; + } + + .scroll-item { + width: 150px; + height: 200px; + } + + .scroll-item img { + width: 100px; + height: 80px; + } + + .stats-grid { + grid-template-columns: repeat(2, 1fr); + } + + .cases-grid { + grid-template-columns: 1fr; + } + + .group-items { + grid-template-columns: 1fr; + } + + .group-header { + flex-direction: column; + gap: 0.5rem; + text-align: center; + } + + .group-footer { + flex-direction: column; + gap: 1rem; + } + + .section-cases { + grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); + gap: 0.75rem; + } + + .case-image { + height: 100px; + } + + .case-title { + font-size: 0.85rem; + } + + .case-description { + font-size: 0.7rem; + } } -/* ── Utilities ── */ -.flex { display: flex; } -.flex-col { flex-direction: column; } -.items-center { align-items: center; } -.justify-between { justify-content: space-between; } -.justify-center { justify-content: center; } -.gap-1 { gap: 0.25rem; } -.gap-2 { gap: 0.5rem; } -.gap-3 { gap: 0.75rem; } -.gap-4 { gap: 1rem; } -.mt-1 { margin-top: 0.25rem; } -.mt-2 { margin-top: 0.5rem; } -.mt-3 { margin-top: 0.75rem; } -.mt-4 { margin-top: 1rem; } -.mb-2 { margin-bottom: 0.5rem; } -.mb-4 { margin-bottom: 1rem; } -.text-center { text-align: center; } -.text-dim { color: var(--text-dim); } -.text-primary { color: var(--primary); } -.text-sm { font-size: 0.78rem; } -.text-xs { font-size: 0.7rem; } -.font-display { font-family: var(--font-display); } -.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } -.w-full { width: 100%; } - -/* ── Animations ── */ -@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.5; } } -@keyframes pulseGlow { 0%,100% { box-shadow: 0 0 8px var(--primary-glow); } 50% { box-shadow: 0 0 25px rgba(245,158,11,0.5); } } -@keyframes slideInUp { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } -@keyframes slideInDown { from { transform: translateY(-20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } -@keyframes scaleIn { from { transform: scale(0.9); opacity: 0; } to { transform: scale(1); opacity: 1; } } -@keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } -@keyframes float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-6px); } } -@keyframes shake { 0%,100% { transform: translateX(0); } 20% { transform: translateX(-4px); } 40% { transform: translateX(4px); } 60% { transform: translateX(-3px); } 80% { transform: translateX(3px); } } -.animate-pulse { animation: pulse 2s ease-in-out infinite; } -.animate-float { animation: float 3s ease-in-out infinite; } -.animate-shake { animation: shake 0.4s ease; } -.animate-slideUp { animation: slideInUp 0.3s ease; } -.animate-scaleIn { animation: scaleIn 0.25s ease; } - -@media (prefers-reduced-motion: reduce) { - *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } -} - -/* ── Responsive helpers ── */ -@media (max-width: 1024px) { - .container { padding: 0 15px; } -} -@media (max-width: 768px) { - .hero { padding: 2.5rem 0; } - .section { padding: 1.5rem 0; } - .stats-grid { grid-template-columns: repeat(2, 1fr); } - .admin-content { padding: 1rem; } - .admin-topbar { padding: 0.6rem 1rem; } -} @media (max-width: 480px) { - .stats-grid { grid-template-columns: 1fr; } - .hero-actions { flex-direction: column; align-items: stretch; } - .hero-actions .btn { justify-content: center; } + .nav-links { + flex-wrap: wrap; + justify-content: center; + } + + .nav-link { + font-size: 0.75rem; + padding: 0.3rem 0.4rem; + } + + .hero h1 { + font-size: 1.5rem; + } + + /* Кейсы */ + .case-title-row { + flex-direction: column; + align-items: flex-start; + } + + .scroll-container-full { + height: 170px; + } + + .scroll-item-full { + width: 90px; + height: 150px; + } + + .scroll-item-full img { + width: 55px; + height: 45px; + } + + .scroll-item-name-full { + font-size: 8px; + } + + .scroll-container-mini { + height: 115px; + } + + .scroll-item-mini { + width: 55px; + height: 100px; + } + + .items-grid-compact { + grid-template-columns: repeat(2, 1fr); + } + + .result-item-compact { + min-width: 130px; + } + + /* Апгрейд */ + .upgrade-header h1 { + font-size: 1.3rem; + } + + .wheel-container { + width: 180px; + height: 180px; + } + + .wheel-center { + width: 35px; + height: 35px; + font-size: 0.7rem; + } + + .selected-item-mini img { + width: 50px; + height: 40px; + } + + .history-grid { + grid-template-columns: 1fr; + } + + /* Кейсы */ + .cases-container h1 { + font-size: 1.3rem; + } + + .section-cases { + grid-template-columns: 1fr 1fr; + } + + .case-image { + height: 90px; + } + + .case-info { + padding: 0.5rem; + } } + +/* Общие мобильные фиксы */ +@media (max-width: 768px) { + body { + font-size: 14px; + } + + input, button, select, textarea { + font-size: 16px !important; + } + + html, body { + max-width: 100%; + overflow-x: hidden; + } + + img { + max-width: 100%; + height: auto; + } +} + +/* ===== АПГРЕЙД — РЕДИЗАЙН ===== */ + +body { + font-family: 'Rajdhani', sans-serif; +} + +h1, h2, h3, h4, h5, h6, .logo, .nav-link, .btn { + font-family: 'Rajdhani', sans-serif; +} + +.upgrade-page { + font-family: 'Rajdhani', sans-serif; + background: radial-gradient(ellipse at 50% 0%, #14161f 0%, #0a0b0e 100%); + min-height: 100vh; +} + +.upgrade-page .upgrade-header h1 { + font-family: 'Russo One', sans-serif; + font-size: 1.75rem; + letter-spacing: 0.05em; + text-transform: uppercase; + background: linear-gradient(135deg, #f59e0b 0%, #d97706 50%, #f59e0b 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + text-shadow: none; + filter: drop-shadow(0 0 20px rgba(245, 158, 11, 0.3)); + margin-bottom: 0.25rem; +} + +.upgrade-page .upgrade-header p { + color: #8a8a9a; + font-size: 0.9rem; + letter-spacing: 0.03em; +} + +.upgrade-page .upgrade-layout { + display: grid; + grid-template-columns: 280px 1fr 280px; + gap: 1rem; + margin-bottom: 1.5rem; +} + +.upgrade-page .panel-title { + font-family: 'Russo One', sans-serif; + font-size: 0.8rem; + letter-spacing: 0.08em; + text-transform: uppercase; + color: #c8c6d0; +} + +/* Панели */ +.upgrade-page .inventory-panel, +.upgrade-page .target-panel { + background: rgba(20, 21, 26, 0.8); + backdrop-filter: blur(8px); + border-radius: 10px; + border: 1px solid rgba(255, 255, 255, 0.06); + display: flex; + flex-direction: column; + max-height: 520px; + overflow: hidden; +} + +.upgrade-page .panel-header, +.upgrade-page .target-header { + padding: 0.65rem 0.75rem; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); + flex-shrink: 0; +} + +.upgrade-page .inventory-list, +.upgrade-page .target-list { + flex: 1; + overflow-y: auto; + padding: 0.4rem; + display: flex; + flex-direction: column; + gap: 0.35rem; +} + +.upgrade-page .inventory-list::-webkit-scrollbar, +.upgrade-page .target-list::-webkit-scrollbar { + width: 4px; +} + +.upgrade-page .inventory-list::-webkit-scrollbar-track, +.upgrade-page .target-list::-webkit-scrollbar-track { + background: transparent; +} + +.upgrade-page .inventory-list::-webkit-scrollbar-thumb, +.upgrade-page .target-list::-webkit-scrollbar-thumb { + background: rgba(245, 158, 11, 0.3); + border-radius: 2px; +} + +/* Карточки предметов */ +.upgrade-page .inventory-item-card, +.upgrade-page .target-item-card { + background: rgba(14, 15, 19, 0.9); + border-radius: 8px; + padding: 0.45rem 0.5rem; + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + border: 1px solid rgba(255, 255, 255, 0.04); + transition: all 0.2s ease; + position: relative; +} + +.upgrade-page .inventory-item-card::before, +.upgrade-page .target-item-card::before { + content: ''; + position: absolute; + left: 0; + top: 4px; + bottom: 4px; + width: 2px; + border-radius: 1px; + background: rgba(255, 255, 255, 0.08); + transition: all 0.2s ease; +} + +.upgrade-page .inventory-item-card:hover, +.upgrade-page .target-item-card:hover { + border-color: rgba(245, 158, 11, 0.2); + background: rgba(20, 21, 26, 0.9); +} + +.upgrade-page .inventory-item-card:hover::before, +.upgrade-page .target-item-card:hover::before { + background: rgba(245, 158, 11, 0.4); + width: 3px; +} + +.upgrade-page .inventory-item-card.selected { + border-color: rgba(245, 158, 11, 0.5); + background: rgba(245, 158, 11, 0.06); + box-shadow: 0 0 20px rgba(245, 158, 11, 0.08), inset 0 0 20px rgba(245, 158, 11, 0.03); +} + +.upgrade-page .inventory-item-card.selected::before { + background: #f59e0b; + width: 3px; + box-shadow: 0 0 8px rgba(245, 158, 11, 0.6); +} + +.upgrade-page .inventory-item-card.disabled, +.upgrade-page .target-item-card.disabled { + opacity: 0.35; + cursor: not-allowed; + pointer-events: none; +} + +.upgrade-page .inventory-item-card img, +.upgrade-page .target-item-card img { + width: 42px; + height: 36px; + object-fit: contain; + background: rgba(0, 0, 0, 0.3); + border-radius: 4px; + padding: 2px; + flex-shrink: 0; +} + +.upgrade-page .inventory-item-name, +.upgrade-page .target-item-name { + font-size: 0.72rem; + font-weight: 600; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + color: #d4d2d8; + letter-spacing: 0.01em; +} + +.upgrade-page .inventory-item-meta, +.upgrade-page .target-item-meta { + display: flex; + justify-content: space-between; + font-size: 0.6rem; + color: #6b6b7a; + margin-top: 0.1rem; +} + +.upgrade-page .inventory-item-price, +.upgrade-page .target-item-price { + color: #f59e0b; + font-weight: 700; + font-size: 0.65rem; +} + +/* Сортировка и поиск */ +.upgrade-page .target-search-input { + width: 100%; + padding: 0.45rem 0.6rem; + background: rgba(0, 0, 0, 0.4); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 6px; + color: #e0dde8; + font-size: 0.8rem; + font-family: 'Rajdhani', sans-serif; + outline: none; + transition: border-color 0.2s; + box-sizing: border-box; +} + +.upgrade-page .target-search-input:focus { + border-color: rgba(245, 158, 11, 0.4); +} + +.upgrade-page .sort-controls { + display: flex; + gap: 0.3rem; + margin-top: 0.4rem; +} + +.upgrade-page .sort-btn { + flex: 1; + padding: 0.25rem 0.3rem; + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.04); + border-radius: 4px; + color: #6b6b7a; + font-size: 0.6rem; + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + cursor: pointer; + transition: all 0.15s; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.upgrade-page .sort-btn:hover { + color: #c8c6d0; + border-color: rgba(255, 255, 255, 0.1); +} + +.upgrade-page .sort-btn.active { + color: #f59e0b; + border-color: rgba(245, 158, 11, 0.3); + background: rgba(245, 158, 11, 0.08); +} + +/* Центральная панель — Колесо */ +.upgrade-page .wheel-panel { + background: rgba(20, 21, 26, 0.8); + backdrop-filter: blur(8px); + border-radius: 10px; + border: 1px solid rgba(255, 255, 255, 0.06); + padding: 1.25rem 1rem; + display: flex; + flex-direction: column; + align-items: center; +} + +.upgrade-page .selected-items-display { + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + margin-bottom: 0.75rem; + width: 100%; +} + +.upgrade-page .selected-item-mini { + text-align: center; + flex: 1; + min-width: 0; +} + +.upgrade-page .selected-item-mini .item-frame { + width: 64px; + height: 52px; + margin: 0 auto; + background: rgba(0, 0, 0, 0.4); + border-radius: 6px; + border: 1px solid rgba(255, 255, 255, 0.06); + display: flex; + align-items: center; + justify-content: center; + padding: 4px; + transition: all 0.3s; +} + +.upgrade-page .selected-item-mini.selected .item-frame { + border-color: rgba(245, 158, 11, 0.4); + box-shadow: 0 0 15px rgba(245, 158, 11, 0.1); +} + +.upgrade-page .selected-item-mini img { + width: 100%; + height: 100%; + object-fit: contain; +} + +.upgrade-page .selected-item-mini-name { + font-size: 0.62rem; + margin-top: 0.25rem; + color: #8a8a9a; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.upgrade-page .selected-item-mini-price { + font-size: 0.7rem; + color: #f59e0b; + font-weight: 700; + font-family: 'Rajdhani', sans-serif; +} + +.upgrade-page .arrow-icon { + font-size: 1rem; + color: #4a4a5a; + flex-shrink: 0; + opacity: 0.5; +} + +/* Колесо */ +.upgrade-page .wheel-container { + position: relative; + width: 280px; + height: 280px; + margin: 0.25rem 0 0.5rem; +} + +.upgrade-page .wheel-outer-ring { + position: absolute; + inset: -8px; + border-radius: 50%; + background: conic-gradient( + from 0deg, + rgba(245, 158, 11, 0.08), + rgba(245, 158, 11, 0.02) 25%, + rgba(245, 158, 11, 0.08) 50%, + rgba(245, 158, 11, 0.02) 75%, + rgba(245, 158, 11, 0.08) 100% + ); + border: 1px solid rgba(245, 158, 11, 0.15); +} + +.upgrade-page .wheel { + width: 100%; + height: 100%; + border-radius: 50%; + background: conic-gradient( + from calc(180deg - var(--probability, 0) * 3.6deg / 2), + #10b981 0deg, + #10b981 calc(var(--probability, 0) * 3.6deg), + #2d1b1b calc(var(--probability, 0) * 3.6deg), + #2d1b1b 360deg + ); + border: 2px solid rgba(255, 255, 255, 0.08); + box-shadow: + 0 0 40px rgba(0, 0, 0, 0.6), + inset 0 0 30px rgba(0, 0, 0, 0.4); + position: relative; + z-index: 1; +} + +.upgrade-page .wheel::after { + content: ''; + position: absolute; + inset: 4px; + border-radius: 50%; + border: 1px solid rgba(255, 255, 255, 0.04); +} + +/* Tick marks */ +.upgrade-page .wheel-ticks { + position: absolute; + inset: -4px; + border-radius: 50%; + z-index: 2; + pointer-events: none; +} + +.upgrade-page .wheel-ticks::before { + content: ''; + position: absolute; + inset: 2px; + border-radius: 50%; + background: repeating-conic-gradient( + from 0deg, + transparent 0deg, + transparent 2deg, + rgba(255, 255, 255, 0.06) 2deg, + rgba(255, 255, 255, 0.06) 3deg + ); +} + +/* Pointer container — вращается вокруг колеса */ +.upgrade-page .wheel-pointer-container { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 10; + pointer-events: none; + transform-origin: center center; +} + +/* Pointer */ +.upgrade-page .wheel-pointer { + position: absolute; + top: -14px; + left: 50%; + transform: translateX(-50%); + width: 0; + height: 0; + border-left: 10px solid transparent; + border-right: 10px solid transparent; + border-top: 24px solid #f59e0b; + filter: drop-shadow(0 0 10px rgba(245, 158, 11, 0.6)) drop-shadow(0 0 20px rgba(245, 158, 11, 0.3)); +} + +.upgrade-page .wheel-pointer::after { + content: ''; + position: absolute; + top: -28px; + left: -4px; + width: 8px; + height: 8px; + background: #f59e0b; + border-radius: 50%; + box-shadow: 0 0 12px rgba(245, 158, 11, 0.8); +} + +/* Center hub */ +.upgrade-page .wheel-center { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 52px; + height: 52px; + background: radial-gradient(circle at 40% 35%, #1e1f2a, #0a0b0e); + border-radius: 50%; + border: 2px solid rgba(245, 158, 11, 0.3); + display: flex; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: 0.85rem; + color: #f59e0b; + z-index: 5; + font-family: 'Russo One', sans-serif; + box-shadow: + 0 0 20px rgba(245, 158, 11, 0.1), + inset 0 0 15px rgba(0, 0, 0, 0.5); + letter-spacing: 0.02em; +} + + + +/* Кнопка апгрейда */ +.upgrade-page .upgrade-btn { + padding: 0.65rem 2.5rem; + font-family: 'Russo One', sans-serif; + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 0.1em; + background: linear-gradient(135deg, #f59e0b, #d97706); + color: #0a0b0e; + border: none; + border-radius: 6px; + cursor: pointer; + transition: all 0.25s; + position: relative; + overflow: hidden; + margin-top: 0.25rem; +} + +.upgrade-page .upgrade-btn:hover:not(:disabled) { + transform: translateY(-1px); + box-shadow: 0 4px 20px rgba(245, 158, 11, 0.3); +} + +.upgrade-page .upgrade-btn:active:not(:disabled) { + transform: translateY(0); +} + +.upgrade-page .upgrade-btn:disabled { + opacity: 0.3; + cursor: not-allowed; +} + +.upgrade-page .upgrade-btn::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(135deg, transparent 40%, rgba(255,255,255,0.15) 50%, transparent 60%); + transition: transform 0.4s; + transform: translateX(-100%); +} + +.upgrade-page .upgrade-btn:hover:not(:disabled)::after { + transform: translateX(100%); +} + +/* Результат */ +/* Toast */ +.toast-container { + position: fixed; + top: 70px; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + display: flex; + flex-direction: column; + gap: 0.4rem; + pointer-events: none; +} + +.toast { + padding: 0.5rem 1rem; + border-radius: 8px; + font-size: 0.8rem; + font-weight: 600; + white-space: nowrap; + opacity: 0; + transform: translateY(-10px); + transition: all 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.2); + pointer-events: auto; + background: var(--bg-card); + border: 1px solid var(--border-color); + color: var(--text-primary); + box-shadow: 0 4px 20px rgba(0,0,0,0.5); +} + +.toast.show { + opacity: 1; + transform: translateY(0); +} + +.toast.success { + border-color: #10b981; + box-shadow: 0 4px 20px rgba(16,185,129,0.3); +} + +.toast.fail { + border-color: #ef4444; + box-shadow: 0 4px 20px rgba(239,68,68,0.2); +} + +.upgrade-page .result-item-display img { + width: 72px; + height: 60px; + object-fit: contain; + animation: resultItemSlide 0.5s ease; +} + +.upgrade-page .result-item-display span { + font-size: 0.65rem; + color: #8a8a9a; + text-align: center; + max-width: 180px; +} + +@keyframes resultFadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes resultPulse { + 0% { transform: scale(0.5); opacity: 0; } + 60% { transform: scale(1.15); } + 100% { transform: scale(1); opacity: 1; } +} + +@keyframes resultItemSlide { + from { transform: translateY(20px); opacity: 0; } + to { transform: translateY(0); opacity: 1; } +} + +/* Win sparkles */ +.upgrade-page .sparkle-container { + position: absolute; + inset: 0; + pointer-events: none; + z-index: 25; + overflow: hidden; + border-radius: 10px; +} + +.upgrade-page .sparkle { + position: absolute; + width: 4px; + height: 4px; + background: #f59e0b; + border-radius: 50%; + animation: sparkleFloat 1.5s ease-out forwards; +} + +@keyframes sparkleFloat { + 0% { + transform: translate(0, 0) scale(1); + opacity: 1; + } + 100% { + transform: translate(var(--dx, 50px), var(--dy, -80px)) scale(0); + opacity: 0; + } +} + +/* История */ +.upgrade-page .history-section { + margin-top: 0.5rem; +} + +.upgrade-page .history-title { + font-family: 'Russo One', sans-serif; + font-size: 0.85rem; + letter-spacing: 0.06em; + text-transform: uppercase; + color: #6b6b7a; + margin-bottom: 0.6rem; +} + +.upgrade-page .history-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + gap: 0.5rem; +} + +.upgrade-page .history-card { + background: rgba(20, 21, 26, 0.6); + border-radius: 8px; + padding: 0.5rem 0.6rem; + display: flex; + align-items: center; + gap: 0.5rem; + border: 1px solid rgba(255, 255, 255, 0.04); + transition: border-color 0.2s; +} + +.upgrade-page .history-card:hover { + border-color: rgba(255, 255, 255, 0.08); +} + +.upgrade-page .history-card.success { + border-left: 3px solid rgba(16, 185, 129, 0.5); +} + +.upgrade-page .history-card.fail { + border-left: 3px solid rgba(239, 68, 68, 0.4); +} + +.upgrade-page .history-card img { + width: 36px; + height: 30px; + object-fit: contain; + background: rgba(0, 0, 0, 0.3); + border-radius: 4px; + padding: 2px; + flex-shrink: 0; +} + +.upgrade-page .history-info { + flex: 1; + min-width: 0; +} + +.upgrade-page .history-names { + font-size: 0.68rem; + color: #b0aeb8; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.upgrade-page .history-meta { + display: flex; + justify-content: space-between; + font-size: 0.6rem; + color: #6b6b7a; + margin-top: 0.1rem; +} + +.upgrade-page .history-result.success { + color: #10b981; + font-weight: 600; +} + +.upgrade-page .history-result.fail { + color: #ef4444; + font-weight: 600; +} + +/* Быстрые фильтры цены */ +.upgrade-page .price-filter-bar { + display: flex; + gap: 0.25rem; + margin-top: 0.4rem; + flex-wrap: wrap; +} + +.upgrade-page .pf-btn { + padding: 0.2rem 0.45rem; + background: rgba(0, 0, 0, 0.3); + border: 1px solid rgba(255, 255, 255, 0.04); + border-radius: 4px; + color: #6b6b7a; + font-size: 0.6rem; + font-family: 'Rajdhani', sans-serif; + font-weight: 600; + cursor: pointer; + transition: all 0.15s; + text-transform: uppercase; + letter-spacing: 0.03em; +} + +.upgrade-page .pf-btn:hover { + color: #c8c6d0; + border-color: rgba(255, 255, 255, 0.1); +} + +.upgrade-page .pf-btn.active { + color: #f59e0b; + border-color: rgba(245, 158, 11, 0.3); + background: rgba(245, 158, 11, 0.08); +} + +/* Пустое состояние */ +.upgrade-page .empty-state { + text-align: center; + padding: 1.5rem 0.5rem; + color: #4a4a5a; + font-size: 0.8rem; +} + +/* Адаптивность */ +@media (max-width: 1000px) { + .upgrade-page .upgrade-layout { + grid-template-columns: 1fr; + gap: 0.75rem; + } + .upgrade-page .inventory-panel, + .upgrade-page .target-panel { + max-height: 320px; + } + .upgrade-page .wheel-container { + width: 240px; + height: 240px; + } +} + +@media (max-width: 768px) { + .upgrade-page .upgrade-header h1 { + font-size: 1.3rem; + } + .upgrade-page .wheel-container { + width: 200px; + height: 200px; + } + .upgrade-page .wheel-center { + width: 44px; + height: 44px; + font-size: 0.7rem; + } + .upgrade-page .selected-item-mini .item-frame { + width: 52px; + height: 42px; + } + .upgrade-page .history-grid { + grid-template-columns: 1fr; + } +} + +/* ===== Дополнительные стили для скролла ===== */ +.scroll-item-sm.target-item { + transition: all 0.3s ease; + z-index: 100; +} + +.mini-scroll-item-sm.target-mini-item { + transition: all 0.3s ease; + z-index: 100; +} + +.scroll-item-sm.target-item[style*="border-color"] { + box-shadow: 0 0 30px currentColor; +} + +.mini-scroll-item-sm.target-mini-item[style*="border-color"] { + box-shadow: 0 0 20px currentColor; +} + +.multi-scroll-container { + display: grid; + gap: 1.5rem; + margin: 2rem 0; + justify-content: center; +} + +.scroll-wrapper { + text-align: center; +} + +.mini-scroll-container { + width: 100%; + min-width: 180px; + height: 200px; + position: relative; + overflow: hidden; + background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); + border-radius: 8px; + border: 2px solid var(--border-color); +} + +.mini-scroll-track { + display: flex; + position: absolute; + top: 0; + left: 0; + height: 100%; + will-change: transform; + transition: filter 0.3s; +} + +.mini-scroll-item { + width: 90px; + height: 180px; + margin: 10px 10px; + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: center; + background: var(--bg-card); + border-radius: 6px; + padding: 8px 4px; + border: 2px solid transparent; +} + +.mini-scroll-item img { + width: 70px; + height: 70px; + object-fit: contain; +} + +.mini-item-name { + font-size: 9px; + text-align: center; + margin-top: 5px; + word-break: break-word; +} + +.mini-item-rarity { + font-size: 8px; + margin-top: 3px; + font-weight: bold; +} + +.mini-center-indicator { + position: absolute; + left: 50%; + top: 0; + bottom: 0; + width: 3px; + background: linear-gradient(to bottom, transparent, #ffd700, #ffd700, transparent); + transform: translateX(-50%); + z-index: 10; + box-shadow: 0 0 20px #ffd700; + pointer-events: none; +} + +.result-count { + position: absolute; + top: 5px; + right: 5px; + background: var(--primary-color); + color: white; + border-radius: 50%; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + font-weight: bold; +} + +.result-item { + position: relative; +} + +.results-actions { + display: flex; + gap: 1rem; + justify-content: center; + margin-top: 2rem; +} + +/* ====== Всеобщий UI-полироль ====== */ + +/* Плавные скроллбары */ +::-webkit-scrollbar { width: 6px; height: 6px; } +::-webkit-scrollbar-track { background: transparent; } +::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.08); border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.15); } + +/* Стеклянные карточки */ +.glass-card, .card, [class*="panel"] { + background: rgba(20, 21, 26, 0.7); + backdrop-filter: blur(12px); + border: 1px solid var(--border-color); + border-radius: 12px; + transition: border-color 0.2s, box-shadow 0.2s; +} +.glass-card:hover, .card:hover, [class*="panel"]:hover { + border-color: rgba(255,255,255,0.1); +} + +/* Тени для всех модалок */ +.modal, [class*="modal"], [class*="Modal"] { + background: rgba(10, 11, 14, 0.85); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); +} + +/* Плавные переходы для элементов */ +a, button, .btn, .nav-link, .item-card, [class*="btn"] { + transition: all 0.2s ease; +} + +/* Улучшенные кнопки */ +.btn { + position: relative; + overflow: hidden; + border-radius: 8px; + font-weight: 600; + letter-spacing: 0.02em; + cursor: pointer; + border: none; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 0.4rem; +} +.btn:active { + transform: scale(0.97); +} +.btn-primary { + background: linear-gradient(135deg, var(--primary-color), #f97316); + color: white; +} +.btn-primary:hover { + filter: brightness(1.1); + box-shadow: 0 4px 20px rgba(245, 158, 11, 0.3); +} + +/* Плавный вход для контента */ +main, .container, .crash-layout, .inventory-container { + animation: contentFadeIn 0.3s ease; +} +@keyframes contentFadeIn { + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } +} + +/* Нормализация отступов */ +main { + padding: 1.5rem 1rem; +} +main.container { + padding: 1.5rem 20px; +} + +/* Улучшенный текст */ +p, span, div, label { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* Красивые инпуты */ +input, select, textarea { + background: rgba(255,255,255,0.04); + border: 1px solid var(--border-color); + border-radius: 8px; + color: var(--text-primary); + padding: 0.6rem 0.8rem; + font-family: 'Rajdhani', sans-serif; + font-size: 0.95rem; + transition: border-color 0.2s, box-shadow 0.2s; + outline: none; +} +input:focus, select:focus, textarea:focus { + border-color: var(--primary-color); + box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.1); +} +input::placeholder { + color: var(--text-secondary); + opacity: 0.6; +} + +/* Улучшенные ссылки */ +a:not(.btn):not(.nav-link):not(.logo) { + color: var(--primary-color); + text-decoration: none; + border-bottom: 1px solid transparent; + transition: border-color 0.2s; +} +a:not(.btn):not(.nav-link):not(.logo):hover { + border-bottom-color: var(--primary-color); +} \ No newline at end of file diff --git a/static/js/app.js b/static/js/app.js index 0a8c690..e2bc26c 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -1,132 +1,155 @@ +// ─── Shared CS2 Simulator Utilities ───────────────────────────────────────── + +// Logout async function logout() { - try { await fetch('/web/api/auth/logout', { method: 'POST' }); } catch (e) {} - window.location.href = '/'; + try { + await fetch('/web/api/auth/logout', { method: 'POST' }); + } catch (e) {} + window.location.href = '/'; } +// Refresh balance display async function refreshBalance() { - try { - const res = await fetch('/web/api/user/balance'); - const data = await res.json(); - if (data.success) { - document.querySelectorAll('.user-balance').forEach(el => { - const old = el.textContent; - const val = `${Math.floor(data.balance)} ₽`; - if (old !== val) { - el.textContent = val; - el.classList.remove('animate-scaleIn'); - void el.offsetWidth; - el.classList.add('animate-scaleIn'); + try { + const res = await fetch('/web/api/user/balance'); + const data = await res.json(); + if (data.success) { + document.querySelectorAll('.user-balance').forEach(el => { + el.textContent = `${Math.floor(data.balance)} ₽`; + }); } - }); - } - } catch (e) {} + } catch (e) {} } +// Rarity colors function getRarityColor(rarity) { - const colors = { - 'Consumer Grade': '#b0b0b0', - 'Industrial Grade': '#5e98d9', - 'Mil-Spec': '#4b69ff', - 'Mil-Spec Grade': '#4b69ff', - 'Restricted': '#8847ff', - 'Classified': '#d32ce6', - 'Covert': '#eb4b4b', - 'Rare Special Item': '#ffd700', - 'Extraordinary': '#ffd700', - }; - return colors[rarity] || '#b0b0b0'; + const colors = { + 'Consumer Grade': '#b0b0b0', + 'Industrial Grade': '#5e98d9', + 'Mil-Spec': '#4b69ff', + 'Mil-Spec Grade': '#4b69ff', + 'Restricted': '#8847ff', + 'Classified': '#d32ce6', + 'Covert': '#eb4b4b', + 'Rare Special Item': '#ffd700', + 'Extraordinary': '#ffd700', + }; + return colors[rarity] || '#b0b0b0'; } +// Format number with spaces function formatNumber(n) { - return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' '); + return n.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' '); } +// Debounce function debounce(fn, ms = 300) { - let timer; - return function (...args) { - clearTimeout(timer); - timer = setTimeout(() => fn.apply(this, args), ms); - }; + let timer; + return function (...args) { + clearTimeout(timer); + timer = setTimeout(() => fn.apply(this, args), ms); + }; } +// Escape HTML function escapeHtml(str) { - const div = document.createElement('div'); - div.textContent = str; - return div.innerHTML; + const div = document.createElement('div'); + div.textContent = str; + return div.innerHTML; } +// Show notification function showNotification(message, type = 'info', duration = 3000) { - let container = document.getElementById('toastContainer'); - if (!container) { - container = document.createElement('div'); - container.id = 'toastContainer'; - container.className = 'toast-container'; - document.body.appendChild(container); - } + const existing = document.querySelector('.notification-toast'); + if (existing) existing.remove(); - const icons = { success: '✓', error: '✗', info: 'ℹ', warning: '⚠' }; - const toast = document.createElement('div'); - toast.className = `toast toast-${type} animate-slideUp`; - toast.innerHTML = `${icons[type] || ''}${message}`; - container.appendChild(toast); + const colors = { + success: '#22c55e', + error: '#ef4444', + info: '#3b82f6', + warning: '#f59e0b', + }; - setTimeout(() => { - toast.style.opacity = '0'; - toast.style.transform = 'translateX(100%)'; - toast.style.transition = 'all 0.3s ease'; - setTimeout(() => toast.remove(), 300); - }, duration); -} - -function showAchievementPopup(title, reward) { - let popup = document.getElementById('achievementGlobalPopup'); - if (!popup) { - popup = document.createElement('div'); - popup.id = 'achievementGlobalPopup'; - popup.className = 'modal-overlay'; - popup.style.background = 'rgba(0,0,0,0.5)'; - popup.style.alignItems = 'flex-start'; - popup.style.paddingTop = '60px'; - popup.innerHTML = ` -
-
🏆 Достижение разблокировано!
-
-
-
+ const toast = document.createElement('div'); + toast.className = 'notification-toast'; + toast.style.cssText = ` + position: fixed; top: 20px; right: 20px; z-index: 99999; + background: #1a1a2e; border: 1px solid ${colors[type] || colors.info}; + color: white; padding: 12px 20px; border-radius: 8px; + font-size: 14px; box-shadow: 0 10px 40px rgba(0,0,0,0.5); + animation: slideInRight 0.3s ease; max-width: 400px; `; - document.body.appendChild(popup); - } + toast.textContent = message; + document.body.appendChild(toast); - document.getElementById('globalPopupTitle').textContent = title; - document.getElementById('globalPopupReward').textContent = reward ? `+${reward} ₽` : ''; - popup.style.display = 'flex'; - - if (window.SoundManager) SoundManager.achievement(); - - setTimeout(() => { - popup.style.display = 'none'; - }, 4000); + setTimeout(() => { + toast.style.animation = 'slideOutRight 0.3s ease forwards'; + setTimeout(() => toast.remove(), 300); + }, duration); } -document.addEventListener('DOMContentLoaded', () => { - const toggle = document.getElementById('mobileToggle'); - const nav = document.getElementById('navLinks'); - if (toggle && nav) { - toggle.addEventListener('click', () => { - nav.classList.toggle('open'); - }); - document.addEventListener('click', (e) => { - if (!toggle.contains(e.target) && !nav.contains(e.target)) { - nav.classList.remove('open'); - } - }); - } +// Inject notification styles once +if (!document.getElementById('notificationStyles')) { + const style = document.createElement('style'); + style.id = 'notificationStyles'; + style.textContent = ` + @keyframes slideInRight { + from { transform: translateX(120%); opacity: 0; } + to { transform: translateX(0); opacity: 1; } + } + @keyframes slideOutRight { + from { transform: translateX(0); opacity: 1; } + to { transform: translateX(120%); opacity: 0; } + } + `; + document.head.appendChild(style); +} - const soundToggle = document.getElementById('soundToggle'); - if (soundToggle && window.SoundManager) { - soundToggle.addEventListener('click', () => { - const enabled = SoundManager.toggle(); - soundToggle.textContent = enabled ? '🔊' : '🔇'; - }); - } -}); +// Show achievement popup (global function used by templates) +function showAchievementPopup(title, reward) { + let popup = document.getElementById('achievementGlobalPopup'); + if (!popup) { + popup = document.createElement('div'); + popup.id = 'achievementGlobalPopup'; + popup.style.cssText = ` + position: fixed; top: 20px; left: 50%; transform: translateX(-50%); + z-index: 99999; background: linear-gradient(135deg, #1a3a1a, #0d260d); + border: 1px solid #22c55e; border-radius: 12px; padding: 1rem 1.5rem; + box-shadow: 0 10px 40px rgba(0,0,0,0.5); + animation: slideInDown 0.5s ease; max-width: 400px; width: 90%; + text-align: center; + `; + popup.innerHTML = ` +
🏆 Новое достижение!
+
+
+ `; + document.body.appendChild(popup); + + if (!document.getElementById('slideInDownStyle')) { + const s = document.createElement('style'); + s.id = 'slideInDownStyle'; + s.textContent = ` + @keyframes slideInDown { + from { transform: translateX(-50%) translateY(-120%); opacity: 0; } + to { transform: translateX(-50%) translateY(0); opacity: 1; } + } + `; + document.head.appendChild(s); + } + } + + document.getElementById('globalPopupTitle').textContent = title; + document.getElementById('globalPopupReward').textContent = reward ? `+${reward} ₽` : ''; + popup.style.display = 'block'; + + if (window.SoundManager) SoundManager.achievement(); + + setTimeout(() => { + popup.style.animation = 'slideInDown 0.5s ease reverse forwards'; + setTimeout(() => { + popup.style.display = 'none'; + popup.style.animation = 'slideInDown 0.5s ease'; + }, 500); + }, 4000); +} diff --git a/static/js/sounds.js b/static/js/sounds.js index 921d528..3035950 100644 --- a/static/js/sounds.js +++ b/static/js/sounds.js @@ -1,349 +1,185 @@ +// Sound effects system using Web Audio API - no external files needed const SoundManager = { - _ctx: null, - _master: null, - _analyser: null, - _enabled: true, - _volume: 0.3, - _ambient: null, - _ambientGain: null, - _initCalled: false, + _ctx: null, + _enabled: true, + _volume: 0.3, - init() { - if (this._initCalled) return; - this._initCalled = true; - try { - this._ctx = new (window.AudioContext || window.webkitAudioContext)(); - this._master = this._ctx.createGain(); - this._master.gain.value = this._volume; - this._master.connect(this._ctx.destination); - } catch (e) { - console.warn('Web Audio API not supported'); - this._enabled = false; + init() { + try { + this._ctx = new (window.AudioContext || window.webkitAudioContext)(); + } catch (e) { + console.warn('Web Audio API not supported'); + this._enabled = false; + } + const saved = localStorage.getItem('sound_enabled'); + if (saved !== null) this._enabled = saved === 'true'; + }, + + setEnabled(on) { + this._enabled = on; + localStorage.setItem('sound_enabled', on); + }, + + toggle() { + this.setEnabled(!this._enabled); + return this._enabled; + }, + + _play(freq, duration, type = 'sine', volume = 1) { + if (!this._enabled || !this._ctx) return; + if (this._ctx.state === 'suspended') this._ctx.resume(); + + const osc = this._ctx.createOscillator(); + const gain = this._ctx.createGain(); + osc.type = type; + osc.frequency.setValueAtTime(freq, this._ctx.currentTime); + gain.gain.setValueAtTime(this._volume * volume, this._ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.001, this._ctx.currentTime + duration); + osc.connect(gain); + gain.connect(this._ctx.destination); + osc.start(); + osc.stop(this._ctx.currentTime + duration); + }, + + _noise(duration, volume = 1) { + if (!this._enabled || !this._ctx) return; + if (this._ctx.state === 'suspended') this._ctx.resume(); + + const bufferSize = this._ctx.sampleRate * duration; + const buffer = this._ctx.createBuffer(1, bufferSize, this._ctx.sampleRate); + const data = buffer.getChannelData(0); + for (let i = 0; i < bufferSize; i++) { + data[i] = Math.random() * 2 - 1; + } + const source = this._ctx.createBufferSource(); + source.buffer = buffer; + const gain = this._ctx.createGain(); + gain.gain.setValueAtTime(this._volume * volume, this._ctx.currentTime); + gain.gain.exponentialRampToValueAtTime(0.001, this._ctx.currentTime + duration); + source.connect(gain); + gain.connect(this._ctx.destination); + source.start(); + }, + + caseOpen() { + // Descending sweep with click + this._play(800, 0.1, 'square', 0.3); + setTimeout(() => this._play(400, 0.15, 'sawtooth', 0.2), 80); + setTimeout(() => this._play(200, 0.2, 'sine', 0.15), 180); + this._noise(0.05, 0.4); + }, + + caseRare() { + // Ascending bright chime for rare items + this._play(523, 0.15, 'sine', 0.3); + setTimeout(() => this._play(659, 0.15, 'sine', 0.3), 100); + setTimeout(() => this._play(784, 0.15, 'sine', 0.3), 200); + setTimeout(() => this._play(1047, 0.3, 'sine', 0.4), 300); + }, + + caseCovert() { + // Epic sound for covert/knife + this._play(392, 0.2, 'sawtooth', 0.3); + setTimeout(() => this._play(523, 0.2, 'sawtooth', 0.3), 150); + setTimeout(() => this._play(659, 0.2, 'sawtooth', 0.3), 300); + setTimeout(() => this._play(784, 0.4, 'sine', 0.5), 450); + setTimeout(() => this._play(1047, 0.6, 'sine', 0.6), 600); + }, + + slotSpin() { + // Ratcheting sound for slot reels + for (let i = 0; i < 8; i++) { + setTimeout(() => { + this._play(300 + Math.random() * 400, 0.05, 'square', 0.15); + }, i * 80); + } + }, + + slotMatch() { + // Win jingle + this._play(523, 0.1, 'sine', 0.3); + setTimeout(() => this._play(659, 0.1, 'sine', 0.3), 100); + setTimeout(() => this._play(784, 0.1, 'sine', 0.3), 200); + setTimeout(() => this._play(1047, 0.4, 'sine', 0.5), 300); + }, + + contractSubmit() { + // Mechanical sound + this._play(150, 0.3, 'sawtooth', 0.2); + setTimeout(() => this._play(200, 0.2, 'square', 0.2), 200); + setTimeout(() => this._play(250, 0.1, 'square', 0.15), 350); + }, + + contractResult() { + // Rising success + this._play(400, 0.15, 'sine', 0.3); + setTimeout(() => this._play(600, 0.15, 'sine', 0.3), 120); + setTimeout(() => this._play(800, 0.3, 'sine', 0.4), 240); + }, + + wheelSpin() { + // Ticking as wheel rotates + this._play(200, 0.03, 'square', 0.1); + }, + + wheelWin() { + // Celebration + this._play(523, 0.15, 'sine', 0.3); + setTimeout(() => this._play(659, 0.15, 'sine', 0.3), 120); + setTimeout(() => this._play(784, 0.2, 'sine', 0.35), 240); + setTimeout(() => this._play(1047, 0.5, 'sine', 0.5), 360); + }, + + wheelLose() { + // Sad trombone + this._play(400, 0.2, 'sine', 0.2); + setTimeout(() => this._play(350, 0.2, 'sine', 0.2), 150); + setTimeout(() => this._play(300, 0.3, 'sine', 0.15), 300); + }, + + achievement() { + // Achievement unlock + this._play(659, 0.1, 'sine', 0.3); + setTimeout(() => this._play(523, 0.1, 'sine', 0.3), 100); + setTimeout(() => this._play(784, 0.1, 'sine', 0.3), 200); + setTimeout(() => this._play(659, 0.1, 'sine', 0.3), 300); + setTimeout(() => this._play(1047, 0.4, 'sine', 0.5), 400); + }, + + crashBet() { + this._play(300, 0.1, 'square', 0.15); + }, + + crashTick() { + this._play(500 + Math.random() * 500, 0.03, 'sine', 0.08); + }, + + crashCrashed() { + // Explosion + this._noise(0.3, 0.6); + this._play(80, 0.5, 'sawtooth', 0.4); + setTimeout(() => this._play(50, 0.8, 'sine', 0.3), 100); + }, + + crashCashout() { + // Cashout success + this._play(600, 0.1, 'sine', 0.3); + setTimeout(() => this._play(800, 0.1, 'sine', 0.3), 80); + setTimeout(() => this._play(1000, 0.2, 'sine', 0.4), 160); + }, + + click() { + this._play(800, 0.03, 'sine', 0.1); + }, + + error() { + this._play(200, 0.15, 'square', 0.2); + }, + + balanceUpdate() { + this._play(1000, 0.05, 'sine', 0.1); } - const saved = localStorage.getItem('sound_enabled'); - if (saved !== null) this._enabled = saved === 'true'; - const vol = localStorage.getItem('sound_volume'); - if (vol !== null) this.setVolume(parseFloat(vol)); - - document.addEventListener('click', () => { - if (this._ctx && this._ctx.state === 'suspended') this._ctx.resume(); - }, { once: true }); - }, - - setEnabled(on) { - this._enabled = on; - localStorage.setItem('sound_enabled', on); - if (!on && this._ambientGain) { - this._ambientGain.gain.setTargetAtTime(0, this._ctx.currentTime, 0.5); - } - }, - - toggle() { - this.setEnabled(!this._enabled); - return this._enabled; - }, - - setVolume(v) { - this._volume = Math.max(0, Math.min(1, v)); - if (this._master) this._master.gain.value = this._volume; - localStorage.setItem('sound_volume', this._volume); - }, - - _t() { - return this._ctx ? this._ctx.currentTime : 0; - }, - - _osc(freq, duration, type = 'sine', vol = 1, dest) { - if (!this._enabled || !this._ctx) return; - if (this._ctx.state === 'suspended') this._ctx.resume(); - const now = this._t(); - const o = this._ctx.createOscillator(); - const g = this._ctx.createGain(); - o.type = type; - o.frequency.setValueAtTime(freq, now); - g.gain.setValueAtTime(vol, now); - g.gain.exponentialRampToValueAtTime(0.001, now + duration); - o.connect(g); - g.connect(dest || this._master); - o.start(now); - o.stop(now + duration); - }, - - _noise(duration, vol = 1, filterFreq, dest) { - if (!this._enabled || !this._ctx) return; - if (this._ctx.state === 'suspended') this._ctx.resume(); - const now = this._t(); - const sr = this._ctx.sampleRate; - const len = sr * duration; - const buf = this._ctx.createBuffer(1, len, sr); - const data = buf.getChannelData(0); - for (let i = 0; i < len; i++) data[i] = Math.random() * 2 - 1; - const src = this._ctx.createBufferSource(); - src.buffer = buf; - let node = src; - if (filterFreq) { - const f = this._ctx.createBiquadFilter(); - f.type = 'lowpass'; - f.frequency.value = filterFreq; - src.connect(f); - node = f; - } - const g = this._ctx.createGain(); - g.gain.setValueAtTime(vol, now); - g.gain.exponentialRampToValueAtTime(0.001, now + duration); - node.connect(g); - g.connect(dest || this._master); - src.start(now); - }, - - _chord(freqs, duration, type = 'sine', vol = 0.15) { - freqs.forEach(f => this._osc(f, duration, type, vol / freqs.length)); - }, - - // ── Rarity color helpers ── - _rarityParams(rarity) { - const map = { - 'Consumer Grade': { baseFreq: 300, arp: [300, 350, 400], noiseVol: 0.2, dur: 0.6 }, - 'Industrial Grade': { baseFreq: 400, arp: [400, 500, 600], noiseVol: 0.2, dur: 0.7 }, - 'Mil-Spec': { baseFreq: 500, arp: [500, 630, 750], noiseVol: 0.25, dur: 0.8 }, - 'Mil-Spec Grade': { baseFreq: 500, arp: [500, 630, 750], noiseVol: 0.25, dur: 0.8 }, - 'Restricted': { baseFreq: 600, arp: [600, 750, 900], noiseVol: 0.3, dur: 1.0 }, - 'Classified': { baseFreq: 700, arp: [700, 880, 1050], noiseVol: 0.35, dur: 1.2 }, - 'Covert': { baseFreq: 800, arp: [800, 1000, 1200], noiseVol: 0.4, dur: 1.5 }, - 'Rare Special Item': { baseFreq: 900, arp: [900, 1100, 1400], noiseVol: 0.45, dur: 1.8 }, - 'Extraordinary': { baseFreq: 900, arp: [900, 1100, 1400], noiseVol: 0.45, dur: 1.8 }, - }; - return map[rarity] || map['Consumer Grade']; - }, - - // ── Ambient ── - startAmbient() { - if (!this._ctx || this._ambient) return; - const now = this._t(); - this._ambientGain = this._ctx.createGain(); - this._ambientGain.gain.value = 0; - - const bufLen = this._ctx.sampleRate * 2; - const buf = this._ctx.createBuffer(1, bufLen, this._ctx.sampleRate); - const data = buf.getChannelData(0); - for (let i = 0; i < bufLen; i++) { - const t = i / this._ctx.sampleRate; - data[i] = (Math.random() - 0.5) * 0.5 - + Math.sin(2 * Math.PI * 55 * t) * 0.08 - + Math.sin(2 * Math.PI * 82.5 * t) * 0.05; - } - const src = this._ctx.createBufferSource(); - src.buffer = buf; - src.loop = true; - - const lp = this._ctx.createBiquadFilter(); - lp.type = 'lowpass'; - lp.frequency.value = 300; - - const hp = this._ctx.createBiquadFilter(); - hp.type = 'highpass'; - hp.frequency.value = 40; - - src.connect(lp); - lp.connect(hp); - hp.connect(this._ambientGain); - this._ambientGain.connect(this._master); - src.start(); - this._ambient = src; - this._ambientGain.gain.setTargetAtTime(0.06, now, 1); - }, - - stopAmbient() { - if (this._ambientGain) { - this._ambientGain.gain.setTargetAtTime(0, this._t(), 0.5); - setTimeout(() => { - if (this._ambient) { try { this._ambient.stop(); } catch (e) {} this._ambient = null; } - }, 1500); - } - }, - - // ── Case Opening ── - caseOpen() { - this._noise(0.15, 0.4, 2000); - this._osc(700, 0.06, 'square', 0.25); - setTimeout(() => this._osc(500, 0.08, 'square', 0.2), 50); - setTimeout(() => this._osc(350, 0.1, 'sawtooth', 0.18), 110); - setTimeout(() => this._osc(250, 0.12, 'sine', 0.12), 180); - setTimeout(() => this._noise(0.3, 0.15, 4000), 120); - }, - - caseReveal(rarity) { - const p = this._rarityParams(rarity); - this._noise(0.08, 0.3, 3000); - p.arp.forEach((f, i) => { - setTimeout(() => { - this._osc(f, 0.15, 'sine', 0.25); - this._osc(f * 2, 0.1, 'sine', 0.08); - }, i * 100); - }); - setTimeout(() => { - this._osc(p.baseFreq * 2, 0.4, 'sine', 0.35); - this._noise(0.15, p.noiseVol, 5000); - this._osc(p.baseFreq, 0.6, 'sawtooth', 0.15); - }, p.arp.length * 100); - }, - - caseCovert() { - this._noise(0.1, 0.5, 4000); - [392, 523, 659, 784, 1047].forEach((f, i) => { - setTimeout(() => { - this._osc(f, 0.2, 'sawtooth', 0.3); - this._osc(f * 1.5, 0.15, 'sine', 0.1); - }, i * 120); - }); - setTimeout(() => { - this._osc(1047, 0.8, 'sine', 0.6); - this._osc(784, 0.6, 'triangle', 0.25); - this._noise(0.6, 0.4, 6000); - }, 600); - }, - - caseRare() { - [523, 659, 784, 1047].forEach((f, i) => { - setTimeout(() => { - this._osc(f, 0.12, 'sine', 0.3); - this._osc(f * 1.5, 0.08, 'sine', 0.06); - }, i * 80); - }); - setTimeout(() => this._osc(1319, 0.5, 'sine', 0.5), 320); - }, - - // ── Slots ── - slotSpin() { - for (let i = 0; i < 10; i++) { - setTimeout(() => { - this._osc(200 + Math.random() * 600, 0.04, 'square', 0.12); - }, i * 60); - } - }, - - slotMatch() { - [523, 659, 784, 1047].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.15, 'sine', 0.35), i * 100); - }); - setTimeout(() => this._noise(0.2, 0.3, 8000), 300); - }, - - // ── Contract ── - contractSubmit() { - this._osc(150, 0.25, 'sawtooth', 0.2); - setTimeout(() => this._osc(200, 0.15, 'square', 0.18), 150); - setTimeout(() => { - this._osc(250, 0.08, 'square', 0.15); - this._noise(0.05, 0.15); - }, 280); - }, - - contractResult() { - [400, 600, 800].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.15, 'sine', 0.3), i * 100); - }); - setTimeout(() => { - this._osc(1200, 0.4, 'sine', 0.45); - this._noise(0.2, 0.2, 5000); - }, 300); - }, - - // ── Wheel ── - wheelTick() { - this._osc(200, 0.03, 'square', 0.08); - }, - - wheelWin() { - [523, 659, 784, 1047].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.18, 'sine', 0.35), i * 100); - }); - setTimeout(() => this._noise(0.4, 0.3, 8000), 400); - }, - - wheelLose() { - [400, 350, 300].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.25, 'sine', 0.2), i * 150); - }); - }, - - // ── Achievements ── - achievement() { - [659, 523, 784, 659, 1047].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.12, 'sine', 0.3), i * 80); - }); - setTimeout(() => this._noise(0.3, 0.25, 6000), 400); - }, - - // ── Crash ── - crashBet() { - this._osc(300, 0.08, 'square', 0.15); - setTimeout(() => this._osc(350, 0.06, 'square', 0.1), 60); - }, - - crashTick(multiplier) { - const freq = 300 + Math.min(multiplier * 50, 800); - this._osc(freq, 0.03, 'sine', 0.05 + Math.min(multiplier * 0.01, 0.15)); - }, - - crashCrashed() { - this._noise(0.5, 0.6, 2000); - this._osc(80, 0.6, 'sawtooth', 0.4); - setTimeout(() => this._osc(50, 1, 'sine', 0.3), 100); - setTimeout(() => this._osc(40, 0.8, 'triangle', 0.2), 200); - }, - - crashCashout(multiplier) { - const vol = 0.2 + Math.min(multiplier * 0.02, 0.5); - [600, 800, 1000, 1200].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.12, 'sine', vol), i * 80); - }); - setTimeout(() => this._noise(0.3, 0.3, 8000), 320); - }, - - // ── Upgrade ── - upgradeSubmit() { - this._osc(250, 0.1, 'square', 0.15); - this._noise(0.05, 0.2); - }, - - upgradeResult() { - [523, 784, 1047].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.2, 'sine', 0.3), i * 120); - }); - setTimeout(() => this._noise(0.25, 0.25, 6000), 360); - }, - - upgradeFail() { - [300, 250, 200].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.2, 'sawtooth', 0.2), i * 120); - }); - }, - - // ── UI ── - click() { - this._osc(800, 0.03, 'sine', 0.08); - }, - - hover() { - this._osc(1200, 0.015, 'sine', 0.03); - }, - - error() { - this._osc(200, 0.15, 'square', 0.2); - setTimeout(() => this._osc(180, 0.12, 'square', 0.15), 100); - }, - - success() { - [600, 800, 1000].forEach((f, i) => { - setTimeout(() => this._osc(f, 0.08, 'sine', 0.2), i * 60); - }); - }, - - balanceUpdate() { - this._osc(1000, 0.04, 'sine', 0.08); - setTimeout(() => this._osc(1200, 0.04, 'sine', 0.06), 50); - }, }; +// Auto-init document.addEventListener('DOMContentLoaded', () => SoundManager.init()); diff --git a/templates/_activity_sidebar.html b/templates/_activity_sidebar.html index a760827..484c579 100644 --- a/templates/_activity_sidebar.html +++ b/templates/_activity_sidebar.html @@ -1,86 +1,203 @@
- - - Лента - - +

Лента

+ 0 👤 - +
-
Загрузка...
+
Загрузка...
- + diff --git a/templates/achievements.html b/templates/achievements.html index 67fb198..ba1e16a 100644 --- a/templates/achievements.html +++ b/templates/achievements.html @@ -3,107 +3,320 @@ - Достижения — CS2 Simulator + Достижения - CS2 Simulator + -
-
-
-
-

🏆 Достижения

-

Выполняй задания и получай награды

+
+
+
+

🏆 Достижения

+

Выполняй задания и получай награды

+
+
+
+
{{ unlocked }}
+
Открыто
-
-
-
{{ unlocked }}/{{ total }}
-
Открыто
-
-
-
{{ "%.0f"|format(unlocked/total*100 if total > 0 else 0) }}%
-
Прогресс
-
+
+
{{ total }}
+
Всего
+
+
+
{{ "%.0f"|format(unlocked/total*100 if total > 0 else 0) }}%
+
Прогресс
+
-
- - - - - - -
+
+ + + + + + +
-
- {% for ach in achievements %} -
-
- {{ ach.icon }} -
-
-
{{ ach.title }}
-
{{ ach.description }}
- {% if ach.reward_amount > 0 %} -
+{{ "%.0f"|format(ach.reward_amount) }} ₽
- {% endif %} -
-
-
-
-
- {% if ach.unlocked %}✅ Получено{% else %}{{ ach.progress }} / {{ ach.requirement_value }}{% endif %} -
+
+ {% for ach in achievements %} +
+
{{ ach.icon }}
+
+
{{ ach.title }}
+
{{ ach.description }}
+ {% if ach.reward_amount > 0 %} +
+{{ "%.0f"|format(ach.reward_amount) }} ₽
+ {% endif %} +
+
+
+
+
+ {% if ach.unlocked %} + ✅ Получено + {% else %} + {{ ach.progress }} / {{ ach.requirement_value }} + {% endif %}
- {% endfor %}
+ {% endfor %}
+ + + {% include '_activity_sidebar.html' %} diff --git a/templates/activity.html b/templates/activity.html index 4b66039..ae15909 100644 --- a/templates/activity.html +++ b/templates/activity.html @@ -3,33 +3,123 @@ - Лента активностей — CS2 Simulator + Лента активностей - CS2 Simulator + -
-
-
-
-

📰 Лента активностей

-

Что происходит на сервере

-
-
- - Live -
+
+
+
+

📰 Лента активностей

+

Что происходит на сервере

+
+ + Live +
+
-
- {% if activities %} - {% for a in activities %} -
-
- {% if a.activity_type == 'case_open' %}📦 - {% elif a.activity_type == 'contract' %}🔄 - {% elif a.activity_type == 'upgrade' %}🆙 - {% elif a.activity_type == 'achievement' %}🏆 - {% elif a.activity_type == 'crash' %}💥 - {% else %}📌{% endif %} -
-
-
{{ a.message }}
-
- {{ a.username }} - • {{ a.created_at }} -
+
+ {% if activities %} + {% for a in activities %} +
+
+ {% if a.activity_type == 'case_open' %}📦 + {% elif a.activity_type == 'contract' %}🔄 + {% elif a.activity_type == 'upgrade' %}🆙 + {% elif a.activity_type == 'achievement' %}🏆 + {% elif a.activity_type == 'crash' %}💥 + {% else %}📌{% endif %} +
+
+
{{ a.message }}
+
+ {{ a.username }} + • {{ a.created_at }}
- {% endfor %} - {% else %} -
-
📭
-

Пока нет активностей

-

Открой кейс или выполни контракт — это появится здесь в реальном времени!

-
- {% endif %}
+ {% endfor %} + {% else %} +
+
📭
+

Пока нет активностей

+

Открой кейс или выполни контракт — это появится здесь в реальном времени!

+
+ {% endif %}
@@ -87,37 +175,71 @@ + -{% include '_activity_sidebar.html' %} diff --git a/templates/admin/base.html b/templates/admin/base.html index 8f34359..56e09fc 100644 --- a/templates/admin/base.html +++ b/templates/admin/base.html @@ -6,93 +6,353 @@ {% block title %}Админ-панель{% endblock %} — CS2 Simulator - +
-
{% block page_title %}Панель управления{% endblock %}
-
{% block top_actions %}{% endblock %}
+
+ {% block page_title %}Панель управления{% endblock %} +
+
+ {% block top_actions %}{% endblock %} +
+
+
+ {% block content %}{% endblock %}
-
{% block content %}{% endblock %}
{% block modals %}{% endblock %} diff --git a/templates/admin/cases.html b/templates/admin/cases.html index d6871ee..334aff7 100644 --- a/templates/admin/cases.html +++ b/templates/admin/cases.html @@ -2,7 +2,9 @@ {% block title %}Кейсы — Админ-панель{% endblock %} {% block nav_cases %}active{% endblock %} {% block page_title %}📦 Управление кейсами{% endblock %} -{% block top_actions %}{% endblock %} +{% block top_actions %} + +{% endblock %} {% block content %}
@@ -62,14 +64,29 @@
🎲 Создать кейс
-
-
+
+ + +
+
+ + +
-
-
+
+ + +
+
+ + +
+
+
+ +
-
📋 Предметы кейса
@@ -99,8 +116,14 @@
➕ Добавить кейс в секцию

Секция:

-
-
+
+ + +
+
+ + +
@@ -108,8 +131,14 @@
➕ Новая секция
-
-
+
+ + +
+
+ + +
{% endblock %} @@ -128,44 +157,98 @@ {% block scripts %} {% endblock %} diff --git a/templates/admin/dashboard.html b/templates/admin/dashboard.html index fd48237..6f87e07 100644 --- a/templates/admin/dashboard.html +++ b/templates/admin/dashboard.html @@ -44,9 +44,9 @@
{{ rpu_count }}
Всего записей
{{ "%.1f"|format(avg_rpu) }}%
Средний уровень
-
{{ lucky_count }}
🍀 Везучих
-
{{ normal_count }}
📊 Обычных
-
{{ unlucky_count }}
🌧️ Невезучих
+
{{ lucky_count }}
🍀 Везучих
+
{{ normal_count }}
📊 Обычных
+
{{ unlucky_count }}
🌧️ Невезучих
{{ "%.0f"|format(total_spent) }} ₽
Потрачено всего
{% else %} diff --git a/templates/admin/user_detail.html b/templates/admin/user_detail.html index 3511418..dc898db 100644 --- a/templates/admin/user_detail.html +++ b/templates/admin/user_detail.html @@ -2,7 +2,7 @@ {% block title %}{{ target_user.username }} — Админ-панель{% endblock %} {% block nav_users %}active{% endblock %} {% block page_title %} - {{ target_user.username }} + 👤 {{ target_user.username }} {% if target_user.is_admin %}Админ{% endif %} {% if target_user.is_banned %}Забанен{% endif %} {% endblock %} @@ -11,63 +11,62 @@ {% endblock %} {% block content %} -
+
Баланс
{{ "%.0f"|format(target_user.balance) }} ₽
-
Предметов
{{ inventory|length }}
-
Открытий кейсов
{{ total_openings }}
-
Контрактов
{{ total_contracts }}
-
+
-
RPU (Режим Персонального Угнетения)
-
-
--
Уровень
-
--
Множитель
-
--
Потрачено
-
--
Открыто
-
--
Авто
+
🎲 РПУ (Режим Персонального Угнетения)
+
+
--
Уровень
+
--
Множитель
+
--
Потрачено
+
--
Открыто
+
--
Авто
-
- - - - - +
+ + + + +
+
-
Действия
-
- - +
🔧 Действия
+
+ + {% if target_user.id != user.id %} - + {% endif %}
+
-
Инвентарь (последние 50)
+
🎒 Инвентарь (последние 50)
@@ -79,7 +78,7 @@ {% endfor %} @@ -90,10 +89,11 @@ {% endblock %} {% block modals %} +
-
Изменить баланс
-

+

💰 Изменить баланс
+

Текущий: {{ "%.2f"|format(target_user.balance) }} ₽

@@ -103,9 +103,9 @@
@@ -115,9 +115,10 @@
+
-
Выдать предмет
+
🎁 Выдать предмет
@@ -129,13 +130,14 @@
+
-
Настройка RPU
+
⚙️ Настройка РПУ
@@ -148,7 +150,7 @@ {% block extra_styles %} -
+
- ← Назад к списку кейсов - -
-
-

{{ case_display_name }}

-

{{ total_items }} предметов в кейсе

+ ← Назад к списку кейсов + +
+
+
+

📦 {{ case_display_name }}

+

{{ total_items }} предметов в кейсе

+
+
+ 🔑 {{ "%.0f"|format(case_price) }} ₽ за шт. +
- 🔑 {{ "%.0f"|format(case_price) }} ₽ за шт. -
- -
- {% if user %} -
- Открыть: -
-
-
- {{ "%.0f"|format(case_price) }} ₽ + +
+ {% if user %} +
+ +
+
+
+ Итого: {{ "%.0f"|format(case_price) }} ₽ +
- + + {% else %} +
+ 🔒 Войдите в аккаунт, чтобы открывать кейсы + Войти + Регистрация +
+ {% endif %}
- {% else %} -
- 🔒 Войдите в аккаунт, чтобы открывать кейсы - Войти - Регистрация -
- {% endif %}
- -
+ +
+ - +
- -
-

📋 Содержимое кейса ({{ total_items }} предметов)

-
- -
- - {% for rarity in sorted_rarities %} - - {% endfor %} -
- - {% for rarity in sorted_rarities %} -
-
-

+ +
+

📋 Содержимое кейса ({{ total_items }} предметов)

+
+ + {% for rarity in sorted_rarities %} +

- ({{ items_by_rarity[rarity]|length }}) + + {% endfor %}
- -
- {% for item in items_by_rarity[rarity] %} -
-
- +

+ {{ rarity }} + ({{ items_by_rarity[rarity]|length }}) +

+ +
+ {% for item in items_by_rarity[rarity] %} +
+ {{ item.name }} -
{{ item.name }}
-
+ onerror="this.src='/static/placeholder.png'"> +
{{ item.name }}
+
{{ item.type }} {{ "%.2f"|format(item.probability) }}%
-
+
Float: {{ "%.2f"|format(item.min_float) }} - {{ "%.2f"|format(item.max_float) }}
{% if item.min_price and item.max_price %} -
+
{% if item.min_price == item.max_price %} {{ "%.0f"|format(item.min_price) }} ₽ {% else %} @@ -356,11 +396,11 @@
{% endif %}
+ {% endfor %}
- {% endfor %}
+ {% endfor %}
- {% endfor %}
@@ -494,9 +534,9 @@ const totalPrice = casePrice * currentOpenCount; const priceElement = document.getElementById('totalPriceDisplay'); const openButton = document.getElementById('openButton'); - if (priceElement) priceElement.textContent = `${totalPrice.toLocaleString()} ₽`; + if (priceElement) priceElement.innerHTML = `Итого: ${totalPrice.toLocaleString()} ₽`; if (openButton) { - openButton.style.background = userBalance < totalPrice ? 'var(--danger)' : ''; + openButton.style.background = userBalance < totalPrice ? 'var(--danger-color)' : 'var(--primary-color)'; openButton.title = userBalance < totalPrice ? 'Недостаточно средств' : ''; } } @@ -1104,7 +1144,7 @@

😕 Увы, топ-дропа не оказалось

Открыто ${currentOpenCount} кейсов, но ничего ценного не выпало.

-

💰 Шлак (${trashItems.length} предметов) автоматически продан.

+

💰 Шлак (${trashItems.length} предметов) автоматически продан.

@@ -1121,7 +1161,7 @@
-
+
💰 Шлак (${trashItems.length} предметов) автоматически продан
`; @@ -1418,449 +1458,449 @@ }).then(r => r.json()).then(data => { if (!data.success) { resolve(null); return; } - const targetItem = data.results[0]; - const items = []; - const totalItems = 32; - const targetPos = 14; - - for (let i = 0; i < totalItems; i++) { - if (i === targetPos) items.push(targetItem); - else items.push(caseItems[Math.floor(Math.random() * caseItems.length)]); - } - - track.innerHTML = ''; - items.forEach((item, idx) => { - const div = document.createElement('div'); - div.className = 'scroll-item-full'; - if (idx === targetPos) div.classList.add('target-item'); - - const color = getRarityColor(item.rarity); - div.style.borderColor = color; - div.style.borderWidth = '2px'; - div.style.borderStyle = 'solid'; - - div.innerHTML = ` - -
${item.name.substring(0, 25)}
-
${item.rarity}
- `; - track.appendChild(div); - }); - - const container = track.parentElement; - const containerWidth = container.offsetWidth; - const dims = getItemDimensions(false); - const itemTotalWidth = dims.itemWidth; - const targetOffset = (containerWidth / 2) - (itemTotalWidth / 2); - const finalPos = -(targetPos * itemTotalWidth) + targetOffset; - - let currentPos = containerWidth + 100; - track.style.transform = `translateX(${currentPos}px)`; - track.style.willChange = 'transform'; - - // Speed lines - const speedLines = addSpeedLines(container); - const duration = 7500; - const startTime = performance.now(); - - // Звук прокрутки: тик на каждом предмете - let lastTickIndex = -1; - - function animate() { - const now = performance.now(); - const elapsed = now - startTime; - const progress = Math.min(elapsed / duration, 1); - const easeOut = 1 - Math.pow(1 - progress, 3); - - const prevPos = currentPos; - currentPos = (containerWidth + 100) - ((containerWidth + 100) - finalPos) * easeOut; - track.style.transform = `translateX(${currentPos}px)`; - - // Звук: определяем какой предмет сейчас в центре - const centerX = -currentPos + targetOffset + itemTotalWidth / 2; - const tickIndex = Math.floor(centerX / itemTotalWidth); - if (tickIndex >= 0 && tickIndex < totalItems && tickIndex !== lastTickIndex) { - SoundManager.wheelSpin(); - lastTickIndex = tickIndex; - } - - if (progress < 1) { - requestAnimationFrame(animate); - } else { - track.style.transform = `translateX(${finalPos}px)`; - track.style.willChange = 'auto'; - removeSpeedLines(speedLines); - - // Финальный звук - const hasRare = ['Covert', 'Extraordinary', 'Rare Special Item'].includes(targetItem.rarity); - const hasMid = ['Classified', 'Restricted'].includes(targetItem.rarity); - if (hasRare) SoundManager.caseCovert(); - else if (hasMid) SoundManager.caseRare(); - - // Flash burst - flashBurst(container, targetItem.rarity); - particleBurst(container, targetItem.rarity, 24); - - const targetElement = track.querySelector('.target-item'); - if (targetElement) { - targetElement.style.transition = 'all 0.3s ease'; - targetElement.style.transform = 'scale(1.08)'; - targetElement.style.boxShadow = `0 0 40px ${getRarityColor(targetItem.rarity)}, 0 0 80px ${getRarityColor(targetItem.rarity)}40`; - targetElement.style.zIndex = '100'; - targetElement.style.borderWidth = '3px'; - } - - setTimeout(() => resolve(data), 800); - } - } - - requestAnimationFrame(animate); - }).catch((err) => { - console.error('Single scroll error:', err); - resolve(null); - }); - }); - } - - function animateMiniScroll(track, index, preloadedResult) { - return new Promise((resolve) => { - if (preloadedResult) { - // Используем предзагруженный результат (оптимизация) - doAnimate({ success: true, results: [preloadedResult], new_balance: 0 }); - return; + const targetItem = data.results[0]; + const items = []; + const totalItems = 32; + const targetPos = 14; + + for (let i = 0; i < totalItems; i++) { + if (i === targetPos) items.push(targetItem); + else items.push(caseItems[Math.floor(Math.random() * caseItems.length)]); } - const formData = new FormData(); - formData.append('case_name', caseName); - formData.append('count', '1'); - fetch('/web/api/cases/open/multiple', { - method: 'POST', - body: formData - }).then(r => r.json()).then(data => doAnimate(data)).catch(err => { - console.error('Mini scroll error:', err); - resolve(null); - }); - function doAnimate(data) { - if (!data || !data.success) { resolve(null); return; } - - const targetItem = data.results[0]; - const items = []; - const totalItems = 28; - const targetPos = 11; - - for (let i = 0; i < totalItems; i++) { - if (i === targetPos) items.push(targetItem); - else items.push(caseItems[Math.floor(Math.random() * caseItems.length)]); - } - - track.innerHTML = ''; - items.forEach((item, idx) => { - const div = document.createElement('div'); - div.className = 'scroll-item-mini'; - if (idx === targetPos) div.classList.add('target-mini-item'); - - const color = getRarityColor(item.rarity); - div.style.borderColor = color; - div.style.borderWidth = '2px'; - div.style.borderStyle = 'solid'; + + track.innerHTML = ''; + items.forEach((item, idx) => { + const div = document.createElement('div'); + div.className = 'scroll-item-full'; + if (idx === targetPos) div.classList.add('target-item'); - div.innerHTML = ` - -
${item.name.substring(0, 12)}
- `; - track.appendChild(div); - }); + const color = getRarityColor(item.rarity); + div.style.borderColor = color; + div.style.borderWidth = '2px'; + div.style.borderStyle = 'solid'; - const container = track.parentElement; - const containerWidth = container.offsetWidth; - const dims = getItemDimensions(true); - const itemTotalWidth = dims.itemWidth; - const targetOffset = (containerWidth / 2) - (itemTotalWidth / 2); - const finalPos = -(targetPos * itemTotalWidth) + targetOffset; - - let currentPos = containerWidth + 50; - track.style.transform = `translateX(${currentPos}px)`; - track.style.willChange = 'transform'; - - // Staggered start - const staggerDelay = (index || 0) * 120; - const speedLines = addSpeedLines(container); - const duration = 6000 + Math.random() * 1500; - const startTime = performance.now() + staggerDelay; - let started = false; - - function animate() { - const now = performance.now(); - const elapsed = now - startTime; - - if (elapsed < 0) { - requestAnimationFrame(animate); - return; - } - - if (!started) { - started = true; - } - - const progress = Math.min(elapsed / duration, 1); - const easeOut = 1 - Math.pow(1 - progress, 3); - - currentPos = (containerWidth + 50) - ((containerWidth + 50) - finalPos) * easeOut; - track.style.transform = `translateX(${currentPos}px)`; - - if (progress < 1) { - requestAnimationFrame(animate); - } else { - track.style.transform = `translateX(${finalPos}px)`; - track.style.willChange = 'auto'; - removeSpeedLines(speedLines); - - // Effects (lighter for mini) - flashBurst(container, targetItem.rarity); - particleBurst(container, targetItem.rarity, 10); - - const targetElement = track.querySelector('.target-mini-item'); - if (targetElement) { - targetElement.style.transition = 'all 0.3s ease'; - targetElement.style.transform = 'scale(1.1)'; - targetElement.style.boxShadow = `0 0 25px ${getRarityColor(targetItem.rarity)}`; - targetElement.style.zIndex = '100'; - } - - setTimeout(() => resolve(data), 400); - } - } - - requestAnimationFrame(animate); - } - }); - } - - function showResults(results) { - const resultsDiv = document.getElementById('openingResults'); - - // Звук в зависимости от редкости - const rarities = results.map(r => r.rarity || ''); - const hasRare = rarities.some(r => r === 'Covert' || r === 'Extraordinary' || r === 'Rare Special Item'); - const hasRestricted = rarities.some(r => r === 'Classified' || r === 'Restricted'); - if (hasRare) { - SoundManager.caseCovert(); - } else if (hasRestricted) { - SoundManager.caseRare(); - } - - const grouped = {}; - results.forEach((item) => { - const key = item.name; - if (!grouped[key]) { - grouped[key] = { ...item, count: 1 }; - } else { - grouped[key].count++; - } - }); - - let totalValue = results.reduce((sum, item) => sum + (item.price || 100), 0); - - let html = ` -
-
🎉 Получено (${results.length})
-
- - -
-
-
- `; - - Object.values(grouped).forEach((item, idx) => { - const color = getRarityColor(item.rarity); - html += ` -
-
+ div.innerHTML = ` -
-
${item.name}
-
- ${item.rarity} -
- -
- ${item.count > 1 ? `x${item.count}` : ''} -
- `; +
${item.name.substring(0, 25)}
+
${item.rarity}
+ `; + track.appendChild(div); + }); + + const container = track.parentElement; + const containerWidth = container.offsetWidth; + const dims = getItemDimensions(false); + const itemTotalWidth = dims.itemWidth; + const targetOffset = (containerWidth / 2) - (itemTotalWidth / 2); + const finalPos = -(targetPos * itemTotalWidth) + targetOffset; + + let currentPos = containerWidth + 100; + track.style.transform = `translateX(${currentPos}px)`; + track.style.willChange = 'transform'; + + // Speed lines + const speedLines = addSpeedLines(container); + const duration = 7500; + const startTime = performance.now(); + + // Звук прокрутки: тик на каждом предмете + let lastTickIndex = -1; + + function animate() { + const now = performance.now(); + const elapsed = now - startTime; + const progress = Math.min(elapsed / duration, 1); + const easeOut = 1 - Math.pow(1 - progress, 3); + + const prevPos = currentPos; + currentPos = (containerWidth + 100) - ((containerWidth + 100) - finalPos) * easeOut; + track.style.transform = `translateX(${currentPos}px)`; + + // Звук: определяем какой предмет сейчас в центре + const centerX = -currentPos + targetOffset + itemTotalWidth / 2; + const tickIndex = Math.floor(centerX / itemTotalWidth); + if (tickIndex >= 0 && tickIndex < totalItems && tickIndex !== lastTickIndex) { + SoundManager.wheelSpin(); + lastTickIndex = tickIndex; + } + + if (progress < 1) { + requestAnimationFrame(animate); + } else { + track.style.transform = `translateX(${finalPos}px)`; + track.style.willChange = 'auto'; + removeSpeedLines(speedLines); + + // Финальный звук + const hasRare = ['Covert', 'Extraordinary', 'Rare Special Item'].includes(targetItem.rarity); + const hasMid = ['Classified', 'Restricted'].includes(targetItem.rarity); + if (hasRare) SoundManager.caseCovert(); + else if (hasMid) SoundManager.caseRare(); + + // Flash burst + flashBurst(container, targetItem.rarity); + particleBurst(container, targetItem.rarity, 24); + + const targetElement = track.querySelector('.target-item'); + if (targetElement) { + targetElement.style.transition = 'all 0.3s ease'; + targetElement.style.transform = 'scale(1.08)'; + targetElement.style.boxShadow = `0 0 40px ${getRarityColor(targetItem.rarity)}, 0 0 80px ${getRarityColor(targetItem.rarity)}40`; + targetElement.style.zIndex = '100'; + targetElement.style.borderWidth = '3px'; + } + + setTimeout(() => resolve(data), 800); + } + } + + requestAnimationFrame(animate); + }).catch((err) => { + console.error('Single scroll error:', err); + resolve(null); }); - - html += `
`; - - resultsDiv.innerHTML = html; - resultsDiv.style.display = 'block'; - - // Stagger appear animation - document.querySelectorAll('.result-card-enhanced').forEach((card, i) => { - card.style.animation = 'none'; - card.offsetHeight; - card.style.animation = `fadeInUp 0.4s ease-out forwards`; - card.style.animationDelay = `${i * 0.06}s`; + }); + } + + function animateMiniScroll(track, index, preloadedResult) { + return new Promise((resolve) => { + if (preloadedResult) { + // Используем предзагруженный результат (оптимизация) + doAnimate({ success: true, results: [preloadedResult], new_balance: 0 }); + return; + } + const formData = new FormData(); + formData.append('case_name', caseName); + formData.append('count', '1'); + fetch('/web/api/cases/open/multiple', { + method: 'POST', + body: formData + }).then(r => r.json()).then(data => doAnimate(data)).catch(err => { + console.error('Mini scroll error:', err); + resolve(null); }); + function doAnimate(data) { + if (!data || !data.success) { resolve(null); return; } + + const targetItem = data.results[0]; + const items = []; + const totalItems = 28; + const targetPos = 11; + + for (let i = 0; i < totalItems; i++) { + if (i === targetPos) items.push(targetItem); + else items.push(caseItems[Math.floor(Math.random() * caseItems.length)]); + } + + track.innerHTML = ''; + items.forEach((item, idx) => { + const div = document.createElement('div'); + div.className = 'scroll-item-mini'; + if (idx === targetPos) div.classList.add('target-mini-item'); + + const color = getRarityColor(item.rarity); + div.style.borderColor = color; + div.style.borderWidth = '2px'; + div.style.borderStyle = 'solid'; + + div.innerHTML = ` + +
${item.name.substring(0, 12)}
+ `; + track.appendChild(div); + }); + + const container = track.parentElement; + const containerWidth = container.offsetWidth; + const dims = getItemDimensions(true); + const itemTotalWidth = dims.itemWidth; + const targetOffset = (containerWidth / 2) - (itemTotalWidth / 2); + const finalPos = -(targetPos * itemTotalWidth) + targetOffset; + + let currentPos = containerWidth + 50; + track.style.transform = `translateX(${currentPos}px)`; + track.style.willChange = 'transform'; + + // Staggered start + const staggerDelay = (index || 0) * 120; + const speedLines = addSpeedLines(container); + const duration = 6000 + Math.random() * 1500; + const startTime = performance.now() + staggerDelay; + let started = false; + + function animate() { + const now = performance.now(); + const elapsed = now - startTime; + + if (elapsed < 0) { + requestAnimationFrame(animate); + return; + } + + if (!started) { + started = true; + } + + const progress = Math.min(elapsed / duration, 1); + const easeOut = 1 - Math.pow(1 - progress, 3); + + currentPos = (containerWidth + 50) - ((containerWidth + 50) - finalPos) * easeOut; + track.style.transform = `translateX(${currentPos}px)`; + + if (progress < 1) { + requestAnimationFrame(animate); + } else { + track.style.transform = `translateX(${finalPos}px)`; + track.style.willChange = 'auto'; + removeSpeedLines(speedLines); + + // Effects (lighter for mini) + flashBurst(container, targetItem.rarity); + particleBurst(container, targetItem.rarity, 10); + + const targetElement = track.querySelector('.target-mini-item'); + if (targetElement) { + targetElement.style.transition = 'all 0.3s ease'; + targetElement.style.transform = 'scale(1.1)'; + targetElement.style.boxShadow = `0 0 25px ${getRarityColor(targetItem.rarity)}`; + targetElement.style.zIndex = '100'; + } + + setTimeout(() => resolve(data), 400); + } + } + + requestAnimationFrame(animate); + } + }); + } + + function showResults(results) { + const resultsDiv = document.getElementById('openingResults'); + + // Звук в зависимости от редкости + const rarities = results.map(r => r.rarity || ''); + const hasRare = rarities.some(r => r === 'Covert' || r === 'Extraordinary' || r === 'Rare Special Item'); + const hasRestricted = rarities.some(r => r === 'Classified' || r === 'Restricted'); + if (hasRare) { + SoundManager.caseCovert(); + } else if (hasRestricted) { + SoundManager.caseRare(); } - async function sellResultItem(itemId) { - if (!confirm('Продать этот предмет?')) return; - - try { - const response = await fetch('/web/api/inventory/items'); - const items = await response.json(); - const inventoryItem = items.find(i => i.item_id === itemId); - - if (!inventoryItem) { - alert('Предмет не найден в инвентаре'); - return; - } - - const formData = new FormData(); - formData.append('inventory_id', inventoryItem.id); - - const sellResponse = await fetch('/web/api/inventory/sell', { - method: 'POST', - body: formData - }); - - const data = await sellResponse.json(); - - if (data.success) { - await refreshUserBalance(); - await refreshInventoryAjax(); - // Remove the sold item card from display - const cards = document.querySelectorAll('.result-card-enhanced'); - for (const card of cards) { - const btn = card.querySelector('.btn-sell-result'); - if (btn && btn.getAttribute('onclick')?.includes(itemId)) { - card.style.transition = 'all 0.3s ease'; - card.style.opacity = '0'; - card.style.transform = 'scale(0.8)'; - setTimeout(() => card.remove(), 300); - break; - } - } - } else { - alert(data.error || 'Ошибка при продаже'); - } - } catch (error) { - alert('Ошибка соединения'); + const grouped = {}; + results.forEach((item) => { + const key = item.name; + if (!grouped[key]) { + grouped[key] = { ...item, count: 1 }; + } else { + grouped[key].count++; } - } - - async function sellAllResults() { - if (!window.lastOpenedItems || window.lastOpenedItems.length === 0) { - alert('Нет предметов для продажи'); + }); + + let totalValue = results.reduce((sum, item) => sum + (item.price || 100), 0); + + let html = ` +
+
🎉 Получено (${results.length})
+
+ + +
+
+
+ `; + + Object.values(grouped).forEach((item, idx) => { + const color = getRarityColor(item.rarity); + html += ` +
+
+ +
+
${item.name}
+
+ ${item.rarity} +
+ +
+ ${item.count > 1 ? `x${item.count}` : ''} +
+ `; + }); + + html += `
`; + + resultsDiv.innerHTML = html; + resultsDiv.style.display = 'block'; + + // Stagger appear animation + document.querySelectorAll('.result-card-enhanced').forEach((card, i) => { + card.style.animation = 'none'; + card.offsetHeight; + card.style.animation = `fadeInUp 0.4s ease-out forwards`; + card.style.animationDelay = `${i * 0.06}s`; + }); + } + + async function sellResultItem(itemId) { + if (!confirm('Продать этот предмет?')) return; + + try { + const response = await fetch('/web/api/inventory/items'); + const items = await response.json(); + const inventoryItem = items.find(i => i.item_id === itemId); + + if (!inventoryItem) { + alert('Предмет не найден в инвентаре'); return; } - const total = window.lastOpenedItems.reduce((sum, i) => sum + (i.price || 100), 0); - if (!confirm(`Продать все выпавшие предметы за ${total.toLocaleString()} ₽?`)) return; + const formData = new FormData(); + formData.append('inventory_id', inventoryItem.id); - try { - const response = await fetch('/web/api/inventory/items'); - const items = await response.json(); - - const inventoryIds = []; - for (const resultItem of window.lastOpenedItems) { - const invItem = items.find(i => i.item_id === resultItem.id && - Math.abs(i.float - resultItem.float) < 0.001); - if (invItem) { - inventoryIds.push(invItem.id); + const sellResponse = await fetch('/web/api/inventory/sell', { + method: 'POST', + body: formData + }); + + const data = await sellResponse.json(); + + if (data.success) { + await refreshUserBalance(); + await refreshInventoryAjax(); + // Remove the sold item card from display + const cards = document.querySelectorAll('.result-card-enhanced'); + for (const card of cards) { + const btn = card.querySelector('.btn-sell-result'); + if (btn && btn.getAttribute('onclick')?.includes(itemId)) { + card.style.transition = 'all 0.3s ease'; + card.style.opacity = '0'; + card.style.transform = 'scale(0.8)'; + setTimeout(() => card.remove(), 300); + break; } } - - if (inventoryIds.length === 0) { - alert('Предметы не найдены в инвентаре'); - return; - } - - const formData = new FormData(); - formData.append('inventory_ids', JSON.stringify(inventoryIds)); - - const sellResponse = await fetch('/web/api/inventory/sell/bulk', { - method: 'POST', - body: formData - }); - - const data = await sellResponse.json(); - - if (data.success) { - await refreshUserBalance(); - await refreshInventoryAjax(); - // Clear results and reset UI - const resultsDiv = document.getElementById('openingResults'); - resultsDiv.style.display = 'none'; - resultsDiv.innerHTML = ''; - window.lastOpenedItems = []; - } else { - alert(data.error || 'Ошибка при продаже'); - } - } catch (error) { - alert('Ошибка соединения'); + } else { + alert(data.error || 'Ошибка при продаже'); } + } catch (error) { + alert('Ошибка соединения'); + } + } + + async function sellAllResults() { + if (!window.lastOpenedItems || window.lastOpenedItems.length === 0) { + alert('Нет предметов для продажи'); + return; } - function filterItems(rarity) { - document.querySelectorAll('.filter-chip').forEach(btn => btn.classList.remove('active')); - event.target.classList.add('active'); - document.querySelectorAll('.rarity-section').forEach(section => { - section.style.display = (rarity === 'all' || section.dataset.rarity === rarity) ? 'block' : 'none'; + const total = window.lastOpenedItems.reduce((sum, i) => sum + (i.price || 100), 0); + if (!confirm(`Продать все выпавшие предметы за ${total.toLocaleString()} ₽?`)) return; + + try { + const response = await fetch('/web/api/inventory/items'); + const items = await response.json(); + + const inventoryIds = []; + for (const resultItem of window.lastOpenedItems) { + const invItem = items.find(i => i.item_id === resultItem.id && + Math.abs(i.float - resultItem.float) < 0.001); + if (invItem) { + inventoryIds.push(invItem.id); + } + } + + if (inventoryIds.length === 0) { + alert('Предметы не найдены в инвентаре'); + return; + } + + const formData = new FormData(); + formData.append('inventory_ids', JSON.stringify(inventoryIds)); + + const sellResponse = await fetch('/web/api/inventory/sell/bulk', { + method: 'POST', + body: formData + }); + + const data = await sellResponse.json(); + + if (data.success) { + await refreshUserBalance(); + await refreshInventoryAjax(); + // Clear results and reset UI + const resultsDiv = document.getElementById('openingResults'); + resultsDiv.style.display = 'none'; + resultsDiv.innerHTML = ''; + window.lastOpenedItems = []; + } else { + alert(data.error || 'Ошибка при продаже'); + } + } catch (error) { + alert('Ошибка соединения'); + } + } + + function filterItems(rarity) { + document.querySelectorAll('.filter-btn').forEach(btn => btn.classList.remove('active')); + event.target.classList.add('active'); + document.querySelectorAll('.rarity-section').forEach(section => { + section.style.display = (rarity === 'all' || section.dataset.rarity === rarity) ? 'block' : 'none'; + }); + } + + async function logout() { + await fetch('/web/api/auth/logout', { method: 'POST' }); + window.location.href = '/'; + } + + window.addEventListener('resize', () => { + if (!isOpening) { + updatePriceDisplay(); + } + }); + + document.addEventListener('DOMContentLoaded', () => { + initCountButtons(); + updatePriceDisplay(); + initSlotUI(); + // Hide fast button for farm cases + if (isFarmCase) { + const fastBtn = document.getElementById('fastOpenButton'); + if (fastBtn) fastBtn.style.display = 'none'; + } + }); + + + + + - - - - - - {% if user %}{% include '_activity_sidebar.html' %}{% endif %} - - + } + + +{% if user %}{% include '_activity_sidebar.html' %}{% endif %} + + \ No newline at end of file diff --git a/templates/cases.html b/templates/cases.html index 5f4ec81..68a4bc2 100644 --- a/templates/cases.html +++ b/templates/cases.html @@ -3,33 +3,181 @@ - Кейсы — CS2 Simulator + Кейсы - CS2 Simulator + -
+
-
-

📦 Кейсы

-

Выберите кейс для открытия

-
- - {% for section in sections %} -
-
{{ section.tab }}
-
- {% for case in section.cases %} - -
- {% if case.image_url %} - {{ case.display_name }} - {% else %} - 📦 - {% endif %} -
-
-
{{ case.display_name }}
- {% if case.description %} -
{{ case.description }}
- {% endif %} -
-
+ @@ -100,4 +256,4 @@ {% if user %}{% include '_activity_sidebar.html' %}{% endif %} - + \ No newline at end of file diff --git a/templates/contracts.html b/templates/contracts.html index c94e297..d9ea34e 100644 --- a/templates/contracts.html +++ b/templates/contracts.html @@ -9,25 +9,25 @@ -
-
-
-
-

🔄 Trade Up Контракт

-

Выберите 10 предметов одинаковой редкости и типа

-
-
+ + +
+
+

🔄 Trade Up Контракт

+

Выберите 10 предметов одинаковой редкости и типа

-
- -
IDНазваниеРедкостьFloat
{{ item.rarity }} {{ "%.4f"|format(item.float_value) }} - +