Phone mockup
Pure CSSA phone with real thickness: screen, back, four thin walls and a stack of rounded slabs that fills the corners. It turns to show both sides.
One clip-path shape repeated in 14 layers, 2px apart. The stack reads as a solid block; back layers are darker and the front one carries a sweeping shine.
Your edited version
clip-path: polygon(evenodd, …). The path runs round the hexagon, jumps in and traces the triangle; with evenodd the area enclosed twice becomes a hole.translateZ(calc((var(--i) - 6.5) * 2px)). Seen at an angle their edges overlap into a solid side, and the hole gets inner walls for free.--i grows: rgb(6 7 20 / calc(0.6 - var(--i) * 0.033)). The side fades from bright to dark like a lit extrusion.translateX only; the layer’s clip-path clips it to the logo, so it never spills out.clip-path polygon with a hole (evenodd)translateZ per layer from --idarkening by depth with calc() alphashine moved with transform only<div class="scene">
<div class="logo">
<i style="--i:0"></i><i style="--i:1"></i><i style="--i:2"></i><i style="--i:3"></i><i style="--i:4"></i>
<i style="--i:5"></i><i style="--i:6"></i><i style="--i:7"></i><i style="--i:8"></i><i style="--i:9"></i>
<i style="--i:10"></i><i style="--i:11"></i><i style="--i:12"></i><i style="--i:13"></i>
</div>
</div>
.scene {
perspective: 800px;
}
.logo {
position: relative;
width: 116px;
height: 116px;
transform-style: preserve-3d;
animation: sway 6s ease-in-out infinite alternate;
}
/* soft glow far behind the mark */
.logo::before {
content: '';
position: absolute;
inset: -26px;
border-radius: 50%;
background: radial-gradient(closest-side, rgb(139 108 255 / 0.38), transparent);
transform: translateZ(-60px);
}
.logo > i {
/* back layers darker */
--shade: calc(0.6 - var(--i) * 0.033);
position: absolute;
inset: 0;
/* hexagon, then a jump in to trace the "play" triangle: evenodd makes it a hole */
clip-path: polygon(evenodd,
50% 0, 93.3% 25%, 93.3% 75%, 50% 100%, 6.7% 75%, 6.7% 25%, 50% 0,
39% 31%, 71% 50%, 39% 69%, 39% 31%);
background:
linear-gradient(rgb(6 7 20 / var(--shade)), rgb(6 7 20 / var(--shade))),
linear-gradient(135deg, #8b6cff, #ff4d9d);
/* 14 layers, 2px apart, centred on the middle */
transform: translateZ(calc((var(--i) - 6.5) * 2px));
}
/* the front layer is the face */
.logo > i:last-child {
background:
radial-gradient(circle at 30% 18%, rgb(255 255 255 / 0.45), transparent 45%),
linear-gradient(135deg, #a28aff, #ff4d9d 70%, #ffb547);
}
/* the shine: clipped by the layer's clip-path, moved with transform only */
.logo > i:last-child::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 0.7) 50%, transparent 65%);
transform: translateX(-100%);
animation: shine 4s ease-in-out infinite;
}
@keyframes sway {
from { transform: rotateX(-10deg) rotateY(-40deg); }
to { transform: rotateX(-4deg) rotateY(40deg); }
}
/* both ends are off the logo, so the jump back is never seen */
@keyframes shine {
0%, 45% { transform: translateX(-100%); }
80%, 100% { transform: translateX(100%); }
}
$n: 14; // layers
$gap: 2px; // distance between layers: 14 × 2px ≈ 26px of extrusion
$s: 116px;
// Hexagon with a "play" triangle cut out of it. With `evenodd` the path runs round the outer
// hexagon, jumps in to trace the triangle, and every area enclosed twice becomes a hole.
$shape: polygon(
evenodd,
50% 0,
93.3% 25%,
93.3% 75%,
50% 100%,
6.7% 75%,
6.7% 25%,
50% 0,
39% 31%,
71% 50%,
39% 69%,
39% 31%
);
.d-logo3d {
position: relative;
width: $s;
height: $s;
transform-style: preserve-3d;
// `alternate` + ease-in-out: seamless, and it lingers on the two angles that show the depth.
animation: d-logo3d-sway 6s ease-in-out infinite alternate;
// soft coloured glow far behind the mark
&::before {
content: '';
position: absolute;
inset: -26px;
border-radius: 50%;
background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 38%, transparent), transparent);
transform: translateZ(-60px);
}
// Sass only hands out the index; the depth and the shading are one calc() each.
@for $i from 0 to $n {
> i:nth-child(#{$i + 1}) {
--i: #{$i};
}
}
> i {
// back layers are darker: the extrusion reads as a side lit from the front
--shade: calc(0.6 - var(--i) * 0.033);
position: absolute;
inset: 0;
clip-path: $shape;
background:
linear-gradient(rgb(6 7 20 / var(--shade)), rgb(6 7 20 / var(--shade))),
linear-gradient(135deg, var(--accent), var(--hot));
transform: translateZ(calc((var(--i) - #{($n - 1) * 0.5}) * #{$gap}));
}
// the front layer is the face: brighter, with a glassy top light and the moving shine
> i:last-child {
background:
radial-gradient(circle at 30% 18%, rgb(255 255 255 / 0.45), transparent 45%),
linear-gradient(135deg, color-mix(in srgb, var(--accent) 80%, #fff), var(--hot) 70%, var(--warm));
// clip-path on the layer also clips this child, so the shine never leaves the logo
&::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 0.7) 50%, transparent 65%);
transform: translateX(-100%);
animation: d-logo3d-shine 4s ease-in-out infinite;
}
}
}
@keyframes d-logo3d-sway {
from {
transform: rotateX(-10deg) rotateY(-40deg);
}
to {
transform: rotateX(-4deg) rotateY(40deg);
}
}
// Off to the left, wait, sweep, off to the right. Both ends are invisible, so the jump back
// is never seen.
@keyframes d-logo3d-shine {
0%,
45% {
transform: translateX(-100%);
}
80%,
100% {
transform: translateX(100%);
}
}