A presence bar of stacked agent avatars, each circled by its own spinning working ring. One finishes: its ring closes green, a check badge pops on, a tooltip names it and the summary rolls over.
Also known as: agent avatar stack, multiplayer presence avatars, agents working indicator.
<div class="aia-agent-presence-stack" role="status" aria-label="Four agents working, docs-sync finished">
<span class="aia-agent-presence-stack-tip" aria-hidden="true"><span>docs-sync finished</span></span>
<div class="aia-agent-presence-stack-bar">
<ul class="aia-agent-presence-stack-faces" aria-hidden="true">
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 7 4.5 5L5 17M12 17.5h7"/></svg></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="M3.5 12h17M12 3.5c2.4 2.4 3.4 5.3 3.4 8.5s-1 6.1-3.4 8.5c-2.4-2.4-3.4-5.3-3.4-8.5s1-6.1 3.4-8.5z"/></svg></li>
<li class="aia-agent-presence-stack-done"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/></svg><i><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5.5 12.5 4 4 9-9.5"/></svg></i></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6" cy="6" r="2.2"/><circle cx="6" cy="18" r="2.2"/><circle cx="18" cy="7" r="2.2"/><path d="M6 8.2v7.6M18 9.2c0 5-6 4.2-11 7.2"/></svg></li>
<li class="aia-agent-presence-stack-more">+2</li>
</ul>
<span class="aia-agent-presence-stack-text">
<span class="aia-agent-presence-stack-swap"><b>4 agents working</b><b>3 working, 1 done</b></span>
<span class="aia-agent-presence-stack-sub">feat/checkout-v2</span>
</span>
</div>
</div>.aia-agent-presence-stack {
--c: var(--aia-color, #7c5cff);
font-size: var(--aia-size, 16px);
font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
line-height: 1.4;
--d: 7s;
--ok: #4ade80;
--bg: color-mix(in srgb, var(--c) 7%, #111114);
position: relative;
display: inline-block;
padding-top: 2.4em;
}
.aia-agent-presence-stack-bar {
display: flex;
align-items: center;
gap: 0.85em;
padding: 0.45em 1.15em 0.45em 0.5em;
border-radius: 999em;
background: var(--bg);
color: #f4f4f5;
box-shadow: 0 0 0 1px rgb(255 255 255 / 0.09), 0 1em 2.2em -1em rgb(0 0 0 / 0.55);
}
.aia-agent-presence-stack-faces {
display: flex;
margin: 0;
padding: 0.2em;
list-style: none;
}
.aia-agent-presence-stack-faces li {
--hue: var(--c);
--spin: 1.1s;
position: relative;
display: grid;
place-items: center;
width: 2.3em;
height: 2.3em;
margin-left: -0.45em;
border-radius: 50%;
background: linear-gradient(140deg, color-mix(in srgb, var(--hue) 85%, #fff), color-mix(in srgb, var(--hue) 70%, #000));
color: #fff;
box-shadow: 0 0 0 0.17em var(--bg);
}
.aia-agent-presence-stack-faces li:first-child { margin-left: 0; }
.aia-agent-presence-stack-faces li:nth-child(2) { --hue: color-mix(in srgb, var(--c) 45%, #0ea5e9); --spin: 1.45s; }
.aia-agent-presence-stack-faces li:nth-child(3) { --hue: color-mix(in srgb, var(--c) 45%, #14b8a6); --spin: 0.95s; z-index: 1; }
.aia-agent-presence-stack-faces li:nth-child(4) { --hue: color-mix(in srgb, var(--c) 45%, #f59e0b); --spin: 1.25s; }
.aia-agent-presence-stack-faces svg {
width: 1.05em;
height: 1.05em;
}
/* the working ring, sitting in the gap around each face */
.aia-agent-presence-stack-faces li:not(.aia-agent-presence-stack-more)::before {
content: "";
position: absolute;
inset: -0.17em;
border-radius: 50%;
border: 0.13em solid rgb(255 255 255 / 0.1);
border-top-color: color-mix(in srgb, var(--c) 40%, #fff);
border-right-color: color-mix(in srgb, var(--c) 40%, #fff);
animation: aia-agent-presence-stack-spin var(--spin) linear infinite;
}
.aia-agent-presence-stack-faces .aia-agent-presence-stack-more {
background: rgb(255 255 255 / 0.1);
color: rgb(255 255 255 / 0.75);
font-size: 0.7em;
font-weight: 700;
width: 3.3em;
height: 3.3em;
margin-left: -0.64em;
}
.aia-agent-presence-stack-done {
animation: aia-agent-presence-stack-lift var(--d) cubic-bezier(0.34, 1.4, 0.64, 1) infinite;
}
.aia-agent-presence-stack-faces .aia-agent-presence-stack-done::before {
animation:
aia-agent-presence-stack-spin var(--spin) linear infinite,
aia-agent-presence-stack-out var(--d) ease infinite;
}
.aia-agent-presence-stack-done::after {
content: "";
position: absolute;
inset: -0.17em;
border-radius: 50%;
border: 0.13em solid var(--ok);
animation: aia-agent-presence-stack-ring var(--d) cubic-bezier(0.34, 1.4, 0.64, 1) infinite;
}
.aia-agent-presence-stack-done i {
position: absolute;
right: -0.3em;
bottom: -0.3em;
display: grid;
place-items: center;
width: 1.05em;
height: 1.05em;
border-radius: 50%;
background: var(--ok);
color: #052e16;
box-shadow: 0 0 0 0.15em var(--bg);
animation: aia-agent-presence-stack-badge var(--d) cubic-bezier(0.34, 1.56, 0.64, 1) infinite;
}
.aia-agent-presence-stack-done i svg {
width: 0.72em;
height: 0.72em;
stroke-width: 3.6;
}
.aia-agent-presence-stack-text {
display: grid;
gap: 0.1em;
line-height: 1.25;
}
.aia-agent-presence-stack-swap {
display: grid;
font-size: 0.86em;
}
.aia-agent-presence-stack-swap b {
grid-area: 1 / 1;
white-space: nowrap;
}
.aia-agent-presence-stack-swap b:first-child { animation: aia-agent-presence-stack-a var(--d) ease infinite; }
.aia-agent-presence-stack-swap b:last-child { animation: aia-agent-presence-stack-b var(--d) ease infinite; }
.aia-agent-presence-stack-sub {
color: rgb(255 255 255 / 0.5);
font: 0.68em ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
}
.aia-agent-presence-stack-tip {
position: absolute;
top: 0;
left: 5.15em;
display: flex;
align-items: center;
gap: 0.4em;
padding: 0.35em 0.65em;
border-radius: 0.55em;
background: var(--bg);
color: #f4f4f5;
box-shadow: 0 0 0 1px rgb(255 255 255 / 0.1), 0 0.6em 1.2em -0.6em rgb(0 0 0 / 0.5);
white-space: nowrap;
animation: aia-agent-presence-stack-tip var(--d) cubic-bezier(0.34, 1.4, 0.64, 1) infinite;
}
.aia-agent-presence-stack-tip::before {
content: "";
width: 0.45em;
height: 0.45em;
border-radius: 50%;
background: var(--ok);
}
.aia-agent-presence-stack-tip::after {
content: "";
position: absolute;
left: calc(50% - 0.3em);
bottom: -0.3em;
width: 0.6em;
height: 0.6em;
background: var(--bg);
transform: rotate(45deg);
box-shadow: 1px 1px 0 rgb(255 255 255 / 0.1);
}
.aia-agent-presence-stack-tip span {
font-size: 0.74em;
font-weight: 600;
}
@keyframes aia-agent-presence-stack-out {
0%, 40% { opacity: 1; }
45%, 95% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes aia-agent-presence-stack-ring {
0%, 41% { opacity: 0; transform: scale(0.8); }
48%, 94% { opacity: 1; transform: scale(1); }
98%, 100% { opacity: 0; transform: scale(1); }
}
@keyframes aia-agent-presence-stack-lift {
0%, 41%, 100% { transform: none; }
47% { transform: translateY(-0.35em); }
54%, 96% { transform: none; }
}
@keyframes aia-agent-presence-stack-badge {
0%, 45% { opacity: 0; transform: scale(0); }
52%, 93% { opacity: 1; transform: scale(1); }
97%, 100% { opacity: 0; transform: scale(0.4); }
}
@keyframes aia-agent-presence-stack-tip {
0%, 48% { opacity: 0; transform: translate(-50%, 0.5em) scale(0.92); }
55%, 86% { opacity: 1; transform: translate(-50%, 0); }
91%, 100% { opacity: 0; transform: translate(-50%, -0.2em); }
}
@keyframes aia-agent-presence-stack-a {
0%, 45%, 100% { opacity: 1; transform: none; }
49%, 96% { opacity: 0; transform: translateY(-0.5em); }
}
@keyframes aia-agent-presence-stack-b {
0%, 45%, 100% { opacity: 0; transform: translateY(0.5em); }
49%, 96% { opacity: 1; transform: none; }
}
@keyframes aia-agent-presence-stack-spin {
to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
.aia-agent-presence-stack *,
.aia-agent-presence-stack *::before,
.aia-agent-presence-stack *::after {
animation-play-state: paused;
animation-delay: calc(var(--d) * -0.7);
}
}
@media (prefers-reduced-motion: reduce) {
.aia-agent-presence-stack, .aia-agent-presence-stack *, .aia-agent-presence-stack::before, .aia-agent-presence-stack::after, .aia-agent-presence-stack *::before, .aia-agent-presence-stack *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--aia-color on the element or a parent.
Currently previewing #3b82f6.--aia-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.