diff --git a/frontend/src/app/globals.css b/frontend/src/app/globals.css
index eaf6a7a..547da3c 100644
--- a/frontend/src/app/globals.css
+++ b/frontend/src/app/globals.css
@@ -193,8 +193,17 @@ html.lenis body {
@keyframes abrbanShimmer {
to { background-position: 200% center; }
}
+/* Gentle horizontal sway for the auth-screen clouds (see AuthSky). */
+@keyframes abrbanCloudDrift {
+ from { transform: translateX(calc(var(--drift, 6vw) * -1)); }
+ to { transform: translateX(var(--drift, 6vw)); }
+}
.abrban-float { animation: abrbanFloat 6s ease-in-out infinite; }
.abrban-scroll-hint { animation: abrbanScrollHint 1.8s ease-in-out infinite; }
+.abrban-cloud-drift {
+ animation: abrbanCloudDrift var(--drift-dur, 40s) ease-in-out infinite alternate;
+ animation-delay: var(--drift-delay, 0s);
+}
.abrban-shimmer {
background: linear-gradient(100deg, #93c5fd 0%, #ffffff 25%, #2563eb 50%, #ffffff 75%, #93c5fd 100%);
background-size: 200% auto;
@@ -223,7 +232,8 @@ html.lenis body {
@media (prefers-reduced-motion: reduce) {
.abrban-float,
.abrban-scroll-hint,
- .abrban-shimmer {
+ .abrban-shimmer,
+ .abrban-cloud-drift {
animation: none;
}
}
diff --git a/frontend/src/components/auth/AuthShell.tsx b/frontend/src/components/auth/AuthShell.tsx
index 2c9e409..8f16a34 100644
--- a/frontend/src/components/auth/AuthShell.tsx
+++ b/frontend/src/components/auth/AuthShell.tsx
@@ -5,11 +5,12 @@ import { Link } from '@/i18n/Link';
import { useT } from '@/i18n/I18nProvider';
import { LanguageSwitcher } from '@/i18n/LanguageSwitcher';
import { Logo } from '@/components/landing/Logo';
+import { AuthSky } from './AuthSky';
-// Auth shell that carries the Abrban brand into a calmer, more premium key: a
-// deep blue gradient, a faint infrastructure grid, soft brand-blue glows and a
-// vignette — no fluffy clouds — with the form inside the same frosted dark-glass
-// panel used across the landing. Direction is inherited from the root layout.
+// Auth shell that carries the Abrban brand straight from the landing: the same
+// bright, cloud-filled sky (see AuthSky) sits behind the form, which lives in the
+// same frosted dark-glass panel — so login/register read as one world with the
+// public landing. Direction is inherited from the root layout.
export function AuthShell({
title,
subtitle,
@@ -27,21 +28,9 @@ export function AuthShell({
}) {
const t = useT();
return (
-
- {/* Background atmosphere */}
-
- {/* Deep brand gradient */}
-
- {/* Fine infrastructure grid, faded toward the edges */}
-
- {/* Soft brand-blue glows */}
-
-
- {/* Crisp hairline along the very top */}
-
- {/* Vignette to focus the centre */}
-
-
+
+ {/* Bright cloud-filled sky backdrop, shared with the landing */}
+
{/* Header */}
diff --git a/frontend/src/components/auth/AuthSky.tsx b/frontend/src/components/auth/AuthSky.tsx
new file mode 100644
index 0000000..7478e41
--- /dev/null
+++ b/frontend/src/components/auth/AuthSky.tsx
@@ -0,0 +1,97 @@
+'use client';
+
+import type { CSSProperties } from 'react';
+
+// A calm, lightweight echo of the landing's cinematic sky — the same pale-blue
+// gradient (weather stop 0) and the very same vendored cloud puff (/cloud.png),
+// but as cheap drifting CSS sprites instead of the full WebGL scene. It keeps the
+// auth screens visually tied to the landing ("ابر" floating behind the form)
+// without pulling three.js onto the login/register routes.
+
+// Each cloud is a small cluster of overlapping puffs so the silhouette reads as a
+// soft fluffy cloud rather than a single blob. Offsets are relative to the
+// cluster's own box (percent of its width).
+const PUFFS = [
+ { l: '0%', t: '32%', w: '52%' },
+ { l: '20%', t: '6%', w: '62%' },
+ { l: '46%', t: '24%', w: '56%' },
+ { l: '28%', t: '40%', w: '66%' },
+];
+
+type CloudSpec = {
+ // Anchor: provide either left/right and either top/bottom.
+ left?: string;
+ right?: string;
+ top?: string;
+ bottom?: string;
+ width: string; // cluster width
+ opacity: number;
+ blur: number; // px
+ drift: string; // horizontal sway amplitude
+ dur: string; // drift duration
+ delay: string; // negative to desync
+};
+
+const CLOUDS: CloudSpec[] = [
+ { top: '6%', left: '-8%', width: '30rem', opacity: 0.92, blur: 1, drift: '7vw', dur: '34s', delay: '0s' },
+ { top: '18%', right: '-10%', width: '36rem', opacity: 0.8, blur: 2, drift: '6vw', dur: '42s', delay: '-7s' },
+ { top: '50%', left: '2%', width: '24rem', opacity: 0.5, blur: 3, drift: '5vw', dur: '38s', delay: '-14s' },
+ { top: '62%', right: '0%', width: '30rem', opacity: 0.58, blur: 3, drift: '8vw', dur: '46s', delay: '-4s' },
+ { bottom: '-6%', left: '18%', width: '38rem', opacity: 0.72, blur: 4, drift: '5vw', dur: '52s', delay: '-22s' },
+];
+
+function Cloud({ spec }: { spec: CloudSpec }) {
+ const driftVars = {
+ '--drift': spec.drift,
+ '--drift-dur': spec.dur,
+ '--drift-delay': spec.delay,
+ } as CSSProperties;
+
+ return (
+
+
+
+ {PUFFS.map((p, i) => (
+
+ ))}
+
+
+
+ );
+}
+
+export function AuthSky() {
+ return (
+
+ {/* Bright sky gradient — landing weather stop 0 (calm, bright overcast). */}
+
+ {/* Soft warm sun glow, high and centred, like the landing's hidden sun. */}
+
+ {/* Drifting clouds. */}
+ {CLOUDS.map((spec, i) => (
+
+ ))}
+ {/* Low fog haze so the bottom melts into the sky like the landing. */}
+
+ {/* Crisp hairline along the very top. */}
+
+ {/* Vignette to focus the centre — matches LandingPage. */}
+
+
+ );
+}