feat(daily): a small burst when the last daily lands

The one moment in this app that is unambiguously good news, and it read
the same as any other tick.

Fires only on a tick that completes the set — the list also shortens when
the reader filters, and a burst there would be congratulating them for
filtering. Nothing on mount either, so arriving at an already-finished
day is not treated as having just finished it.

Decorative, aria-hidden and under a second; the "All done" text beside it
is what a screen reader gets. Fully off under prefers-reduced-motion
rather than merely reduced — nothing here carries meaning, so the honest
reduced version is nothing at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lucas WintherandClaude Opus 5 committed 2026-08-16 20:39:09 +02:00
1 parent a0d0faf231
commit c3e9b9064d
4 files changed
+146 -5

No files matched your search

+52
View File
@@ -225,6 +225,58 @@ body {
}
}
/* ---- The daily burst ---------------------------------------------------- */
/*
* Fires once, when the last daily of the day gets ticked. Purely decorative and
* pointer-transparent, so it never sits between the reader and a chip.
*
* The whole thing is inside `prefers-reduced-motion: no-preference` rather than
* being merely reduced by it: unlike the meter, nothing here carries meaning
* that would be lost, so the honest reduced version is nothing at all.
*/
.fireworks {
position: absolute;
inset: 0;
overflow: hidden;
pointer-events: none;
display: none;
}
.firework {
position: absolute;
display: block;
width: 0;
height: 0;
}
.spark {
position: absolute;
width: 3px;
height: 3px;
border-radius: 999px;
}
@media (prefers-reduced-motion: no-preference) {
.fireworks {
display: block;
}
.spark {
animation: spark-fly 900ms cubic-bezier(0.15, 0.7, 0.35, 1) var(--delay, 0ms)
both;
}
@keyframes spark-fly {
from {
transform: rotate(var(--a)) translateX(0) scale(0.6);
opacity: 0;
}
18% {
opacity: 1;
}
to {
transform: rotate(var(--a)) translateX(var(--d)) scale(1);
opacity: 0;
}
}
}
/* Focus ring: visible, and never removed. */
:where(a, button, [tabindex]):focus-visible {
outline: 2px solid var(--color-near);