diff --git a/src/app/globals.css b/src/app/globals.css index 365701a..297b8a5 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -219,18 +219,22 @@ } /* Über-uns paw print trail — scattered decorative icons behind the story - text (Gitea #23) that "stamp" into place as each one scrolls into view. - Base rule sets the resting rotation/scale so the fallback (no scroll- - timeline support) still looks intentional, not broken. */ + text (Gitea #23) that fade + "stamp" into place as each one scrolls into + view, opacity and scale both driven by scroll position. Base rule sets + the resting opacity/rotation/scale so the fallback (no scroll-timeline + support) still looks intentional, not broken. */ .paw-trail-icon { + opacity: var(--paw-opacity, 0.15); transform: scale(1) rotate(var(--paw-rot, 0deg)); } @keyframes paw-trail-reveal { from { + opacity: 0; transform: scale(0.4) rotate(var(--paw-rot, 0deg)); } to { + opacity: var(--paw-opacity, 0.15); transform: scale(1) rotate(var(--paw-rot, 0deg)); } } @@ -255,6 +259,7 @@ } .paw-trail-icon { animation: none !important; + opacity: var(--paw-opacity, 0.15) !important; transform: scale(1) rotate(var(--paw-rot, 0deg)) !important; } } \ No newline at end of file diff --git a/src/components/landing/PawPrintTrail.tsx b/src/components/landing/PawPrintTrail.tsx index 62d7961..07de552 100644 --- a/src/components/landing/PawPrintTrail.tsx +++ b/src/components/landing/PawPrintTrail.tsx @@ -12,30 +12,35 @@ type Print = { static?: boolean; }; -// Scattered footprint positions down the "Über uns" page — deliberately -// irregular (varied rotation/offset/size) so it reads as a trail, not a grid. +// Scattered footprint positions down the "Über uns" page — irregular gaps +// and side assignment (no strict alternation) so it reads as a trail, not +// a grid. Offsets sit closer to the centered text column than the viewport +// edge, so the trail feels like it's flanking the story, not the screen. const PRINTS: Print[] = [ - { top: "2%", side: "right", offset: "6%", size: "h-14 w-14 sm:h-20 sm:w-20", rotate: -18, opacity: 0.15, static: true }, - { top: "10%", side: "left", offset: "5%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: 10, opacity: 0.14 }, - { top: "18%", side: "right", offset: "12%", size: "h-10 w-10 sm:h-14 sm:w-14", rotate: -6, opacity: 0.15 }, - { top: "26%", side: "left", offset: "8%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: 14, opacity: 0.16 }, - { top: "34%", side: "right", offset: "6%", size: "h-16 w-16 sm:h-24 sm:w-24", rotate: 6, opacity: 0.14 }, - { top: "42%", side: "left", offset: "12%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: -12, opacity: 0.15 }, - { top: "50%", side: "right", offset: "9%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: 18, opacity: 0.16 }, - { top: "58%", side: "left", offset: "6%", size: "h-14 w-14 sm:h-20 sm:w-20", rotate: -8, opacity: 0.14 }, - { top: "66%", side: "right", offset: "14%", size: "h-10 w-10 sm:h-14 sm:w-14", rotate: 10, opacity: 0.15 }, - { top: "74%", side: "left", offset: "9%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: -16, opacity: 0.16 }, - { top: "82%", side: "right", offset: "7%", size: "h-14 w-14 sm:h-20 sm:w-20", rotate: 12, opacity: 0.14 }, - { top: "88%", side: "left", offset: "5%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: -10, opacity: 0.15 }, - { top: "94%", side: "right", offset: "10%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: 8, opacity: 0.14 }, + { top: "1%", side: "right", offset: "18%", size: "h-14 w-14 sm:h-20 sm:w-20", rotate: -16, opacity: 0.15, static: true }, + { top: "8%", side: "left", offset: "22%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: 9, opacity: 0.14 }, + { top: "13%", side: "left", offset: "16%", size: "h-11 w-11 sm:h-14 sm:w-14", rotate: -14, opacity: 0.16 }, + { top: "21%", side: "right", offset: "26%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: 18, opacity: 0.13 }, + { top: "25%", side: "right", offset: "15%", size: "h-16 w-16 sm:h-24 sm:w-24", rotate: 4, opacity: 0.15 }, + { top: "33%", side: "left", offset: "28%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: -8, opacity: 0.16 }, + { top: "38%", side: "right", offset: "19%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: 14, opacity: 0.14 }, + { top: "46%", side: "left", offset: "17%", size: "h-14 w-14 sm:h-20 sm:w-20", rotate: -20, opacity: 0.13 }, + { top: "49%", side: "right", offset: "24%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: 10, opacity: 0.16 }, + { top: "57%", side: "left", offset: "20%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: -6, opacity: 0.15 }, + { top: "64%", side: "right", offset: "16%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: 16, opacity: 0.14 }, + { top: "70%", side: "left", offset: "25%", size: "h-14 w-14 sm:h-20 sm:w-20", rotate: -12, opacity: 0.16 }, + { top: "78%", side: "right", offset: "21%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: 7, opacity: 0.13 }, + { top: "87%", side: "left", offset: "18%", size: "h-12 w-12 sm:h-16 sm:w-16", rotate: -18, opacity: 0.15 }, + { top: "95%", side: "right", offset: "23%", size: "h-9 w-9 sm:h-12 sm:w-12", rotate: 11, opacity: 0.14 }, ]; /** * Decorative paw print trail behind the "Über uns" story content (Gitea * #23) — pure CSS scroll-driven animation (see .paw-trail-icon in * globals.css), so this stays a Server Component. Each print (other than - * the first, always-visible one) "stamps" into place as it scrolls into - * view instead of just sitting static. + * the first, always-visible one) fades and scales into place as it scrolls + * into view, opacity set via --paw-opacity so the keyframe can animate + * toward it instead of the print appearing at full strength immediately. */ export function PawPrintTrail() { return ( @@ -47,8 +52,9 @@ export function PawPrintTrail() { style={{ top: print.top, [print.side]: print.offset, - opacity: print.opacity, - ...(print.static ? { transform: `rotate(${print.rotate}deg)` } : { "--paw-rot": `${print.rotate}deg` }), + ...(print.static + ? { opacity: print.opacity, transform: `rotate(${print.rotate}deg)` } + : { "--paw-opacity": print.opacity, "--paw-rot": `${print.rotate}deg` }), } as React.CSSProperties} fill="currentColor" strokeWidth={0}