Qwen3.8 Flash
by QwenReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 4 min 59 s
- Cost
- $0.011
- Output tokens
- 22,524
- Spent thinking
- 17,455 tokens
- Speed
- 75.6 tok/s
- Console errors
- 0
- First token after
- 809 ms
- First visible text after
- 4 min 16 s
- Prompt tokens
- 561
- Code size
- 11.7 KB
- Finish reason
- stop
- Served by
- Alibaba
- Model id
qwen/qwen3.8-flash- Reasoning sent
model default- 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 · 527 lines
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Animated Weather Cards — HTML & CSS Only</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
padding: 32px 20px;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
"Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: radial-gradient(circle at 50% 0, #334a66, #07101b 58%, #02060c);
color: #e8f2ff;
display: flex;
justify-content: center;
}
.page {
width: min(1280px, 100%);
}
.intro {
text-align: center;
margin-bottom: 30px;
}
.intro h1 {
margin: 0 0 10px;
font-size: clamp(1.7rem, 4vw, 3rem);
letter-spacing: 0.02em;
text-shadow: 0 10px 24px rgba(0, 0, 0, 0.28);
}
.intro p {
margin: 0;
opacity: 0.82;
font-size: 0.98rem;
}
.weather-grid {
display: grid;
gap: 24px;
width: 100%;
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.weather-card {
position: relative;
min-height: 300px;
border-radius: 30px;
padding: 24px 18px 22px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
text-align: center;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.28);
box-shadow: 0 16px 32px rgba(0, 0, 0, 0.28);
transition:
transform 0.35s cubic-bezier(0.2, 0.7, 0.2, 1),
box-shadow 0.35s cubic-bezier(0.2, 0.7, 0.2, 1);
}
.weather-card:hover {
transform: translateY(-12px) scale(1.025);
box-shadow: 0 30px 52px rgba(0, 0, 0, 0.38);
}
.sunny {
background: linear-gradient(160deg, #fff7cf 0%, #ffd85e 45%, #ff9a2e 100%);
color: #5f3600;
}
.rainy {
background: linear-gradient(160deg, #d7efff 0%, #7ab5e8 45%, #254c7a 100%);
color: #ffffff;
}
.snowy {
background: linear-gradient(160deg, #fbfdff 0%, #d5ebff 45%, #93bfff 100%);
color: #16375c;
}
.stormy {
background: linear-gradient(160deg, #7b8b96 0%, #37474f 45%, #0d1418 100%);
color: #ffffff;
}
.city-name {
margin: 12px 0 0;
font-size: 1.12rem;
font-weight: 700;
letter-spacing: 0.02em;
}
.temperature {
margin: 0;
font-size: 2.75rem;
font-weight: 900;
line-height: 1;
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
}
.sunny .temperature,
.snowy .temperature {
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.36);
}
.description {
margin: 2px 0 0;
font-size: 0.95rem;
opacity: 0.92;
line-height: 1.35;
max-width: 210px;
}
.icon {
position: relative;
width: 118px;
height: 118px;
margin-bottom: 6px;
flex: 0 0 auto;
}
.sun-core,
.sun-rays,
.ray,
.cloud,
.drop,
.flake,
.bolt {
position: absolute;
}
/* SUN */
.sun-core {
inset: 50%;
width: 56px;
height: 56px;
margin: -28px;
border-radius: 50%;
background: radial-gradient(circle at 32% 30%, #fffbe3 0%, #ffd34d 45%, #ff9d1c 100%);
box-shadow:
0 0 28px rgba(255, 187, 20, 0.95),
inset 0 -6px 14px rgba(190, 100, 0, 0.18);
animation: pulse 3s ease-in-out infinite;
}
.sun-rays {
inset: 0;
transform-origin: 50% 50%;
animation: spin 22s linear infinite;
}
.ray {
left: 50%;
top: 50%;
width: 90px;
height: 8px;
margin: -4px -45px;
border-radius: 999px;
background: linear-gradient(
90deg,
rgba(255, 200, 30, 0),
#ffd23f 16%,
#ffb703 50%,
#ffd23f 84%,
rgba(255, 200, 30, 0)
);
box-shadow: 0 0 12px rgba(255, 173, 21, 0.62);
transform-origin: 50% 50%;
}
.ray:nth-child(1) { transform: rotate(0deg); }
.ray:nth-child(2) { transform: rotate(45deg); }
.ray:nth-child(3) { transform: rotate(90deg); }
.ray:nth-child(4) { transform: rotate(135deg); }
/* SHARED CLOUD */
.cloud {
z-index: 2;
left: 50%;
top: 18px;
width: 74px;
height: 32px;
margin-left: -37px;
border-radius: 999px;
background: linear-gradient(180deg, #ffffff, #dbeafe);
box-shadow: 0 10px 18px rgba(0, 0, 0, 0.15);
}
.cloud::before,
.cloud::after {
content: "";
position: absolute;
border-radius: 50%;
background: #ffffff;
}
.cloud::before {
width: 42px;
height: 42px;
left: -17px;
top: -21px;
}
.cloud::after {
width: 34px;
height: 34px;
right: -14px;
top: -15px;
}
/* RAIN */
.rain-icon .cloud {
top: 20px;
background: linear-gradient(180deg, #ffffff, #d8eaff);
}
.drop {
z-index: 1;
width: 6px;
height: 17px;
border-radius: 0 7px 7px 7px;
background: linear-gradient(180deg, #ffffff, #66bfff);
transform: rotate(20deg);
opacity: 0;
filter: drop-shadow(0 2px 3px rgba(25, 80, 130, 0.3));
animation: rain-fall 1.55s linear infinite;
}
.drop.d1 { left: 24px; top: 54px; animation-delay: 0s; }
.drop.d2 { left: 50px; top: 48px; animation-delay: 0.22s; }
.drop.d3 { left: 78px; top: 55px; animation-delay: 0.48s; }
.drop.d4 { left: 42px; top: 60px; animation-delay: 0.72s; }
.drop.d5 { left: 68px; top: 62px; animation-delay: 0.98s; }
/* SNOW */
.snow-icon .cloud {
top: 17px;
width: 72px;
height: 30px;
margin-left: -36px;
background: linear-gradient(180deg, #ffffff, #e7f1ff);
}
.flake {
z-index: 1;
width: 18px;
height: 18px;
opacity: 0;
animation: snow-fall 4.6s ease-in-out infinite;
}
.flake::before,
.flake::after,
.flake i {
position: absolute;
left: 50%;
top: 50%;
width: 100%;
height: 2px;
border-radius: 999px;
background: #ffffff;
box-shadow: 0 0 8px rgba(255, 255, 255, 0.75);
transform: translate(-50%, -50%);
}
.flake::before,
.flake::after {
content: "";
}
.flake::after {
transform: translate(-50%, -50%) rotate(60deg);
}
.flake i {
transform: translate(-50%, -50%) rotate(120deg);
}
.flake.f1 { left: 18px; top: 52px; animation-duration: 4.2s; animation-delay: 0s; }
.flake.f2 { left: 46px; top: 48px; width: 14px; height: 14px; animation-duration: 5.1s; animation-delay: 0.35s; }
.flake.f3 { left: 74px; top: 53px; animation-duration: 4.6s; animation-delay: 0.7s; }
.flake.f4 { left: 34px; top: 60px; width: 12px; height: 12px; animation-duration: 5.7s; animation-delay: 1.1s; }
.flake.f5 { left: 60px; top: 63px; animation-duration: 4.9s; animation-delay: 1.45s; }
/* STORM */
.storm-icon .cloud {
top: 10px;
width: 88px;
height: 38px;
margin-left: -44px;
background: linear-gradient(180deg, #71818d, #28333c);
box-shadow: 0 16px 24px rgba(0, 0, 0, 0.48);
}
.storm-icon .cloud::before {
width: 50px;
height: 50px;
left: -22px;
top: -26px;
background: #65737f;
}
.storm-icon .cloud::after {
width: 42px;
height: 42px;
right: -20px;
top: -20px;
background: #546371;
}
.bolt {
z-index: 1;
left: 50%;
top: 44px;
width: 34px;
height: 56px;
margin-left: -17px;
background: linear-gradient(180deg, #fff7cc, #ffd54d 45%, #ffca28);
clip-path: polygon(52% 0, 18% 54%, 44% 54%, 24% 100%, 88% 34%, 54% 34%, 76% 0);
transform: rotate(2deg);
filter: drop-shadow(0 0 10px rgba(255, 233, 138, 0.9));
animation: lightning 3.4s ease-out infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.07); }
}
@keyframes rain-fall {
0% {
opacity: 0;
transform: translateY(0) rotate(20deg);
}
15% {
opacity: 1;
transform: translateY(6px) rotate(20deg);
}
80% {
opacity: 1;
transform: translateY(34px) rotate(20deg);
}
100% {
opacity: 0;
transform: translateY(48px) rotate(20deg);
}
}
@keyframes snow-fall {
0% {
opacity: 0;
transform: translate(0, 0) rotate(0deg) scale(0.55);
}
10% {
opacity: 0.95;
}
35% {
transform: translate(10px, 18px) rotate(40deg) scale(1);
}
65% {
transform: translate(-9px, 32px) rotate(92deg) scale(0.96);
}
100% {
opacity: 0;
transform: translate(7px, 52px) rotate(145deg) scale(0.68);
}
}
@keyframes lightning {
0%, 14%, 100% {
opacity: 0.08;
transform: rotate(2deg) scale(0.98);
}
16%, 20% {
opacity: 1;
transform: rotate(2deg) scale(1.05);
}
22%, 26% {
opacity: 0.2;
transform: rotate(2deg) scale(1);
}
28%, 34% {
opacity: 1;
transform: rotate(2deg) scale(1.03);
}
36%, 50% {
opacity: 0.05;
transform: rotate(2deg) scale(0.99);
}
}
@media (max-width: 980px) {
.weather-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 640px) {
body {
padding: 24px 14px;
}
.weather-grid {
grid-template-columns: 1fr;
}
.weather-card {
min-height: auto;
padding: 22px 16px;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation: none !important;
transition: none !important;
}
.weather-card:hover {
transform: none;
}
.drop {
opacity: 0.92;
transform: translateY(18px) rotate(20deg);
}
.flake {
opacity: 0.92;
transform: translate(4px, 12px) rotate(24deg);
}
.bolt {
opacity: 0.92;
filter: drop-shadow(0 0 12px rgba(255, 228, 110, 0.9));
}
.sun-core {
transform: scale(1);
}
.sun-rays {
transform: rotate(28deg);
}
}
</style>
</head>
<body>
<div class="page">
<header class="intro">
<h1>Animated Weather Cards</h1>
<p>HTML & CSS only · no JavaScript · no images</p>
</header>
<main class="weather-grid" aria-label="Weather forecast">
<article class="weather-card sunny">
<div class="icon sunny-icon" aria-hidden="true">
<div class="sun-core"></div>
<div class="sun-rays">
<span class="ray"></span>
<span class="ray"></span>
<span class="ray"></span>
<span class="ray"></span>
</div>
</div>
<h2 class="city-name">Palma</h2>
<p class="temperature">31°C</p>
<p class="description">Clear skies and warm sunshine</p>
</article>
<article class="weather-card rainy">
<div class="icon rain-icon" aria-hidden="true">
<div class="cloud"></div>
<span class="drop d1"></span>
<span class="drop d2"></span>
<span class="drop d3"></span>
<span class="drop d4"></span>
<span class="drop d5"></span>
</div>
<h2 class="city-name">London</h2>
<p class="temperature">14°C</p>
<p class="description">Grey skies with steady rain</p>
</article>
<article class="weather-card snowy">
<div class="icon snow-icon" aria-hidden="true">
<div class="cloud"></div>
<span class="flake f1"><i></i></span>
<span class="flake f2"><i></i></span>
<span class="flake f3"><i></i></span>
<span class="flake f4"><i></i></span>
<span class="flake f5"><i></i></span>
</div>
<h2 class="city-name">Reykjavík</h2>
<p class="temperature">-4°C</p>
<p class="description">Light snow drifting softly</p>
</article>
<article class="weather-card stormy">
<div class="icon storm-icon" aria-hidden="true">
<div class="cloud"></div>
<span class="bolt"></span>
</div>
<h2 class="city-name">Singapore</h2>
<p class="temperature">27°C</p>
<p class="description">Dark clouds and lightning</p>
</article>
</main>
</div>
</body>
</html>Reasoning trace (17,455 tokens)
We need answer user's request: generate self-contained web demo exactly one fenced code block. Need produce HTML/CSS only, no script. Must satisfy all. Need think in English same language. Now craft final code block.
Need ensure no JS, no <script>, no inline handlers. Four weather cards animated CSS only. Icons: sunny rotating sun rays, rainy falling raindrops, snowy drifting snowflakes, stormy flashing lightning. Each card background gradient. Responsive grid 4 per row desktop, stacked mobile, lift on hover. Smooth infinite @keyframes, respect prefers-reduced-motion.
We need make robust in sandbox iframe no external. Need no script tag. Could use <style> in head. Ensure accessible maybe aria-label. No JS. No localStorage.
Design: cards with city name, temp, desc. Icons built HTML + pseudo-elements. Need careful CSS to create icons with divs. Could use CSS animations.
Important: "Absolutely no JavaScript: file must not contain any <script> tag or inline event handler." We can have CSS :hover. No onclick. No script. Maybe avoid event handlers in HTML.
Need visible first paint. All animations auto.
Sunny icon: a central circle and rays. We can make container .sunny-icon with .sun-core and eight rays via pseudo elements? For rotating rays, use one wrapper .rays with 8 ray divs? HTML-only can have multiple elements but pseudo-elements. Requirement says icons built from HTML elements and pseudo-elements. We can include child divs. For 8 rays, we can use divs .ray1... but no SVG. Or use .rays::before/::after for pairs and multiple elements. Simpler: .sunny-icon .sun-rays with 4 child divs each styled with two pseudo-elements? Need 8 rays maybe okay: each div a rectangle positioned center rotated 0,45,90,135; pseudo-elements before/after for opposite? Let's design robust.
Could use conic-gradient? But icons built from elements and pseudo. But no images. CSS gradients allowed? Background gradients are CSS. Icons maybe could use multiple radial gradients? But "built from HTML elements and pseudo-elements styled with CSS" maybe not pure background gradients? It's okay? Better explicit elements.
Rain: cloud + drops. Cloud: .cloud and ::before/::after circles. Drops: child .drop elements with animation translateY fade. Falling rain drops. Could use 3 drops.
Snow: cloud + snowflakes. Snowflakes maybe small squares/circles with drift and rotate. Could have .flake elements with ::before/::after? Drifting: translate down and x sway. Use different nth-child delays.
Storm: dark cloud + lightning. Lightning: element .bolt built from two triangles? Use clip-path polygon maybe CSS. Flashing via opacity animation. Could also have rain? Storm maybe flashing lightning. Need background gradient stormy. Card text.
Need ensure responsive grid: display grid; grid-template-columns repeat(auto-fit,minmax(240px,1fr))? But requirement 4 per row desktop, stacked mobile. Could use @media max-width 1100 maybe 2; max-width 760 stack. For desktop exactly 4 columns: min-width 1200: repeat(4,1fr). But responsive: use grid-template-columns: repeat(4, minmax(0,1fr)) and media stack. Or repeat(auto-fit,minmax(220px,1fr)) yields 4 on wide but not guaranteed if width large? It's fine. Requirement says 4 per row desktop, stacked mobile. We can set @media (min-width:900px) four columns; (max-width: 900px) 2; (max-width: 640px) 1.
Lift on hover: transform translateY(-10px), box-shadow. Add transition.
Prefers reduced motion: @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } } But need maybe not too harsh? Good.
Need no external fonts, use system-ui.
Could add body gradient. No script. Need self-contained.
Let's construct HTML:
<main class="weather-grid" aria-label="Weather cards">
<article class="card card-sunny" aria-label="Sunny weather in ...">
<div class="icon icon-sunny" aria-hidden="true">
<div class="sun-core"></div>
<div class="sun-rays">
<span class="ray"></span>
<span class="ray"></span>
<span class="ray"></span>
<span class="ray"></span>
</div>
</div>
<h2>City</h2>
<div class="temp">28°</div>
<p>Sunny and clear.</p>
</article>
...
Need pseudo elements for rays. Each .ray is a vertical bar centered, transform rotate. Since four rays, each ray also has ::before/::after maybe same? But four rotated elements create 4 lines through center if each bar centered and length 90? Actually if one bar rotated 0, another 45, another 90, another 135, each bar spans through center? If bar length 84 with height 8 and center at middle, rotate 0,45,90,135 -> 8 rays (each bar has two ends). That's enough. But need separate bars maybe positioned top/left 50%. Use .ray { position:absolute; left:50%; top:50%; width:76px; height:8px; margin-left:-38px; margin-top:-4px; border-radius:4px; background: var(--sun); transform-origin:center; }
.ray:nth-child(1) transform rotate(0) ; .ray:nth-child(2) rotate(45); 90; 135. But if all are full length, they overlap through center. Good. Could animate .sun-rays rotation 20s linear. Also core pulse maybe.
Sunny background: linear-gradient(#ffd36f, #ff9f43) etc.
Rain: Need card background gradient blue/gray. Icon: cloud with rain. Use .rain-icon { position: relative; } .cloud etc. Drops: three child <span class="drop"></span> positioned under cloud. Animation translateY from 0 to 60 with fade. Use delays. Could use ::before? Fine.
Rain drops: .drop { width:6px;height:14px;background:#4fc3f7; border-radius:0 60% 60% 60%; transform: rotate(45deg)?} Falling rain drops could be small elongated rounded. Use animation rain-fall. Need not overflow.
Snow: cloud + flakes. Flakes are small circles maybe with pseudo? Could use child .flake; animation snow-fall translate y + x. Could add rotating 6-point snowflake? Requirement says drifting snowflakes, not necessarily shape. Could make flakes as small circles and rotate/drift. But maybe nicer: each flake ::before/::after lines forming snowflake? Let's design: .flake { position:absolute; width:18px; height:18px; } .flake::before {content:''; position:absolute; inset:50% auto auto 50%; width:22px;height:3px; transform:translate(-50%,-50%); background:#fff; border-radius:3px; box-shadow:0 0 8px rgba(255,255,255,.8);} .flake::after { content:''; position:absolute; inset:50%; width:22px;height:3px; background:#fff; transform:translate(-50%,-50%) rotate(60deg); } plus maybe another element? Pseudo only gives two crossed lines (6-ray? actually 2 lines make 4 rays; can add box-shadow to duplicate rotate? Not easy). Could use multiple children? No SVG. We can have .flake .a, .b, .c? HTML elements okay. Use each flake with three bars? But requirement icons built HTML + pseudo-elements. Child span okay. Could do .flake { display: inline-block; position: relative; } .flake::before and ::after plus .flake > span? For simplicity use circles with drift. But "snowflakes" maybe okay. Maybe better use CSS clip-path to create 6-point? But built from elements. We can make small divs with multiple pseudo? Could have .flake as 3 crossed bars via ::before and ::after? Need three rotated rectangles through center = 6 rays. If each flake has two pseudo-elements only 2 bars; can use .flake::before as one bar, .flake::after as two? Maybe ::after can have box-shadow to simulate other bars? Not transform. Could include inner span for third bar. Use HTML: <span class="flake"><i></i><b></b></span> but many tags. Could use divs .flake1 .flake2 .flake3 each with <span class="flake-line"></span>. But maybe overkill.
Storm: Cloud + lightning. .bolt { position:absolute; width:24px;height:40px; background:#ffd54f; clip-path: polygon(45% 0, 10% 55%, 40% 55%, 25% 100%, 95% 35%, 55% 35%, 80% 0); transform: skew? Use clip-path allowed CSS, no images. Animation flash: opacity 0 -> 1 -> 0 plus glow. Add raindrops maybe optional. Requirement flashing lightning only. Could also cloud.
Need cards have their own background gradient matching weather. We can use class-specific. Ensure text readable.
Accessibility: aria-hidden for decorative icons. But city/temp maybe heading. Need maybe labels.
Could use CSS custom properties.
Need no script. Check no inline event handler: none. No <script>. Use <style>.
Potential issues: Pseudo-element content. Need content:''.
Let's write full HTML. Need final exactly one fenced code block. Could include <!doctype html>. No text outside. Good.
Let's detail CSS.
Body: min-height:100vh; margin:0; display:flex; align-items:center; justify-content:center; padding:24px; background: radial-gradient(circle at top,#1f2937,#0b1220 70%); color:#fff; font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
Maybe add .page? h1? Could add title. The task only asks set of cards; but first paint should show cards. We can add optional heading but not necessary. Maybe include heading. Keep within viewport. Grid max-width 1280.
.card { min-height:260px; border-radius:24px; padding:20px; display:flex; flex-direction:column; align-items:center; justify-content:flex-start; gap:6px; box-shadow: 0 14px 30px rgba(0,0,0,.25); overflow:hidden; transform: translateY(0); transition: transform .35s ease, box-shadow .35s ease; position:relative; }
.card:hover, .card:focus-within { transform: translateY(-12px) scale(1.02); box-shadow:0 30px 50px rgba(0,0,0,.35); }
Focus with keyboard? No JS, okay.
.card h2 { font-size:1.25rem; margin:10px 0 0; font-weight:700; text-shadow: 0 1px 6px rgba(0,0,0,.2); }
.temp { font-size:2.5rem; font-weight:800; line-height:1; }
.desc { opacity:.9; font-size: .95rem; text-align:center; margin:0; }
Maybe align center.
Backgrounds:
.card-sunny { background: linear-gradient(160deg,#ffefc2 0%,#ffd86b 45%,#ff9c3a 100%); color:#5b3a00; }
Need text dark? Could be #4b2a00. card-rainy { linear-gradient(160deg,#b9dcff 0%,#6aa6e8 45%,#2c5b8f 100%); color:#fff; } card-snowy { linear-gradient(160deg,#edf7ff 0%,#cfe8ff 45%,#8fb9ff 100%); color:#183a5a; } card-stormy { linear-gradient(160deg,#6b7280 0%,#37474f 45%,#10161a 100%); color:#fff; }
Icon sizes maybe 120x120.
Sunny:
.icon-sunny { width:112px;height:112px; position:relative; margin:12px auto; }
.sun-core { position:absolute; left:50%; top:50%; width:52px;height:52px; margin-left:-26px;margin-top:-26px; border-radius:50%; background: radial-gradient(circle at 35% 35%,#fffbe8,#ffd54f 45%,#ff9f1c 100%); box-shadow:0 0 22px rgba(255,196,50,.85), inset 0 -6px 12px rgba(220,120,0,.25); animation: sun-pulse 3.2s ease-in-out infinite; }
.sun-rays { position:absolute; inset:0; animation: spin 18s linear infinite; }
.ray { position:absolute; left:50%; top:50%; width:72px; height:8px; border-radius:999px; margin-left:-36px;margin-top:-4px; background: linear-gradient(90deg, rgba(255,213,79,0) 0%, #ffd54f 18%, #ffb703 50%, #ffd54f 82%, rgba(255,213,79,0)100%); transform-origin:50% 50%; box-shadow:0 0 10px rgba(255,180,30,.55); }
.ray:nth-child(1){transform:rotate(0);} ... 45,90,135.
But with 4 full bars, rotating .sun-rays, okay.
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes sun-pulse {0,100 {transform: scale(1);} 50 {scale(1.06);} } But .sun-core also transform used? Only center via margins no transform, animation can transform scale with no issue. Good.
Could add glow.
Rain:
.icon-rainy { width:112px;height:112px;position:relative;margin:12px auto; }
.cloud { position:absolute; left:50%; top:24px; width:64px;height:30px; margin-left:-32px; border-radius:20px; background: linear-gradient(180deg,#ffffff,#d8e8ff); box-shadow: 0 10px 20px rgba(33,72,109,.18); }
.cloud::before { content:""; position:absolute; left:-14px; top:-16px; width:36px;height:36px;border-radius:50%; background:#fff; }
.cloud::after { content:""; position:absolute; right:-12px; top:-12px; width:30px;height:30px;border-radius:50%; background:#f5fbff; }
Maybe cloud shape not symmetrical but okay. Need no overflow.
.drops { position:absolute; inset:0; }
.drop { position:absolute; top:58px; left:34px; width:5px;height:13px; border-radius:0 6px 6px 6px; background: linear-gradient(180deg,#dff3ff,#4fc3f7); transform: rotate(25deg); opacity:0; animation: rain-fall 1.5s linear infinite; }
.drop:nth-child(1) { left:30px; animation-delay:0s; }
.drop:nth-child(2) { left:54px; top:52px; animation-delay:.25s; transform: rotate(18deg); }
.drop:nth-child(3) { left:74px; top:58px; animation-delay:.5s; transform: rotate(28deg); }
Maybe more drops (5). Use HTML with five spans .drop. Keyframes:
@keyframes rain-fall { 0% { transform: translate(0,0) rotate(25deg); opacity:0; } 10% { opacity:1; } 80% { opacity:1; } 100% { transform: translate(-12px,48px) rotate(25deg); opacity:0; } }
But if each drop has base transform rotate, animation overrides transform. Could include rotate in each keyframe. Need left positions.
Maybe use separate .drop::before? Not needed.
Need cloud and drops. HTML:
<div class="cloud"></div>
<span class="drop"></span> <span class="drop"></span> <span class="drop"></span> <span class="drop"></span> <span class="drop"></span>
But if spans are direct children of icon. .icon-rainy { --drop-start? } We'll style nth-of-type? Could use .drop:nth-child(2) etc. Need not mix.
Snow:
.icon-snowy { width:112px;height:112px;position:relative;margin:12px auto; }
Cloud maybe bluish. .snow-flakes { position:absolute; inset:0; }
.flake { position:absolute; top:52px; left:24px; width:14px;height:14px; background:#fff; border-radius:50%; box-shadow: 0 0 8px rgba(255,255,255,.75); opacity:0; animation: snow-fall 4s ease-in-out infinite; }
For snowflakes drifting: use translate y and sway x plus scale. Need 5 flakes with different positions/delays/durations.
Could make each flake a 6-ray snowflake using ::before and ::after with lines:
.flake { width:18px; height:18px; }
.flake::before, .flake::after { content:""; position:absolute; left:50%; top:50%; width:20px; height:2.5px; border-radius:999px; background:#fff; transform: translate(-50%,-50%) rotate(var(--r,0deg)); box-shadow:0 0 7px rgba(255,255,255,.75); }
.flake::before { --r:0deg; }
.flake::after { --r:60deg; }
Need third bar 120deg but can use .flake span? We can include <i></i> child: .flake > i { content? element } position absolute lines with rotate 120. Or use box-shadow? Not easy.
Maybe simpler round flakes; requirement says snowflakes. Could be okay? It says falling/drifting snowflakes. Could call them snowflakes but round. But "icon built" could be round flakes. To make more snowflake-like, use clip-path star: .flake::before clip-path polygon star? We can make one element with ::before using star shape? CSS only, no SVG. clip-path allowed. But built from HTML + pseudo. Could do .flake::before: clip-path polygon(50% 0, 62% 34%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 38% 34%) star 10. But background white. Need maybe not complex. But if round, okay.
Storm:
.icon-stormy { width:112px;height:112px;position:relative;margin:12px auto; }
.cloud-storm { position:absolute; left:50%; top:18px; width:74px; height:34px; margin-left:-37px; border-radius:24px; background:linear-gradient(180deg,#5f6b78,#2b3640); box-shadow:0 10px 18px rgba(0,0,0,.4); }
.cloud-storm::before { content:''; left:-18px; top:-18px; width:42px; height:42px; border-radius:50%; background:#5f6b78; }
.cloud-storm::after { right:-16px; top:-14px; width:36px; height:36px; border-radius:50%; background:#4a5663; }
.bolt { position:absolute; left:50%; top:46px; width:32px; height:48px; margin-left:-16px; background:#ffe066; clip-path: polygon(50% 0, 18% 54%, 46% 54%, 30% 100%, 85% 36%, 53% 36%, 72% 0); filter: drop-shadow(0 0 8px rgba(255,224,102,.85)); animation: lightning 2.6s steps(1,end) infinite; }
Need maybe flash keyframes:
@keyframes lightning { 0%,18%,100% { opacity:.15; } 20%,24% { opacity:1; } 26%,28% { opacity:.35; } 30%,34% { opacity:1; } 36% { opacity:.05; } }
Could use ease? infinite. Add storm glow overlay .storm-glow::before? Maybe. Need no images. Could add rain drops maybe but not required. Stormy background gradient.
Potential issue clip-path supported Chrome. Fine.
Need grid.
.weather-grid { width:min(1240px,100%); display:grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap:22px; }
But requirement 4 per row desktop, stacked mobile. With auto-fit and minmax 220, on 1280 likely 4. On smaller adapt. Could specify:
@media (min-width:980px) { .weather-grid { grid-template-columns: repeat(4, minmax(220px, 1fr)); } }
@media (max-width:979px) { .weather-grid { grid-template-columns: repeat(2, minmax(160px,1fr)); } }
@media (max-width:640px) { .weather-grid { grid-template-columns: 1fr; } }
Need ensure cards fit 4 on 1280 with gap; minmax maybe 180. Use repeat(4, minmax(0,1fr)).
Could add page header:
<div class="page"><header class="intro"><h1>Animated Weather Cards</h1><p>HTML & CSS only — no JavaScript</p></header><main class="weather-grid">...</main></div>
No script.
Need ensure no external fonts. Good.
Check no script tags: none.
Check no event handlers: none.
Could there be issue with pseudo-elements on .drop? Not needed.
Let's refine rain cloud and drops positions. Icon size 120, cloud top 26. Drops below cloud at top 58. Falling distance maybe 46. Card min height 260. Icon margin bottom 12.
Rain drops could overflow if translate to 58. Use .icon-rainy overflow hidden? No.
Better:
.drop { position:absolute; top:54px; left:22px; width:6px; height:16px; background:linear-gradient(180deg,#ffffff,#74c0fc); border-radius: 0 50% 50% 50%; transform: rotate(22deg); opacity:0; animation: rain-fall 1.6s linear infinite; }
.drop:nth-child(2) { left:42px; top:48px; animation-delay:.22s; transform: rotate(18deg); } etc.
Keyframe uses rotate per child? If animation overrides transform for all, each child same rotation from keyframe. Could set --r and keyframe transform: translate(var(--x), var(--y)) rotate(var(--r))? CSS variables in keyframe? Can animate? It can use var in transform but var per element okay. But translate not animated? We can animate custom property? No JS, but @property needed? Simpler: use separate keyframes for each? Could set animation-name same but base transform in keyframes uses rotate(24deg). For drops all same. Fine.
@keyframes rain-fall { 0% { transform: translateY(0) rotate(22deg); opacity:0; } 15% { opacity:1; } 85% { opacity:1; } 100% { transform: translateY(44px) rotate(22deg); opacity:0; } }
Could include x drift: translate(-10px,44px). Good.
Use five drops.
Snow flake keyframes:
@keyframes snow-fall {
0% { transform: translate(0,0) scale(.5) rotate(0deg); opacity:0; }
10% { opacity:.95; }
35% { transform: translate(10px,22px) scale(.95) rotate(90deg); }
65% { transform: translate(-10px,38px) scale(1) rotate(180deg); opacity:.9; }
100% { transform: translate(8px,58px) scale(.75) rotate(360deg); opacity:0; }
}
Durations 4s etc.
Flake shape: use ::before/::after with bars plus an <i> for third bar. HTML: <span class="flake"><i></i></span> x 5.
.flake { position:absolute; top:52px; left:24px; width:18px; height:18px; opacity:0; animation: snow-fall 4s ease-in-out infinite; }
.flake::before, .flake::after, .flake i { content:''; position:absolute; left:50%; top:50%; width:18px; height:2px; border-radius:999px; background:#fff; transform:translate(-50%,-50%); box-shadow:0 0 8px rgba(255,255,255,.8); }
.flake::after { transform:translate(-50%,-50%) rotate(60deg); }
.flake i { transform:translate(-50%,-50%) rotate(120deg); }
Then flake moves as whole. Add smaller center dot? Could add .flake::before background line; okay. Need i element not pseudo? HTML elements allowed. Use <i></i> inside flake.
Maybe each flake has different size and delays.
Could use nth-child to position and delay:
.flake:nth-child(1) { left:20px; top:50px; --fall:4.2s; animation-duration:4.2s; animation-delay:.0s; transform-origin:center; }
But animation properties can be in keyframe? We can set directly. Need not use custom.
.flake:nth-child(2) { left:58px; top:46px; animation-duration:5s; animation-delay:.45s; width:14px;height:14px; }
But ::before line width should scale? Could define width:70% maybe. Use width:100%; for line extends beyond. Better:
.flake::before, .flake::after, .flake i { width:100%; }
For 14px line 14px. Good.
Set animation-delay.
For drift maybe left different and keyframes same; okay.
Need if .flake width smaller, line same width. Good.
Storm: lightning may need more flashing. Add .storm-glow as absolute full overlay with radial gradient? But pseudo? Maybe .icon-stormy::after { content:''; position:absolute; inset:-10%; background: radial-gradient(circle at 50% 60%, rgba(255,245,180,.28), transparent 60%); animation: storm-flash ...; } But overlay. Could cause background radial gradient (CSS gradient). Allowed? Icon built? It's glow not icon. Fine. But background gradient for glow. Could be simpler: .bolt has filter drop-shadow and animation. Also add .storm-cloud maybe raindrops? Not needed.
Potential issue with prefers-reduced-motion: If all animations none, hover transitions none. Fine. But then still visible. If using animation to set opacity for raindrops/snow/bolt, reduced motion none leaves default opacity? We need define default states visible if animation disabled. Important! If prefers-reduced-motion sets animation:none, elements that depend on animation for visibility will show initial opacity? For rain/snow/bolt we set opacity:0 default. If animation none, they'd be invisible. Need handle: in reduced motion media, set animation:none and also set opacity for drops/flakes/bolt to visible? Requirement "respect prefers-reduced-motion" typically disable animation but still visible. So add within media:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count:1 !important; transition-duration: .01ms !important; }? Or animation:none.
.drop { opacity:1; transform: translateY(18px) rotate(22deg); }
.flake { opacity:.85; transform: translate(0,10px) rotate(0); }
.bolt { opacity:.9; }
.sun-core { transform: scale(1); } .sun-rays { transform: none; }
}
But if we just animation:none, transforms from nth-child? Need set visible. Could do both.
However rule says smooth infinite animations using @keyframes, and respect prefers-reduced-motion. It may be acceptable to set animation: none. But need elements visible. Use reduce media:
@media (prefers-reduced-motion: reduce) {
* { animation: none !important; transition: none !important; }
.drop { opacity: 1; transform: translateY(16px) rotate(22deg); }
.flake { opacity: .9; transform: translate(4px,12px) rotate(10deg); }
.bolt { opacity: .95; filter: drop-shadow(0 0 8px rgba(255,224,102,.7)); }
}
Need .sun-rays maybe no rotation but okay. .sun-core default no transform visible.
Card hover transitions none. Good.
Also if not reduced, .drop default opacity:0, but animation starts with 0 then visible. Fine.
Could use animation-fill-mode? no need.
Need maybe focus state? Could make .card:focus-within not because article not focusable. Could set tabindex? No JS, but tabindex okay? It's HTML not event handler. But no need. For hover only.
Need check "lift up on hover": CSS transform. Good.
Potential issue: grid with four columns may cause icons/text overflow on 1280? Cards width ~300 minus gap. Fine.
Let's think about "made with HTML and CSS only" could include heading etc. Good.
Now craft final code. Need only code block. No explanation.
Let's ensure syntax valid.
Full:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Animated Weather Cards — HTML & CSS Only</title>
<style> ... </style>
</head>
<body>
<div class="page">
<header class="intro">
<h1>Animated Weather Cards</h1>
<p>Four CSS-only weather scenes. No JavaScript, no images, no icon fonts.</p>
</header>
<main class="weather-grid">
<article class="weather-card sunny">
<div class="icon sunny-icon" aria-hidden="true">
<div class="sun-core"></div>
<div class="sun-rays">
<span class="ray"></span><span class="ray"></span><span class="ray"></span><span class="ray"></span>
</div>
</div>
<div class="city-name">Palma</div>
<div class="temperature">31°C</div>
<div class="description">Sunny and bright</div>
</article>
...
Maybe use city-name, temperature, description. No headings? Could use h2 for semantics.
City: Sunny: "Santorini"? Rainy: "London"? Snowy: "Reykjavik"? Stormy: "Singapore". Description short.
Rain icon HTML:
<div class="icon rain-icon" aria-hidden="true">
<div class="cloud"></div>
<span class="drop"></span>
<span class="drop"></span>
<span class="drop"></span>
<span class="drop"></span>
<span class="drop"></span>
</div>
Snow icon HTML:
<div class="icon snow-icon" aria-hidden="true">
<div class="cloud snow-cloud"></div>
<span class="flake"><i></i></span> ... 5
</div>
Storm icon:
<div class="icon storm-icon" aria-hidden="true">
<div class="cloud storm-cloud"></div>
<span class="bolt"></span>
</div>
Need .cloud reused but with variants. Use class cloud .rain-cloud? Better.
CSS details:
:root maybe.
body { ... }
.intro { max-width: 1240px; margin: 0 auto 28px; text-align:center; }
h1 { margin:0 0 8px; font-size:clamp(1.6rem, 3vw, 2.5rem); }
p { margin:0; opacity:.8; }
Weather card: .weather-card { border-radius: 28px; padding: 24px 18px; display:flex; flex-direction:column; align-items:center; gap:10px; min-height: 290px; position:relative; overflow:hidden; transition: transform .32s cubic-bezier(.2,.7,.2,1), box-shadow .32s; box-shadow: 0 12px 24px rgba(0,0,0,.22); border:1px solid rgba(255,255,255,.25); }
.weather-card:hover { transform: translateY(-12px) scale(1.02); box-shadow: 0 28px 48px rgba(0,0,0,.34); }
Backgrounds and text colors:
.sunny { background: linear-gradient(160deg, #fff6cf 0%, #ffd85e 45%, #ff9a2e 100%); color:#5f3600; }
.rainy { background: linear-gradient(160deg, #d7efff 0%, #7ab5e8 45%, #264b78 100%); color:#fff; }
.snowy { background: linear-gradient(160deg, #fbfdff 0%, #d5ebff 45%, #93bfff 100%); color:#16375c; }
.stormy { background: linear-gradient(160deg, #78909c 0%, #37474f 45%, #0d1418 100%); color:#fff; }
Need .weather-card::after maybe subtle shine. Could add pointer-events:none, not necessary.
City-name: font-size:1.1rem; font-weight:700; letter-spacing:.03em; opacity:.95.
temperature: font-size:2.6rem; font-weight:900; line-height:1; text-shadow maybe depending background. description: font-size:.95rem; opacity:.9; text-align:center; line-height:1.25; max-width:180px.
Maybe align.
Icons:
.icon { width: 116px; height: 116px; position:relative; margin:0 0 10px; }
Sunny:
.sunny-icon .sun-core { position:absolute; inset:50%; width:54px;height:54px; margin:-27px; border-radius:50%; background: radial-gradient(circle at 32% 30%, #fffbe3 0%, #ffd34d 45%, #ff9d1c 100%); box-shadow: 0 0 26px rgba(255,187,20,.95), inset 0 -5px 12px rgba(190,100,0,.18); animation: pulse 3s ease-in-out infinite; }
.sunny-icon .sun-rays { position:absolute; inset:0; animation: spin 22s linear infinite; }
.ray { position:absolute; left:50%; top:50%; width:88px; height:8px; margin:-4px -44px; border-radius:999px; background: linear-gradient(90deg, rgba(255,200,30,0), #ffd23f 16%, #ffb703 50%, #ffd23f 84%, rgba(255,200,30,0)); box-shadow: 0 0 12px rgba(255,173,21,.65); }
.ray:nth-child(1) { transform: rotate(0deg); }
.ray:nth-child(2) { transform: rotate(45deg); }
.ray:nth-child(3) { transform: rotate(90deg); }
.ray:nth-child(4) { transform: rotate(135deg); }
Maybe .rays wrapper transform rotate with individual ray transform okay.
But .ray with transform rotate and parent rotate animation: parent rotate, children transform relative; fine.
Rain cloud:
.rain-icon .cloud { position:absolute; left:50%; top:18px; width:74px; height:34px; margin-left:-37px; border-radius:999px; background: linear-gradient(180deg, #ffffff, #dceeff); box-shadow: 0 12px 20px rgba(25,64,99,.18); }
.rain-icon .cloud::before { content:""; position:absolute; width:42px; height:42px; left:-18px; top:-20px; border-radius:50%; background:#ffffff; }
.rain-icon .cloud::after { content:""; position:absolute; width:34px; height:34px; right:-14px; top:-14px; border-radius:50%; background:#f6fbff; }
Maybe cloud width 70. Drop positions relative icon.
.drop { position:absolute; top:56px; left:34px; width:6px; height:17px; border-radius:0 7px 7px 7px; background: linear-gradient(180deg,#ffffff, #66bfff); transform: rotate(20deg); opacity:0; animation: rain-fall 1.55s linear infinite; filter: drop-shadow(0 2px 3px rgba(31,91,140,.35)); }
.rain-icon .drop:nth-child(2) { left:28px; top:52px; animation-delay:0s; } Wait first .drop is first child after cloud? In icon-rainy children: .cloud, .drop (1), .drop (2)... nth-child of .icon-rainy? If style .rain-icon .drop:nth-child(2), it targets first .drop? Because .drop is second child. Need use :nth-of-type? Since all drops are span, cloud is div, use .rain-icon .drop:nth-of-type(1) to nth-of-type(5). Or structure with wrapper .rain-drops { } with drops as children. Simpler: use spans with classes drop drop1 etc? Better use <span class="drop d1"></span> and style .d1 .d2. But CSS only. Use class names to avoid nth-child confusion.
Let's assign: <span class="drop d1"></span> etc. CSS:
.d1 { left:32px; top:54px; animation-delay:.0s; }
.d2 { left:50px; top:48px; animation-delay:.25s; }
.d3 { left:68px; top:55px; animation-delay:.5s; }
.d4 { left:44px; top:60px; animation-delay:.75s; }
.d5 { left:58px; top:62px; animation-delay:1s; }
But if top values maybe too low. Falling down to 100. Fine.
Need maybe base left. .drop top:52; each .d sets.
Rain keyframes:
@keyframes rain-fall { 0% { transform: translateY(0) rotate(20deg); opacity:0; } 10% { opacity:.95; } 75% { opacity:.95; } 100% { transform: translateY(46px) rotate(20deg); opacity:0; } }
Drops with .d4 maybe top 60; translate to 106, within icon 116 okay. Good.
Snow:
.snow-icon .cloud (snow-cloud): position top 12? Use .cloud as base? Define .cloud class generic. But .snow-icon .cloud::before/after maybe white/gray. Could share.
.snow-icon .cloud { top:16px; background:linear-gradient(180deg,#fff,#d8e9ff); box-shadow...}
.snow-icon .cloud::before/::after same.
.flake { position:absolute; width:18px; height:18px; top:54px; left:26px; opacity:0; animation: snow-fall 4.4s ease-in-out infinite; }
.flake::before, .flake::after, .flake i { content:""; position:absolute; left:50%; top:50%; width:100%; height:2px; border-radius:999px; background:#fff; box-shadow: 0 0 8px rgba(255,255,255,.75); transform: translate(-50%,-50%); }
.flake::after { transform: translate(-50%,-50%) rotate(60deg); }
.flake i { transform: translate(-50%,-50%) rotate(120deg); }
Need .flake i is <i> element, content property? For non-pseudo element, content not needed. So separate rule: .flake i { display:block; position:absolute; ... } It doesn't need content. Could have shared rule for .flake::before,.flake::after and .flake i? Use .flake::before, .flake::after, .flake i { position:absolute; ... } Content in .flake::before and ::after? Content applies only to pseudo; can include content:''; for .flake i it has no effect but okay? CSS property content on normal elements is ignored. So include.
Set .flake i transform rotate(120). Need specificity. Good.
Flake delays:
.flake.f1 { left:18px; top:54px; animation-duration:4.2s; animation-delay:.0s; }
.f2 { left:42px; top:48px; animation-duration:5s; animation-delay:.35s; width:14px;height:14px; }
.f3 { left:70px; top:52px; animation-duration:4.6s; animation-delay:.7s; }
.f4 { left:34px; top:60px; animation-duration:5.6s; animation-delay:1.1s; width:12px;height:12px; }
.f5 { left:58px; top:62px; animation-duration:4.8s; animation-delay:1.45s; }
Maybe 5.
Snow keyframe:
@keyframes snow-fall { 0% { transform: translate(0,0) rotate(0deg) scale(.55); opacity:0; } 10% { opacity:.95; } 35% { transform: translate(10px,18px) rotate(40deg) scale(1); } 65% { transform: translate(-8px,32px) rotate(90deg) scale(.95); } 100% { transform: translate(6px,50px) rotate(140deg) scale(.7); opacity:0; } }
This drifts. Good.
Storm:
.storm-icon .cloud { top:12px; background:linear-gradient(180deg,#78909c,#2f3b45); box-shadow:0 14px 22px rgba(0,0,0,.45); width:84; height:38; left:50%; margin-left:-42; }
.storm-icon .cloud::before { width:46;height:46; left:-20;top:-22;background:#64747f; }
.storm-icon .cloud::after { width:38;height:38; right:-16;top:-16;background:#546470; }
.storm-icon .bolt { position:absolute; left:50%; top:42px; width:34px; height:56px; margin-left:-17px; background: linear-gradient(180deg,#fff7cc, #ffd54d 45%, #ffca28); clip-path: polygon(52% 0, 18% 54%, 44% 54%, 24% 100%, 88% 34%, 54% 34%, 76% 0); transform: rotate(2deg); filter: drop-shadow(0 0 10px rgba(255,233,138,.9)); animation: flash 2.8s steps(1,end) infinite; }
.bolt::before? Could add secondary flicker overlay? Not needed.
Keyframe flash:
@keyframes flash {
0%, 16%, 100% { opacity:.12; filter: drop-shadow(0 0 4px rgba(255,213,77,.2)); transform: rotate(2deg) scale(1); }
18%, 22% { opacity:1; filter: drop-shadow(0 0 20px rgba(255,245,180,1)); transform: rotate(2deg) scale(1.04); }
24%, 28% { opacity:.28; filter: drop-shadow(0 0 8px rgba(255,213,77,.45)); transform: rotate(2deg) scale(1); }
30%, 36% { opacity:1; filter: drop-shadow(0 0 18px rgba(255,245,180,.9)); transform: rotate(2deg) scale(1.03); }
38% { opacity:0; }
}
Need keyframe steps? If use steps(1,end) may be too abrupt? Could be okay. Actually "flashing lightning" can use steps. But if using steps(1,end) between percentages may only show keyframe at each 1/2? Better use normal ease? We can set animation: flash 3.5s ease-in-out infinite. Keyframes with opacity. Smooth? Flash could be discrete. It's okay.
Maybe add background card stormy has subtle flash overlay using .weather-card.stormy::before { content:''; position:absolute; inset:0; background: radial-gradient(circle at 50% 45%, rgba(255,245,190,.18), transparent 45%); animation: storm-glow 3.5s ease-in-out infinite; pointer-events:none; } But pseudo on card okay. Need not overcomplicate. If .weather-card::before generic? Could create issues with text? pointer-events none, z-index? Maybe not needed. Bolt flash enough.
Need ensure cards backgrounds matching weather and text. Could add small badge? Not required.
Potential issue: .weather-card:hover scale may transform entire grid. Fine.
Potential issue: prefers-reduced-motion override all transitions. But if using animation:none, .drop .flake initial opacity 0. Need set. In reduce block, include .drop, .flake, .bolt opacity. Also maybe .storm-icon::before? If card::before overlay exists. Let's not use overlay to keep reduce simple.
Need ensure keyframe animations infinite. All yes.
Need ensure no JS. Check no <script>, no onclick, onload, etc. Good.
Could include HTML comments? Fine. No script.
Let's think if "no icon fonts" we don't use fonts. Good.
Could "no SVG" we don't use SVG. clip-path okay.
Need final code exactly one block. Ensure not too long but enough. We can include. Let's verify CSS selectors and HTML matches.
Let's draft final code:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Animated Weather Cards</title>
<style>
* { box-sizing: border-box; }
body { ... }
...
@media (max-width: 980px) { ... }
@media (max-width: 640px) { ... }
@media (prefers-reduced-motion: reduce) { ... }
</style>
</head>
<body>
<div class="page">
<header class="intro">
<h1>Animated Weather Cards</h1>
<p>HTML & CSS only · no JavaScript · no images</p>
</header>
<main class="weather-grid" aria-label="Weather forecast">
<article class="weather-card sunny">
<div class="icon sunny-icon" aria-hidden="true">
<div class="sun-core"></div>
<div class="sun-rays">
<span class="ray"></span>
<span class="ray"></span>
<span class="ray"></span>
<span class="ray"></span>
</div>
</div>
<h2 class="city-name">Palma</h2>
<p class="temperature">31°</p>
<p class="description">Clear skies, gentle breeze</p>
</article>
<article class="weather-card rainy">
<div class="icon rain-icon" aria-hidden="true">
<div class="cloud"></div>
<span class="drop d1"></span>
<span class="drop d2"></span>
<span class="drop d3"></span>
<span class="drop d4"></span>
<span class="drop d5"></span>
</div>
<h2 class="city-name">London</h2>
<p class="temperature">14°</p>
<p class="description">Grey skies, constant rain</p>
</article>
<article class="weather-card snowy">
<div class="icon snow-icon" aria-hidden="true">
<div class="cloud"></div>
<span class="flake f1"><i></i></span>
<span class="flake f2"><i></i></span>
<span class="flake f3"><i></i></span>
<span class="flake f4"><i></i></span>
<span class="flake f5"><i></i></span>
</div>
<h2 class="city-name">Reykjavik</h2>
<p class="temperature">-4°</p>
<p class="description">Soft snow drifting</p>
</article>
<article class="weather-card stormy">
<div class="icon storm-icon" aria-hidden="true">
<div class="cloud"></div>
<span class="bolt"></span>
</div>
<h2 class="city-name">Singapore</h2>
<p class="temperature">27°</p>
<p class="description">Thunderstorms and lightning</p>
</article>
</main>
</div>
</body>
</html>
CSS:
.intro { width:min(1240px,100%); margin:0 auto 30px; text-align:center; color:#e6f1ff; }
.intro h1 { font-size: clamp(1.8rem, 4vw, 3rem); margin:0 0 10px; letter-spacing:.02em; }
.intro p { margin:0; opacity:.82; }
.weather-grid { width:min(1240px,100%); margin:0 auto; display:grid; gap:24px; grid-template-columns:repeat(4,minmax(0,1fr)); }
.weather-card { position:relative; overflow:hidden; min-height:300px; border-radius:30px; padding:26px 18px 22px; display:flex; flex-direction:column; align-items:center; gap:8px; text-align:center; box-shadow:0 16px 32px rgba(0,0,0,.28); border:1px solid rgba(255,255,255,.28); transition: transform .35s cubic-bezier(.2,.7,.2,1), box-shadow .35s cubic-bezier(.2,.7,.2,1); }
.city-name { margin:10px 0 0; font-size:1.12rem; font-weight:700; letter-spacing:.02em; }
.temperature { margin:0; font-size:2.8rem; font-weight:900; line-height:1; text-shadow:0 2px 10px rgba(0,0,0,.12); }
.description { margin:2px 0 0; font-size:.95rem; opacity:.92; line-height:1.35; max-width:200px; }
Icon:
.icon { position:relative; width:118px; height:118px; margin-bottom:8px; flex:0 0 auto; }
Sunny CSS as above.
For .sun-core using animation transform scale, but base center with inset:50%; margin:-27px; no transform. Good.
For rain .drop, use .d classes. .drop { position:absolute; ... opacity:0; animation:rain-fall...; }
.d1 { left:24px; top:52px; animation-delay:0s; }
.d2 { left:50px; top:46px; animation-delay:.22s; }
.d3 { left:76px; top:54px; animation-delay:.48s; }
.d4 { left:42px; top:58px; animation-delay:.72s; }
.d5 { left:68px; top:60px; animation-delay:.98s; }
Could top left values. width 6. Fine.
For snow .flake: .f1 {left:20px; top:52px; ...} etc. Need line width scale if .f2 width 14: line width 100%. Good.
Storm .bolt top 44 left 50 width 34 height 54 margin-left -17. Good.
Keyframes:
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.07); } }
Note .sun-core transform scale. Good.
@keyframes rain-fall { ... }
@keyframes snow-fall { ... }
@keyframes flash { ... }
Reduced motion:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation: none !important; transition: none !important; }
.drop { opacity: .92; transform: translateY(18px) rotate(20deg); }
.d2 { transform: translateY(14px) rotate(20deg); } maybe no need.
.flake { opacity: .92; transform: translate(4px,12px) rotate(24deg); }
.bolt { opacity: .92; filter: drop-shadow(0 0 12px rgba(255,228,110,.9)); }
.sun-core { transform: scale(1); }
.sun-rays { transform: rotate(28deg); }
}
If .flake has child i absolute, no issue. If .flake animation none but initial opacity 0 override visible.
Potential issue .weather-card:hover transition disabled under reduced, so lift still transform? Hover will still transform because transition none? Actually transition none means instant, but transform on hover still occurs. That's okay? Respect reduced motion? Could disable hover transform too? To be safe: .weather-card:hover { transform:none; } under reduce? If transition none but transform applies, instant jump maybe not motion. But maybe we can add .weather-card:hover { transform: none; } to reduce. But requirement lift on hover maybe not essential in reduced. We can set .weather-card { transition:none } but hover transform could be abrupt. Better set .weather-card:hover { transform: translateY(-2px) scale(1.005)? } Or none. Use none.
@media reduce .weather-card:hover { transform:none; }
Need check if .sun-rays transform rotate under reduce? If .sun-rays base no transform; we can set. Good.
Let's consider visual: .rain-icon .cloud has ::before and ::after circles. But .snow-icon .cloud and .storm-icon .cloud may have same class but CSS variants override. We need define .rain-icon .cloud::before etc. But .snow-icon .cloud::before also should exist. Could share:
.cloud::before, .cloud::after { content:""; position:absolute; border-radius:50%; background:#fff; }
.cloud::before { width:44px; height:44px; left:-18px; top:-22px; }
.cloud::after { width:36px; height:36px; right:-14px; top:-16px; }
.cloud { position:absolute; left:50%; top:18px; width:76px; height:34px; margin-left:-38px; border-radius:999px; background:#fff; box-shadow...}
Then variant .rain-icon .cloud background gradient etc; .snow-icon .cloud top 16 background; .storm-icon .cloud background and top 12 width 84, height 38, margin-left -42. But if variant sets width/margin, pseudo positions relative maybe okay. For storm pseudo background need gray. Could set .storm-icon .cloud::before background:#657580; .storm-icon .cloud::after background:#52626e.
Need for snow pseudo maybe background white/#f7fcff. Could set .snow-icon .cloud::before background:#ffffff; ::after #f5faff.
However shared .cloud::before/after uses background #fff. For rain okay. For storm variant override.
Let's set:
.cloud { position:absolute; left:50%; top:20px; width:74px; height:32px; margin-left:-37px; border-radius:999px; background:linear-gradient(180deg,#fff,#dbeafe); box-shadow:0 10px 18px rgba(0,0,0,.15); }
.cloud::before, .cloud::after { content:""; position:absolute; border-radius:50%; background:inherit? background inherit? If .cloud background gradient, pseudo can't inherit gradient nicely? Could use background:#fff. Fine.
.cloud::before { width:42px;height:42px; left:-18px; top:-22px; }
.cloud::after { width:34px;height:34px; right:-14px;top:-14px; }
Variant:
.rain-icon .cloud { top:18px; background:linear-gradient(180deg,#ffffff,#d9ebff); }
.snow-icon .cloud { top:16px; width:72; height:30; background:linear-gradient(180deg,#ffffff,#e7f1ff); }
.storm-icon .cloud { top:12px; width:86px; height:38px; margin-left:-43px; background:linear-gradient(180deg,#697782,#2b3843); box-shadow:0 16px 24px rgba(0,0,0,.48); }
.storm-icon .cloud::before, .storm-icon .cloud::after { background:#606e78; }
.storm-icon .cloud::after { background:#4d5b66; }
Pseudo positions maybe need adjust width/height? For storm .cloud bigger but pseudo left/right relative okay. .before left -18 top -22 size 46? Could override .storm-icon .cloud::before { width:48px; height:48px; left:-22px; top:-24px; } .storm-icon .cloud::after { width:40px; height:40px; right:-18px; top:-18px; }.
But .cloud::before background may be overridden. Good.
Need ensure .storm-icon .cloud z-index above bolt? Bolt top 44, cloud top 12 height 38, bolt emerges below. If z-index not set, cloud after? HTML order cloud then bolt, bolt after cloud so drawn over. But cloud should be above bolt? Maybe bolt starts below cloud, so okay. Could add .storm-icon .cloud { z-index:2 } .bolt { z-index:1 }? If bolt top 44 and cloud bottom around 50, overlap maybe cloud should cover top of bolt. Use z-index. HTML order bolt after cloud; if no z-index, bolt on top. Better bolt below cloud. Add .storm-icon .cloud { z-index:3; } .storm-icon .bolt { z-index:1; } Good. For rain drops after cloud, drops drawn over cloud maybe okay but drops should start below cloud and not overlap cloud. Top 46 maybe near cloud bottom 50? Could be over cloud? Set .rain-icon .drop z-index:1; .rain-icon .cloud z-index:2. For snow too.
Let's set generic .icon .cloud { z-index: 2; } and drops/flakes/bolt z-index:1. But .sun no. .drop z-index:1, .flake z-index:1. .bolt z-index:1.
Potential overflow hidden on card means animations clipped within card; fine.
Check temperature degrees: Use 31°C. Good.
Need no horizontal scrollbar. Body padding 24px, width 100%. At 375 grid 1 col. Body padding maybe 16. Fine.
Let's ensure .weather-grid media:
@media (max-width:980px) { .weather-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width:640px) { .weather-grid { grid-template-columns: 1fr; } .weather-card { min-height:auto; } }
Maybe on 375, card padding reduces? .weather-card padding 18 12; icon 110. Fine.
Need maybe card description text color on bright sunny: dark. Good. On rain/snow maybe text-shadow. For snow card text #16375c. For rain white; use text-shadow. For storm white. For sunny dark; text-shadow maybe 0 1px 0 rgba(255,255,255,.35). We can set .sunny .temperature { text-shadow:0 1px 0 rgba(255,255,255,.35); }.
Need maybe card::after shine not essential.
Let's consider "rotating sun rays" — yes .sun-rays spin.
"falling rain drops" — yes.
"drifting snowflakes" — yes snow-fall with x drift.
"flashing lightning" — yes.
"Each card shows animated icon, city name, temperature, short description" — yes.
"background gradient matching weather" — yes.
"responsive grid 4 per row desktop, stacked mobile" — yes.
"lift on hover" — yes.
"Smooth infinite animations" — mostly smooth; lightning uses ease? We can avoid steps to smooth. But flash can be infinite. Use @keyframes lightning with discrete jumps? Smooth? It says smooth infinite animations using @keyframes. Could use ease-out for flash maybe. Lightning flashing can be abrupt. Fine.
"respect prefers-reduced-motion" — yes.
Need zero errors in console: CSS no errors. HTML no script.
Let's check if inline event handler? None.
Now, final should be code block with html. But user asked exactly one fenced code block. We'll output.
Double-check CSS syntax.
Let's write CSS in detail:
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
padding: 32px 20px;
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: radial-gradient(circle at 50% 0, #334a66, #07101b 58%, #02060c);
color: #e8f2ff;
display: flex;
justify-content: center;
}
.page {
width: min(1280px, 100%);
}
.intro {
text-align:center;
margin-bottom: 30px;
}
.intro h1 { ... }
Need body display flex might add vertical centering? .page width. okay.
.weather-card h2 etc margins.
Icon sun:
.ray background gradient might look line ends fade. With 4 bars and rotating.
@keyframes pulse transform scale. Because .sun-core uses inset:50%; margin negative; transform-origin center by default? If transform scale, origin center? yes.
Rain cloud:
.cloud { z-index:2; }
.drop { z-index:1; }
@keyframes rain-fall { 0% { opacity:0; transform: translateY(0) rotate(20deg); } 15% { opacity:1; transform: translateY(6px) rotate(20deg); } 80% { opacity:1; transform: translateY(34px) rotate(20deg); } 100% { opacity:0; transform: translateY(48px) rotate(20deg); } }
Need base left/top. Good.
.flake z-index 1; snow-fall keyframes.
.flake::before, ::after, .flake i { ... }
Need .flake i { z-index? no. }
Potential issue .flake i line and pseudo lines overlap; okay.
Set .flake { animation: snow-fall 4.5s ease-in-out infinite; }
.f2 width/height changes, but animation keyframe transform scale relative, line width based on current width. Good.
.bolt animation lightning. Need keyframe:
@keyframes lightning {
0%, 14%, 100% { opacity: .08; transform: rotate(2deg) scale(.98); }
16%, 20% { opacity: 1; transform: rotate(2deg) scale(1.05); }
22%, 26% { opacity: .2; transform: rotate(2deg) scale(1); }
28%, 34% { opacity: 1; transform: rotate(2deg) scale(1.03); }
36%, 50% { opacity: .05; transform: rotate(2deg) scale(.99); }
}
This gives smooth-ish. Use ease-out? animation-timing-function: ease-out. Good.
.bolt { animation: lightning 3.4s ease-out infinite; }
Could add filter drop-shadow in keyframes? We can set filter animation? Not necessary. But maybe base filter, at opacity changes filter persists. Good.
Could add .storm-icon::before? Maybe no.
Need ensure .storm-icon .bolt after cloud z-index maybe if cloud z-index 3 and bolt 1, but bolt after cloud in DOM, z-index overrides, bolt hidden behind cloud if overlap. Bolt top 46, cloud bottom top12+38=50, overlap 4px. Good.
Now check reduced: .drop visible with transform; .flake visible; .bolt visible. .sun-rays visible with rotate maybe. .weather-card:hover transform none. Add .weather-card:hover { transform: none; }.
Potential issue under reduced: .flake lines are white and visible. Good.
Let's consider if no JavaScript and "self-playing demo"? This is not game. Good.
Could "Absolutely no JavaScript" means no <script> anywhere. We comply.
Need final output no prose. Use ```html.
Let's maybe include more polish: cards have badge like "HUMIDITY"? Not required. Avoid clutter.
Could add subtle inner border highlight:
.weather-card::before { content:""; position:absolute; inset:0; background:linear-gradient(180deg, rgba(255,255,255,.28), transparent 35%); pointer-events:none; }
But for storm maybe. This doesn't hurt. But pseudo could interfere with icons? It is behind due to no z-index? Card content default stacking? .weather-card::before position absolute but no z-index, content after? Since ::before comes before children, maybe behind if children have position? Text not positioned? Could overlay? pointer-events none. z-index:0? Need not. We can omit to reduce risk.
But adding shine can make cards nicer. Ensure not covering. .weather-card::before { content:""; position:absolute; left:0; right:0; top:0; height:55%; background: linear-gradient(180deg, rgba(255,255,255,.2), rgba(255,255,255,0)); pointer-events:none; z-index:0; } .weather-card > * { position:relative; z-index:1; } But .icon has position; maybe children. Need add > *? If .icon position relative z-index auto maybe okay? If z-index 0 and icon no z-index, icon might be above? To be safe, avoid.
Card backgrounds gradients already nice.
Could add hover background brightness filter? transition filter? Not necessary.
Need final. Let's ensure no HTML invalid: <p class="temperature"> inside article with h2 then p. Good.
Potential issue using ° symbol without encoding? charset utf-8; okay. Use 31°C.
Potential issue line-height on temp, card min height. Good.
Let's maybe set max width cards? Fine.
Check responsive: On desktop 1280 viewport, 4 columns: each (1280 - 3*24)/4 = 302. Card min height 300. Body padding 32 20, header maybe ~80, total >800? 1280x800; page max width. Grid cards maybe 300; total height header 80+30+300=410, fits. Good. On 1000 width media 2 columns, fits. On mobile 375: cards full width, header maybe wraps, total height ~4*300 =1200 scroll vertical. No horizontal.
Need "first paint about 3 seconds without interaction" all visible. Good.
Let's ensure animations don't start hidden too long. Drops initial invisible for first ~0.2s then visible. Snow too. Lightning initial .08 maybe visible faintly. Fine.
Could use animation-delay negative to make some visible immediately. But not required. For first paint at 3s, all animated. Good.
Let's write final code cleanly.
Double-check CSS specificity for .storm-icon .cloud::before etc.
.shared cloud:
.cloud { position: absolute; z-index:2; ...}
.cloud::before, .cloud::after { content:""; position:absolute; border-radius:50%; background: #fff; }
.cloud::before { width:42px; height:42px; left:-17px; top:-21px; }
.cloud::after { width:34px; height:34px; right:-14px; top:-15px; }
.rain-icon .cloud { background: linear-gradient(180deg,#ffffff,#d8eaff); top:18px; }
.snow-icon .cloud { top:14px; background: linear-gradient(180deg,#ffffff,#e8f3ff); }
.storm-icon .cloud { top:10px; width:88px; height:38px; margin-left:-44px; background: linear-gradient(180deg,#71818d,#28333c); box-shadow: ... }
.storm-icon .cloud::before { width:50px; height:50px; left:-22px; top:-26px; background:#65737f; }
.storm-icon .cloud::after { width:42px; height:42px; right:-20px; top:-20px; background:#546371; }
Pseudo background overrides shared #fff.
Need drop/flake z-index:1 below cloud. .drop, .flake, .bolt { position:absolute; z-index:1; }. Good.
But .sun-core maybe no z-index.
Potential issue with .sun-rays .ray: .ray has transform rotate individually. Parent spin uses transform rotate on .sun-rays. Since .ray transform is not overridden by parent. Good.
Could there be layout issue: .icon width height, absolute rays; .sun-core center. Good.
Need check .sun-rays spin: animation transform rotate, but also .ray rotate values. If parent rotates, ray bars rotate around center. Good.
Let's maybe set .sunny-icon .sun-rays { transform-origin: 50% 50%; }.
Potential issue with .ray background gradient from rgba to solid; when rotated, gradient stays along bar. Good.
Now code final.
But we should consider if the demo may be compared visually; cards need distinct gradients and nice look. Could add small city/temperature text style maybe. Let's enhance.
Temperature degrees with <span class="unit">°C</span> maybe not necessary. Use 31°. Maybe 31°C bigger? 2.5rem. City name smaller.
Could include badges for condition? Not required.
Need "short description". Good.
Let's final. Ensure code block only.