Models 44

Qwen3.8 Max (0902)

by Qwenreasoning defaultClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
9 min 19 s
Cost
$0.153
Output tokens
25,238
Spent thinking
16,272 tokens
Speed
45.3 tok/s
Console errors
0
First token after
1.9 s
First visible text after
6 min 47 s
Prompt tokens
561
Code size
21.5 KB
Finish reason
stop
Served by
Alibaba
Model id
qwen/qwen3.8-max-0902
Reasoning sent
model default
Max output
131,072 tokens
Generated
Nov 12, 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 · 523 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Skycast — Four Weather Cards, Pure CSS</title>
<style>
/* ============ FOUNDATION ============ */
:root{
  --display: "Avenir Next", "Segoe UI Variable Display", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --serif: Georgia, "Times New Roman", serif;
  --mono: ui-monospace, "Cascadia Code", "SF Mono", Menlo, Consolas, "Courier New", monospace;
  --page-ink: #dfe7f2;
}
*{ margin:0; padding:0; box-sizing:border-box; }
html, body{ overflow-x:hidden; }
body{
  min-height:100vh;
  color:var(--page-ink);
  font-family:var(--display);
  background-color:#0b1120;
  background-image:
    radial-gradient(1100px 620px at 85% -10%, rgba(70,110,180,.28), transparent 60%),
    radial-gradient(900px 520px at 6% 110%, rgba(255,150,60,.12), transparent 60%),
    linear-gradient(180deg,#0e1729 0%, #0a0f1c 55%, #0b0e17 100%);
  background-attachment:fixed;
  padding: clamp(20px,4vh,44px) clamp(16px,4vw,44px) 56px;
}
/* dotted chart-paper texture */
body::before{
  content:""; position:fixed; inset:0; pointer-events:none; z-index:0;
  background-image: radial-gradient(rgba(255,255,255,.05) 1px, transparent 1.5px);
  background-size: 28px 28px;
}
/* slow-drifting ambient glow */
body::after{
  content:""; position:fixed; inset:-22%; pointer-events:none; z-index:0;
  background:
    radial-gradient(620px 420px at 30% 22%, rgba(90,140,220,.11), transparent 60%),
    radial-gradient(720px 520px at 76% 78%, rgba(255,170,80,.09), transparent 60%);
  animation: ambient 26s ease-in-out infinite alternate;
}
.wrap{ position:relative; z-index:1; max-width:1280px; margin:0 auto; }

/* ============ MASTHEAD ============ */
.masthead{
  display:flex; flex-wrap:wrap; align-items:flex-end; gap:14px 28px;
  padding-bottom:18px; margin-bottom:30px;
  border-bottom:1px solid rgba(255,255,255,.14);
}
.masthead__brand{ display:flex; flex-direction:column; gap:8px; }
.eyebrow{
  font-family:var(--mono); font-size:.6rem; font-weight:600;
  letter-spacing:.26em; text-transform:uppercase; color:rgba(223,231,242,.55);
}
h1{
  font-size:clamp(1.9rem,3.4vw,2.6rem); font-weight:800;
  letter-spacing:-.02em; color:#f5f8fc; line-height:1;
}
h1::after{
  content:""; display:block; width:58px; height:4px; margin-top:9px;
  border-radius:2px; background:#ffd84d;
}
.masthead__right{ margin-left:auto; display:flex; flex-direction:column; align-items:flex-end; gap:7px; }
.dateline{ font-family:var(--mono); font-size:.66rem; letter-spacing:.18em; text-transform:uppercase; color:rgba(223,231,242,.7); }
.live{
  display:inline-flex; align-items:center; gap:8px;
  font-family:var(--mono); font-size:.6rem; font-weight:700;
  letter-spacing:.24em; color:#7cf0b4;
}
.live i{
  width:8px; height:8px; border-radius:50%; background:#38e08b;
  box-shadow:0 0 0 0 rgba(56,224,139,.55);
  animation:pulse 2s ease-out infinite;
}

/* ============ GRID ============ */
.deck{ display:grid; gap:24px; grid-template-columns:1fr; }
@media (min-width:560px){ .deck{ grid-template-columns:repeat(2,1fr);} }
@media (min-width:1020px){ .deck{ grid-template-columns:repeat(4,1fr);} }

/* ============ CARD SHELL ============ */
.card{
  position:relative; display:flex; flex-direction:column; overflow:hidden;
  min-height:432px; padding:16px 18px 18px;
  border-radius:14px; border:1px solid var(--edge);
  color:var(--ink); background:var(--sky);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.22), 0 14px 30px -14px rgba(0,0,0,.5);
  transition: transform .4s cubic-bezier(.2,.8,.2,1), box-shadow .4s ease;
}
.card::after{ /* top-light sheen */
  content:""; position:absolute; inset:0; pointer-events:none; border-radius:inherit;
  background: linear-gradient(180deg, var(--shine), transparent 30%);
}
.card:hover{
  transform:translateY(-10px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 34px 62px -18px rgba(0,0,0,.62);
}
.card:active{ transform:translateY(-5px); }

/* palettes */
.card--sunny{
  --sky:linear-gradient(168deg,#ffe79f 0%,#ffb95e 48%,#ff7f3f 100%);
  --ink:#53290a; --muted:rgba(83,41,10,.8); --edge:rgba(255,255,255,.55);
  --tag-bg:rgba(255,255,255,.55); --tag-ink:#833f00; --shine:rgba(255,255,255,.3);
  --rule:rgba(90,40,0,.22); --idx:rgba(90,40,0,.16);
}
.card--rainy{
  --sky:linear-gradient(168deg,#5d7b98 0%,#31465f 52%,#1b2a3c 100%);
  --ink:#eef4fb; --muted:rgba(238,244,251,.72); --edge:rgba(255,255,255,.2);
  --tag-bg:rgba(255,255,255,.16); --tag-ink:#dbe9f7; --shine:rgba(255,255,255,.12);
  --rule:rgba(255,255,255,.18); --idx:rgba(255,255,255,.15);
}
.card--snowy{
  --sky:linear-gradient(168deg,#f3f9fe 0%,#d6e6f4 55%,#a8c3e0 100%);
  --ink:#20406b; --muted:rgba(32,64,107,.74); --edge:rgba(255,255,255,.7);
  --tag-bg:rgba(255,255,255,.72); --tag-ink:#2d5aa0; --shine:rgba(255,255,255,.4);
  --rule:rgba(32,64,107,.2); --idx:rgba(32,64,107,.14);
}
.card--stormy{
  --sky:linear-gradient(168deg,#3f3c58 0%,#232138 52%,#0f0e1a 100%);
  --ink:#f2efff; --muted:rgba(242,239,255,.7); --edge:rgba(255,255,255,.16);
  --tag-bg:rgba(255,217,74,.16); --tag-ink:#ffd94a; --shine:rgba(255,255,255,.1);
  --rule:rgba(255,255,255,.16); --idx:rgba(255,255,255,.14);
}

/* ============ CARD TEXT ============ */
.card__meta{ display:flex; justify-content:space-between; align-items:center; gap:10px; }
.tag{
  font-family:var(--mono); font-size:.6rem; font-weight:700;
  letter-spacing:.18em; text-transform:uppercase;
  padding:.5em .9em .45em; border-radius:999px;
  background:var(--tag-bg); color:var(--tag-ink);
}
.clock{ font-family:var(--mono); font-size:.6rem; letter-spacing:.16em; text-transform:uppercase; opacity:.72; }

.scene{
  position:relative; height:192px; margin:8px 0 6px; overflow:hidden;
  border-radius:12px;
  transition: transform .5s cubic-bezier(.2,.7,.2,1);
}
.card:hover .scene{ transform:scale(1.05); }
.index{
  position:absolute; top:8px; right:12px; z-index:3;
  font-family:var(--mono); font-weight:700; font-size:2rem; color:var(--idx);
  letter-spacing:-.05em;
}

.card__main{ display:flex; justify-content:space-between; align-items:flex-end; gap:10px; margin-top:2px; }
.city{ font-size:1.45rem; font-weight:800; letter-spacing:-.01em; line-height:1.1; }
.region{ font-family:var(--mono); font-size:.58rem; letter-spacing:.2em; text-transform:uppercase; color:var(--muted); margin-top:4px; }
.temp{ font-size:3rem; font-weight:800; letter-spacing:-.04em; line-height:.9; white-space:nowrap; }
.temp span{ font-size:.45em; font-weight:600; vertical-align:.9em; margin-left:1px; opacity:.75; }

.desc{
  font-family:var(--serif); font-style:italic; font-size:.93rem;
  line-height:1.5; color:var(--muted); margin-top:10px;
}
.stats{
  margin-top:auto; padding-top:12px; border-top:1px solid var(--rule);
  font-family:var(--mono); font-size:.58rem; font-weight:600;
  letter-spacing:.14em; text-transform:uppercase; color:var(--muted);
  display:flex; flex-wrap:wrap; gap:6px 0;
}
.stats b{ font-weight:600; color:var(--ink); opacity:.85; }
.stats .dot{ margin:0 8px; opacity:.5; }

/* ============ SUNNY ICON ============ */
.sun{ position:absolute; left:50%; top:14px; width:150px; height:150px; margin-left:-75px; animation:float 7s ease-in-out infinite alternate; }
.sun__halo{
  position:absolute; inset:-8px; border-radius:50%; filter:blur(9px);
  background:radial-gradient(circle, rgba(255,216,120,.6), transparent 68%);
  animation:haloPulse 4s ease-in-out infinite alternate;
}
.sun__rays{ position:absolute; inset:0; animation:spin 26s linear infinite; filter:drop-shadow(0 0 7px rgba(255,190,80,.55)); }
.sun__rays i{
  position:absolute; left:50%; top:50%; width:150px; height:6px; margin:-3px 0 0 -75px;
  border-radius:999px;
  background:linear-gradient(90deg, rgba(255,213,112,.95) 0 18%, transparent 31% 69%, rgba(255,213,112,.95) 82% 100%);
}
.sun__rays i:nth-child(1){ transform:rotate(0deg); }
.sun__rays i:nth-child(2){ transform:rotate(30deg); }
.sun__rays i:nth-child(3){ transform:rotate(60deg); }
.sun__rays i:nth-child(4){ transform:rotate(90deg); }
.sun__rays i:nth-child(5){ transform:rotate(120deg); }
.sun__rays i:nth-child(6){ transform:rotate(150deg); }
.sun__core{
  position:absolute; inset:40px; border-radius:50%;
  background:radial-gradient(circle at 34% 30%, #fff3b0, #ffd23f 48%, #ff9d2e 100%);
  box-shadow:0 0 30px 5px rgba(255,196,64,.6), inset -6px -9px 18px rgba(230,96,10,.4);
  animation:coreGlow 4s ease-in-out infinite alternate;
}
/* small drifting cloud crossing the sun */
.cloud--drift{
  --cbg:rgba(255,255,255,.75);
  width:72px; height:22px; top:52px; left:50%; margin-left:-36px; z-index:2;
  filter:drop-shadow(0 6px 8px rgba(214,110,20,.3));
  animation:drift 26s linear infinite;
}
.cloud--drift::before{ width:30px; height:30px; top:-16px; left:9px; }
.cloud--drift::after{ width:21px; height:21px; top:-10px; right:11px; }
.mote{
  position:absolute; bottom:34px; width:4px; height:4px; border-radius:50%;
  background:rgba(255,244,205,.9); opacity:.4;
  animation:moteUp 5.5s linear infinite;
}
.mote:nth-child(2){ left:18%; animation-delay:-1.4s; }
.mote:nth-child(3){ left:30%; bottom:22px; animation-delay:-3.2s; }
.mote:nth-child(4){ left:72%; animation-delay:-.6s; }
.mote:nth-child(5){ left:84%; bottom:44px; animation-delay:-4.3s; }

/* ============ SHARED CLOUD ============ */
.cloud{
  position:absolute; width:130px; height:40px; border-radius:999px;
  background:var(--cbg);
  animation:sway 5.5s ease-in-out infinite alternate;
}
.cloud::before,.cloud::after{
  content:""; position:absolute; background:var(--cbg); border-radius:50%;
}
.cloud::before{ width:54px; height:54px; top:-28px; left:16px; }
.cloud::after{ width:38px; height:38px; top:-18px; right:20px; }

/* ============ RAINY ICON ============ */
.cloud--rain{
  --cbg:#c9d6e3; top:36px; left:calc(50% - 65px);
  filter:drop-shadow(0 16px 16px rgba(8,16,28,.45));
}
.cloud--rain-mini{
  --cbg:rgba(201,214,227,.55); width:82px; height:26px; top:16px; left:auto; right:6%;
  animation:sway 6.5s ease-in-out -2.2s infinite alternate;
}
.cloud--rain-mini::before{ width:34px; height:34px; top:-18px; left:10px; }
.cloud--rain-mini::after{ width:24px; height:24px; top:-11px; right:12px; }
.drops{ position:absolute; top:78px; left:calc(50% - 62px); width:124px; height:76px; }
.drops i{
  position:absolute; top:0; width:3px; height:13px; border-radius:4px;
  background:linear-gradient(180deg, rgba(190,228,255,.15), var(--drop, rgba(180,222,255,.95)));
  opacity:.75; transform:translateY(26px) rotate(var(--tilt,15deg));
  animation:fall 1.2s linear infinite;
}
.drops i:nth-child(1){ left:5%;  animation-delay:-.15s; animation-duration:1.12s; }
.drops i:nth-child(2){ left:20%; animation-delay:-.62s; animation-duration:1.26s; }
.drops i:nth-child(3){ left:35%; animation-delay:-.34s; animation-duration:1.05s; }
.drops i:nth-child(4){ left:50%; animation-delay:-.86s; animation-duration:1.2s;  }
.drops i:nth-child(5){ left:65%; animation-delay:-.48s; animation-duration:1.1s;  }
.drops i:nth-child(6){ left:80%; animation-delay:-.95s; animation-duration:1.3s;  }
.drops i:nth-child(7){ left:94%; animation-delay:-.25s; animation-duration:1.16s; }

/* ============ SNOWY ICON ============ */
.cloud--snow{
  --cbg:#ffffff; top:36px; left:calc(50% - 65px);
  filter:drop-shadow(0 16px 16px rgba(50,90,150,.3));
}
.cloud--snow-mini{
  --cbg:rgba(255,255,255,.7); width:78px; height:25px; top:20px; left:6%;
  animation:sway 7s ease-in-out -3s infinite alternate;
}
.cloud--snow-mini::before{ width:32px; height:32px; top:-17px; left:9px; }
.cloud--snow-mini::after{ width:22px; height:22px; top:-10px; right:11px; }
.flakes{ position:absolute; top:82px; left:calc(50% - 66px); width:132px; height:96px; }
.flakes i{
  position:absolute; top:0; width:2.5px; height:16px; border-radius:2px;
  color:#ffffff; background:currentColor;
  box-shadow:0 0 5px rgba(255,255,255,.85);
  opacity:.9; transform:translate(4px,42px) rotate(30deg);
  animation:snowfall 4.2s linear infinite;
}
.flakes i::before,.flakes i::after{
  content:""; position:absolute; inset:0; border-radius:inherit;
  background:currentColor;
}
.flakes i::before{ transform:rotate(60deg); }
.flakes i::after{ transform:rotate(-60deg); }
.flakes i:nth-child(1){ left:12%; --sw:12px; animation-delay:-.4s; animation-duration:4s; }
.flakes i:nth-child(2){ left:48%; --sw:-10px; height:12px; animation-delay:-2.1s; animation-duration:3.5s; }
.flakes i:nth-child(3){ left:80%; --sw:14px; height:19px; animation-delay:-1.2s; animation-duration:4.6s; }
.specks{ position:absolute; top:84px; left:calc(50% - 62px); width:124px; height:90px; }
.specks i{
  position:absolute; top:0; width:4px; height:4px; border-radius:50%;
  background:rgba(255,255,255,.92); opacity:.8; transform:translateY(30px);
  animation:speckFall 3.2s linear infinite;
}
.specks i:nth-child(1){ left:24%; animation-delay:-.9s; }
.specks i:nth-child(2){ left:38%; animation-delay:-2.3s; animation-duration:3.7s; }
.specks i:nth-child(3){ left:64%; animation-delay:-.4s; animation-duration:2.9s; }
.specks i:nth-child(4){ left:90%; animation-delay:-1.6s; }

/* ============ STORMY ICON ============ */
.cloud--storm{
  --cbg:#4d5470; width:142px; height:44px; top:30px; left:calc(50% - 71px);
  filter:drop-shadow(0 16px 18px rgba(0,0,0,.5));
  animation:cloudJolt 3.6s linear infinite;
}
.cloud--storm::before{ width:58px; height:58px; top:-30px; left:18px; }
.cloud--storm::after{ width:40px; height:40px; top:-19px; right:20px; }
.cloud--storm-mini{
  --cbg:rgba(77,84,112,.6); width:80px; height:25px; top:14px; left:auto; right:4%;
  animation:sway 6s ease-in-out -1.6s infinite alternate;
}
.cloud--storm-mini::before{ width:32px; height:32px; top:-17px; left:10px; }
.cloud--storm-mini::after{ width:22px; height:22px; top:-10px; right:11px; }
.bolt{
  position:absolute; top:70px; left:calc(50% - 17px); width:36px; height:66px; z-index:2;
  background:linear-gradient(180deg,#fff8cf 0%,#ffdf4d 55%,#ffb300 100%);
  clip-path:polygon(65% 0%, 22% 52%, 46% 52%, 16% 100%, 76% 40%, 50% 40%, 90% 0%);
  filter:drop-shadow(0 0 9px rgba(255,214,60,.9));
  opacity:.92;
  animation:boltFlash 3.6s linear infinite;
}
.drops--storm{ top:82px; --tilt:26deg; --dist:74px; --drop:rgba(160,190,255,.9); }
.drops--storm i{ height:15px; animation-duration:.85s; }
.drops--storm i:nth-child(1){ left:8%;  animation-delay:-.1s; }
.drops--storm i:nth-child(2){ left:30%; animation-delay:-.45s; }
.drops--storm i:nth-child(3){ left:52%; animation-delay:-.28s; animation-duration:.78s; }
.drops--storm i:nth-child(4){ left:74%; animation-delay:-.6s; }
.drops--storm i:nth-child(5){ left:92%; animation-delay:-.36s; animation-duration:.9s; }
.scene--storm::after{ /* sky lightning wash */
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(circle at 54% 28%, rgba(255,240,180,.55), transparent 62%);
  opacity:0; animation:sceneFlash 3.6s linear infinite;
}

/* ============ KEYFRAMES ============ */
@keyframes spin{ to{ transform:rotate(360deg); } }
@keyframes float{ from{ transform:translateY(-4px); } to{ transform:translateY(4px); } }
@keyframes haloPulse{ from{ opacity:.5; transform:scale(.96); } to{ opacity:.95; transform:scale(1.07); } }
@keyframes coreGlow{
  from{ box-shadow:0 0 24px 4px rgba(255,196,64,.5), inset -6px -9px 18px rgba(230,96,10,.38); }
  to  { box-shadow:0 0 46px 11px rgba(255,208,86,.82), inset -6px -9px 18px rgba(230,96,10,.38); }
}
@keyframes drift{ from{ transform:translateX(-175px); } to{ transform:translateX(175px); } }
@keyframes sway{ from{ transform:translateX(-5px); } to{ transform:translateX(5px); } }
@keyframes moteUp{
  0%{ transform:translateY(0); opacity:0; }
  20%{ opacity:.7; }
  100%{ transform:translateY(-52px); opacity:0; }
}
@keyframes fall{
  0%{ transform:translate3d(0,-6px,0) rotate(var(--tilt,15deg)); opacity:0; }
  15%{ opacity:.95; }
  78%{ opacity:.9; }
  100%{ transform:translate3d(-8px, var(--dist,62px), 0) rotate(var(--tilt,15deg)); opacity:0; }
}
@keyframes snowfall{
  0%{ transform:translate3d(-4px,-6px,0) rotate(0deg); opacity:0; }
  12%{ opacity:.95; }
  88%{ opacity:.9; }
  100%{ transform:translate3d(var(--sw,10px), 86px, 0) rotate(170deg); opacity:0; }
}
@keyframes speckFall{
  0%{ transform:translateY(-4px); opacity:0; }
  15%{ opacity:.85; }
  100%{ transform:translateY(82px); opacity:0; }
}
@keyframes boltFlash{
  0%,69%{ opacity:0; }
  70%{ opacity:1; }
  72%{ opacity:.15; }
  74%{ opacity:1; }
  78%,100%{ opacity:0; }
}
@keyframes sceneFlash{
  0%,69%{ opacity:0; }
  70%{ opacity:.45; }
  72%{ opacity:.06; }
  74%{ opacity:.4; }
  78%,100%{ opacity:0; }
}
@keyframes cloudJolt{
  0%,69%,79%,100%{ transform:translateX(0); }
  71%{ transform:translateX(-2.5px); }
  75%{ transform:translateX(2.5px); }
}
@keyframes ambient{
  from{ transform:translate3d(-2%,-1%,0) scale(1); }
  to{ transform:translate3d(2%,2%,0) scale(1.06); }
}
@keyframes pulse{
  0%{ box-shadow:0 0 0 0 rgba(56,224,139,.55); }
  100%{ box-shadow:0 0 0 10px rgba(56,224,139,0); }
}

/* ============ FOOTER ============ */
.colophon{
  margin-top:34px;
  font-family:var(--mono); font-size:.6rem; letter-spacing:.16em;
  text-transform:uppercase; color:rgba(223,231,242,.45);
}
.colophon .dot{ margin:0 8px; opacity:.6; }

/* ============ REDUCED MOTION ============ */
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{
    animation: none !important;
    transition: none !important;
  }
}
</style>
</head>
<body>
<div class="wrap">

  <header class="masthead">
    <div class="masthead__brand">
      <p class="eyebrow">Pure HTML + CSS · every icon drawn in CSS · zero JavaScript</p>
      <h1>Skycast</h1>
    </div>
    <div class="masthead__right">
      <p class="dateline">Tuesday · 14:00 UTC</p>
      <span class="live"><i></i>LIVE FEED</span>
    </div>
  </header>

  <main class="deck">

    <!-- SUNNY -->
    <article class="card card--sunny">
      <div class="card__meta">
        <span class="tag">Clear</span>
        <span class="clock">Tue · 09:40</span>
      </div>
      <div class="scene">
        <b class="index">01</b>
        <i class="mote"></i><i class="mote"></i><i class="mote"></i><i class="mote"></i>
        <div class="sun">
          <span class="sun__halo"></span>
          <span class="sun__rays"><i></i><i></i><i></i><i></i><i></i><i></i></span>
          <span class="sun__core"></span>
        </div>
        <div class="cloud cloud--drift"></div>
      </div>
      <div class="card__main">
        <div>
          <h2 class="city">Lisbon</h2>
          <p class="region">Portugal · W Europe</p>
        </div>
        <p class="temp">29<span>°</span></p>
      </div>
      <p class="desc">High sun and dry heat — a hard blue sky that holds until dusk.</p>
      <footer class="stats"><b>SW 12 km/h</b><span class="dot">·</span><b>Humidity 28%</b><span class="dot">·</span><b>UV 8</b></footer>
    </article>

    <!-- RAINY -->
    <article class="card card--rainy">
      <div class="card__meta">
        <span class="tag">Showers</span>
        <span class="clock">Tue · 14:20</span>
      </div>
      <div class="scene">
        <b class="index">02</b>
        <div class="cloud cloud--rain-mini"></div>
        <div class="cloud cloud--rain"></div>
        <div class="drops"><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div>
      </div>
      <div class="card__main">
        <div>
          <h2 class="city">Bergen</h2>
          <p class="region">Norway · North Sea</p>
        </div>
        <p class="temp">11<span>°</span></p>
      </div>
      <p class="desc">Steady Atlantic showers rolling in off the fjord all afternoon.</p>
      <footer class="stats"><b>W 22 km/h</b><span class="dot">·</span><b>Humidity 88%</b><span class="dot">·</span><b>Rain 6 mm</b></footer>
    </article>

    <!-- SNOWY -->
    <article class="card card--snowy">
      <div class="card__meta">
        <span class="tag">Snowfall</span>
        <span class="clock">Tue · 21:05</span>
      </div>
      <div class="scene">
        <b class="index">03</b>
        <div class="cloud cloud--snow-mini"></div>
        <div class="cloud cloud--snow"></div>
        <div class="specks"><i></i><i></i><i></i><i></i></div>
        <div class="flakes"><i></i><i></i><i></i></div>
      </div>
      <div class="card__main">
        <div>
          <h2 class="city">Sapporo</h2>
          <p class="region">Japan · Hokkaidō</p>
        </div>
        <p class="temp">−2<span>°</span></p>
      </div>
      <p class="desc">Soft, fat flakes settling over the rooftops through the night.</p>
      <footer class="stats"><b>NW 9 km/h</b><span class="dot">·</span><b>Snow 14 cm</b><span class="dot">·</span><b>Vis 2 km</b></footer>
    </article>

    <!-- STORMY -->
    <article class="card card--stormy">
      <div class="card__meta">
        <span class="tag">Thunder</span>
        <span class="clock">Tue · 17:55</span>
      </div>
      <div class="scene scene--storm">
        <b class="index">04</b>
        <div class="cloud cloud--storm-mini"></div>
        <div class="cloud cloud--storm"></div>
        <div class="bolt"></div>
        <div class="drops drops--storm"><i></i><i></i><i></i><i></i><i></i></div>
      </div>
      <div class="card__main">
        <div>
          <h2 class="city">Chicago</h2>
          <p class="region">USA · Lake Michigan</p>
        </div>
        <p class="temp">18<span>°</span></p>
      </div>
      <p class="desc">Black cumulus stacking up with sharp bursts of rain and lightning.</p>
      <footer class="stats"><b>SW 41 km/h</b><span class="dot">·</span><b>Humidity 76%</b><span class="dot">·</span><b>CAPE high</b></footer>
    </article>

  </main>

  <footer class="colophon">
    Four forecasts<span class="dot">·</span>spinning rays, falling rain, drifting snow, striking lightning — all @keyframes<span class="dot">·</span>honors prefers-reduced-motion
  </footer>

</div>
</body>
</html>
Reasoning trace (16,272 tokens)
The user is asking for 4 animated weather cards (sunny, rainy, snowy, stormy) using HTML and CSS only. No JavaScript whatsoever. No images, no SVG, no icon fonts. All icons built from HTML elements and pseudo-elements. Each card: animated icon, city name, temperature, short description. Unique background gradients per weather type. Responsive grid: 4 columns on desktop, stacked vertically on mobile. Lift effect on hover. Smooth infinite @keyframes, with prefers-reduced-motion support.

This has to be self-contained HTML. It's a static CSS demo, not a game — but it should still look vibrant, be polished, and have rich motion and micro-interactions. Focus on: rich layered backgrounds, animated icons, hover effects, strong typographic contrast.

Design direction: weather cards. Make each card feel like a little atmospheric scene rather than a flat card with an icon. Ideas:

- Sunny: warm golden gradient sky, a sun with a glowing core, spinning rays, maybe a subtle rotating halo, and drifting clouds too? The sun rays could be 8–12 rays created by multiple elements or rotated pseudo-elements. Building many rays from a single element is hard; can use a few child spans each containing a pseudo-element, rotated via transform. Example: `.sun-rays span:nth-child(n)` rotated. The task requires building icons from HTML elements and pseudo-elements — spans are fine.

Better: `<div class="rays"><i></i>×6</div>` with each `<i>` rotated in 30° increments (each i displays two opposing rays, so 6 elements = 12 rays). Animate the container to rotate slowly. The core is a circle with box-shadow glow and a pulsing animation.

- Rainy: cloud built from element + pseudo-elements (circles), raindrops are multiple `<i>` elements animating translateY and fading in/out. Cloud sways gently. Dark slate-blue gradient background.

- Snowy: cloud + snowflakes drifting down while swaying laterally. Snowflake shapes: small dots, or using the ❄ character? "No icon fonts" — text glyphs from a font might count as icons; pure CSS shapes are safer. Snowflakes as small circles/rounded squares with blur, drifting while rotating. Or actual 6-armed flakes with crossed bars and pseudo-elements — might be overkill; small glowing dots of varying size/speed look elegant and obviously "snow". Could also make 2–3 real flake shapes with crossed bars for authenticity, plus small dots. Going with the crossed-bar flakes — 3 `<i>` elements each forming a 6-point asterisk with bar + ::before/::after rotated ±60°. Then add small dot snow particles. Nice.

- Stormy: dark cloud, flashing lightning bolt made from CSS shapes (stacked triangles/clipped polygons shapes). Lightning flashes: opacity keyframes with jagged timing; the entire card background also flashes subtly (animated overlay). Rain inside the storm too. Lightning via clip-path polygon on a div — clip-path is CSS, fine.

Typography: distinctive display face + readable body face. No external fonts (no network requests). So I have to use system font stacks while still pairing a display stack and a body stack. I can get a display feel with system fonts: for display `font-family: "Futura", "Avenir Next", "Segoe UI", ...` bold weight, tight tracking; body "Georgia"? A serif body over the weather cards might feel strange; but a distinctive pairing is wanted. Maybe display: "Avenir Next Condensed", "Arial Narrow"... hmm. Options without webfonts: display = "Palatino"? Let me think about aesthetic: weather dashboard, cinematic. Going with heavy grotesque headline with tight letter spacing: `font-family: "Helvetica Neue", "Segoe UI", system-ui` with font-weight 800 and large temperature digits, and a lighter face for descriptions `"Georgia", serif` italic for mood descriptions ("Clear skies all day") — serif italic descriptions would feel like an almanac and distinctive. Actually this pairing (bold sans-serif numbers + serif italic mood line) is charming, like a modern take on a farmers' almanac. Monospace for labels too: `"Courier New"` small-caps-ish labels like "TUESDAY · 14:00"? Monospace small labels give it a dashboard feel. Three layers: mono micro-labels, huge sans-serif temperature, serif italic description. Distinctive without webfonts.

Background behind the grid: layered ambient — deep night-sky-ish gradient? The cards have their own gradients; the page background should complement. Maybe a subtly animated gradient and a dark base with a drifting haze (pseudo-element). Keep it tasteful. Page header: something weather-forecast-y — like a masthead "SKY REPORT" with a date line, left-aligned masthead with a thin rule line. Keep it modest; the cards are the star, visible on first paint at 1280×800: header + one row of cards should fit within 800px height. Keep the header compact.

Layout: grid: `grid-template-columns: repeat(auto-fit, minmax(240px, 1fr))` with max-width 1200 for 4 columns on desktop. At 1280 → 4 columns. Stacks at 375. On hover: translateY(-8px) + shadow intensify + slight icon scale.

Card design details: each card ~ landscape portrait? Aspect ratio about 3/4 or fixed height around 380px. Icon scene at top (height ~180px), then text. Big temperature (like 44px–56px), small °. Mono uppercase city with letter-spacing? Or a big display city name. Let's do: mono top row with the condition label ("CLEAR SKIES" tag / "CONDITION 01"?), a scene area, then city name (large), temperature huge, description serif italic, and an additional meta row (wind/humidity as pseudo-data?). The requirements are city, temperature, description — extra meta adds richness (wind, humidity chips). Add small stats row: mono tiny "SW 12 km/h · 34%". Good.

Card gradient:
- Sunny: warm amber/orange sky: linear-gradient(160deg, #ffd76f, #ff9d3f, #f4572f)? Plus a radial sun glow overlay.
- Rainy: deep blue slate: #33415c → #1f2733? Teal-ish rain: #3a6073 → #16222a.
- Snowy: icy pale: #cfe3f2 → #8fb3d9? Light card needs dark text. Hmm, mixing text colors between cards adds complexity but is richer: sunny/snowy are light backgrounds → dark ink text; rainy/stormy are dark → light text. Manageable with per-card classes.
- Stormy: near-black purple-slate: #2b2b3d → #0d0d17 with flashes.

Text color is set per card via a custom property `--ink`.

Scene layering: each `.scene` contains the icon composition and ambient extras (like drifting haze pseudo-elements). Add subtle scene backgrounds: e.g. rainy card with a faint diagonal streak overlay animated? Already have drops; good.

Construction of the sunny icon:
```html
<div class="icon sun">
  <div class="rays"><i></i>×6</div>
  <div class="core"></div>
  <div class="halo"></div>
</div>
```
Rays: each `<i>` is absolutely centered, width: 4px? Each ray via border? Simplest: an `i` is a full-size cross-bar: width: 100%; height: 3px, background, border-radius, rotate in 30° increments → 12 ray ends. But rays should start away from the core: use a bar with transparent middle? Better: make each `i` two rays via ::before/::after placed at top and bottom? Alternative: a bar with a gradient background to make the center transparent: `background: linear-gradient(90deg, color 0 22%, transparent 30% 70%, color 78% 100%)`. This gives two opposing ray segments. 6 bars × 30° = 12 rays. Animate `.rays` rotating 360° linearly infinite over ~20s. Core: a circle with inner gradient and pulsing glow box-shadow (animation that scales/shadows). Halo: a big blurred circle pulsing in opacity.

Rainy icon: cloud: a rounded rectangular base with ::before/::after circles. Then drops: `.drops i` (maybe 7 of them) absolutely positioned with varying left, each `animation: fall 1.1s linear infinite` with delays, `transform: translateY(0)→56px; opacity 0→1→0`. Slanted slightly: rotate the drop shape; drop shape: width 3px height 12px border-radius 50%/bottom? teardrop: `border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%` or just a slightly rotated round pill. Cloud sways: translateX ±4px ease-in-out alternate.

Snowy icon: cloud (lighter) + flakes: 3 big crossed flakes + 4 tiny dots. Big flakes: `.flake i` element width 2px height 14px background white, with ::before/::after same bars rotated 60/-60 → 6 arms; animate fall + sway using two animations? Sway via keyframe translate combining X and Y: keyframes snowfall { 0% translate3d(0,-10px,0) rotate(0); 100% translate3d(±8px, 60px,0) rotate(120deg);} with opacity fade. Vary with nth-child delays/durations.

Stormy: dark cloud + lightning bolt: `.bolt` with clip-path polygon of lightning; white-yellow; animate flash: `@keyframes flash { 0%,86%,92%,98% opacity 0; 88%,94%,100%? }` classic: mostly hidden, quick double flash. Also a glow with filter drop-shadow (filter allowed) or box-shadow can't be used on clip-path shapes... use `filter: drop-shadow(0 0 6px rgba(255,220,90,.8))`. Also, animate a scene overlay `::after` opacity for background flash. Rain streaks in storm too (reuse drops with faster fall, slanted).

Cloud shapes: build a reusable class `.cloud` with body (border-radius 999px) and ::before/::after bumps. Different sizes/colors per card.

Handling text colors: define per card:
```
.card--sunny { --ink:#4a2a04; background: ...; }
```
Sunny card: light yellow background with dark brown ink. Snowy: pale ice with deep blue ink. Rainy/stormy: light text.

Temperature display: big numbers and superscript °: `<span class="temp">29<sup>°</sup></span>` or with a small C? "29°" is enough.

Card header micro-label: e.g. "TUE · 09:00" etc. and a condition tag. Composition of card:

```
<article class="card card--sunny">
  <header class="card__meta">
    <span class="tag">Clear</span>
    <span class="clock">Tue · 09:00</span>
  </header>
  <div class="scene"> ...icon elements... </div>
  <h2 class="city">Lisbon</h2>
  <p class="temp">29°</p>
  <p class="desc">High sun, dry heat and a bright blue sky until dusk.</p>
  <footer class="stats">SW 12 km/h <span>·</span> Humidity 28%</footer>
</article>
```

Cities: sunny → Lisbon or Seville; rainy → Bergen or London; snowy → Sapporo or Helsinki; stormy → Chicago or Miami. Nice picks: Lisbon, Bergen, Sapporo, Chicago.

Descriptions (short):
- Sunny: "Clear skies and a warm golden light all afternoon."
- Rainy: "Steady showers rolling in from the North Sea."
- Snowy: "Soft, steady flakes settling over the city overnight."
- Stormy: "Thunderheads building with sharp bursts of rain."

Hover lift: `.card:hover { transform: translateY(-10px); box-shadow bigger; }` with transition. Also `.card:hover .sun .rays { animation-duration: 6s }`? Speed-up on hover is a nice micro-interaction (pure CSS). Also scale the scene slightly.

prefers-reduced-motion: reduce → set all animations to none (or keep static). `@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }` but this kills everything; then the icons are shown in a static state — drop animation needs a sensible static state: the fall animation moves opacity; if animation removed, element displays with base styles — make base style of drops visible (a few drops) so the static state looks good too: set base opacity to 0.9? But during animation it's overridden anyway. Hmm: keyframe 0% opacity 0. If animation runs, it controls. If no animation, element shows with base styles → make base state a pleasant static composition: drops positioned and visible, snowflakes visible. Good approach.

Also disable the lift transition under reduced motion.

Grid responsiveness:
```
.grid { display:grid; gap: 22px; grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1100px) { 2 columns }
@media (max-width: 620px) { 1 column }
```
Requirement is 4 per row desktop, stacked on mobile. Use auto-fit minmax? Explicit breakpoints are more predictable: `repeat(auto-fit, minmax(250px,1fr))` gives 4 columns at 1280 (container ~1200 → 4×~280). At 375 → 1 column. But intermediate widths could give 3 → fine. Going with explicit media queries for certainty, plus maybe a container max-width 1240 and padding.

Page background: dark blue-slate with subtle animated haze: body::before radial gradients drifting slowly (transform translate) — an ambient layer. Maybe a faint grid of stars/dots via repeating gradient? Subtle. Also give the page a mono top masthead: big "WEATHERDECK"? Title idea: "The Sky, Today" — masthead: left: big display title "SKY CONDITIONS"; right: mono date. Keep it compact (fit within 800px height: header ~120px, cards ~520px height?). Card heights: scene 170 + text ~... total maybe 400–460. Header 100 + cards 460 + margins = ~600–700, fits within 800. Good. Card min-height around 420.

Also a small footer line? Maybe a tiny footer "HTML + CSS only — no JavaScript, no images". Modest.

Card hover lift: transform translateY(-8px) scale(1.01); deepen shadow. Transition .35s cubic-bezier. Also focus-visible for accessibility: cards as <article>, add tabindex? Not needed; keeping focus is fine. Could add `.card:focus-within` but no interactive children. Skip.

Now colors per card:

Sunny gradient: `linear-gradient(165deg,#ffe29a 0%, #ffb45e 45%, #ff7a3d 100%)` with maybe a radial highlight top-left. Ink: #59300a / darker #3f1f04. Tag bg rgba(255,255,255,.45) with dark text.

Snowy: `linear-gradient(165deg,#eef6fc, #cfe0f1 55%, #9fb9d8)` ink #25406b.

Rainy: `linear-gradient(165deg,#4a6a8a? )` rainy mood: top #55708c → bottom #22344a? Let's do `linear-gradient(170deg,#5d7b98, #2c4059 55%, #1a2a3d)`. Ink #eaf2fa.

Stormy: `linear-gradient(170deg,#3c3a52, #1d1c2e 55%, #0e0d18)` ink #f2efff. Accent yellow #ffd94a.

Also add a subtle top scene overlay per card (white/black radial) for depth.

Icon colors: sun core #ffdd55 → #ff9d2e gradient, rays #ffd76a. Rain cloud: slate #aebfd2 top with a darker base? Rain cloud is grayish blue: body #9fb2c6, drops #bfe3ff / rgba(190,225,255,.9). Snow cloud: white #fff with soft shadow, flakes white with a light-blue glow. Storm cloud: dark #3a3f55 / #2a2e42 with rim light, bolt #ffe066.

Card radius: keep varied rather than one uniform large radius. Let's go with 12px. Keep it simple: border-radius 12px; border: 1px solid var(--edge) with --edge rgba(white,.25) for dark cards / rgba(black,.08) for light.

Card inner texture: subtle noise? repeating-linear-gradient? Might add subtle diagonal shimmer overlay via ::after with a radial highlight — cheap depth.

Now let's write the final code carefully.

Key dimensions: card padding 18px; scene height 190px? Total card height: meta 24 + scene 190 + city 30 + temp 60 + desc ~40 + stats 20 + padding → ~400. Good.

Let me spell out all the icon markup:

Sunny scene:
```html
<div class="scene scene--sunny">
  <i class="mote" style? no inline? 
```
Inline styles are allowed (not event handlers). But cleaner: use nth-child. Motes: 4 `<i>` positioned via nth-child.

Sun markup:
```html
<div class="sun">
  <span class="sun__halo"></span>
  <span class="sun__rays">
    <i></i><i></i><i></i><i></i><i></i><i></i>
  </span>
  <span class="sun__core"></span>
</div>
```

Rainy:
```html
<div class="cloud cloud--rain"></div>
<div class="drops"><i></i>×7</div>
```
Drops absolutely positioned below cloud, in the lower area of the scene.

Snowy:
```html
<div class="cloud cloud--snow"></div>
<div class="flakes">
  <i></i><i></i><i></i>  (each i is a 6-armed star)
</div>
<div class="specks"><i></i>×4</div>
```

Stormy:
```html
<div class="cloud cloud--storm"></div>
<div class="bolt"></div>
<div class="drops drops--storm"><i></i>×5</div>
<span class="flash"></span> (scene-level overlay)
```

Cloud shape CSS:

```css
.cloud{ position:absolute; width:120px; height:38px; border-radius:999px; }
.cloud::before,.cloud::after{ content:""; position:absolute; background:inherit; border-radius:50%; }
.cloud::before{ width:52px;height:52px; left:14px; top:-26px; }
.cloud::after{ width:36px;height:36px; right:18px; top:-16px; }
```
Colors per modifier.

Sun:
```css
.sun{ position:relative; width:150px; height:150px; animation: bob? maybe none }
.sun__core{ position:absolute; inset:38px; border-radius:50%; background: radial-gradient(circle at 35% 30%, #fff3b0, #ffd23f 45%, #ff9d2e); box-shadow: 0 0 30px rgba(255,190,60,.8), inset -6px -8px 18px rgba(255,120,20,.45); animation: coreGlow 4s ease-in-out infinite alternate; }
.sun__rays{ position:absolute; inset:0; animation: spin 26s linear infinite; }
.sun__rays i{ position:absolute; left:50%; top:50%; width:150px; height:5px; margin:-2.5px 0 0 -75px; border-radius:999px; background: linear-gradient(90deg, var(--ray) 0 20%, transparent 32% 68%, var(--ray) 80% 100%); }
.sun__rays i:nth-child(1){ transform: rotate(0deg) } ... in 30deg steps up to 150.
```
ray color rgba(255,214,110,.95). Halo: inset -10px? blurred radial with pulsing opacity.

@keyframes spin { to { transform: rotate(360deg) } }
coreGlow: scale 1↔1.05 + shadow intensity.

Drop keyframes:
```css
@keyframes fall {
  0% { transform: translateY(-8px) ; opacity:0 }
  15% { opacity: var(--o,.9) }? custom properties in keyframes are OK, but keep simple: 15% opacity .9;
  80% { opacity:.9 }
  100% { transform: translateY(64px); opacity:0 }
}
```
The slant of drops: rotate(14deg) — but keyframes override transform; include rotate in both keyframes.

For storm, steeper slant + faster.

Static fallback for reduced motion: drops get base transform translateY(20px) rotate(14deg) opacity .7 → looks like mid-rain still. Snowflakes at base position visible. Bolt at base opacity .85.

Flake keyframes:
```css
@keyframes snowfall {
  0% { transform: translate3d(0,-6px,0) rotate(0deg); opacity:0 }
  12% { opacity:.95 }
  100% { transform: translate3d(var(--sway,10px), 84px,0) rotate(160deg); opacity:0 }
}
```
Custom property --sway per nth-child set inline via CSS rule.

Specks: small dots falling straight.

Bolt flash:
```css
@keyframes flash {
  0%,74%,80%,100% { opacity:0 }
  76%,78% { opacity:1 }
  ... 
}
```
Let's craft: dark, then a double blink late in cycle:
0%–70%: 0
71%: 1
73%: 0.2
75%: 1
77%: 0
100%: 0
Duration 3.4s. Also scene flash overlay similar timing but lower intensity (opacity .35). Sync them with same duration/delays.

Card hover micro-interactions:
```css
.card { transition: transform .35s ease, box-shadow .35s ease; }
.card:hover { transform: translateY(-10px); box-shadow: 0 30px 60px -18px rgba(0,0,0,.55); }
.card:hover .sun__rays { animation-duration: 7s; }  // speed up — changing duration mid-animation jumps; acceptable? It restarts the interpolation and causes a rotational jump. Might glitch. Alternative: on hover, scale the core or brighten the halo (transition-based, no jump): .card:hover .sun__core { box-shadow stronger } transitions box-shadow nicely.
For rain: .card:hover .cloud { translateY(-3px) } transition.
Storm: show bolt brighter on hover? Keep transitions only on transform/filter/opacity for smoothness.
```
Also scene zoom: .card:hover .scene { transform: scale(1.04) }? Scene is a block; transitioning transform is fine.

Also tag hover state.

Masthead:
```html
<header class="masthead">
  <p class="masthead__eyebrow">HTML + CSS · no images, no scripts</p>
  <h1>Skycast</h1> or "THE SKY REPORT"
  <div class="masthead__right">Tuesday · 14:00 GMT</div>
</header>
```
Layout: flex space-between baseline. Title in display font weight 800, largeish (clamp). Add a thin rule with gradient underline.

Ambient background: body gradient #0d1420 → #101a2b; body::before with two radial glows (warm top-left, cool right) drifting with a slow keyframe (transform translate), animation 30s alternate. Plus a faint dot texture: `background-image: radial-gradient(rgba(255,255,255,.05) 1px, transparent 1.5px); background-size: 26px 26px;` overlay via body::after fixed. Subtle.

Text color: page ink #dfe7f2; eyebrow mono letter-spacing .2em uppercase small; date mono.

Footer: small mono line "Four moods of weather — pure CSS animation". Maybe include a small legend of the keyframes names? Keep minimal.

Reduced motion block:
```css
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after { animation-duration: .001s !important; animation-iteration-count: 1 !important; transition: none !important; }
}
```
But one-shot .001s finishes with end state = often opacity 0 (drops invisible). Better: `animation: none !important` with base styles being a static look. Set base styles to a good static frame: drops: transform translateY(26px) rotate(14deg), opacity .75; flakes: opacity .9 translate3d mid-position; bolt opacity .9; sun rays static (OK); halo static. With animation:none, those base styles show.

Make sure keyframes define the opacity from 0 — the running animation will override base. Good.

Also for reduced motion, hover lift transform: transition none, keep transform change (instant, acceptable) or disable lift? Keep the lift but instant. OK.

Viewport fit at 1280×800: masthead ~110px, grid gap, cards ~430 → total ~600 + page padding 48 → fits.

Now let's write code, minding selector correctness and no JS. Also ensure no horizontal scrollbar: scene elements are absolutely positioned inside overflow hidden cards. body overflow-x hidden.

Card text sizes: city 1.45rem weight 800 letter-spacing tight; temp 3.4rem weight 800 with lighter sup? Temperature digits slightly condensed; desc 0.95rem serif italic line-height 1.45; stats mono 0.72rem uppercase tracking.

Tag style: small pill, mono uppercase, bg rgba per card via var(--tag-bg), color var(--tag-ink).

Let's define card custom properties:
```css
.card{ --edge: rgba(255,255,255,.28); --ink:...; --muted:...; --tag-bg:...; --tag-ink:...; }
```

Rainy ink: #eef4fb, muted rgba(238,244,251,.75).
Sunny ink: #4a2504? warm brown #5b2c06; muted rgba(91,44,6,.78). Tag bg rgba(255,255,255,.5), tag-ink #7a3d00.
Snowy ink: #23406d; tag bg rgba(255,255,255,.65) tag ink #2d5aa0.
Stormy ink #f1eeff; accent #ffd94a.

Stats separator "·".

Grid breakpoints:
- default (mobile first) 1 column
- min-width 560px: 2 columns
- min-width 960px: 4 columns? At 960/4 = 240-22 gap ≈ 220 wide — narrow but OK. Use 1000px → cards 235. Desktop 1280 is what matters; 4 columns from 1020px. Between 560–1020: 2 columns. Good.

Container max-width: 1260px; padding-inline: clamp(16px, 4vw, 40px).

Now sun ray nth-child rotations: 6 i → 0,30,60,90,120,150 degrees.

Halo: `position:absolute; inset:14px; border-radius:50%; background: radial-gradient(circle, rgba(255,214,120,.55), transparent 70%); filter: blur(6px); animation: halo 4s ease-in-out infinite alternate;` keyframes scale/opacity.

Scene positioning: `.scene{ position:relative; height:190px; margin: 6px 0 10px; }` icons absolutely centered with left:50%, translateX(-50%). Avoiding transform on positioned wrapper if children animate transforms? Child transforms are separate elements, OK.

Sun wrapper: `.sun{ position:absolute; left:50%; top:50%; width:150px;height:150px; margin:-75px 0 0 -75px; }`

Clouds for rain/snow/storm: `.cloud{ left:50%; top:36px; transform: translateX(-50%); }` but then sway animation on cloud will conflict with translateX transform. Solution: wrap cloud in a positioner: `.cloudWrap`? Or animate margin-left? Simpler: give cloud a `left: calc(50% - 60px)` (width 120 known) and no transform; then sway animation transform translateX is free. Similarly storm cloud width maybe 130 → left calc(50% - 65px).

Drops container: absolute positioned below cloud: `.rain{ position:absolute; top:78px; left:50%; ... }` but drops need individual left: place `.drops` container with width 110px margin-left -55px; drops `left: nth%`.

Drop nth positions: left 6%,20%,36%,52%,66%,80%,93% with delays 0,.25,.5,.12,.4,.62,.3 and durations around 1.05–1.3s.

For storm drops: reuse `.drops--storm i` faster 0.7s, rotate 22°, fewer.

Snow flakes: container `.flakes` top 80px width 130px. flake i: width 16px height 16px? Construction: element itself = vertical bar: width:2.5px;height:16px; left offset; ::before/::after same bar rotated ±60 with center origin: `position:absolute; inset:0; transform: rotate(60deg); background:inherit?` need explicit background; `background:currentColor` use? i { background:#fff } and ::before background:#fff same. Set `color` and background: currentColor. Also glow with box-shadow: small blur.

Give each flake animation: snowfall Xs linear infinite delay; nth-child varies --sway and left and scale? Use scale in transform of keyframes? Include scale in keyframe transform... simpler: flake i:nth-of-type sizes: one small bar height 12px. OK — variety through size/lateral shift.

Static base for flakes: opacity:.9; transform: translate(6px, 40px) rotate(40deg); (visible mid-fall).

Specks: 3px dots with slight blur, animation speckFall nearly straight.

Scene flash overlay for storm: `.scene--storm::after{ content:""; position:absolute; inset:0; background: radial-gradient(circle at 55% 30%, rgba(255,240,180,.5), transparent 60%); opacity:0; animation: sceneFlash 3.4s infinite; pointer-events:none; }`

Bolt: absolute positioned below cloud: left calc(50% - 16px) top 74px; width 34px height 62px; clip-path polygon(58% 0, 26% 46%, 48% 46%, 20% 100%, 78% 40%, 52% 40%, 86% 0)? Let me sketch a bolt: container 36×64. Classic lightning polygon (percent): (60,0) (20,55) (45,55) (10,100) (80,42) (55,42) (90,0)? hmm verify: start top-left-ish. Try: polygon(65% 0%, 22% 52%, 46% 52%, 18% 100%, 74% 40%, 50% 40%, 88% 0%). Trace: top x65 → bottom-left to (22,52) middle-left, then right to (46,52), then down to lower-left (18,100) tip, then jump to top-right (74,40), then left to (50,40), then top-right (88,0), close to start (65,0). Forms a zig-zag bolt. Fill gradient: linear-gradient(180deg,#fff6c8, #ffd83d 55%, #ffb300). drop-shadow glow. Static opacity base .9; animation flash 3.6s infinite.

Sync sceneFlash with same duration and similar keyframe percents.

Flash keyframes:
```
@keyframes boltFlash{
  0%,69% {opacity:0}
  70% {opacity:1}
  72% {opacity:.15}
  74% {opacity:1}
  78% {opacity:0}
  100% {opacity:0}
}
```
Base opacity .9 for reduced motion — but when animation runs, at 0% opacity 0 is fine.

Hmm bolt base opacity .9 vs animation start 0 — during running OK.

Scene flash keyframes similar but max .45.

Also storm cloud slight jitter during flash? Could animate cloud filter brightness at same timing: `.scene--storm .cloud{ animation: cloudJolt 3.6s infinite }` keyframes at 70–78 brightness 1.6 and translate. Nice touch. Keep simple: brightness only + slight translate.

Storm cloud color: base #34394f? With top brighter? Use gradient background on cloud body: linear-gradient(180deg,#4a5170,#2b2f45). bumps inherit? background inherit works with same gradient — but bumps are circles with a vertical gradient sized to parent; background-attachment default border-box — gradient sized to element box; bumps are smaller, gradient restarts per element → visible seam but acceptable; alternatively give cloud a solid color and ::before/::after `background: inherit` works with solid. For storm: solid dark slate, with box-shadow inset to add rim highlight? Use `box-shadow: inset 0 6px 10px rgba(255,255,255,.08), 0 10px 24px rgba(0,0,0,.35)`. inherit passes box-shadow? No, inherit copies the box-shadow too — bumps get same shadow; fine-ish. Simpler: give cloud a `--cloud-bg` variable and pseudo-elements use `background: var(--cloud-bg)`. Inherit passes custom property automatically. Let's do: `.cloud{ background: var(--cbg); } .cloud::before,.cloud::after{ background: var(--cbg); }` with modifiers setting --cbg.

Also cloud shadow via filter: drop-shadow? drop-shadow on cloud shape applies to composite including pseudos: `filter: drop-shadow(0 14px 18px rgba(...))`. Per-card color for filter drop-shadow. Nice.

Rain cloud color: linear? Solid #cfd9e4 slightly grayish-blue; drops are below so a slightly darker underside. Keep solid #c3d2e0. Snow cloud: #ffffff / #f2f8ff. Storm: #3a4059? Against dark card bg, needs separation: brighter #565d7c on top? Solid #4d5470 with drop-shadow darker. Let's do storm cloud #59618333? Actually storm sky is dark; the cloud should be dark charcoal with a brighter rim: #3d4258 with drop-shadow of rgba(120,130,255,.25)? And flash brightens it. OK.

Also add a second smaller distant cloud on rainy scene for depth? Adds richness: `.cloud--mini` scaled to .6 offset left/right, different animation-delay for sway, lower opacity. Yes — rainy gets mini cloud upper-right, sunny gets a small drifting haze cloud across the sun? Sun card: add a small white semi-transparent cloud slowly drifting across via keyframe drift (translateX loop). Nice for "drifting" element. Sunny: small cloud passes behind sun (z-index below core): keyframes drift: from translateX(-140px) to 180px over 24s linear infinite, opacity .8. Positioned y ~ top.

Sway keyframe: `@keyframes sway { from{ transform: translateX(-4px)} to{ transform: translateX(4px)} }` alternate ease-in-out 5s.

Drift keyframe for sunny cloud: from translateX(-160px) to translateX(160px) 26s linear infinite; left:50% top:40px; small cloud; z-index 1 with core on top? Core z 2. Cloud passes behind core (nice).

Snow scene maybe add small drifting haze too? Enough.

Card structure height: scene 190. Maybe 200 for breathing room; total card maybe 440.

Font sizes: temp 3.2rem. City: also small country tag next to city? Keep city bold.

Meta row: left tag pill, right clock mono. Bottom stats mono with separators and maybe small arrow "▲" "▼"? Avoid Unicode arrows? OK as text (not icon fonts). Keep plain words.

Now page title: "SKYCAST — four moods of weather". Masthead eyebrow mono: "PURE HTML + CSS · ZERO JAVASCRIPT · NO IMAGES". H1: "Skycast" with a live dot? Add a pulsing dot "LIVE" next to right side date — pure CSS pulse. Nice detail: `<span class="live"><i></i> LIVE</span>` dot pulses green.

Right side of masthead: "TUESDAY · 14:00 CET" mono.

Footer: mono small muted: "Sun spins · rain falls · snow drifts · lightning strikes — all @keyframes. Honors prefers-reduced-motion." left-aligned, subtle.

Now let's code carefully. Watch:
- No duplicate ids, valid HTML.
- CSS custom properties per card.
- Media queries.
- Reduced motion.

Let me define z-indexes in scene: sun rays below core; halo behind.

Sun core inset: with 150 box, inset:40px → 70px diameter core. Rays length 150 full width, with transparent middle segment so rays appear beyond core: core radius 35; the ray segments from edge: bar is 150 wide; transparent middle 32–68% leaves a gap of ±(0.32*75=24px?) hmm 32% of 150 = 48px from left end; center is 75; transparent zone 48→102px i.e., within ±27px from center — but core radius 35 covers to 35 > 27, so ray segments are visible from 48px from center? Wait, left segment is 0→48px from left end meaning -75→-27 relative to center: ray length 48 to 27 px outside center — outer part at 27..48? No: segment is -75 to -27 relative to center; core covers -35..35 → visible ray portion -75..-35 (length 40px) starting at core edge... but -27..-35 is covered. Visible ray is 40px length from core edge going out. Ray outer tip at 75px from center; box half is 75. OK looks good: 12 rays around.

Rays color: rgba(255,216,120,.95); height 6px rounded; add slight glow drop-shadow? Filter on 6 bars × performance cost is fine but keep filter on parent .sun__rays { filter: drop-shadow(0 0 6px rgba(255,190,80,.6)); } applies to composite. Nice.

Sun bob: subtle floating of entire sun: animation float 7s ease-in-out infinite alternate translateY(±4). Add to .sun.

coreGlow: `@keyframes coreGlow { from { box-shadow: 0 0 26px 4px rgba(255,196,64,.55), inset -6px -8px 16px rgba(230,96,10,.35);} to { box-shadow: 0 0 44px 10px rgba(255,206,84,.8), inset -6px -8px 16px rgba(230,96,10,.35);} }` 4s alternate.

Halo pulse: opacity .5↔.9 scale .95↔1.08.

Card overflow: scenes overflow hidden? Drift cloud extends ±160 out of 150 box... scene width = card width (~280). Cloud drifts from -160 to 160, relative to center; with half-width 140 → exceeds → set `.scene{ overflow:hidden; }` but card itself rounded; scene overflow hidden clips rays? Rays are inside box, so OK. Snow falls to 84px below origin top 80 → 164 < 190 OK. Drops fall to 64 below top 78 → 142 OK. Storm drops same. Good: `.scene{overflow:hidden; border-radius:10px;}` maybe give scene a subtle inset background (white/black tint) — no, keep sky continuous; card gradient is sky. Scene transparent.

But overflow hidden + hover scale fine.

Sun scene: scene height 200; sun 150 box top 20.

Now card content padding: 18px 20px 20px.

Temp with unit: `<p class="temp">29<span>°</span></p>` style the span smaller, aligned top.

Snowy maybe temp −2° with minus sign "−2°". Rainy 11°, Stormy 18°? Chicago storm 17°. Sunny Lisbon 29°.

Meta clock strings: "TUE · 09:00", "WED · 14:20", etc. Keep short.

Also add per-card `--glow` for hover shadow tint? Shadow is dark generic.

Edge highlight: `.card{ border:1px solid var(--edge); }`

Deep shadow on dark cards. Base shadow: `box-shadow: 0 12px 30px -12px rgba(0,0,0,.45);` hover: `0 34px 60px -18px rgba(0,0,0,.6)`.

Light cards shadow rgba(30,50,90,.35)? Generic OK.

Also transition transform on the card, plus `.card:hover .scene{ transform: scale(1.045); }` scene with transition transform .5s. Scene default transform none.

Tag pill: `.tag{ font: 600 .62rem/1 var(--mono); letter-spacing:.18em; text-transform:uppercase; padding:.45em .8em; border-radius:999px; background:var(--tag-bg); color:var(--tag-ink); }`

Clock: `.clock{ font: .62rem var(--mono); letter-spacing:.14em; opacity:.75; text-transform:uppercase }`.

Stats: `font .6rem mono ls .12em uppercase opacity .7` with `<b>`? Use spans.

Description serif italic: `font-family: var(--serif); font-style: italic; font-size:.92rem;` muted color.

City: `font-family: var(--display); font-weight:800; font-size:1.5rem; letter-spacing:-.01em;`

Temp: display 800 3.1rem letter-spacing -0.03em; unit span .45em weight 600 margin-left 2px opacity .8.

Masthead h1: display 800, size clamp(2rem, 4vw, 3rem), letter-spacing -0.02em; color #f4f7fb; plus a thin colored slash accent? Maybe a small yellow bolt glyph? Text only. Add eyebrow above and rule below masthead: `border-bottom:1px solid rgba(255,255,255,.12); padding-bottom:18px; margin-bottom:26px;` with flex.

Live badge: green dot pulsing: `@keyframes pulse { ... box-shadow ring }` `.live i{ width:8px;height:8px;border-radius:50%;background:#38e08b; box-shadow:0 0 0 0 rgba(56,224,139,.6); animation: pulse 2s infinite; }` pulse to box-shadow 0 0 0 8px transparent. Mono text .62rem ls .2em.

Right date: mono muted.

Now ensure no external requests: fonts are system-only. Icons are pure CSS. No JS.

Let me draft the full file in my head, then output.

Also requirement: "lift on hover" ✓ translateY(-10px).

Grid: `.deck{ display:grid; gap:24px; grid-template-columns: 1fr; }` media 560: 2; 1020: 4.

Card max-width none.

Body padding: `padding: clamp(20px,4vh,44px) clamp(16px,4vw,44px) 60px;` container max-width 1280 margin auto.

Ambient background: body { background: fixed gradient } `background-color:#0b1120; background-image: radial-gradient(1100px 600px at 85% -10%, rgba(70,110,180,.25), transparent 60%), radial-gradient(900px 500px at 8% 110%, rgba(255,150,60,.12), transparent 60%), linear-gradient(180deg,#0d1526,#0a0f1c 60%,#0b0e17);` plus dot texture ::before fixed, no animation (static texture) and ::after drifting glow? Animating fixed pseudo translate: transform translate3d small ±30px 26s alternate. Provide `body::after{ content:""; position:fixed; inset:-20%; background: radial-gradient(600px 400px at 30% 20%, rgba(90,140,220,.10), transparent 60%), radial-gradient(700px 500px at 75% 80%, rgba(255,170,80,.08), transparent 60%); animation: ambient 26s ease-in-out infinite alternate; pointer-events:none; z-index:0 }` content wrapper z-index 1 relative.

Keyframes ambient { from transform: translate3d(-2%, -1%,0) scale(1); to translate3d(2%,2%,0) scale(1.05); }

Dot texture body::before: `position:fixed; inset:0; background-image: radial-gradient(rgba(255,255,255,.045) 1px, transparent 1.4px); background-size: 28px 28px; pointer-events:none;` mask fading edges? Keep simple, opacity fine. z-index 0.

Make sure page content is z-index:1 relative.

Now reduced motion: disable ambient too (covered by * rule).

Let me write:

```css
@media (prefers-reduced-motion: reduce){
  *, *::before, *::after{ animation: none !important; transition: none !important; }
}
```

Static fallback states: drops base visible: define base `opacity:.75; transform: translateY(26px) rotate(15deg);` but keyframe 0% sets opacity 0 transform translateY(-6px) rotate(15deg). When animation active, overrides; fine.

But nth-child rules also set `animation-delay: -1.15s;` etc. With animation removed, base shows static drops — good, staggered delays no longer matter.

Static flakes: base `opacity:.9; transform: translate(4px,44px) rotate(30deg);` keyframes start translate3d(-4px,-6px,0) rotate(0) opacity 0.

Specks base opacity .8 translateY(30px).

Bolt base opacity .92 (static bolt shown). Scene flash ::after base opacity 0 → with no animation stays 0 — OK (no flash frozen mid-scene weirdness).

Sun rays static — OK. Drift cloud base at left mid? base transform none → placed at left:50% top area; visible — OK.

Sway cloud static fine.

Now compile drops delay/duration via nth-child under `.drops i`. Both rain and storm share `.drops`; storm modifier adjusts duration via `.drops--storm i { animation-duration:.85s }` etc. But nth sets animation shorthand? Set `animation: fall 1.15s linear infinite;` on base `.drops i`, then nth sets delay and duration via `animation-delay` and `animation-duration` overrides (keeping name). Then `.drops--storm i { animation-duration:.8s; }` but nth-child specificity (0,2,1)? `.drops--storm i` = (0,1,1) same as `.drops i` but nth overrides? Specificity of `.drops i:nth-child(3)` (0,1,1)+(0,1,0)?? class+i pseudo-class = (0,2,1)? Actually pseudo-class counts as class: `.drops i:nth-child(3)` = class(2) element(1) → (0,2,1). `.drops--storm i` (0,1,1). nth wins → duration stays 1.15. To simplify: define per-drop timing only via CSS variable: base `.drops i{ animation: fall var(--fd,1.2s) linear var(--fdel,0s) infinite; }` and nth-child sets `--fd/--fdel` custom properties (custom properties are not subject to specificity conflict in the same way — later rule overrides; nth selectors define variables; storm container sets different defaults? Variables from nth still apply...). Simplest: write separate nth rules for storm drops. Since the markup differs anyway, style `.drops--storm i:nth-child(n)` with own --sway? Rain is vertical.

Plan: `.drops i { position:absolute; top:0; width:3px; height:13px; border-radius:4px; background: linear-gradient(180deg, rgba(...0), var(--drop)); animation: fall 1.2s linear infinite; }` transform in keyframes includes rotate(var?) — variables inside keyframes resolve per element — OK: keyframes fall { 0%{ transform: translate3d(0,-6px,0) rotate(var(--tilt,14deg)); opacity:0 } ... } and .drops--storm i { --tilt:24deg; --fall:70px; } keyframes use var(--fall,62px). Custom props in keyframes: supported in latest Chrome ✓.

Delay via nth-child: `.drops i:nth-child(1){ left:6%; animation-delay:-.2s; animation-duration:1.18s }` etc. Storm: `.drops--storm i:nth-child(1){...}` override with own values (higher specificity? Both (0,2,1). Storm class + element + nth = (0,3,1) wins). Element has both .drops and .drops--storm classes.

Snow flakes similar pattern.

OK, writing final HTML. Also add `lang="en"`, meta viewport, title.

Double-check "no inline event handlers" — none. No script tag ✓.

Fonts: define:
```css
--display: "Avenir Next","Segoe UI Variable Display","Segoe UI",system-ui,-apple-system,"Helvetica Neue",Arial,sans-serif;
--serif: Georgia,"Times New Roman",serif;
--mono: "SF Mono","Cascadia Code",Consolas,"Courier New",monospace;  (ui-monospace first)
```
Use `ui-monospace, "Cascadia Code", "SF Mono", Menlo, Consolas, monospace`.

Card --edge variable.

Now sizes: scene height 190px; cloud top placement:
- Rain cloud: top 34px; width 130px height 40px; bumps: before 54/54 top -28 left 16; after 38/38 top -18 right 20.
- Drops top: cloud bottom ≈ 34+40=74 → drops container top 76.
- Storm cloud: top 30, slightly bigger 140×44, darker; bolt top ≈ 30+44-6=68; bolt height 66.
- Snow cloud top 34.

Scene height: 190 → drops fall 62 from top 76 → 138 ✓. Snow falls 84 from top 80 → 164 ✓. Storm drops 60 from 80 → OK. Bolt 68+66=134 ✓.

Sun scene: sun 150 top ~12.

Sunny drifting cloud: small cloud scale: width 70 height 22, bumps 28/28 & 20/20; rgba(255,255,255,.55); top 34; animation drift 26s linear infinite; drift keyframe translateX(-170px)→(170px). Since no base translateX, static position at center OK.

z-index: drifting cloud z1; rays z2? Rays behind core; cloud behind sun core but above rays? Behind all: cloud z0, rays z1, core z2, halo z0 below rays. Sun float wrapper animates transform translateY — contains halo/rays/core; drifting cloud is separate element in scene.

Mini cloud for rain: `.cloud--mini{ width:80px; height:26px; opacity:.7; right:8%; left:auto; top:20px; sway with delay }` bumps before 32/32 top -16 left 10; after 22/22 top -10 right 12. Use same ::before sizes scaled? Fixed before/after sizes would look chunky on mini; give `.cloud--mini` its own pseudo sizes. And its own background variable.

Snow: maybe 2nd mini cloud left too? Add mini on left with opacity .8.

Storm: small cloud right too.

Enough richness.

Card hover: also `.card:hover .tag` brighten? Skip.

`.card::after` for top scene shine too: `content:""; position:absolute; inset:0; background: linear-gradient(180deg, rgba(255,255,255,.14), transparent 28%); pointer-events:none; border-radius:inherit;` subtle glassy top. Light cards already light; use white .18 for dark, black .05 for light? Use variable --shine.

Also inner border highlight: `.card{ box-shadow: inset 0 1px 0 rgba(255,255,255,.25), base shadow }` composite.

Now temperature alignment: place temp and city in a row? Layout: scene → city → desc → spacer flex → temp at bottom? Strong order: big temp immediately after scene with city overlay? Classic card: city big top below meta, big temp bottom-right. Let's do: scene, then header row: city left, temp right aligned bottom (baseline). Then desc, then stats at bottom with margin-top auto. Use flex column, card min-height for equal heights; stats mt-auto. Grid rows stretch → card equal heights.

Header row: `.card__main{ display:flex; justify-content:space-between; align-items:flex-end; gap:10px; margin-top:4px; }` city block: city + small region? Add a small country line mono beneath city? Keep city + small country line? Skip.

Temp font 3rem — width tight at 280px? "29°" OK.

Stats row at bottom, top border 1px dashed var(--edge)? Subtle dashed adds texture: `border-top:1px solid color-mix? ` use var(--rule) rgba. Simple solid low opacity.

Finalize copy:

1. Sunny — Lisbon, Portugal. Tag "Clear". Clock "Tue · 09:40". Temp 29°. Description: "High sun, dry heat and a hard blue sky that holds until dusk." Stats: "SW 12 km/h · Humidity 28% · UV 8"
2. Rainy — Bergen, Norway. Tag "Showers". Clock "Tue · 14:20". Temp 11°. Description: "Steady Atlantic showers rolling in off the fjord all afternoon." Stats "W 22 km/h · Humidity 88% · 6 mm"
3. Snowy — Sapporo, Japan. Tag "Snowfall". Clock "Tue · 21:05". Temp −2° (use −). Description: "Soft, fat flakes settling over the rooftops through the night." Stats "NW 9 km/h · Snow 14 cm · Vis 2 km"
4. Stormy — Chicago, USA. Tag "Thunder". Clock "Tue · 17:55". Temp 18°. Description: "Black cumulus stacking up with sharp bursts of rain and lightning." Stats "SW 41 km/h · Humidity 76% · CAPE high"

Title/h1: "Skycast" eyebrow: "PURE HTML + CSS — EVERY ICON DRAWN IN CSS, ZERO JAVASCRIPT". Right: "Tuesday · 14:00 UTC" + LIVE badge.

Footer line small.

Edge case: at 1280 the masthead h1 must fit on one line with right side — flex wrap OK.

Now let's write it all. Watch: no JS. Ensure `sup`/`span` for degree.

Let me spell out the CSS variables for drops:
Rain drops color: rgba(173,216,255,.95) with top fading transparent gradient.
Storm drops: rgba(150,180,255,.85).

Snow specks white.

Bolt gradient + drop-shadow via filter.

Also `.card:hover .icon-scale`? I said scene scale 1.045 on hover; ensure scene transition transform .45s ease. Also `.card:hover .sun__halo{ opacity boost }`? Halo animated (opacity keyframe) — hover transition conflicts; skip.

Storm cloud jolt: `@keyframes cloudJolt{ 0%,69%,79%,100%{ transform: translateX(0); filter: drop-shadow(...) } 71%{ transform: translateX(-2px);} 75%{ transform: translateX(2px); filter: drop-shadow(0 14px 18px rgba(0,0,0,.4)) brightness(1.5);} }` filter string changes — interpolation between different drop-shadow lists? Keep same structure and only brightness var? Simplify: animate `filter: brightness()` separately on pseudo? Overkill — animate only translateX jolt + ::after glow on cloud? Cloud already glows via scene flash. Keep jolt translate only.

But base cloud has `filter: drop-shadow(...)` static; keyframes without filter leaves it. Fine.

Cloud sway vs jolt conflict (both transform animations): storm cloud uses cloudJolt only (no sway).

Rain mini cloud sway: `.cloud--mini{ animation: sway 6.5s ease-in-out -2s infinite alternate; }` base cloud sway 5.5s.

Sway keyframes translateX -5→5 — but cloud uses left positioning without base transform ✓.

Now drift keyframe must not conflict with positioning: drifting cloud left:50%; margin-left:-35px; animation drift. OK.

Let me write sun rays gradient variable: --ray: rgba(255,213,112,.95).

Also sun scene might have floating dust `.mote` elements: 3 small circles rising: keyframes rise translateY(-20) opacity fade. Adds life. Add 3 `.mote` in sunny scene with nth positioning. Low cost. Let's do it: motes absolute bottom area, width 4px blur? Just glow dots: background rgba(255,240,200,.8), border-radius 50%, animation moteUp 5s infinite delay. Static base opacity .5 visible.

Keyframes moteUp { 0%{ transform: translateY(0); opacity:0 } 20%{opacity:.7} 100%{ transform: translateY(-46px); opacity:0 } }.

Snow scene sparkles? Skip.

Time to write. Also ensure meta viewport, meta charset. Title.

One more: at 1280 width, 4 columns: container max-width 1272? Use 1280 - padding (44*2)=1192 → cards ~ (1192-72)/4=280 ✓.

Card min-height: 420px maybe; content flex column; stats mt auto.

Also on very narrow (375), scene stays fine.

prefers-reduced-motion also stops hover-lift transform? Transition none → instant lift; acceptable.

Add `:focus-visible` outline on page? No interactive elements; skip.

Let's write final answer as a single html code block. No JS confirmed. Ensure no `onclick` etc.

Write CSS neatly with section comments.

Double-check: no `#` colors misused, all keyframes defined: spin, coreGlow, haloPulse, float, drift, sway, fall, snowfall, speckFall, moteUp, boltFlash, sceneFlash, cloudJolt, ambient, pulse (live dot). All referenced.

Snow flakes base: `.flakes i{ position:absolute; top:0; }` nth sets left/delay/duration/size? Size via width/height on nth; but ::before/::after inset:0 adapts ✓.

Flake bar width 2.5px, height: nth1 16px, nth2 13px, nth3 18px? Plus scale? OK.

flakes left: 12%, 46%, 78%.

Snow keyframes translateX --sw: variable per nth set in rule for nth (custom property on element) ✓.

Specks: `.specks i` 4 dots, left 28%,60%,88%,20%? width 4px.

Storm drops left: 8,30,52,74,92%.

Rain drops left: 5,20,35,50,65,80,94 (7 drops).

Ensure .drops container: `position:absolute; top:76px; left:calc(50% - 62px); width:124px; height:70px;` for storm maybe top 80 width 130.

Sunny halo/rays/core coordinates as planned.

Card scene: `.scene{ position:relative; height:190px; margin:2px -2px 8px; overflow:hidden; border-radius:12px; transition: transform .5s cubic-bezier(.2,.7,.2,1); }` negative margin spreads slightly? Keep within padding; margin 0 0 6px.

Hmm scene overflow hidden clips the sun's halo blur at edges — halo inside anyway.

Also add a per-scene sky tint inside? Card gradient covers.

Finally the footer.

Also page background ambient reduced motion: covered.

Now let's generate code. Be careful with nth-child selector counts.

Sun rays rotations: i:nth-child(1){transform:rotate(0)} (2)30 (3)60 (4)90 (5)120 (6)150.

But `.sun__rays i` base has no transform; fine.

Rays gradient: `linear-gradient(90deg, var(--ray) 0 18%, transparent 30% 70%, var(--ray) 82% 100%)` two-argument stops with `0 18%` syntax valid ✓.

Core inset:40px.

Sun float: `.sun{ animation: float 7s ease-in-out infinite alternate; }` float keyframes translateY(-4px)→(4px). From base 0 → alt from 0 to 8? Define float {from translateY(-4px) to translateY(4px)}. Static base at 0, OK.

Halo inset:-6px blur 10px.

Now hover scene scale: `.card:hover .scene{ transform: scale(1.05); }` may cause drops clipped at bottom — small so OK.

Also `will-change`? Skip.

Masthead rule: `.masthead{ display:flex; flex-wrap:wrap; align-items:flex-end; gap:14px 28px; padding-bottom:18px; border-bottom:1px solid rgba(255,255,255,.14); margin-bottom:30px; }` left block flex column: eyebrow + h1. Right block margin-left:auto flex column align-end gap 6: date mono, live badge.

h1 size clamp(1.9rem,3.4vw,2.6rem). Add slight two-tone: "Sky" normal + "cast" in accent? Single color with `em`? Simple: white, add small underline accent bar via ::after (yellow-to-blue gradient bar 64px) under h1 — a small gradient bar is fine, but keep it a flat accent: background #ffd84d width 56px height 4px radius.

Footer: `margin-top:34px; font mono .62rem; opacity:.55; letter-spacing:.14em; text-transform:uppercase;` content: "Four forecasts · pure @keyframes · honors prefers-reduced-motion".

Maybe include live region? No JS.

Let's write it out.

Also html, body height/overflow-x hidden.

Let me spell out the entire file.

Additionally: card hover should lift; add `.card:active` subtle press translateY(-4px)? Nice: add.

Also ensure `.card` position relative + overflow hidden (shine ::after and scene clips separately). Card overflow hidden clips lift shadow? Shadow outside isn't affected by its own overflow. Fine. Card overflow hidden clips drifting cloud within scene — scene already clips.

Edge: `.card--sunny` shine --shine rgba(255,255,255,.35)? Light bg: subtle. Use .25.

Also each card has a small corner index "01"? Maybe mono big ghost number in top-right behind scene for editorial feel: `.card__meta` already has tag+clock. Skip ghosts to avoid clutter... actually a ghost number adds editorial feel; put in scene top-right `.index` mono 700 2.2rem opacity .18. Cheap. But scene overflow hidden and icon overlaps maybe; place at top-right corner of scene OK. Let's add with per-card color variable.

Order of meta: left tag, right clock; ghost index inside scene top-right.

Final check reduced-motion static state: rays static, core glow static shadow base? base box-shadow defined on `.sun__core` static ✓ define base shadow. Halo base opacity .7 ✓. Drops visible with base transform — but base transform also includes translateY(26px) — with animation off, appears mid-fall ✓. Flakes visible ✓ bolt .92 ✓ motes base opacity .5? Set base opacity .0? With animation off, mote invisible — set base opacity .45 translateY(-12px)? Just static dots near bottom. Base: opacity:.4. OK.

Drift cloud base at center ✓.

Good. Now output. Careful: `--` variable names.

Also no inline styles anywhere; all nth-child CSS.

Storm drops more slanted: keyframes fall uses var(--tilt) and var(--dist). Rain default --dist:62px; storm sets 70px and duration .8s via `.drops--storm i { animation-duration:.8s; }` specificity vs nth rule setting animation-duration `.drops i:nth-child(n)` (0,2,1) vs `.drops--storm i` (0,1,1) → nth wins if nth also sets duration. For storm I'll set duration in its own nth rule `.drops--storm i:nth-child(1){...duration}` — simpler: give storm drops their own nth block defining left/delay/duration. And rain block under `.drops--rain i:nth-child`. Keep the generic `.drops i` just for looks + animation name/duration default 1.2s.

For flakes define generic `.flakes i` with `animation: snowfall 4s linear infinite;` and nth adjust.

OK writing.

Also add slight `border-radius: 14px` to cards and ::after shine gradient.

Double-check hover lift: `.card{ transition: transform .4s cubic-bezier(.2,.8,.2,1), box-shadow .4s; }`.

Now let me produce the final code block.