MiniMax M3.1 Flash
by MiniMaxReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 1 min 11 s
- Cost
- $0.011
- Output tokens
- 17,538
- Spent thinking
- 9,787 tokens
- Speed
- 247.3 tok/s
- Console errors
- 0
- First token after
- 345 ms
- First visible text after
- 50.2 s
- Prompt tokens
- 681
- Code size
- 20.6 KB
- Finish reason
- stop
- Served by
- Nebius
- Model id
minimax/minimax-m3.1-flash- Reasoning sent
{"effort":"xhigh"}- Max output
- 64,000 tokens
- Generated
- Nov 11, 2026
What it was asked
The prompt
Create a set of four animated weather cards (sunny, rainy, snowy, stormy), made with HTML and CSS only. Requirements: - Absolutely no JavaScript: the file must not contain any <script> tag or inline event handler. - No images, no SVG, no icon fonts: every weather icon is built from HTML elements and pseudo-elements styled with CSS. - Each card shows an animated icon (rotating sun rays, falling rain drops, drifting snowflakes, flashing lightning), a city name, a temperature and a short description. - Each card has its own background gradient matching the weather. - The cards are displayed in a responsive grid (4 per row on desktop, stacked on mobile) and lift up on hover. - Smooth infinite animations using @keyframes, and respect prefers-reduced-motion.
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task. Output rules: - Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block. - Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task. - Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw. - The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar. - Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction. - Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session. - Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing. - The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message. - The code must run with zero errors in the console of the latest Chrome.
Code run-1.html · 632 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Weather Cards — Pure CSS</title>
<style>
/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
:root {
--radius: 24px;
--font: "Segoe UI", Roboto, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
}
html, body { max-width: 100%; overflow-x: hidden; }
body {
margin: 0;
min-height: 100vh;
padding: 46px 20px 70px;
font-family: var(--font);
color: #eaf1fb;
background:
radial-gradient(1100px 620px at 15% -15%, #1d2c48 0%, rgba(29,44,72,0) 60%),
radial-gradient(900px 520px at 95% -5%, #32264d 0%, rgba(50,38,77,0) 62%),
radial-gradient(800px 700px at 50% 120%, #14243a 0%, rgba(20,36,58,0) 60%),
linear-gradient(180deg, #0a1120 0%, #060a13 100%);
display: flex;
justify-content: center;
}
.wrap { width: 100%; max-width: 1260px; }
header { text-align: center; margin-bottom: 40px; }
header h1 {
margin: 0 0 10px;
font-size: clamp(26px, 4.2vw, 42px);
font-weight: 700;
letter-spacing: .5px;
background: linear-gradient(90deg, #ffffff, #bcd4f0 60%, #ffd9a0);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
header p {
margin: 0;
color: #93a6c2;
font-size: 15px;
letter-spacing: .04em;
}
header .tag {
display: inline-block;
margin-top: 14px;
padding: 6px 14px;
font-size: 11.5px;
letter-spacing: .18em;
text-transform: uppercase;
color: #a9c4e6;
border: 1px solid rgba(168, 196, 230, .28);
border-radius: 999px;
background: rgba(120, 160, 210, .08);
}
/* ---------- grid ---------- */
.grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 26px;
}
/* ---------- card shell ---------- */
.card {
position: relative;
display: flex;
flex-direction: column;
min-height: 430px;
border-radius: var(--radius);
overflow: hidden;
isolation: isolate;
box-shadow:
0 22px 38px -22px rgba(0, 0, 0, .85),
0 1px 0 rgba(255, 255, 255, .10) inset,
0 0 0 1px rgba(255, 255, 255, .06);
transition: transform .38s cubic-bezier(.2, .85, .25, 1), box-shadow .38s ease;
transform: translateZ(0);
will-change: transform;
}
.card:hover {
transform: translateY(-14px);
box-shadow:
0 40px 55px -26px rgba(0, 0, 0, .9),
0 1px 0 rgba(255, 255, 255, .16) inset,
0 0 0 1px rgba(255, 255, 255, .12);
}
/* glossy sheen */
.card::after {
content: "";
position: absolute;
inset: 0;
z-index: 5;
pointer-events: none;
background: linear-gradient(118deg, rgba(255, 255, 255, .18) 0%, rgba(255, 255, 255, 0) 38%);
}
.card--sunny { background: linear-gradient(168deg, #ffdf8c 0%, #ffb14f 46%, #ef7a2c 100%); --accent: #ffd166; --ink: #4a2a06; }
.card--rainy { background: linear-gradient(168deg, #7d9fc0 0%, #4a6a87 45%, #2b4258 100%); --accent: #7fd4ff; --ink: #ffffff; }
.card--snowy { background: linear-gradient(168deg, #d8ecfb 0%, #a6c9e4 45%, #6f96ba 100%); --accent: #ffffff; --ink: #10304c; }
.card--stormy { background: linear-gradient(168deg, #555a7c 0%, #2c2f49 45%, #14162a 100%); --accent: #ffcf5c; --ink: #ffffff; }
/* ---------- sky / icon stage ---------- */
.sky {
position: relative;
flex: 1 1 auto;
min-height: 232px;
overflow: hidden;
}
.card:hover .sun__core { box-shadow: 0 0 52px rgba(255, 214, 110, .95), 0 0 100px rgba(255, 175, 60, .6); }
/* ---------- SUN ---------- */
.sun {
position: absolute;
left: 50%;
top: 50%;
width: 150px;
height: 150px;
transform: translate(-50%, -50%);
}
.sun__glow {
position: absolute;
inset: -34%;
border-radius: 50%;
background: radial-gradient(circle, rgba(255, 240, 175, .60) 0%, rgba(255, 226, 140, 0) 66%);
animation: breathe 4.6s ease-in-out infinite;
}
.sun__rays {
position: absolute;
inset: -14%;
border-radius: 50%;
background: conic-gradient(from 0deg,
rgba(255, 248, 214, .95) 0deg 5deg, rgba(255, 248, 214, 0) 5deg 27deg,
rgba(255, 248, 214, .95) 27deg 31deg, rgba(255, 248, 214, 0) 31deg 58deg,
rgba(255, 248, 214, .95) 58deg 64deg, rgba(255, 248, 214, 0) 64deg 91deg,
rgba(255, 248, 214, .95) 91deg 95deg, rgba(255, 248, 214, 0) 95deg 126deg,
rgba(255, 248, 214, .95) 126deg 132deg, rgba(255, 248, 214, 0) 132deg 160deg,
rgba(255, 248, 214, .95) 160deg 164deg, rgba(255, 248, 214, 0) 164deg 196deg,
rgba(255, 248, 214, .95) 196deg 202deg, rgba(255, 248, 214, 0) 202deg 231deg,
rgba(255, 248, 214, .95) 231deg 235deg, rgba(255, 248, 214, 0) 235deg 268deg,
rgba(255, 248, 214, .95) 268deg 274deg, rgba(255, 248, 214, 0) 274deg 300deg,
rgba(255, 248, 214, .95) 300deg 306deg, rgba(255, 248, 214, 0) 306deg 330deg,
rgba(255, 248, 214, .95) 330deg 334deg, rgba(255, 248, 214, 0) 334deg 360deg);
-webkit-mask: radial-gradient(circle, transparent 0 35%, #000 38% 50%, transparent 51%);
mask: radial-gradient(circle, transparent 0 35%, #000 38% 50%, transparent 51%);
animation: spin 26s linear infinite;
}
.sun__core {
position: absolute;
inset: 23%;
border-radius: 50%;
background: radial-gradient(circle at 34% 28%, #fffdf2 0 20%, #ffe484 44%, #ffb52e 76%, #ff8f1c 100%);
box-shadow: 0 0 40px rgba(255, 205, 80, .8), 0 0 82px rgba(255, 170, 50, .45);
transition: box-shadow .4s ease;
animation: pulse 3.8s ease-in-out infinite;
}
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.08); } }
@keyframes breathe{ 0%, 100% { opacity: .7; transform: scale(1); } 50% { opacity: 1; transform: scale(1.1); } }
/* ---------- CLOUD ---------- */
.cloud {
position: absolute;
left: 50%;
top: 26px;
width: 132px;
height: 44px;
margin-left: -66px;
border-radius: 999px;
background: linear-gradient(180deg, #ffffff 0%, #d6e0ec 100%);
box-shadow: 0 12px 22px rgba(10, 20, 35, .28);
z-index: 3;
}
.cloud::before,
.cloud::after {
content: "";
position: absolute;
border-radius: 50%;
background: inherit;
}
.cloud::before { width: 64px; height: 64px; left: 12px; top: -30px; }
.cloud::after { width: 84px; height: 84px; right: 10px; top: -42px; }
.cloud--storm {
background: linear-gradient(180deg, #7c829e 0%, #4b5069 100%);
box-shadow: 0 14px 26px rgba(0, 0, 0, .5);
}
.cloud--rain { opacity: .97; }
/* ---------- drifting background clouds ---------- */
.drift {
position: absolute;
height: 66px;
width: 170px;
border-radius: 50%;
background: rgba(255, 255, 255, .16);
filter: blur(20px);
animation: drift 30s linear infinite;
z-index: 0;
}
.drift--1 { top: 14px; left: -45%; }
.drift--2 { top: 84px; left: -60%; animation-duration: 44s; animation-delay: -16s; }
.card--stormy .drift { background: rgba(255, 255, 255, .09); }
@keyframes drift { from { transform: translateX(0); } to { transform: translateX(620px); } }
/* ---------- RAIN ---------- */
.rain, .snow {
position: absolute;
left: 4%;
right: 4%;
top: 96px;
bottom: 0;
z-index: 1;
}
.drop {
position: absolute;
top: 0;
left: var(--x);
width: 3px;
height: 18px;
border-radius: 4px;
background: linear-gradient(180deg, rgba(214, 238, 255, 0) 0%, rgba(214, 238, 255, .95) 65%);
box-shadow: 0 0 7px rgba(190, 226, 255, .55);
opacity: 0;
animation: fall var(--dur) linear infinite;
animation-delay: var(--d);
}
.rain .drop:nth-child(1) { --x: 5%; --d: 0s; --dur: .95s; }
.rain .drop:nth-child(2) { --x: 16%; --d: .34s; --dur: 1.15s; }
.rain .drop:nth-child(3) { --x: 27%; --d: .68s; --dur: 1.02s; }
.rain .drop:nth-child(4) { --x: 38%; --d: .18s; --dur: 1.22s; }
.rain .drop:nth-child(5) { --x: 48%; --d: .82s; --dur: .98s; }
.rain .drop:nth-child(6) { --x: 59%; --d: .5s; --dur: 1.18s; }
.rain .drop:nth-child(7) { --x: 70%; --d: .12s; --dur: 1.06s; }
.rain .drop:nth-child(8) { --x: 81%; --d: .74s; --dur: 1.24s; }
.rain .drop:nth-child(9) { --x: 91%; --d: .44s; --dur: 1s; }
@keyframes fall {
0% { transform: translate3d(0, -26px, 0) scaleY(.55); opacity: 0; }
14% { opacity: .95; }
72% { opacity: .95; }
100% { transform: translate3d(-11px, 112px, 0) scaleY(1.15); opacity: 0; }
}
/* puddle shimmer under the rain */
.puddle {
position: absolute;
left: 50%;
bottom: 2px;
width: 170px;
height: 24px;
margin-left: -85px;
border-radius: 50%;
background: radial-gradient(ellipse at center, rgba(226, 244, 255, .40) 0%, rgba(226, 244, 255, 0) 70%);
animation: ripple 3.4s ease-in-out infinite;
z-index: 1;
}
@keyframes ripple { 0%, 100% { transform: scaleX(.86); opacity: .55; } 50% { transform: scaleX(1.06); opacity: .95; } }
/* ---------- SNOW ---------- */
.flake {
position: absolute;
top: 0;
left: var(--x);
width: var(--s);
height: var(--s);
background:
radial-gradient(circle, #ffffff 0 20%, rgba(255,255,255,0) 22%),
linear-gradient(0deg, rgba(255,255,255,0) 44%, #fff 44% 56%, rgba(255,255,255,0) 56%),
linear-gradient(-30deg, rgba(255,255,255,0) 44%, #fff 44% 56%, rgba(255,255,255,0) 56%),
linear-gradient(30deg, rgba(255,255,255,0) 44%, #fff 44% 56%, rgba(255,255,255,0) 56%);
filter: drop-shadow(0 0 4px rgba(255, 255, 255, .8));
opacity: 0;
animation: snowfall var(--dur) linear infinite;
animation-delay: var(--d);
}
.snow .flake:nth-child(1) { --x: 4%; --s: 13px; --d: 0s; --dur: 6.4s; }
.snow .flake:nth-child(2) { --x: 14%; --s: 9px; --d: 1.1s; --dur: 7.6s; }
.snow .flake:nth-child(3) { --x: 24%; --s: 12px; --d: 2.3s; --dur: 8.4s; }
.snow .flake:nth-child(4) { --x: 34%; --s: 8px; --d: 3.1s; --dur: 6.9s; }
.snow .flake:nth-child(5) { --x: 43%; --s: 14px; --d: .6s; --dur: 9.1s; }
.snow .flake:nth-child(6) { --x: 53%; --s: 10px; --d: 4.4s; --dur: 7.2s; }
.snow .flake:nth-child(7) { --x: 63%; --s: 12px; --d: 2.7s; --dur: 8.8s; }
.snow .flake:nth-child(8) { --x: 73%; --s: 9px; --d: 5.2s; --dur: 6.6s; }
.snow .flake:nth-child(9) { --x: 83%; --s: 13px; --d: 1.7s; --dur: 9.4s; }
.snow .flake:nth-child(10) { --x: 93%; --s: 8px; --d: 3.8s; --dur: 7.9s; }
@keyframes snowfall {
0% { transform: translate3d(0, -22px, 0) rotate(0deg); opacity: 0; }
12% { opacity: .95; }
50% { transform: translate3d(15px, 46px, 0) rotate(180deg); }
88% { opacity: .9; }
100% { transform: translate3d(-13px, 116px, 0) rotate(360deg); opacity: 0; }
}
/* ---------- STORM ---------- */
.flash {
position: absolute;
inset: 0;
z-index: 4;
pointer-events: none;
opacity: 0;
background: radial-gradient(circle at 50% 42%, rgba(255,255,255,.70) 0%, rgba(255,255,255,0) 62%);
animation: flash 7s linear infinite;
}
.bolt {
position: absolute;
left: 50%;
top: 84px;
width: 40px;
height: 84px;
margin-left: -20px;
z-index: 2;
background: linear-gradient(180deg, #fffbe0 0%, #ffd23f 60%, #ffa319 100%);
clip-path: polygon(56% 0%, 18% 54%, 45% 54%, 30% 100%, 82% 42%, 53% 42%);
filter: drop-shadow(0 0 10px rgba(255, 214, 70, .9));
opacity: 0;
animation: flash 7s linear infinite;
}
@keyframes flash {
0%, 3% { opacity: 0; }
4% { opacity: .95; }
5% { opacity: .08; }
6% { opacity: .85; }
7%, 44% { opacity: 0; }
45% { opacity: .70; }
46% { opacity: .05; }
47% { opacity: .55; }
48%, 100%{ opacity: 0; }
}
.wind i {
position: absolute;
height: 2px;
width: 74px;
border-radius: 2px;
background: linear-gradient(90deg, rgba(255,255,255,0), rgba(255,255,255,.55), rgba(255,255,255,0));
transform: rotate(-11deg);
z-index: 2;
animation: gust 5.2s linear infinite;
}
.wind i:nth-child(1) { top: 150px; left: -90px; animation-delay: 0s; }
.wind i:nth-child(2) { top: 186px; left: -120px; animation-delay: -2.4s; }
.wind i:nth-child(3) { top: 120px; left: -150px; animation-delay: -3.6s; opacity: .6; }
@keyframes gust {
0% { transform: translateX(0) rotate(-11deg); opacity: 0; }
15% { opacity: .9; }
85% { opacity: .9; }
100% { transform: translateX(420px) rotate(-11deg); opacity: 0; }
}
/* ---------- info panel ---------- */
.info {
position: relative;
z-index: 6;
padding: 20px 22px 22px;
color: var(--ink);
background: var(--glass, rgba(8, 16, 28, .30));
-webkit-backdrop-filter: blur(6px);
backdrop-filter: blur(6px);
border-top: 1px solid rgba(255, 255, 255, .14);
}
.card--sunny { --glass: rgba(60, 25, 0, .20); }
.card--rainy { --glass: rgba(6, 18, 32, .32); }
.card--snowy { --glass: rgba(255, 255, 255, .42); }
.card--stormy { --glass: rgba(6, 6, 14, .42); }
.row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.city {
margin: 0;
font-size: 13px;
font-weight: 600;
letter-spacing: .2em;
text-transform: uppercase;
opacity: .85;
}
.chip {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 5px 11px;
border-radius: 999px;
font-size: 11px;
letter-spacing: .12em;
text-transform: uppercase;
background: rgba(255, 255, 255, .16);
border: 1px solid rgba(255, 255, 255, .22);
white-space: nowrap;
}
.card--snowy .chip { background: rgba(255, 255, 255, .6); border-color: rgba(16, 48, 76, .18); }
.chip .dot {
width: 7px;
height: 7px;
border-radius: 50%;
background: var(--accent);
animation: dotPulse 2.2s ease-in-out infinite;
}
.card--snowy .chip .dot { background: #2f6f9e; }
@keyframes dotPulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, .0); opacity: .75; }
50% { box-shadow: 0 0 0 4px rgba(255, 255, 255, .18); opacity: 1; }
}
.temp {
margin: 10px 0 0;
font-size: 46px;
font-weight: 700;
line-height: 1;
letter-spacing: -1px;
text-shadow: 0 2px 14px rgba(0, 0, 0, .22);
}
.card--snowy .temp { text-shadow: 0 2px 14px rgba(255, 255, 255, .55); }
.temp .deg {
font-size: 21px;
font-weight: 600;
vertical-align: super;
margin-left: 2px;
opacity: .8;
}
.desc {
margin: 10px 0 16px;
font-size: 13.5px;
line-height: 1.5;
opacity: .82;
min-height: 40px;
}
.stats {
display: flex;
flex-wrap: wrap;
gap: 8px;
padding-top: 14px;
border-top: 1px solid rgba(255, 255, 255, .18);
font-size: 11.5px;
letter-spacing: .06em;
opacity: .85;
}
.card--snowy .stats { border-top-color: rgba(16, 48, 76, .16); }
.stats span {
padding: 5px 10px;
border-radius: 8px;
background: rgba(255, 255, 255, .14);
}
.card--snowy .stats span { background: rgba(255, 255, 255, .55); }
/* ---------- responsive ---------- */
@media (max-width: 1080px) {
.grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
body { padding: 30px 14px 54px; }
.grid { grid-template-columns: 1fr; gap: 20px; }
.card { min-height: 400px; }
header { margin-bottom: 26px; }
}
/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
.sun__rays, .sun__core, .sun__glow, .drift, .drop, .flake,
.bolt, .flash, .wind i, .chip .dot {
animation: none !important;
}
.drop { opacity: .85; }
.flake { opacity: .95; }
.bolt { opacity: 1; }
.flash { opacity: 0; }
/* freeze rain / snow into a readable static pattern */
.rain .drop:nth-child(1) { top: 14px; } .rain .drop:nth-child(2) { top: 56px; }
.rain .drop:nth-child(3) { top: 30px; } .rain .drop:nth-child(4) { top: 74px; }
.rain .drop:nth-child(5) { top: 8px; } .rain .drop:nth-child(6) { top: 48px; }
.rain .drop:nth-child(7) { top: 66px; } .rain .drop:nth-child(8) { top: 24px; }
.rain .drop:nth-child(9) { top: 84px; }
.snow .flake:nth-child(1) { top: 16px; } .snow .flake:nth-child(2) { top: 62px; }
.snow .flake:nth-child(3) { top: 36px; } .snow .flake:nth-child(4) { top: 84px; }
.snow .flake:nth-child(5) { top: 6px; } .snow .flake:nth-child(6) { top: 50px; }
.snow .flake:nth-child(7) { top: 26px; } .snow .flake:nth-child(8) { top: 72px; }
.snow .flake:nth-child(9) { top: 44px; } .snow .flake:nth-child(10) { top: 92px; }
}
</style>
</head>
<body>
<div class="wrap">
<header>
<h1>Four Skies</h1>
<p>Animated weather cards — built with nothing but HTML & CSS.</p>
<span class="tag">No JavaScript · No images · No SVG</span>
</header>
<div class="grid">
<!-- ============ SUNNY ============ -->
<article class="card card--sunny">
<div class="sky">
<div class="sun">
<div class="sun__glow"></div>
<div class="sun__rays"></div>
<div class="sun__core"></div>
</div>
</div>
<div class="info">
<div class="row">
<h2 class="city">Phoenix</h2>
<span class="chip"><i class="dot"></i>Clear</span>
</div>
<p class="temp">32<span class="deg">°C</span></p>
<p class="desc">Blazing sunshine, dry desert heat and a whisper of warm wind.</p>
<div class="stats"><span>Humidity 18%</span><span>Wind 9 km/h</span><span>UV 11</span></div>
</div>
</article>
<!-- ============ RAINY ============ -->
<article class="card card--rainy">
<div class="sky">
<div class="drift drift--1"></div>
<div class="drift drift--2"></div>
<div class="cloud cloud--rain"></div>
<div class="rain">
<span class="drop"></span><span class="drop"></span><span class="drop"></span>
<span class="drop"></span><span class="drop"></span><span class="drop"></span>
<span class="drop"></span><span class="drop"></span><span class="drop"></span>
</div>
<div class="puddle"></div>
</div>
<div class="info">
<div class="row">
<h2 class="city">Seattle</h2>
<span class="chip"><i class="dot"></i>Rain</span>
</div>
<p class="temp">13<span class="deg">°C</span></p>
<p class="desc">A soft grey drizzle under endless low clouds, puddles gathering.</p>
<div class="stats"><span>Humidity 88%</span><span>Wind 22 km/h</span><span>Rain 4mm</span></div>
</div>
</article>
<!-- ============ SNOWY ============ -->
<article class="card card--snowy">
<div class="sky">
<div class="drift drift--1"></div>
<div class="drift drift--2"></div>
<div class="cloud"></div>
<div class="snow">
<span class="flake"></span><span class="flake"></span><span class="flake"></span>
<span class="flake"></span><span class="flake"></span><span class="flake"></span>
<span class="flake"></span><span class="flake"></span><span class="flake"></span>
<span class="flake"></span>
</div>
</div>
<div class="info">
<div class="row">
<h2 class="city">Reykjavík</h2>
<span class="chip"><i class="dot"></i>Snow</span>
</div>
<p class="temp">−7<span class="deg">°C</span></p>
<p class="desc">Fresh powder drifting down over quiet, frosted streets.</p>
<div class="stats"><span>Humidity 71%</span><span>Wind 17 km/h</span><span>Snow 9cm</span></div>
</div>
</article>
<!-- ============ STORMY ============ -->
<article class="card card--stormy">
<div class="sky">
<div class="drift drift--1"></div>
<div class="drift drift--2"></div>
<div class="flash"></div>
<div class="bolt"></div>
<div class="wind"><i></i><i></i><i></i></div>
<div class="cloud cloud--storm"></div>
<div class="rain">
<span class="drop"></span><span class="drop"></span><span class="drop"></span>
<span class="drop"></span><span class="drop"></span><span class="drop"></span>
<span class="drop"></span><span class="drop"></span><span class="drop"></span>
</div>
</div>
<div class="info">
<div class="row">
<h2 class="city">Miami</h2>
<span class="chip"><i class="dot"></i>Storm</span>
</div>
<p class="temp">29<span class="deg">°C</span></p>
<p class="desc">Thunder crackles over a boiling sea, lashing rain and wild gusts.</p>
<div class="stats"><span>Humidity 84%</span><span>Wind 46 km/h</span><span>Rain 22mm</span></div>
</div>
</article>
</div>
</div>
</body>
</html>Reasoning trace (9,787 tokens)
Let me create a beautiful weather cards page with pure HTML/CSS.
Key requirements:
- No JS
- No images/SVG/icon fonts — CSS-only icons built from divs and pseudo-elements
- Animated: rotating sun rays, falling rain drops, drifting snowflakes, flashing lightning
- City name, temperature, description
- Own gradient background per card
- Responsive grid: 4 per row desktop, stacked mobile
- Hover lift
- Infinite @keyframes animations
- prefers-reduced-motion
Let me design.
Sun card: sun circle with rotating ray ring. Rays built from pseudo-elements ::before and ::after each with repeating-linear-gradient? Actually we can use conic-gradient for a ray ring, but rotating a conic gradient... The rays ring: use a div with `background: repeating-conic-gradient(...)` masked with radial-gradient to make spokes. Rotate that ring. Masking with radial-gradient is CSS-only and works in Chrome.
Simpler: `.sun-rays` is a circle with `background: repeating-conic-gradient(from 0deg, rgba(255,220,120,.9) 0 6deg, transparent 6deg 30deg)` and `mask: radial-gradient(circle, transparent 0 30%, #000 32% 50%, transparent 52%)`. Animate rotate 360deg over 20s.
Sun core: radial gradient circle with glow, pulsing.
Rain card: cloud shape from divs, rain drops as multiple elements with animation translateY. Use spans for drops with staggered delays. Drops: thin rounded rects with gradient blue, animated falling with opacity fade.
Cloud: build from divs: a big rounded rect base plus circles ::before/::after. Use pseudo elements.
Snow card: cloud + snowflakes as small circles with text? No text? We can use characters? "No images, no SVG, no icon fonts" — Unicode characters like ❄ might count as text, not an icon font. But safer: build snowflakes from CSS with a div that has ::before and ::after crossing bars — 6-arm snowflake via two crossed bars at 0/60/120 degrees needs 3 pseudo... We only have ::before and ::after per element. But a snowflake can be made from a container with 3 child spans each rotated 60deg, each span being a line (::before). Hmm.
Alternative: each snowflake is a span containing 3 child spans, each a line. Or simply use a 6-pointed shape: a div with border-radius 50% plus a rotated cross.
Simplest elegant: snowflake = span with `::before` and `::after` being two bars crossing at 60°, plus the span itself has a background radial gradient? Let's do: flake is 14px circle-ish; use `.flake` with background: radial-gradient(circle, #fff 0 2px, transparent 2px) center? Then add 3 arms via linear-gradients in background layer: `background: linear-gradient(60deg, transparent 46%, #fff 46% 54%, transparent 54%), linear-gradient(-60deg, ...), linear-gradient(0deg, ...)`. Three linear gradients crossing at 0/60/120 degrees give a 6-arm snowflake. That's clean! Combine with radial-gradient core. Good.
Rain drops: elongated rounded shapes.
Lightning: a zigzag polygon shape via clip-path (CSS-only, allowed since no SVG). clip-path polygon is fine — it's CSS. Use a div with clip-path: polygon(...) forming a bolt. Animate opacity flashing at irregular intervals plus sky flash overlay.
Also storm card could have rain + lightning. Stormy: dark gradient, cloud, lightning bolt flashing, maybe wind streaks.
Let's build the structure:
```html
<div class="grid">
<article class="card card--sunny">
<div class="sky">
<div class="sun">
<div class="sun__rays"></div>
<div class="sun__core"></div>
</div>
</div>
<div class="info">
<h2 class="city">Lisbon</h2>
<div class="temp">28°</div>
<p class="desc">Clear skies, warm breeze</p>
</div>
</article>
...
```
Card layout: icon at top, then info. Use flex column, space-between.
Backgrounds:
- Sunny: linear-gradient(160deg, #ffd86b, #fc9f3e) plus maybe sky blue? Sun card warm gradient: `linear-gradient(180deg,#ffdf8b,#ff9b54 60%,#ff7b3d)`.
- Rainy: `linear-gradient(180deg,#3f5d7d,#22364d)`.
- Snowy: `linear-gradient(180deg,#8fb7d6,#4a6b8a)` or lighter icy `linear-gradient(180deg,#cfe6f5,#7fa9c9)`.
- Stormy: `linear-gradient(180deg,#2b2f45,#14161f)`.
Text color: white with slight shadow.
Now details on cloud shape. Cloud made of a container div `.cloud` with:
- `.cloud__puff` base: width 100%, height 40%, border-radius 999px, background white, positioned bottom.
- circles: use `.cloud::before` and `::after` as two circles positioned. Plus the base as the element itself.
So `.cloud { width: 120px; height: 48px; border-radius: 999px; background: #fff; position: relative; }` with `::before` circle 60x60 at left top and `::after` circle 76x76 at right-ish top. Then the whole cloud is in a wrapper `.cloud-wrap` with the circles not clipped (overflow visible). Good.
For rainy card, cloud sits at top of sky area, drops fall below.
Rain drops: create 8 spans `.drop` inside `.rain`, each with `left` variable and `animation-delay` variable via inline style? Inline style attribute is allowed (not an event handler). Yes, style attributes are fine. But maybe better to use nth-child selectors in CSS to keep HTML clean. I'll use nth-child rules with distinct left/delay/duration — that keeps CSS bigger but fine. Or use inline style="--x:10%;--d:1.2s;--t:1.4s". I'll use nth-child for robustness and clean markup. Let's do a hybrid: nth-child in CSS.
Let me write CSS for drops:
```css
.rain { position:absolute; inset: 0; }
.drop {
position: absolute;
top: -10%;
width: 3px; height: 16px;
border-radius: 3px;
background: linear-gradient(180deg, rgba(255,255,255,0), #bfe4ff);
animation: fall var(--dur,1.1s) linear infinite;
animation-delay: var(--delay,0s);
opacity: 0;
}
@keyframes fall {
0% { transform: translate3d(0,-20%,0) scaleY(.7); opacity:0;}
10% {opacity:.9;}
80% {opacity:.9;}
100% { transform: translate3d(-8px, 220%, 0) scaleY(1.1); opacity: 0;}
}
```
Position top relative to rain area which starts below cloud. Set `.rain` top offset.
Snowflakes: similar with drift and rotate.
```css
.flake {
position:absolute; top:-12%;
width: var(--s, 12px); height: var(--s,12px);
background:
linear-gradient(0deg, transparent 45%, #fff 45% 55%, transparent 55%),
linear-gradient(60deg, transparent 45%, #fff 45% 55%, transparent 55%),
linear-gradient(-60deg, transparent 45%, #fff 45% 55%, transparent 55%);
animation: snowfall ...
}
```
Hmm the linear-gradient at 60deg with #fff 45%-55% band gives a bar across the element at 60°. Combined with 0deg and -60deg gives 6 arms. Good. Add radial-gradient for center dot? Add first layer radial-gradient(circle, #fff 0 18%, transparent 19%).
Animation: fall with horizontal sway: translateX with sine easing.
@keyframes snowfall { 0% { transform: translate(0,-10%) rotate(0) } 50% { transform: translate(12px, 45%) rotate(180deg)} 100% { transform: translate(-10px, 100%) rotate(360deg) } }
Lightning: bolt via clip-path polygon. Shape like:
polygon(58% 0%, 20% 55%, 45% 55%, 35% 100%, 80% 40%, 52% 40%) — a classic bolt. Plus glow filter drop-shadow. Animate with a flash keyframe: opacity 0 most of the time with quick flashes at certain percentages.
```css
@keyframes flash {
0%, 8%, 12%, 40%, 44%, 100% { opacity: 0; }
9%, 11% { opacity: 1; }
41%, 43% { opacity: .9; }
}
```
Also sky flash overlay: white overlay div with same animation.
Stormy card: dark cloud, bolt, plus slanted rain streaks maybe. And a wind swish.
Also add drifting clouds in background? Keep it moderate.
Sun card additional: maybe some warm haze, sun rising/pulsing, rays rotating.
Let's also add subtle "shine" rotating conic gradient overlay on sunny card.
Card hover lift: `transform: translateY(-10px) scale(1.02); box-shadow: bigger`. Note card has its own animation? Don't animate transform on card itself to avoid conflict; use transition.
Grid: `display:grid; grid-template-columns: repeat(4, 1fr); gap: 24px;` media queries: at 1100px → repeat(2,1fr); at 700px → 1fr. Container max-width 1240px, padding.
prefers-reduced-motion: disable all animations (`animation: none !important;`) and show static icon states — ensure static states look good (sun rays visible static, drops visible mid-air maybe). With animation:none, drops would be at top:-10% opacity 0 — invisible. Better: in reduced motion, set drops opacity .7 and position them distributed statically. Let's define reduced-motion styles: `.drop { animation: none; opacity:.75; top: 20%; }` with different top per nth-child so they're visible along. Similarly flakes.
Let's write the reduced motion block:
```css
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; transition: none !important; }
.drop { opacity: .8; top: 30%; }
.flake { opacity: .9; top: 25%; }
.bolt, .flash { opacity: 1; }
}
```
But also drop top overrides per nth-child need distinct values — I'll add in reduced motion block nth-child rules for top variations.
Also the lightning should be visible in reduced motion: set opacity 1.
Now write the HTML with four cards: cities — e.g., "Seville" 31° sunny, "Seattle" 14° rainy, "Reykjavík" -6° snowy, "Oslo"? Stormy: "Miami" hurricane 27°. Let's pick: Sunny: Phoenix, 32°, "Blazing sun and clear skies". Rainy: Seattle 13° "Steady drizzle with low clouds". Snowy: Reykjavík -7° "Fresh powder falling quietly". Stormy: Miami 29° "Thunderstorms and heavy gusts".
Text: use °C sign. Fine.
Maybe also add a small "condition chip" label. Keep clean.
Let me carefully build the sun icon:
```html
<div class="sky sky--sun">
<div class="sun">
<div class="sun__rays"></div>
<div class="sun__glow"></div>
<div class="sun__core"></div>
</div>
<div class="haze"></div>
</div>
```
sun__rays: absolute circle of 200% size centered, background repeating-conic-gradient, mask radial to ring, animation spin 24s linear infinite.
```css
.sun__rays{
position:absolute; top:50%; left:50%;
width: 190px; height:190px;
margin:-95px 0 0 -95px;
border-radius:50%;
background: repeating-conic-gradient(from 0deg, rgba(255,241,180,.95) 0deg 5deg, rgba(255,241,180,0) 5deg 30deg);
-webkit-mask: radial-gradient(circle, transparent 0 40%, #000 42% 50%, transparent 51%);
mask: radial-gradient(circle, transparent 0 40%, #000 42% 50%, transparent 51%);
animation: spin 26s linear infinite;
}
```
Wait the mask ring: transparent 0 40% means inner hole, opaque 42%-50%, transparent beyond 51%. The rays only show in a thin ring at radius 42-50% — that's a thin ring where spokes show. Good.
sun__core: 86px circle radial-gradient(#fff8d6 → #ffd24d → #ff9f2e), box-shadow glow, animation pulse 3s ease-in-out infinite (scale 1 → 1.06).
Also sun__glow: larger blurred circle behind with pulsing opacity.
Let's also give sun rays a slight "shimmer" — keep simple.
Rainy card sky: light blue-grey gradient; add background of moving clouds? Let's add a couple of `.drift-cloud` divs in the sky for rain and storm, drifting horizontally with `translateX` loop.
Cloud shape:
```css
.cloud{ position:relative; width:130px; height:44px; border-radius:999px; background: linear-gradient(180deg,#fdfdff,#cfd9e6); box-shadow: 0 8px 18px rgba(0,0,0,.18);}
.cloud::before,.cloud::after{content:""; position:absolute; border-radius:50%; background:inherit;}
.cloud::before{ width:62px;height:62px; left:14px; top:-28px; background: linear-gradient(180deg,#fdfdff,#dbe4ef);}
.cloud::after{ width:80px;height:80px; right:14px; top:-38px; background: linear-gradient(180deg,#fdfdff,#d3dde9);}
```
Cloud colors: for storm card darker cloud: `.cloud--dark` with grey gradient.
Rain area positioned under the cloud.
Card layout: sky area has fixed height (e.g., 190px) with icon centered. For rain/snow, cloud at top ~28px, rain/snow fills the rest.
Structure for rain:
```html
<div class="sky sky--rain">
<div class="clouds"> <div class="drift drift--1"></div> <div class="drift drift--2"></div> </div>
<div class="cloud cloud--rain"></div>
<div class="rain">
<span class="drop"></span> x8
</div>
</div>
```
Positions: cloud absolute top 24px left 50% translateX(-50%). Rain container absolute inset top 90px (below cloud) height 100px.
Hmm, easier: `.rain { position:absolute; left:0; right:0; top:88px; bottom:10px; }` and drops positioned with `left: X%` and animate translateY from -20% to 110%.
Drop animation uses `top:0` start and translateY.
Let me define drop top: 0; animation: fall with translate from translateY(-20px) to translateY(120px) where 120px ~ container height. Use percentages of container? transform percentages refer to element size, not container. Use px: container height ~110px. Let's use `translateY(-24px)` → `translateY(130px)`. Fine with fixed sizes. But responsive scaling changes card size; sky height fixed at 190px so ok.
Snow container similar.
Storm card: dark sky with flash overlay, dark cloud, bolt under cloud, plus wind streaks (thin diagonal lines moving), maybe rain too.
Bolt:
```css
.bolt{
position:absolute; left:50%; top:96px; width:34px; height:70px;
margin-left:-17px;
background: linear-gradient(180deg,#fff7c4,#ffc531);
clip-path: polygon(55% 0%, 18% 52%, 44% 52%, 30% 100%, 82% 42%, 52% 42%);
filter: drop-shadow(0 0 8px rgba(255,214,64,.85));
animation: flash 6s linear infinite;
}
```
Also add a `.bolt-glow` behind.
Flash overlay:
```css
.flash{ position:absolute; inset:0; background: radial-gradient(circle at 50% 40%, rgba(255,255,255,.55), rgba(255,255,255,0) 60%); opacity:0; animation: flash 6s linear infinite; pointer-events:none;}
```
But flash over the whole card would wash out the text too if inside sky only — put inside sky, fine.
@keyframes flash:
0%, 4% {opacity:0}
5% {opacity:.85}
6% {opacity:.1}
7% {opacity:.9}
8%, 45% {opacity:0}
46%{opacity:.7}
47%{opacity:0}
100%{opacity:0}
Add wind streaks for storm: `.wind i` diagonal lines animating translateX.
Also storm card rain: reuse drops with darker colors maybe.
Now the info section: city name uppercase letterspaced small, temp large (44px), description.
Maybe add a chip showing condition e.g. "SUNNY" with a dot. Let's do: `.meta` row with a pill.
Layout of card: display flex column; sky flex:1; info padded.
Hover: `.card:hover { transform: translateY(-12px); }` plus `.card:hover .sun__core { transform: scale(1.1) }`? Careful with existing animation on core (pulse). Use a wrapper for hover scale? Simpler: keep hover to card only plus shadow and maybe brighten icon slightly via filter on sky. Use `.card:hover .sky { filter: saturate(1.15) brightness(1.06); }` — filter on parent is fine.
Also `box-shadow` transition.
Page background: dark neutral with subtle radial gradients; heading "Weather Cards" and subtitle. White text. Card text white.
Let's write it.
Also add "lift up on hover" with cursor pointer.
Reduced motion: also the card hover transform transitions disabled (transition none) — fine, but then hover lift doesn't happen; that's acceptable-ish but requirement says respect reduced motion. Keep hover transform but remove transition? Reduced motion mainly about motion; a hover lift without animation is fine but transition:none makes it instant. I'll keep transition but reduce? I'll just disable animations and keep transitions short. Actually simpler: in reduced motion, disable animations; keep hover transition (it's user-triggered, small). I'll keep transition but the `* { animation:none !important }` rule. Don't kill transitions globally—I'll leave transitions.
Let me write nth-child rules for drops (8 drops) and flakes (10 flakes).
Drops positions left: 8%, 18%, 27%, 38%, 47%, 58%, 68%, 80% with delays 0, .35, .7, 1.05, .25, .6, .95, 1.3 and durations alternating 1.0s/1.2s.
Flakes: 10 with lefts spread 6%..92%, sizes 8-14px, delays.
Now let me also ensure "no horizontal scrollbar" — use overflow-x hidden on body maybe, and everything fits.
Font: system fonts stack.
Write final code.
Detailed CSS:
```css
:root{
--radius: 22px;
}
*{box-sizing:border-box;}
body{
margin:0;
min-height:100vh;
background: #0b1220 radial-gradient(1200px 600px at 20% -10%, #1c2942, transparent),
radial-gradient(900px 500px at 100% 0%, #26203a, transparent),
linear-gradient(180deg,#0b1220,#070b14);
color:#eaf1fb;
font-family: "Segoe UI", Roboto, -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif;
display:flex; justify-content:center; padding: 40px 20px 64px;
}
.wrap{width:100%; max-width:1240px;}
header{ text-align:center; margin-bottom: 34px;}
h1{font-size: clamp(26px, 4vw, 40px); margin:0 0 8px; letter-spacing:.5px;}
.sub{color:#9fb0c9; margin:0; font-size:15px;}
.grid{display:grid; gap:26px; grid-template-columns: repeat(4, minmax(0,1fr));}
```
Card:
```css
.card{
position:relative; display:flex; flex-direction:column; min-height:400px;
border-radius:var(--radius); overflow:hidden; isolation:isolate;
box-shadow: 0 18px 30px -18px rgba(0,0,0,.75), 0 2px 0 rgba(255,255,255,.06) inset;
transition: transform .35s cubic-bezier(.2,.8,.2,1), box-shadow .35s;
transform: translateZ(0);
}
.card:hover{ transform: translateY(-12px); box-shadow: 0 30px 45px -20px rgba(0,0,0,.85);}
```
Add a gloss sheen on hover: `.card::after` with a gradient sweeping? Could be nice: a diagonal shine that moves on hover using transform transition. Let's add `.card::before` as top gloss.
Card gradients:
- .card--sunny { background: linear-gradient(170deg, #ffd977 0%, #ffb04d 45%, #f5822f 100%); }
- .card--rainy { background: linear-gradient(170deg, #6f93b5 0%, #43637f 45%, #2c4459 100%); }
- .card--snowy { background: linear-gradient(170deg, #cfe8fb 0%, #9dc3e0 45%, #6d94b8 100%); }
- .card--stormy { background: linear-gradient(170deg, #4a4e6b 0%, #2a2c44 45%, #16172a 100%); }
For snowy card text should be dark-ish navy for contrast on light background: `.card--snowy .info{ color:#12314a;}` and text-shadow none. Let's set that.
Text on sunny: dark brown? White on orange is okay-ish; better use deep amber text? Use white with strong shadow; fine. Actually for readability, sunny card could have dark text (#5a3208)? Let's use white text with shadow for sunny/rainy/stormy and navy for snowy.
Hmm, for sunny, white text on orange gradient is readable enough. Keep white.
Sky area:
```css
.sky{ position:relative; flex: 1 1 auto; min-height: 210px; overflow:hidden; }
```
Overflow hidden on sky so rain doesn't spill.
But the card overflow hidden already handles. Keep sky overflow hidden to clip drifting clouds.
Sun position: center of sky.
Let me now write the drift clouds for rainy background: `.drift` = elongated blurred white blobs, low opacity, animate translateX from -30% to 130%.
Let's write the code fully.
For the sunny sky, add a subtle sunbeam sweep: `.sunbeams` with conic gradient rotating slowly and low opacity, masked. Could add but maybe overload. Add a soft radial glow behind sun instead.
I also want each card to look "polished": add a top-right small chip with condition label (e.g., "CLEAR"), and a bottom meta row with "Humidity 32%" etc. Let's add meta row: two small stats. Nice detail.
Info section:
```html
<div class="info">
<div class="row">
<h2 class="city">Phoenix</h2>
<span class="chip">Clear</span>
</div>
<div class="temp">32<span class="deg">°C</span></div>
<p class="desc">Blazing sun, dry heat and a light desert breeze.</p>
<div class="stats">
<span>Humidity 18%</span><span>Wind 8 km/h</span>
</div>
</div>
```
Now write full CSS for icons.
Sun:
```css
.sun{ position:absolute; left:50%; top:52%; width:150px; height:150px; transform:translate(-50%,-50%); }
.sun__glow{ position:absolute; inset:-30%; border-radius:50%; background: radial-gradient(circle, rgba(255,238,170,.55), rgba(255,238,170,0) 65%); animation: breathe 4.5s ease-in-out infinite;}
.sun__rays{ position:absolute; inset:-12%; border-radius:50%; background: repeating-conic-gradient(from 0deg, rgba(255,247,214,.95) 0deg 4deg, rgba(255,247,214,0) 4deg 30deg); -webkit-mask: radial-gradient(circle, transparent 0 36%, #000 38% 50%, transparent 51%); mask: radial-gradient(circle, transparent 0 36%, #000 38% 50%, transparent 51%); animation: spin 24s linear infinite;}
.sun__core{ position:absolute; inset:22%; border-radius:50%; background: radial-gradient(circle at 35% 30%, #fffdf0 0 22%, #ffe07a 45%, #ffb52e 78%, #ff9320 100%); box-shadow: 0 0 40px rgba(255,205,80,.75), 0 0 80px rgba(255,170,50,.45); animation: pulse 3.6s ease-in-out infinite;}
```
inset:22% of 150 = 33px each side → core 84px. Good. Rays inset -12% → 168px, ring at 38-50% of 168 = 64-84px radius from center; core radius 42px. Good gap.
@keyframes spin { to { transform: rotate(360deg);} }
@keyframes pulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.07)} }
@keyframes breathe { 0%,100%{opacity:.75; transform:scale(1)} 50%{opacity:1; transform:scale(1.08)} }
Ray ring rotation visible — with 12 spokes rotating slowly; the spokes at 30deg intervals symmetric → rotation might look static if exactly symmetric! With 30deg period, rotating by 30deg looks identical. Since animation goes continuously, motion still perceptible but pattern symmetry makes it look like it's not rotating. Better use irregular spoke pattern: repeating-conic-gradient with varying widths, e.g. 0 6deg, gap 6-16deg (10deg), then 16-20, gap 20-30. Let's define a non-uniform repeating pattern — but repeating-conic-gradient repeats identically. Use a manual multi-stop conic-gradient with distinct spoke angles to break symmetry:
background: conic-gradient(from 0deg,
rgba(255,247,214,.95) 0deg 5deg, transparent 5deg 27deg,
rgba(255,247,214,.95) 27deg 31deg, transparent 31deg 58deg,
rgba(255,247,214,.95) 58deg 64deg, transparent 64deg 91deg,
rgba(255,247,214,.95) 91deg 95deg, transparent 95deg 126deg,
rgba(255,247,214,.95) 126deg 132deg, transparent 132deg 160deg,
rgba(255,247,214,.95) 160deg 164deg, transparent 164deg 196deg,
rgba(255,247,214,.95) 196deg 202deg, transparent 202deg 231deg,
rgba(255,247,214,.95) 231deg 235deg, transparent 235deg 268deg,
rgba(255,247,214,.95) 268deg 274deg, transparent 274deg 300deg,
rgba(255,247,214,.95) 300deg 306deg, transparent 306deg 330deg,
rgba(255,247,214,.95) 330deg 334deg, transparent 334deg 360deg);
That's 10 spokes with unequal gaps → rotation clearly visible. Good.
Rain drops: also add splash at bottom? skip.
Now the drift clouds for rainy background: two blurred ellipses.
Let me write rain:
```css
.rain{ position:absolute; left:6%; right:6%; top:96px; bottom:6px; }
.drop{ position:absolute; top:0; left:var(--x); width:3px; height:18px; border-radius:4px; background: linear-gradient(180deg, rgba(210,236,255,0), rgba(210,236,255,.95)); box-shadow: 0 0 6px rgba(190,225,255,.6); animation: fall var(--dur) linear infinite; animation-delay: var(--d); opacity:0;}
```
Using CSS vars set via nth-child rules:
.rain .drop:nth-child(1){--x:4%; --d:0s; --dur:.95s}
... etc.
fall keyframes:
```css
@keyframes fall{
0%{ transform: translate3d(0,-24px,0) scaleY(.6); opacity:0;}
12%{ opacity:.95;}
75%{ opacity:.95;}
100%{ transform: translate3d(-10px,150px,0) scaleY(1.15); opacity:0;}
}
```
Container height = 210-96-6 ≈ 108px; translate 150px will overflow bottom — but sky has overflow hidden, and rain container is within sky, so it clips at sky bottom. Good, though drops vanish before reaching bottom edge... Actually sky is 210px min-height, container bottom 6px → 108px tall; drops move to 150px → they exit the rain container but still rendered (no overflow hidden on .rain) and get clipped by sky at 210px. At 150px they'd be at y=246 > 210 → clipped. Slight early clip is fine but better to have them fade before clipping: opacity goes to 0 at 100%. They fade from 75% to 100% (i.e., at 126px → still within card at y=222... hmm clip). Let's set fall end translateY(120px) so they fade out at y=216 ≈ near bottom of sky. Since sky overflow hidden, they'd be clipped at 210. Let's use end 110px → y=206, inside sky. Good. Use 0→110px.
Actually the info section is below sky in the card, and sky min-height 210px but flex:1 makes it grow. Card min-height 400 → sky maybe 210. Fine.
Snow:
```css
.snow{ position:absolute; left:0; right:0; top:100px; bottom:0;}
.flake{ position:absolute; top:0; left:var(--x); width:var(--s); height:var(--s); background: radial-gradient(circle, #fff 0 22%, transparent 24%), linear-gradient(0deg, transparent 44%, #fff 44% 56%, transparent 56%), linear-gradient(60deg, transparent 44%, #fff 44% 56%, transparent 56%), linear-gradient(-60deg, transparent 44%, #fff 44% 56%, transparent 56%); animation: snowfall var(--dur) linear infinite; animation-delay: var(--d); opacity:.95;}
```
Wait linear-gradient(60deg, transparent 44%, #fff 44% 56%, transparent 56%) creates a band at 60deg across the whole element — with the element square, the band goes corner to corner at 60°? The gradient axis at 60deg; the band positions 44%-56% of the gradient line length. The gradient line length for a square at 60deg is |w sin60| + |h cos60| = 0.866w+0.5w=1.366w. The band at center will be a stripe of width 12% * 1.366w measured perpendicular-ish. The stripe passes through the center? The gradient line passes through center, so yes the 44-56% band straddles the center line, giving a bar through the center at 60° to horizontal (since gradient direction 60deg means color changes along 60deg direction, so stripes are perpendicular to that → bar oriented at 60-90 = -30°... hmm.
For linear-gradient(angle), the gradient line points in direction of angle (0deg = to top, 90deg = to right). Color bands are perpendicular to the gradient line. So a band means a stripe whose long axis is perpendicular to the gradient line. For angle 0deg (to top), bands are horizontal stripes → bar is horizontal. For 90deg, vertical stripes → vertical bar. For 60deg, stripe orientation perpendicular to 60deg line = 150deg i.e., a bar tilted. Hmm we want bars at 0°, 60°, 120°. Bars at 0° (horizontal) come from gradient 0deg. Bars at 60°: perpendicular to gradient line direction 60° → gradient angle = 60-90 = -30deg (or 150deg). Bars at 120°: gradient angle = 120-90 = 30deg.
So use linear-gradient(0deg,...), linear-gradient(-30deg,...), linear-gradient(30deg,...). Then bars are at 0°, 60°, 120° → 6 arms.
Let me verify: gradient angle -30deg means gradient line points at -30° from vertical toward... CSS angle measured clockwise from "to top". -30deg points up-left-ish (330deg). Bands perpendicular to that → bar orientation at -30+90 = 60°. Yes correct. And 30deg → bar at 120°.
So:
```css
background:
radial-gradient(circle, #fff 0 20%, transparent 22%),
linear-gradient(0deg, transparent 44%, #fff 44% 56%, transparent 56%),
linear-gradient(-30deg, transparent 44%, #fff 44% 56%, transparent 56%),
linear-gradient(30deg, transparent 44%, #fff 44% 56%, transparent 56%);
```
The stripe width: at angle 0, gradient line length = h; band 12% of h → 12% of size. For a 12px flake, band ~1.4px. Good.
Snowfall keyframes:
```css
@keyframes snowfall{
0%{ transform: translate3d(0,-20px,0) rotate(0deg); opacity:0;}
10%{opacity:.95;}
50%{ transform: translate3d(14px,52px,0) rotate(180deg);}
90%{opacity:.9;}
100%{ transform: translate3d(-12px,124px,0) rotate(360deg); opacity:0;}
}
```
Hmm the 50% position jump with different easing could be jerky but linear is ok. Use ease-in-out? linear is fine, but let me use "linear" with an added sway using two animations? One animation with translate at 0/50/100 with linear timing: 0 → (14,52) → (-12,124). That's fine, drift appears.
Storm:
```html
<div class="sky sky--storm">
<div class="flash"></div>
<div class="clouds"><div class="drift drift--1"></div><div class="drift drift--2"></div></div>
<div class="cloud cloud--storm"></div>
<div class="bolt"></div>
<div class="storm-rain">drops</div>
<div class="wind"><i></i><i></i></div>
</div>
```
Maybe storm gets rain drops too (lighter) plus bolt. Good.
Bolt position: below cloud, centered-ish. Cloud at top 26px, height ~44+ → bottom ~ 100px. Bolt top 92px height 64 → overlaps cloud slightly, fine (lightning behind cloud looks better: bolt z-index below cloud). Put bolt before cloud in DOM so cloud overlaps.
Wind streaks: two thin white diagonal lines moving right, low opacity:
```css
.wind i{ position:absolute; height:2px; width:60px; border-radius:2px; background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent); transform: rotate(-12deg); animation: gust 4s linear infinite;}
```
OK. Also cloudy background in rainy card: `.drift` blurred ellipses moving.
Also add rain card: a light-blue "puddle"/splash? skip.
Now write info styles.
```css
.info{ padding: 20px 22px 22px; background: linear-gradient(180deg, rgba(0,0,0,.12), rgba(0,0,0,.28)); }
```
Better: give info a translucent dark panel for legibility: background: rgba(6,12,22,.28) with backdrop-filter blur(4px). backdrop-filter works in Chrome. Use it.
For snowy card: info background rgba(255,255,255,.35), text dark.
City: font-size 15px, letter-spacing .16em, uppercase, opacity .85.
Temp: 42px bold, line-height 1.
deg: 20px, vertical align top.
desc: 13.5px, opacity .8, margin 8px 0 14px, min-height for alignment.
stats: flex gap, small pills.
Chip: small pill with dot: `<span class="chip"><i class="dot"></i>Clear</span>`. Dot color varies per card via CSS var.
Use CSS custom property --accent per card for chip dot and temp color maybe.
Card accents: sunny #ffd166, rainy #7fd4ff, snowy #eaf6ff, stormy #ffcf5c.
Now responsive:
@media (max-width: 1080px) { .grid{grid-template-columns: repeat(2, minmax(0,1fr));} }
@media (max-width: 620px) { .grid{grid-template-columns: 1fr;} body{padding:28px 14px 48px;} }
Font sizes fine.
Now reduced motion block:
```css
@media (prefers-reduced-motion: reduce){
.sun__rays, .sun__core, .sun__glow, .drop, .flake, .bolt, .flash, .drift, .wind i, .chip-dot { animation: none !important; }
.drop{ opacity:.85; }
.flake{ opacity:.95; }
.bolt{ opacity:1; }
.flash{ opacity:0; }
}
```
But drops with animation:none sit at top:0 with opacity .85 — all at same top row, overlapping cloud region. Add per-child static top offsets in reduced motion:
```css
@media (prefers-reduced-motion: reduce){
.drop:nth-child(1){top:10px} .drop:nth-child(2){top:48px} ...
.flake:nth-child(1){top:14px} ...
}
```
That gives a static distribution. Good. And the transform on drops would be none so they stay vertical. Fine.
Also `.card:hover` transform still works — with transition it still animates; reduced motion users may prefer none. I'll keep transition but that's user-initiated small movement. Acceptable. Maybe add `.card{transition-duration:.01ms}`? The instruction: respect prefers-reduced-motion. I'll disable the infinite animations; keep hover transition as it's direct manipulation (allowed per guidelines). Actually many implementations disable it too. I'll keep hover but make it instant-ish? I'll keep transition; it's fine.
Let me write the HTML now, with the four cards.
Card 1: Phoenix, 32°C, "Clear", "Blazing sunshine with dry desert air.", stats: Humidity 18% / Wind 9 km/h.
Card 2: Seattle, 13°C, "Rain", "Cool drizzle and endless grey clouds.", Humidity 88% / Wind 22 km/h.
Card 3: Reykjavík, -7°C, "Snow", "Fresh powder drifting over quiet streets.", Humidity 71% / Wind 17 km/h.
Card 4: Miami, 29°C, "Storm", "Thunder crackles over a boiling sea.", Humidity 84% / Wind 46 km/h.
For snowy card temp -7° — use "−7" (minus sign U+2212) fine.
Now write out everything carefully.
One more: "Each card shows an animated icon" — done.
Also for the rainy card, maybe add a cloud with drips and a puddle shimmer at bottom. Add `.puddle` ellipse at bottom with subtle animation (scale/opacity). Nice.
Let me also double check the `.sky` min-height and card layout: `.card { display:flex; flex-direction:column; }` `.sky { flex: 1 1 auto; min-height: 220px; }` `.info { flex: 0 0 auto; }` Card min-height 420px.
Let me write the final code.
Also add a subtle glass reflection overlay on the whole card: `.card::after { content:""; position:absolute; inset:0; background: linear-gradient(115deg, rgba(255,255,255,.16), transparent 40%); pointer-events:none; }` — but this would sit above info; z-index fine. Add z-index: 2 for ::after and content z-index 3? ::after overlays text slightly but low opacity; fine. Actually careful with hover transform; fine.
Let me finalize CSS for chip dot animation: a pulsing dot (box-shadow pulse).
Write the code.
For the drifting background clouds in rainy/storm cards, `.drift` uses blurred white ellipse:
```css
.drift{ position:absolute; height:60px; width:160px; border-radius:50%; background: rgba(255,255,255,.18); filter: blur(18px); animation: drift 26s linear infinite; }
.drift--1{ top:20px; left:-30%; }
.drift--2{ top:70px; left:-40%; animation-duration:38s; animation-delay:-12s; }
@keyframes drift{ from{transform:translateX(0)} to{transform:translateX(520px)} }
```
Hmm, from left:-30% width 160 → translateX 520px moves it across. Good enough.
For storm card use darker drift color: `.card--stormy .drift{ background: rgba(255,255,255,.10); }` and maybe lightning-tinted.
Also add rain in storm: `.storm-rain` with drops darker color and steeper. Reuse .drop class inside .storm-rain, position container.
Storm card: cloud--storm dark grey with purple tint.
Let me write the final HTML/CSS. I'll be thorough but keep it manageable.
CSS variables per card:
```css
.card--sunny{ --accent:#ffd166; --glass: rgba(30,12,0,.22); }
```
Info background uses var(--glass)? For snowy, --glass: rgba(255,255,255,.32) and text color navy.
Set `.card--snowy .city, .card--snowy .temp, ... { color:#10314b; }` — easier: `.card--snowy .info{ color:#12304a; }` and children inherit, with opacity adjustments. Yes use currentColor + opacity.
Let me write it.
Final check on `mask` support: Chrome supports `mask` unprefixed now (Chrome 120+). Use both -webkit-mask and mask.
Let's write.