Showcase

Four weather cards — CSS only, built by GPT-6 Luna

Hostedvia Codex CLIOpenRouter
Running live in your browserNew tab
Show the code the model wrote
HTML22,338 characters
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#f2f3ef" />
    <title>Weather, in motion</title>
    <style>
      :root {
        color-scheme: light;
        font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
        font-synthesis: none;
        text-rendering: optimizeLegibility;
        --ink: #182c3e;
        --muted-ink: #617487;
        --paper: #f2f3ef;
      }

      * { box-sizing: border-box; }

      body {
        min-width: 320px;
        min-height: 100vh;
        margin: 0;
        padding: clamp(28px, 6vw, 76px) 24px 34px;
        color: var(--ink);
        background:
          radial-gradient(ellipse at 50% 0%, rgba(255,255,255,.95), transparent 46rem),
          var(--paper);
      }

      .page {
        width: min(100%, 1192px);
        margin: 0 auto;
      }

      .intro {
        display: flex;
        align-items: end;
        justify-content: space-between;
        gap: 28px;
        margin: 0 2px 30px;
      }

      .kicker, .card-kicker, .condition {
        font-size: 10px;
        font-weight: 750;
        letter-spacing: .16em;
        text-transform: uppercase;
      }

      .kicker {
        display: inline-flex;
        align-items: center;
        gap: 9px;
        margin: 0 0 13px;
        color: #718391;
      }

      .kicker::before {
        width: 7px;
        height: 7px;
        border-radius: 50%;
        background: #f0a854;
        box-shadow: 0 0 0 4px rgba(240,168,84,.15);
        content: "";
      }

      h1 {
        margin: 0;
        font-size: clamp(31px, 4vw, 48px);
        font-weight: 570;
        letter-spacing: -.055em;
        line-height: 1;
      }

      .intro-note {
        max-width: 220px;
        margin: 0 0 2px;
        color: #758594;
        font-size: 13px;
        line-height: 1.6;
        text-align: right;
      }

      .weather-grid {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 16px;
      }

      .weather-card {
        position: relative;
        isolation: isolate;
        min-width: 0;
        height: 392px;
        overflow: hidden;
        border: 1px solid rgba(255,255,255,.53);
        border-radius: 25px;
        box-shadow: 0 18px 38px rgba(32,53,71,.095), 0 2px 6px rgba(32,53,71,.04);
        color: #173348;
        background: #c4e9f4;
      }

      .weather-card::before {
        position: absolute;
        z-index: -1;
        inset: 0;
        background: linear-gradient(180deg, rgba(255,255,255,.18), transparent 44%, rgba(255,255,255,.13));
        content: "";
        pointer-events: none;
      }

      .card-sun {
        background: linear-gradient(160deg, #65c8e9 0%, #a4e5ec 49%, #f9d49f 100%);
      }

      .card-rain {
        color: #f2f7fa;
        background: linear-gradient(155deg, #859cab 0%, #a9c1c9 51%, #d2e0de 100%);
      }

      .card-snow {
        color: #f5fbff;
        background: linear-gradient(155deg, #7ea9c2 0%, #a9cfdd 49%, #dce9e8 100%);
      }

      .card-storm {
        color: #eef5ff;
        background: linear-gradient(150deg, #202e48 0%, #36465d 52%, #647487 100%);
      }

      .card-top {
        position: absolute;
        z-index: 8;
        top: 20px;
        right: 20px;
        left: 20px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 8px;
      }

      .card-kicker {
        margin: 0;
        color: currentColor;
        opacity: .76;
      }

      .condition {
        padding: 7px 9px 6px;
        border: 1px solid rgba(255,255,255,.37);
        border-radius: 999px;
        color: currentColor;
        background: rgba(255,255,255,.14);
        font-size: 8px;
        letter-spacing: .12em;
        white-space: nowrap;
        backdrop-filter: blur(8px);
      }

      .scene {
        position: absolute;
        z-index: 1;
        top: 62px;
        right: 0;
        bottom: 113px;
        left: 0;
        overflow: hidden;
      }

      .card-copy {
        position: absolute;
        z-index: 7;
        right: 21px;
        bottom: 21px;
        left: 21px;
      }

      .card-copy h2 {
        margin: 0 0 6px;
        font-size: 12px;
        font-weight: 760;
        letter-spacing: .17em;
        line-height: 1;
      }

      .temperature {
        display: flex;
        align-items: start;
        gap: 5px;
        margin: 0;
        font-size: 52px;
        font-weight: 520;
        letter-spacing: -.075em;
        line-height: 1;
      }

      .temperature sup {
        margin-top: 7px;
        font-size: 22px;
        font-weight: 450;
        letter-spacing: -.04em;
      }

      .summary {
        margin: 11px 0 0;
        color: currentColor;
        font-size: 12px;
        font-weight: 520;
        opacity: .78;
      }

      /* Sun */
      .sun-rays, .sun-disc, .sun-cloud {
        position: absolute;
        left: 50%;
        border-radius: 50%;
        transform: translate(-50%, -50%);
      }

      .sun-rays {
        top: 46%;
        width: 190px;
        aspect-ratio: 1;
        background: repeating-conic-gradient(from 0deg, transparent 0deg 9deg, rgba(255,249,214,.68) 9deg 11deg, transparent 11deg 20deg);
        -webkit-mask: radial-gradient(circle, transparent 0 40%, #000 44% 59%, transparent 64%);
        mask: radial-gradient(circle, transparent 0 40%, #000 44% 59%, transparent 64%);
        animation: rays-turn 32s linear infinite;
        animation-delay: -7s;
      }

      .sun-disc {
        top: 46%;
        width: 104px;
        aspect-ratio: 1;
        background: radial-gradient(circle at 35% 30%, #fff6bf 0%, #ffdb7b 47%, #ffb85f 100%);
        box-shadow: 0 0 25px 8px rgba(255,222,127,.46), 0 0 70px 24px rgba(255,221,132,.25);
        animation: sun-breathe 5.8s ease-in-out infinite;
        animation-delay: -2.1s;
      }

      .sun-cloud {
        top: 66%;
        left: 0;
        width: 87px;
        height: 25px;
        border-radius: 30px;
        background: linear-gradient(180deg, #fff 0%, #e9f5ee 100%);
        box-shadow: 0 8px 16px rgba(57,111,128,.13);
        opacity: 0;
        animation: cloud-drift 22s ease-in-out infinite;
        animation-delay: -9s;
      }

      .sun-cloud::before, .sun-cloud::after {
        position: absolute;
        bottom: 10px;
        border-radius: 50%;
        background: inherit;
        content: "";
      }

      .sun-cloud::before { left: 17px; width: 38px; height: 38px; }
      .sun-cloud::after { right: 11px; width: 47px; height: 47px; }

      /* Shared cloud made from one element and two CSS lobes. */
      .cloud {
        position: absolute;
        top: 29px;
        left: 50%;
        width: 119px;
        height: 31px;
        border-radius: 28px;
        background: linear-gradient(180deg, #f5f8f7 0%, #dce8e8 100%);
        box-shadow: 0 10px 18px rgba(43,65,79,.16);
        transform: translateX(-50%);
      }

      .cloud::before, .cloud::after {
        position: absolute;
        bottom: 12px;
        border-radius: 50%;
        background: inherit;
        content: "";
      }

      .cloud::before { left: 19px; width: 48px; height: 48px; }
      .cloud::after { right: 15px; width: 60px; height: 60px; }

      .card-storm .cloud {
        top: 27px;
        width: 133px;
        height: 34px;
        background: linear-gradient(180deg, #8595a7 0%, #526277 100%);
        box-shadow: 0 12px 25px rgba(8,17,31,.38);
      }

      .card-storm .cloud::before { left: 20px; width: 53px; height: 53px; }
      .card-storm .cloud::after { right: 13px; width: 67px; height: 67px; }

      .rain-drop {
        position: absolute;
        top: 89px;
        left: var(--x);
        width: 3px;
        height: var(--length, 19px);
        border-radius: 50%;
        background: linear-gradient(180deg, rgba(245,252,255,.08), rgba(239,251,255,.9));
        box-shadow: 0 0 5px rgba(225,247,255,.3);
        opacity: 0;
        animation: rain-fall var(--duration, 1.24s) linear infinite;
        animation-delay: var(--delay, 0s);
      }

      .card-storm .rain-drop {
        top: 87px;
        width: 3px;
        background: linear-gradient(180deg, rgba(205,227,255,.1), rgba(213,234,255,.96));
        animation-duration: var(--duration, .78s);
      }

      .puddle {
        position: absolute;
        right: 13%;
        bottom: 6px;
        left: 13%;
        height: 12px;
        border-top: 1px solid rgba(243,255,255,.57);
        border-radius: 50%;
        background: radial-gradient(ellipse at 50% 0%, rgba(238,253,255,.33), rgba(238,253,255,0) 70%);
        opacity: .86;
      }

      .ripple {
        position: absolute;
        bottom: 5px;
        left: var(--x);
        width: 19px;
        height: 6px;
        border: 1px solid rgba(244,255,255,.72);
        border-radius: 50%;
        opacity: 0;
        transform: scale(.3);
        animation: ripple-out 1.65s ease-out infinite;
        animation-delay: var(--delay, 0s);
      }

      .ripple:nth-of-type(2) { width: 25px; animation-duration: 1.9s; }

      /* Snow */
      .snowbank {
        position: absolute;
        right: -12%;
        bottom: -14px;
        left: -12%;
        height: 32px;
        border-radius: 50% 50% 0 0 / 55% 55% 0 0;
        background: linear-gradient(180deg, rgba(250,254,255,.88), rgba(236,247,250,.96));
        box-shadow: 0 -4px 18px rgba(246,254,255,.32);
      }

      .card-snow .card-copy { color: #2b566d; }

      .flake {
        position: absolute;
        top: -9px;
        left: var(--x);
        width: var(--size, 6px);
        height: var(--size, 6px);
        border-radius: 50%;
        background: rgba(255,255,255,.96);
        box-shadow: 0 0 8px rgba(255,255,255,.9);
        opacity: 0;
        animation: snow-drift var(--duration, 8s) ease-in infinite;
        animation-delay: var(--delay, 0s);
      }

      .flake.crystal {
        width: 2px;
        height: var(--size, 13px);
        border-radius: 3px;
        background: rgba(250,255,255,.88);
        box-shadow: 0 0 7px rgba(255,255,255,.7);
      }

      .flake.crystal::before, .flake.crystal::after {
        position: absolute;
        top: 50%;
        left: 50%;
        width: 2px;
        height: var(--size, 13px);
        border-radius: inherit;
        background: inherit;
        content: "";
      }

      .flake.crystal::before { transform: translate(-50%, -50%) rotate(60deg); }
      .flake.crystal::after { transform: translate(-50%, -50%) rotate(-60deg); }

      /* Thunderstorm */
      .card-storm .scene { bottom: 108px; }

      .bolt {
        position: absolute;
        z-index: 2;
        top: 86px;
        left: 52%;
        width: 28px;
        height: 77px;
        background: #fff3a6;
        clip-path: polygon(54% 0, 100% 0, 69% 41%, 100% 41%, 28% 100%, 43% 55%, 8% 55%);
        filter: drop-shadow(0 0 7px rgba(255,238,147,.95)) drop-shadow(0 0 16px rgba(180,215,255,.9));
        opacity: 0;
        transform: translateX(-50%);
        animation: bolt-strike 23s steps(1, end) infinite;
        animation-delay: -4.7s;
      }

      .storm-flash {
        position: absolute;
        z-index: 6;
        inset: 0;
        background: rgba(225,242,255,.91);
        mix-blend-mode: screen;
        opacity: 0;
        pointer-events: none;
        animation: card-lightning 23s steps(1, end) infinite;
        animation-delay: -4.7s;
      }

      @keyframes rays-turn { to { transform: translate(-50%, -50%) rotate(360deg); } }

      @keyframes sun-breathe {
        0%, 100% { transform: translate(-50%, -50%) scale(.96); box-shadow: 0 0 21px 6px rgba(255,222,127,.4), 0 0 60px 18px rgba(255,221,132,.21); }
        50% { transform: translate(-50%, -50%) scale(1.045); box-shadow: 0 0 33px 11px rgba(255,228,145,.59), 0 0 83px 30px rgba(255,221,132,.31); }
      }

      @keyframes cloud-drift {
        0% { transform: translate(-45px, -50%); opacity: 0; }
        9% { opacity: .95; }
        46% { opacity: .95; }
        62% { opacity: .86; }
        91% { opacity: 0; }
        100% { transform: translate(310px, -50%); opacity: 0; }
      }

      @keyframes rain-fall {
        0% { transform: translateY(-13px) scaleY(.65); opacity: 0; }
        10% { opacity: .84; }
        76% { opacity: .82; }
        100% { transform: translateY(88px) scaleY(1); opacity: 0; }
      }

      @keyframes ripple-out {
        0%, 25% { transform: scale(.24); opacity: 0; }
        39% { opacity: .68; }
        100% { transform: scale(1.35); opacity: 0; }
      }

      @keyframes snow-drift {
        0% { transform: translate3d(0, -14px, 0) rotate(0deg); opacity: 0; }
        11% { opacity: .92; }
        39% { transform: translate3d(15px, 78px, 0) rotate(95deg); }
        73% { transform: translate3d(-13px, 155px, 0) rotate(205deg); opacity: .88; }
        100% { transform: translate3d(8px, 224px, 0) rotate(310deg); opacity: 0; }
      }

      @keyframes bolt-strike {
        0%, 14.25%, 14.42%, 15.05%, 45.69%, 45.87%, 46.4%, 47%, 86.17%, 86.35%, 86.9%, 87.58%, 100% { opacity: 0; }
        14.26%, 14.41%, 14.53%, 14.74%, 45.7%, 45.86%, 46.08%, 46.39%, 46.73%, 46.99%, 86.18%, 86.34%, 86.57%, 86.89%, 87.26%, 87.57% { opacity: 1; }
      }

      @keyframes card-lightning {
        0%, 14.25%, 15.05%, 45.69%, 47%, 86.17%, 87.58%, 100% { opacity: 0; }
        14.26% { opacity: .96; }
        14.41% { opacity: .1; }
        14.53% { opacity: .78; }
        14.74% { opacity: .08; }
        14.88% { opacity: .52; }
        15.05% { opacity: 0; }
        45.7% { opacity: .84; }
        45.86% { opacity: .06; }
        46.08% { opacity: .97; }
        46.39% { opacity: .09; }
        46.73% { opacity: .68; }
        47% { opacity: 0; }
        86.18% { opacity: .92; }
        86.34% { opacity: .08; }
        86.57% { opacity: .98; }
        86.89% { opacity: .11; }
        87.26% { opacity: .73; }
        87.58% { opacity: 0; }
      }

      .page-foot {
        display: flex;
        justify-content: space-between;
        gap: 12px;
        margin: 17px 3px 0;
        color: #8a979d;
        font-size: 10px;
        font-weight: 650;
        letter-spacing: .12em;
        text-transform: uppercase;
      }

      @media (max-width: 940px) {
        .weather-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
        .weather-card { height: 370px; }
        .scene { bottom: 105px; }
      }

      @media (max-width: 520px) {
        body { padding: 30px 14px 22px; }
        .intro { align-items: start; margin: 0 2px 22px; }
        .intro-note { max-width: 132px; font-size: 11px; }
        .weather-grid { gap: 10px; }
        .weather-card { height: 338px; border-radius: 20px; }
        .card-top { top: 15px; right: 13px; left: 13px; align-items: start; flex-direction: column; }
        .condition { padding: 6px 8px 5px; }
        .scene { top: 76px; bottom: 103px; }
        .card-copy { right: 14px; bottom: 17px; left: 14px; }
        .card-copy h2 { font-size: 10px; }
        .temperature { font-size: 42px; }
        .temperature sup { font-size: 18px; }
        .summary { margin-top: 8px; font-size: 10px; }
        .sun-rays { width: 158px; }
        .sun-disc { width: 86px; }
        .cloud { transform: translateX(-50%) scale(.84); }
        .card-storm .cloud { transform: translateX(-50%) scale(.88); }
        .page-foot { font-size: 8px; }
      }

      @media (prefers-reduced-motion: reduce) {
        *, *::before, *::after {
          animation-duration: .01ms !important;
          animation-iteration-count: 1 !important;
          scroll-behavior: auto !important;
        }
        .sun-cloud, .rain-drop, .ripple, .flake, .bolt, .storm-flash { opacity: 0; }
      }
    </style>
  </head>
  <body>
    <main class="page">
      <header class="intro">
        <div>
          <p class="kicker">Atmosphere study · 04</p>
          <h1>Weather, in motion.</h1>
        </div>
        <p class="intro-note">Four little windows into the sky, wherever it turns.</p>
      </header>

      <section class="weather-grid" aria-label="Animated weather forecast">
        <article class="weather-card card-sun" aria-labelledby="sun-title">
          <div class="card-top">
            <p class="card-kicker">01 / Clear skies</p>
            <span class="condition">Feels like 23°</span>
          </div>
          <div class="scene" aria-hidden="true">
            <div class="sun-rays"></div>
            <div class="sun-disc"></div>
            <div class="sun-cloud"></div>
          </div>
          <div class="card-copy">
            <h2 id="sun-title">SUN</h2>
            <p class="temperature">23<sup>°</sup></p>
            <p class="summary">Warm light all afternoon</p>
          </div>
        </article>

        <article class="weather-card card-rain" aria-labelledby="rain-title">
          <div class="card-top">
            <p class="card-kicker">02 / Rain</p>
            <span class="condition">Humidity 82%</span>
          </div>
          <div class="scene" aria-hidden="true">
            <div class="cloud"></div>
            <i class="rain-drop" style="--x: 19%; --delay: -.18s; --duration: 1.2s"></i>
            <i class="rain-drop" style="--x: 31%; --delay: -.83s; --duration: 1.42s; --length: 23px"></i>
            <i class="rain-drop" style="--x: 43%; --delay: -.51s; --duration: 1.08s"></i>
            <i class="rain-drop" style="--x: 55%; --delay: -.97s; --duration: 1.34s; --length: 22px"></i>
            <i class="rain-drop" style="--x: 68%; --delay: -.33s; --duration: 1.16s"></i>
            <i class="rain-drop" style="--x: 79%; --delay: -.71s; --duration: 1.48s; --length: 21px"></i>
            <i class="rain-drop" style="--x: 25%; --delay: -.62s; --duration: 1.38s; --length: 17px"></i>
            <i class="rain-drop" style="--x: 62%; --delay: -.08s; --duration: 1.27s"></i>
            <i class="rain-drop" style="--x: 85%; --delay: -1.11s; --duration: 1.31s; --length: 24px"></i>
            <div class="puddle"></div>
            <i class="ripple" style="--x: 24%; --delay: -.2s"></i>
            <i class="ripple" style="--x: 49%; --delay: -1.06s"></i>
            <i class="ripple" style="--x: 72%; --delay: -.63s"></i>
          </div>
          <div class="card-copy">
            <h2 id="rain-title">RAIN</h2>
            <p class="temperature">16<sup>°</sup></p>
            <p class="summary">Steady drops, softer streets</p>
          </div>
        </article>

        <article class="weather-card card-snow" aria-labelledby="snow-title">
          <div class="card-top">
            <p class="card-kicker">03 / Winter calm</p>
            <span class="condition">Wind 8 km/h</span>
          </div>
          <div class="scene" aria-hidden="true">
            <div class="cloud"></div>
            <i class="flake crystal" style="--x: 16%; --size: 12px; --delay: -2.7s; --duration: 8.8s"></i>
            <i class="flake" style="--x: 28%; --size: 5px; --delay: -5.1s; --duration: 7.2s"></i>
            <i class="flake crystal" style="--x: 41%; --size: 9px; --delay: -1.3s; --duration: 9.7s"></i>
            <i class="flake" style="--x: 52%; --size: 8px; --delay: -6.6s; --duration: 8.1s"></i>
            <i class="flake crystal" style="--x: 66%; --size: 14px; --delay: -3.9s; --duration: 10.4s"></i>
            <i class="flake" style="--x: 78%; --size: 4px; --delay: -7.4s; --duration: 7.7s"></i>
            <i class="flake crystal" style="--x: 88%; --size: 10px; --delay: -4.5s; --duration: 9.2s"></i>
            <i class="flake" style="--x: 22%; --size: 7px; --delay: -1.9s; --duration: 10.8s"></i>
            <i class="flake crystal" style="--x: 59%; --size: 11px; --delay: -8.3s; --duration: 8.6s"></i>
            <div class="snowbank"></div>
          </div>
          <div class="card-copy">
            <h2 id="snow-title">SNOW</h2>
            <p class="temperature">−2<sup>°</sup></p>
            <p class="summary">A quiet drift through the day</p>
          </div>
        </article>

        <article class="weather-card card-storm" aria-labelledby="storm-title">
          <div class="card-top">
            <p class="card-kicker">04 / Electric skies</p>
            <span class="condition">Wind 34 km/h</span>
          </div>
          <div class="scene" aria-hidden="true">
            <div class="cloud"></div>
            <div class="bolt"></div>
            <i class="rain-drop" style="--x: 13%; --delay: -.57s; --duration: .82s; --length: 25px"></i>
            <i class="rain-drop" style="--x: 23%; --delay: -.14s; --duration: .71s; --length: 28px"></i>
            <i class="rain-drop" style="--x: 34%; --delay: -.69s; --duration: .93s; --length: 24px"></i>
            <i class="rain-drop" style="--x: 45%; --delay: -.38s; --duration: .76s; --length: 30px"></i>
            <i class="rain-drop" style="--x: 57%; --delay: -.82s; --duration: .88s; --length: 25px"></i>
            <i class="rain-drop" style="--x: 69%; --delay: -.22s; --duration: .69s; --length: 28px"></i>
            <i class="rain-drop" style="--x: 81%; --delay: -.61s; --duration: .84s; --length: 31px"></i>
            <i class="rain-drop" style="--x: 91%; --delay: -.31s; --duration: .73s; --length: 26px"></i>
            <i class="rain-drop" style="--x: 28%; --delay: -.9s; --duration: .91s; --length: 22px"></i>
            <i class="rain-drop" style="--x: 75%; --delay: -.48s; --duration: .79s; --length: 27px"></i>
            <div class="puddle"></div>
            <i class="ripple" style="--x: 21%; --delay: -.77s"></i>
            <i class="ripple" style="--x: 52%; --delay: -.31s"></i>
            <i class="ripple" style="--x: 77%; --delay: -1.22s"></i>
          </div>
          <div class="card-copy">
            <h2 id="storm-title">STORM</h2>
            <p class="temperature">11<sup>°</sup></p>
            <p class="summary">Heavy rain, distant thunder</p>
          </div>
          <div class="storm-flash" aria-hidden="true"></div>
        </article>
      </section>

      <footer class="page-foot">
        <span>Local conditions</span>
        <span>Updated just now&nbsp; · &nbsp;°C</span>
      </footer>
    </main>
  </body>
</html>

Same prompt, other models

8 more
Compare side by side

One email when a new model lands on the board or in the showcase. Unsubscribe anytime.