Files
KoalaSync/website/styles/demo.css
T

1612 lines
40 KiB
CSS

/* --- Hero Live Demo Scene (two synced tabs + extension popup) --- */
.hero-mockup-wrapper {
flex-direction: column;
gap: 0.9rem;
container-type: inline-size;
}
/* Fixed height that already fits the open popup, so toggling it never changes
layout (the vertically centered hero never jumps). The empty lower area is
the invisible room the popup drops into.
Do not move .hero-mockup-wrapper down to align the headline and demo tops:
the extension popup is bottom-anchored inside this scene, so moving the whole
wrapper destroys the vertical balance and leaves no breathing room below. */
.hero-demo-scene {
--demo-content-y: 0px;
position: relative;
width: 100%;
height: max(calc(59cqw + 100px), 548px);
}
.demo-tab-stack {
position: relative;
width: 100%;
height: calc(59cqw + 100px + var(--demo-content-y));
}
@media (min-width: 1025px) {
.hero-demo-scene {
/* Balance the demo inside the visible hero area below the fixed navbar.
Shift the scene content, not the hero text or grid. */
--demo-content-y: 2.75rem;
}
}
/* While initializing, suppress all transitions so the popup can start closed
without a visible open->closed animation on page load. */
.hero-demo-scene.demo-no-anim,
.hero-demo-scene.demo-no-anim * {
transition-duration: 0s !important;
}
/* Sync status chip: green "in sync" at rest, flashes the broadcast event */
.demo-sync-chip {
position: absolute;
top: var(--demo-content-y);
left: 2px;
z-index: 8;
display: inline-flex;
align-items: center;
gap: 7px;
padding: 5px 12px;
border-radius: 99px;
background: oklch(0.68 0.13 150 / 0.12);
border: 1px solid oklch(0.68 0.13 150 / 0.35);
color: #86efac;
font-family: inherit;
font-size: 11px;
font-weight: 800;
letter-spacing: 0.06em;
text-transform: uppercase;
cursor: default;
transition: background 0.3s, border-color 0.3s, color 0.3s;
}
.demo-chip-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: oklch(0.68 0.13 150);
box-shadow: 0 0 8px oklch(0.68 0.13 150);
transition: background 0.3s, box-shadow 0.3s;
}
.demo-sync-chip .demo-chip-event { display: none; }
.demo-sync-chip.event {
background: oklch(0.68 0.13 150 / 0.14);
border-color: oklch(0.68 0.13 150 / 0.45);
color: oklch(0.85 0.07 150);
}
.demo-sync-chip.event .demo-chip-dot {
background: oklch(0.75 0.13 150);
box-shadow: 0 0 8px oklch(0.75 0.13 150);
}
.demo-sync-chip.event .demo-chip-label-sync { display: none; }
.demo-sync-chip.event .demo-chip-event { display: inline; }
@keyframes demoBlink {
50% { opacity: 0.35; }
}
/* Video tab cards: a clean window cascade — the right one is in front */
.demo-tab-card {
position: absolute;
width: 310px;
width: 70cqw;
background: var(--demo-card);
border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: 14px;
box-shadow: 0 18px 36px rgba(0, 0, 0, 0.45), inset 0 1px rgba(255, 255, 255, 0.05);
overflow: hidden;
cursor: pointer;
user-select: none;
transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.25s;
}
.demo-tab-card:hover,
.demo-tab-card:focus-visible {
border-color: oklch(0.68 0.13 150 / 0.55);
}
/* Card A = the foreground window at the top right ("your" browser,
hosts the extension icon in its toolbar) */
.demo-tab-a {
top: calc(49px + var(--demo-content-y));
right: -3%;
transform: rotate(1.2deg);
transform-origin: top right;
z-index: 3;
}
.demo-tab-a:hover {
z-index: 4;
transform: rotate(1.2deg) scale(1.02);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.65), 0 0 20px oklch(0.68 0.13 150 / 0.2);
}
/* Card B = the friend's window, lower left, tucked behind */
.demo-tab-b {
top: 142px;
top: calc(20cqw + 67px + var(--demo-content-y));
left: -3%;
transform: rotate(-1.6deg);
transform-origin: top left;
z-index: 2;
}
.demo-tab-b:hover {
z-index: 4;
transform: rotate(-1.6deg) scale(1.02);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.65), 0 0 20px oklch(0.68 0.13 150 / 0.2);
}
/* When the popup slides in from the right edge, the tabs step aside */
.hero-demo-scene.popup-open .demo-tab-a {
top: calc(22px + var(--demo-content-y));
transform: rotate(1deg) translate(-44%, 20%) scale(0.88);
}
.hero-demo-scene.popup-open .demo-tab-a:hover {
z-index: 4;
transform: rotate(1deg) translate(-44%, 20%) scale(0.92);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.65), 0 0 20px oklch(0.68 0.13 150 / 0.2);
}
.hero-demo-scene.popup-open .demo-tab-b {
top: calc(20cqw + 40px + var(--demo-content-y));
transform: rotate(-1.6deg) translate(0, 14%) scale(0.94);
}
.hero-demo-scene.popup-open .demo-tab-b:hover {
z-index: 4;
transform: rotate(-1.6deg) translate(0, 14%) scale(0.98);
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.65), 0 0 20px oklch(0.68 0.13 150 / 0.2);
}
.demo-tab-titlebar {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 8px 6px 10px;
background: var(--demo-toolbar);
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
font-size: 10.5px;
color: var(--text-muted);
font-weight: 600;
}
.demo-tab-dots {
display: flex;
gap: 4px;
flex-shrink: 0;
}
.demo-tab-dots i {
display: block;
width: 7px;
height: 7px;
border-radius: 50%;
background: oklch(0.32 0.03 125);
}
.demo-tab-title {
display: flex;
align-items: center;
gap: 5px;
flex: 1;
min-width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.demo-tab-title svg { flex-shrink: 0; }
.demo-tab-user {
flex-shrink: 0;
font-size: 9.5px;
font-weight: 700;
padding: 2px 7px;
border-radius: 99px;
}
.demo-user-a {
color: oklch(0.80 0.10 150);
background: oklch(0.68 0.13 150 / 0.15);
}
.demo-user-b {
color: #86efac;
background: oklch(0.68 0.13 150 / 0.12);
}
/* Extension launcher pinned in the foreground window's toolbar */
.demo-ext-launcher {
position: relative;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
padding: 0;
border-radius: 7px;
background: oklch(0.30 0.03 130);
border: 1px solid rgba(255, 255, 255, 0.12);
cursor: pointer;
transition: border-color 0.25s, box-shadow 0.25s, transform 0.15s;
}
.demo-ext-launcher img {
display: block;
width: 16px;
height: 16px;
border-radius: 4px;
}
.demo-ext-launcher:hover {
border-color: var(--accent);
transform: translateY(-1px);
}
.demo-ext-launcher:active {
transform: scale(0.94);
}
.hero-demo-scene.popup-open .demo-ext-launcher {
border-color: oklch(0.68 0.13 150 / 0.7);
box-shadow: 0 0 10px oklch(0.68 0.13 150 / 0.45);
}
.demo-ext-launcher::after {
content: '';
position: absolute;
top: -3px;
right: -3px;
width: 8px;
height: 8px;
border-radius: 50%;
background: oklch(0.68 0.13 150);
box-shadow: 0 0 8px oklch(0.68 0.13 150);
opacity: 0;
transition: opacity 0.3s;
}
.hero-demo-scene:not(.popup-open) .demo-ext-launcher:not(.demo-ext-static)::after {
opacity: 1;
animation: demoBlink 1.4s ease-in-out infinite;
}
/* Card B shows the same extension icon, purely to signal the friend has it
installed too. It is not interactive and does not blink or glow. */
.demo-ext-static,
.demo-ext-static:hover {
cursor: default;
border-color: rgba(255, 255, 255, 0.12);
transform: none;
box-shadow: none;
}
.demo-ext-static::after { display: none; }
/* Abstract "video" artwork with a slow cinematic pan/zoom while playing */
.demo-video {
position: relative;
aspect-ratio: 16 / 9;
background: var(--demo-sky-bottom);
overflow: hidden;
}
.demo-video::after {
content: '';
position: absolute;
inset: 0;
z-index: 1;
pointer-events: none;
/* Cinematic vignette: soft edge falloff + heavier floor for the controls */
box-shadow:
inset 0 0 0 1px rgba(255, 255, 255, 0.05),
inset 0 0 34px oklch(0.04 0.015 145 / 0.32),
inset 0 -26px 40px oklch(0.04 0.015 145 / 0.26);
}
html.theme-light .hero-demo-scene .demo-video::after {
box-shadow:
inset 0 0 0 1px oklch(0.30 0.04 145 / 0.13),
inset 0 18px 32px oklch(0.98 0.03 90 / 0.1),
inset 0 -22px 34px oklch(0.18 0.05 145 / 0.16);
}
.demo-video-art {
position: absolute;
inset: 0;
background:
radial-gradient(30% 42% at 76% 29%, var(--demo-glow), transparent 64%),
radial-gradient(90% 85% at 18% 5%, var(--demo-glow), transparent 66%),
linear-gradient(160deg, var(--demo-sky-top) 0%, var(--demo-sky-mid) 52%, var(--demo-sky-bottom) 100%);
transform-origin: 60% 40%;
animation:
demoKenBurns 9s ease-in-out infinite alternate,
demoArtShift 7s ease-in-out infinite alternate;
animation-play-state: paused;
}
/* Soft light drifting through the scene */
.demo-video-art::before {
content: '';
position: absolute;
top: -25%;
left: -12%;
width: 70%;
aspect-ratio: 1;
border-radius: 50%;
background: radial-gradient(circle, var(--demo-glow), transparent 65%);
animation: demoGlowDrift 7s ease-in-out infinite alternate;
animation-play-state: paused;
}
.demo-video-art::after {
content: '';
position: absolute;
inset: 0;
background: linear-gradient(105deg, transparent 30%, oklch(0.75 0.13 150 / 0.14) 45%, oklch(0.75 0.10 150 / 0.1) 55%, transparent 70%);
transform: translateX(-100%);
animation: demoSheen 2.8s linear infinite;
animation-play-state: paused;
}
/* Playing runs the animations; pausing freezes them mid-frame, so a synced
pause is visible at a glance */
.demo-tab-card.playing .demo-video-art,
.demo-tab-card.playing .demo-video-art::before,
.demo-tab-card.playing .demo-video-art::after {
animation-play-state: running;
}
@keyframes demoKenBurns {
from { transform: scale(1) translate(0, 0); }
to { transform: scale(1.18) translate(-3%, 2%); }
}
@keyframes demoArtShift {
from { filter: hue-rotate(0deg) brightness(1); }
to { filter: hue-rotate(40deg) brightness(1.15); }
}
@keyframes demoGlowDrift {
from { transform: translate(0, 0); }
to { transform: translate(65%, 30%); }
}
@keyframes demoSheen {
to { transform: translateX(100%); }
}
/* Play / pause overlay */
.demo-play-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: oklch(0.10 0.01 135 / 0.35);
transition: opacity 0.25s, background 0.25s;
}
.demo-icon-wrap {
display: flex;
align-items: center;
justify-content: center;
width: 46px;
height: 46px;
border-radius: 50%;
background: oklch(0.20 0.025 140 / 0.75);
border: 1px solid rgba(255, 255, 255, 0.25);
color: white;
box-shadow: 0 4px 18px rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
transition: transform 0.2s;
}
.demo-tab-card:hover .demo-icon-wrap { transform: scale(1.1); }
.demo-play-overlay .icon-pause { display: none; }
.demo-tab-card.playing .icon-play { display: none; }
.demo-tab-card.playing .icon-pause { display: block; }
.demo-tab-card.playing .demo-play-overlay {
opacity: 0;
background: transparent;
}
.demo-tab-card.playing:hover .demo-play-overlay,
.demo-tab-card.playing:focus-visible .demo-play-overlay {
opacity: 1;
}
/* Timestamp + seekable progress bar */
.demo-video-controls {
position: absolute;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
gap: 8px;
padding: 14px 10px 8px;
background: linear-gradient(transparent, var(--demo-control-fade));
font-size: 9.5px;
color: oklch(0.88 0.015 90);
z-index: 1;
}
.demo-time,
.demo-duration {
flex-shrink: 0;
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-weight: 700;
letter-spacing: 0.03em;
font-variant-numeric: tabular-nums;
}
.demo-duration {
font-weight: 600;
opacity: 0.7;
}
/* Decorative player chrome: play state glyph, volume, HD, fullscreen */
.demo-ctrl-icon {
display: flex;
align-items: center;
flex-shrink: 0;
opacity: 0.85;
}
.demo-ctrl-play .icon-pause { display: none; }
.demo-tab-card.playing .demo-ctrl-play .icon-play { display: none; }
.demo-tab-card.playing .demo-ctrl-play .icon-pause { display: block; }
.demo-ctrl-badge {
flex-shrink: 0;
font-size: 7px;
font-weight: 800;
letter-spacing: 0.06em;
line-height: 1;
padding: 2px 3px;
border: 1px solid currentColor;
border-radius: 3px;
opacity: 0.65;
}
.demo-progress {
position: relative;
flex: 1;
height: 5px;
border-radius: 99px;
background: var(--demo-track);
cursor: pointer;
}
/* Generous invisible hit area for seeking */
.demo-progress::before {
content: '';
position: absolute;
inset: -8px 0;
}
/* Buffered range behind the playhead, like a real player */
.demo-progress-buffer {
position: absolute;
top: 0;
bottom: 0;
left: 0;
width: 56%;
border-radius: 99px;
background: oklch(0.92 0.02 95 / 0.14);
pointer-events: none;
}
.demo-progress-fill {
position: relative;
height: 100%;
width: 30%;
border-radius: 99px;
background: linear-gradient(90deg, oklch(0.68 0.13 150), oklch(0.62 0.14 45));
pointer-events: none;
}
/* Scrub thumb, revealed on hover */
.demo-progress-fill::after {
content: '';
position: absolute;
right: -5px;
top: 50%;
width: 11px;
height: 11px;
margin-top: -5.5px;
border-radius: 50%;
background: oklch(0.88 0.015 90);
box-shadow: 0 0 6px oklch(0.68 0.13 150 / 0.8);
opacity: 0;
transform: scale(0.6);
transition: opacity 0.2s, transform 0.2s;
}
.demo-tab-card:hover .demo-progress-fill::after {
opacity: 1;
transform: scale(1);
}
/* Sync pulse ring on both cards */
.demo-tab-card.sync-pulse {
animation: demoCardPulse 0.9s ease-out;
}
@keyframes demoCardPulse {
0% { box-shadow: 0 18px 36px rgba(0, 0, 0, 0.45), 0 0 0 0 oklch(0.68 0.13 150 / 0.65); }
100% { box-shadow: 0 18px 36px rgba(0, 0, 0, 0.45), 0 0 0 22px oklch(0.68 0.13 150 / 0); }
}
/* The existing popup mockup slides in at the right edge, dropping out of
the toolbar icon of the foreground window */
.hero-demo-scene .extension-mockup {
position: absolute;
bottom: 0;
right: 0;
z-index: 5;
width: 292px;
width: min(320px, 66cqw);
margin: 0;
transform-origin: top right;
transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.35s, visibility 0.45s;
}
@media (min-width: 1025px) {
.hero-demo-scene .extension-mockup {
/* Counter the content shift so the opened panel is balanced below nav. */
bottom: 0.625rem;
}
}
.hero-demo-scene:not(.popup-open) .extension-mockup {
transform: translate(2%, -3%) scale(0.5);
opacity: 0;
visibility: hidden;
pointer-events: none;
}
/* Ghost cursor for the automated walkthrough */
.demo-cursor {
position: absolute;
top: 52%;
left: 46%;
z-index: 20;
width: 22px;
height: 22px;
opacity: 0;
pointer-events: none;
filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6));
transition: top 0.65s cubic-bezier(0.45, 0.05, 0.25, 1), left 0.65s cubic-bezier(0.45, 0.05, 0.25, 1), opacity 0.35s;
}
.demo-cursor.visible { opacity: 1; }
.demo-cursor svg {
display: block;
width: 100%;
height: 100%;
}
.demo-cursor::before {
content: '';
position: absolute;
top: -6px;
left: -8px;
width: 32px;
height: 32px;
border-radius: 50%;
border: 2px solid oklch(0.75 0.13 150);
opacity: 0;
transform: scale(0.35);
}
.demo-cursor.clicking::before {
animation: demoClickRipple 0.45s ease-out;
}
@keyframes demoClickRipple {
0% { opacity: 0.9; transform: scale(0.35); }
100% { opacity: 0; transform: scale(1.25); }
}
/* Caption below the scene */
.demo-hint {
margin: 0.75rem auto 0;
max-width: min(100%, 34rem);
text-align: center;
font-size: 0.82rem;
line-height: 1.45;
color: var(--text-muted);
opacity: 0;
transition: opacity 0.6s;
}
.demo-hint.show { opacity: 0.75; }
/* Tablet/Small Desktop: fall back to the classic static popup mockup */
@media (max-width: 1023px) {
.hero-demo-scene,
.hero-demo-scene.popup-open {
height: auto;
max-width: 320px;
margin: 0 auto;
}
.demo-tab-card,
.demo-tab-stack,
.demo-sync-chip,
.demo-cursor,
.demo-hint {
display: none !important;
}
.hero-demo-scene .extension-mockup,
.hero-demo-scene:not(.popup-open) .extension-mockup {
position: static;
width: 100%;
transform: none;
opacity: 1;
visibility: visible;
pointer-events: auto;
}
}
@media (prefers-reduced-motion: reduce) {
.hero-demo-scene:not(.popup-open) .demo-ext-launcher::after {
animation: none;
}
}
/* --- Story walkthrough additions: room creation, invite flight, film --- */
/* The stick-figure film carries the motion now — keep only the color drift
on the backdrop (the animation shorthand resets play-state, so re-pause) */
.demo-video-art {
animation: demoArtShift 7s ease-in-out infinite alternate;
animation-play-state: paused;
}
.demo-film {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.hero-demo-scene .film-stars,
.illus-sync-theater .film-stars { fill: var(--demo-stars) !important; }
.hero-demo-scene .film-clouds { fill: var(--demo-stars) !important; }
.hero-demo-scene .film-mist-scroll { fill: var(--demo-stars) !important; }
.hero-demo-scene .film-shooting-star { stroke: var(--demo-stars) !important; }
.hero-demo-scene .film-moon,
.illus-sync-theater .film-moon {
fill: var(--demo-moon) !important;
filter: drop-shadow(0 0 6px var(--demo-moon));
}
.hero-demo-scene .film-mtn-scroll,
.illus-sync-theater .film-mtn-scroll { fill: var(--demo-mountain) !important; }
.hero-demo-scene .film-mid-scroll > *,
.illus-sync-theater .film-mid-scroll > * { fill: var(--demo-midground) !important; }
.hero-demo-scene .film-fore-scroll > *,
.illus-sync-theater .film-fore-scroll > * { fill: var(--demo-foreground) !important; }
/* Stars: staggered twinkle so the sky feels alive */
.film-star {
transform-box: fill-box;
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); }
}
/* Moon: gentle glow pulse + slow arc drift. The drift lives on the wrapper
group so the craters travel with the disc; the glow stays on the circle.
(Step-3 uses a bare .film-moon without wrapper — filmMoon still covers it.) */
.film-moon-g {
transform-box: fill-box;
transform-origin: center;
animation: filmMoonDrift 6s ease-in-out infinite alternate;
animation-play-state: paused;
}
.film-moon-g .film-moon {
animation-name: filmMoonGlow;
}
@keyframes filmMoonDrift {
from { transform: translate(0, 0); }
to { transform: translate(-6px, 3px); }
}
@keyframes filmMoonGlow {
from { filter: drop-shadow(0 0 4px oklch(0.95 0.01 100 / 0.5)); }
to { filter: drop-shadow(0 0 10px oklch(0.95 0.01 100 / 0.95)); }
}
.film-moon {
transform-box: fill-box;
transform-origin: center;
animation: filmMoon 6s ease-in-out infinite alternate;
animation-play-state: paused;
}
@keyframes filmMoon {
from { transform: translate(0, 0); filter: drop-shadow(0 0 4px oklch(0.95 0.01 100 / 0.5)); }
to { transform: translate(-6px, 3px); filter: drop-shadow(0 0 10px oklch(0.95 0.01 100 / 0.95)); }
}
.film-mtn-scroll {
transform: translateX(var(--scroll-back, 0px));
}
.film-mid-scroll {
transform: translateX(var(--scroll-mid, 0px));
}
.film-fore-scroll {
transform: translateX(var(--scroll-fore, 0px));
}
/* Twinkle & Glow play state bindings */
.film-star {
transform-box: fill-box;
transform-origin: center;
animation: filmTwinkle 2.8s ease-in-out infinite;
animation-play-state: paused;
}
.demo-tab-card.playing :is(.film-star, .film-moon, .film-moon-g, .film-cloud, .film-shooting-star) {
animation-play-state: running;
}
/* Drifting clouds: gentle back-and-forth so there is no wrap pop */
.film-cloud {
transform-box: fill-box;
animation: filmCloudDrift 26s ease-in-out infinite alternate;
animation-play-state: paused;
}
.film-cloud-2 {
animation-duration: 34s;
animation-delay: -12s;
}
@keyframes filmCloudDrift {
from { transform: translateX(-6px); }
to { transform: translateX(10px); }
}
/* A shooting star streaks across the sky every few loops */
.film-shooting-star {
opacity: 0;
animation: filmShoot 11s linear infinite;
animation-play-state: paused;
}
@keyframes filmShoot {
0%, 87% { opacity: 0; transform: translate(0, 0); }
89% { opacity: 0.9; }
95%, 100% { opacity: 0; transform: translate(-46px, 20px); }
}
/* Valley mist rides the slow background parallax between tree layers */
.film-mist-scroll {
transform: translateX(var(--scroll-back, 0px));
}
/* Play button pulsing indicator at the end of the walkthrough */
.hero-demo-scene.demo-complete #demo-tab-a:not(.playing) .demo-icon-wrap {
animation: playButtonPulse 1.6s ease-in-out infinite;
border-color: oklch(0.68 0.13 150);
box-shadow: 0 0 15px oklch(0.68 0.13 150 / 0.8);
}
@keyframes playButtonPulse {
0%, 100% { transform: scale(1); box-shadow: 0 0 10px oklch(0.68 0.13 150 / 0.5); }
50% { transform: scale(1.12); box-shadow: 0 0 20px oklch(0.68 0.13 150 / 0.9); }
}
/* Seek-reset: scrubbing restarts animations from frame zero */
.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%,
oklch(0.75 0.13 150 / 0.35) 20%,
rgba(255, 255, 255, 0.55) 50%,
oklch(0.75 0.13 150 / 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;
transform: translateY(-4px);
pointer-events: none;
transition: background 0.3s, border-color 0.3s, color 0.3s, opacity 0.4s, transform 0.4s;
}
.hero-demo-scene.connected .demo-sync-chip {
opacity: 1;
transform: none;
pointer-events: auto;
}
/* Toast on the friend's window ("Room joined", "Tab selected") */
.demo-tab-toast {
position: absolute;
top: 36px;
left: 50%;
transform: translate(-50%, -6px);
z-index: 2;
padding: 4px 10px;
border-radius: 99px;
background: oklch(0.20 0.025 140 / 0.92);
border: 1px solid oklch(0.68 0.13 150 / 0.5);
color: oklch(0.85 0.07 150);
font-size: 9.5px;
font-weight: 700;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s, transform 0.3s;
}
.demo-tab-toast.show {
opacity: 1;
transform: translate(-50%, 0);
}
/* Invite link pill flying from the popup to the friend's window */
.demo-invite-fly {
position: absolute;
z-index: 30;
display: inline-flex;
align-items: center;
gap: 5px;
padding: 4px 10px;
border-radius: 99px;
background: var(--accent);
color: var(--text-on-green);
font-size: 9.5px;
font-weight: 700;
white-space: nowrap;
box-shadow: 0 6px 18px oklch(0.68 0.13 150 / 0.5);
opacity: 0;
pointer-events: none;
transition: left 0.75s cubic-bezier(0.3, 0.7, 0.4, 1), top 0.75s cubic-bezier(0.3, 0.7, 0.4, 1), opacity 0.3s;
}
/* Attention flash (e.g. on the video select while "choosing the tab") */
.demo-attn {
animation: demoAttn 0.7s ease-in-out 2;
}
@keyframes demoAttn {
50% { box-shadow: 0 0 0 3px oklch(0.68 0.13 150 / 0.75); }
}
/* --- Bento Card Host Control Mockup Additions --- */
.bento-content-wrap {
display: flex;
flex-direction: column;
gap: 1.2rem;
width: 100%;
}
.bento-host-control-mockup {
background: oklch(0.20 0.025 140 / 0.6);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 0.75rem 1rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
width: 100%;
box-sizing: border-box;
}
.bento-mockup-header {
font-size: 0.65rem;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-muted);
font-weight: 700;
}
.bento-mockup-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
font-size: 0.75rem;
color: white;
font-weight: 600;
margin-top: 2px;
}
/* Custom switch toggle representation */
.bento-switch-wrap {
position: relative;
display: inline-block;
width: 28px;
height: 16px;
flex-shrink: 0;
}
.bento-switch-wrap input {
opacity: 0;
width: 0;
height: 0;
}
.bento-switch-slider {
position: absolute;
cursor: default;
top: 0; left: 0; right: 0; bottom: 0;
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 16px;
transition: .3s;
}
.bento-switch-slider:before {
position: absolute;
content: "";
height: 10px;
width: 10px;
left: 2px;
bottom: 2px;
background-color: oklch(0.68 0.02 100);
border-radius: 50%;
transition: .3s;
}
.bento-switch-wrap input:checked + .bento-switch-slider {
background-color: oklch(0.68 0.13 150 / 0.25);
border-color: oklch(0.68 0.13 150 / 0.6);
box-shadow: 0 0 8px oklch(0.68 0.13 150 / 0.3);
}
.bento-switch-wrap input:checked + .bento-switch-slider:before {
transform: translateX(12px);
background-color: var(--accent);
box-shadow: 0 0 6px var(--accent-glow);
}
/* --- Step 2 & Step 3 Visual Redesign Styles --- */
/* Step 2 Browser video player mock */
.illus-video-player-mock {
width: 85%;
height: 65%;
background: linear-gradient(135deg, oklch(0.20 0.04 145), oklch(0.12 0.02 138));
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 8px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
margin-top: 15px;
}
.video-mock-play-button {
width: 32px;
height: 32px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 0.8rem;
cursor: default;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
}
.video-mock-timeline {
position: absolute;
bottom: 8px;
left: 8px;
right: 8px;
height: 3px;
background: rgba(255, 255, 255, 0.15);
border-radius: 2px;
}
.video-mock-timeline-fill {
width: 35%;
height: 100%;
background: var(--accent);
border-radius: 2px;
}
/* Step 2 extension popup dropdown alignment */
.illus-extension-popup.drop-down {
top: 2.2rem;
right: 0.6rem;
width: 145px;
animation: popup-dropdown-float 4s ease-in-out infinite;
}
@keyframes popup-dropdown-float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-3px); }
}
.status-badge-select {
background: oklch(0.68 0.13 150 / 0.12);
color: oklch(0.85 0.07 150);
font-size: 0.58rem;
font-weight: 700;
padding: 2px 6px;
border-radius: 4px;
border: 1px solid oklch(0.68 0.13 150 / 0.2);
display: inline-flex;
align-items: center;
text-transform: uppercase;
letter-spacing: 0.2px;
}
.popup-form-group {
margin-top: 6px;
width: 100%;
text-align: left;
}
.popup-form-label {
display: block;
font-size: 0.6rem;
color: var(--text-muted);
margin-bottom: 4px;
font-weight: 700;
}
.popup-select-wrapper {
position: relative;
width: 100%;
}
.popup-select-mock {
width: 100%;
background: var(--card);
border: 1px solid rgba(255, 255, 255, 0.12);
color: white;
padding: 6px;
border-radius: 6px;
font-family: inherit;
font-size: 0.62rem;
outline: none;
appearance: none;
-webkit-appearance: none;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: default;
display: block;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
}
.popup-cursor-pointer {
position: absolute;
bottom: -15px;
right: 15px;
font-size: 1.1rem;
pointer-events: none;
z-index: 10;
/* Static hand — the looping tap bob was the busiest part of step 2 and
distracted from the copy (step 3 keeps its lively animation). */
}
/* Step 3 forest movie continuous animation bindings */
.step-illustration-3 .film-mtn-scroll {
animation: scrollBack 12s linear infinite !important;
}
.step-illustration-3 .film-mid-scroll {
animation: scrollMid 6s linear infinite !important;
}
.step-illustration-3 .film-fore-scroll {
animation: scrollFore 3s linear infinite !important;
}
@media (prefers-reduced-motion: reduce) {
.step-illustration-3 .film-mtn-scroll,
.step-illustration-3 .film-mid-scroll,
.step-illustration-3 .film-fore-scroll {
animation: none !important;
}
}
@keyframes scrollBack {
0% { transform: translateX(0); }
100% { transform: translateX(-160px); }
}
@keyframes scrollMid {
0% { transform: translateX(0); }
100% { transform: translateX(-160px); }
}
@keyframes scrollFore {
0% { transform: translateX(0); }
100% { transform: translateX(-160px); }
}
/* --- High Fidelity Micro-Animations & Identity additions --- */
/* Scroll progress bar glowing line at the top */
.scroll-progress-bar {
position: fixed;
top: 0;
left: 0;
height: 3px;
background: linear-gradient(90deg, var(--accent), oklch(0.62 0.14 45), oklch(0.62 0.14 45));
z-index: 9999;
width: 0%;
transition: width 0.1s ease-out;
box-shadow: 0 0 8px var(--accent-glow);
}
/* Navigation logo pop & spin */
.nav-logo-img {
animation: logo-entrance 1.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
transform-origin: center;
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
will-change: transform, opacity;
}
.nav-logo-img:hover {
transform: scale(1.15) rotate(360deg);
}
@keyframes logo-entrance {
0% {
transform: scale(0) rotate(-180deg);
opacity: 0;
}
100% {
transform: scale(1) rotate(0deg);
opacity: 1;
}
}
/* Glowing reflection sweep on buttons */
.btn-primary, .btn-firefox, .btn-secondary {
position: relative;
overflow: hidden;
}
.btn-primary::after, .btn-firefox::after, .btn-secondary::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0%,
rgba(255, 255, 255, 0.25) 50%,
rgba(255, 255, 255, 0) 100%
);
transform: skewX(-25deg);
transition: none;
pointer-events: none;
}
.btn-primary:hover::after, .btn-firefox:hover::after, .btn-secondary:hover::after {
left: 100%;
transition: left 0.8s ease-in-out;
}
/* Step 2 mockup control panel styles */
.popup-mock-controls {
display: flex;
gap: 8px;
margin-top: 4px;
width: 100%;
}
.popup-mock-btn {
flex: 1;
text-align: center;
padding: 6px;
border-radius: 6px;
font-size: 0.62rem;
font-weight: 700;
color: white;
cursor: default;
opacity: 0.75;
}
.popup-mock-btn.play {
background: oklch(0.68 0.13 150);
color: var(--text-on-green);
}
.popup-mock-btn.pause {
background: oklch(0.55 0.15 25);
}
/* Phone and portrait-tablet widths: keep the full hero demo out of the page
flow. The demo modal mounts the same node in its own fixed layer. */
@media (max-width: 900px) {
.hero-grid > .hero-mockup-wrapper {
display: none !important;
}
}
@media (max-width: 900px) {
.hero-github-cta {
display: none;
}
.btn-demo-mobile {
display: inline-flex;
}
}
body.mobile-demo-open {
overflow: hidden;
}
.mobile-demo-modal[hidden] {
display: none;
}
.mobile-demo-modal {
position: fixed;
inset: 0;
z-index: 2400;
display: flex;
flex-direction: column;
padding: 0 !important;
}
.mobile-demo-backdrop {
position: absolute;
inset: 0;
background: oklch(0.10 0.01 135 / 0.25);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
}
.mobile-demo-panel {
position: relative;
z-index: 1;
width: 100% !important;
height: 100% !important;
max-height: none !important;
display: flex;
flex-direction: column;
overflow: hidden;
background: transparent !important;
backdrop-filter: none !important;
-webkit-backdrop-filter: none !important;
border: none !important;
border-radius: 0 !important;
box-shadow: none !important;
}
.mobile-demo-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
padding: 0.85rem 0.95rem;
border-bottom: none !important;
flex-shrink: 0;
}
.mobile-demo-header h2 {
margin: 0;
font-size: 0.95rem;
line-height: 1.2;
color: oklch(0.96 0.01 90);
}
.mobile-demo-close {
display: inline-flex;
align-items: center;
justify-content: center;
width: 38px;
height: 38px;
padding: 0;
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 10px;
background: oklch(0.27 0.035 130 / 0.72);
color: oklch(0.88 0.015 90);
cursor: pointer;
flex-shrink: 0;
}
.mobile-demo-stage {
position: relative;
flex: 1;
min-height: 0;
overflow: hidden !important;
padding: 1rem 0.75rem 1.25rem;
overscroll-behavior: contain;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
}
/* Ensure the demo scene canvas is transparent inside the modal to let the glass backdrop blend */
.mobile-demo-stage .hero-demo-scene {
background: transparent !important;
border: none !important;
box-shadow: none !important;
}
/* Ensure the close button hover stays consistent in dark glass theme */
.mobile-demo-close:hover {
background: rgba(51, 65, 85, 0.85) !important;
}
/* Light Mode Frosted Glass overrides */
html.theme-light .mobile-demo-backdrop {
background: oklch(0.95 0.01 100 / 0.2) !important;
}
html.theme-light .mobile-demo-panel {
background: transparent !important;
border: none !important;
box-shadow: none !important;
}
html.theme-light .mobile-demo-header {
border-bottom: none !important;
}
html.theme-light .mobile-demo-header h2 {
color: var(--text) !important;
}
html.theme-light .mobile-demo-close {
background: rgba(255, 255, 255, 0.4) !important;
border-color: oklch(0.20 0.025 140 / 0.1) !important;
color: var(--text) !important;
}
html.theme-light .mobile-demo-close:hover {
background: rgba(255, 255, 255, 0.75) !important;
}
.mobile-demo-stage .hero-mockup-wrapper {
display: flex !important;
position: relative;
width: min(100%, 560px);
margin: 0 auto;
will-change: transform;
}
/* Mobile S / short screens */
@media (max-height: 600px) {
.mobile-demo-stage .hero-mockup-wrapper {
transform: scale(0.68) !important;
transform-origin: top center !important;
height: 380px !important;
}
}
/* Mobile M/L / medium screens */
@media (min-height: 601px) and (max-height: 740px) {
.mobile-demo-stage .hero-mockup-wrapper {
transform: scale(0.82) !important;
transform-origin: top center !important;
height: 460px !important;
}
}
/* Default / tall screens */
@media (min-height: 741px) {
.mobile-demo-stage .hero-mockup-wrapper {
transform: scale(1) !important;
transform-origin: top center !important;
height: 550px !important;
}
}
.mobile-demo-stage .hero-demo-scene,
.mobile-demo-stage .hero-demo-scene.popup-open {
position: relative;
width: 100%;
height: 100% !important;
max-width: none;
margin: 0 auto;
}
.mobile-demo-stage .demo-tab-stack {
display: block !important;
position: static !important;
height: auto !important;
}
.mobile-demo-stage .demo-tab-card {
display: block !important;
}
.mobile-demo-stage .demo-sync-chip {
display: inline-flex !important;
}
.mobile-demo-stage .demo-cursor {
display: block !important;
}
.mobile-demo-stage .demo-hint {
display: block !important;
position: absolute !important;
left: 0 !important;
right: 0 !important;
top: auto !important;
bottom: 12px !important;
margin: 0 auto !important;
padding-inline: 1rem;
max-width: 90%;
z-index: 10;
}
.mobile-demo-stage .hero-demo-scene .extension-mockup {
position: absolute;
bottom: 0 !important;
right: 0;
z-index: 15 !important;
width: min(320px, 66cqw);
transform: none !important;
transform-origin: top right !important;
transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.35s, visibility 0.45s;
}
.mobile-demo-stage .hero-demo-scene:not(.popup-open) .extension-mockup {
bottom: 0 !important;
transform: translate(2%, -3%) scale(0.5) !important;
opacity: 0;
visibility: hidden;
pointer-events: none;
}
@media (max-width: 380px) {
.mobile-demo-modal {
padding: 0 !important;
}
.mobile-demo-stage {
padding-inline: 0.45rem !important;
}
}
/* Performance optimization for off-screen sections (below the fold) */
.lazy-section {
content-visibility: auto;
}
.use-cases-section {
contain-intrinsic-block-size: auto 600px;
}
.comparison-section {
contain-intrinsic-block-size: auto 800px;
}
#self-hosting {
contain-intrinsic-block-size: auto 400px;
}
#faq {
contain-intrinsic-block-size: auto 450px;
}
@media (max-width: 768px) {
.use-cases-section {
contain-intrinsic-block-size: auto 900px;
}
.comparison-section {
contain-intrinsic-block-size: auto 1100px;
}
#self-hosting {
contain-intrinsic-block-size: auto 550px;
}
#faq {
contain-intrinsic-block-size: auto 700px;
}
}
/* Final responsive hierarchy overrides. Keep these last: the landing page has
several component-level media blocks above that intentionally own geometry. */
@media (max-width: 768px) {
.container {
padding-inline: 1.15rem;
}
section {
padding-block: 4.25rem;
}
.hero-text h1,
.section-title,
#how-it-works h2,
#self-hosting h2,
#faq h2 {
font-size: clamp(2rem, 9vw, 2.65rem) !important;
text-wrap: balance;
}
.cta-group {
display: grid;
grid-template-columns: 1fr 1fr;
align-items: stretch;
width: 100%;
}
.cta-group .btn {
width: 100%;
min-height: 48px;
justify-content: center;
}
}
@media (max-width: 430px) {
.cta-group {
grid-template-columns: 1fr;
}
}