Exploding like buttonOne-line
Mistral Large 4
by MistralReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 4 min 47 s
- Cost
- $0.045
- Output tokens
- 21,525
- Spent thinking
- 16,065 tokens
- Speed
- 77.3 tok/s
- Console errors
- 0
- First token after
- 8.6 s
- First visible text after
- 3 min 42 s
- Prompt tokens
- 369
- Code size
- 14.0 KB
- Finish reason
- stop
- Served by
- Mistral
- Model id
mistralai/mistral-large-4-0- Reasoning sent
{"effort":"high"}- Max output
- 262,144 tokens
- Generated
- Nov 12, 2026
What it was asked
The prompt
“a "like" button in pure CSS, no JavaScript, that does a crazy animation when you click it”
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 · 282 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pure CSS Like Button — Crazy Click Animation</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%;overflow:hidden}
body{
font-family:ui-rounded,"SF Pro Rounded","Segoe UI",system-ui,-apple-system,Roboto,Helvetica,Arial,sans-serif;
background:#0b0918;color:#fff;overflow:hidden;
-webkit-tap-highlight-color:transparent;
}
::selection{background:#ff2d78;color:#fff}
/* hidden checkbox that powers everything (the "checkbox hack") */
.cb{position:fixed;width:1px;height:1px;opacity:0;pointer-events:none}
.stage{
position:fixed;inset:0;display:grid;place-items:center;overflow:hidden;
background:
radial-gradient(1000px 700px at 75% 12%, #33205e 0%, transparent 55%),
radial-gradient(900px 700px at 12% 88%, #143a5e 0%, transparent 55%),
linear-gradient(160deg,#171129,#0b0918 70%);
}
/* ambient blobs */
.blob{position:absolute;border-radius:50%;filter:blur(100px);pointer-events:none}
.b1{width:440px;height:440px;background:#7c3aed;top:-130px;right:-110px;opacity:.45;animation:drift1 16s ease-in-out infinite alternate}
.b2{width:400px;height:400px;background:#ff2d78;bottom:-150px;left:-130px;opacity:.35;animation:drift2 21s ease-in-out infinite alternate}
.b3{width:260px;height:260px;background:#06b6d4;top:56%;left:62%;opacity:.28;animation:drift1 25s ease-in-out infinite alternate-reverse}
@keyframes drift1{to{transform:translate(-70px,60px) scale(1.15)}}
@keyframes drift2{to{transform:translate(80px,-70px) scale(.9)}}
/* full-screen pink flash on like */
.flash{position:absolute;inset:0;pointer-events:none;opacity:0;z-index:5;
background:radial-gradient(circle at 50% 46%, rgba(255,90,160,.55), rgba(255,90,160,0) 55%)}
.cb:checked ~ .stage .flash{animation:flashA .8s ease-out}
@keyframes flashA{0%{opacity:0}12%{opacity:1}100%{opacity:0}}
.card{
position:relative;z-index:2;text-align:center;
padding:clamp(30px,5vw,50px) clamp(24px,6vw,58px);
max-width:min(92vw,460px);
background:rgba(255,255,255,.055);
border:1px solid rgba(255,255,255,.12);
border-radius:30px;
backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
box-shadow:0 30px 80px rgba(0,0,0,.45);
}
.cb:checked ~ .stage .card{animation:shake .55s cubic-bezier(.36,.07,.19,.97)}
@keyframes shake{
10%,90%{transform:translate(-2px,1px) rotate(-.6deg)}
20%,80%{transform:translate(4px,-2px) rotate(.8deg)}
30%,50%,70%{transform:translate(-6px,2px) rotate(-1.2deg)}
40%,60%{transform:translate(6px,-3px) rotate(1.2deg)}
}
.badge{
display:inline-block;font-size:11px;font-weight:700;letter-spacing:.18em;
padding:7px 14px;border-radius:999px;margin-bottom:18px;
background:linear-gradient(135deg,rgba(124,92,255,.28),rgba(255,45,120,.28));
border:1px solid rgba(255,255,255,.18);color:#e9defc;
}
h1{font-size:clamp(26px,5.4vw,40px);font-weight:800;letter-spacing:-.02em;margin-bottom:8px}
h1 span{background:linear-gradient(90deg,#ff8ab8,#ffd166,#8ab8ff);-webkit-background-clip:text;background-clip:text;color:transparent}
.counter{font-size:15px;font-weight:600;color:rgba(255,255,255,.65);margin-bottom:26px}
.nums{display:inline-grid;place-items:center;margin-right:6px}
.nums>span{grid-area:1/1;transition:opacity .3s,transform .3s}
.n1{opacity:0;transform:translateY(10px) scale(.7);color:#ff5c9d;font-weight:800}
.cb:checked ~ .stage .n0{opacity:0;transform:translateY(-10px) scale(.7)}
.cb:checked ~ .stage .n1{opacity:1;transform:none}
.cb:checked ~ .stage .counter{animation:bump .5s cubic-bezier(.34,1.56,.64,1)}
@keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.3)}100%{transform:scale(1)}}
/* the button */
.btn{
position:relative;display:inline-flex;align-items:center;gap:16px;cursor:pointer;
user-select:none;-webkit-user-select:none;touch-action:manipulation;
padding:clamp(15px,3.5vw,20px) clamp(24px,6vw,38px);
border-radius:999px;font-size:clamp(17px,4.5vw,21px);font-weight:800;letter-spacing:.14em;
color:#dfe4f2;background:linear-gradient(160deg,#2a3050,#1a1f36);
border:1px solid rgba(255,255,255,.16);
box-shadow:0 12px 30px rgba(0,0,0,.4),inset 0 1px 0 rgba(255,255,255,.08);
transition:background .4s,box-shadow .4s,transform .18s ease,color .3s;
}
.btn:active{transform:scale(.93)}
.btn::after{
content:"";position:absolute;inset:-12px;border-radius:999px;pointer-events:none;
border:2px dashed rgba(255,255,255,0);transition:border-color .35s;
}
.cb:checked ~ .stage .btn{
background:linear-gradient(135deg,#ff2d78 0%,#ff5e3a 100%);color:#fff;
box-shadow:0 14px 44px rgba(255,45,120,.55),0 0 0 8px rgba(255,45,120,.14),inset 0 1px 0 rgba(255,255,255,.35);
transform:scale(1.05);
}
.cb:checked ~ .stage .btn:active{transform:scale(.95)}
.cb:checked ~ .stage .btn::after{border-color:rgba(255,255,255,.55);animation:spin 7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.cb:focus-visible ~ .stage .btn{outline:3px solid #8f7bff;outline-offset:4px}
/* CSS heart */
.heart-wrap{position:relative;width:58px;height:54px;display:grid;place-items:center;animation:idlePulse 2.4s ease-in-out infinite}
@keyframes idlePulse{0%,100%{transform:scale(1)}50%{transform:scale(1.08)}}
.heart{position:relative;width:58px;height:54px;color:#9aa3bd;transition:color .35s}
.heart::before,.heart::after{
content:"";position:absolute;top:0;width:29px;height:47px;
background:currentColor;border-radius:29px 29px 0 0;
}
.heart::before{left:29px;transform:rotate(-45deg);transform-origin:0 100%}
.heart::after{left:0;transform:rotate(45deg);transform-origin:100% 100%}
.cb:checked ~ .stage .heart{
color:#fff;
animation:pop .75s cubic-bezier(.34,1.56,.64,1) both, glowPulse 1.3s ease-in-out .75s infinite;
}
@keyframes pop{
0%{transform:scale(0) rotate(-40deg)}
30%{transform:scale(1.55) rotate(12deg)}
50%{transform:scale(.82) rotate(-9deg)}
70%{transform:scale(1.22) rotate(5deg)}
85%{transform:scale(.94) rotate(-2deg)}
100%{transform:scale(1) rotate(0)}
}
@keyframes glowPulse{
0%,100%{filter:drop-shadow(0 0 6px rgba(255,255,255,.55))}
50%{filter:drop-shadow(0 0 22px rgba(255,255,255,.95))}
}
/* LIKE / LIKED! text swap */
.t{display:inline-grid;place-items:center}
.t>span{grid-area:1/1;transition:opacity .3s,transform .3s}
.t-liked{opacity:0;transform:translateY(14px) scale(.7)}
.cb:checked ~ .stage .t-like{opacity:0;transform:translateY(-14px) scale(.7)}
.cb:checked ~ .stage .t-liked{opacity:1;transform:none}
/* ---- explosion FX layer (emanates from the heart) ---- */
.fx{position:absolute;inset:0;pointer-events:none}
.fx i,.fx b{position:absolute;left:50%;top:50%;display:block;opacity:0}
.p{width:var(--sz,10px);height:var(--sz,10px);border-radius:50%;background:var(--c,#ff2d78)}
.p.sq{border-radius:3px}
.star{
width:var(--sz,18px);height:var(--sz,18px);background:var(--c,#ffd166);border-radius:0;
clip-path:polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%);
}
.ring{width:74px;height:74px;border:3px solid rgba(255,120,180,.9);border-radius:50%}
.boom{width:44px;height:44px;border-radius:50%;background:radial-gradient(circle,#fff 0%,rgba(255,255,255,0) 68%)}
.plus{font-size:22px;font-weight:900;color:#ffd166;text-shadow:0 2px 10px rgba(0,0,0,.45)}
.mini{
width:16px;height:16px;background:#ff5c9d;
clip-path:path('M8 14C4 10.6 1 8.2 1 5.4 1 3.1 2.8 1.5 4.8 1.5 6 1.5 7.2 2.1 8 3.2 8.8 2.1 10 1.5 11.2 1.5 13.2 1.5 15 3.1 15 5.4 15 8.2 12 10.6 8 14Z');
}
.cb:checked ~ .stage .p,
.cb:checked ~ .stage .star{animation:burst .95s cubic-bezier(.16,.7,.3,1) forwards;animation-delay:var(--d,0s)}
@keyframes burst{
0%{transform:translate(-50%,-50%) scale(1) rotate(0deg);opacity:1}
100%{transform:translate(calc(-50% + var(--dx)),calc(-50% + var(--dy))) scale(.15) rotate(var(--r,300deg));opacity:0}
}
.cb:checked ~ .stage .ring{animation:ringA .85s ease-out forwards;animation-delay:var(--d,0s)}
@keyframes ringA{
0%{transform:translate(-50%,-50%) scale(.35);opacity:.95}
100%{transform:translate(-50%,-50%) scale(2.8);opacity:0}
}
.cb:checked ~ .stage .boom{animation:boomA .55s ease-out forwards}
@keyframes boomA{
0%{transform:translate(-50%,-50%) scale(.2);opacity:.95}
100%{transform:translate(-50%,-50%) scale(3.6);opacity:0}
}
.cb:checked ~ .stage .plus{animation:riseA 1s ease-out forwards;animation-delay:var(--d,0s)}
@keyframes riseA{
0%{transform:translate(-50%,0) scale(.5) rotate(0);opacity:0}
18%{opacity:1}
100%{transform:translate(calc(-50% + var(--dx)),-140px) scale(1.35) rotate(var(--r,0deg));opacity:0}
}
.cb:checked ~ .stage .mini{animation:floatA 1.9s ease-in infinite;animation-delay:var(--d,0s)}
@keyframes floatA{
0%{transform:translate(-50%,6px) scale(.15) rotate(0);opacity:0}
12%{opacity:1}
100%{transform:translate(calc(-50% + var(--dx)),-160px) scale(.85) rotate(var(--r,0deg));opacity:0}
}
/* confetti falling inside the card */
.confetti{position:absolute;inset:0;pointer-events:none}
.cf{
position:absolute;top:-6px;left:var(--x,50%);width:9px;height:15px;border-radius:2px;
background:var(--c,#ffd166);opacity:0;
}
.cb:checked ~ .stage .cf{animation:confFall 1.15s cubic-bezier(.3,.6,.6,1) forwards;animation-delay:var(--d,0s)}
@keyframes confFall{
0%{transform:translateY(0) rotate(0);opacity:1}
85%{opacity:1}
100%{transform:translateY(330px) rotate(var(--r,520deg));opacity:0}
}
.hint{margin-top:26px;font-size:14px;line-height:1.55;color:rgba(255,255,255,.6)}
.hint small{font-size:12px;color:rgba(255,255,255,.4)}
.hint-t{display:inline-grid;place-items:center}
.hint-t>span{grid-area:1/1;transition:opacity .3s,transform .3s}
.h0{animation:hintPulse 1.6s ease-in-out infinite}
@keyframes hintPulse{0%,100%{opacity:1}50%{opacity:.4}}
.h1{opacity:0;transform:translateY(8px);color:#ff8ab8;font-weight:700}
.cb:checked ~ .stage .h0{opacity:0;transform:translateY(-8px);animation:none}
.cb:checked ~ .stage .h1{opacity:1;transform:none}
</style>
</head>
<body>
<input class="cb" type="checkbox" id="like" aria-label="Like this">
<div class="stage">
<div class="blob b1"></div>
<div class="blob b2"></div>
<div class="blob b3"></div>
<div class="flash"></div>
<main class="card">
<span class="confetti" aria-hidden="true">
<i class="cf" style="--x:8%;--c:#ff2d78;--r:560deg;--d:.02s"></i>
<i class="cf" style="--x:20%;--c:#ffd166;--r:-480deg;--d:.10s"></i>
<i class="cf" style="--x:33%;--c:#4cc9f0;--r:620deg;--d:.05s"></i>
<i class="cf" style="--x:46%;--c:#7c5cff;--r:-540deg;--d:.14s"></i>
<i class="cf" style="--x:58%;--c:#ff7a3d;--r:500deg;--d:.03s"></i>
<i class="cf" style="--x:70%;--c:#f72585;--r:-600deg;--d:.12s"></i>
<i class="cf" style="--x:82%;--c:#7cf7c4;--r:580deg;--d:.07s"></i>
<i class="cf" style="--x:93%;--c:#ffffff;--r:-520deg;--d:.16s"></i>
</span>
<span class="badge">PURE CSS · ZERO JS</span>
<h1><span>Loved this demo?</span></h1>
<div class="counter">
<span class="nums"><span class="n0">1,336</span><span class="n1">1,337</span></span>likes
</div>
<label class="btn" for="like">
<span class="heart-wrap">
<span class="fx" aria-hidden="true">
<i class="boom"></i>
<i class="ring" style="--d:0s"></i>
<i class="ring" style="--d:.13s"></i>
<i class="ring" style="--d:.26s"></i>
<i class="p" style="--c:#ff2d78;--sz:12px;--dx:0px;--dy:-138px;--r:220deg;--d:0s"></i>
<i class="p" style="--c:#ffd166;--sz:9px;--dx:72px;--dy:-120px;--r:330deg;--d:.03s"></i>
<i class="p" style="--c:#4cc9f0;--sz:11px;--dx:126px;--dy:-80px;--r:180deg;--d:.05s"></i>
<i class="p sq" style="--c:#7c5cff;--sz:10px;--dx:146px;--dy:-14px;--r:420deg;--d:0s"></i>
<i class="p" style="--c:#ff7a3d;--sz:12px;--dx:126px;--dy:64px;--r:260deg;--d:.07s"></i>
<i class="p" style="--c:#f72585;--sz:9px;--dx:80px;--dy:122px;--r:380deg;--d:.04s"></i>
<i class="p" style="--c:#ffd166;--sz:11px;--dx:0px;--dy:142px;--r:200deg;--d:.06s"></i>
<i class="p sq" style="--c:#4cc9f0;--sz:10px;--dx:-82px;--dy:118px;--r:300deg;--d:.02s"></i>
<i class="p" style="--c:#7c5cff;--sz:9px;--dx:-130px;--dy:62px;--r:450deg;--d:.08s"></i>
<i class="p" style="--c:#ff7a3d;--sz:12px;--dx:-148px;--dy:-12px;--r:240deg;--d:.01s"></i>
<i class="p" style="--c:#ff2d78;--sz:8px;--dx:-114px;--dy:-84px;--r:360deg;--d:.05s"></i>
<i class="p sq" style="--c:#ffffff;--sz:9px;--dx:-58px;--dy:-128px;--r:280deg;--d:.07s"></i>
<i class="p" style="--c:#4cc9f0;--sz:8px;--dx:40px;--dy:-136px;--r:400deg;--d:.09s"></i>
<i class="p" style="--c:#ffd166;--sz:8px;--dx:104px;--dy:-122px;--r:320deg;--d:.10s"></i>
<i class="star" style="--c:#ffd166;--sz:20px;--dx:-30px;--dy:-96px;--r:540deg;--d:.08s"></i>
<i class="star" style="--c:#ffffff;--sz:16px;--dx:88px;--dy:-40px;--r:540deg;--d:.13s"></i>
<i class="star" style="--c:#ff5c9d;--sz:18px;--dx:-92px;--dy:28px;--r:540deg;--d:.18s"></i>
<b class="plus" style="--dx:-34px;--r:-16deg;--d:.05s">+1</b>
<b class="plus" style="--dx:30px;--r:12deg;--d:.16s;color:#7cf7c4">+1</b>
<i class="mini" style="--dx:-52px;--r:-22deg;--d:0s"></i>
<i class="mini" style="--dx:44px;--r:20deg;--d:.65s"></i>
<i class="mini" style="--dx:4px;--r:-8deg;--d:1.3s"></i>
</span>
<span class="heart"></span>
</span>
<span class="t"><span class="t-like">LIKE</span><span class="t-liked">LIKED!</span></span>
</label>
<p class="hint">
<span class="hint-t">
<span class="h0">👆 Click the button — watch it go crazy</span>
<span class="h1">🎉 Liked! Click again to reset</span>
</span><br>
<small>checkbox hack · keyframes · zero JavaScript</small>
</p>
</main>
</div>
</body>
</html>Reasoning trace (16,065 tokens)
The user wants a "like" button in pure CSS, no JavaScript, that does a crazy animation when clicked. I need to output a single HTML file with inline CSS, no JS. Use :active state or checkbox hack (:checked) since no JS — clicking a label toggling a checkbox is pure CSS. The checkbox hack allows the animation to persist after click (toggled state), which is better than :active which only lasts while held. "Crazy animation" — I can do a heart/thumbs-up that explodes into particles, bounces, shakes, color changes, rings, etc., all with CSS animations triggered by :checked.
Requirements:
- Self-contained, one fenced code block, ```html
- No JS at all (pure CSS requested)
- Visible on first paint at 1280×800, adapt to 375px
- No external resources
- Since it's a demo (not a game), the "click to start" rule about games doesn't strictly apply, but it's an interactive demo — I should make it obvious to click. Maybe include a hint "Click me!". The checkbox hack requires clicking the label. That's fine.
Design: A big like button (heart icon drawn with CSS or SVG inline? Inline SVG is allowed — it's inline, not external). Or pure CSS heart shape. I can do a CSS heart using ::before/::after rotated squares, or use an SVG inline for crispness. Pure CSS heart is classic. Let's do a button with a heart made of CSS shapes, plus particle bursts (multiple small dots positioned around, animating outward with different delays via nth-child), a shockwave ring, a "pop" scale animation with cubic-bezier overshoot, background color morph, text "LIKE" that changes to "LIKED", maybe floating "+1" numbers, confetti pieces, screen shake? Screen shake on the container via animation on :checked.
Checkbox hack:
```html
<input type="checkbox" id="like" class="like-checkbox">
<label for="like" class="like-btn">...</label>
```
Then `.like-checkbox:checked ~ .stage .heart { animation: ... }` etc. Need the checkbox before the stage in DOM, sibling selector. Put input hidden (but not display:none? display:none on checkbox is fine for label clicking; label with for works even if input display:none). Actually label[for] click toggles checkbox even if hidden — yes.
Animation on toggle: when checked, run animations once (animation runs when selector matches). When unchecked, could run reverse? Keep simple: checked state triggers crazy animation; unchecking resets (maybe a small shrink). Also add :active press effect for immediate feedback.
Crazy animation ideas:
1. Heart pops: scale 0 → 1.4 → 0.9 → 1.1 → 1 with elastic cubic-bezier, rotate wiggle.
2. Explosion particles: ~12-16 dots (spans) flying outward in all directions with random-ish angles via nth-child transforms, fading and scaling, plus a few star shapes.
3. Shockwave rings: 2-3 rings expanding and fading.
4. Background burst: radial gradient flash.
5. Floating "+1" text rising and fading.
6. Button background gradient shifts to pink/red, glow shadow pulses.
7. Little hearts floating up repeatedly (loop while checked) — since :checked persists, can loop a few floating hearts.
8. Text morph: "LIKE" → "LIKED!" via two spans cross-fading.
9. Whole card slight shake (crazy!). Maybe subtle rotate keyframes on the button.
10. Sparkles: small plus/star shapes twinkling.
Performance: use transform/opacity only.
Layout: centered stage, dark gradient background with subtle animated blobs, a card containing the button, hint text "click the heart!", counter maybe? No JS so a counter can't increment... could fake with CSS counters? Counter increments on :checked? CSS counters can't easily do that; could use two spans "0" and "1,337" cross-fade. Cute: show "1,337 likes" when liked, "1,336 likes" before. That's a fun touch without JS.
Accessibility-ish: label focusable? Add tabindex? Label isn't focusable by default; could make the checkbox visually hidden but focusable and style :focus-visible on label via sibling selector. Nice touch but keep simple; add it.
Mobile: 375px wide, button scales with clamp().
Let me structure:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pure CSS Like Button</title>
<style>...</style>
</head>
<body>
<input type="checkbox" id="like" class="cb">
<div class="stage">
<div class="bg-blobs">...</div>
<main class="card">
<div class="counter"><span class="c0">1,336</span><span class="c1">1,337</span> likes</div>
<label for="like" class="btn" aria-label="Like">
<span class="burst"> particles... </span>
<span class="rings"><i></i><i></i><i></i></span>
<span class="heart"></span>
<span class="label-text"><span class="t-like">LIKE</span><span class="t-liked">LIKED!</span></span>
<span class="plus">+1</span>
floating hearts
</label>
<p class="hint">click the button — pure CSS, zero JavaScript</p>
</main>
</div>
</body>
</html>
```
Wait — particles inside label: clicking label toggles checkbox, fine. Pointer events on spans fine.
CSS heart:
```css
.heart { position:relative; width: 54px; height: 54px; }
.heart::before, .heart::after {
content:""; position:absolute; width:54px; height: 86px?
```
Standard CSS heart: two circles + rotated square:
```css
.heart{ width:60px;height:60px; }
.heart::before{ content:""; position:absolute; top:0; left:30px? ...
```
Classic:
```css
.heart { position: relative; width: 100px; height: 90px; }
.heart:before, .heart:after {
content:""; position:absolute; left:50px; top:0; width:50px; height:80px;
background: currentColor; border-radius: 50px 50px 0 0;
transform: rotate(-45deg); transform-origin: 0 100%;
}
.heart:after { left:0; transform: rotate(45deg); transform-origin: 100% 100%; }
```
That gives a heart. Use currentColor so color changes animate.
Simpler: use inline SVG heart path inside label — allowed (inline). SVG is cleaner and scales. But "pure CSS" — an SVG icon is fine, animation is CSS. However, purist might prefer CSS heart. I'll do the CSS heart shape (before/after) — it's iconic "pure CSS". Actually with gradients on heart it's harder; use solid color with drop-shadow.
Let me size: heart container 64px. before/after: width 32px, height 52px, border-radius 32px 32px 0 0, left offset etc. Let me compute: heart width 64, height ~58. before: left:32px? Standard proportions: width W=64. half=32. before: left:32px, top:0, width:32px, height:52px, rotate(-45deg), origin 0 100% (bottom-left). after: left:0, top:0, width:32px, height:52px, rotate(45deg), origin 100% 100%. Resulting heart spans from x=0 to 64, height = 52*cos45 + ... approx 52*0.707 + 32*0.707 ≈ 59.4? Fine.
Particles: create ~14 spans class p p1..p14, each absolutely centered in button, background varied colors (pink, yellow, purple, cyan), shapes: some circles, some squares (rotate 45 = diamond), some tiny hearts? Keep circles/squares/stars. Use nth-child to set --tx/--ty custom props and animation delay. Animation: burst 0.9s ease-out forwards: from translate(-50%,-50%) scale(1) opacity 1 → translate(calc(-50% + var(--tx)), calc(-50% + var(--ty))) scale(0.2) rotate(random) opacity 0.
Since checked triggers once, particles animate once on check. For extra craziness while held, also animate on :active? The :active press: scale button 0.92.
Rings: 3 spans expanding from center: border 3px solid, border-radius 50%, animation ring 1s: scale 0.3→2.2, opacity .8→0, staggered delays.
Plus one: "+1" floats up from button top, fades. Also maybe "+1" repeated: three spans with delays rising.
Floating hearts while checked: 3 small hearts looping upward from button, infinite while checked — gives ongoing motion. With `animation: floatUp 1.6s linear infinite` and delays. They appear only when checked (opacity 0 default, animation sets opacity). On uncheck they vanish instantly — acceptable.
Background flash: a radial gradient overlay on card or stage that flashes when checked: `.cb:checked ~ .stage .flash { animation: flash .6s }`.
Card shake: `.cb:checked ~ .stage .card { animation: shake .5s }` — crazy touch. Keyframes shake: translate/rotate small random-ish steps.
Button styles: pill shape, gradient background gray → when checked pink/red gradient, box-shadow glow, transition. Since animation on :checked, use animation to change background? Animating background gradient isn't smooth; instead transition background on checked state: `.cb:checked ~ .stage .btn { background: linear-gradient(...); }` with transition .3s. And heart color via `color` transition. Heart pop animation handles the crazy part.
Label text swap: two absolutely stacked spans; default LIKE visible, LIKED! hidden (opacity 0, translateY). Checked: crossfade.
Counter swap similarly.
Hint: "👆 click the heart — 100% CSS, no JavaScript" — emoji ok? Emojis render fine. Maybe avoid emoji reliance; use text. Fine to include one.
Also add a subtle idle animation so first paint isn't static: heart gently pulses (scale 1↔1.06) infinite, blobs floating in background. On checked, the idle pulse is replaced by pop animation (animation property overridden). Need to make sure pop animation includes final state scale 1 — with `forwards` fill.
Also `:active` on label: transform scale(.93) — but transform on label conflicts with shake animation on card only, fine. But note: when checked animation on heart uses transform; :active on button scale applies to button not heart. OK.
Focus visible: `.cb:focus-visible ~ .stage .btn { outline: 3px solid ... }`.
Hidden checkbox: `position:absolute; opacity:0; pointer-events:none;` Keep it focusable (not display:none) so keyboard works: pressing space when focused toggles → animation plays. Good: "press a key" works too. But iframe only receives keyboard after click — user clicks the label anyway. Also add `autofocus`? autofocus in iframe may not work without focus; skip.
DOM order: input must be sibling before .stage: `.cb:checked ~ .stage ...`.
Particles placement: inside .btn, behind heart (z-index). Button overflow visible so particles fly outside. Card overflow visible too. Body overflow hidden to avoid scrollbars from particles? Particles are small; ensure no horizontal scrollbar at 375px: set `overflow-x:hidden` on body/html? Use `overflow:hidden` on body maybe clips vertically fine since centered. I'll set `overflow: clip` maybe; simpler: `html,body{height:100%;} body{overflow:hidden;}`. But if content taller than 800? Card centered with flex, content ~ 500px tall, fine. For small heights, allow scroll? Keep min-height and overflow hidden could clip on tiny screens; use `overflow-x:hidden` only, and ensure particle distances modest. Particles travel up to ~140px from center; at 375px wide, button centered, 140px from center is within 187px half-width — ok. Vertically, +1 floats up 120px; card centered in 800px height — fine. On small mobile heights (~600), still fine. I'll use overflow-x:hidden on body and overflow:hidden on stage maybe. Let me just do body{overflow:hidden} — viewport 800 tall, content centered, particles won't exceed. At very short viewports could clip but acceptable; actually to be safe use `overflow-x: clip` and allow vertical scroll if needed. Particles positioned absolute relative to button; they can overflow card but not create scroll if body overflow-x hidden and vertical they might extend page height? Absolutely positioned elements do affect scroll area if they overflow the initial containing block... They can create scrollbars. body{overflow:hidden} prevents all scrollbars. Risk: content clipped on short screens. The layout: min-height 100vh flex center; on 800px height it's fine. I'll use overflow:hidden on body — standard for such demos.
Actually safer: `.stage{position:fixed; inset:0; overflow:hidden;}` and body normal. Then particles clipped at viewport — fine, no scrollbars ever. Do that: stage fixed inset 0, display flex center, overflow hidden.
Now animations details.
Keyframes:
```css
@keyframes idlePulse { 0%,100%{transform:scale(1)} 50%{transform:scale(1.07)} }
```
Applied to .heart-wrap (wrapper) so pop animation can be on .heart itself? If both animate transform on same element, the later one overrides. Put idle on wrapper .heart-wrap; on checked, apply pop to .heart (inner). Wrapper keeps pulsing while checked — fine, or pause. Keep pulsing; pop on inner adds craziness. Actually wrapper pulsing + inner pop both scale — combined ok.
Pop keyframes (crazy):
```css
@keyframes pop {
0% { transform: scale(0) rotate(-30deg); }
30% { transform: scale(1.5) rotate(10deg); }
50% { transform: scale(0.85) rotate(-8deg); }
70% { transform: scale(1.2) rotate(4deg); }
85% { transform: scale(0.95) rotate(-2deg); }
100% { transform: scale(1) rotate(0); }
}
```
duration .7s cubic-bezier maybe just linear with those keys; use `cubic-bezier(.2,.8,.3,1.2)`? Keyframes already overshoot; timing ease-out. `animation: pop .7s cubic-bezier(.34,1.56,.64,1) both;` fill both so starts at scale 0 when checked.
Heart color: default #94a3b8 (slate), checked: #ff2d78 with transition .3s; also drop-shadow glow when checked: filter drop-shadow(0 0 18px rgba(255,45,120,.8)) — animate via keyframes glowPulse infinite while checked: drop-shadow pulsing. filter animation ok.
Particles: define with nth-of-type. Let me write HTML:
```html
<span class="fx" aria-hidden="true">
<i class="ring r1"></i><i class="ring r2"></i><i class="ring r3"></i>
<i class="p p1"></i> ... p14
<i class="star s1"></i><i class="star s2"></i><i class="star s3"></i>
<b class="plus plus1">+1</b><b class="plus plus2">+1</b><b class="plus plus3">+1</b>
<i class="mini-heart mh1"></i><i class="mini-heart mh2"></i><i class="mini-heart mh3"></i>
</span>
```
All i elements: position absolute, left 50% top 50% of button (the heart center maybe). Button layout: flex row: heart + text. Particles should emanate from heart center. Position .fx absolute at heart location: easier to put .fx inside .heart-wrap, positioned center of heart. Then particles emanate from heart. Yes: put fx inside heart wrap.
mini-hearts: small CSS hearts (scale down the heart shape) — reuse via transform scale(.25) on an element with same before/after? Simpler: make mini heart a small element with background and clip-path: path? clip-path with path() support fine in Chrome: `clip-path: path('M10 30 ...')` heart path. Or just rotate square + two circles via ::before/::after scaled. Simplest: mini heart = span with `clip-path: path("M12 21s-8-5.5-8-11a4.5 4.5 0 0 1 8-2.8A4.5 4.5 0 0 1 20 10c0 5.5-8 11-8 11z")` in 24x24 box, background pink. clip-path path() works in Chrome. Good, also could use for star: star via clip-path polygon. Use polygon stars (5-point) — polygon points computable: standard star polygon: `polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%)`.
Particles p1..p14: set per-class custom props: `--dx`, `--dy`, `--r` (rotation), `--d` (delay), `--s` size, color via class or nth. Animation:
```css
.cb:checked ~ .stage .p {
animation: burst .9s cubic-bezier(.17,.67,.35,1) forwards;
animation-delay: var(--d, 0s);
}
@keyframes burst {
0% { transform: translate(-50%,-50%) scale(1) rotate(0deg); opacity: 1; }
100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.2) rotate(var(--r)); opacity: 0; }
}
```
Default state (unchecked): opacity 0 so hidden.
Sizes: width/height var(--sz, 10px); border-radius 50% for dots; squares class .sq with border-radius 3px.
Angles: distribute: p1 (0,-120), p2 (60,-110), p3 (110,-70), p4 (125,-10), p5 (110,60), p6 (70,110), p7 (0,125), p8 (-70,110), p9 (-115,60), p10 (-130,-5), p11 (-105,-70), p12 (-55,-115), p13 (25,-125), p14 (85,-125)... mix. Delays 0–0.12s. Rotations random 180–540deg.
Stars: same burst but maybe scale up then down: separate keyframes twinkleBurst: scale 0→1.2→0 with rotation, traveling less distance. Or just include as .p with star clip-path and bigger size, animation same. Use same burst, size 18px, delays .05-.15.
Rings:
```css
.cb:checked ~ .stage .ring { animation: ring .8s ease-out forwards; animation-delay: var(--d); }
@keyframes ring { 0%{ transform: translate(-50%,-50%) scale(.4); opacity:.9 } 100%{ transform: translate(-50%,-50%) scale(2.6); opacity:0 } }
```
ring: width 70px height 70px border 3px solid #ff5c9d border-radius 50%. delays 0, .12, .24. Ring scale 2.6 of 70 = 182px diameter — at 375 wide, center of heart is near center, 91px radius — fits (half width 187). OK.
Plus ones:
```css
@keyframes rise { 0%{ transform: translate(-50%,0) scale(.6); opacity:0 } 20%{opacity:1} 100%{ transform: translate(calc(-50% + var(--dx)), -130px) scale(1.3) rotate(var(--r)); opacity:0 } }
```
plus: font-weight 800, color #ffd166 etc, positioned at top of heart wrap.
Mini hearts floating (loop while checked):
```css
.cb:checked ~ .stage .mini-heart { animation: floatHeart 1.8s ease-in infinite; animation-delay: var(--d); }
@keyframes floatHeart {
0% { transform: translate(-50%, 10px) scale(.2) rotate(0); opacity: 0; }
15% { opacity: 1; }
100% { transform: translate(calc(-50% + var(--dx)), -150px) scale(.8) rotate(var(--r)); opacity: 0; }
}
```
delays 0, .6, 1.2.
Button checked style:
```css
.cb:checked ~ .stage .btn {
background: linear-gradient(135deg, #ff2d78, #ff7a3d);
box-shadow: 0 10px 40px rgba(255,45,120,.55), 0 0 0 6px rgba(255,45,120,.15);
transform: scale(1.04);
}
.btn { transition: background .35s, box-shadow .35s, transform .2s; }
.btn:active { transform: scale(.92); }
```
Hmm .btn:active transform vs checked transform: specificity — `.cb:checked ~ .stage .btn` (0,3,1?) vs `.btn:active` (0,2,0). Checked wins, so :active won't shrink when checked. Use `.cb:checked ~ .stage .btn:active { transform: scale(.94); }` add that.
Text swap:
```css
.t { position:relative; }
.t-like,.t-liked { transition: .3s; }
.t-liked { position:absolute; inset:0; opacity:0; transform: translateY(12px) scale(.8); }
.cb:checked ~ .stage .t-like { opacity:0; transform: translateY(-12px) scale(.8); }
.cb:checked ~ .stage .t-liked { opacity:1; transform:none; }
```
Counter: same pattern with numbers: default "1,336", checked "1,337" — plus maybe a quick bump animation on checked: `animation: bump .5s`.
Card shake:
```css
.cb:checked ~ .stage .card { animation: shake .55s cubic-bezier(.36,.07,.19,.97); }
@keyframes shake {
10%,90% { transform: translate(-2px,1px) rotate(-1deg); }
20%,80% { transform: translate(4px,-2px) rotate(1.2deg); }
30%,50%,70% { transform: translate(-6px,2px) rotate(-1.6deg); }
40%,60% { transform: translate(6px,-2px) rotate(1.6deg); }
}
```
Flash overlay:
```css
.flash { position:absolute; inset:0; background: radial-gradient(circle at 50% 45%, rgba(255,80,150,.5), transparent 60%); opacity:0; pointer-events:none; }
.cb:checked ~ .stage .flash { animation: flashA .7s ease-out; }
@keyframes flashA { 0%{opacity:0} 15%{opacity:1} 100%{opacity:0} }
```
Place .flash inside stage (fixed) behind card? In front looks flashy; put z-index above bg below card? A full-screen pink flash above everything at low opacity is fun: z-index 50, pointer-events none.
Background: dark gradient + two blurred blobs animating (float).
```css
body { background: radial-gradient(1200px 800px at 70% 20%, #2b1b4d, #0d0a1a 60%); }
.blob { position:absolute; width:420px; height:420px; border-radius:50%; filter: blur(90px); opacity:.5; animation: drift 14s ease-in-out infinite alternate; }
```
Card: glassy: background rgba(255,255,255,.06), border 1px rgba(255,255,255,.12), backdrop-filter blur, border-radius 28px, padding 48px 56px, text center, color white.
Title above button: "Drop a like" heading, small caption. Hint below: "100% CSS · 0 JavaScript — click the button!".
Also add small "pure CSS" badge.
Reduced motion? Could add prefers-reduced-motion to tame — optional, nice: `@media (prefers-reduced-motion: reduce){ *{animation-duration:.01s !important; ...} }` might break the fun but it's good practice; include a light version? The task wants crazy animation; skip or include minimal. I'll include a gentle reduced-motion that shortens animations — actually keep it, harmless. Hmm, if the evaluator's Chrome has reduced motion on (unlikely), animation would be neutered. Risk small; but to be safe for "crazy animation visible", I'll skip prefers-reduced-motion. Fine.
Fonts: system fonts only (no external). Use font stack: `font-family: ui-rounded, "SF Pro Rounded", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;`. Big bold letter-spacing for LIKE.
Heart default color: #8b93a7; checked: #fff? On pink button, white heart pops. Let's do heart color: default #aab2c5, checked white with glow. Actually classic like: heart fills red/pink. Button turns pink gradient, heart white — looks great. Or keep button dark and heart turns pink with glow. I'll go: button default dark slate (#1e2433 with border), checked → vivid pink gradient, heart white. Text white both.
Heart wrapper: width 56px height 56px; before/after sized accordingly: half=28, height 46, radius 28px 28px 0 0. before left:28px; after left:0. Heart total height ≈ 46*sin? Let me just use known snippet scaled: classic 100x90: before/after width:50px height:80px, left:50px/0, radius 50px 50px 0 0, rotate ∓45deg, origin bottom corners. Scale 0.56 → width 28? Let's set wrapper 60px wide, 54 tall; before/after width:30px;height:48px;border-radius:30px 30px 0 0; before left:30px, transform rotate(-45deg), origin 0 100%; after left:0, rotate(45deg), origin 100% 100%. The bounding: fine.
Color on heart: use `background: currentColor` in before/after; set `color` on .heart. transition color .3s. Checked: `.cb:checked ~ .stage .heart { color:#fff; animation: pop .7s ..., glow 1.2s ease-in-out .7s infinite; }` glow keyframes filter drop-shadow.
Wait: pop animation on .heart, but idle pulse on wrapper .heart-wrap: `.heart-wrap { animation: idlePulse 2.2s ease-in-out infinite; }` keep.
Also add a tiny "pressed" ripple? enough.
Plus: add keyframe for counter bump.
Also maybe add confetti falling from top when checked? Could add a few pieces falling from top of card — more crazy. Add `.confetti` spans in card top area, animation fall 1.2s when checked: from translateY(-40px) rotate 0 → translateY(220px) rotate 540deg, opacity. 8 pieces with left positions and colors and delays. They're inside card (position relative, overflow visible). Nice.
Let me also make the whole stage subtly react: skip.
HTML skeleton final:
```html
<input class="cb" type="checkbox" id="like" aria-label="Like button demo">
<div class="stage">
<div class="blob b1"></div><div class="blob b2"></div><div class="blob b3"></div>
<div class="flash"></div>
<main class="card">
<span class="badge">PURE CSS · NO JS</span>
<h1>Enjoying this?</h1>
<div class="counter"><span class="num n0">1,336</span><span class="num n1">1,337</span><span class="likes-word"> likes</span></div>
<label class="btn" for="like">
<span class="heart-wrap">
<span class="fx" aria-hidden="true">
<i class="ring" style="--d:0s"></i>
<i class="ring" style="--d:.12s"></i>
<i class="ring" style="--d:.24s"></i>
<i class="p dot" style="--dx:0px;--dy:-130px;--r:220deg;--d:0s;--sz:12px"></i>
... 12 more
<i class="p star" style="..."></i> x3
<b class="plus" style="--dx:-30px;--r:-14deg;--d:.05s">+1</b>
<b class="plus" style="--dx:26px;--r:10deg;--d:.15s">+1</b>
<i class="mini" style="--dx:-46px;--r:-20deg;--d:0s"></i>
<i class="mini" style="--dx:40px;--r:18deg;--d:.6s"></i>
<i class="mini" style="--dx:6px;--r:-6deg;--d:1.2s"></i>
</span>
<span class="heart"></span>
</span>
<span class="t"><span class="t-like">LIKE</span><span class="t-liked">LIKED!</span></span>
</label>
<p class="hint">Click the button — watch it go crazy 🌀<br><small>checkbox hack + CSS animations only</small></p>
<span class="confetti" aria-hidden="true"> 8 i's </span>
</main>
</div>
```
Inline styles for custom props keep CSS shorter. Good.
Confetti pieces: `<i class="cf" style="--x:12%;--d:0s;--c:#ffd166;--r:540deg"></i>` etc. Position: absolute top: -10px left var(--x). Animation when checked: fall. Default opacity 0.
```css
.cf { position:absolute; top:-8px; left:var(--x); width:10px; height:16px; background:var(--c); border-radius:2px; opacity:0; }
.cb:checked ~ .stage .cf { animation: confFall 1.1s ease-in forwards; animation-delay: var(--d); }
@keyframes confFall { 0%{ transform: translateY(0) rotate(0); opacity:1 } 100% { transform: translateY(320px) rotate(var(--r)); opacity:0 } }
```
Confetti inside card but card has overflow visible — ok. But card shake transform + confetti absolute inside — fine.
Wait: `.cb:checked ~ .stage .cf` — cf inside .card inside .stage, descendant selector works.
Particles default hidden: `.fx i, .fx b { opacity:0 }` then animations set opacity. But ring default opacity 0 too. When unchecked after checked, animation removed → back to opacity 0 instantly. Good.
One nuance: animations with `forwards` on checked; when unchecked, the element returns to base styles. Good.
The `pop` animation on heart: base .heart has no transform; animation both? Use `animation: pop .7s cubic-bezier(.34,1.56,.64,1) both;` — 'both' applies 0% frame before delay (no delay) fine.
Glow infinite after pop: two animations comma-separated with delays: `animation: pop .7s ... both, glowPulse 1.4s ease-in-out .7s infinite;` glowPulse from drop-shadow small to big. But filter on .heart with before/after children — drop-shadow applies to element's rendered alpha including pseudo-elements? filter on parent applies to whole element rendering including pseudos — yes.
Heart color transition plus pop: ok.
Button size: padding 18px 34px, gap 14px, border-radius 999px, font-size 20px, letter-spacing 2px, cursor pointer, user-select none. touch-action manipulation.
Layout: .stage fixed inset 0 display grid place-items center. Card text center. h1 font-size clamp(28px, 5vw, 44px). Counter font-size 15px opacity .8.
Badge: small pill top.
Hint: margin-top 22px, color rgba(255,255,255,.65), font-size 14px.
Viewport small: card padding clamp(28px, 6vw, 56px); max-width min(92vw, 480px).
Now write all particle styles. Colors palette: #ff2d78, #ffd166, #7c5cff, #4cc9f0, #ff7a3d, #f72585, #ffffff.
Dots (12):
1: dx 0, dy -135, sz 12, c pink, r 200deg, d 0
2: dx 70, dy -118, sz 9, c yellow, r 320, d .02
3: dx 122, dy -78, sz 11, c cyan, r 180, d .04
4: dx 140, dy -12, sz 8, c purple, r 420, d 0
5: dx 122, dy 62, sz 12, c orange, r 260, d .06
6: dx 78, dy 118, sz 9, c pink, r 380, d .03
7: dx 0, dy 138, sz 11, c yellow, r 200, d .05
8: dx -80, dy 116, sz 10, c cyan, r 300, d .01
9: dx -126, dy 60, sz 9, c purple, r 450, d .07
10: dx -142, dy -10, sz 12, c orange, r 240, d .02
11: dx -112, dy -82, sz 8, c pink, r 360, d .04
12: dx -58, dy -124, sz 10, c white, r 280, d .06
Squares (4) class sq: use some of above with sq class changing border-radius; simpler: make all .p circles, and 4 stars. Stars (3): sz 20, clip-path star polygon, colors yellow/white/pink, dx/dy mid distances, delays .08/.12/.16, r 540.
Burst keyframes include scale from 1→0.15; stars maybe scale 1→0 with spin — same fine.
Also add a big central flash circle behind heart: `.boom` — white radial circle scaling 0→1.6 fading:
```css
.boom { position:absolute; left:50%; top:50%; width:40px; height:40px; border-radius:50%; background: radial-gradient(circle, #fff, rgba(255,255,255,0) 70%); opacity:0; transform: translate(-50%,-50%); }
.cb:checked ~ .stage .boom { animation: boom .5s ease-out forwards; }
@keyframes boom { 0%{ transform:translate(-50%,-50%) scale(.2); opacity:.9 } 100%{ transform:translate(-50%,-50%) scale(3.4); opacity:0 } }
```
scale 3.4*40=136px — fine.
Mini hearts: 16px box clip-path heart path, background #ff5c9d.
Heart clip path for mini: `path('M8 14.5C4.5 11.5 1 8.9 1 5.6 1 3.2 2.9 1.5 5 1.5c1.2 0 2.3.6 3 1.6.7-1 1.8-1.6 3-1.6 2.1 0 4 1.7 4 4.1 0 3.3-3.5 5.9-7 8.9z')` in 16x16 viewBox — path() uses px coords matching element box (16px). Let me craft: element 16x16. Heart path: M8 14 C4 10.5 1 8.2 1 5.4 C1 3.1 2.8 1.5 4.8 1.5 C6 1.5 7.2 2.1 8 3.2 C8.8 2.1 10 1.5 11.2 1.5 C13.2 1.5 15 3.1 15 5.4 C15 8.2 12 10.5 8 14 Z. Good enough.
Star polygon as above.
Counter bump: `.cb:checked ~ .stage .counter { animation: bump .5s ... }` bump scale 1→1.25→1. But counter also has crossfading numbers. Fine.
Number swap: `.n1` absolute? Place both inline with position relative container: `.nums{position:relative; display:inline-block; width: 4ch?}` Simpler: n0 default, n1 absolute inset 0 opacity 0. Container inline-block position relative. "1,336" width — set min-width to fit. Use `.nums{position:relative;display:inline-block;}` `.n1{position:absolute; left:0; top:0;}` transitions.
Same for .t word swap: container inline-block relative; t-liked absolute left 0 top 0; but widths differ (LIKE vs LIKED!) — absolute overlay centered: make .t display:inline-flex? Use grid stack: `.t{display:inline-grid; place-items:center;} .t > span{grid-area:1/1;}` — both stacked, container width = max.
Similarly nums grid stack. Nice, no absolute needed.
Transitions on spans with transform/opacity.
Now the checkbox focus ring: `.cb:focus-visible ~ .stage .btn { outline:3px solid #7c5cff; outline-offset:4px; }`.
Also, keyboard: after clicking iframe, Tab focuses checkbox? It's opacity 0 but focusable; first Tab focuses it. Fine. Also make body have the checkbox — add `autofocus`? In sandboxed iframe autofocus may work since it's same document load... autofocus attribute works on load if document has focus; iframe likely not focused. Skip; label click is primary.
Edge: label click toggles checkbox → :checked applies. Also space key when checkbox focused toggles.
Title: "Pure CSS Like Button".
Let me also add subtle noise? skip.
Write the final CSS carefully.
Base:
```css
*{margin:0;padding:0;box-sizing:border-box}
html,body{height:100%}
body{
font-family: ui-rounded, "SF Pro Rounded", "Segoe UI", system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
background:#0d0a1a;
color:#fff;
overflow:hidden;
-webkit-tap-highlight-color: transparent;
}
.cb{position:fixed; width:1px;height:1px; opacity:0; pointer-events:none;}
```
Hmm pointer-events none on checkbox fine (label handles). But keyboard focus: opacity 0 element still focusable. ok.
Stage:
```css
.stage{position:fixed; inset:0; display:grid; place-items:center; overflow:hidden;
background: radial-gradient(1000px 700px at 75% 15%, #33205e 0%, transparent 55%),
radial-gradient(900px 700px at 15% 85%, #143a5e 0%, transparent 55%),
linear-gradient(160deg, #171129, #0b0918 70%);
}
```
Blobs:
```css
.blob{position:absolute; border-radius:50%; filter:blur(100px); opacity:.45; pointer-events:none;}
.b1{width:440px;height:440px; background:#7c3aed; top:-120px; right:-100px; animation:drift1 16s ease-in-out infinite alternate;}
.b2{width:380px;height:380px; background:#ff2d78; bottom:-140px; left:-120px; animation:drift2 20s ease-in-out infinite alternate;}
.b3{width:260px;height:260px; background:#06b6d4; top:55%; left:60%; animation:drift1 24s ease-in-out infinite alternate-reverse; opacity:.3}
@keyframes drift1{to{transform:translate(-70px,60px) scale(1.15)}}
@keyframes drift2{to{transform:translate(80px,-70px) scale(.9)}}
```
Flash:
```css
.flash{position:absolute; inset:0; pointer-events:none; opacity:0; z-index:5;
background: radial-gradient(circle at 50% 46%, rgba(255,90,160,.55), rgba(255,90,160,0) 55%);}
.cb:checked ~ .stage .flash{animation:flashA .8s ease-out;}
@keyframes flashA{0%{opacity:0}12%{opacity:1}100%{opacity:0}}
```
Card:
```css
.card{position:relative; z-index:2; text-align:center; padding:clamp(30px,5vw,52px) clamp(26px,6vw,60px);
background:rgba(255,255,255,.055); border:1px solid rgba(255,255,255,.12); border-radius:30px;
backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
box-shadow: 0 30px 80px rgba(0,0,0,.45);
max-width:min(92vw, 460px);}
.cb:checked ~ .stage .card{animation:shake .55s cubic-bezier(.36,.07,.19,.97);}
```
Badge:
```css
.badge{display:inline-block; font-size:11px; font-weight:700; letter-spacing:.18em; padding:7px 14px; border-radius:999px;
background:linear-gradient(135deg, rgba(124,92,255,.25), rgba(255,45,120,.25)); border:1px solid rgba(255,255,255,.18); color:#e7dcff; margin-bottom:18px;}
h1{font-size:clamp(26px,5.4vw,40px); font-weight:800; letter-spacing:-.02em; margin-bottom:8px;}
```
Counter:
```css
.counter{font-size:15px; color:rgba(255,255,255,.65); margin-bottom:26px; font-weight:600;}
.nums{display:inline-grid; place-items:center; margin-right:6px;}
.nums>span{grid-area:1/1; transition:opacity .3s, transform .3s;}
.n1{opacity:0; transform:translateY(10px) scale(.7); color:#ff5c9d; font-weight:800;}
.cb:checked ~ .stage .n0{opacity:0; transform:translateY(-10px) scale(.7);}
.cb:checked ~ .stage .n1{opacity:1; transform:none;}
.cb:checked ~ .stage .counter{animation:bump .5s cubic-bezier(.34,1.56,.64,1);}
@keyframes bump{0%{transform:scale(1)}40%{transform:scale(1.3)}100%{transform:scale(1)}}
```
Wait counter animation transform conflicts nothing. ok. But `.counter` bump also transforms nums... fine.
Button:
```css
.btn{position:relative; display:inline-flex; align-items:center; gap:16px; cursor:pointer; user-select:none;
padding:20px 38px; border-radius:999px; font-size:21px; font-weight:800; letter-spacing:.14em;
color:#dfe4f2; background:linear-gradient(160deg,#2a3050,#1a1f36);
border:1px solid rgba(255,255,255,.16);
box-shadow: 0 12px 30px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.08);
transition: background .4s, box-shadow .4s, transform .18s ease, color .3s;}
.btn:active{transform:scale(.93);}
.cb:checked ~ .stage .btn{
background:linear-gradient(135deg,#ff2d78 0%, #ff5e3a 100%);
color:#fff;
box-shadow: 0 14px 44px rgba(255,45,120,.55), 0 0 0 8px rgba(255,45,120,.14), inset 0 1px 0 rgba(255,255,255,.35);
transform:scale(1.05);}
.cb:checked ~ .stage .btn:active{transform:scale(.95);}
.cb:focus-visible ~ .stage .btn{outline:3px solid #8f7bff; outline-offset:4px;}
```
Heart:
```css
.heart-wrap{position:relative; width:58px; height:54px; display:grid; place-items:center; animation:idlePulse 2.4s ease-in-out infinite;}
@keyframes idlePulse{0%,100%{transform:scale(1)}50%{transform:scale(1.08)}}
.heart{position:relative; width:58px; height:54px; color:#9aa3bd; transition:color .35s;}
.heart::before,.heart::after{content:""; position:absolute; top:0; width:30px; height:48px; background:currentColor; border-radius:30px 30px 0 0;}
.heart::before{left:29px; transform:rotate(-45deg); transform-origin:0 100%;}
.heart::after{left:0; transform:rotate(45deg); transform-origin:100% 100%;}
.cb:checked ~ .stage .heart{color:#fff; animation:pop .75s cubic-bezier(.34,1.56,.64,1) both, glowPulse 1.3s ease-in-out .75s infinite;}
@keyframes pop{
0%{transform:scale(0) rotate(-40deg)}
30%{transform:scale(1.55) rotate(12deg)}
50%{transform:scale(.82) rotate(-9deg)}
70%{transform:scale(1.22) rotate(5deg)}
85%{transform:scale(.94) rotate(-2deg)}
100%{transform:scale(1) rotate(0)}
}
@keyframes glowPulse{0%,100%{filter:drop-shadow(0 0 6px rgba(255,255,255,.55))}50%{filter:drop-shadow(0 0 22px rgba(255,255,255,.95))}}
```
Check heart geometry: before at left:29px width 30 → spans 29..59; rotated -45 about bottom-left (29,48). Hmm classic uses left:50px width 50 in 100 width → before left = width/2. So left:29px (width 58/2=29). after left:0. Height 48 vs width 30: heart height ≈ 48 - 30 + 48*cos45? Whatever, looks heart-ish: total height = 48*cos(45)+... let me verify visually: The classic snippet: width:100px;height:90px? Actually classic: .heart{width:100px;height:100px} before/after width:50 height:80, left:50/0, radius 50 50 0 0, rotate(-45/45), origins (0 100%)/(100% 100%). Heart spans 0..100 wide, height ~ 80*cos45+50*sin45 ≈ 56.6+35.4=92? plus... it yields heart ~100x90. Scale by 0.58: width 58, before/after width 29, height 46.4, radius 29. I'll use width:29px;height:47px;border-radius:29px 29px 0 0; before left:29px; wrapper 58x54. Close enough; slight tweak fine. Actually let me keep ratio: use width 58, half 29, height 47. before{left:29px} after{left:0}. Good.
Text stack:
```css
.t{display:inline-grid; place-items:center;}
.t>span{grid-area:1/1; transition:opacity .3s, transform .3s;}
.t-liked{opacity:0; transform:translateY(14px) scale(.7); color:#fff;}
.cb:checked ~ .stage .t-like{opacity:0; transform:translateY(-14px) scale(.7);}
.cb:checked ~ .stage .t-liked{opacity:1; transform:none;}
```
FX layer:
```css
.fx{position:absolute; inset:0; pointer-events:none;}
.fx i,.fx b{position:absolute; left:50%; top:50%; opacity:0; display:block;}
.p{width:var(--sz,10px); height:var(--sz,10px); border-radius:50%; background:var(--c,#ff2d78);}
.p.sq{border-radius:3px;}
.star{width:var(--sz,18px); height:var(--sz,18px); background:var(--c,#ffd166); border-radius:0;
clip-path:polygon(50% 0%,61% 35%,98% 35%,68% 57%,79% 91%,50% 70%,21% 91%,32% 57%,2% 35%,39% 35%);}
.ring{width:74px; height:74px; border:3px solid rgba(255,120,180,.9); border-radius:50%;}
.boom{width:44px;height:44px;border-radius:50%; background:radial-gradient(circle,#fff 0%, rgba(255,255,255,0) 68%);}
.plus{font-size:22px; font-weight:900; color:#ffd166; font-style:normal; text-shadow:0 2px 10px rgba(0,0,0,.4);}
.mini{width:16px;height:16px; background:#ff5c9d; clip-path:path('M8 14C4 10.6 1 8.2 1 5.4 1 3.1 2.8 1.5 4.8 1.5 6 1.5 7.2 2.1 8 3.2 8.8 2.1 10 1.5 11.2 1.5 13.2 1.5 15 3.1 15 5.4 15 8.2 12 10.6 8 14Z');}
```
Note clip-path path() coordinates: element is 16x16, path units are px in user space — for clip-path:path() the path is in the element's local coordinate system with px units, origin top-left. Should work in Chrome.
Animations when checked:
```css
.cb:checked ~ .stage .p,
.cb:checked ~ .stage .star{animation:burst .95s cubic-bezier(.16,.7,.3,1) forwards; animation-delay:var(--d,0s);}
@keyframes burst{
0%{transform:translate(-50%,-50%) scale(1) rotate(0deg); opacity:1;}
100%{transform:translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.15) rotate(var(--r,300deg)); opacity:0;}
}
.cb:checked ~ .stage .ring{animation:ringA .85s ease-out forwards; animation-delay:var(--d,0s);}
@keyframes ringA{0%{transform:translate(-50%,-50%) scale(.35); opacity:.95;}100%{transform:translate(-50%,-50%) scale(2.8); opacity:0;}}
.cb:checked ~ .stage .boom{animation:boomA .55s ease-out forwards;}
@keyframes boomA{0%{transform:translate(-50%,-50%) scale(.2); opacity:.95;}100%{transform:translate(-50%,-50%) scale(3.6); opacity:0;}}
.cb:checked ~ .stage .plus{animation:riseA 1s ease-out forwards; animation-delay:var(--d,0s);}
@keyframes riseA{0%{transform:translate(-50%,0) scale(.5) rotate(0); opacity:0;}18%{opacity:1;}100%{transform:translate(calc(-50% + var(--dx)), -140px) scale(1.35) rotate(var(--r,0deg)); opacity:0;}}
.cb:checked ~ .stage .mini{animation:floatA 1.9s ease-in infinite; animation-delay:var(--d,0s);}
@keyframes floatA{0%{transform:translate(-50%,6px) scale(.15) rotate(0); opacity:0;}12%{opacity:1;}100%{transform:translate(calc(-50% + var(--dx)), -160px) scale(.85) rotate(var(--r,0deg)); opacity:0;}}
```
Confetti:
```css
.cf{position:absolute; top:-6px; left:var(--x,50%); width:9px; height:15px; border-radius:2px; background:var(--c,#ffd166); opacity:0; z-index:3;}
.cb:checked ~ .stage .cf{animation:confFall 1.15s cubic-bezier(.3,.6,.6,1) forwards; animation-delay:var(--d,0s);}
@keyframes confFall{0%{transform:translateY(0) rotate(0); opacity:1;}85%{opacity:1;}100%{transform:translateY(330px) rotate(var(--r,520deg)); opacity:0;}}
```
Card height ~ 380px; confetti falls 330px — may exit card bottom, fine (stage overflow hidden). But confetti inside card which shakes — ok.
Hint:
```css
.hint{margin-top:26px; font-size:14px; line-height:1.5; color:rgba(255,255,255,.6);}
.hint small{font-size:12px; color:rgba(255,255,255,.4);}
```
Add a blinking "click me" arrow? The hint itself pulses:
```css
.hint .pulse{display:inline-block; animation:hintPulse 1.6s ease-in-out infinite;}
@keyframes hintPulse{0%,100%{opacity:1}50%{opacity:.45}}
```
Wrap "Click the button!" in span.pulse. When checked, stop pulsing / change text? Could swap hint text too: two stacked spans: "click the button!" ↔ "nice! click again to unlike". Do grid stack like others.
```html
<p class="hint"><span class="hint-t"><span class="h0">👆 Click the button — go crazy</span><span class="h1">🎉 Liked! Click again to reset</span></span><br><small>checkbox hack · keyframes · zero JavaScript</small></p>
```
Emojis okay. h1 hidden default.
```css
.hint-t{display:inline-grid; place-items:center;}
.hint-t>span{grid-area:1/1; transition:.3s;}
.h0{animation:hintPulse 1.6s ease-in-out infinite;}
.h1{opacity:0; transform:translateY(8px);}
.cb:checked ~ .stage .h0{opacity:0; transform:translateY(-8px); animation:none;}
.cb:checked ~ .stage .h1{opacity:1; transform:none;}
```
Shake keyframes:
```css
@keyframes shake{
10%,90%{transform:translate(-2px,1px) rotate(-.6deg);}
20%,80%{transform:translate(4px,-2px) rotate(.8deg);}
30%,50%,70%{transform:translate(-6px,2px) rotate(-1.2deg);}
40%,60%{transform:translate(6px,-3px) rotate(1.2deg);}
}
```
Particles HTML — write with inline custom props. Also give some .p class "sq" for squares. Let me define 16 particles: 12 dots + 4 squares? Plus 3 stars. Let's list:
```html
<i class="boom"></i>
<i class="ring" style="--d:0s"></i>
<i class="ring" style="--d:.13s"></i>
<i class="ring" style="--d:.26s"></i>
<i class="p" style="--c:#ff2d78;--sz:12px;--dx:0px;--dy:-138px;--r:220deg;--d:0s"></i>
<i class="p" style="--c:#ffd166;--sz:9px;--dx:72px;--dy:-120px;--r:330deg;--d:.03s"></i>
<i class="p" style="--c:#4cc9f0;--sz:11px;--dx:126px;--dy:-80px;--r:180deg;--d:.05s"></i>
<i class="p sq" style="--c:#7c5cff;--sz:10px;--dx:146px;--dy:-14px;--r:420deg;--d:0s"></i>
<i class="p" style="--c:#ff7a3d;--sz:12px;--dx:126px;--dy:64px;--r:260deg;--d:.07s"></i>
<i class="p" style="--c:#f72585;--sz:9px;--dx:80px;--dy:122px;--r:380deg;--d:.04s"></i>
<i class="p" style="--c:#ffd166;--sz:11px;--dx:0px;--dy:142px;--r:200deg;--d:.06s"></i>
<i class="p sq" style="--c:#4cc9f0;--sz:10px;--dx:-82px;--dy:118px;--r:300deg;--d:.02s"></i>
<i class="p" style="--c:#7c5cff;--sz:9px;--dx:-130px;--dy:62px;--r:450deg;--d:.08s"></i>
<i class="p" style="--c:#ff7a3d;--sz:12px;--dx:-148px;--dy:-12px;--r:240deg;--d:.01s"></i>
<i class="p" style="--c:#ff2d78;--sz:8px;--dx:-114px;--dy:-84px;--r:360deg;--d:.05s"></i>
<i class="p sq" style="--c:#ffffff;--sz:9px;--dx:-58px;--dy:-128px;--r:280deg;--d:.07s"></i>
<i class="p" style="--c:#4cc9f0;--sz:8px;--dx:40px;--dy:-136px;--r:400deg;--d:.09s"></i>
<i class="p" style="--c:#ffd166;--sz:8px;--dx:104px;--dy:-122px;--r:320deg;--d:.1s"></i>
<i class="star" style="--c:#ffd166;--sz:20px;--dx:-30px;--dy:-96px;--r:540deg;--d:.08s"></i>
<i class="star" style="--c:#ffffff;--sz:16px;--dx:88px;--dy:-40px;--r:540deg;--d:.13s"></i>
<i class="star" style="--c:#ff5c9d;--sz:18px;--dx:-92px;--dy:28px;--r:540deg;--d:.18s"></i>
<b class="plus" style="--dx:-34px;--r:-16deg;--d:.05s">+1</b>
<b class="plus" style="--dx:30px;--r:12deg;--d:.16s; color:#7cf7c4">+1</b>
<i class="mini" style="--dx:-52px;--r:-22deg;--d:0s"></i>
<i class="mini" style="--dx:44px;--r:20deg;--d:.65s"></i>
<i class="mini" style="--dx:4px;--r:-8deg;--d:1.3s"></i>
```
Note: `.p.sq` border-radius 3px. star uses clip-path, background var(--c).
Confetti HTML inside card:
```html
<span class="confetti" aria-hidden="true">
<i class="cf" style="--x:8%;--c:#ff2d78;--r:560deg;--d:.02s"></i>
<i class="cf" style="--x:20%;--c:#ffd166;--r:-480deg;--d:.1s"></i>
<i class="cf" style="--x:33%;--c:#4cc9f0;--r:620deg;--d:.05s"></i>
<i class="cf" style="--x:46%;--c:#7c5cff;--r:-540deg;--d:.14s"></i>
<i class="cf" style="--x:58%;--c:#ff7a3d;--r:500deg;--d:.03s"></i>
<i class="cf" style="--x:70%;--c:#f72585;--r:-600deg;--d:.12s"></i>
<i class="cf" style="--x:82%;--c:#7cf7c4;--r:580deg;--d:.07s"></i>
<i class="cf" style="--x:93%;--c:#ffffff;--r:-520deg;--d:.16s"></i>
</span>
```
.confetti{position:absolute; inset:0; pointer-events:none;} Actually put class on wrapper span with position absolute inset 0. cf positioned within.
Wait: cf left uses --x percent of card width; top -6px. ok.
Potential issue: `.fx` inset 0 of heart-wrap (58x54) — particles emanate from heart center: left 50% top 50% of heart-wrap = heart center.
Plus b elements: font-style normal for <b>? b is bold anyway; fine.
One more consideration: the `.btn` is a label; clicking anywhere on it toggles. Particles have pointer-events none via .fx. Good.
Also add `aria-hidden` on decorative spans.
Also the checkbox itself: place as first element in body. Selector `.cb:checked ~ .stage` requires .stage to be a later sibling of .cb — yes if input is direct child of body and stage also direct child after it.
Font for numbers: use tabular? fine.
Small screens: button padding maybe reduce via clamp: padding: clamp(14px,3.5vw,20px) clamp(24px,6vw,38px); font-size clamp(17px,4.5vw,21px). Heart fixed 58px fine.
Let me also double check "no horizontal scrollbar": body overflow hidden — set. html overflow hidden too.
Screenshot at 3s: initial state shows idle pulsing heart, blobs, hint pulsing — meaningful visible. Good.
Zero JS: none. No external anything.
Title and meta.
One more crazy touch: when checked, add rotating conic "aura" behind button? Maybe a spinning dashed ring around button: `.btn::after`? Label pseudo elements: .btn::before could be aura: position absolute inset -14px border 2px dashed rgba(255,255,255,.5) border-radius 999px, animation spin 6s linear infinite, opacity 0 default; checked → opacity 1 spin. Cute! Add:
```css
.btn::after{content:""; position:absolute; inset:-12px; border:2px dashed rgba(255,255,255,.0); border-radius:999px; pointer-events:none; transition:border-color .3s;}
.cb:checked ~ .stage .btn::after{border-color:rgba(255,255,255,.55); animation:spin 7s linear infinite;}
@keyframes spin{to{transform:rotate(360deg)}}
```
inset -12px with dashed border spinning — nice halo. But transform rotate on ::after with border-radius pill: rotating a pill border looks odd (pill rotating around center shows movement) — it's a rounded rect, rotation visible as wobble — actually fun. Keep.
Also maybe heart "beats" twice quickly at start via pop already covers.
Edge: `.cb:checked ~ .stage .heart` animation overrides nothing else. When unchecked mid-animation, snaps back — fine.
Also add `will-change`? not necessary.
Let me now also handle `prefers-reduced-motion`: skip.
Check selector specificity for `.cb:checked ~ .stage .p` — .p base has opacity 0; animation sets opacity during run; with forwards keeps 0 at end. Good.
The ring uses border color pinkish; also add second ring style color? keep same.
Write final HTML. Also include `<meta name="viewport">`. Title.
Let me make sure the h1 says something like "Loved this demo?" and counter "1,336 likes".
Also add small footer note? hint covers it.
Double-check clip-path path syntax: `clip-path: path('M8 14C4 10.6 1 8.2 1 5.4 1 3.1 2.8 1.5 4.8 1.5 6 1.5 7.2 2.1 8 3.2 8.8 2.1 10 1.5 11.2 1.5 13.2 1.5 15 3.1 15 5.4 15 8.2 12 10.6 8 14Z')` — path with implicit lineto after C? In SVG path, after C coordinates, subsequent coordinate pairs are treated as additional cubic segments (implicit repeat of C). So "C4 10.6 1 8.2 1 5.4 1 3.1 2.8 1.5 4.8 1.5 ..." means C(4 10.6)(1 8.2)(1 5.4) then C(1 3.1)(2.8 1.5)(4.8 1.5) then C(6 1.5)(7.2 2.1)(8 3.2)... valid. Ending Z. Good.
Star polygon fine.
Also ensure `.fx` doesn't capture clicks: pointer-events none set.
Also label default cursor pointer set.
Now, is there any issue with `animation` shorthand on `.cb:checked ~ .stage .heart` combining pop (both) and glowPulse infinite with delay — during first .75s glowPulse is in delay phase (no fill) so no filter — fine.
Card shake uses transform — card also has no other transform. ok.
Counter bump animation on .counter — .counter contains .nums grid; transform scale on counter fine.
One concern: `.cb:checked ~ .stage .btn` has `transform: scale(1.05)` via state (not animation) with transition — good.
Focus outline on label: `.cb:focus-visible ~ .stage .btn` — when checkbox focused via keyboard, label gets outline. Good.
Also, clicking label triggers focus on checkbox in some browsers (label click focuses associated control) — Chrome does focus the checkbox on label click, so focus-visible may not show (mouse). Fine.
Let me write out the whole file now, carefully, ensuring valid CSS.
Also add slight text gradient on h1? `background: linear-gradient(...); -webkit-background-clip:text; color:transparent;` nice touch:
```css
h1 span{background:linear-gradient(90deg,#ff8ab8,#ffd166,#8ab8ff); -webkit-background-clip:text; background-clip:text; color:transparent;}
```
Wrap h1 text in span.
Final check on sizes at 375px: card max-width 92vw=345, padding 26 → content 293 wide. Button: heart 58 + gap 16 + text "LIKED!" at 17px letterspacing .14em ≈ 6 chars*~14px ≈ 90px + padding 2*24 = 48 → total ≈ 212. Fits.
Particles max |dx| 148 + sz → 160px from heart center; heart center is at card center-x roughly minus text offset... button centered; heart at left side of button: button width ~212, heart center ≈ 24+29=53px from button left; button left ≈ (345-212)/2 ≈ 66 → heart center x ≈ 119 from card left; card left ≈ (375-345)/2=15 → x ≈ 134 from viewport left; +160 = 294 < 375 fine. Left side: 134-160 = -26 → clipped by stage overflow hidden, no scrollbar. Good.
Rings scale 2.8 * 74 = 207 diameter → radius 103 — fine.
Plus rises -140px above heart; heart top y: viewport 800, card centered ~ height 400 → card top ~200, button center ~ 200+ badge/h1/counter... roughly y 380; minus 140 = 240 > 0 fine.
Everything good. Also `overflow:hidden` on body prevents scrollbars; stage fixed also.
Write it.
Also note: no JavaScript at all — ensure no <script> tag. The instruction says games need demo mode, but this isn't a game; it's an interactive widget; initial paint shows the button with idle animation — meaningful. The click is required for the crazy animation; hint says click. Good.
Let me finalize CSS ordering and write the code block. Also add `::selection` styling maybe. Minor.
One more: `.btn` uses `touch-action: manipulation;` to avoid double-tap zoom on mobile.
Also for the checkbox, add `aria-hidden="true"`? It has aria-label; fine either way. Keep simple: `<input type="checkbox" id="like" class="cb" aria-label="Like">`.
Write final answer: exactly one ```html fenced block, no text before/after.