From 306f90a21c2a163d1db52dd77f26fa2934b26cc4 Mon Sep 17 00:00:00 2001 From: oliver Date: Tue, 4 Aug 2026 09:08:44 +0800 Subject: [PATCH] Refine login layout with left earth stage and natural sunlight. Move the globe beside the form, drop the orbit ring, and soften a blue atmospheric limb that fades into space. Co-authored-by: Cursor --- web/src/index.css | 250 +++++++++++++++++++++++++---------- web/src/pages/LoginShell.tsx | 6 +- 2 files changed, 180 insertions(+), 76 deletions(-) diff --git a/web/src/index.css b/web/src/index.css index 11be147..5f68853 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -6761,13 +6761,14 @@ pre { --login-field: rgba(255, 255, 255, 0.08); --login-field-border: rgba(255, 255, 255, 0.14); --login-danger: #fda29b; + --login-rail-w: clamp(360px, 30vw, 420px); position: relative; isolation: isolate; min-height: 100vh; overflow: hidden; - display: flex; - align-items: center; - justify-content: center; + display: grid; + grid-template-columns: minmax(0, 1fr) var(--login-rail-w); + align-items: stretch; background: #00050a; font-family: "IBM Plex Sans", "Segoe UI", sans-serif; color: var(--login-ink); @@ -6779,10 +6780,10 @@ pre { z-index: 1; display: flex; align-items: center; + /* Center earth within the left stage (not under the form rail). */ justify-content: center; - background: - linear-gradient(rgba(0, 0, 0, 0.58), rgba(0, 0, 0, 0.42)), - url("/login-space.webp") center / cover no-repeat; + padding: 3vh calc(var(--login-rail-w) + 3vw) 3vh 5vw; + background: url("/login-space.webp") center / cover no-repeat; } .login-page__space::before { @@ -6792,44 +6793,105 @@ pre { z-index: 2; pointer-events: none; background: - linear-gradient(transparent 0%, rgba(0, 0, 0, 0.32) 100%), - linear-gradient(transparent 50%, rgba(0, 0, 0, 0.68) 100%); + linear-gradient( + 90deg, + transparent 0%, + transparent 52%, + rgba(0, 5, 12, 0.28) 70%, + rgba(0, 5, 12, 0.68) 88%, + rgba(0, 5, 12, 0.88) 100% + ), + linear-gradient(180deg, rgba(0, 0, 0, 0.1) 0%, transparent 30%, transparent 72%, rgba(0, 0, 0, 0.38) 100%); +} + +/* Distant sun — upper-left, feeds the lit limb. */ +.login-page__sun { + position: absolute; + z-index: 0; + top: -2%; + left: -4%; + width: min(520px, 42vw); + height: min(520px, 42vw); + border-radius: 50%; + pointer-events: none; + background: radial-gradient( + circle at 55% 55%, + rgba(160, 205, 255, 0.26) 0%, + rgba(90, 150, 240, 0.12) 32%, + rgba(50, 110, 210, 0.04) 55%, + transparent 72% + ); + filter: blur(8px); } .login-planet { - position: absolute; + position: relative; z-index: 1; - width: 520px; - height: 520px; + width: min(500px, 38vw, 62vmin); + height: min(500px, 38vw, 62vmin); border-radius: 50%; - transform: scale(2.5) translateY(38%) rotate(12.2deg); + transform: rotate(5deg); animation: login-planet-enter 1.8s cubic-bezier(0.76, -0.46, 0.37, 0.99) both; } -.login-planet__railway { +/* Soft blue atmosphere outside the clipped ball — fades into space. */ +.login-planet::after { + content: ""; position: absolute; - top: -40px; - left: -40px; - width: calc(100% + 80px); - height: calc(100% + 80px); + z-index: 0; + inset: -10%; border-radius: 50%; - border: 0.5px dashed rgba(255, 255, 255, 0.48); - animation: login-railway-rotate 40s linear infinite; pointer-events: none; + background: radial-gradient( + 120% 105% at 28% 24%, + transparent 48%, + rgba(40, 100, 210, 0.38) 64%, + rgba(55, 125, 230, 0.18) 74%, + transparent 86% + ); + filter: blur(10px); } .login-planet__earth { position: relative; + z-index: 1; width: 100%; height: 100%; border-radius: 50%; overflow: hidden; + /* Feather the limb into space — no hard circular cut. */ + -webkit-mask-image: radial-gradient(circle at 50% 50%, #000 86%, transparent 100%); + mask-image: radial-gradient(circle at 50% 50%, #000 86%, transparent 100%); box-shadow: - 0 0 8px rgba(150, 186, 255, 0.48), - 0 0 60px 12px rgba(150, 186, 255, 0.32); + -16px -18px 40px 8px rgba(60, 130, 230, 0.35), + -6px -8px 16px 2px rgba(80, 150, 240, 0.22); transform-origin: center center; } +/* Surface light falloff: bright TL → soft mid → deeper BR. */ +.login-planet__earth::before { + content: ""; + position: absolute; + z-index: 1; + inset: 0; + border-radius: 50%; + pointer-events: none; + background: linear-gradient( + 148deg, + rgba(120, 175, 255, 0.22) 0%, + rgba(70, 130, 220, 0.1) 18%, + rgba(40, 90, 180, 0.04) 34%, + transparent 48%, + rgba(0, 12, 36, 0.16) 68%, + rgba(0, 8, 24, 0.36) 86%, + rgba(0, 4, 16, 0.5) 100% + ); +} + +/* + * Blue atmosphere crescent on the sun limb + soft edge wash that + * dissolves with the feathered mask. + */ .login-planet__earth::after { content: ""; position: absolute; @@ -6837,51 +6899,71 @@ pre { inset: 0; border-radius: 50%; pointer-events: none; + background: + radial-gradient( + 130% 100% at 6% 10%, + rgba(90, 160, 255, 0.62) 0%, + rgba(50, 120, 230, 0.36) 24%, + rgba(30, 90, 200, 0.12) 46%, + transparent 64% + ), + radial-gradient( + circle at 50% 50%, + transparent 72%, + rgba(40, 105, 215, 0.16) 86%, + rgba(55, 130, 235, 0.32) 93%, + rgba(70, 150, 245, 0.12) 98%, + transparent 100% + ); box-shadow: - inset 0 0 8px 4px rgba(59, 104, 196, 0.98), - inset -24px 0 12px 2px rgba(59, 104, 196, 0.08), - inset 0 0 48px 48px rgba(59, 104, 196, 0.28), - inset -48px 0 24px 48px rgba(59, 104, 196, 0.08); - animation: login-earth-inner 1.8s ease-in-out 0.9s both; + inset 28px 32px 36px 4px rgba(70, 140, 235, 0.16), + inset -22px -26px 48px 12px rgba(0, 6, 20, 0.28); + animation: login-earth-inner 2.2s ease-in-out 0.7s both; } .login-planet__textures { position: absolute; - top: 0; - left: 0; - width: 200%; + inset: 0; + width: 100%; height: 100%; - background-color: rgba(0, 18, 77, 0.18); + background-color: rgba(8, 28, 72, 0.2); background-image: url("/login-earth-night.webp"); - background-size: 50% 100%; background-repeat: repeat-x; - filter: brightness(2.4) contrast(1.2); - animation: login-earth-spin 60s linear infinite; - will-change: transform; - transform: translate3d(0, 0, 0); + background-size: 200%; + /* Softer map — less crunchy, blends into the limb fade. */ + filter: brightness(2.45) contrast(1.02) saturate(1.08); + animation: login-earth-spin 80s linear infinite; + will-change: background-position; } -.login-page__content { +.login-page__rail { position: relative; z-index: 3; - width: min(400px, calc(100% - 40px)); - padding: 24px 0; + grid-column: 2; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + min-width: 0; + padding: 48px clamp(32px, 3.5vw, 52px) 48px 8px; } .login-card { width: 100%; + max-width: 340px; display: flex; flex-direction: column; - gap: 14px; - padding: 20px 20px 22px; - border-radius: 14px; - border: 1px solid rgba(255, 255, 255, 0.08); - background: rgba(8, 16, 32, 0.22); - backdrop-filter: blur(8px) saturate(1.08); - -webkit-backdrop-filter: blur(8px) saturate(1.08); + gap: 15px; + padding: 26px 24px 28px; + border-radius: 16px; + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(8, 16, 32, 0.58); + backdrop-filter: blur(16px) saturate(1.12); + -webkit-backdrop-filter: blur(16px) saturate(1.12); box-shadow: - 0 8px 28px rgba(0, 0, 0, 0.18), - inset 0 1px 0 rgba(255, 255, 255, 0.05); + 0 18px 48px rgba(0, 0, 0, 0.32), + 0 0 0 1px rgba(120, 170, 255, 0.07), + inset 0 1px 0 rgba(255, 255, 255, 0.07); animation: login-card-in 520ms cubic-bezier(0.22, 1, 0.36, 1) both; } @@ -7071,42 +7153,30 @@ pre { @keyframes login-planet-enter { 0% { - transform: scale(1) translateY(0) rotate(-12.2deg); + transform: scale(0.92) rotate(-5deg); + opacity: 0.65; } -} - -@keyframes login-railway-rotate { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); + 100% { + transform: rotate(5deg); + opacity: 1; } } @keyframes login-earth-spin { from { - transform: translate3d(0, 0, 0); + background-position: calc(120% + 120px) 0; } to { - transform: translate3d(-50%, 0, 0); + background-position: calc(-80% + 120px) 0; } } @keyframes login-earth-inner { 0% { - box-shadow: - inset 0 0 8px 4px rgba(59, 104, 196, 0.98), - inset -24px 0 12px 2px rgba(59, 104, 196, 0.08), - inset 0 0 48px 48px rgba(59, 104, 196, 0.28), - inset -48px 0 24px 48px rgba(59, 104, 196, 0.08); + opacity: 0.55; } 100% { - box-shadow: - inset 0 0 8px 4px rgba(59, 104, 196, 0.98), - inset 24px 0 12px 2px rgba(59, 104, 196, 0.58), - inset 0 8px 48px 48px rgba(59, 104, 196, 0.28), - inset 48px 0 24px 48px rgba(59, 104, 196, 0.28); + opacity: 1; } } @@ -7146,7 +7216,7 @@ pre { } @media (prefers-reduced-motion: reduce) { - /* Keep ambient earth / orbit motion; only drop entrance flourishes. */ + /* Keep ambient earth spin; only drop entrance flourishes. */ .login-planet, .login-planet__earth::after, .login-card, @@ -7156,7 +7226,7 @@ pre { } .login-planet { - transform: scale(2.5) translateY(38%) rotate(12.2deg); + transform: rotate(5deg); } .login-card__submit:hover:not(:disabled) { @@ -7164,13 +7234,47 @@ pre { } } -@media (max-width: 480px) { +@media (max-width: 1200px) { + .login-page { + --login-rail-w: clamp(340px, 34vw, 400px); + } + .login-planet { - transform: scale(1.5) translateY(28%) rotate(12.2deg); + width: min(440px, 40vw, 58vmin); + height: min(440px, 40vw, 58vmin); + } +} + +@media (max-width: 820px) { + .login-page { + grid-template-columns: 1fr; + } + + .login-page__space { + justify-content: center; + padding: 0; + } + + .login-page__space::before { + background: + linear-gradient(180deg, rgba(0, 0, 0, 0.18) 0%, transparent 30%, transparent 48%, rgba(0, 0, 0, 0.72) 100%); + } + + .login-planet { + width: min(420px, 78vmin); + height: min(420px, 78vmin); + opacity: 0.9; + } + + .login-page__rail { + grid-column: 1; + min-height: 100vh; + padding: 28px 18px 36px; } .login-card { - padding: 18px 16px 20px; + max-width: 380px; + padding: 20px 18px 22px; } .login-card__brand, diff --git a/web/src/pages/LoginShell.tsx b/web/src/pages/LoginShell.tsx index f367700..fdd2136 100644 --- a/web/src/pages/LoginShell.tsx +++ b/web/src/pages/LoginShell.tsx @@ -1,18 +1,18 @@ import type { ReactNode } from "react"; -/** Auth shell modeled after CuteCloud login: space BG + rotating night-earth + centered form. */ +/** Auth shell: night-earth stage on the left, form rail on the right. */ export function LoginShell({ children }: { children: ReactNode }) { return (