feat(motion): staggered page-load reveal on header chrome

The header is the first thing a user sees. A short staggered fade-in
(logo → title → action button → right-side icons over ~360ms) turns the
instant-pop-in feel into a subtle "the tool is composing itself" beat.

Pure CSS @keyframes (no JS), cubic-bezier(0.2, 0.7, 0.2, 1) for the
"settle in" easing curve. Respects prefers-reduced-motion. Total budget
~260ms before everything is visible — well under the threshold where it
becomes a perceptible delay.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
ZDDC 2026-05-10 20:10:45 -05:00
parent 6260aa4860
commit 1f03631d2d
2 changed files with 69 additions and 1 deletions

View file

@ -332,6 +332,40 @@ a:hover {
display: block;
}
/* Page-load reveal. The header is the first thing a user sees a
short staggered fade-in over ~360ms turns "instant pop-in" into a
subtle "the tool is composing itself for you" beat. Pure CSS, no
JS; respects prefers-reduced-motion. The stagger order (logo
title action buttons right-side icons) mirrors the reading
order of the chrome itself. */
@keyframes zddc-header-rise {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.app-header__logo,
.header-title-group,
.header-left > .btn,
.header-right > * {
animation: zddc-header-rise 360ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.app-header__logo { animation-delay: 0ms; }
.header-title-group { animation-delay: 60ms; }
.header-left > .btn { animation-delay: 120ms; }
.header-right > *:nth-child(1) { animation-delay: 180ms; }
.header-right > *:nth-child(2) { animation-delay: 220ms; }
.header-right > *:nth-child(3) { animation-delay: 260ms; }
@media (prefers-reduced-motion: reduce) {
.app-header__logo,
.header-title-group,
.header-left > .btn,
.header-right > * {
animation: none;
}
}
/* ── Build timestamp ──────────────────────────────────────────────────────── */
.build-timestamp {
font-size: 0.55rem;

View file

@ -371,6 +371,40 @@ a:hover {
display: block;
}
/* Page-load reveal. The header is the first thing a user sees — a
short staggered fade-in over ~360ms turns "instant pop-in" into a
subtle "the tool is composing itself for you" beat. Pure CSS, no
JS; respects prefers-reduced-motion. The stagger order (logo →
title → action buttons → right-side icons) mirrors the reading
order of the chrome itself. */
@keyframes zddc-header-rise {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.app-header__logo,
.header-title-group,
.header-left > .btn,
.header-right > * {
animation: zddc-header-rise 360ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
.app-header__logo { animation-delay: 0ms; }
.header-title-group { animation-delay: 60ms; }
.header-left > .btn { animation-delay: 120ms; }
.header-right > *:nth-child(1) { animation-delay: 180ms; }
.header-right > *:nth-child(2) { animation-delay: 220ms; }
.header-right > *:nth-child(3) { animation-delay: 260ms; }
@media (prefers-reduced-motion: reduce) {
.app-header__logo,
.header-title-group,
.header-left > .btn,
.header-right > * {
animation: none;
}
}
/* ── Build timestamp ──────────────────────────────────────────────────────── */
.build-timestamp {
font-size: 0.55rem;
@ -1207,7 +1241,7 @@ body.help-open .app-header {
</svg>
<div class="header-title-group">
<span class="app-header__title" id="table-title">ZDDC Table</span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.17-alpha · 2026-05-11 01:08:41 · 8be6c4d-dirty</span></span>
<span class="build-timestamp"><span style="color:red;font-weight:bold">v0.0.17-alpha · 2026-05-11 01:10:25 · 6260aa4-dirty</span></span>
</div>
</div>
<div class="header-right">