/* @property registers the medal's angle so it can transition and animate on its own. The hills are SVG backgrounds
(clip-path would break the 3D sorting). :has(), container queries and cqi units are utilities in the markup. */
@property --mc-ry{syntax:"<angle>";inherits:true;initial-value:0deg}
@keyframes mc-turn{from{--mc-ry:0deg}to{--mc-ry:360deg}}
@utility mc-hill-1{background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpolygon points='0,70 14,38 27,60 44,22 60,55 74,30 90,58 100,44 100,100 0,100' fill='%23a78bfa'/%3E%3C/svg%3E") 0 0/100% 100% no-repeat}
@utility mc-hill-2{background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpolygon points='0,62 18,52 32,74 50,48 66,70 82,50 100,66 100,100 0,100' fill='%237c3aed'/%3E%3C/svg%3E") 0 0/100% 100% no-repeat}
@utility mc-hill-3{background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100' preserveAspectRatio='none'%3E%3Cpolygon points='0,80 10,70 12,52 14,70 30,78 52,74 70,82 84,66 86,48 88,66 100,74 100,100 0,100' fill='%233b0764'/%3E%3C/svg%3E") 0 0/100% 100% no-repeat}
About this set
Three 3D effects that newer CSS features make possible without JavaScript. The medal is a gold race medal with a front and a back. Its turn is a custom property, –mc-ry, registered with @property as an angle, so it can transition when Back is picked and animate a full spin while the transform simply reads it. :has() connects the Front and Back radios and the Spin switch to the medal wherever they sit in the markup, and the spin only runs after the visitor turns it on. The diorama is a paper-cut scene of three hills inside a box; a five by five grid of invisible hover cells updates two custom properties through :has(), and perspective-origin follows them, so moving the pointer lets you look around inside the box. The weather card takes its depth from its container: the sun, cloud, temperature and forecast sit at translateZ distances in cqi units, and an @container rule switches to a wide layout from 480 pixels. The same card is shown in a narrow and a wide slot. Each effect falls back to a static design in browsers without these features.
What’s included
Angle registered with @property, so one rotation can transition and animate
:has() links the radios and the Spin switch to the medal without JavaScript
perspective-origin that follows the pointer through a :has() hover grid
translateZ depth in cqi units and an @container wide layout
Spin switch hidden under prefers-reduced-motion
Accessibility
The medal controls are a radio group with a legend and a checkbox with role="switch", each with a 3px focus outline on the visible control. The diorama is one image with a text alternative and a caption below it, since its effect depends on a pointer. The weather cards are articles named by their city. Under prefers-reduced-motion the spin switch is hidden, the medal turns without a transition and the diorama view changes without easing.
Customise it
Change the spin speed in the mc-turn animation and the turn time in the --mc-ry transition, the look-around range in the --px and --py rules, and the depth of each weather layer in cqi. The wide layout starts at the @container (min-width: 480px) rule, or the @min-[480px] variants in Tailwind.