9 CSS 3D Designs 02 / 09
Midnight Coverflow
Seven cards arranged in a cylindrical coverflow perspective — the active card at full scale and brightness, flanking cards receding in angle, Z-depth, and brightness so the focused piece reads with cinematic clarity.
Best forportfolio galleries, media collections, hero sliders, editorial product reveals, music/film catalogs.
The code
<section class="cd-cvr" aria-label="Midnight coverflow carousel demo">
<div class="card">
<div class="cvr-ground" aria-hidden="true"></div>
<div class="viewport">
<div class="stage" data-cd-cvr-stage>
<div class="cf-card" data-i="0"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-1a"></div>
<div class="geo geo-1b"></div>
<span class="card-title-sm">001 — Spectra</span>
<div class="card-title-lg">Void<br />Protocol</div>
<div class="card-sub">Digital Exploration</div>
</div></div></div>
<div class="cf-card" data-i="1"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-2a"></div>
<div class="geo geo-2b"></div>
<span class="card-title-sm">002 — Azure</span>
<div class="card-title-lg">Meridian<br />Drift</div>
<div class="card-sub">Ocean Systems</div>
</div></div></div>
<div class="cf-card" data-i="2"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-3a"></div>
<div class="geo geo-3b"></div>
<span class="card-title-sm">003 — Ember</span>
<div class="card-title-lg">Solstice<br />Engine</div>
<div class="card-sub">Heat Architecture</div>
</div></div></div>
<div class="cf-card" data-i="3"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-4a"></div>
<div class="geo geo-4b"></div>
<span class="card-title-sm">004 — Canopy</span>
<div class="card-title-lg">Biolum<br />Forest</div>
<div class="card-sub">Living Systems</div>
</div></div></div>
<div class="cf-card" data-i="4"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-5a"></div>
<div class="geo geo-5b"></div>
<span class="card-title-sm">005 — Rosa</span>
<div class="card-title-lg">Ultraviolet<br />Bloom</div>
<div class="card-sub">Bio-Digital</div>
</div></div></div>
<div class="cf-card" data-i="5"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-6a"></div>
<div class="geo geo-6b"></div>
<span class="card-title-sm">006 — Sol</span>
<div class="card-title-lg">Photon<br />Archive</div>
<div class="card-sub">Light Research</div>
</div></div></div>
<div class="cf-card" data-i="6"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-7a"></div>
<div class="geo geo-7b"></div>
<span class="card-title-sm">007 — Abyss</span>
<div class="card-title-lg">Deep<br />Current</div>
<div class="card-sub">Oceanic Studies</div>
</div></div></div>
</div>
</div>
<div class="nav-dots" data-cd-cvr-dots></div>
<div class="arrows">
<button class="arr" type="button" data-cd-cvr-prev aria-label="Previous">←</button>
<button class="arr" type="button" data-cd-cvr-next aria-label="Next">→</button>
</div>
</div>
</section> <section class="cd-cvr" aria-label="Midnight coverflow carousel demo">
<div class="card">
<div class="cvr-ground" aria-hidden="true"></div>
<div class="viewport">
<div class="stage" data-cd-cvr-stage>
<div class="cf-card" data-i="0"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-1a"></div>
<div class="geo geo-1b"></div>
<span class="card-title-sm">001 — Spectra</span>
<div class="card-title-lg">Void<br />Protocol</div>
<div class="card-sub">Digital Exploration</div>
</div></div></div>
<div class="cf-card" data-i="1"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-2a"></div>
<div class="geo geo-2b"></div>
<span class="card-title-sm">002 — Azure</span>
<div class="card-title-lg">Meridian<br />Drift</div>
<div class="card-sub">Ocean Systems</div>
</div></div></div>
<div class="cf-card" data-i="2"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-3a"></div>
<div class="geo geo-3b"></div>
<span class="card-title-sm">003 — Ember</span>
<div class="card-title-lg">Solstice<br />Engine</div>
<div class="card-sub">Heat Architecture</div>
</div></div></div>
<div class="cf-card" data-i="3"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-4a"></div>
<div class="geo geo-4b"></div>
<span class="card-title-sm">004 — Canopy</span>
<div class="card-title-lg">Biolum<br />Forest</div>
<div class="card-sub">Living Systems</div>
</div></div></div>
<div class="cf-card" data-i="4"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-5a"></div>
<div class="geo geo-5b"></div>
<span class="card-title-sm">005 — Rosa</span>
<div class="card-title-lg">Ultraviolet<br />Bloom</div>
<div class="card-sub">Bio-Digital</div>
</div></div></div>
<div class="cf-card" data-i="5"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-6a"></div>
<div class="geo geo-6b"></div>
<span class="card-title-sm">006 — Sol</span>
<div class="card-title-lg">Photon<br />Archive</div>
<div class="card-sub">Light Research</div>
</div></div></div>
<div class="cf-card" data-i="6"><div class="cf-card-inner"><div class="card-art">
<div class="geo geo-7a"></div>
<div class="geo geo-7b"></div>
<span class="card-title-sm">007 — Abyss</span>
<div class="card-title-lg">Deep<br />Current</div>
<div class="card-sub">Oceanic Studies</div>
</div></div></div>
</div>
</div>
<div class="nav-dots" data-cd-cvr-dots></div>
<div class="arrows">
<button class="arr" type="button" data-cd-cvr-prev aria-label="Previous">←</button>
<button class="arr" type="button" data-cd-cvr-next aria-label="Next">→</button>
</div>
</div>
</section>/* ─── 02 Midnight Coverflow — 7-card cylindrical carousel ──── */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;700&family=Unbounded:wght@200;400;700&display=swap');
.cd-cvr {
--cd-cvr-bg: #060508;
position: relative;
width: 100%;
height: 640px;
background: var(--cd-cvr-bg);
font-family: 'Space Grotesk', system-ui, sans-serif;
overflow: hidden;
user-select: none;
box-sizing: border-box;
}
.cd-cvr *,
.cd-cvr *::before,
.cd-cvr *::after { box-sizing: border-box; margin: 0; padding: 0; }
.cd-cvr .card {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.cd-cvr .card::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(ellipse 90% 60% at 50% 40%, rgba(40,10,80,0.18) 0%, transparent 70%),
radial-gradient(ellipse 60% 40% at 50% 90%, rgba(180,80,0,0.06) 0%, transparent 70%);
pointer-events: none;
}
.cd-cvr .cvr-ground {
position: absolute;
bottom: 0; left: 0; right: 0;
height: 45%;
background: linear-gradient(to top, rgba(5,3,8,0.98) 0%, transparent 100%);
pointer-events: none;
z-index: 5;
}
.cd-cvr .viewport {
perspective: 1000px;
width: 100%;
height: 420px;
position: relative;
z-index: 1;
}
.cd-cvr .stage {
width: 100%;
height: 420px;
position: relative;
transform-style: preserve-3d;
}
.cd-cvr .cf-card {
width: 240px;
height: 320px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -120px;
margin-top: -160px;
border-radius: 18px;
overflow: hidden;
cursor: pointer;
transform-style: preserve-3d;
transition: transform 0.65s cubic-bezier(0.23, 1, 0.32, 1),
opacity 0.65s ease,
filter 0.65s ease;
-webkit-box-reflect: below 8px linear-gradient(transparent 75%, rgba(5,3,8,0.55) 100%);
}
.cd-cvr .cf-card-inner {
width: 100%; height: 100%;
position: relative;
overflow: hidden;
border-radius: 18px;
}
.cd-cvr .card-art {
width: 100%; height: 100%;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-end;
padding: 22px;
}
.cd-cvr .card-art::before {
content: '';
position: absolute;
inset: 0;
background: inherit;
}
.cd-cvr .card-title-sm {
font-family: 'Space Grotesk', sans-serif;
font-size: 9px;
letter-spacing: 3px;
text-transform: uppercase;
margin-bottom: 5px;
position: relative;
z-index: 1;
}
.cd-cvr .card-title-lg {
font-family: 'Unbounded', sans-serif;
font-size: 16px;
font-weight: 700;
line-height: 1.25;
position: relative;
z-index: 1;
}
.cd-cvr .card-sub {
font-family: 'Space Grotesk', sans-serif;
font-size: 10px;
margin-top: 5px;
position: relative;
z-index: 1;
opacity: 0.65;
}
.cd-cvr .cf-card-inner::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.08) 0%, transparent 40%, rgba(0,0,0,0.2) 100%);
pointer-events: none;
}
/* Per-card palettes */
.cd-cvr .cf-card[data-i="0"] .card-art { background: linear-gradient(148deg, #0d0020 0%, #2a0058 40%, #1a0040 100%); }
.cd-cvr .cf-card[data-i="0"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 70% 30%, rgba(120,60,255,0.4) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="0"] .card-title-sm { color: rgba(180,140,255,0.7); }
.cd-cvr .cf-card[data-i="0"] .card-title-lg { color: #e8d8ff; }
.cd-cvr .cf-card[data-i="0"] .card-sub { color: rgba(180,140,255,0.5); }
.cd-cvr .cf-card[data-i="1"] .card-art { background: linear-gradient(148deg, #001a20 0%, #003050 40%, #001828 100%); }
.cd-cvr .cf-card[data-i="1"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 30% 60%, rgba(0,180,255,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="1"] .card-title-sm { color: rgba(80,200,255,0.7); }
.cd-cvr .cf-card[data-i="1"] .card-title-lg { color: #c8f0ff; }
.cd-cvr .cf-card[data-i="1"] .card-sub { color: rgba(80,200,255,0.5); }
.cd-cvr .cf-card[data-i="2"] .card-art { background: linear-gradient(148deg, #100400 0%, #300e00 40%, #1e0800 100%); }
.cd-cvr .cf-card[data-i="2"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 60% 40%, rgba(255,100,0,0.4) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="2"] .card-title-sm { color: rgba(255,160,80,0.7); }
.cd-cvr .cf-card[data-i="2"] .card-title-lg { color: #ffe8c8; }
.cd-cvr .cf-card[data-i="2"] .card-sub { color: rgba(255,160,80,0.5); }
.cd-cvr .cf-card[data-i="3"] .card-art { background: linear-gradient(148deg, #001800 0%, #003000 40%, #001a00 100%); }
.cd-cvr .cf-card[data-i="3"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 50% 50%, rgba(0,220,80,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="3"] .card-title-sm { color: rgba(80,220,120,0.7); }
.cd-cvr .cf-card[data-i="3"] .card-title-lg { color: #c8ffe0; }
.cd-cvr .cf-card[data-i="3"] .card-sub { color: rgba(80,220,120,0.5); }
.cd-cvr .cf-card[data-i="4"] .card-art { background: linear-gradient(148deg, #1a0010 0%, #3a0028 40%, #220018 100%); }
.cd-cvr .cf-card[data-i="4"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 40% 35%, rgba(255,40,180,0.38) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="4"] .card-title-sm { color: rgba(255,140,200,0.7); }
.cd-cvr .cf-card[data-i="4"] .card-title-lg { color: #ffd8f0; }
.cd-cvr .cf-card[data-i="4"] .card-sub { color: rgba(255,140,200,0.5); }
.cd-cvr .cf-card[data-i="5"] .card-art { background: linear-gradient(148deg, #0a0a00 0%, #1e1e00 40%, #121200 100%); }
.cd-cvr .cf-card[data-i="5"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 60% 30%, rgba(220,220,0,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="5"] .card-title-sm { color: rgba(220,220,80,0.7); }
.cd-cvr .cf-card[data-i="5"] .card-title-lg { color: #fffff0; }
.cd-cvr .cf-card[data-i="5"] .card-sub { color: rgba(220,220,80,0.5); }
.cd-cvr .cf-card[data-i="6"] .card-art { background: linear-gradient(148deg, #000e18 0%, #001c30 40%, #001020 100%); }
.cd-cvr .cf-card[data-i="6"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 50% 60%, rgba(40,120,200,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="6"] .card-title-sm { color: rgba(100,180,255,0.7); }
.cd-cvr .cf-card[data-i="6"] .card-title-lg { color: #d8eeff; }
.cd-cvr .cf-card[data-i="6"] .card-sub { color: rgba(100,180,255,0.5); }
/* Decorative geo blobs */
.cd-cvr .geo { position: absolute; border-radius: 50%; opacity: 0.15; }
.cd-cvr .geo-1a { width: 140px; height: 140px; background: #a060ff; top: -30px; right: -30px; }
.cd-cvr .geo-1b { width: 70px; height: 70px; background: #6020ff; bottom: 40%; left: 20%; }
.cd-cvr .geo-2a { width: 180px; height: 180px; background: #00aaff; top: -50px; left: -30px; }
.cd-cvr .geo-2b { width: 55px; height: 55px; background: #00e8ff; bottom: 30%; right: 15%; }
.cd-cvr .geo-3a { width: 110px; height: 110px; background: #ff6600; top: 20px; right: 20px; }
.cd-cvr .geo-3b { width: 160px; height: 160px; background: #ff3300; bottom: -30px; left: -30px; }
.cd-cvr .geo-4a { width: 130px; height: 130px; background: #00cc44; top: -20px; left: 50%; margin-left: -65px; }
.cd-cvr .geo-4b { width: 80px; height: 80px; background: #00ff88; bottom: 20%; right: 10%; }
.cd-cvr .geo-5a { width: 140px; height: 140px; background: #ff00cc; top: 10px; right: -30px; }
.cd-cvr .geo-5b { width: 90px; height: 90px; background: #cc0088; bottom: 30%; left: 0%; }
.cd-cvr .geo-6a { width: 180px; height: 180px; background: #dddd00; top: -40px; left: -20px; }
.cd-cvr .geo-6b { width: 60px; height: 60px; background: #ffff40; bottom: 35%; right: 20%; }
.cd-cvr .geo-7a { width: 120px; height: 120px; background: #1c78cc; top: 30px; left: 30px; }
.cd-cvr .geo-7b { width: 100px; height: 100px; background: #3090e0; bottom: 20%; right: -10px; }
/* Nav */
.cd-cvr .nav-dots {
display: flex;
gap: 8px;
margin-top: 24px;
position: relative;
z-index: 10;
}
.cd-cvr .dot {
width: 6px; height: 6px;
border-radius: 50%;
background: rgba(255,255,255,0.2);
cursor: pointer;
border: none;
padding: 0;
transition: all 0.3s;
}
.cd-cvr .dot.active {
width: 22px;
border-radius: 3px;
background: rgba(255,255,255,0.7);
}
.cd-cvr .arrows {
position: absolute;
bottom: 28px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 16px;
z-index: 20;
}
.cd-cvr .arr {
width: 44px; height: 44px;
border-radius: 50%;
border: 1px solid rgba(255,255,255,0.12);
background: rgba(255,255,255,0.04);
color: rgba(255,255,255,0.6);
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
backdrop-filter: blur(8px);
font-family: sans-serif;
}
.cd-cvr .arr:hover {
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.25);
color: #fff;
transform: scale(1.08);
}
.cd-cvr .arr:active { transform: scale(0.96); }
@media (max-width: 720px) {
.cd-cvr { height: 560px; }
.cd-cvr .cf-card { width: 200px; height: 268px; margin-left: -100px; margin-top: -134px; }
}
@media (prefers-reduced-motion: reduce) {
.cd-cvr .cf-card { transition: none !important; }
} /* ─── 02 Midnight Coverflow — 7-card cylindrical carousel ──── */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;700&family=Unbounded:wght@200;400;700&display=swap');
.cd-cvr {
--cd-cvr-bg: #060508;
position: relative;
width: 100%;
height: 640px;
background: var(--cd-cvr-bg);
font-family: 'Space Grotesk', system-ui, sans-serif;
overflow: hidden;
user-select: none;
box-sizing: border-box;
}
.cd-cvr *,
.cd-cvr *::before,
.cd-cvr *::after { box-sizing: border-box; margin: 0; padding: 0; }
.cd-cvr .card {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.cd-cvr .card::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(ellipse 90% 60% at 50% 40%, rgba(40,10,80,0.18) 0%, transparent 70%),
radial-gradient(ellipse 60% 40% at 50% 90%, rgba(180,80,0,0.06) 0%, transparent 70%);
pointer-events: none;
}
.cd-cvr .cvr-ground {
position: absolute;
bottom: 0; left: 0; right: 0;
height: 45%;
background: linear-gradient(to top, rgba(5,3,8,0.98) 0%, transparent 100%);
pointer-events: none;
z-index: 5;
}
.cd-cvr .viewport {
perspective: 1000px;
width: 100%;
height: 420px;
position: relative;
z-index: 1;
}
.cd-cvr .stage {
width: 100%;
height: 420px;
position: relative;
transform-style: preserve-3d;
}
.cd-cvr .cf-card {
width: 240px;
height: 320px;
position: absolute;
left: 50%;
top: 50%;
margin-left: -120px;
margin-top: -160px;
border-radius: 18px;
overflow: hidden;
cursor: pointer;
transform-style: preserve-3d;
transition: transform 0.65s cubic-bezier(0.23, 1, 0.32, 1),
opacity 0.65s ease,
filter 0.65s ease;
-webkit-box-reflect: below 8px linear-gradient(transparent 75%, rgba(5,3,8,0.55) 100%);
}
.cd-cvr .cf-card-inner {
width: 100%; height: 100%;
position: relative;
overflow: hidden;
border-radius: 18px;
}
.cd-cvr .card-art {
width: 100%; height: 100%;
position: relative;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-end;
padding: 22px;
}
.cd-cvr .card-art::before {
content: '';
position: absolute;
inset: 0;
background: inherit;
}
.cd-cvr .card-title-sm {
font-family: 'Space Grotesk', sans-serif;
font-size: 9px;
letter-spacing: 3px;
text-transform: uppercase;
margin-bottom: 5px;
position: relative;
z-index: 1;
}
.cd-cvr .card-title-lg {
font-family: 'Unbounded', sans-serif;
font-size: 16px;
font-weight: 700;
line-height: 1.25;
position: relative;
z-index: 1;
}
.cd-cvr .card-sub {
font-family: 'Space Grotesk', sans-serif;
font-size: 10px;
margin-top: 5px;
position: relative;
z-index: 1;
opacity: 0.65;
}
.cd-cvr .cf-card-inner::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(135deg, rgba(255,255,255,0.08) 0%, transparent 40%, rgba(0,0,0,0.2) 100%);
pointer-events: none;
}
/* Per-card palettes */
.cd-cvr .cf-card[data-i="0"] .card-art { background: linear-gradient(148deg, #0d0020 0%, #2a0058 40%, #1a0040 100%); }
.cd-cvr .cf-card[data-i="0"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 70% 30%, rgba(120,60,255,0.4) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="0"] .card-title-sm { color: rgba(180,140,255,0.7); }
.cd-cvr .cf-card[data-i="0"] .card-title-lg { color: #e8d8ff; }
.cd-cvr .cf-card[data-i="0"] .card-sub { color: rgba(180,140,255,0.5); }
.cd-cvr .cf-card[data-i="1"] .card-art { background: linear-gradient(148deg, #001a20 0%, #003050 40%, #001828 100%); }
.cd-cvr .cf-card[data-i="1"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 30% 60%, rgba(0,180,255,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="1"] .card-title-sm { color: rgba(80,200,255,0.7); }
.cd-cvr .cf-card[data-i="1"] .card-title-lg { color: #c8f0ff; }
.cd-cvr .cf-card[data-i="1"] .card-sub { color: rgba(80,200,255,0.5); }
.cd-cvr .cf-card[data-i="2"] .card-art { background: linear-gradient(148deg, #100400 0%, #300e00 40%, #1e0800 100%); }
.cd-cvr .cf-card[data-i="2"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 60% 40%, rgba(255,100,0,0.4) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="2"] .card-title-sm { color: rgba(255,160,80,0.7); }
.cd-cvr .cf-card[data-i="2"] .card-title-lg { color: #ffe8c8; }
.cd-cvr .cf-card[data-i="2"] .card-sub { color: rgba(255,160,80,0.5); }
.cd-cvr .cf-card[data-i="3"] .card-art { background: linear-gradient(148deg, #001800 0%, #003000 40%, #001a00 100%); }
.cd-cvr .cf-card[data-i="3"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 50% 50%, rgba(0,220,80,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="3"] .card-title-sm { color: rgba(80,220,120,0.7); }
.cd-cvr .cf-card[data-i="3"] .card-title-lg { color: #c8ffe0; }
.cd-cvr .cf-card[data-i="3"] .card-sub { color: rgba(80,220,120,0.5); }
.cd-cvr .cf-card[data-i="4"] .card-art { background: linear-gradient(148deg, #1a0010 0%, #3a0028 40%, #220018 100%); }
.cd-cvr .cf-card[data-i="4"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 40% 35%, rgba(255,40,180,0.38) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="4"] .card-title-sm { color: rgba(255,140,200,0.7); }
.cd-cvr .cf-card[data-i="4"] .card-title-lg { color: #ffd8f0; }
.cd-cvr .cf-card[data-i="4"] .card-sub { color: rgba(255,140,200,0.5); }
.cd-cvr .cf-card[data-i="5"] .card-art { background: linear-gradient(148deg, #0a0a00 0%, #1e1e00 40%, #121200 100%); }
.cd-cvr .cf-card[data-i="5"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 60% 30%, rgba(220,220,0,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="5"] .card-title-sm { color: rgba(220,220,80,0.7); }
.cd-cvr .cf-card[data-i="5"] .card-title-lg { color: #fffff0; }
.cd-cvr .cf-card[data-i="5"] .card-sub { color: rgba(220,220,80,0.5); }
.cd-cvr .cf-card[data-i="6"] .card-art { background: linear-gradient(148deg, #000e18 0%, #001c30 40%, #001020 100%); }
.cd-cvr .cf-card[data-i="6"] .card-art::before { background: radial-gradient(ellipse 70% 60% at 50% 60%, rgba(40,120,200,0.35) 0%, transparent 70%); }
.cd-cvr .cf-card[data-i="6"] .card-title-sm { color: rgba(100,180,255,0.7); }
.cd-cvr .cf-card[data-i="6"] .card-title-lg { color: #d8eeff; }
.cd-cvr .cf-card[data-i="6"] .card-sub { color: rgba(100,180,255,0.5); }
/* Decorative geo blobs */
.cd-cvr .geo { position: absolute; border-radius: 50%; opacity: 0.15; }
.cd-cvr .geo-1a { width: 140px; height: 140px; background: #a060ff; top: -30px; right: -30px; }
.cd-cvr .geo-1b { width: 70px; height: 70px; background: #6020ff; bottom: 40%; left: 20%; }
.cd-cvr .geo-2a { width: 180px; height: 180px; background: #00aaff; top: -50px; left: -30px; }
.cd-cvr .geo-2b { width: 55px; height: 55px; background: #00e8ff; bottom: 30%; right: 15%; }
.cd-cvr .geo-3a { width: 110px; height: 110px; background: #ff6600; top: 20px; right: 20px; }
.cd-cvr .geo-3b { width: 160px; height: 160px; background: #ff3300; bottom: -30px; left: -30px; }
.cd-cvr .geo-4a { width: 130px; height: 130px; background: #00cc44; top: -20px; left: 50%; margin-left: -65px; }
.cd-cvr .geo-4b { width: 80px; height: 80px; background: #00ff88; bottom: 20%; right: 10%; }
.cd-cvr .geo-5a { width: 140px; height: 140px; background: #ff00cc; top: 10px; right: -30px; }
.cd-cvr .geo-5b { width: 90px; height: 90px; background: #cc0088; bottom: 30%; left: 0%; }
.cd-cvr .geo-6a { width: 180px; height: 180px; background: #dddd00; top: -40px; left: -20px; }
.cd-cvr .geo-6b { width: 60px; height: 60px; background: #ffff40; bottom: 35%; right: 20%; }
.cd-cvr .geo-7a { width: 120px; height: 120px; background: #1c78cc; top: 30px; left: 30px; }
.cd-cvr .geo-7b { width: 100px; height: 100px; background: #3090e0; bottom: 20%; right: -10px; }
/* Nav */
.cd-cvr .nav-dots {
display: flex;
gap: 8px;
margin-top: 24px;
position: relative;
z-index: 10;
}
.cd-cvr .dot {
width: 6px; height: 6px;
border-radius: 50%;
background: rgba(255,255,255,0.2);
cursor: pointer;
border: none;
padding: 0;
transition: all 0.3s;
}
.cd-cvr .dot.active {
width: 22px;
border-radius: 3px;
background: rgba(255,255,255,0.7);
}
.cd-cvr .arrows {
position: absolute;
bottom: 28px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 16px;
z-index: 20;
}
.cd-cvr .arr {
width: 44px; height: 44px;
border-radius: 50%;
border: 1px solid rgba(255,255,255,0.12);
background: rgba(255,255,255,0.04);
color: rgba(255,255,255,0.6);
font-size: 18px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
backdrop-filter: blur(8px);
font-family: sans-serif;
}
.cd-cvr .arr:hover {
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.25);
color: #fff;
transform: scale(1.08);
}
.cd-cvr .arr:active { transform: scale(0.96); }
@media (max-width: 720px) {
.cd-cvr { height: 560px; }
.cd-cvr .cf-card { width: 200px; height: 268px; margin-left: -100px; margin-top: -134px; }
}
@media (prefers-reduced-motion: reduce) {
.cd-cvr .cf-card { transition: none !important; }
}(() => {
const root = document.querySelector('.cd-cvr');
if (!root) return;
const stage = root.querySelector('[data-cd-cvr-stage]');
const dotsEl = root.querySelector('[data-cd-cvr-dots]');
const prevBtn = root.querySelector('[data-cd-cvr-prev]');
const nextBtn = root.querySelector('[data-cd-cvr-next]');
if (!stage || !dotsEl || !prevBtn || !nextBtn) return;
const cards = Array.from(stage.querySelectorAll('.cf-card'));
const N = cards.length;
let current = Math.floor(N / 2);
cards.forEach((_, i) => {
const d = document.createElement('button');
d.type = 'button';
d.className = 'dot' + (i === current ? ' active' : '');
d.setAttribute('aria-label', `Go to slide ${i + 1}`);
d.addEventListener('click', () => goTo(i));
dotsEl.appendChild(d);
});
function updatePositions() {
const ANGLE_STEP = 42;
const Z_OFFSET = 80;
const SCALE_FALLOFF = 0.12;
cards.forEach((card, i) => {
const offset = i - current;
const absOff = Math.abs(offset);
const angle = offset * ANGLE_STEP;
const z = -absOff * Z_OFFSET;
const scale = Math.max(0.45, 1 - absOff * SCALE_FALLOFF);
const opacity = absOff > 3 ? 0 : Math.max(0.25, 1 - absOff * 0.22);
const brightness = Math.max(0.35, 1 - absOff * 0.2);
card.style.transform = `rotateY(${angle}deg) translateZ(${z}px) scale(${scale})`;
card.style.opacity = opacity;
card.style.filter = `brightness(${brightness})`;
card.style.zIndex = 10 - absOff;
card.style.pointerEvents = absOff <= 1 ? 'auto' : 'none';
});
Array.from(dotsEl.children).forEach((d, i) => {
d.className = 'dot' + (i === current ? ' active' : '');
});
}
function goTo(n) {
current = Math.max(0, Math.min(N - 1, n));
updatePositions();
}
prevBtn.addEventListener('click', () => goTo(current - 1));
nextBtn.addEventListener('click', () => goTo(current + 1));
cards.forEach((card, i) => {
card.addEventListener('click', () => { if (i !== current) goTo(i); });
});
// Keyboard — only when wrapper has focus or pointer is inside it
let pointerInside = false;
root.addEventListener('mouseenter', () => { pointerInside = true; });
root.addEventListener('mouseleave', () => { pointerInside = false; });
document.addEventListener('keydown', e => {
if (!pointerInside) return;
if (e.key === 'ArrowLeft') { goTo(current - 1); e.preventDefault(); }
if (e.key === 'ArrowRight') { goTo(current + 1); e.preventDefault(); }
});
// Drag scoped to wrapper
let dragStart = null;
root.addEventListener('mousedown', e => { dragStart = e.clientX; });
root.addEventListener('mouseup', e => {
if (dragStart === null) return;
const dx = e.clientX - dragStart;
if (Math.abs(dx) > 40) goTo(current + (dx < 0 ? 1 : -1));
dragStart = null;
});
root.addEventListener('mouseleave', () => { dragStart = null; });
root.addEventListener('touchstart', e => { dragStart = e.touches[0].clientX; }, { passive: true });
root.addEventListener('touchend', e => {
if (dragStart === null) return;
const dx = e.changedTouches[0].clientX - dragStart;
if (Math.abs(dx) > 40) goTo(current + (dx < 0 ? 1 : -1));
dragStart = null;
});
updatePositions();
})(); (() => {
const root = document.querySelector('.cd-cvr');
if (!root) return;
const stage = root.querySelector('[data-cd-cvr-stage]');
const dotsEl = root.querySelector('[data-cd-cvr-dots]');
const prevBtn = root.querySelector('[data-cd-cvr-prev]');
const nextBtn = root.querySelector('[data-cd-cvr-next]');
if (!stage || !dotsEl || !prevBtn || !nextBtn) return;
const cards = Array.from(stage.querySelectorAll('.cf-card'));
const N = cards.length;
let current = Math.floor(N / 2);
cards.forEach((_, i) => {
const d = document.createElement('button');
d.type = 'button';
d.className = 'dot' + (i === current ? ' active' : '');
d.setAttribute('aria-label', `Go to slide ${i + 1}`);
d.addEventListener('click', () => goTo(i));
dotsEl.appendChild(d);
});
function updatePositions() {
const ANGLE_STEP = 42;
const Z_OFFSET = 80;
const SCALE_FALLOFF = 0.12;
cards.forEach((card, i) => {
const offset = i - current;
const absOff = Math.abs(offset);
const angle = offset * ANGLE_STEP;
const z = -absOff * Z_OFFSET;
const scale = Math.max(0.45, 1 - absOff * SCALE_FALLOFF);
const opacity = absOff > 3 ? 0 : Math.max(0.25, 1 - absOff * 0.22);
const brightness = Math.max(0.35, 1 - absOff * 0.2);
card.style.transform = `rotateY(${angle}deg) translateZ(${z}px) scale(${scale})`;
card.style.opacity = opacity;
card.style.filter = `brightness(${brightness})`;
card.style.zIndex = 10 - absOff;
card.style.pointerEvents = absOff <= 1 ? 'auto' : 'none';
});
Array.from(dotsEl.children).forEach((d, i) => {
d.className = 'dot' + (i === current ? ' active' : '');
});
}
function goTo(n) {
current = Math.max(0, Math.min(N - 1, n));
updatePositions();
}
prevBtn.addEventListener('click', () => goTo(current - 1));
nextBtn.addEventListener('click', () => goTo(current + 1));
cards.forEach((card, i) => {
card.addEventListener('click', () => { if (i !== current) goTo(i); });
});
// Keyboard — only when wrapper has focus or pointer is inside it
let pointerInside = false;
root.addEventListener('mouseenter', () => { pointerInside = true; });
root.addEventListener('mouseleave', () => { pointerInside = false; });
document.addEventListener('keydown', e => {
if (!pointerInside) return;
if (e.key === 'ArrowLeft') { goTo(current - 1); e.preventDefault(); }
if (e.key === 'ArrowRight') { goTo(current + 1); e.preventDefault(); }
});
// Drag scoped to wrapper
let dragStart = null;
root.addEventListener('mousedown', e => { dragStart = e.clientX; });
root.addEventListener('mouseup', e => {
if (dragStart === null) return;
const dx = e.clientX - dragStart;
if (Math.abs(dx) > 40) goTo(current + (dx < 0 ? 1 : -1));
dragStart = null;
});
root.addEventListener('mouseleave', () => { dragStart = null; });
root.addEventListener('touchstart', e => { dragStart = e.touches[0].clientX; }, { passive: true });
root.addEventListener('touchend', e => {
if (dragStart === null) return;
const dx = e.changedTouches[0].clientX - dragStart;
if (Math.abs(dx) > 40) goTo(current + (dx < 0 ? 1 : -1));
dragStart = null;
});
updatePositions();
})();