feat: shine a code redeemed or an event completed on its way out
A code redeemed on its last server sweeps in the game's colour and greys in place for 0.8 s, then lands in Redeemed or expired. A completed event greys and shines while its Moved to Archive notice holds, now 0.9 s rather than 1.5 s, which read as unresponsive; an ignored one only greys. Settings → Appearance gains Motion & celebrations as three What to track cards: Reduce motion (stops every animation and the fireworks, adding to the device's own setting), Fireworks, and Shine. Reduce motion locks the other two off without forgetting them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9c22a85134
commit
54d13d7472
15 files changed
+628
-59
No files matched your search
+112
-12
@@ -4268,6 +4268,86 @@ dialog.archive-detail {
|
||||
text-decoration: line-through;
|
||||
text-decoration-color: var(--color-muted);
|
||||
}
|
||||
/* A checklist event on its way to the Archive greys its text while it holds,
|
||||
so it reads as leaving; the "Moved to Archive" line under it stays legible. */
|
||||
.event-list > li[data-leaving] > button > span {
|
||||
opacity: 0.45;
|
||||
}
|
||||
/* A code shining on its way to Redeemed greys the same way; its Redeemed
|
||||
boxes stay full strength, so the tick that sent it is still plain. */
|
||||
.code-row[data-shine] > div:first-child > * {
|
||||
opacity: 0.45;
|
||||
}
|
||||
/* A code just redeemed, or an event just completed: the dailies' sweep and
|
||||
ring cross the row in the game's colour. A code then fades out and lands
|
||||
among the redeemed; an event fades as the Archive takes it. Only the
|
||||
reader's own action sets these, and reduced motion skips the code's hold. */
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.event-list > li > button > span,
|
||||
.code-row > div:first-child > * {
|
||||
transition: opacity 300ms ease-out;
|
||||
}
|
||||
.code-row[data-shine],
|
||||
.event-list > li[data-shine] > button {
|
||||
position: relative;
|
||||
animation: daily-glow 560ms ease-out;
|
||||
}
|
||||
.code-row[data-shine] {
|
||||
animation:
|
||||
daily-glow 560ms ease-out,
|
||||
code-leave 210ms ease-in 590ms forwards;
|
||||
}
|
||||
.code-row[data-shine]::after,
|
||||
.event-list > li[data-shine] > button::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
background: linear-gradient(
|
||||
100deg,
|
||||
transparent 30%,
|
||||
color-mix(in srgb, var(--g, var(--color-ink)) 38%, transparent) 50%,
|
||||
transparent 70%
|
||||
);
|
||||
background-size: 250% 100%;
|
||||
animation: code-sweep 640ms ease-out both;
|
||||
}
|
||||
.code-row[data-landing] {
|
||||
animation: code-land 360ms ease-out;
|
||||
}
|
||||
.code-row label[data-fresh] input {
|
||||
animation: daily-pop 420ms cubic-bezier(0.3, 1.6, 0.5, 1);
|
||||
}
|
||||
.codes-clear[data-fresh] {
|
||||
animation: daily-rise 360ms ease-out;
|
||||
}
|
||||
/* The dailies' sweep, held bright until it has crossed: a single row is
|
||||
too thin for a band that fades as it travels. */
|
||||
@keyframes code-sweep {
|
||||
from {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
75% {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
background-position: 0% 0;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes code-leave {
|
||||
to {
|
||||
opacity: 0;
|
||||
transform: translateY(6px);
|
||||
}
|
||||
}
|
||||
@keyframes code-land {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-6px);
|
||||
}
|
||||
}
|
||||
}
|
||||
.game-settings .new-code {
|
||||
margin-left: 6px;
|
||||
font-size: 11px;
|
||||
@@ -4292,13 +4372,13 @@ dialog.archive-detail {
|
||||
color: var(--color-faint);
|
||||
letter-spacing: 0;
|
||||
}
|
||||
.game-settings .comp {
|
||||
:is(.game-settings, .motion-cards) .comp {
|
||||
margin: 14px 0 8px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 8px;
|
||||
}
|
||||
.game-settings .comp button {
|
||||
:is(.game-settings, .motion-cards) .comp button {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -4308,22 +4388,22 @@ dialog.archive-detail {
|
||||
border: 1px solid var(--rule-strong);
|
||||
border-radius: 3px;
|
||||
}
|
||||
.game-settings .comp button:hover {
|
||||
:is(.game-settings, .motion-cards) .comp button:hover {
|
||||
border-color: var(--color-muted);
|
||||
}
|
||||
.game-settings .comp button[data-st="on"] {
|
||||
:is(.game-settings, .motion-cards) .comp button[data-st="on"] {
|
||||
background: color-mix(in srgb, var(--g) 14%, transparent);
|
||||
border-color: color-mix(in srgb, var(--g) 70%, transparent);
|
||||
}
|
||||
.game-settings .comp button[data-st="some"] {
|
||||
:is(.game-settings, .motion-cards) .comp button[data-st="some"] {
|
||||
border-style: dashed;
|
||||
border-color: color-mix(in srgb, var(--g) 70%, transparent);
|
||||
}
|
||||
/* Nothing built in yet: dimmed like the mockup, but still a choice that is remembered. */
|
||||
.game-settings .comp button[data-empty="true"]:not([data-st="on"]) {
|
||||
:is(.game-settings, .motion-cards) .comp button[data-empty="true"]:not([data-st="on"]) {
|
||||
opacity: 0.55;
|
||||
}
|
||||
.game-settings .comp .cbx {
|
||||
:is(.game-settings, .motion-cards) .comp .cbx {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
@@ -4334,37 +4414,57 @@ dialog.archive-detail {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
.game-settings .comp button[data-st="on"] .cbx {
|
||||
:is(.game-settings, .motion-cards) .comp button[data-st="on"] .cbx {
|
||||
background: var(--g);
|
||||
border-color: var(--g);
|
||||
}
|
||||
.game-settings .comp button[data-st="some"] .cbx::after {
|
||||
:is(.game-settings, .motion-cards) .comp button[data-st="some"] .cbx::after {
|
||||
content: "";
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
background: var(--g);
|
||||
}
|
||||
.game-settings .comp .cbx svg {
|
||||
:is(.game-settings, .motion-cards) .comp .cbx svg {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
stroke: var(--color-ground);
|
||||
stroke-width: 3;
|
||||
fill: none;
|
||||
}
|
||||
.game-settings .comp .ln {
|
||||
:is(.game-settings, .motion-cards) .comp .ln {
|
||||
display: block;
|
||||
padding-right: 22px;
|
||||
font: 600 17px/1.1 var(--font-display);
|
||||
letter-spacing: 0.02em;
|
||||
color: var(--color-ink);
|
||||
}
|
||||
.game-settings .comp .ls {
|
||||
:is(.game-settings, .motion-cards) .comp .ls {
|
||||
display: block;
|
||||
margin-top: 3px;
|
||||
font-size: 11.5px;
|
||||
line-height: 1.3;
|
||||
color: var(--color-faint);
|
||||
}
|
||||
/* Settings → Appearance → Motion & celebrations: the same cards, three across.
|
||||
A card Reduce motion holds off is dimmed and cannot be pressed. */
|
||||
.motion-cards {
|
||||
--rule-strong: color-mix(in srgb, var(--color-ink) 22%, var(--color-surface));
|
||||
}
|
||||
.motion-cards .comp {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
.motion-cards .comp button:disabled {
|
||||
opacity: 0.45;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.motion-cards .comp button:disabled:hover {
|
||||
border-color: var(--rule-strong);
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.motion-cards .comp {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
.game-settings .compnote {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
|
||||
Reference in new issue
Block a user