diff --git a/apps/web/app/components/ui/Navigation/Navigation.css b/apps/web/app/components/ui/Navigation/Navigation.css
index 3a14c20..3fb363e 100644
--- a/apps/web/app/components/ui/Navigation/Navigation.css
+++ b/apps/web/app/components/ui/Navigation/Navigation.css
@@ -29,20 +29,30 @@
last, slowest part of the decelerating slide. The translate is physical
(translateX) on purpose: the lockup row is pinned to dir="ltr" because a
Latin wordmark never mirrors, so the P is always left of the suffix, in
- Arabic too. Pure CSS, so it runs from the server-rendered HTML without
- waiting for hydration, and the `both` fill keeps the suffix hidden through
- the delay instead of flashing in first. It replays whenever the navigation
- mounts again, e.g. on a client-side navigation back to a page. Under
- prefers-reduced-motion the animation is removed outright - app.css only
- collapses the duration and would leave the delay holding the suffix
- hidden - so the full name is simply there from the start. */
+ Arabic too.
+
+After that one-time reveal the mark keeps breathing: after a long rest
+ (~26s of stillness per cycle) it slides back out from behind the P and
+ returns, so the wordmark quietly draws the eye without the glyphs moving
+ while they are visible. The two
+ animations are sequenced by delay - the reveal (once, `both` fill, so the
+ suffix stays hidden through its delay instead of flashing in) hands over
+ to the loop, whose later position in the list wins from its start, and
+ whose own delay is when the revealed lockup is simply at rest. Pure CSS,
+ so it runs from the server-rendered HTML without waiting for hydration.
+ Under prefers-reduced-motion both animations are removed outright -
+ app.css only collapses the duration and would leave the delay holding the
+ suffix hidden - so the full name is simply there from the start. */
.sh-brand-suffix {
overflow: hidden;
}
.sh-brand-suffix__mark {
- animation: sh-brand-suffix-in var(--motion-duration-reveal)
- var(--motion-ease-entrance) var(--motion-delay-reveal) both;
+ animation:
+ sh-brand-suffix-in var(--motion-duration-reveal)
+ var(--motion-ease-entrance) var(--motion-delay-reveal) both,
+ sh-brand-breathe calc(var(--motion-duration-reveal) * 37.5)
+ ease-in-out calc(var(--motion-duration-reveal) * 5) infinite;
}
@media (prefers-reduced-motion: reduce) {
@@ -68,6 +78,53 @@
}
}
+/* One 30s breath: dwell at rest (~26s - the stillness is what stretches, the
+ gestures stay at a human pace), slide back out behind the P (the reverse of
+ the reveal - solid while it pulls away, fading as it leaves), pass on
+ hidden, then play the reveal again, and hold. Looped, with the cycle ending
+ where it starts so the seam is invisible. Each slide is ONE eased interval
+ of roughly one reveal duration - the opacity stop inside the out-slide is
+ opacity-only, so it never splits the transform's easing and the glyphs
+ cannot stall or hitch mid-gesture. */
+@keyframes sh-brand-breathe {
+ /* settled */
+ 0%, 87% {
+ transform: translateX(0);
+ opacity: 1;
+ animation-timing-function: var(--motion-ease-standard);
+ }
+
+ /* pull back solid - opacity only, so the 87→90 transform still runs one
+ eased interval and the slide never hitches */
+ 88.5% {
+ opacity: 1;
+ }
+
+ /* gone, behind the P */
+ 90% {
+ transform: translateX(-100%);
+ opacity: 0;
+ }
+
+ /* pass, hidden, then the reveal again - one eased slide back in */
+ 94% {
+ transform: translateX(-100%);
+ opacity: 0;
+ animation-timing-function: var(--motion-ease-entrance);
+ }
+
+ 97% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+
+ /* settled until the cycle hands over (0% is settled too) */
+ 100% {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
@keyframes sh-nav-menu-in {
from {
opacity: 0;
diff --git a/apps/web/app/routes/_page-kit/sections.tsx b/apps/web/app/routes/_page-kit/sections.tsx
index 4f66548..bb18cf1 100644
--- a/apps/web/app/routes/_page-kit/sections.tsx
+++ b/apps/web/app/routes/_page-kit/sections.tsx
@@ -583,12 +583,6 @@ export function PageHero({
aria-hidden="true"
className="pointer-events-none absolute inset-0 bg-[var(--overlay-picture-tint)]"
/>
- {/* A highlight travelling across the picture - the draft's
- `sheen`. Decorative, and it rides on top of both washes. */}
-
{/* The colour band (478:16360, redrawn in the drafts' home
diff --git a/apps/web/app/routes/home.tsx b/apps/web/app/routes/home.tsx
index 1f20329..bafdf81 100644
--- a/apps/web/app/routes/home.tsx
+++ b/apps/web/app/routes/home.tsx
@@ -479,7 +479,7 @@ export default function Home({ loaderData }: Route.ComponentProps) {
/>