Exploding like buttonOne-line
MiniMax M3.1 Flash
by MiniMaxReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 1 min 20 s
- Cost
- $0.0080
- Output tokens
- 13,270
- Spent thinking
- 6,920 tokens
- Speed
- 171.1 tok/s
- Console errors
- 0
- First token after
- 2.5 s
- First visible text after
- 56.6 s
- Prompt tokens
- 541
- Code size
- 16.4 KB
- Finish reason
- stop
- Served by
- Parasail
- Model id
minimax/minimax-m3.1-flash- Reasoning sent
{"effort":"high"}- Max output
- 64,000 tokens
- Generated
- Nov 11, 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 · 382 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pure CSS Like Button</title>
<style>
@property --ang { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
*{box-sizing:border-box}
html,body{height:100%}
body{
margin:0;
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
color:#fff;
background:
radial-gradient(900px 600px at 15% 10%, #4b1d6b 0%, transparent 60%),
radial-gradient(800px 600px at 85% 85%, #0d3b66 0%, transparent 60%),
radial-gradient(700px 500px at 70% 15%, #6b1230 0%, transparent 55%),
#0a0713;
display:grid;
place-items:center;
overflow:hidden;
-webkit-font-smoothing:antialiased;
}
/* ---------- hidden checkbox (the only "logic" in the whole page) ---------- */
.toggle{
position:absolute; width:1px; height:1px; opacity:0; margin:0;
pointer-events:none;
}
.wrap{
position:relative;
width:min(92vw, 460px);
display:grid;
place-items:center;
}
/* ---------- ambient floating hearts in the background ---------- */
.ambient{position:fixed;inset:0;pointer-events:none;overflow:hidden;z-index:0}
.ambient span{
position:absolute; bottom:-60px; color:#ff5c8a; opacity:.16;
font-size:var(--s); animation: floatUp var(--t) linear infinite;
animation-delay:var(--d); text-shadow:0 0 22px rgba(255,60,120,.55);
}
@keyframes floatUp{
0%{transform:translateY(0) rotate(0deg);opacity:0}
10%{opacity:.22}
90%{opacity:.14}
100%{transform:translateY(-115vh) rotate(320deg);opacity:0}
}
/* ---------- screen flash ---------- */
.flash{
position:fixed; inset:0; pointer-events:none; z-index:5; opacity:0;
background:radial-gradient(circle at 50% 48%, rgba(255,70,130,.55) 0%, rgba(255,120,190,.22) 35%, transparent 65%);
}
/* ---------- the card ---------- */
.card{
position:relative; z-index:2;
width:100%;
padding:34px 26px 28px;
border-radius:30px;
text-align:center;
background:linear-gradient(160deg, rgba(255,255,255,.11), rgba(255,255,255,.04));
border:1px solid rgba(255,255,255,.14);
box-shadow:0 30px 80px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.25);
backdrop-filter:blur(18px) saturate(140%);
-webkit-backdrop-filter:blur(18px) saturate(140%);
animation:cardIn .8s cubic-bezier(.2,.9,.3,1) both;
}
@keyframes cardIn{from{opacity:0;transform:translateY(24px) scale(.96)}}
.card::before{
content:""; position:absolute; inset:-3px; border-radius:33px; z-index:-1;
background:conic-gradient(from var(--ang),
#ff2d78,#ff7a18,#ffe600,#3ddc84,#22d3ee,#6366f1,#d946ef,#ff2d78);
filter:blur(16px); opacity:0; transition:opacity .45s ease;
}
.toggle:checked ~ .wrap .card::before{opacity:.9;animation:spinbg 7s linear infinite}
@keyframes spinbg{to{--ang:360deg}}
.eyebrow{
margin:0 0 6px; font-size:11px; letter-spacing:.32em; text-transform:uppercase;
color:#ffb3d0; font-weight:700;
}
h1{margin:0 0 6px; font-size:clamp(26px,7vw,38px); line-height:1.1; letter-spacing:-.02em}
h1 .spark{display:inline-block;animation:twinkle 2.4s ease-in-out infinite}
@keyframes twinkle{0%,100%{transform:scale(1) rotate(0);filter:drop-shadow(0 0 0 rgba(255,220,120,0))}
50%{transform:scale(1.25) rotate(18deg);filter:drop-shadow(0 0 12px rgba(255,220,120,.9))}}
.sub{margin:0 0 24px; color:#cdbfe0; font-size:14px; line-height:1.5}
/* ---------- the button ---------- */
.stage{position:relative; display:grid; place-items:center; height:190px}
.like{
position:relative;
width:148px; height:148px; border-radius:50%;
display:grid; place-items:center;
cursor:pointer; user-select:none; -webkit-tap-highlight-color:transparent;
background:linear-gradient(145deg,#7c3aed,#4f46e5 55%,#2563eb);
border:1px solid rgba(255,255,255,.28);
box-shadow:
0 18px 40px rgba(79,70,229,.45),
inset 0 2px 0 rgba(255,255,255,.4),
inset 0 -14px 26px rgba(0,0,0,.28);
transition:transform .22s cubic-bezier(.2,1.4,.4,1), box-shadow .35s ease, background .45s ease;
z-index:2;
}
.like:hover{transform:scale(1.06)}
.like:active{transform:scale(.93)}
.toggle:checked ~ .wrap .like{
background:linear-gradient(145deg,#ff2d78,#e01e5a 55%,#b3123f);
box-shadow:
0 18px 46px rgba(255,45,120,.55),
0 0 0 6px rgba(255,45,120,.12),
inset 0 2px 0 rgba(255,255,255,.45),
inset 0 -14px 26px rgba(0,0,0,.25);
animation:btnBounce .75s cubic-bezier(.2,1.7,.35,1), glowPulse 1.6s ease-in-out infinite .75s;
}
@keyframes btnBounce{
0%{transform:scale(1)}
22%{transform:scale(.82) rotate(-7deg)}
45%{transform:scale(1.22) rotate(8deg)}
65%{transform:scale(.94) rotate(-4deg)}
82%{transform:scale(1.06) rotate(2deg)}
100%{transform:scale(1)}
}
@keyframes glowPulse{
0%,100%{box-shadow:0 18px 46px rgba(255,45,120,.5), 0 0 0 6px rgba(255,45,120,.10), inset 0 2px 0 rgba(255,255,255,.45), inset 0 -14px 26px rgba(0,0,0,.25)}
50%{box-shadow:0 18px 70px rgba(255,45,120,.9), 0 0 0 18px rgba(255,45,120,0), inset 0 2px 0 rgba(255,255,255,.45), inset 0 -14px 26px rgba(0,0,0,.25)}
}
.heart{
width:68px; height:68px; z-index:3;
fill:transparent; stroke:#fff; stroke-width:1.7;
filter:drop-shadow(0 6px 14px rgba(0,0,0,.35));
transition:fill .3s ease;
}
.toggle:checked ~ .wrap .heart{
fill:#fff; stroke:#fff;
animation:heartPop .8s cubic-bezier(.2,1.7,.3,1);
}
@keyframes heartPop{
0%{transform:scale(1)}
25%{transform:scale(.5) rotate(-12deg)}
55%{transform:scale(1.35) rotate(10deg)}
75%{transform:scale(.92) rotate(-5deg)}
100%{transform:scale(1) rotate(0)}
}
/* spinning gradient halo ring */
.ring{
position:absolute; inset:-14px; border-radius:50%; z-index:1; opacity:0;
background:conic-gradient(from 0deg, transparent 0 35%, #ff2d78, #ffd166, #7cffb2, transparent 85%);
-webkit-mask:radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
mask:radial-gradient(farthest-side, transparent calc(100% - 5px), #000 calc(100% - 4px));
transition:opacity .4s ease;
}
.toggle:checked ~ .wrap .ring{opacity:.95;animation:spin 2.6s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
/* expanding shock rings */
.rings{position:absolute; inset:0; z-index:1; pointer-events:none}
.rings i{
position:absolute; inset:0; border-radius:50%;
border:3px solid rgba(255,90,150,.85); opacity:0;
}
.toggle:checked ~ .wrap .rings i{animation:ripple 1.1s cubic-bezier(.15,.75,.3,1) infinite; animation-delay:var(--d)}
.rings i:nth-child(2){border-color:rgba(255,214,102,.8)}
.rings i:nth-child(3){border-color:rgba(150,220,255,.75)}
@keyframes ripple{
0%{transform:scale(.7);opacity:0}
18%{opacity:.9}
100%{transform:scale(2.15);opacity:0}
}
/* orbiting sparkles */
.orbit{position:absolute; inset:0; z-index:1; pointer-events:none}
.orbit i{
position:absolute; left:50%; top:50%; margin:-9px 0 0 -9px; font-size:17px;
opacity:0; filter:drop-shadow(0 0 8px rgba(255,220,130,.9));
}
.toggle:checked ~ .wrap .orbit i{
opacity:.95;
animation:orbit 3.2s linear infinite; animation-delay:var(--d);
}
@keyframes orbit{
0%{transform:rotate(var(--a)) translateX(96px) rotate(calc(-1 * var(--a)));opacity:0}
12%{opacity:.95}
88%{opacity:.95}
100%{transform:rotate(calc(var(--a) + 360deg)) translateX(96px) rotate(calc(-1 * var(--a) - 360deg));opacity:0}
}
/* burst particles */
.fx{position:absolute; inset:0; z-index:4; pointer-events:none}
.fx i{position:absolute; left:50%; top:50%; opacity:0; will-change:transform,opacity}
.p{
color:var(--c,#ff4d7d); font-size:var(--s,24px); line-height:1;
text-shadow:0 0 14px rgba(255,60,120,.75);
}
.toggle:checked ~ .wrap .fx .p{animation:burst 1.15s cubic-bezier(.12,.72,.28,1) both; animation-delay:var(--d,0s)}
@keyframes burst{
0%{transform:translate(-50%,-50%) scale(.15) rotate(0deg);opacity:0}
12%{opacity:1;transform:translate(-50%,-50%) scale(1.25) rotate(calc(var(--r) * .2))}
55%{opacity:1}
100%{transform:translate(calc(-50% + var(--x)), calc(-50% + var(--y))) scale(.55) rotate(var(--r,0deg));opacity:0}
}
/* un-like: hearts fall & fade (triggered once the box has focus, i.e. after a click) */
.toggle:focus:not(:checked) ~ .wrap .fx .p{animation:fall .75s ease-in forwards; animation-delay:var(--d,0s)}
@keyframes fall{
0%{transform:translate(-50%,-50%) scale(1) rotate(0);opacity:.9}
100%{transform:translate(calc(-50% + var(--x,0px)), calc(-50% + 150px)) scale(.4) rotate(220deg);opacity:0}
}
.sp{ color:#ffd166; font-size:var(--s,16px); }
.toggle:checked ~ .wrap .fx .sp{animation:burst 1.3s cubic-bezier(.12,.72,.28,1) both; animation-delay:var(--d,0s)}
.cf{
width:9px; height:14px; border-radius:2px; background:var(--c,#fff);
box-shadow:0 0 10px rgba(255,255,255,.35);
}
.toggle:checked ~ .wrap .fx .cf{animation:confetti 1.5s cubic-bezier(.2,.6,.4,1) both; animation-delay:var(--d,0s)}
@keyframes confetti{
0%{transform:translate(-50%,-50%) rotate(0deg);opacity:0}
10%{opacity:1}
100%{transform:translate(calc(-50% + var(--x,0px)), calc(-50% + 300px)) rotate(var(--r,540deg));opacity:0}
}
/* "+1" popup */
.pop{
position:absolute; left:50%; top:-6px; transform:translateX(-50%);
font-size:26px; font-weight:800; color:#fff; opacity:0; pointer-events:none; z-index:5;
text-shadow:0 0 18px rgba(255,90,150,.95);
}
.toggle:checked ~ .wrap .pop{animation:popUp 1.1s cubic-bezier(.2,.9,.3,1) both}
@keyframes popUp{
0%{opacity:0;transform:translate(-50%,10px) scale(.4)}
25%{opacity:1;transform:translate(-50%,-14px) scale(1.2)}
70%{opacity:1;transform:translate(-50%,-42px) scale(1)}
100%{opacity:0;transform:translate(-50%,-78px) scale(.85)}
}
/* caption */
.cap{margin-top:18px; font-size:19px; font-weight:700; letter-spacing:.01em; min-height:26px}
.cap .on{display:none}
.toggle:checked ~ .wrap .cap .off{display:none}
.toggle:checked ~ .wrap .cap .on{display:inline-block; animation:capPop .5s cubic-bezier(.2,1.6,.4,1)}
@keyframes capPop{from{transform:scale(.4);opacity:0}to{transform:scale(1);opacity:1}}
/* meta row + pure-CSS counter */
.meta{
margin-top:12px; display:inline-flex; align-items:center; gap:8px;
padding:8px 16px; border-radius:999px;
background:rgba(255,255,255,.08); border:1px solid rgba(255,255,255,.14);
font-size:14px; color:#ffe7f2;
}
.countwrap{counter-reset:likes 12047}
.toggle:checked ~ .wrap .countwrap{counter-reset:likes 12048}
.count::after{content:counter(likes)}
.badge{
margin-left:4px; font-size:10px; letter-spacing:.16em; text-transform:uppercase; font-weight:800;
padding:4px 8px; border-radius:999px; background:linear-gradient(90deg,#22d3ee,#a855f7); color:#0b0713;
}
.hint{margin:18px 0 0; font-size:12px; color:#a99cc0}
.toggle:focus-visible ~ .wrap .like{outline:3px solid #fff; outline-offset:8px}
/* shake the whole stage on like */
.toggle:checked ~ .wrap .stage{animation:shake .6s cubic-bezier(.36,.07,.19,.97)}
@keyframes shake{
10%,90%{transform:translateX(-2px)}
20%,80%{transform:translateX(4px)}
30%,50%,70%{transform:translateX(-7px)}
40%,60%{transform:translateX(7px)}
}
.toggle:checked ~ .wrap .flash{animation:flash .75s ease-out}
@keyframes flash{0%{opacity:0}20%{opacity:.9}100%{opacity:0}}
@media (max-width:420px){
.card{padding:26px 18px 22px;border-radius:24px}
.like{width:126px;height:126px}
.heart{width:58px;height:58px}
.stage{height:170px}
.orbit i{--a:0deg}
}
</style>
</head>
<body>
<input class="toggle" type="checkbox" id="like">
<div class="wrap">
<div class="flash" aria-hidden="true"></div>
<div class="ambient" aria-hidden="true">
<span style="left:8%; --s:26px; --t:13s; --d:0s">♥</span>
<span style="left:24%; --s:16px; --t:10s; --d:1.4s">♥</span>
<span style="left:38%; --s:34px; --t:16s; --d:3.1s">♥</span>
<span style="left:57%; --s:20px; --t:12s; --d:.7s">♥</span>
<span style="left:72%; --s:14px; --t:9s; --d:2.2s">♥</span>
<span style="left:86%; --s:28px; --t:14s; --d:4.3s">♥</span>
<span style="left:95%; --s:18px; --t:11s; --d:5.1s">♥</span>
</div>
<main class="card">
<p class="eyebrow">Zero JavaScript</p>
<h1>Like this <span class="spark">✨</span></h1>
<p class="sub">One hidden checkbox, one <code><label></code>, and a completely unhinged animation.</p>
<div class="stage">
<label class="like" for="like" title="Like">
<span class="ring" aria-hidden="true"></span>
<span class="rings" aria-hidden="true"><i style="--d:0s"></i><i style="--d:.28s"></i><i style="--d:.56s"></i></span>
<span class="orbit" aria-hidden="true">
<i style="--a:0deg; --d:0s">✦</i>
<i style="--a:60deg; --d:.15s">✧</i>
<i style="--a:120deg; --d:.3s">✦</i>
<i style="--a:180deg; --d:.45s">✧</i>
<i style="--a:240deg; --d:.6s">✦</i>
<i style="--a:300deg; --d:.75s">✧</i>
</span>
<span class="fx" aria-hidden="true">
<!-- hearts -->
<i class="p" style="--x:0px; --y:-150px; --r:0deg; --d:0s; --s:27px">♥</i>
<i class="p" style="--x:85px; --y:-125px; --r:120deg; --d:.04s; --s:20px; --c:#ff7aa8">♥</i>
<i class="p" style="--x:145px; --y:-60px; --r:-160deg; --d:.08s; --s:24px">♥</i>
<i class="p" style="--x:160px; --y:20px; --r:80deg; --d:.02s; --s:18px; --c:#ff9ec4">♥</i>
<i class="p" style="--x:130px; --y:95px; --r:-90deg; --d:.10s; --s:22px">♥</i>
<i class="p" style="--x:70px; --y:145px; --r:200deg; --d:.05s; --s:17px; --c:#ff6b95">♥</i>
<i class="p" style="--x:-15px; --y:155px; --r:45deg; --d:.09s; --s:25px">♥</i>
<i class="p" style="--x:-95px; --y:130px; --r:-140deg; --d:.03s; --s:19px; --c:#ff9ec4">♥</i>
<i class="p" style="--x:-145px;--y:65px; --r:110deg; --d:.07s; --s:23px">♥</i>
<i class="p" style="--x:-165px;--y:-15px; --r:-60deg; --d:.11s; --s:18px; --c:#ff6b95">♥</i>
<i class="p" style="--x:-120px;--y:-100px; --r:170deg; --d:.06s; --s:21px">♥</i>
<i class="p" style="--x:-45px; --y:-150px; --r:-120deg; --d:.12s; --s:16px; --c:#ff9ec4">♥</i>
<!-- sparkles -->
<i class="p sp" style="--x:52px; --y:-162px; --r:200deg; --d:.13s; --s:18px">✦</i>
<i class="p sp" style="--x:-118px;--y:-138px; --r:60deg; --d:.18s; --s:15px">✦</i>
<i class="p sp" style="--x:168px; --y:62px; --r:280deg; --d:.22s; --s:17px">✧</i>
<i class="p sp" style="--x:-168px;--y:-52px; --r:120deg; --d:.26s; --s:16px">✦</i>
<i class="p sp" style="--x:20px; --y:172px; --r:340deg; --d:.30s; --s:14px">✧</i>
<i class="p sp" style="--x:-40px; --y:168px; --r:20deg; --d:.34s; --s:16px">✦</i>
<!-- confetti -->
<i class="cf" style="--x:-70px; --r:520deg; --d:.02s; --c:#ffd166"></i>
<i class="cf" style="--x:66px; --r:-420deg;--d:.05s; --c:#22d3ee"></i>
<i class="cf" style="--x:-120px;--r:680deg; --d:.08s; --c:#ff6b95"></i>
<i class="cf" style="--x:118px; --r:-610deg;--d:.11s; --c:#a3e635"></i>
<i class="cf" style="--x:-18px; --r:460deg; --d:.14s; --c:#ffffff"></i>
<i class="cf" style="--x:34px; --r:-560deg;--d:.17s; --c:#c084fc"></i>
<i class="cf" style="--x:-92px; --r:380deg; --d:.20s; --c:#ffd166"></i>
<i class="cf" style="--x:96px; --r:-480deg;--d:.23s; --c:#34d399"></i>
<i class="cf" style="--x:-46px; --r:600deg; --d:.26s; --c:#fb7185"></i>
<i class="cf" style="--x:8px; --r:-700deg;--d:.29s; --c:#38bdf8"></i>
</span>
<span class="pop" aria-hidden="true">+1</span>
<svg class="heart" viewBox="0 0 24 24" aria-hidden="true">
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>
</label>
</div>
<div class="cap"><span class="off">Like</span><span class="on">Liked! 🎉</span></div>
<div class="meta">
<span class="countwrap"><span class="count"></span></span>
<span>likes</span>
<span class="badge">CSS only</span>
</div>
<p class="hint">Click the heart (or focus it and press <b>Space</b>) — no scripts were harmed.</p>
</main>
</div>
</body>
</html>Reasoning trace (6,920 tokens)
The task: a "like" button in pure CSS, no JavaScript, that does a crazy animation when you click it. Need the checkbox hack: hidden checkbox + label. But "no JavaScript" — CSS only. Clicking the label toggles the checkbox, triggering animations.
Make it crazy: burst of hearts, confetti, rings, color change, sparkles, wiggle, scale, glow, flying emoji particles, etc.
Let's build a nice design: dark gradient background, glassmorphism card, big heart button. On click:
- Heart pops with elastic scale
- Particle hearts burst outward (using CSS keyframes with custom properties per particle)
- Shockwave rings expand
- Confetti
- Background color flash
- Button text changes to "Liked!"
- Rotating glow ring
- Screen shake
- Counter increments? Counter increment with CSS only — possible with sibling selectors and :checked counters. Actually we could use a counter with `counter-reset` on the checked state. E.g., a span with `counter-increment: likes` and `content: counter(likes)` — but counter increments on element render; using `input:checked ~ .count { counter-increment: likes; }` then `content: counter(likes)` — the counter-reset should be on a common ancestor. Hmm, counters increment in document order; each checked state would add. Tricky to make it increase per click. Classic trick: use :checked state to change counter-reset value directly: e.g. `input:checked ~ .counter::after { content: counter(likes) }` and `counter-reset: likes 1` when checked. But that only shows 1, not increasing. Since toggling is only on/off (can't count clicks with CSS alone reliably). Actually we could use several checkboxes to count clicks (binary counting) but that's complex. Simpler: show a like count that increments once per check. Maybe skip counter; use a "likes" counter that goes 1,201 -> 1,202 using :checked. Hmm.
Alternative: use multiple checkboxes to implement a counter in binary — 8 checkboxes giving 0-255. That's a fun pure-CSS trick but a lot of markup. Maybe keep it simpler: display "Liked!" text change and a heart count that just shows 1 when checked. Or use a numeric count that changes between two states.
Let me instead do a counter trick: place `counter-reset: likes 1247;` on container and `counter-increment: likes 1` on checked element → that gives 1248 when checked. But that's per state, not cumulative clicks. Good enough: shows 1,247 → 1,248.
Actually better idea: use CSS counter with `counter-reset` on body default 1247 and the checked sibling increments it → since the increment applies when checked, the displayed value becomes 1248. Nice.
Let me also add a separate "unlike" behavior—clicking again unlikes with a different animation (hearts fade/fall away).
I'll build:
Structure:
```html
<div class="stage">
<input type="checkbox" id="like" class="sr">
<label class="btn" for="like">
<span class="ring"></span>
<span class="burst"> x many heart spans </span>
<span class="heart">♥</span>
<span class="label-text">Like</span>
</label>
<div class="count">...</div>
</div>
```
But particles need to animate on check. Since the particles are inside the label, when checked they play animation (animation runs on state change; when unchecked, animation is removed → restarts on re-check). Good.
Also add "sparkles" and "confetti" pieces.
Also a flying heart that travels up? Nice.
Also screen shake on the card: `.card:has(input:checked)` — `:has` supported in modern Chrome. But :has applies as soon as checked, and animation would apply always while checked (animation runs once when state changes though). Using `animation` on `:has()` works: when the state changes, the animation starts. But if it stays checked, it won't rerun. Fine.
However, the shake should also play on uncheck (a "deflate"). Could just use `:has()` for shake and let uncheck do a different animation? `:has(:not(:checked))` = always true when unchecked... that'd run on load. Better skip.
Let's design visually appealing:
- Background: deep radial gradient, purple/pink.
- Card centered with glass effect.
- Title "Pure CSS Like Button", subtitle "Zero JavaScript · just a checkbox".
- Button: big rounded pill with gradient, heart icon, label text.
- On liked: gradient shifts to red/pink, heart fills, particles burst, ring pulses, confetti, counter increments, plus a "Liked!" toast appears.
Also add a second decorative element: floating hearts in background (always drifting) — adds life.
Also maybe multiple buttons? Keep one main but could add a row of small ones. Let's add 3-4 small "like" mini buttons in a row for variety, each with own particles? That'd multiply markup a lot. Instead, keep one hero button plus a row of small icon-only like buttons with simpler burst (scale pulse). Hmm, might be nice but keep focus.
I'll do: hero card with a big like button; below, a row of 3 smaller buttons that also work independently with a simpler pop + a rotating emoji. To limit markup, mini buttons each get 6 particles.
Let's plan the CSS animations.
Particles: for i in 1..16, each with `--tx`, `--ty`, `--rot`, `--delay`, `--size`. Use nth-child to set variables.
Burst keyframes:
```
@keyframes burst {
0% { transform: translate(0,0) scale(0.4) rotate(0); opacity: 0; }
10% { opacity: 1; }
60% { opacity: 1; }
100% { transform: translate(var(--tx), var(--ty)) scale(1) rotate(var(--rot)); opacity: 0; }
}
```
With easing cubic-bezier.
Rings: 3 expanding rings with different delays.
Shockwave: a pseudo-element on button scaling up with fade.
Heart pop: scale elastic.
Button wiggle: rotate keyframes.
Background flash: overlay with radial gradient fading.
Confetti: small rects falling with rotate.
Let me write the code.
Heart SVG inline: use inline SVG for crisp heart with fill transition (stroke → fill). Inline SVG allowed (no external). Use path heart.
Let's write:
```html
<label class="like-btn" for="like">
<span class="pulse-ring"></span>
<span class="pulse-ring r2"></span>
<span class="pulse-ring r3"></span>
<span class="shock"></span>
<span class="particles">
<i style="--x:..px;--y:..px;--r:..deg;--d:..s;--s:..px">♥</i> ...
</span>
<span class="confetti">...</span>
<svg class="heart" viewBox="0 0 24 24">...</svg>
<span class="txt">Like</span>
</label>
```
Label text changes via CSS content? We can't easily change text content without JS... but we can have two spans, one shown when unchecked and one when checked, using sibling selectors with the input placed before them. Since input is a sibling of the label in the DOM, `input:checked ~ .card .txt-unlike { display:none }`.
Structure:
```html
<input id="like" type="checkbox" class="toggle">
<div class="card">
... label ...
</div>
```
input must be before card for `~` selector. But the input also should be the direct previous sibling. Fine: put `<input>` first (hidden) then `<main class="card">`.
But particles inside label can be targeted by `.toggle:checked ~ .card .particles i { animation: burst ... }`.
Also for heart fill: `.toggle:checked ~ .card .heart path { fill: #fff }` etc.
Let's write particles using nth-child(1..14) with angles computed manually. I'll compute positions: use a circle of radius ~ 120px with varied radii.
Let me generate values: angle degrees and radius.
I'll just hand-write:
1: --x: 0px; --y:-130px; --r: 10deg
2: --x: 70px; --y:-115px; --r: 120deg
3: --x: 120px; --y:-60px; --r: 200deg
4: --x: 135px; --y: 10px; --r: -60deg
5: --x: 110px; --y: 80px; --r: 45deg
6: --x: 60px; --y: 125px; --r: -120deg
7: --x: -10px; --y: 140px; --r: 160deg
8: --x: -80px; --y: 120px; --r: -30deg
9: --x: -130px; --y: 60px; --r: 90deg
10: --x: -145px; --y:-20px; --r: -150deg
11: --x: -115px; --y:-95px; --r: 220deg
12: --x: -40px; --y:-140px; --r: -80deg
13: --x: 95px; --y:-135px; --r: 300deg (smaller, delayed)
14: --x: -95px; --y: -140px; --r: 60deg
15: --x: 150px; --y: 40px; --r: 180deg
16: --x: -150px; --y:-45px; --r: -20deg
Add some emoji particles mixed? Use text characters: ♥, ✦, ★, ✿, 💖? Emoji might render inconsistently but fine. Use a mix: heart shapes via characters and CSS colored.
I'll give particles two classes: hearts (♥ colored red/pink) and sparkles (✦ gold). Keep it simple: all use `content` from text in HTML: I'll write text inside <i> elements.
Confetti: small squares with background colors, falling down-out, ~12 pieces.
Also "text pop" maybe a "LOL 1.2k" floating label above.
Also add a toast "Added to your likes!" that flies up and fades when checked.
Background: also a full-screen flash overlay `.flash` that animates when checked.
Let's write the CSS carefully.
Key: animations must be triggered on check. Use `animation` property on `:checked ~` selectors. When unchecked → no animation → elements at base state (opacity 0 for particles).
For the background flash overlay, place inside card? Better fixed full-screen: put as a sibling of card inside main container, so `.toggle:checked ~ .wrap .flash { animation: flash .7s }`.
Structure:
```html
<input id="like" class="toggle" type="checkbox">
<div class="wrap">
<div class="flash"></div>
<div class="card"> ... </div>
</div>
```
Now, keyboard accessibility: the checkbox is focusable but hidden (opacity 0, position absolute). Label click toggles it. Space toggles when focused. But iframe keyboard requires a click first; that's fine — clicking the button counts.
Also add a focus-visible style on the card button.
Let's also handle reduced motion? Optional, skip or add minimal.
Now the card content: title, subtitle, the button, like count row with counter.
Counter trick:
```css
.count-wrap { counter-reset: likes 1247; }
.toggle:checked ~ .wrap .count-wrap { counter-reset: likes 1248; }
```
Hmm counter-reset on checked replaces. But if the increment happens within the same element... Simplest: define counter on .count-wrap with `counter-reset: likes 1247` and a child `.count::after { content: counter(likes) }`. When checked: `.toggle:checked ~ .wrap .count-wrap { counter-reset: likes 1248; }`. That gives 1248 when liked, 1247 otherwise.
Wait, does counter-reset on a later rule override? Both rules apply to same element; the later/more specific one wins — specificity: `.toggle:checked ~ .wrap .count-wrap` (0,3,1) > `.count-wrap` (0,1,0). Yes.
Hmm but careful: counter-reset in the checked rule and the ::after content in a descendant — the counter scope is the element and its descendants, so `.count::after` inside `.count-wrap` will see it. Good.
Also show formatted: content: counter(likes) — 1247.
Now writing the animation for the heart: on check, `animation: pop .6s cubic-bezier(...)`. Heart SVG with stroke white and fill transparent; when checked fill gradient? Use fill: #ff4d6d.
Button gradient: default purple-blue; checked: pink-red gradient with glow.
Wiggle: whole card shakes? Maybe subtle: `.toggle:checked ~ .wrap .card { animation: shake .5s }` plus burst.
Also a rotating conic gradient ring around button when liked (infinite) — nice "crazy" factor. Use a pseudo-element with conic-gradient and mask to make ring, spinning infinitely when checked.
Also add "sparkle" orbit: small stars rotating around the button continuously when checked. Could be a container with 6 stars positioned via rotate+translate animation.
Let me also add floating ambient hearts in background always animating (independent).
Let's write everything now.
HTML skeleton:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pure CSS Like Button</title>
<style>...</style>
</head>
<body>
<input class="toggle" type="checkbox" id="like">
<div class="wrap">
<div class="flash" aria-hidden="true"></div>
<div class="ambient" aria-hidden="true">
<span>♥</span> x8 with custom props
</div>
<main class="card">
<p class="eyebrow">Zero JavaScript</p>
<h1>Like it? <span class="spark">✨</span></h1>
<p class="sub">One hidden checkbox. One label. Endless confetti.</p>
<div class="stage">
<label class="like" for="like" title="Like">
<span class="rings" aria-hidden="true"><i></i><i></i><i></i></span>
<span class="shock" aria-hidden="true"></span>
<span class="orbit" aria-hidden="true"><i></i>...</span>
<span class="fx" aria-hidden="true"> hearts + confetti </span>
<svg class="heart" viewBox="0 0 24 24" aria-hidden="true"><path d="..."/></svg>
<span class="txt"><span class="t-off">Like</span><span class="t-on">Liked!</span></span>
</label>
</div>
<div class="meta">
<span class="count-wrap"><span class="count"></span> likes</span>
<span class="badge">CSS only</span>
</div>
<p class="hint">Click the heart (or press Space) — no scripts were harmed.</p>
</main>
</div>
</body>
</html>
```
For text switch: `.t-on { display:none }` and `.toggle:checked ~ .wrap .t-off{display:none}` etc.
But note the counter `.count::after{content:counter(likes)}` — I need the "likes" word. Fine.
Wait — counter-reset must be on an ancestor of ::after content. `.count-wrap` is ancestor of `.count` whose ::after holds content. Good.
Hmm, but there's a subtlety: does the ::after content counter read counter from ancestor scope? Yes, counters inherit into descendants.
Now let's carefully write CSS for the fx.
`.fx` positioned absolute center, pointer-events none, overflow visible.
Hearts: `<i class="p h1">♥</i>` each with `--x,--y,--r,--d,--s`.
Keyframes burst:
```
@keyframes burst {
0% { transform: translate3d(0,0,0) scale(.2) rotate(0deg); opacity:0 }
15% { opacity:1 }
70% { opacity:1 }
100% { transform: translate3d(var(--x), var(--y),0) scale(1) rotate(var(--r)); opacity:0 }
}
```
Hearts also fade at end; add a second animation? Single is fine.
But on uncheck, particles vanish instantly (base opacity 0) — that's okay, but nicer: add animation for uncheck where hearts fall down/fade. Let's add `.toggle:not(:checked) ~ .wrap .fx i { animation: ... }`? That would run on load too (page load animation runs). Actually on load, :not(:checked) is true → animation runs at load, which would look like a burst on load. Not desired. Use a trick: apply "fall" animation only when the checkbox has been interacted with — impossible in CSS without :active etc. Alternatively keep the uncheck simple: the button returns to default with a quick "squish" via the card's `:has(:not(:checked))`? same issue.
Alternative: Use `:focus` on the checkbox to signal interaction? After clicking, the checkbox gets focus. So `.toggle:focus ~ .wrap .fx i { animation: fall ... }` would apply after click but also on load if the checkbox is autofocused — it's not. But clicking the label focuses the checkbox, so on uncheck we'd get fall animation. But on the first check, both :checked and :focus are true — the burst rule and fall rule conflict; order matters: put the fall rule with `:focus:not(:checked)`. Good:
`.toggle:focus:not(:checked) ~ .wrap .fx i { animation: fall .6s ease-in forwards; }`
Hmm, but initial state: not focused → base. Good.
Actually simpler: skip the fall; instead on uncheck, a "deflate" ring. Let's include the fall since it's a nice touch, keyed on focus.
Careful: The `:checked` burst rule vs `:focus:not(:checked)` fall rule — mutually exclusive states, no conflict.
Also on uncheck we might want the shockwave to shrink. Fine.
Confetti: pieces `<i class="c" style="--x;--d;--rot;--color">` falling: from center top going down-out with rotation.
```
@keyframes confetti {
0% { transform: translate(0,0) rotate(0) ; opacity:0 }
10%{opacity:1}
100% { transform: translate(var(--x), 320px) rotate(var(--rot)); opacity:0 }
}
```
Also add a second wave of hearts that goes up and fades (like a rising stream) maybe.
Text pop: `<span class="pop">+1</span>` scaling up and fading. Positioned above the button.
Also "ring" pulses: 3 rings expanding with scale and fade, different delays.
Also shockwave: a circle scaling from 0 to 3 with border.
Also the button itself: `.like` gets `animation: bounce .7s` when checked; scale.
Also `.like` glow: box-shadow pulse infinite when checked? Could do `animation: glow 1.6s ease-in-out infinite` when checked — that's fine (crazy).
Orbit stars: container .orbit with `animation: spin 6s linear infinite` when checked; children positioned at radius using transform rotate(a) translateX(r) and counter-rotate. Simpler: each star i has its own animation `orbit` with `--a` start angle:
```
@keyframes orbit {
from { transform: rotate(var(--a)) translateX(78px) rotate(calc(-1 * var(--a))); }
to { transform: rotate(calc(var(--a) + 360deg)) translateX(78px) rotate(calc(-1 * var(--a) - 360deg)); }
}
```
That works for continuous rotation with the star facing outward-ish. Need also translateY(-50%) to center; use margin-top:-8px.
Let me now write the ambient background hearts: absolutely positioned at various positions, floating up with different durations/delays.
Let me write the full CSS.
Colors: background #0b0714 radial gradients with pink/purple blobs; card rgba(255,255,255,.06) backdrop blur, border 1px rgba(255,255,255,.12), radius 28px, padding 40px.
Font: system-ui stack.
Button: 190px circle? Let's make it a pill: width 200px height 76px, radius 999px, with heart icon and text. Actually a round button (110px) with the "Like" text beneath might look cleaner, but pill with heart+text is more recognizable as a like button. I'll do pill: heart 30px + text.
Hmm, but burst from the heart center: put fx inside label, centered on the heart? Put fx centered on the whole label; fine, or position fx over the heart (left area). Let's make the button a round-ish circle (128px) with the heart in the middle and the "Like" text below inside the card. Then particles radiate from the heart center — nicer. But then the label text "Like"/"Liked!" below the button as a caption that changes.
I think: big circular button 140px with heart icon; below it a caption "Like" → "Liked!" that swaps with a pop animation. Count below.
Let's do that: `.like` is 140x140 circle, border-radius 50%, gradient background, box-shadow. Heart svg 64px.
Position fx container centered on the button (absolute inset 0, display grid place-items center).
Caption: `.cap` with two spans, and when checked the "Liked!" appears with pop.
Also add tiny "sparkle" star marks.
Let me write out the code now, with careful attention to the `~` sibling chain: input.toggle is first child of body; .wrap is second child of body. Selectors: `.toggle:checked ~ .wrap .thing`.
Write final code.
Extra flair: when liked, the card gets a subtle rainbow border animation (conic gradient rotating) — "crazy". Use a ::before on card with conic gradient masked as border via padding-box/border-box mask trick:
```
.card::before {
content:''; position:absolute; inset:-2px; border-radius:30px;
background: conic-gradient(from var(--ang), #ff2d78, #ff9500, #ffe600, #34d399, #22d3ee, #6366f1, #ff2d78);
filter: blur(14px); opacity:0; z-index:-1; transition: opacity .4s;
}
.toggle:checked ~ .wrap .card::before { opacity:.85; animation: spinbg 6s linear infinite; }
```
With @property --ang for smooth rotation. @property is supported in Chrome. Let's use:
```
@property --ang { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
@keyframes spinbg { to { --ang: 360deg } }
```
Good.
Also flash overlay: radial gradient pink from center, opacity 0→.5→0.
Also the whole page could have a "screen shake" — shake the wrap.
Now write it.
Card sizing responsive: at 375px width, reduce paddings, button 120px.
Let me write the code.
Detailed particle list with inline styles (CSS custom props). I'll write them inline in HTML for clarity.
Hearts (12):
1 --x:0px --y:-150px --r:0deg --d:0s --s:26px
2 --x:85px --y:-125px --r:120deg --d:.04s
3 --x:145px --y:-60px --r:-160deg --d:.08s
4 --x:160px --y:20px --r:80deg --d:.02s
5 --x:130px --y:95px --r:-90deg --d:.1s
6 --x:70px --y:145px --r:200deg --d:.05s
7 --x:-15px --y:155px --r:45deg --d:.09s
8 --x:-95px --y:130px --r:-140deg --d:.03s
9 --x:-145px --y:65px --r:110deg --d:.07s
10 --x:-165px --y:-15px --r:-60deg --d:.11s
11 --x:-120px --y:-100px --r:170deg --d:.06s
12 --x:-45px --y:-150px --r:-120deg --d:.12s
Sparkles (8): smaller, star char ✦ with gold color, positions slightly different, delay later:
--x:55px --y:-160px etc.
Confetti (14): colored squares, --x offset, --rot.
Also "mini hearts" that fly straight up far and shrink.
OK, writing now. Keep the code organized.
One risk: too much visual noise; keep opacity moderate.
Let's write the final HTML.
For the caption swap with animation, `.cap .on { display:none }`, `.toggle:checked ~ .wrap .cap .off { display:none }`, `.toggle:checked ~ .wrap .cap .on { display:inline-block; animation: pop .5s }`.
Also add a "1.2k" style count.
Now the count-wrap: I'll put it in the meta row:
```html
<div class="meta">
<span class="countwrap"><span class="count"></span></span>
<span class="word">likes</span>
</div>
```
CSS: `.countwrap{counter-reset: likes 1247}` and `.toggle:checked ~ .wrap .countwrap{counter-reset: likes 1248}` and `.count::after{content: counter(likes)}`.
Hmm: When checked, count = 1248. Good.
Maybe nicer: start at 12,047 → 12,048. Use 12047.
Let me finalize. Also the button when checked gets a heart filled white.
Heart SVG path: standard Material heart:
M12 21s-7.5-4.9-10-9.4C.3 8.2 2.2 4.5 5.8 4.5c2 0 3.4 1.1 4.2 2.3l1 1.3 1-1.3c.8-1.2 2.2-2.3 4.2-2.3 3.6 0 5.5 3.7 3.8 7.1-2.5 4.5-10 9.4-10 9.4z
Simpler: use path "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" — standard.
Use fill with stroke.
CSS:
```
.heart{ width:66px;height:66px; fill:none; stroke:#fff; stroke-width:1.6; filter: drop-shadow(...) }
.toggle:checked ~ .wrap .heart { fill:#fff; stroke:#fff; animation: heartpop .7s cubic-bezier(.2,1.6,.4,1) }
```
Hmm the checked fill white on pink button — good.
Also the button itself when checked: background gradient pink/red.
Let me now produce final code.
Also add `@media (prefers-reduced-motion: reduce)` to shorten animations? Optional; skip to avoid complexity, but maybe include minimal.
I'll write it now carefully.
Also the "orbit" stars: `.orbit i` positioned absolute at center with animation. Let me define:
```
.orbit{position:absolute;inset:0;pointer-events:none}
.orbit i{position:absolute;left:50%;top:50%;font-size:14px;opacity:0}
.toggle:checked ~ .wrap .orbit i{ animation: orbit 3.4s linear infinite; animation-delay: var(--d); opacity:.9 }
@keyframes orbit{
0%{transform:rotate(var(--a)) translateX(92px) rotate(calc(-1*var(--a))); opacity:0}
10%{opacity:.95}
90%{opacity:.95}
100%{transform:rotate(calc(var(--a) + 360deg)) translateX(92px) rotate(calc(-1*var(--a) - 360deg)); opacity:0}
}
```
Set --a per star: 0,60,120,180,240,300.
Careful: the transform includes translateX from center; the element is at left:50% top:50% so need margin offsets: use `margin:-8px 0 0 -8px`.
OK.
Also a rotating conic ring behind the button (border gradient) that spins when checked:
```
.ring{position:absolute;inset:-10px;border-radius:50%;background:conic-gradient(from 0deg, transparent 0 40%, #ff2d78, #ffd166, transparent 80%); opacity:0; transition:.3s; mask: radial-gradient(farthest-side, transparent calc(100% - 4px), #000 calc(100% - 3px)); -webkit-mask: ...}
.toggle:checked ~ .wrap .ring{opacity:1;animation: spin 2.5s linear infinite}
```
Use `mask` shorthand might need -webkit- prefix; Chrome supports `mask` now (Chrome 120+). Include -webkit-mask for safety.
But the label has overflow visible; ring behind the button: z-index -1? Button has background; ring outside. Fine, set .like position relative and .ring z-index 0 while heart z-index 2.
Structure inside label: ring, shock, orbit, fx, then heart span (z-index 3).
OK writing.
Let's produce the final file.
Also need `.toggle` hidden: position absolute; opacity 0; width 1px;height1px; but keep focusable. Use `appearance:none; position:absolute; opacity:0; pointer-events:none;` Actually keep it focusable via keyboard: don't set display:none. Use:
```
.toggle{position:absolute;width:1px;height:1px;opacity:0;margin:0;pointer-events:none}
```
focus-visible style on `.like:focus-visible`? The label isn't focusable; the input is. So style the button when input focused: `.toggle:focus-visible ~ .wrap .like{ outline: 3px solid #fff; outline-offset:6px }`.
Now final code.
I'll write the HTML with all particles. Let me count markup size — acceptable.
Write it.