Download Progress Key
A raised download key that sinks while working: the arrow turns into a spinner, then a check on an emerald Done state.
Preview and code
index.html
<button class="dl" type="button"><span class="dl__i"><svg class="dl__a" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 4v11M7 11l5 5 5-5M5 20h14"/></svg><svg class="dl__s" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 3a9 9 0 1 0 9 9"/></svg><svg class="dl__c" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 5 5 9-10"/></svg></span><span class="dl__t" aria-live="polite">Download File</span></button>
styles.css
.dl{display:inline-flex;align-items:center;gap:10px;padding:15px 24px;border:1px solid #e5e5e5;border-radius:14px;background:#fff;color:#262626;font:500 16px/1 system-ui,sans-serif;cursor:pointer;box-shadow:0 5px 0 #d4d4d4,0 14px 22px rgba(0,0,0,.1);transition:transform .15s ease,box-shadow .15s ease,background-color .25s ease,color .25s ease}
.dl__i{position:relative;width:18px;height:18px}
.dl svg{position:absolute;inset:0;width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;opacity:0;transition:opacity .2s ease}
.dl__a{opacity:1!important}
.dl.is-busy{transform:translateY(4px);box-shadow:0 1px 0 #d4d4d4,0 4px 10px rgba(0,0,0,.08);pointer-events:none}
.dl.is-busy .dl__a{opacity:0!important}
.dl.is-busy .dl__s{opacity:1;animation:dl-spin .7s linear infinite}
.dl.is-done{background:#10b981;border-color:#0e9f6e;color:#fff;box-shadow:0 5px 0 #047857,0 14px 22px rgba(16,185,129,.25);pointer-events:none}
.dl.is-done .dl__a{opacity:0!important}
.dl.is-done .dl__c{opacity:1}
@keyframes dl-spin{to{transform:rotate(360deg)}}
.dl:focus-visible{outline:2px solid #1659f5;outline-offset:4px}
@media (prefers-reduced-motion:reduce){.dl{transition:none}.dl.is-busy .dl__s{animation:none}}
script.js
const b=document.querySelector('.dl'),t=b.querySelector('.dl__t');let busy=false;
b.addEventListener('click',()=>{if(busy)return;busy=true;b.classList.add('is-busy');t.textContent='Downloading...';
setTimeout(()=>{b.classList.remove('is-busy');b.classList.add('is-done');t.textContent='Done';},1400);
setTimeout(()=>{b.classList.remove('is-done');t.textContent='Download File';busy=false;},3200);});
About
Click to start. The key presses in, shows a spinner, then rises in emerald with Done and resets. Swap the timers for your real download events.