fix: hero CTAs invisible until scroll, seek animation skip, layout overhaul

- Remove data-reveal from hero h1/subtitle/mascot/cta-group/version-badge
  (critical above-fold content must never start hidden)
- Change IntersectionObserver rootMargin -150px to -30px, threshold 0.1 to 0.05
  (CTAs at ~530px were past the observer zone on laptops)
- Hero layout: align-items flex-start + padding-top 7.5rem for content at top
- Cards 62cqw to 70cqw, -3% offsets for dramatic overlap cascade
- Film animation: replace stick-figure walker with cinematic night scene
  (7 twinkling stars, glowing moon with drift, parallax mountains, firefly)
- Seek now restarts all film child animations via .demo-reset class toggle
  (was incorrectly resetting parent only — no visible jump)
- Add .demo-seek-sweep overlay + brightness flash during seek
- Video select: placeholder option ('Choose a video tab...') until story picks
- RATE 8 to 1 for realtime playback
- Version badge moved below download buttons
- All 15 locale files: add DEMO_SELECT_PLACEHOLDER key
This commit is contained in:
KoalaDev
2026-07-03 10:42:09 +02:00
parent e5a4032710
commit 573847486b
18 changed files with 219 additions and 95 deletions
+135 -58
View File
@@ -218,16 +218,16 @@ nav {
.hero {
min-height: 100vh;
display: flex;
align-items: center;
padding-top: 8rem;
padding-bottom: 4rem;
align-items: flex-start;
padding-top: 7.5rem;
padding-bottom: 3rem;
}
.hero-grid {
display: grid;
grid-template-columns: 1.2fr 1fr;
align-items: center;
gap: 4rem;
align-items: start;
gap: 3rem;
text-align: left;
width: 100%;
}
@@ -236,7 +236,7 @@ nav {
font-size: 4.5rem;
font-weight: 800;
line-height: 1.1;
margin-bottom: 1.5rem;
margin-bottom: 1.4rem;
padding-bottom: 0.1em;
background: linear-gradient(to bottom, #fff 40%, #6366f1);
-webkit-background-clip: text;
@@ -251,7 +251,7 @@ nav {
.hero-text p, .hero-subtitle {
font-size: 1.25rem;
color: var(--text-muted);
margin-bottom: 2.5rem;
margin-bottom: 1.9rem;
max-width: 600px;
font-weight: 400;
line-height: 1.6;
@@ -343,6 +343,11 @@ nav {
transition: transform 0.2s, box-shadow 0.2s, background 0.2s;
}
.version-badge-below {
margin-bottom: 0;
margin-top: 1.5rem;
}
.version-badge:hover {
background: rgba(99, 102, 241, 0.2);
box-shadow: 0 0 16px rgba(99, 102, 241, 0.3);
@@ -2977,13 +2982,13 @@ header[id] {
.hero-demo-scene {
position: relative;
width: 100%;
height: 370px;
height: calc(63cqw + 84px);
height: 390px;
height: calc(66cqw + 78px);
transition: height 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}
.hero-demo-scene.popup-open {
height: 590px;
height: 600px;
}
/* While initializing, suppress all transitions so the popup can start closed
@@ -3048,8 +3053,8 @@ header[id] {
/* Video tab cards: a clean window cascade — the right one is in front */
.demo-tab-card {
position: absolute;
width: 274px;
width: 62cqw;
width: 310px;
width: 70cqw;
background: #131c31;
border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: 14px;
@@ -3068,8 +3073,8 @@ header[id] {
/* Card A = the foreground window at the top right ("your" browser,
hosts the extension icon in its toolbar) */
.demo-tab-a {
top: 30px;
right: 0;
top: 22px;
right: -3%;
transform: rotate(1.2deg);
transform-origin: top right;
z-index: 3;
@@ -3077,21 +3082,21 @@ header[id] {
/* Card B = the friend's window, lower left, tucked behind */
.demo-tab-b {
top: 168px;
top: calc(28cqw + 44px);
left: 0;
transform: rotate(-1.5deg);
top: 142px;
top: calc(20cqw + 40px);
left: -3%;
transform: rotate(-1.6deg);
transform-origin: top left;
z-index: 2;
}
/* When the popup slides in from the right edge, the tabs step aside */
.hero-demo-scene.popup-open .demo-tab-a {
transform: rotate(1deg) translate(-55%, 2%) scale(0.9);
transform: rotate(1deg) translate(-48%, 2%) scale(0.88);
}
.hero-demo-scene.popup-open .demo-tab-b {
transform: rotate(-1.5deg) scale(0.95);
transform: rotate(-1.6deg) scale(0.94);
}
.demo-tab-titlebar {
@@ -3533,62 +3538,134 @@ header[id] {
height: 100%;
}
.film-limb {
stroke: #e2e8f0;
stroke-width: 2;
stroke-linecap: round;
/* Cinematic "movie" scene: a moonlit landscape with parallax mountains,
twinkling stars, a glowing moon, and a drifting firefly. Every layer
freezes when playback pauses — on both tabs at once. */
.demo-film {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.film-walker {
transform: translate(-15px, 74px);
animation: filmWalk 10s linear infinite;
}
@keyframes filmWalk {
to { transform: translate(175px, 74px); }
}
.film-bob {
animation: filmBob 0.5s ease-in-out infinite alternate;
}
@keyframes filmBob {
to { transform: translateY(-1.8px); }
}
.film-swing-1,
.film-swing-2 {
/* Stars: staggered twinkle so the sky feels alive */
.film-star {
transform-box: fill-box;
transform-origin: top center;
transform-origin: center;
animation: filmTwinkle 2.8s ease-in-out infinite;
}
.film-star:nth-child(2) { animation-duration: 3.4s; animation-delay: 0.5s; }
.film-star:nth-child(3) { animation-duration: 2.4s; animation-delay: 1.1s; }
.film-star:nth-child(4) { animation-duration: 3.6s; animation-delay: 0.3s; }
.film-star:nth-child(5) { animation-duration: 2.6s; animation-delay: 1.6s; }
.film-star:nth-child(6) { animation-duration: 3.2s; animation-delay: 0.8s; }
.film-star:nth-child(7) { animation-duration: 2.2s; animation-delay: 1.3s; }
@keyframes filmTwinkle {
0%, 100% { opacity: 0.25; transform: scale(0.85); }
50% { opacity: 1; transform: scale(1.15); }
}
.film-swing-1 { animation: filmSwing 0.5s ease-in-out infinite alternate; }
.film-swing-2 { animation: filmSwing 0.5s ease-in-out infinite alternate-reverse; }
@keyframes filmSwing {
from { transform: rotate(30deg); }
to { transform: rotate(-30deg); }
/* Moon: gentle glow pulse + slow arc drift */
.film-moon {
transform-box: fill-box;
transform-origin: center;
animation: filmMoon 6s ease-in-out infinite alternate;
}
.film-ball-x {
animation: filmBallX 6.5s linear infinite;
@keyframes filmMoon {
from { transform: translate(0, 0); filter: drop-shadow(0 0 4px rgba(241,245,249,0.5)); }
to { transform: translate(-6px, 3px); filter: drop-shadow(0 0 10px rgba(241,245,249,0.95)); }
}
@keyframes filmBallX {
to { transform: translateX(175px); }
/* Mountain layers: subtle parallax sway (oscillates so it never runs off-edge) */
.film-mtn-back {
transform-box: fill-box;
animation: filmMtnBack 24s ease-in-out infinite alternate;
}
.film-ball {
animation: filmBallY 0.55s cubic-bezier(0.4, 0, 0.6, 1) infinite alternate;
@keyframes filmMtnBack {
from { transform: translateX(-3px); }
to { transform: translateX(3px); }
}
@keyframes filmBallY {
to { transform: translateY(-16px); }
.film-mtn-front {
transform-box: fill-box;
animation: filmMtnFront 16s ease-in-out infinite alternate;
}
@keyframes filmMtnFront {
from { transform: translateX(-5px); }
to { transform: translateX(5px); }
}
/* Firefly: warm dot floating across the foreground */
.film-firefly {
animation: filmFireflyX 11s linear infinite;
}
@keyframes filmFireflyX {
from { transform: translate(15px, 0); }
to { transform: translate(145px, 0); }
}
.film-firefly-light {
transform-box: fill-box;
transform-origin: center;
animation: filmFireflyBob 2.6s ease-in-out infinite alternate;
filter: drop-shadow(0 0 5px rgba(253, 224, 71, 0.95));
}
@keyframes filmFireflyBob {
from { transform: translateY(-4px) scale(0.9); opacity: 0.7; }
to { transform: translateY(4px) scale(1.15); opacity: 1; }
}
.demo-film * { animation-play-state: paused; }
.demo-tab-card.playing .demo-film * { animation-play-state: running; }
/* Seek-reset: scrubbing restarts every film layer from frame zero so the
jump reads as a real cut, not a silent time update. */
.demo-film.demo-reset * {
animation: none !important;
}
/* Seek-break: scrubbing the timeline visibly glitches both videos so the
jump reads as a real cut instead of an invisible time update. A scanline
sweep + brightness pop, and the film animations restart mid-stride. */
.demo-video-art { transition: filter 0.12s ease-out; }
.demo-tab-card.demo-seeking .demo-video-art {
animation-play-state: paused;
filter: brightness(1.9) saturate(1.4) blur(0.6px);
}
.demo-tab-card .demo-seek-sweep {
position: absolute;
inset: 0;
z-index: 4;
pointer-events: none;
opacity: 0;
background: linear-gradient(90deg,
transparent 0%,
rgba(129, 140, 248, 0.35) 20%,
rgba(255, 255, 255, 0.55) 50%,
rgba(129, 140, 248, 0.35) 80%,
transparent 100%);
mix-blend-mode: screen;
transform: translateX(-100%);
}
.demo-tab-card.demo-seeking .demo-seek-sweep {
animation: demoSeekSweep 0.34s ease-out;
}
@keyframes demoSeekSweep {
0% { opacity: 0; transform: translateX(-100%); }
20% { opacity: 1; }
100% { opacity: 0; transform: translateX(100%); }
}
/* The sync chip only appears once the room is connected (story progression) */
.demo-sync-chip {
opacity: 0;