diff --git a/web_server.py b/web_server.py
index 1e85c203..3ffed756 100644
--- a/web_server.py
+++ b/web_server.py
@@ -2342,6 +2342,129 @@ def get_beatport_featured_charts():
'charts': []
}), 500
+
+@app.route('/api/beatport/dj-charts')
+def get_beatport_dj_charts():
+ """Get DJ charts from Beatport for the DJ charts slider using Carousel approach"""
+ try:
+ logger.info("🎧 Fetching Beatport DJ charts...")
+
+ # Initialize scraper
+ scraper = BeatportUnifiedScraper()
+
+ # Get page and extract charts
+ soup = scraper.get_page(scraper.base_url)
+ if not soup:
+ raise Exception("Could not fetch Beatport homepage")
+
+ # Find all Carousel containers
+ carousels = soup.select('[class*="Carousel-style__Wrapper"]')
+ dj_container = None
+
+ logger.info(f"🔍 Checking {len(carousels)} Carousel containers for DJ charts...")
+
+ # Based on test results, DJ charts are in the second carousel (index 1) with ~9 chart links
+ for i, container in enumerate(carousels):
+ chart_links = container.select('a[href*="/chart/"]')
+ logger.info(f"📋 Carousel {i+1}: {len(chart_links)} chart links")
+
+ # DJ charts container typically has 8-12 chart links (not 99+ like featured charts)
+ if 5 <= len(chart_links) <= 15:
+ dj_container = container
+ logger.info(f"🔥 FOUND DJ CHARTS: Carousel {i+1} with {len(chart_links)} charts")
+ break
+
+ if not dj_container:
+ logger.warning("❌ No DJ Charts Carousel container found")
+ return jsonify({
+ 'success': False,
+ 'error': 'DJ Charts section not found',
+ 'charts': []
+ })
+
+ # Extract charts from the container using chart links
+ charts = []
+ chart_links = dj_container.select('a[href*="/chart/"]')
+
+ logger.info(f"📊 Found {len(chart_links)} DJ chart links")
+
+ for i, link in enumerate(chart_links):
+ chart_data = {}
+
+ # Extract chart name from link text or nearby elements
+ name_elem = link.select_one('h3, h4, h5, h6, [class*="title"], [class*="Title"], [class*="name"], [class*="Name"]')
+ if name_elem:
+ name_text = name_elem.get_text(strip=True)
+ else:
+ name_text = link.get_text(strip=True)
+
+ if name_text and len(name_text) > 2:
+ chart_data['name'] = name_text
+
+ # Extract creator - for DJ charts, the chart name might be the artist name
+ creator = name_text # Use chart name as creator for DJ charts
+
+ # Look for additional creator info in parent elements
+ parent = link.parent
+ if parent:
+ creator_selectors = [
+ '[class*="artist"]', '[class*="Artist"]',
+ '[class*="creator"]', '[class*="Creator"]',
+ '[class*="author"]', '[class*="Author"]'
+ ]
+
+ for selector in creator_selectors:
+ creator_elem = parent.select_one(selector)
+ if creator_elem:
+ creator_text = creator_elem.get_text(strip=True)
+ if creator_text and len(creator_text) > 1 and creator_text != name_text:
+ creator = creator_text
+ break
+
+ chart_data['creator'] = creator
+
+ # Extract URL
+ href = link.get('href', '')
+ if href:
+ if href.startswith('/'):
+ chart_data['url'] = f"https://www.beatport.com{href}"
+ else:
+ chart_data['url'] = href
+
+ # Extract image
+ img_elem = link.select_one('img') or (link.parent.select_one('img') if link.parent else None)
+ if img_elem:
+ src = img_elem.get('src', '') or img_elem.get('data-src', '')
+ if src:
+ if src.startswith('//'):
+ src = f"https:{src}"
+ elif src.startswith('/'):
+ src = f"https://www.beatport.com{src}"
+ chart_data['image'] = src
+
+ # Only add if we have meaningful data
+ if 'name' in chart_data and 'url' in chart_data:
+ charts.append(chart_data)
+ logger.info(f"✅ DJ Chart {len(charts)}: {chart_data['name']} by {chart_data['creator']}")
+
+ logger.info(f"📊 Successfully extracted {len(charts)} DJ charts")
+
+ return jsonify({
+ 'success': True,
+ 'charts': charts,
+ 'count': len(charts),
+ 'slides': max(1, (len(charts) + 2) // 3), # 3 cards per slide
+ 'timestamp': datetime.now().isoformat()
+ })
+
+ except Exception as e:
+ logger.error(f"❌ Error fetching DJ charts: {str(e)}")
+ return jsonify({
+ 'success': False,
+ 'error': str(e),
+ 'charts': []
+ }), 500
+
# --- Placeholder API Endpoints for Other Pages ---
@app.route('/api/activity')
diff --git a/webui/index.html b/webui/index.html
index 8079084c..55beb3b0 100644
--- a/webui/index.html
+++ b/webui/index.html
@@ -871,6 +871,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
🎧 Loading DJ Charts...
+
Fetching curated DJ selections
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/webui/static/script.js b/webui/static/script.js
index c39d53e5..7cee8ca8 100644
--- a/webui/static/script.js
+++ b/webui/static/script.js
@@ -9736,6 +9736,7 @@ function initializeSyncPage() {
initializeBeatportRebuildSlider();
initializeBeatportReleasesSlider();
initializeBeatportChartsSlider();
+ initializeBeatportDJSlider();
}
});
});
@@ -19108,3 +19109,283 @@ function cleanupBeatportChartsSlider() {
beatportChartsSliderState.autoPlayInterval = null;
}
}
+
+// ===================================
+// BEATPORT DJ CHARTS SLIDER
+// ===================================
+
+// State management for DJ charts slider (3 cards per slide)
+let beatportDJSliderState = {
+ currentSlide: 0,
+ totalSlides: 0,
+ autoPlayInterval: null,
+ autoPlayDelay: 12000, // Longer auto-play for DJ charts
+ isInitialized: false
+};
+
+/**
+ * Initialize the beatport DJ charts slider functionality (based on charts slider)
+ */
+function initializeBeatportDJSlider() {
+ console.log('🎧 Initializing beatport DJ charts slider...');
+
+ const slider = document.getElementById('beatport-dj-slider');
+ if (!slider) {
+ console.warn('Beatport DJ slider not found');
+ return;
+ }
+
+ // Prevent double initialization
+ if (slider.dataset.initialized === 'true') {
+ console.log('DJ slider already initialized');
+ return;
+ }
+
+ const sliderTrack = document.getElementById('beatport-dj-slider-track');
+ const indicatorsContainer = document.getElementById('beatport-dj-slider-indicators');
+
+ if (!sliderTrack || !indicatorsContainer) {
+ console.warn('DJ slider elements not found');
+ return;
+ }
+
+ // Load data and initialize
+ loadBeatportDJCharts().then(success => {
+ if (success) {
+ setupBeatportDJSliderNavigation();
+ setupBeatportDJSliderIndicators();
+ setupBeatportDJSliderHoverPause();
+ startBeatportDJSliderAutoPlay();
+ slider.dataset.initialized = 'true';
+ beatportDJSliderState.isInitialized = true;
+ console.log('✅ DJ charts slider initialized successfully');
+ }
+ });
+}
+
+/**
+ * Load DJ charts data from API
+ */
+async function loadBeatportDJCharts() {
+ try {
+ console.log('🎧 Loading DJ charts data...');
+ const response = await fetch('/api/beatport/dj-charts');
+ const data = await response.json();
+
+ if (data.success && data.charts && data.charts.length > 0) {
+ console.log(`📈 Loaded ${data.charts.length} DJ charts`);
+ createBeatportDJSlides(data.charts);
+ return true;
+ } else {
+ console.warn('No DJ charts data available');
+ return false;
+ }
+ } catch (error) {
+ console.error('❌ Error loading DJ charts:', error);
+ return false;
+ }
+}
+
+/**
+ * Create DJ chart slides with 3 cards per slide layout
+ */
+function createBeatportDJSlides(charts) {
+ const sliderTrack = document.getElementById('beatport-dj-slider-track');
+ const indicatorsContainer = document.getElementById('beatport-dj-slider-indicators');
+
+ if (!sliderTrack || !indicatorsContainer) {
+ console.error('DJ slider elements not found');
+ return;
+ }
+
+ const cardsPerSlide = 3; // 3 cards per slide for DJ charts
+ const totalSlides = Math.ceil(charts.length / cardsPerSlide);
+
+ // Clear existing content
+ sliderTrack.innerHTML = '';
+ indicatorsContainer.innerHTML = '';
+
+ // Update state
+ beatportDJSliderState.totalSlides = totalSlides;
+ beatportDJSliderState.currentSlide = 0;
+
+ console.log(`🎯 Creating ${totalSlides} DJ chart slides with ${cardsPerSlide} cards each`);
+
+ // Generate slides HTML
+ for (let slideIndex = 0; slideIndex < totalSlides; slideIndex++) {
+ const startIndex = slideIndex * cardsPerSlide;
+ const endIndex = Math.min(startIndex + cardsPerSlide, charts.length);
+ const slideCharts = charts.slice(startIndex, endIndex);
+
+ // Create grid HTML for this slide
+ const gridHtml = slideCharts.map(chart => {
+ const bgImageStyle = chart.image ? `--dj-bg-image: url('${chart.image}')` : '';
+ return `
+
+
+
${chart.name || 'Unknown Chart'}
+
${chart.creator || 'Unknown Creator'}
+
+
+ `;
+ }).join('');
+
+ // Create slide HTML
+ const slideHtml = `
+
+ `;
+
+ sliderTrack.innerHTML += slideHtml;
+
+ // Create indicator
+ const indicatorHtml = ``;
+ indicatorsContainer.innerHTML += indicatorHtml;
+ }
+
+ console.log(`✅ Created ${totalSlides} DJ chart slides`);
+}
+
+/**
+ * Set up navigation functionality (copied from charts slider with button cloning)
+ */
+function setupBeatportDJSliderNavigation() {
+ const prevBtn = document.getElementById('beatport-dj-prev-btn');
+ const nextBtn = document.getElementById('beatport-dj-next-btn');
+
+ if (prevBtn) {
+ // Clone button to remove all existing event listeners
+ const newPrevBtn = prevBtn.cloneNode(true);
+ prevBtn.parentNode.replaceChild(newPrevBtn, prevBtn);
+
+ newPrevBtn.addEventListener('click', (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ console.log('Previous DJ button clicked, current slide:', beatportDJSliderState.currentSlide);
+ goToBeatportDJSlide(beatportDJSliderState.currentSlide - 1);
+ resetBeatportDJSliderAutoPlay();
+ });
+ }
+
+ if (nextBtn) {
+ // Clone button to remove all existing event listeners
+ const newNextBtn = nextBtn.cloneNode(true);
+ nextBtn.parentNode.replaceChild(newNextBtn, nextBtn);
+
+ newNextBtn.addEventListener('click', (e) => {
+ e.preventDefault();
+ e.stopPropagation();
+ console.log('Next DJ button clicked, current slide:', beatportDJSliderState.currentSlide);
+ goToBeatportDJSlide(beatportDJSliderState.currentSlide + 1);
+ resetBeatportDJSliderAutoPlay();
+ });
+ }
+}
+
+/**
+ * Set up indicator functionality (copied from charts slider)
+ */
+function setupBeatportDJSliderIndicators() {
+ const indicators = document.querySelectorAll('.beatport-dj-indicator');
+
+ indicators.forEach((indicator, index) => {
+ indicator.addEventListener('click', () => {
+ goToBeatportDJSlide(index);
+ resetBeatportDJSliderAutoPlay();
+ });
+ });
+}
+
+/**
+ * Navigate to a specific slide (copied from charts slider)
+ */
+function goToBeatportDJSlide(slideIndex) {
+ console.log('goToBeatportDJSlide called with:', slideIndex, 'current:', beatportDJSliderState.currentSlide);
+
+ // Wrap around if out of bounds
+ if (slideIndex < 0) {
+ slideIndex = beatportDJSliderState.totalSlides - 1;
+ } else if (slideIndex >= beatportDJSliderState.totalSlides) {
+ slideIndex = 0;
+ }
+
+ console.log('After wrapping, slideIndex:', slideIndex);
+
+ // Update current slide
+ beatportDJSliderState.currentSlide = slideIndex;
+
+ // Update slide visibility
+ const slides = document.querySelectorAll('.beatport-dj-slide');
+ slides.forEach((slide, index) => {
+ slide.classList.remove('active', 'prev', 'next');
+
+ if (index === slideIndex) {
+ slide.classList.add('active');
+ } else if (index < slideIndex) {
+ slide.classList.add('prev');
+ } else {
+ slide.classList.add('next');
+ }
+ });
+
+ // Update indicators
+ const indicators = document.querySelectorAll('.beatport-dj-indicator');
+ indicators.forEach((indicator, index) => {
+ indicator.classList.toggle('active', index === slideIndex);
+ });
+
+ console.log('DJ slide updated to:', beatportDJSliderState.currentSlide);
+}
+
+/**
+ * Start auto-play functionality (copied from charts slider)
+ */
+function startBeatportDJSliderAutoPlay() {
+ if (beatportDJSliderState.autoPlayInterval) {
+ clearInterval(beatportDJSliderState.autoPlayInterval);
+ }
+
+ beatportDJSliderState.autoPlayInterval = setInterval(() => {
+ goToBeatportDJSlide(beatportDJSliderState.currentSlide + 1);
+ }, beatportDJSliderState.autoPlayDelay);
+}
+
+/**
+ * Reset auto-play timer (copied from charts slider)
+ */
+function resetBeatportDJSliderAutoPlay() {
+ startBeatportDJSliderAutoPlay();
+}
+
+/**
+ * Set up hover pause functionality (copied from charts slider)
+ */
+function setupBeatportDJSliderHoverPause() {
+ const sliderContainer = document.querySelector('.beatport-dj-slider-container');
+
+ if (sliderContainer) {
+ sliderContainer.addEventListener('mouseenter', () => {
+ if (beatportDJSliderState.autoPlayInterval) {
+ clearInterval(beatportDJSliderState.autoPlayInterval);
+ beatportDJSliderState.autoPlayInterval = null;
+ }
+ });
+
+ sliderContainer.addEventListener('mouseleave', () => {
+ startBeatportDJSliderAutoPlay();
+ });
+ }
+}
+
+/**
+ * Clean up DJ slider when switching away (copied from charts slider)
+ */
+function cleanupBeatportDJSlider() {
+ if (beatportDJSliderState.autoPlayInterval) {
+ clearInterval(beatportDJSliderState.autoPlayInterval);
+ beatportDJSliderState.autoPlayInterval = null;
+ }
+}
diff --git a/webui/static/style.css b/webui/static/style.css
index 7584b851..a7c01422 100644
--- a/webui/static/style.css
+++ b/webui/static/style.css
@@ -12793,3 +12793,369 @@ body {
font-size: 24px;
}
}
+
+/* ==================== DJ CHARTS SLIDER STYLES ==================== */
+
+/* DJ Section */
+.beatport-dj-section {
+ margin-top: 40px;
+ padding: 0 30px;
+}
+
+.beatport-dj-header {
+ text-align: center;
+ margin-bottom: 30px;
+}
+
+.beatport-dj-title {
+ font-size: 32px;
+ font-weight: 700;
+ color: #ffffff;
+ margin-bottom: 8px;
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
+}
+
+.beatport-dj-subtitle {
+ font-size: 16px;
+ color: rgba(255, 255, 255, 0.8);
+ margin: 0;
+}
+
+/* DJ Slider Container */
+.beatport-dj-slider-container {
+ position: relative;
+ background: linear-gradient(135deg,
+ rgba(147, 51, 234, 0.1),
+ rgba(79, 70, 229, 0.05));
+ border-radius: 20px;
+ border: 1px solid rgba(147, 51, 234, 0.2);
+ backdrop-filter: blur(15px);
+ min-height: 300px;
+ padding: 30px;
+}
+
+.beatport-dj-slider {
+ position: relative;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ border-radius: 16px;
+}
+
+.beatport-dj-slider-track {
+ position: relative;
+ height: 300px;
+}
+
+.beatport-dj-slide {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ transition: all 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+ transform: translateX(100px);
+}
+
+.beatport-dj-slide.active {
+ opacity: 1;
+ z-index: 10;
+ transform: translateX(0);
+}
+
+.beatport-dj-slide.prev {
+ opacity: 0;
+ transform: translateX(-100px);
+}
+
+.beatport-dj-slide.next {
+ opacity: 0;
+ transform: translateX(100px);
+}
+
+/* DJ Cards Layout - 3 cards per slide */
+.beatport-dj-grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 25px;
+ padding: 20px;
+ background: linear-gradient(135deg,
+ rgba(16, 16, 16, 0.6),
+ rgba(24, 24, 24, 0.4));
+ border-radius: 16px;
+ border: 1px solid rgba(147, 51, 234, 0.15);
+ justify-items: center;
+ align-items: center;
+ margin: 0 auto;
+}
+
+/* DJ Chart Card Styling - Unique vertical design */
+.beatport-dj-card {
+ position: relative;
+ width: 100%;
+ height: 220px;
+ min-height: 220px;
+ max-height: 220px;
+ border-radius: 20px;
+ cursor: pointer;
+ transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+ overflow: hidden;
+ background: linear-gradient(135deg,
+ rgba(147, 51, 234, 0.8),
+ rgba(79, 70, 229, 0.6));
+ box-shadow:
+ 0 8px 32px rgba(0, 0, 0, 0.4),
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
+}
+
+.beatport-dj-card::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: var(--dj-bg-image, linear-gradient(135deg, #9333ea, #4f46e5));
+ background-size: cover;
+ background-position: center;
+ border-radius: 20px;
+ z-index: 1;
+}
+
+.beatport-dj-card::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(
+ 180deg,
+ rgba(147, 51, 234, 0.3) 0%,
+ rgba(0, 0, 0, 0.4) 50%,
+ rgba(0, 0, 0, 0.8) 100%
+ );
+ border-radius: 20px;
+ z-index: 2;
+}
+
+.beatport-dj-card:hover {
+ transform: translateY(-15px) scale(1.1);
+ box-shadow:
+ 0 30px 60px rgba(0, 0, 0, 0.8),
+ 0 0 50px rgba(147, 51, 234, 0.6),
+ inset 0 1px 0 rgba(255, 255, 255, 0.3);
+ z-index: 25;
+}
+
+.beatport-dj-card:hover::after {
+ background: linear-gradient(
+ 180deg,
+ rgba(147, 51, 234, 0.4) 0%,
+ rgba(0, 0, 0, 0.2) 50%,
+ rgba(0, 0, 0, 0.6) 100%
+ );
+}
+
+.beatport-dj-card:hover .beatport-dj-name {
+ color: rgba(147, 51, 234, 0.95);
+ text-shadow: 0 2px 15px rgba(0, 0, 0, 0.9);
+ transform: translateY(-3px);
+}
+
+.beatport-dj-card:hover .beatport-dj-creator {
+ color: #ffffff;
+ text-shadow: 0 1px 10px rgba(0, 0, 0, 0.9);
+ transform: translateY(-2px);
+}
+
+.beatport-dj-card-content {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ padding: 25px;
+ z-index: 3;
+ text-align: center;
+}
+
+.beatport-dj-name {
+ font-size: 20px;
+ font-weight: 700;
+ color: #ffffff;
+ margin-bottom: 10px;
+ line-height: 1.2;
+ text-shadow: 0 2px 10px rgba(0, 0, 0, 0.8);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+
+.beatport-dj-creator {
+ font-size: 16px;
+ color: rgba(255, 255, 255, 0.9);
+ font-weight: 500;
+ text-shadow: 0 1px 6px rgba(0, 0, 0, 0.8);
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+}
+
+/* DJ Loading State */
+.beatport-dj-loading {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 300px;
+ background: linear-gradient(135deg,
+ rgba(147, 51, 234, 0.1),
+ rgba(16, 16, 16, 0.8));
+ border-radius: 16px;
+ border: 1px solid rgba(147, 51, 234, 0.2);
+}
+
+.beatport-dj-loading-content {
+ text-align: center;
+ color: #ffffff;
+}
+
+.beatport-dj-loading-content h3 {
+ font-size: 24px;
+ margin-bottom: 8px;
+ color: rgba(147, 51, 234, 0.9);
+}
+
+.beatport-dj-loading-content p {
+ font-size: 16px;
+ color: rgba(255, 255, 255, 0.7);
+ margin: 0;
+}
+
+/* DJ Navigation */
+.beatport-dj-slider-nav {
+ position: absolute;
+ top: 50%;
+ left: 0;
+ right: 0;
+ transform: translateY(-50%);
+ display: flex;
+ justify-content: space-between;
+ padding: 0 20px;
+ pointer-events: none;
+ z-index: 100;
+}
+
+.beatport-dj-nav-btn {
+ background: linear-gradient(135deg,
+ rgba(147, 51, 234, 0.9),
+ rgba(79, 70, 229, 0.8));
+ border: none;
+ color: #ffffff;
+ font-size: 24px;
+ font-weight: 600;
+ width: 50px;
+ height: 50px;
+ border-radius: 50%;
+ cursor: pointer;
+ transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
+ backdrop-filter: blur(10px);
+ border: 2px solid rgba(255, 255, 255, 0.2);
+ box-shadow:
+ 0 4px 16px rgba(0, 0, 0, 0.3),
+ inset 0 1px 0 rgba(255, 255, 255, 0.2);
+ pointer-events: auto;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.beatport-dj-nav-btn:hover {
+ background: linear-gradient(135deg,
+ rgba(147, 51, 234, 1),
+ rgba(79, 70, 229, 0.9));
+ transform: scale(1.1);
+ box-shadow:
+ 0 8px 24px rgba(0, 0, 0, 0.4),
+ 0 0 20px rgba(147, 51, 234, 0.5),
+ inset 0 1px 0 rgba(255, 255, 255, 0.3);
+}
+
+.beatport-dj-nav-btn:active {
+ transform: scale(0.95);
+}
+
+/* DJ Indicators */
+.beatport-dj-slider-indicators {
+ position: absolute;
+ bottom: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ display: flex;
+ gap: 8px;
+ z-index: 10;
+}
+
+.beatport-dj-indicator {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.4);
+ border: none;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.beatport-dj-indicator.active {
+ background: rgba(147, 51, 234, 0.9);
+ transform: scale(1.2);
+ box-shadow: 0 0 10px rgba(147, 51, 234, 0.5);
+}
+
+.beatport-dj-indicator:hover {
+ background: rgba(255, 255, 255, 0.6);
+ transform: scale(1.1);
+}
+
+/* DJ Responsive Design */
+@media (max-width: 1200px) {
+ .beatport-dj-grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 20px;
+ }
+
+ .beatport-dj-card {
+ height: 200px;
+ min-height: 200px;
+ max-height: 200px;
+ }
+}
+
+@media (max-width: 900px) {
+ .beatport-dj-grid {
+ grid-template-columns: 1fr;
+ gap: 16px;
+ }
+
+ .beatport-dj-slider-container {
+ padding: 20px;
+ }
+
+ .beatport-dj-card {
+ height: 180px;
+ min-height: 180px;
+ max-height: 180px;
+ }
+}
+
+@media (max-width: 600px) {
+ .beatport-dj-section {
+ padding: 0 15px;
+ }
+
+ .beatport-dj-title {
+ font-size: 24px;
+ }
+}