diff --git a/package.json b/package.json index 83bb999..539da78 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "sociowire-frontend", "private": true, - "version": "0.0.75", + "version": "0.0.87", "type": "module", "scripts": { "dev": "vite --host 0.0.0.0", diff --git a/src/api/client.js b/src/api/client.js index 7dd3ac2..7b8794a 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -821,7 +821,7 @@ export async function createPostComment(postId, body) { body: JSON.stringify({ post_id: postId, body }), }); const data = await res.json().catch(() => ({})); - return { ok: res.ok, ...data }; + return { ...data, ok: res.ok }; } catch { return { ok: false }; } diff --git a/src/components/Layout/TopBar.jsx b/src/components/Layout/TopBar.jsx index f2e8dd8..4d7076b 100644 --- a/src/components/Layout/TopBar.jsx +++ b/src/components/Layout/TopBar.jsx @@ -57,7 +57,7 @@ function parseMergedParams() { return { qs, hs, get, hash }; } -export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, onUserIsland }) { +export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, onUserIsland, onSearch, onMyLocation }) { const { t, i18n } = useTranslation(); const { loading, @@ -79,45 +79,23 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, } = useAuth(); const [showLangMenu, setShowLangMenu] = useState(false); - const [langMenuPos, setLangMenuPos] = useState({ top: 0, right: 0 }); - const langBtnRef = useRef(null); - const [showThemeMenu, setShowThemeMenu] = useState(false); - const [themeMenuPos, setThemeMenuPos] = useState({ top: 0, right: 0 }); + const [showUserMenu, setShowUserMenu] = useState(false); + const langBtnRef = useRef(null); const themeBtnRef = useRef(null); + const userMenuRef = useRef(null); + + const [searchQuery, setSearchQuery] = useState(""); + const [searchFocused, setSearchFocused] = useState(false); const changeLanguage = (lang) => { i18n.changeLanguage(lang); setShowLangMenu(false); }; - const toggleLangMenu = () => { - if (!showLangMenu && langBtnRef.current) { - const rect = langBtnRef.current.getBoundingClientRect(); - setLangMenuPos({ - top: rect.bottom + 6, - right: window.innerWidth - rect.right, - }); - } - setShowLangMenu(!showLangMenu); - setShowThemeMenu(false); - }; - - const toggleThemeMenu = () => { - if (!showThemeMenu && themeBtnRef.current) { - const rect = themeBtnRef.current.getBoundingClientRect(); - setThemeMenuPos({ - top: rect.bottom + 6, - right: window.innerWidth - rect.right, - }); - } - setShowThemeMenu(!showThemeMenu); - setShowLangMenu(false); - }; - - // Close lang/theme menu when clicking outside + // Close menus when clicking outside useEffect(() => { - if (!showLangMenu && !showThemeMenu) return; + if (!showLangMenu && !showThemeMenu && !showUserMenu) return; const handleClick = (e) => { if (showLangMenu && langBtnRef.current && !langBtnRef.current.contains(e.target)) { setShowLangMenu(false); @@ -125,10 +103,13 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, if (showThemeMenu && themeBtnRef.current && !themeBtnRef.current.contains(e.target)) { setShowThemeMenu(false); } + if (showUserMenu && userMenuRef.current && !userMenuRef.current.contains(e.target)) { + setShowUserMenu(false); + } }; document.addEventListener("click", handleClick); return () => document.removeEventListener("click", handleClick); - }, [showLangMenu, showThemeMenu]); + }, [showLangMenu, showThemeMenu, showUserMenu]); const [showAuth, setShowAuth] = useState(false); const [mode, setMode] = useState("login"); @@ -140,14 +121,13 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, const [usernameInfo, setUsernameInfo] = useState(""); const [usernameSaving, setUsernameSaving] = useState(false); const usernamePromptTimer = useRef(null); - const invalidSinceRef = useRef(null); const [stableUsername, setStableUsername] = useState(""); const displayUsername = (() => { const raw = (stableUsername || username || "user").toString(); if (!stableUsername && raw.includes("@")) return "user"; - if (raw.length <= 9) return raw; - return raw.slice(0, 9) + ".."; + if (raw.length <= 12) return raw; + return raw.slice(0, 12) + ".."; })(); const [loginUser, setLoginUser] = useState(""); @@ -229,16 +209,13 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, const loadRequests = async () => { try { const res = await fetchFriendRequests(); - // Only count received requests (not sent ones) const received = (res?.requests || []).filter(r => r?.direction === 'received'); setPendingRequestsCount(received.length); } catch (err) { - console.error('[TopBar] Error fetching friend requests:', err); setPendingRequestsCount(0); } }; loadRequests(); - // Refresh every 30 seconds const interval = setInterval(loadRequests, 30000); return () => clearInterval(interval); }, [authenticated]); @@ -303,9 +280,7 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, useEffect(() => { const handler = (e) => { const detail = e?.detail || {}; - const msg = - (detail.message || "").toString().trim() || - t('auth.pleaseSignIn'); + const msg = (detail.message || "").toString().trim() || t('auth.pleaseSignIn'); setAuthNotice(msg); setMode(detail.mode === "signup" ? "signup" : "login"); setShowAuth(true); @@ -314,27 +289,19 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, return () => window.removeEventListener("sociowire:auth-required", handler); }, []); - // Check if PWA install should be shown (simple: hide if already PWA) + // Check if PWA install should be shown useEffect(() => { const checkInstall = () => { - // Hide if already running as PWA if (isRunningAsPWA()) { setShowInstallBtn(false); return; } - // Show if can install setShowInstallBtn(canInstall()); }; - checkInstall(); - - const handlePrompt = () => { - setTimeout(checkInstall, 100); - }; - + const handlePrompt = () => setTimeout(checkInstall, 100); window.addEventListener('beforeinstallprompt', handlePrompt); window.addEventListener('appinstalled', () => setShowInstallBtn(false)); - return () => { window.removeEventListener('beforeinstallprompt', handlePrompt); window.removeEventListener('appinstalled', () => setShowInstallBtn(false)); @@ -344,28 +311,11 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, useEffect(() => { try { const { get, qs, hs, hash } = parseMergedParams(); - - const verified = - get("verified") || - get("validated") || - get("email_verified") || - get("emailVerified") || - get("kc_verified"); - + const verified = get("verified") || get("validated") || get("email_verified") || get("emailVerified") || get("kc_verified"); const signup = get("signup"); const notice = get("notice"); - - const email = - get("email") || - get("user_email") || - get("mail"); - - const uname = - get("username") || - get("user") || - get("preferred_username") || - get("login"); - + const email = get("email") || get("user_email") || get("mail"); + const uname = get("username") || get("user") || get("preferred_username") || get("login"); const last = readLastSignup(); if (truthyParam(verified)) { @@ -373,11 +323,9 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, setSignupInfo("✅ " + t('auth.emailConfirmedMsg') + (who ? " (" + who + ")" : "")); setMode("login"); setShowAuth(true); - const prefill = (uname || email || last?.username || last?.email || "").trim(); if (prefill) setLoginUser(prefill); } else if (truthyParam(signup)) { - // Open FRESH signup form - clear all old data try { localStorage.removeItem(LAST_SIGNUP_KEY); } catch {} setSignupInfo(""); setSignupError(""); @@ -394,8 +342,7 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, } } - const touched = - qs.has("verified") || qs.has("validated") || qs.has("email_verified") || qs.has("emailVerified") || qs.has("signup") || qs.has("notice") || + const touched = qs.has("verified") || qs.has("validated") || qs.has("email_verified") || qs.has("emailVerified") || qs.has("signup") || qs.has("notice") || hs.has("verified") || hs.has("validated") || hs.has("email_verified") || hs.has("emailVerified") || hs.has("signup") || hs.has("notice"); if (touched) { @@ -403,9 +350,7 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, const clean = window.location.pathname + cleanHash; window.history.replaceState({}, "", clean); } - } catch (e) { - // ignore - } + } catch (e) {} }, []); const handleLoginSubmit = async (e) => { @@ -428,35 +373,29 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, try { setSignupLoading(true); trackEvent("signup_submit"); - const u = regUser.trim(); const em = regEmail.trim(); - - await registerUser({ - username: u, - email: em, - password: regPass, - firstName: firstName.trim(), - lastName: lastName.trim(), - }); - - try { - localStorage.setItem(LAST_SIGNUP_KEY, JSON.stringify({ username: u, email: em })); - } catch {} - + await registerUser({ username: u, email: em, password: regPass, firstName: firstName.trim(), lastName: lastName.trim() }); + try { localStorage.setItem(LAST_SIGNUP_KEY, JSON.stringify({ username: u, email: em })); } catch {} setSignupInfo("✅ " + t('auth.accountCreatedMsg') + " (" + em + ")"); trackEvent("signup_success"); setMode("login"); setLoginUser(u || em); setLoginPass(""); } catch (err) { - console.error(err); setSignupError(err.message || t('auth.registrationError')); } finally { setSignupLoading(false); } }; + const handleSearchSubmit = (e) => { + e.preventDefault(); + if (searchQuery.trim() && onSearch) { + onSearch(searchQuery.trim()); + } + }; + const toast = useMemo(() => { if (lastError) { const toastType = needsEmailVerification ? "warn" : "error"; @@ -469,10 +408,12 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, return null; }, [lastError, lastInfo, needsEmailVerification, t]); + const themeIcon = theme === 'dark' ? 'fa-moon' : theme === 'light' ? 'fa-sun' : 'fa-droplet'; + return ( <> - {/* Toast area (under topbar) */} - {toast?.message ? ( + {/* Toast area */} + {toast?.message && (
- ) : null} + )} -
-
-
-
SocioWire
-
-
SOCIOWIRE.com
-
{t('topbar.wiredToLife')}
-
+
+ {/* LEFT: Logo + Brand */} +
+
+ SocioWire
- - {/* Theme dots */} -
-
- {["dark", "blue", "light"].map((themeKey) => ( - - ))} -
+
+ SocioWire + {t('topbar.wiredToLife')}
-
- {/* User info */} -
- {authenticated ? ( - - ) : ( -
-
- -
-
-
{loading ? t('common.loading') : t('common.guest')}
-
{t('common.anon')}
-
+ )} + +
+ + {/* RIGHT: Actions */} +
+ {/* My Location */} + + + {/* Islands */} + + + {/* Install PWA */} + {showInstallBtn && ( + + )} + + {/* Theme */} +
+ + {showThemeMenu && ( +
+ {THEMES.map((themeKey) => ( + + ))}
)} -
- {/* Action buttons - separate section */} -
- {/* PWA Install button - no dismiss X */} - {showInstallBtn && ( - - )} - - {/* Theme selector (mobile dropdown) */} -
- - {showThemeMenu && ( -
- {THEMES.map((themeKey) => ( - - ))} -
- )} -
- - {/* Language selector */} -
- - {showLangMenu && ( -
- {SUPPORTED_LANGS.map((lang) => ( - - ))} -
- )} -
- - {/* Friends button - only when authenticated */} - {authenticated && ( - - )} - - {/* Login/Logout button */} + {/* Language */} +
+ {showLangMenu && ( +
+ {SUPPORTED_LANGS.map((lang) => ( + + ))} +
+ )} +
+ + {/* Friends - only when authenticated */} + {authenticated && ( + + )} + + {/* User / Login */} +
+ + {showUserMenu && authenticated && ( +
+ + +
+ )}
- {showAuth ? ( + {/* Auth Modal */} + {showAuth && (
e.stopPropagation()}>
@@ -679,88 +636,57 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, > {t('auth.signup')} - +
- {signupInfo ?
{signupInfo}
: null} - {authNotice ?
{authNotice}
: null} - {mode === "login" && lastError ? ( + {signupInfo &&
{signupInfo}
} + {authNotice &&
{authNotice}
} + {mode === "login" && lastError && (
{lastError}
- ) : null} + )} {mode === "login" ? (
- - {needsEmailVerification ? ( + {needsEmailVerification && (
⚠️ {t('auth.verifyEmail')}
- ) : null} + )} - {ssoEnabled ? ( + {ssoEnabled && ( <>
{t('auth.orContinueWith')}
- -
- ) : null} - + )}
) : (
@@ -786,9 +712,7 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, {t('auth.password')} setRegPass(e.target.value)} /> - - {signupError ?
{signupError}
: null} - + {signupError &&
{signupError}
} @@ -796,28 +720,22 @@ export default function TopBar({ theme = "dark", onChangeTheme, onIslandsClick, )}
- ) : null} + )} - {showUsernameModal ? ( + {/* Username Modal */} + {showUsernameModal && (
{}}>
e.stopPropagation()}>
{t('auth.chooseUsername')}
-
- {t('auth.pickUsername')} -
- {usernameError ?
{usernameError}
: null} - {usernameInfo ?
{usernameInfo}
: null} +
{t('auth.pickUsername')}
+ {usernameError &&
{usernameError}
} + {usernameInfo &&
{usernameInfo}
}
- ) : null} + )} - {/* Friends Panel - dropdown from topbar */} + {/* Friends Panel */} {showFriends && (
{ - setShowFriends(false); - if (onUserIsland) onUserIsland(uname); - }} + onSelectUser={(uname) => { setShowFriends(false); if (onUserIsland) onUserIsland(uname); }} onClose={() => setShowFriends(false)} />
diff --git a/src/components/Layout/TopBarNew.jsx b/src/components/Layout/TopBarNew.jsx index 584442d..1cec67a 100644 --- a/src/components/Layout/TopBarNew.jsx +++ b/src/components/Layout/TopBarNew.jsx @@ -207,13 +207,13 @@ function UserChip({ authenticated, loading, username, avatarUrl, onClick }) { whileTap={{ scale: 0.98 }} > {/* Avatar */} -
{avatarUrl ? ( {username} ) : ( -
- {authenticated ? initialLetter(username) : } +
+ {authenticated ? initialLetter(username) : }
)}
@@ -235,7 +235,7 @@ function UserChip({ authenticated, loading, username, avatarUrl, onClick }) { // Main Component // ───────────────────────────────────────────────────────────────────────────── -export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClick, onUserIsland }) { +export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClick, onUserIsland, onMyLocation, onSearch }) { const { t, i18n } = useTranslation(); const { loading, authenticated, username, login, logout, restore, loginWithProvider, ssoEnabled, @@ -257,6 +257,7 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic const [showFriends, setShowFriends] = useState(false); const [pendingRequestsCount, setPendingRequestsCount] = useState(0); const [showInstallBtn, setShowInstallBtn] = useState(false); + const [searchQuery, setSearchQuery] = useState(""); // Form states const [loginUser, setLoginUser] = useState(""); @@ -387,6 +388,13 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic }, [authenticated, username, showUsernameModal, loading, needsUsername]); // Handlers + const handleSearchSubmit = (e) => { + e.preventDefault(); + if (searchQuery.trim() && onSearch) { + onSearch(searchQuery.trim()); + } + }; + const handleLoginSubmit = async (e) => { e.preventDefault(); trackEvent("login_submit"); @@ -503,19 +511,17 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic animate={{ opacity: [0.3, 0.6, 0.3] }} transition={{ duration: 2, repeat: Infinity }} /> -
-
- S -
+
+ SocioWire
-
- +
+ SOCIOWIRE - + @@ -524,23 +530,8 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic
- {/* Center: Theme pills (desktop) */} -
- {THEMES.map((themeKey) => ( - onChangeTheme?.(themeKey)} - whileHover={{ scale: 1.05 }} - whileTap={{ scale: 0.95 }} - > - {t(`theme.${themeKey}`)} - - ))} -
+ {/* Spacer */} +
{/* Right: Action buttons */}
@@ -556,14 +547,15 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic whileTap={{ scale: 0.95 }} > - {t('topbar.install')} + {t('topbar.installApp')} )} - {/* Theme (mobile) */} -
+ + {/* Theme */} +
{/* Friends */} - {authenticated && ( - setShowFriends(!showFriends)} - whileHover={{ scale: 1.1 }} - whileTap={{ scale: 0.9 }} - > - - {pendingRequestsCount > 0 && ( - - {pendingRequestsCount} - - )} - - )} + authenticated ? setShowFriends(!showFriends) : openModal("login")} + whileHover={{ scale: 1.1 }} + whileTap={{ scale: 0.9 }} + title={t('topbar.friends')} + > + + {authenticated && pendingRequestsCount > 0 && ( + + {pendingRequestsCount} + + )} + {/* Separator */}
@@ -651,7 +642,7 @@ export default function TopBarNew({ theme = "dark", onChangeTheme, onIslandsClic className="absolute inset-0 bg-gradient-to-r from-emerald-400 to-teal-400 opacity-0 group-hover:opacity-100 transition-opacity" /> - {t('topbar.joinNow')} + {t('topbar.login')} )}
diff --git a/src/components/Posts/PostDetailModal.jsx b/src/components/Posts/PostDetailModal.jsx index 833f8f0..1fc8416 100644 --- a/src/components/Posts/PostDetailModal.jsx +++ b/src/components/Posts/PostDetailModal.jsx @@ -505,13 +505,17 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe }, [postId]); // Fetch comments - const refreshComments = useCallback(async () => { + const refreshComments = useCallback(async (autoOpen = false) => { if (!postId) return; const items = await fetchPostComments(postId, 50); - if (Array.isArray(items)) { setComments(items); setCounts(c => ({ ...c, comments: items.length })); } + if (Array.isArray(items)) { + setComments(items); + setCounts(c => ({ ...c, comments: items.length })); + if (autoOpen && items.length > 0) setShowComments(true); + } }, [postId]); - useEffect(() => { refreshComments(); }, [refreshComments]); + useEffect(() => { refreshComments(true); }, [refreshComments]); useEffect(() => { if (showComments) commentsEndRef.current?.scrollIntoView({ behavior: "smooth" }); }, [comments, showComments]); // Handlers @@ -545,7 +549,7 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe setCommentInput(""); setCommentSending(true); const tempId = `temp_${Date.now()}`; - const newComment = { id: tempId, body, author: username || "You", created_at: new Date().toISOString(), _pending: true }; + const newComment = { id: tempId, body, username: username || "You", created_at: new Date().toISOString(), _pending: true }; setComments(prev => [...prev, newComment]); setCounts(c => ({ ...c, comments: c.comments + 1 })); const res = await createPostComment(postId, body); @@ -764,28 +768,28 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe
{/* Truth Score */} -
-
+
+
handleTruthVote("false")} - className="w-12 h-12 rounded-full bg-red-500/20 border border-red-500/30 text-red-400 flex items-center justify-center hover:bg-red-500/30"> - + className="w-9 h-9 rounded-full bg-red-500/20 border border-red-500/30 text-red-400 flex items-center justify-center hover:bg-red-500/30"> +
-
- = 70 ? 'text-emerald-400' : truth.score >= 50 ? 'text-amber-400' : 'text-red-400'}`}> +
+ = 70 ? 'text-emerald-400' : truth.score >= 50 ? 'text-amber-400' : 'text-red-400'}`}> {Math.round(truth.score)} - / 100 + / 100
-
+
= 70 ? 'bg-gradient-to-r from-emerald-500 to-teal-400' : truth.score >= 50 ? 'bg-gradient-to-r from-amber-500 to-orange-400' : 'bg-gradient-to-r from-red-500 to-pink-400'}`} initial={{ width: 0 }} animate={{ width: `${truth.score}%` }} transition={{ duration: 0.6 }} />
-

{truth.count} votes

+

{truth.count} votes

handleTruthVote("true")} - className="w-12 h-12 rounded-full bg-emerald-500/20 border border-emerald-500/30 text-emerald-400 flex items-center justify-center hover:bg-emerald-500/30"> - + className="w-9 h-9 rounded-full bg-emerald-500/20 border border-emerald-500/30 text-emerald-400 flex items-center justify-center hover:bg-emerald-500/30"> +
@@ -834,12 +838,19 @@ export default function PostDetailModal({ post, onClose, onPostUpdated, onPostDe comments.map((c) => ( -
- @{c.author} - {relativeTime(c.created_at, t)} - {c._failed && Failed} +
+
+ {(c.username || "?")[0]?.toUpperCase()} +
+
+
+ @{c.username || "user"} + {relativeTime(c.created_at, t)} + {c._failed && Failed} +
+

{c.body}

+
-

{c.body}

)) )} diff --git a/src/styles/topbar.css b/src/styles/topbar.css index 97a9511..2d06a4e 100644 --- a/src/styles/topbar.css +++ b/src/styles/topbar.css @@ -1,1103 +1,898 @@ -.topbar{ - position: sticky; top:0; z-index:1000; - width:100%; - padding: .55rem .4rem .55rem 1.2rem; +/* ============================================================================ + SOCIOWIRE TOPBAR - Facebook-inspired modern design + ============================================================================ */ + +.sw-topbar { + position: sticky; + top: 0; + z-index: 1000; display: flex; align-items: center; justify-content: space-between; gap: 1rem; - background: linear-gradient(135deg,#071225 0%,#0b2b5f 38%,#0e65c0 72%,#27a8ff 100%); - border-bottom-left-radius:18px; border-bottom-right-radius:18px; - box-shadow: 0 10px 24px rgba(0,0,0,.55), 0 0 18px rgba(56,189,248,.45); - overflow: visible; + padding: 0.5rem 1rem; + background: linear-gradient(135deg, #0a1628 0%, #0d2847 50%, #1a4b8c 100%); + border-bottom: 1px solid rgba(56, 189, 248, 0.2); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4), 0 0 40px rgba(56, 189, 248, 0.1); } -.logo-circle{ - width:52px; height:52px; flex-shrink:0; - margin: -6px 0; -} -.logo-circle img{ - width:100%; height:100%; object-fit:contain; -} +/* ============================================================================ + LEFT SECTION - Logo & Brand + ============================================================================ */ -.title-block{ display:flex; flex-direction:column; line-height:1.05; min-width:0; } -.main-title{ font-size:1.02rem; font-weight:800; letter-spacing:.04em; color:#f9fafb; } -.sub-title{ font-size:.74rem; color:#dbeafe; opacity:.95; } - -.topbar-right{ - display: inline-flex; - align-items: center; - gap: 0.4rem; - margin-left: auto; - margin-right: 0; - padding-right: 0; - flex-wrap: nowrap; - flex-shrink: 0; - width: auto; - justify-content: flex-end; -} - -.topbar-user-section{ - display: inline-flex; +.sw-topbar-left { + display: flex; align-items: center; + gap: 0.75rem; flex-shrink: 0; } - -.theme-switch{ display:flex; gap:.28rem; } -.theme-dot{ - width:22px; height:22px; border-radius:999px; - border:1px solid rgba(148,163,184,.85); - background:rgba(15,23,42,.9); color:#e5e7eb; font-size:.65rem; - display:flex; align-items:center; justify-content:center; padding:0; cursor:pointer; - box-shadow:0 0 6px rgba(15,23,42,.9); transition:transform 0.36s ease; -} -.theme-dot:hover{ transform:scale(1.06); } -.theme-dot-active{ border-color:#facc15; box-shadow:0 0 10px rgba(250,204,21,.9),0 0 14px rgba(56,189,248,.55); } - -.btn-primary, .btn-secondary{ - padding:.32rem .85rem; font-size:.78rem; border-radius:999px; font-weight:700; cursor:pointer; - white-space:nowrap; line-height:1; -} -.btn-primary{ - border:1px solid #22c55e; - background:radial-gradient(circle at 30% 30%,#22c55e,#16a34a); - color:#f9fafb; - box-shadow:0 4px 10px rgba(22,163,74,.5),0 0 8px rgba(22,163,74,.6); -} -.btn-primary:disabled{ opacity:.6; cursor:default; } -.btn-secondary{ - border:1px solid #bfdbfe; - background:rgba(15,23,42,.25); - color:#e0f2fe; - box-shadow:0 3px 10px rgba(15,23,42,.6); -} -.btn-secondary:hover{ background:rgba(15,23,42,.45); } - -.btn-icon{ - width: 36px; - height: 36px; - border-radius: 50%; - border: 1px solid rgba(148,163,184,.5); - background: rgba(15,23,42,.6); - color: #38bdf8; - font-size: 1rem; +.sw-logo { + width: 48px; + height: 48px; + border-radius: 12px; + background: linear-gradient(135deg, #1e40af, #3b82f6); + padding: 4px; + box-shadow: 0 4px 15px rgba(59, 130, 246, 0.4); display: flex; align-items: center; justify-content: center; - padding: 0; - cursor: pointer; - box-shadow: 0 0 10px rgba(56,189,248,.3); - transition: all 0.3s ease; -} -.btn-icon:hover{ - background: rgba(56,189,248,.2); - box-shadow: 0 0 16px rgba(56,189,248,.6); - transform: scale(1.1); - border-color: #38bdf8; -} - -/* New action buttons design */ -.topbar-actions{ - display: inline-flex; - align-items: center; - gap: 0.3rem; - flex-shrink: 0; - margin: 0; - padding: 0; -} - -.btn-action{ - height: 32px; - padding: 0 0.5rem; - border-radius: 999px; - border: 1px solid rgba(148, 163, 184, 0.3); - background: linear-gradient(135deg, rgba(15, 23, 42, 0.8), rgba(30, 41, 59, 0.8)); - color: #f1f5f9; - font-size: 0.8rem; - font-weight: 600; - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.35rem; - cursor: pointer; - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - white-space: nowrap; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); -} - -.btn-action i{ - font-size: 0.9rem; -} - -.btn-action .btn-label{ - font-size: 0.8rem; - letter-spacing: 0.01em; -} - -.btn-action:hover{ - transform: translateY(-2px); - box-shadow: 0 4px 12px rgba(56, 189, 248, 0.4); - border-color: rgba(56, 189, 248, 0.6); -} - -.btn-action:active{ - transform: translateY(0); -} - -.btn-action:disabled{ - opacity: 0.5; - cursor: not-allowed; - transform: none; -} - -/* Specific button colors */ -.btn-action-install{ - background: linear-gradient(135deg, #3b82f6, #2563eb); - border-color: rgba(139, 92, 246, 0.5); - color: white; -} - -.btn-action-install:hover{ - background: linear-gradient(135deg, #60a5fa, #3b82f6); - box-shadow: 0 4px 16px rgba(139, 92, 246, 0.6); - border-color: #60a5fa; -} - -.btn-action-islands{ - background: linear-gradient(135deg, #06b6d4, #0891b2); - border-color: rgba(6, 182, 212, 0.5); - color: white; -} - -.btn-action-islands:hover{ - background: linear-gradient(135deg, #22d3ee, #06b6d4); - box-shadow: 0 4px 16px rgba(6, 182, 212, 0.6); - border-color: #22d3ee; -} - -.btn-action-auth{ - background: linear-gradient(135deg, #10b981, #059669); - border-color: rgba(16, 185, 129, 0.5); - color: white; -} - -.btn-action-auth:hover{ - background: linear-gradient(135deg, #34d399, #10b981); - box-shadow: 0 4px 16px rgba(16, 185, 129, 0.6); - border-color: #34d399; -} - -@media (max-width:900px){ - .topbar-right{ - gap: 0.6rem; - } - - .btn-action .btn-label{ - display: none; - } - - .btn-action{ - padding: 0 0.5rem; - } -} - -@media (max-width:640px){ - .topbar{ - padding: .5rem .4rem .5rem .7rem; - border-bottom-left-radius: 16px; - border-bottom-right-radius: 16px; - flex-wrap: wrap; - } - - .main-title{ font-size: 1rem; } - .sub-title{ font-size: .7rem; } - - .topbar-right{ - width: fit-content !important; - max-width: fit-content !important; - justify-content: flex-end; - gap: 0.4rem; - margin-left: auto; - margin-top: 0.5rem; - flex-grow: 0; - flex-shrink: 1; - } - - .topbar-user-section{ - order: 1; - width: fit-content !important; - max-width: fit-content !important; - flex-grow: 0; - } - - .sw-userchip{ - width: fit-content !important; - max-width: fit-content !important; - flex-grow: 0; - } - - .sw-usertext{ - width: fit-content !important; - max-width: fit-content !important; - flex-grow: 0; - } - - .sw-userline, .sw-userhandle{ - max-width: fit-content !important; - } - - .topbar-actions{ - order: 2; - gap: 0.3rem; - width: fit-content !important; - flex-grow: 0; - } - - .btn-action{ - height: 34px; - min-width: 34px; - padding: 0 0.5rem; - } - - .btn-action i{ - font-size: 0.9rem; - } -} - -/* SW_AUTH_UI:BEGIN */ -.auth-strip{ - margin-top: 6px; - display:flex; - align-items:center; - gap: .45rem; - flex-wrap: wrap; -} - -.auth-pill{ - display:inline-flex; - align-items:center; - gap: .35rem; - padding: .18rem .55rem; - border-radius: 999px; - font-size: .70rem; - font-weight: 900; - letter-spacing: .02em; - border: 1px solid rgba(148,163,184,.55); - background: rgba(2,6,23,.25); - color: #e5e7eb; -} -.auth-pill i{ font-size: .85rem; opacity:.95; } - -.auth-pill--ok{ - border-color: rgba(34,197,94,.65); - background: rgba(34,197,94,.16); -} -.auth-pill--loading{ - border-color: rgba(56,189,248,.65); - background: rgba(56,189,248,.14); -} -.auth-pill--anon{ - border-color: rgba(148,163,184,.55); - background: rgba(2,6,23,.20); -} - -.auth-banner{ - margin-top: 6px; - padding: 6px 10px; - border-radius: 14px; - font-size: .72rem; - font-weight: 800; - display:flex; - gap: 8px; - align-items:center; - flex-wrap:wrap; -} -.auth-banner--error{ - background: rgba(248,113,113,0.14); - border: 1px solid rgba(248,113,113,0.55); - color: #ffe4e6; -} -.auth-banner--info{ - background: rgba(56,189,248,0.14); - border: 1px solid rgba(56,189,248,0.55); - color: #e0f2fe; -} -.auth-banner--success{ - background: rgba(34,197,94,0.14); - border: 1px solid rgba(34,197,94,0.55); - color: #d1fae5; -} - -.user-chip{ - display:inline-flex; - align-items:center; - gap: .45rem; - padding: .22rem .55rem; - border-radius: 999px; - background: rgba(2,6,23,.25); - border: 1px solid rgba(148,163,184,.55); -} -.user-avatar{ - width: 26px; - height: 26px; - border-radius: 999px; - display:flex; - align-items:center; - justify-content:center; - background: rgba(56,189,248,0.18); - border: 1px solid rgba(56,189,248,0.35); -} -.user-avatar i{ font-size: 14px; } - -.user-name{ - font-size: .80rem; - font-weight: 950; - color: #f9fafb; - max-width: 220px; - overflow:hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -/* Light theme readability */ -body[data-theme="light"] .auth-pill{ - background: rgba(255,255,255,0.82); - border-color: rgba(148,163,184,0.85); - color: #0b1220; -} -body[data-theme="light"] .user-chip{ - background: rgba(255,255,255,0.82); - border-color: rgba(148,163,184,0.85); -} -body[data-theme="light"] .user-name{ color:#0b1220; } -body[data-theme="light"] .user-avatar{ - background: rgba(30,107,255,0.12); - border-color: rgba(30,107,255,0.35); - color:#0b1220; -} -/* SW_AUTH_UI:END */ - -/* SW_AUTH_UI2:BEGIN */ -.sw-notice{ - margin: 10px 14px 0 14px; - padding: 10px 12px; - border-radius: 16px; - font-size: .78rem; - font-weight: 800; - line-height: 1.2; - border: 1px solid rgba(148,163,184,.35); - background: rgba(2,6,23,.22); - color: #e5e7eb; -} -.sw-notice--error{ - background: rgba(248,113,113,0.14); - border-color: rgba(248,113,113,0.55); - color: #ffe4e6; -} -.sw-notice--info{ - background: rgba(56,189,248,0.14); - border-color: rgba(56,189,248,0.55); - color: #e0f2fe; -} -.sw-notice--success{ - background: rgba(34,197,94,0.14); - border-color: rgba(34,197,94,0.55); - color: #d1fae5; -} -.sw-notice--warn{ - background: rgba(251,191,36,0.12); - border-color: rgba(251,191,36,0.40); - color: #fffbeb; -} - -/* single user chip (no duplicates) */ -.user-chip{ - display:inline-flex; - align-items:center; - gap: .45rem; - padding: .22rem .55rem; - border-radius: 999px; - background: rgba(2,6,23,.25); - border: 1px solid rgba(148,163,184,.55); -} -.user-avatar{ - width: 26px; - height: 26px; - border-radius: 999px; - display:flex; - align-items:center; - justify-content:center; - background: rgba(56,189,248,0.18); - border: 1px solid rgba(56,189,248,0.35); -} -.user-avatar i{ font-size: 14px; } -.user-name{ - font-size: .82rem; - font-weight: 950; - color: #f9fafb; - max-width: 180px; - overflow:hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.user-badge{ - display:inline-flex; - align-items:center; - gap: .35rem; - padding: .10rem .45rem; - border-radius: 999px; - font-size: .70rem; - font-weight: 950; - border: 1px solid rgba(34,197,94,.55); - background: rgba(34,197,94,.14); - color: #d1fae5; -} -/* SW_AUTH_UI2:END */ - - -/* SW_TOPBAR_POLISH:BEGIN */ - -/* Make right side look like a clean “glass dock” */ -.topbar-right{ - padding: calc(.28rem + 5px) calc(.35rem + 5px); - border-radius: 999px; - background: rgba(2,6,23,.18); - border: 1px solid rgba(255,255,255,.14); - backdrop-filter: blur(10px); - min-height: 44px; - min-width: max-content; - overflow: visible; -} - -/* User chip used by TopBar.jsx (missing styles before) */ -.sw-userchip{ - display: inline-flex; - align-items: center; - gap: 0.3rem; - padding: 0.2rem 0.4rem; - border-radius: 999px; - background: rgba(2,6,23,.22); - border: 1px solid rgba(148,163,184,.45); - box-shadow: 0 4px 14px rgba(0,0,0,.25); - margin: 0; -} - -.sw-userchip-btn{ - border: 0; - cursor: pointer; -} - -.sw-userchip-btn:hover{ - box-shadow: 0 6px 16px rgba(56,189,248,.35); - border-color: rgba(56,189,248,.7); -} - -.sw-avatar{ - width: 26px; - height: 26px; - border-radius: 50%; - display: grid; - place-items: center; - background: rgba(56,189,248,0.18); - border: 1px solid rgba(56,189,248,0.35); - color: #e5e7eb; - font-weight: 950; overflow: hidden; - flex-shrink: 0; } -.sw-avatar i{ font-size: 12px; } -.sw-avatar-guest{ - background: transparent; - border: none; -} -.sw-avatar img{ + +.sw-logo img { width: 100%; height: 100%; - object-fit: cover; - display: block; + object-fit: contain; + filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.3)); } -.sw-usertext{ +.sw-brand { display: flex; flex-direction: column; - line-height: 1.05; - min-width: 0; - max-width: max-content; -} -.sw-userline{ - font-size: 0.68rem; - font-weight: 950; - color: #f9fafb; - white-space: nowrap; -} -.sw-userhandle{ - font-size: 0.64rem; - font-weight: 800; - color: #dbeafe; - opacity: .92; - max-width: max-content; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + line-height: 1.1; } -/* Mobile: dock becomes full width and nice */ -@media (max-width:640px){ - .topbar-right{ - width:100%; - border-radius: 16px; - justify-content: flex-start; - } +.sw-brand-name { + font-size: 1.4rem; + font-weight: 900; + color: #ffffff; + letter-spacing: -0.02em; + text-shadow: 0 2px 10px rgba(56, 189, 248, 0.5); } -/* Light theme readability */ -body[data-theme="light"] .topbar-right{ - background: rgba(255,255,255,.55); - border-color: rgba(148,163,184,.55); -} -body[data-theme="light"] .sw-userchip{ - background: rgba(255,255,255,.80); - border-color: rgba(148,163,184,.70); - color: #0b1220; -} -body[data-theme="light"] .sw-userline, -body[data-theme="light"] .sw-userhandle{ - color:#0b1220; -} -body[data-theme="light"] .sw-avatar{ - background: rgba(30,107,255,0.10); - border-color: rgba(30,107,255,0.35); - color:#0b1220; +.sw-brand-tagline { + font-size: 0.7rem; + font-weight: 600; + color: #93c5fd; + letter-spacing: 0.05em; + text-transform: uppercase; } -/* SW_TOPBAR_POLISH:END */ +/* ============================================================================ + CENTER SECTION - Search Bar + ============================================================================ */ -/* SW_TOPBAR_OVERFLOW_FIX:BEGIN */ -.topbar{ - flex-wrap: wrap; /* ✅ allow wrap instead of overflowing right */ - row-gap: .45rem; +.sw-topbar-center { + flex: 1; + max-width: 500px; + margin: 0 1rem; } -.topbar-left{ - display:flex; - align-items:center; - gap: .65rem; - min-width: 0; /* ✅ allow shrinking */ +.sw-search-form { + position: relative; + display: flex; + align-items: center; } -.title-block{ min-width:0; } -.main-title, .sub-title{ - max-width: 58vw; - overflow:hidden; - text-overflow: ellipsis; - white-space: nowrap; +.sw-search-icon { + position: absolute; + left: 14px; + color: #64748b; + font-size: 0.9rem; + pointer-events: none; + transition: color 0.2s; } -.topbar-right{ - min-width: 0; - max-width: 100%; - flex: 1 1 auto; - justify-content: flex-end; - flex-wrap: wrap; /* ✅ wrap buttons instead of clipping */ - gap: .45rem; -} - -@media (max-width:640px){ - .main-title, .sub-title{ max-width: 86vw; } - .topbar-right{ - justify-content: flex-start; - width: 100%; - } -} - -/* Unified auth button (guest online / log on / log off) */ -.sw-auth-combo{ - display:flex; - align-items:center; - gap:.5rem; - padding:.25rem .55rem; +.sw-search-input { + width: 100%; + padding: 0.65rem 2.5rem 0.65rem 2.5rem; border-radius: 999px; - border: 1px solid rgba(148,163,184,.55); - background: rgba(2,6,23,.22); - color: #e5e7eb; - cursor:pointer; - max-width: 100%; - box-shadow: 0 4px 14px rgba(0,0,0,.22); + border: 1px solid rgba(148, 163, 184, 0.2); + background: rgba(15, 23, 42, 0.6); + color: #f1f5f9; + font-size: 0.9rem; + outline: none; + transition: all 0.25s ease; + backdrop-filter: blur(8px); } -.sw-auth-combo .sw-usertext{ - min-width: 0; +.sw-search-input::placeholder { + color: #64748b; } -.sw-auth-combo .sw-userhandle{ - max-width: 120px; - overflow:hidden; - text-overflow: ellipsis; - white-space: nowrap; +.sw-search-input:focus { + border-color: rgba(56, 189, 248, 0.6); + background: rgba(15, 23, 42, 0.8); + box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.15), 0 4px 15px rgba(0, 0, 0, 0.2); } -.sw-auth-action{ - margin-left: .25rem; - padding: .22rem .55rem; - border-radius: 999px; - font-weight: 950; - font-size: .70rem; - border: 1px solid rgba(56,189,248,.35); - background: rgba(56,189,248,.14); - color: #dbeafe; - white-space: nowrap; +.sw-topbar-center.is-focused .sw-search-icon { + color: #38bdf8; } -.sw-auth-combo--on .sw-auth-action{ - border-color: rgba(34,197,94,.45); - background: rgba(34,197,94,.16); - color: #d1fae5; -} -/* SW_TOPBAR_OVERFLOW_FIX:END */ - - -/* SW_TOPBAR_ONE_LINE_FIX:BEGIN */ -/* Keep the header on ONE ROW (no wrapping to a second line) */ -.topbar{ - flex-wrap: nowrap; - align-items: center; -} - -/* Left brand stack (logo + title, with theme dots underneath) */ -.brand-stack{ - display: flex; - flex-direction: column; - gap: 4px; - min-width: 0; -} - -.brand-toprow{ +.sw-search-clear { + position: absolute; + right: 10px; + width: 24px; + height: 24px; + border: none; + background: rgba(100, 116, 139, 0.3); + color: #94a3b8; + border-radius: 50%; + cursor: pointer; display: flex; align-items: center; - gap: .65rem; - min-width: 0; + justify-content: center; + font-size: 0.7rem; + transition: all 0.2s; } -.brand-under{ +.sw-search-clear:hover { + background: rgba(239, 68, 68, 0.3); + color: #fca5a5; +} + +/* ============================================================================ + RIGHT SECTION - Action Buttons + ============================================================================ */ + +.sw-topbar-right { display: flex; align-items: center; - gap: .5rem; - padding-left: 46px; /* aligns under title block visually */ + gap: 0.5rem; + flex-shrink: 0; } -/* Prevent title from pushing the right side off-screen */ -.title-block{ min-width: 0; } -.main-title{ - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: min(360px, 48vw); -} -.sub-title{ - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: min(360px, 48vw); -} - -/* Right side never wraps */ -.topbar-right{ - flex-wrap: nowrap !important; - white-space: nowrap; - min-width: 0; - max-width: max-content; - overflow: visible; -} - -/* Make user handle and chip take only needed space */ -.sw-userchip{ min-width: 0; max-width: max-content; width: max-content; } - -@media (max-width: 640px){ - .main-title, .sub-title{ max-width: 62vw; } - .topbar-right{ max-width: 100%; } - .brand-under{ padding-left: 0; } -} -/* SW_TOPBAR_ONE_LINE_FIX:END */ - -/* SW_FRIENDS_BUTTON:BEGIN */ -.btn-action-friends{ - background: linear-gradient(135deg, #f59e0b, #d97706); - border-color: rgba(245, 158, 11, 0.5); - color: white; -} - -.btn-action-friends:hover{ - background: linear-gradient(135deg, #fbbf24, #f59e0b); - box-shadow: 0 4px 16px rgba(245, 158, 11, 0.6); - border-color: #fbbf24; -} - -.btn-action-friends.is-active{ - background: linear-gradient(135deg, #fbbf24, #f59e0b); - box-shadow: 0 4px 16px rgba(245, 158, 11, 0.6); - border-color: #fbbf24; -} - -.btn-action-friends{ +.sw-topbar-btn { + width: 40px; + height: 40px; + border-radius: 50%; + border: 1px solid rgba(148, 163, 184, 0.2); + background: rgba(15, 23, 42, 0.5); + color: #e2e8f0; + font-size: 1rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); position: relative; } -.friends-badge-count{ +.sw-topbar-btn:hover { + background: rgba(56, 189, 248, 0.15); + border-color: rgba(56, 189, 248, 0.4); + color: #38bdf8; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(56, 189, 248, 0.25); +} + +.sw-topbar-btn.is-active { + background: rgba(56, 189, 248, 0.2); + border-color: rgba(56, 189, 248, 0.5); + color: #38bdf8; +} + +/* Button variants */ +.sw-topbar-btn-location { + background: linear-gradient(135deg, rgba(34, 197, 94, 0.15), rgba(16, 185, 129, 0.15)); + border-color: rgba(34, 197, 94, 0.3); + color: #4ade80; +} + +.sw-topbar-btn-location:hover { + background: linear-gradient(135deg, rgba(34, 197, 94, 0.25), rgba(16, 185, 129, 0.25)); + border-color: rgba(34, 197, 94, 0.5); + color: #86efac; + box-shadow: 0 4px 12px rgba(34, 197, 94, 0.3); +} + +.sw-topbar-btn-islands { + background: linear-gradient(135deg, rgba(6, 182, 212, 0.15), rgba(14, 165, 233, 0.15)); + border-color: rgba(6, 182, 212, 0.3); + color: #22d3ee; +} + +.sw-topbar-btn-islands:hover { + background: linear-gradient(135deg, rgba(6, 182, 212, 0.25), rgba(14, 165, 233, 0.25)); + border-color: rgba(6, 182, 212, 0.5); + color: #67e8f9; + box-shadow: 0 4px 12px rgba(6, 182, 212, 0.3); +} + +.sw-topbar-btn-install { + background: linear-gradient(135deg, rgba(139, 92, 246, 0.15), rgba(168, 85, 247, 0.15)); + border-color: rgba(139, 92, 246, 0.3); + color: #a78bfa; +} + +.sw-topbar-btn-install:hover { + background: linear-gradient(135deg, rgba(139, 92, 246, 0.25), rgba(168, 85, 247, 0.25)); + border-color: rgba(139, 92, 246, 0.5); + color: #c4b5fd; + box-shadow: 0 4px 12px rgba(139, 92, 246, 0.3); +} + +.sw-topbar-btn-theme { + background: linear-gradient(135deg, rgba(99, 102, 241, 0.15), rgba(129, 140, 248, 0.15)); + border-color: rgba(99, 102, 241, 0.3); + color: #818cf8; +} + +.sw-topbar-btn-theme:hover { + background: linear-gradient(135deg, rgba(99, 102, 241, 0.25), rgba(129, 140, 248, 0.25)); + border-color: rgba(99, 102, 241, 0.5); + color: #a5b4fc; + box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3); +} + +.sw-topbar-btn-lang { + background: rgba(15, 23, 42, 0.5); + min-width: 40px; +} + +.sw-lang-code { + font-size: 0.75rem; + font-weight: 800; + letter-spacing: 0.02em; +} + +.sw-topbar-btn-friends { + background: linear-gradient(135deg, rgba(245, 158, 11, 0.15), rgba(251, 191, 36, 0.15)); + border-color: rgba(245, 158, 11, 0.3); + color: #fbbf24; +} + +.sw-topbar-btn-friends:hover, +.sw-topbar-btn-friends.is-active { + background: linear-gradient(135deg, rgba(245, 158, 11, 0.25), rgba(251, 191, 36, 0.25)); + border-color: rgba(245, 158, 11, 0.5); + color: #fcd34d; + box-shadow: 0 4px 12px rgba(245, 158, 11, 0.3); +} + +/* Badge for notifications */ +.sw-badge { position: absolute; - top: -6px; - right: -6px; + top: -4px; + right: -4px; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; - background: #ef4444; + background: linear-gradient(135deg, #ef4444, #dc2626); color: white; font-size: 0.65rem; font-weight: 700; display: flex; align-items: center; justify-content: center; - border: 2px solid rgba(15, 23, 42, 0.9); - box-shadow: 0 2px 6px rgba(239, 68, 68, 0.5); + border: 2px solid #0a1628; + box-shadow: 0 2px 8px rgba(239, 68, 68, 0.5); } -/* Friends dropdown panel positioning */ -.friends-dropdown-wrap{ - position: fixed; - top: 70px; - right: 16px; - z-index: 1000; - animation: friendsSlideIn 0.2s ease-out; +/* ============================================================================ + USER BUTTON + ============================================================================ */ + +.sw-topbar-user { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.35rem 0.5rem 0.35rem 0.35rem; + border-radius: 999px; + border: 1px solid rgba(148, 163, 184, 0.2); + background: rgba(15, 23, 42, 0.5); + color: #e2e8f0; + cursor: pointer; + transition: all 0.25s ease; } -@keyframes friendsSlideIn{ - from{ - opacity: 0; - transform: translateY(-10px); - } - to{ - opacity: 1; - transform: translateY(0); - } +.sw-topbar-user:hover { + background: rgba(56, 189, 248, 0.1); + border-color: rgba(56, 189, 248, 0.3); } -@media (max-width: 640px){ - .friends-dropdown-wrap{ - top: auto; - bottom: 80px; - right: 10px; - left: 10px; - } - .friends-dropdown-wrap .friends-panel{ - max-width: none; - width: 100%; - } -} -/* SW_FRIENDS_BUTTON:END */ - -/* SW_LANGUAGE_SELECTOR:BEGIN */ -.lang-selector-wrap{ - position: relative; - z-index: 9999; -} - -.btn-action-lang{ - background: rgba(56, 189, 248, 0.12); +.sw-topbar-user.is-active { + background: rgba(56, 189, 248, 0.15); border-color: rgba(56, 189, 248, 0.4); } -.btn-action-lang .btn-label{ - font-size: 0.65rem; +.sw-user-avatar { + width: 32px; + height: 32px; + border-radius: 50%; + background: linear-gradient(135deg, #3b82f6, #1d4ed8); + display: flex; + align-items: center; + justify-content: center; + color: white; font-weight: 700; + font-size: 0.85rem; + overflow: hidden; + flex-shrink: 0; } -.btn-action-lang.is-active{ - background: rgba(56, 189, 248, 0.25); - border-color: rgba(56, 189, 248, 0.7); +.sw-user-avatar img { + width: 100%; + height: 100%; + object-fit: cover; } -.lang-dropdown{ - position: fixed; - top: auto; - right: auto; - margin-top: 6px; - min-width: 140px; +.sw-user-avatar i { + font-size: 0.9rem; + opacity: 0.8; +} + +.sw-user-info { + display: flex; + flex-direction: column; + line-height: 1.15; + min-width: 0; +} + +.sw-user-name { + font-size: 0.8rem; + font-weight: 700; + color: #f1f5f9; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100px; +} + +.sw-user-status { + font-size: 0.65rem; + font-weight: 500; + color: #4ade80; +} + +.sw-user-chevron { + font-size: 0.65rem; + color: #64748b; + margin-left: 0.25rem; + transition: transform 0.2s; +} + +.sw-topbar-user.is-active .sw-user-chevron { + transform: rotate(180deg); +} + +/* ============================================================================ + DROPDOWN MENUS + ============================================================================ */ + +.sw-topbar-dropdown { + position: relative; +} + +.sw-dropdown-menu { + position: absolute; + top: calc(100% + 8px); + right: 0; + min-width: 160px; background: rgba(15, 23, 42, 0.98); - border: 1px solid rgba(148, 163, 184, 0.5); - border-radius: 14px; - box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(255,255,255,0.05); + border: 1px solid rgba(148, 163, 184, 0.2); + border-radius: 12px; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.05); backdrop-filter: blur(16px); overflow: hidden; z-index: 1001; - animation: langDropIn 0.18s ease-out; + animation: dropdownSlide 0.2s ease-out; } -@keyframes langDropIn{ - from{ +@keyframes dropdownSlide { + from { opacity: 0; transform: translateY(-8px) scale(0.95); } - to{ + to { opacity: 1; transform: translateY(0) scale(1); } } -.lang-option{ - display: block; +.sw-dropdown-item { + display: flex; + align-items: center; + gap: 0.75rem; width: 100%; - padding: 12px 16px; - text-align: left; - background: transparent; + padding: 0.75rem 1rem; border: none; - color: #e5e7eb; + background: transparent; + color: #e2e8f0; font-size: 0.9rem; - font-weight: 600; + font-weight: 500; + text-align: left; cursor: pointer; transition: background 0.15s; } -.lang-option:hover{ - background: rgba(56, 189, 248, 0.18); +.sw-dropdown-item:hover { + background: rgba(56, 189, 248, 0.1); } -.lang-option.is-active{ - background: rgba(56, 189, 248, 0.28); +.sw-dropdown-item.is-active { + background: rgba(56, 189, 248, 0.15); color: #38bdf8; } -body[data-theme="light"] .lang-dropdown{ - background: rgba(255, 255, 255, 0.98); - border-color: rgba(148, 163, 184, 0.6); +.sw-dropdown-item i { + width: 18px; + text-align: center; + font-size: 0.9rem; + opacity: 0.8; } -body[data-theme="light"] .lang-option{ - color: #0f172a; +.sw-dropdown-logout { + border-top: 1px solid rgba(148, 163, 184, 0.1); + color: #f87171; } -body[data-theme="light"] .lang-option:hover{ - background: rgba(56, 189, 248, 0.15); +.sw-dropdown-logout:hover { + background: rgba(239, 68, 68, 0.1); } -body[data-theme="light"] .lang-option.is-active{ - background: rgba(56, 189, 248, 0.25); - color: #0369a1; -} -/* SW_LANGUAGE_SELECTOR:END */ +/* ============================================================================ + FRIENDS PANEL + ============================================================================ */ -/* SW_THEME_SELECTOR:BEGIN */ -.theme-selector-wrap{ - position: relative; -} - -.btn-action-theme{ - background: linear-gradient(135deg, #3b82f6, #6366f1); - border-color: rgba(139, 92, 246, 0.5); - color: white; -} - -.btn-action-theme:hover{ - background: linear-gradient(135deg, #60a5fa, #818cf8); -} - -.btn-action-theme.is-active{ - background: linear-gradient(135deg, #2563eb, #4f46e5); - box-shadow: 0 0 12px rgba(139, 92, 246, 0.6); -} - -.theme-dropdown{ +.friends-dropdown-wrap { position: fixed; - z-index: 1001; + top: 70px; + right: 16px; + z-index: 1000; + animation: dropdownSlide 0.2s ease-out; +} + +/* ============================================================================ + TOAST + ============================================================================ */ + +.sw-toast-wrap { + position: fixed; + top: 70px; + left: 50%; + transform: translateX(-50%); + z-index: 1100; + animation: toastSlide 0.3s ease-out; +} + +@keyframes toastSlide { + from { + opacity: 0; + transform: translateX(-50%) translateY(-10px); + } + to { + opacity: 1; + transform: translateX(-50%) translateY(0); + } +} + +/* ============================================================================ + AUTH MODAL (keep existing styles) + ============================================================================ */ + +.auth-modal-backdrop { + position: fixed; + inset: 0; + z-index: 2000; + background: rgba(0, 0, 0, 0.7); + backdrop-filter: blur(4px); + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; +} + +.auth-modal { + width: 100%; + max-width: 400px; background: rgba(15, 23, 42, 0.98); - border: 1px solid rgba(139, 92, 246, 0.5); - border-radius: 8px; - min-width: 120px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); - backdrop-filter: blur(12px); + border: 1px solid rgba(148, 163, 184, 0.2); + border-radius: 20px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); overflow: hidden; } -.theme-option{ - display: block; - width: 100%; - padding: 12px 16px; - text-align: left; - background: transparent; +.auth-modal-header { + display: flex; + align-items: center; + border-bottom: 1px solid rgba(148, 163, 184, 0.15); +} + +.auth-tab { + flex: 1; + padding: 1rem; border: none; - color: #e5e7eb; - font-size: 0.9rem; + background: transparent; + color: #94a3b8; + font-size: 0.95rem; font-weight: 600; cursor: pointer; - transition: background 0.15s; + transition: all 0.2s; } -.theme-option:hover{ - background: rgba(139, 92, 246, 0.18); +.auth-tab:hover { + color: #e2e8f0; + background: rgba(56, 189, 248, 0.05); } -.theme-option.is-active{ - background: rgba(139, 92, 246, 0.28); - color: #60a5fa; +.auth-tab-active { + color: #38bdf8; + background: rgba(56, 189, 248, 0.1); + box-shadow: inset 0 -2px 0 #38bdf8; } -body[data-theme="light"] .theme-dropdown{ - background: rgba(255, 255, 255, 0.98); - border-color: rgba(139, 92, 246, 0.6); +.auth-close { + width: 40px; + height: 40px; + border: none; + background: transparent; + color: #64748b; + font-size: 1.2rem; + cursor: pointer; + transition: color 0.2s; } -body[data-theme="light"] .theme-option{ +.auth-close:hover { + color: #f87171; +} + +.auth-notice { + margin: 0.75rem 1rem; + padding: 0.75rem 1rem; + border-radius: 10px; + font-size: 0.85rem; + font-weight: 500; +} + +.auth-notice-success { + background: rgba(34, 197, 94, 0.15); + border: 1px solid rgba(34, 197, 94, 0.3); + color: #86efac; +} + +.auth-notice-error { + background: rgba(239, 68, 68, 0.15); + border: 1px solid rgba(239, 68, 68, 0.3); + color: #fca5a5; +} + +.auth-notice-warn { + background: rgba(251, 191, 36, 0.15); + border: 1px solid rgba(251, 191, 36, 0.3); + color: #fde68a; +} + +.auth-notice-info { + background: rgba(56, 189, 248, 0.15); + border: 1px solid rgba(56, 189, 248, 0.3); + color: #7dd3fc; +} + +.auth-form { + padding: 1.25rem; +} + +.auth-form label { + display: block; + margin-bottom: 1rem; + font-size: 0.85rem; + font-weight: 500; + color: #94a3b8; +} + +.auth-form input { + display: block; + width: 100%; + margin-top: 0.4rem; + padding: 0.75rem 1rem; + border-radius: 10px; + border: 1px solid rgba(148, 163, 184, 0.2); + background: rgba(15, 23, 42, 0.6); + color: #f1f5f9; + font-size: 0.95rem; + outline: none; + transition: all 0.2s; +} + +.auth-form input:focus { + border-color: rgba(56, 189, 248, 0.5); + box-shadow: 0 0 0 3px rgba(56, 189, 248, 0.1); +} + +.auth-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; +} + +.auth-link { + display: block; + margin-bottom: 1rem; + border: none; + background: none; + color: #38bdf8; + font-size: 0.85rem; + cursor: pointer; + text-align: left; +} + +.auth-link:hover { + text-decoration: underline; +} + +.btn-primary { + width: 100%; + padding: 0.85rem 1.5rem; + border: none; + border-radius: 10px; + background: linear-gradient(135deg, #3b82f6, #1d4ed8); + color: white; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.2s; +} + +.btn-primary:hover { + background: linear-gradient(135deg, #60a5fa, #3b82f6); + box-shadow: 0 4px 15px rgba(59, 130, 246, 0.4); +} + +.btn-primary:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +.btn-full { + width: 100%; +} + +.auth-divider { + text-align: center; + margin: 1.25rem 0; + color: #64748b; + font-size: 0.8rem; + position: relative; +} + +.auth-divider::before, +.auth-divider::after { + content: ""; + position: absolute; + top: 50%; + width: 30%; + height: 1px; + background: rgba(148, 163, 184, 0.2); +} + +.auth-divider::before { + left: 0; +} + +.auth-divider::after { + right: 0; +} + +.auth-oauth { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.btn-oauth { + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + width: 100%; + padding: 0.75rem 1rem; + border-radius: 10px; + border: 1px solid rgba(148, 163, 184, 0.2); + font-size: 0.9rem; + font-weight: 500; + cursor: pointer; + transition: all 0.2s; +} + +.btn-oauth-google { + background: white; + color: #1f2937; +} + +.btn-oauth-google:hover { + background: #f3f4f6; + border-color: rgba(148, 163, 184, 0.4); +} + +.btn-oauth-facebook { + background: #1877f2; + color: white; + border-color: #1877f2; +} + +.btn-oauth-facebook:hover { + background: #166fe5; +} + +/* ============================================================================ + LIGHT THEME + ============================================================================ */ + +body[data-theme="light"] .sw-topbar { + background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 50%, #cbd5e1 100%); + border-bottom-color: rgba(148, 163, 184, 0.3); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); +} + +body[data-theme="light"] .sw-brand-name { + color: #0f172a; + text-shadow: none; +} + +body[data-theme="light"] .sw-brand-tagline { + color: #475569; +} + +body[data-theme="light"] .sw-search-input { + background: rgba(255, 255, 255, 0.8); + border-color: rgba(148, 163, 184, 0.3); color: #0f172a; } -body[data-theme="light"] .theme-option:hover{ - background: rgba(139, 92, 246, 0.15); +body[data-theme="light"] .sw-search-input:focus { + background: white; + border-color: rgba(59, 130, 246, 0.5); } -body[data-theme="light"] .theme-option.is-active{ - background: rgba(139, 92, 246, 0.25); - color: #6d28d9; -} -/* SW_THEME_SELECTOR:END */ - -/* SW_MOBILE_TOPBAR_COMPACT:BEGIN - Facebook-style compact single-row topbar */ -@media (max-width: 900px){ - .btn-action .btn-label{ - display: none; - } - .btn-action{ - padding: 0 0.45rem; - min-width: 32px; - height: 30px; - } +body[data-theme="light"] .sw-topbar-btn { + background: rgba(255, 255, 255, 0.6); + border-color: rgba(148, 163, 184, 0.3); + color: #475569; } -@media (max-width: 640px){ - /* COMPACT SINGLE ROW - like Facebook */ - .topbar{ - flex-direction: row !important; - flex-wrap: nowrap !important; - align-items: center; - padding: 0.35rem 0.5rem; - gap: 0.4rem; - min-height: 44px; - max-height: 52px; +body[data-theme="light"] .sw-topbar-btn:hover { + background: rgba(59, 130, 246, 0.1); + border-color: rgba(59, 130, 246, 0.4); + color: #2563eb; +} + +body[data-theme="light"] .sw-topbar-user { + background: rgba(255, 255, 255, 0.6); + border-color: rgba(148, 163, 184, 0.3); +} + +body[data-theme="light"] .sw-user-name { + color: #0f172a; +} + +body[data-theme="light"] .sw-dropdown-menu { + background: rgba(255, 255, 255, 0.98); + border-color: rgba(148, 163, 184, 0.3); +} + +body[data-theme="light"] .sw-dropdown-item { + color: #0f172a; +} + +body[data-theme="light"] .sw-dropdown-item:hover { + background: rgba(59, 130, 246, 0.1); +} + +body[data-theme="light"] .auth-modal { + background: rgba(255, 255, 255, 0.98); +} + +body[data-theme="light"] .auth-form input { + background: rgba(241, 245, 249, 0.8); + color: #0f172a; +} + +/* ============================================================================ + RESPONSIVE - Tablet + ============================================================================ */ + +@media (max-width: 900px) { + .sw-topbar-center { + max-width: 300px; + margin: 0 0.5rem; } - /* Logo smaller */ - .logo-circle{ - width: 32px; - height: 32px; - margin: 0; - } - - /* Brand stack inline, no column */ - .brand-stack{ - flex-direction: row; - align-items: center; - gap: 0.35rem; - min-width: 0; - flex-shrink: 1; - } - - .brand-toprow{ - gap: 0.35rem; - min-width: 0; - } - - /* Hide subtitle and theme dots on mobile */ - .sub-title{ - display: none; - } - .brand-under{ + .sw-user-info { display: none; } - .main-title{ - font-size: 0.85rem; - white-space: nowrap; + .sw-topbar-user { + padding: 0.25rem; + } +} + +/* ============================================================================ + RESPONSIVE - Mobile + ============================================================================ */ + +@media (max-width: 640px) { + .sw-topbar { + padding: 0.4rem 0.6rem; + gap: 0.5rem; } - /* Right side: compact pill with small buttons */ - .topbar-right{ - flex-shrink: 0; - padding: 0.2rem 0.3rem; - border-radius: 999px; - gap: 0.25rem; - min-height: 34px; + .sw-logo { + width: 38px; + height: 38px; + border-radius: 10px; + } + + .sw-brand-name { + font-size: 1.1rem; + } + + .sw-brand-tagline { + display: none; + } + + .sw-topbar-center { + flex: 1; max-width: none; - width: auto; - background: rgba(2, 6, 23, 0.25); - border: 1px solid rgba(255, 255, 255, 0.12); + margin: 0 0.4rem; } - /* User chip: just avatar, no text */ - .topbar-user-section{ - flex-shrink: 0; - } - .sw-userchip{ - padding: 0.15rem; - gap: 0; - } - .sw-usertext{ - display: none; - } - .sw-avatar{ - width: 24px; - height: 24px; + .sw-search-input { + padding: 0.5rem 2rem 0.5rem 2.2rem; + font-size: 0.85rem; } - /* Compact action buttons */ - .topbar-actions{ - gap: 0.2rem; - } - .btn-action{ - height: 28px; - min-width: 28px; - padding: 0 0.35rem; - border-radius: 999px; - } - .btn-action i{ - font-size: 0.8rem; - } - .btn-action .btn-label{ - display: none; + .sw-topbar-right { + gap: 0.35rem; } - /* Friends badge smaller */ - .friends-badge-count{ - top: -4px; - right: -4px; - min-width: 14px; - height: 14px; - font-size: 0.55rem; - padding: 0 3px; + .sw-topbar-btn { + width: 34px; + height: 34px; + font-size: 0.9rem; } -} -@media (max-width: 380px){ - .topbar{ - padding: 0.3rem 0.4rem; - } - .logo-circle{ + .sw-user-avatar { width: 28px; height: 28px; } - .main-title{ - font-size: 0.75rem; - white-space: nowrap; + + .sw-badge { + min-width: 16px; + height: 16px; + font-size: 0.6rem; + top: -3px; + right: -3px; } - .btn-action{ - height: 26px; - min-width: 26px; - padding: 0 0.3rem; - } - .btn-action i{ - font-size: 0.75rem; - } - .sw-avatar{ - width: 22px; - height: 22px; + + .friends-dropdown-wrap { + top: auto; + bottom: 80px; + right: 10px; + left: 10px; + } +} + +@media (max-width: 480px) { + .sw-brand { + display: none; + } + + .sw-topbar-btn-location, + .sw-topbar-btn-islands { + display: none; } } -/* SW_MOBILE_TOPBAR_COMPACT:END */