beatport progress

This commit is contained in:
Broque Thomas 2025-09-30 09:32:52 -07:00
parent d885316077
commit df11474951
4 changed files with 850 additions and 0 deletions

View file

@ -13321,6 +13321,102 @@ def get_beatport_dj_charts_improved():
"count": 0
}), 500
@app.route('/api/beatport/hype-picks')
def get_beatport_hype_picks():
"""Get Beatport Hype Picks for the rebuild slider grid (EXACT same pattern as new-releases)"""
try:
logger.info("🔥 Fetching Beatport hype picks...")
# Initialize scraper
scraper = BeatportUnifiedScraper()
# Get page and extract releases
soup = scraper.get_page(scraper.base_url)
if not soup:
raise Exception("Could not fetch Beatport homepage")
# Extract hype pick cards using data-testid selector (equivalent to new-releases CSS selector)
hype_pick_cards = soup.select('[data-testid="hype-picks"]')
releases = []
logger.info(f"🔍 Found {len(hype_pick_cards)} hype pick cards")
for i, card in enumerate(hype_pick_cards[:100]): # Limit to 100 for 10 slides (same as new-releases)
release_data = {}
# Extract title (exact same logic as new-releases)
title_elem = card.select_one('[class*="title"], [class*="Title"], h1, h2, h3, h4, h5, h6')
if title_elem:
title_text = title_elem.get_text(strip=True)
if title_text and len(title_text) > 2 and title_text not in ['Hype Picks', 'Buy', 'Play']:
release_data['title'] = title_text
# Extract artist (exact same logic as new-releases)
artist_elem = card.select_one('[class*="artist"], [class*="Artist"], a[href*="/artist/"]')
if artist_elem:
artist_text = artist_elem.get_text(strip=True)
if artist_text and len(artist_text) > 1:
release_data['artist'] = artist_text
# Extract label (exact same logic as new-releases)
label_elem = card.select_one('[class*="label"], [class*="Label"], a[href*="/label/"]')
if label_elem:
label_text = label_elem.get_text(strip=True)
if label_text and len(label_text) > 1:
release_data['label'] = label_text
# Extract URL (exact same logic as new-releases)
url_link = card.select_one('a[href*="/release/"]')
if url_link:
href = url_link.get('href')
if href:
release_data['url'] = urljoin(scraper.base_url, href)
# Extract image (exact same logic as new-releases)
img = card.select_one('img')
if img:
src = img.get('src') or img.get('data-src') or img.get('data-lazy-src')
if src:
release_data['image_url'] = src
# URL fallback for title (exact same logic as new-releases)
if not release_data.get('title') and release_data.get('url'):
url_parts = release_data['url'].split('/release/')
if len(url_parts) > 1:
slug = url_parts[1].split('/')[0]
release_data['title'] = slug.replace('-', ' ').title()
# Only add if we have essential data (exact same logic as new-releases)
if release_data.get('title') and release_data.get('url'):
# Add fallbacks for missing data (exact same logic as new-releases)
if not release_data.get('artist'):
release_data['artist'] = 'Various Artists'
if not release_data.get('label'):
release_data['label'] = 'Unknown Label'
releases.append(release_data)
logger.info(f"✅ Successfully extracted {len(releases)} hype picks")
return jsonify({
'success': True,
'releases': releases,
'count': len(releases),
'slides': (len(releases) + 9) // 10, # Calculate number of slides needed (same as new-releases)
'timestamp': datetime.now().isoformat()
})
except Exception as e:
logger.error(f"❌ Error getting Beatport hype picks: {e}")
return jsonify({
'success': False,
'error': str(e),
'releases': [],
'count': 0
}), 500
@app.route('/api/beatport/discovery/start/<url_hash>', methods=['POST'])
def start_beatport_discovery(url_hash):
"""Start Spotify discovery for Beatport chart tracks"""

View file

@ -839,6 +839,39 @@
</div>
</div>
<!-- Hype Picks Grid Slideshow Section -->
<div class="beatport-hype-picks-section">
<div class="beatport-hype-picks-header">
<h2 class="beatport-hype-picks-title">🔥 Hype Picks</h2>
<p class="beatport-hype-picks-subtitle">Editor selected trending tracks from Beatport</p>
</div>
<div class="beatport-hype-picks-slider-container">
<div class="beatport-hype-picks-slider" id="beatport-hype-picks-slider">
<div class="beatport-hype-picks-slider-track" id="beatport-hype-picks-slider-track">
<!-- Loading placeholder -->
<div class="beatport-hype-picks-loading">
<div class="beatport-hype-picks-loading-content">
<h3>🔥 Loading Hype Picks...</h3>
<p>Fetching the hottest trending tracks</p>
</div>
</div>
</div>
<!-- Slider Navigation -->
<div class="beatport-hype-picks-slider-nav">
<button class="beatport-hype-picks-nav-btn beatport-hype-picks-prev-btn" id="beatport-hype-picks-prev-btn"></button>
<button class="beatport-hype-picks-nav-btn beatport-hype-picks-next-btn" id="beatport-hype-picks-next-btn"></button>
</div>
<!-- Slider Indicators -->
<div class="beatport-hype-picks-slider-indicators" id="beatport-hype-picks-slider-indicators">
<!-- Indicators will be dynamically generated -->
</div>
</div>
</div>
</div>
<!-- Featured Charts Grid Slideshow Section -->
<div class="beatport-charts-section">
<div class="beatport-charts-header">

View file

@ -9735,6 +9735,7 @@ function initializeSyncPage() {
if (tabId === 'rebuild') {
initializeBeatportRebuildSlider();
initializeBeatportReleasesSlider();
initializeBeatportHypePicksSlider();
initializeBeatportChartsSlider();
initializeBeatportDJSlider();
}
@ -18830,6 +18831,335 @@ function cleanupBeatportReleasesSlider() {
}
}
// ===================================
// BEATPORT HYPE PICKS SLIDER
// ===================================
// Hype Picks Slider State
let beatportHypePicksSliderState = {
currentSlide: 0,
totalSlides: 0,
autoPlayInterval: null,
autoPlayDelay: 4000,
isInitialized: false
};
/**
* Initialize the beatport hype picks slider functionality (based on releases slider)
*/
function initializeBeatportHypePicksSlider() {
console.log('🔥 Initializing beatport hype picks slider...');
const slider = document.getElementById('beatport-hype-picks-slider');
if (!slider) {
console.warn('Beatport hype picks slider not found');
return;
}
// Check if already initialized
if (beatportHypePicksSliderState.isInitialized) {
console.log('Beatport hype picks slider already initialized, skipping...');
startBeatportHypePicksSliderAutoPlay(); // Just restart autoplay
return;
}
// Mark as initialized
beatportHypePicksSliderState.isInitialized = true;
// Reset state
beatportHypePicksSliderState.currentSlide = 0;
beatportHypePicksSliderState.totalSlides = 0;
// Load data and initialize
loadBeatportHypePicks().then(success => {
if (success) {
setupBeatportHypePicksSliderNavigation();
setupBeatportHypePicksSliderIndicators();
setupBeatportHypePicksSliderHoverPause();
startBeatportHypePicksSliderAutoPlay();
}
});
console.log('✅ Beatport hype picks slider initialized successfully');
}
/**
* Load hype picks data from API
*/
async function loadBeatportHypePicks() {
try {
console.log('🔥 Fetching hype picks data...');
const response = await fetch('/api/beatport/hype-picks');
const data = await response.json();
if (data.success && data.releases && data.releases.length > 0) {
console.log(`🔥 Loaded ${data.releases.length} hype picks releases`);
populateBeatportHypePicksSlider(data.releases);
return true;
} else {
console.error('Failed to load hype picks:', data.error || 'No hype picks found');
showBeatportHypePicksError(data.error || 'No hype picks available');
return false;
}
} catch (error) {
console.error('Error loading hype picks:', error);
showBeatportHypePicksError('Failed to load hype picks');
return false;
}
}
/**
* Populate the hype picks slider with data (based on releases slider)
*/
function populateBeatportHypePicksSlider(releases) {
const sliderTrack = document.getElementById('beatport-hype-picks-slider-track');
const indicatorsContainer = document.getElementById('beatport-hype-picks-slider-indicators');
if (!sliderTrack || !indicatorsContainer) return;
// Clear existing content
sliderTrack.innerHTML = '';
indicatorsContainer.innerHTML = '';
// Group releases into slides (10 releases per slide in 5x2 grid)
const releasesPerSlide = 10;
const slides = [];
for (let i = 0; i < releases.length; i += releasesPerSlide) {
slides.push(releases.slice(i, i + releasesPerSlide));
}
console.log(`🔥 Hype Picks: Got ${releases.length} releases, creating ${slides.length} slides`);
beatportHypePicksSliderState.totalSlides = slides.length;
beatportHypePicksSliderState.currentSlide = 0;
// Create slides
slides.forEach((slideReleases, slideIndex) => {
const slideHtml = `
<div class="beatport-hype-picks-slide ${slideIndex === 0 ? 'active' : ''}"
data-slide="${slideIndex}">
<div class="beatport-hype-picks-grid">
${slideReleases.map(release => createBeatportHypePickCard(release)).join('')}
${slideReleases.length < releasesPerSlide ?
Array(releasesPerSlide - slideReleases.length).fill(0).map(() =>
`<div class="beatport-hype-pick-card beatport-hype-pick-placeholder">
<div class="placeholder-icon">🔥</div>
</div>`
).join('') : ''
}
</div>
</div>
`;
sliderTrack.insertAdjacentHTML('beforeend', slideHtml);
console.log(`🔥 Created slide ${slideIndex + 1}/${slides.length} with ${slideReleases.length} releases`);
// Create indicator
const indicatorHtml = `<button class="beatport-hype-picks-indicator ${slideIndex === 0 ? 'active' : ''}" data-slide="${slideIndex}"></button>`;
indicatorsContainer.insertAdjacentHTML('beforeend', indicatorHtml);
});
// Add click handlers to track cards
setupBeatportHypePickCardHandlers();
}
/**
* Create a hype pick card HTML (for release cards, same as new releases)
*/
function createBeatportHypePickCard(release) {
const artworkUrl = release.image_url || '';
const bgStyle = artworkUrl ? `style="--card-bg-image: url('${artworkUrl}')"` : '';
return `
<div class="beatport-hype-pick-card" data-url="${release.url || ''}" ${bgStyle}>
<div class="beatport-hype-pick-card-content">
<div class="beatport-hype-pick-artwork">
${artworkUrl ? `<img src="${artworkUrl}" alt="${release.title || 'Release'}" loading="lazy">` : ''}
</div>
<div class="beatport-hype-pick-info">
<div class="beatport-hype-pick-title">${release.title || 'Unknown Title'}</div>
<div class="beatport-hype-pick-artist">${release.artist || 'Unknown Artist'}</div>
<div class="beatport-hype-pick-label">${release.label || 'Hype Pick'}</div>
</div>
</div>
</div>
`;
}
/**
* Setup navigation for hype picks slider (same pattern as releases)
*/
function setupBeatportHypePicksSliderNavigation() {
const prevBtn = document.getElementById('beatport-hype-picks-prev-btn');
const nextBtn = document.getElementById('beatport-hype-picks-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 hype picks button clicked, current slide:', beatportHypePicksSliderState.currentSlide);
goToBeatportHypePicksSlide(beatportHypePicksSliderState.currentSlide - 1);
resetBeatportHypePicksSliderAutoPlay();
});
}
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 hype picks button clicked, current slide:', beatportHypePicksSliderState.currentSlide);
goToBeatportHypePicksSlide(beatportHypePicksSliderState.currentSlide + 1);
resetBeatportHypePicksSliderAutoPlay();
});
}
}
/**
* Setup indicators for hype picks slider
*/
function setupBeatportHypePicksSliderIndicators() {
const indicators = document.querySelectorAll('.beatport-hype-picks-indicator');
indicators.forEach((indicator, index) => {
indicator.addEventListener('click', () => {
goToBeatportHypePicksSlide(index);
resetBeatportHypePicksSliderAutoPlay();
});
});
}
/**
* Navigate to specific slide
*/
function goToBeatportHypePicksSlide(slideIndex) {
console.log('goToBeatportHypePicksSlide called with:', slideIndex, 'current:', beatportHypePicksSliderState.currentSlide);
// Handle wrap around
if (slideIndex < 0) {
slideIndex = beatportHypePicksSliderState.totalSlides - 1;
} else if (slideIndex >= beatportHypePicksSliderState.totalSlides) {
slideIndex = 0;
}
// Update current slide
beatportHypePicksSliderState.currentSlide = slideIndex;
// Update slides
const slides = document.querySelectorAll('.beatport-hype-picks-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-hype-picks-indicator');
indicators.forEach((indicator, index) => {
indicator.classList.toggle('active', index === slideIndex);
});
console.log('Slide updated to:', beatportHypePicksSliderState.currentSlide);
}
/**
* Start auto-play for hype picks slider
*/
function startBeatportHypePicksSliderAutoPlay() {
if (beatportHypePicksSliderState.autoPlayInterval) {
clearInterval(beatportHypePicksSliderState.autoPlayInterval);
}
beatportHypePicksSliderState.autoPlayInterval = setInterval(() => {
goToBeatportHypePicksSlide(beatportHypePicksSliderState.currentSlide + 1);
}, beatportHypePicksSliderState.autoPlayDelay);
console.log('🔥 Hype picks slider autoplay started');
}
/**
* Reset auto-play for hype picks slider
*/
function resetBeatportHypePicksSliderAutoPlay() {
startBeatportHypePicksSliderAutoPlay();
}
/**
* Setup hover pause for hype picks slider
*/
function setupBeatportHypePicksSliderHoverPause() {
const sliderContainer = document.querySelector('.beatport-hype-picks-slider-container');
if (sliderContainer) {
sliderContainer.addEventListener('mouseenter', () => {
if (beatportHypePicksSliderState.autoPlayInterval) {
clearInterval(beatportHypePicksSliderState.autoPlayInterval);
}
});
sliderContainer.addEventListener('mouseleave', () => {
startBeatportHypePicksSliderAutoPlay();
});
}
}
/**
* Setup click handlers for hype pick cards
*/
function setupBeatportHypePickCardHandlers() {
const cards = document.querySelectorAll('.beatport-hype-pick-card:not(.beatport-hype-pick-placeholder)');
cards.forEach(card => {
card.addEventListener('click', () => {
const releaseUrl = card.dataset.releaseUrl;
if (releaseUrl) {
console.log('🔥 Clicked hype pick release:', releaseUrl);
// You can add release handling logic here
// For now, just log the click
showToast('🔥 Hype pick release clicked!', 'info');
}
});
});
}
/**
* Show error state for hype picks slider
*/
function showBeatportHypePicksError(errorMessage) {
const sliderTrack = document.getElementById('beatport-hype-picks-slider-track');
if (sliderTrack) {
sliderTrack.innerHTML = `
<div class="beatport-hype-picks-loading">
<div class="beatport-hype-picks-loading-content">
<h3> Error Loading Hype Picks</h3>
<p>${errorMessage}</p>
</div>
</div>
`;
}
}
/**
* Clean up hype picks slider when switching away
*/
function cleanupBeatportHypePicksSlider() {
if (beatportHypePicksSliderState.autoPlayInterval) {
clearInterval(beatportHypePicksSliderState.autoPlayInterval);
beatportHypePicksSliderState.autoPlayInterval = null;
}
}
// ===================================
// BEATPORT FEATURED CHARTS SLIDER
// ===================================

View file

@ -12421,6 +12421,397 @@ body {
}
}
/* ==================== HYPE PICKS SLIDER STYLES ==================== */
.beatport-hype-picks-section {
margin-top: 40px;
padding: 0 20px;
}
.beatport-hype-picks-header {
text-align: center;
margin-bottom: 30px;
}
.beatport-hype-picks-title {
font-size: 32px;
font-weight: bold;
background: linear-gradient(135deg, #ff6b6b, #ff8787, #ffa8a8);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 8px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.beatport-hype-picks-subtitle {
font-size: 16px;
color: rgba(255, 255, 255, 0.7);
margin: 0;
}
.beatport-hype-picks-slider-container {
position: relative;
background: linear-gradient(135deg,
rgba(18, 18, 18, 0.95),
rgba(30, 30, 30, 0.9));
border-radius: 20px;
padding: 30px;
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow:
0 20px 40px rgba(0, 0, 0, 0.5),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.beatport-hype-picks-slider {
position: relative;
border-radius: 16px;
}
.beatport-hype-picks-slider-track {
position: relative;
height: 425px;
}
.beatport-hype-picks-loading {
display: flex;
align-items: center;
justify-content: center;
min-height: 400px;
background: linear-gradient(135deg,
rgba(255, 107, 107, 0.1),
rgba(255, 135, 135, 0.05));
border-radius: 16px;
border: 2px dashed rgba(255, 107, 107, 0.3);
}
.beatport-hype-picks-loading-content {
text-align: center;
}
.beatport-hype-picks-loading-content h3 {
font-size: 24px;
color: #ff6b6b;
margin-bottom: 8px;
font-weight: 600;
}
.beatport-hype-picks-loading-content p {
color: rgba(255, 255, 255, 0.6);
font-size: 14px;
margin: 0;
}
/* Individual Slide (contains 10 cards in 5x2 grid) */
.beatport-hype-picks-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-hype-picks-slide.active {
opacity: 1;
z-index: 10;
transform: translateX(0);
}
.beatport-hype-picks-slide.prev {
transform: translateX(-100px);
}
.beatport-hype-picks-slide.next {
transform: translateX(100px);
}
.beatport-hype-picks-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 20px;
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(255, 255, 255, 0.08);
justify-items: center;
align-items: center;
margin: 0 auto;
}
/* Hype Pick Card Styling */
.beatport-hype-pick-card {
background: linear-gradient(145deg,
rgba(40, 40, 40, 0.9),
rgba(28, 28, 28, 0.95));
border-radius: 12px;
padding: 16px;
border: 1px solid rgba(255, 255, 255, 0.1);
cursor: pointer;
transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
position: relative;
overflow: hidden;
backdrop-filter: blur(10px);
box-shadow:
0 4px 16px rgba(0, 0, 0, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
width: 100%;
height: 160px;
min-height: 160px;
max-height: 160px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.beatport-hype-pick-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--card-bg-image, none);
background-size: cover;
background-position: center;
opacity: 0.15;
border-radius: 12px;
z-index: 0;
}
.beatport-hype-pick-card:hover {
transform: translateY(-2px) scale(1.05);
background: linear-gradient(145deg,
rgba(255, 107, 107, 0.15),
rgba(40, 40, 40, 0.95));
border-color: rgba(255, 107, 107, 0.4);
box-shadow:
0 8px 24px rgba(0, 0, 0, 0.4),
0 0 16px rgba(255, 107, 107, 0.3),
inset 0 1px 0 rgba(255, 255, 255, 0.15);
z-index: 10;
}
.beatport-hype-pick-card-content {
position: relative;
z-index: 1;
text-align: center;
}
.beatport-hype-pick-artwork {
width: 80px;
height: 80px;
border-radius: 8px;
margin: 0 auto 12px auto;
background: linear-gradient(135deg, #333, #555);
border: 2px solid rgba(255, 255, 255, 0.1);
overflow: hidden;
position: relative;
}
.beatport-hype-pick-artwork img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.beatport-hype-pick-card:hover .beatport-hype-pick-artwork img {
transform: scale(1.1);
}
.beatport-hype-pick-info {
text-align: center;
}
.beatport-hype-pick-title {
font-size: 13px;
font-weight: 600;
color: #ffffff;
margin-bottom: 4px;
line-height: 1.2;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.beatport-hype-pick-artist {
font-size: 11px;
color: rgba(255, 255, 255, 0.7);
margin-bottom: 4px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.beatport-hype-pick-label {
font-size: 10px;
color: rgba(255, 107, 107, 0.8);
font-weight: 500;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Placeholder Card Styling */
.beatport-hype-pick-placeholder {
opacity: 0.3;
cursor: default;
pointer-events: none;
}
.beatport-hype-pick-placeholder .placeholder-icon {
font-size: 32px;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
color: rgba(255, 255, 255, 0.5);
}
.beatport-hype-pick-placeholder:hover {
transform: none;
background: linear-gradient(145deg,
rgba(40, 40, 40, 0.9),
rgba(28, 28, 28, 0.95));
}
/* Navigation Buttons */
.beatport-hype-picks-slider-nav {
position: absolute;
top: 50%;
width: 100%;
display: flex;
justify-content: space-between;
transform: translateY(-50%);
pointer-events: none;
z-index: 10;
}
.beatport-hype-picks-nav-btn {
pointer-events: all;
background: linear-gradient(135deg,
rgba(255, 107, 107, 0.9),
rgba(255, 135, 135, 0.8));
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
color: white;
font-size: 24px;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
backdrop-filter: blur(10px);
box-shadow: 0 6px 20px rgba(255, 107, 107, 0.4);
transition: all 0.3s ease;
border: 2px solid rgba(255, 255, 255, 0.2);
}
.beatport-hype-picks-nav-btn:hover {
transform: scale(1.1);
background: linear-gradient(135deg,
rgba(255, 107, 107, 1),
rgba(255, 135, 135, 0.9));
box-shadow: 0 8px 25px rgba(255, 107, 107, 0.6);
}
.beatport-hype-picks-prev-btn {
margin-left: -25px;
}
.beatport-hype-picks-next-btn {
margin-right: -25px;
}
/* Slider Indicators */
.beatport-hype-picks-slider-indicators {
display: flex;
justify-content: center;
gap: 12px;
margin-top: 25px;
}
.beatport-hype-picks-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
border: 2px solid rgba(255, 255, 255, 0.1);
cursor: pointer;
transition: all 0.3s ease;
}
.beatport-hype-picks-indicator.active {
background: linear-gradient(135deg, #ff6b6b, #ff8787);
border-color: rgba(255, 107, 107, 0.6);
box-shadow: 0 0 15px rgba(255, 107, 107, 0.5);
transform: scale(1.2);
}
.beatport-hype-picks-indicator:hover {
background: rgba(255, 255, 255, 0.5);
transform: scale(1.1);
}
/* Responsive Design */
@media (max-width: 1400px) {
.beatport-hype-picks-grid {
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(2, 1fr);
}
}
@media (max-width: 1200px) {
.beatport-hype-picks-grid {
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
gap: 16px;
}
.beatport-hype-pick-artwork {
width: 70px;
height: 70px;
}
}
@media (max-width: 900px) {
.beatport-hype-picks-grid {
grid-template-columns: repeat(2, 1fr);
grid-template-rows: repeat(3, 1fr);
gap: 14px;
}
.beatport-hype-picks-slider-container {
padding: 20px;
}
}
@media (max-width: 600px) {
.beatport-hype-picks-grid {
grid-template-columns: 1fr;
grid-template-rows: repeat(5, 1fr);
gap: 12px;
}
.beatport-hype-picks-section {
padding: 0 15px;
}
.beatport-hype-picks-title {
font-size: 24px;
}
}
/* ==================== FEATURED CHARTS SLIDER STYLES ==================== */
/* Charts Section */