feat(01-03): paid tick renders the branded screensaver ring (FED-06)
Demo images / Build & push demo images (push) Failing after 1m14s

Both paid-tick surfaces now show the EQ-segment ring instead of a CSS ripple
burst (send modal) and a plain circle (scan modal), via a new `badge` size
variant at 160px/192px with matching --viz-radius. A transform scale of the
compact variant was ruled out in 01-UI-SPEC.md because it would scale segment
stroke width and blur along with the geometry.

Both surfaces use the identical composition — a badge-sized relative container
with the checkmark core absolutely centred over the ring — so the two ticks
cannot drift apart visually.

ScreensaverRing also gains the prefers-reduced-motion guard it never had, on
the component rather than per call site, so the screensaver and
SystemDangerZone variants are covered too.

Also records live-browser verification for 01-13's scroll cue (three
viewports, plus a geometry probe of the hide condition).

Verified: 5 new tests; full suite 102 files / 822 tests green; npm run build
clean with viz-ring-badge present in the built bundle. The live visual
no-clipping observation Task 2 asks for is explicitly NOT done — recorded as
deferred to plan 01-07's consolidated sign-off.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-01 06:07:10 -04:00
co-authored by Claude Opus 5
parent 8b51b7e2dc
commit 579398981f
7 changed files with 406 additions and 40 deletions
+30 -31
View File
@@ -3,14 +3,14 @@
<!-- ============ SUCCESS PANE the payment's moment, not a footnote ============ -->
<template v-if="successInfo">
<div class="text-center py-4">
<div class="send-success-burst mx-auto mb-6">
<span class="burst-ring"></span>
<span class="burst-ring burst-ring-2"></span>
<span class="burst-ring burst-ring-3"></span>
<div class="burst-core">
<svg class="w-14 h-14 text-green-400 burst-check" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
<div class="send-success-badge mx-auto mb-6">
<ScreensaverRing size="badge" />
<div class="send-success-burst">
<div class="burst-core">
<svg class="w-14 h-14 text-green-400 burst-check" fill="none" stroke="currentColor" stroke-width="3" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
</svg>
</div>
</div>
</div>
@@ -259,6 +259,7 @@ import { ref, computed, watch, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import { rpcClient } from '@/api/rpc-client'
import BaseModal from '@/components/BaseModal.vue'
import ScreensaverRing from '@/components/ScreensaverRing.vue'
const { t } = useI18n()
@@ -681,10 +682,27 @@ async function send() {
</script>
<style scoped>
/* Success burst — pop-in check inside radiating rings, wallet palette
(emerald for the settled payment, one Archipelago-orange ring). */
.send-success-burst {
/* Success badge (FED-06) — the branded ScreensaverRing carries the motion,
with the emerald pop-in check centred over it. */
.send-success-badge {
position: relative;
width: 160px;
height: 160px;
display: flex;
align-items: center;
justify-content: center;
}
@media (min-width: 768px) {
.send-success-badge {
width: 192px;
height: 192px;
}
}
.send-success-burst {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 7rem;
height: 7rem;
}
@@ -704,20 +722,6 @@ async function send() {
stroke-dashoffset: 32;
animation: burst-draw 0.45s ease-out 0.25s forwards;
}
.burst-ring {
position: absolute;
inset: 0;
border-radius: 9999px;
border: 2px solid rgba(16, 185, 129, 0.45);
animation: burst-ripple 1.8s ease-out infinite;
}
.burst-ring-2 {
animation-delay: 0.45s;
}
.burst-ring-3 {
animation-delay: 0.9s;
border-color: rgba(249, 115, 22, 0.35);
}
@keyframes burst-pop {
from { transform: scale(0.3); opacity: 0; }
to { transform: scale(1); opacity: 1; }
@@ -725,13 +729,8 @@ async function send() {
@keyframes burst-draw {
to { stroke-dashoffset: 0; }
}
@keyframes burst-ripple {
0% { transform: scale(0.7); opacity: 0.9; }
100% { transform: scale(2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.burst-core, .burst-check, .burst-ring { animation: none; }
.burst-core, .burst-check { animation: none; }
.burst-check { stroke-dashoffset: 0; }
.burst-ring { display: none; }
}
</style>