From e518fc46a96248ec44f8b61520826ebbe07223ff Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Wed, 13 May 2026 09:39:47 +0300 Subject: [PATCH] feat: section body animation with blur-out, delayed enter, and animation tokens Add animation tokens to :root (--ease-spring, --ease-decelerate, --ease-default, --duration-fast/normal/slow/spring). Apply spring easing to section title enter. Add separate section-body transition: fast blur-out exit (100ms), clean slide-in enter (350ms) delayed by 200ms so content appears after the title animation completes. --- src/shared/styles/theme.css | 61 ++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/shared/styles/theme.css b/src/shared/styles/theme.css index cabb3e0..e193ffe 100644 --- a/src/shared/styles/theme.css +++ b/src/shared/styles/theme.css @@ -75,6 +75,15 @@ /* === GRID === */ --grid-gap: var(--space-3); + + /* === ANIMATION === */ + --ease-default: ease; + --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); + --ease-decelerate: cubic-bezier(0.25, 0, 0, 1); + --duration-fast: 100ms; + --duration-normal: 200ms; + --duration-slow: 350ms; + --duration-spring: 380ms; } @theme inline { @@ -235,8 +244,8 @@ opacity: 1; transform: translateY(0); transition: - opacity 0.35s ease, - transform 0.35s ease; + opacity var(--duration-slow) var(--ease-default), + transform var(--duration-slow) var(--ease-default); } @starting-style { @@ -248,11 +257,17 @@ /* Cross-section view transition (navigation between sections) */ ::view-transition-old(section-content) { - animation: 200ms ease both section-fade-out; + animation-name: section-fade-out; + animation-duration: var(--duration-normal); + animation-timing-function: var(--ease-default); + animation-fill-mode: both; } ::view-transition-new(section-content) { - animation: 300ms ease both section-fade-in; + animation-name: section-fade-in; + animation-duration: var(--duration-spring); + animation-timing-function: var(--ease-spring); + animation-fill-mode: both; } @keyframes section-fade-out { @@ -276,3 +291,41 @@ transform: translateY(0); } } + +/* Section body: instant blur-out, clean slide-in */ +::view-transition-old(section-body) { + animation-name: section-body-out; + animation-duration: var(--duration-fast); + animation-timing-function: var(--ease-default); + animation-fill-mode: both; +} + +::view-transition-new(section-body) { + animation-name: section-body-in; + animation-duration: var(--duration-slow); + animation-delay: var(--duration-normal); + animation-timing-function: var(--ease-decelerate); + animation-fill-mode: both; +} + +@keyframes section-body-out { + from { + opacity: 1; + filter: blur(0); + } + to { + opacity: 0; + filter: blur(3px); + } +} + +@keyframes section-body-in { + from { + opacity: 0; + transform: translateY(16px); + } + to { + opacity: 1; + transform: translateY(0); + } +}