Hover card fan
Pure CSSThree overlapping cards: the one you point at straightens and comes toward you while the others dim and lean away. Static strips catch the pointer, so nothing flickers.
Radio buttons open one section at a time: its panel swings down on its top edge like a flap while the headers below slide out of the way. No height is animated.
Your edited version
<input type="radio">s (visually hidden, not display: none) drive the state — that keeps arrow-key navigation and screen readers working for free.transform-origin: top center plus rotateX(-90deg) to fold it flat, edge-on to the viewer, until its radio is checked.height. The frame has a fixed size; sections below the open one are pushed down with translateY by exactly one panel and its gap (76 units) instead.~ (general sibling) plus :checked lets one radio style both its own section and every section after it, all from CSS alone.--u, so the accordion is the same share of a gallery card, the editor and a recording canvas. The widget is its own control, so it fills the model box and has no control row under it.:checked ~ sibling selectorsrotateX on transform-origin: toptranslateY instead of heightfixed-size frame<div class="scene">
<div class="accordion">
<input type="radio" name="acc" id="acc-0" checked />
<input type="radio" name="acc" id="acc-1" />
<input type="radio" name="acc" id="acc-2" />
<div class="sec" style="--i:0">
<label for="acc-0">Perspective</label>
<div class="panel">The camera distance. Put it on the parent; smaller values look more dramatic.</div>
</div>
<div class="sec" style="--i:1">
<label for="acc-1">Preserve-3d</label>
<div class="panel">Without it, children are flattened into the plane of their parent.</div>
</div>
<div class="sec" style="--i:2">
<label for="acc-2">Backface</label>
<div class="panel">Hide the reverse side of a face so text never shows mirrored.</div>
</div>
</div>
</div>
.scene {
/* one base unit: every length below is a multiple of it, so the accordion is the same share
of a card, the editor, a full screen and a recording canvas */
--u: 0.30vmin;
perspective: calc(800 * var(--u));
}
.accordion {
position: relative;
width: calc(196 * var(--u));
height: calc(187 * var(--u)); /* 3 × (header 32 + gap 5) + panel 71 */
transform-style: preserve-3d;
transform: rotateY(-18deg) rotateX(4deg);
/* the frame and the headers are coplanar, and coplanar boxes have no stable hit-test order in
3D, so the frame itself could win a click in the middle of a header. Nothing but a header
(and an open panel) takes the pointer. */
pointer-events: none;
}
/* real radios keep it keyboard-friendly (arrow keys move between sections); only hidden */
.accordion > input {
position: absolute;
width: calc(1 * var(--u));
height: calc(1 * var(--u));
margin: 0;
opacity: 0;
pointer-events: none;
}
.sec {
position: absolute;
top: calc(var(--i) * 37 * var(--u));
right: 0;
left: 0;
height: calc(32 * var(--u));
transform-style: preserve-3d;
transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.accordion label {
display: flex;
align-items: center;
justify-content: space-between;
/* the header is its section's 32 units, border included */
box-sizing: border-box;
height: 100%;
padding: 0 calc(12 * var(--u));
border: calc(1 * var(--u)) solid rgb(140 150 220 / 0.34);
border-radius: calc(9 * var(--u));
background: color-mix(in srgb, #8b6cff 14%, #141830);
color: #eceefb;
font-size: calc(12 * var(--u));
font-weight: 700;
cursor: pointer;
user-select: none;
pointer-events: auto;
}
/* chevron */
.accordion label::after {
content: '';
width: calc(6 * var(--u));
height: calc(6 * var(--u));
border-right: calc(2 * var(--u)) solid #949bc0;
border-bottom: calc(2 * var(--u)) solid #949bc0;
transform: translateY(calc(-2 * var(--u))) rotate(45deg);
transition: transform 0.4s;
}
/* the flap: hinged on its top edge, folded back flat (edge-on to the viewer) until opened */
.panel {
position: absolute;
top: calc(100% + 5 * var(--u));
right: 0;
left: 0;
/* 71 units outside, padding and border included: the sections below slide down 76, the panel
and its 5-unit gap */
box-sizing: border-box;
height: calc(71 * var(--u));
padding: calc(9 * var(--u)) calc(12 * var(--u));
border: calc(1 * var(--u)) solid color-mix(in srgb, #2ee6d6 60%, transparent);
border-radius: calc(9 * var(--u));
background: linear-gradient(180deg, color-mix(in srgb, #2ee6d6 26%, #141830), color-mix(in srgb, #8b6cff 16%, #141830));
color: #eceefb;
font-size: calc(11 * var(--u));
line-height: 1.45;
opacity: 0;
pointer-events: none;
transform-origin: top center;
transform: rotateX(-90deg);
transition:
transform 0.5s cubic-bezier(0.4, 0, 0.2, 1),
opacity 0.3s;
}
/* the open section: flap down, header lit (each radio only ever targets its own section) */
#acc-0:checked ~ .sec:nth-of-type(1) .panel,
#acc-1:checked ~ .sec:nth-of-type(2) .panel,
#acc-2:checked ~ .sec:nth-of-type(3) .panel {
opacity: 1;
pointer-events: auto;
transform: rotateX(0deg);
}
#acc-0:checked ~ .sec:nth-of-type(1) label,
#acc-1:checked ~ .sec:nth-of-type(2) label,
#acc-2:checked ~ .sec:nth-of-type(3) label {
border-color: #8b6cff;
background: color-mix(in srgb, #8b6cff 38%, #141830);
}
#acc-0:checked ~ .sec:nth-of-type(1) label::after,
#acc-1:checked ~ .sec:nth-of-type(2) label::after,
#acc-2:checked ~ .sec:nth-of-type(3) label::after {
transform: translateY(calc(1 * var(--u))) rotate(-135deg);
}
#acc-0:focus-visible ~ .sec:nth-of-type(1) label,
#acc-1:focus-visible ~ .sec:nth-of-type(2) label,
#acc-2:focus-visible ~ .sec:nth-of-type(3) label {
outline: calc(2 * var(--u)) solid #2ee6d6;
outline-offset: calc(2 * var(--u));
}
/* every section after the open one slides down by exactly one panel's height */
#acc-0:checked ~ .sec:nth-of-type(n + 2) {
transform: translateY(calc(76 * var(--u)));
}
#acc-1:checked ~ .sec:nth-of-type(n + 3) {
transform: translateY(calc(76 * var(--u)));
}