e.stopPropagation()}>
@@ -256,18 +342,18 @@ export default function TopBar({ theme = "dark", onChangeTheme }) {
- {/* SW_MODAL_NOTICE:BEGIN */}
- {signupInfo ? (
-
- {signupInfo}
+ {/* Pretty notices inside modal */}
+ {signupInfo ?
{signupInfo}
: null}
+ {mode === "login" && lastError ? (
+
+ {lastError}
) : null}
- {/* SW_MODAL_NOTICE:END */}
{mode === "login" ? (
) : (
- )}
+ ) : null}
>
);
}
diff --git a/src/components/Layout/TopBar.jsx.bak.1766217948 b/src/components/Layout/TopBar.jsx.bak.1766217948
new file mode 100644
index 0000000..4fc365e
--- /dev/null
+++ b/src/components/Layout/TopBar.jsx.bak.1766217948
@@ -0,0 +1,392 @@
+import React, { useEffect, useMemo, useState } from "react";
+import { useAuth } from "../../auth/AuthContext";
+import { registerUser } from "../../api/client";
+import AuthToast from "../Auth/AuthToast";
+
+const THEME_LABELS = { dark: "Dark", blue: "Blue", light: "Light" };
+const LAST_EMAIL_KEY = "sociowire:lastEmail";
+
+function initialLetter(name = "") {
+ const s = (name || "").trim();
+ return s ? s[0].toUpperCase() : "G";
+}
+
+function looksLikeEmail(s = "") {
+ return typeof s === "string" && /.+@.+\..+/.test(s.trim());
+}
+
+export default function TopBar({ theme = "dark", onChangeTheme }) {
+ const {
+ loading,
+ authenticated,
+ username,
+ login,
+ logout,
+ needsEmailVerification,
+ resendVerificationEmail,
+ lastError,
+ lastInfo,
+ setError,
+ setLastInfo,
+ } = useAuth();
+
+ const clearError = () => setError && setError("");
+ const clearInfo = () => setLastInfo && setLastInfo("");
+
+ const [showAuth, setShowAuth] = useState(false);
+ const [mode, setMode] = useState("login");
+
+ const [loginUser, setLoginUser] = useState("");
+ const [loginPass, setLoginPass] = useState("");
+
+ const [firstName, setFirstName] = useState("");
+ const [lastName, setLastName] = useState("");
+ const [regUser, setRegUser] = useState("");
+ const [regEmail, setRegEmail] = useState("");
+ const [regPass, setRegPass] = useState("");
+ const [signupError, setSignupError] = useState("");
+ const [signupInfo, setSignupInfo] = useState("");
+ const [signupLoading, setSignupLoading] = useState(false);
+
+ const openModal = (nextMode) => {
+ setMode(nextMode);
+ setShowAuth(true);
+ setSignupError("");
+ setSignupInfo("");
+
+ // Prefill login with last known email (nice for email-verified return)
+ if (nextMode === "login") {
+ try {
+ const last = localStorage.getItem(LAST_EMAIL_KEY) || "";
+ if (!loginUser.trim() && last.trim()) setLoginUser(last.trim());
+ } catch {}
+ }
+ };
+
+ const closeModal = () => {
+ setShowAuth(false);
+ setLoginPass("");
+ setSignupError("");
+ setSignupInfo("");
+ };
+
+ useEffect(() => {
+ if (authenticated) setShowAuth(false);
+ }, [authenticated]);
+
+ /* SW_URL_NOTICE:BEGIN */
+ useEffect(() => {
+ try {
+ const qs = new URLSearchParams(window.location.search || "");
+ const verified = qs.get("verified") || qs.get("email_verified");
+ const signup = qs.get("signup");
+ const notice = qs.get("notice");
+ const email = (qs.get("email") || qs.get("user") || qs.get("username") || "").trim();
+
+ if (email) {
+ try { localStorage.setItem(LAST_EMAIL_KEY, email); } catch {}
+ // If user uses email to login, prefill it
+ if (!loginUser.trim()) setLoginUser(email);
+ if (!regEmail.trim()) setRegEmail(email);
+ }
+
+ if (verified === "1" || verified === "true") {
+ setSignupInfo(`✅ Email confirmé${email ? ` (${email})` : ""}. Tu peux te connecter.`);
+ setMode("login");
+ setShowAuth(true);
+ } else if (signup === "1" || signup === "true") {
+ setSignupInfo("✅ Compte créé. Vérifie tes emails (et le spam), puis connecte-toi.");
+ setMode("login");
+ setShowAuth(true);
+ } else if (notice) {
+ const msg = decodeURIComponent(notice);
+ if (msg && msg.trim()) {
+ setSignupInfo(msg.trim());
+ setMode("login");
+ setShowAuth(true);
+ }
+ }
+
+ // clean URL (remove params without reload)
+ if (verified || signup || notice || email) {
+ const clean = window.location.pathname + (window.location.hash || "");
+ window.history.replaceState({}, "", clean);
+ }
+ } catch (e) {
+ // ignore
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
+ /* SW_URL_NOTICE:END */
+
+ const handleLoginSubmit = async (e) => {
+ e.preventDefault();
+ // store email-like login for next time
+ try {
+ if (looksLikeEmail(loginUser)) localStorage.setItem(LAST_EMAIL_KEY, loginUser.trim());
+ } catch {}
+ await login(loginUser, loginPass);
+ };
+
+ const handleSignupSubmit = async (e) => {
+ e.preventDefault();
+ setSignupError("");
+ setSignupInfo("");
+
+ if (!firstName.trim() || !lastName.trim() || !regUser.trim() || !regEmail.trim() || !regPass) {
+ setSignupError("First name, last name, username, email and password are required.");
+ return;
+ }
+
+ try {
+ setSignupLoading(true);
+
+ await registerUser({
+ username: regUser.trim(),
+ email: regEmail.trim(),
+ password: regPass,
+ firstName: firstName.trim(),
+ lastName: lastName.trim(),
+ });
+
+ try { localStorage.setItem(LAST_EMAIL_KEY, regEmail.trim()); } catch {}
+
+ setSignupInfo("✅ Account created. Check your inbox (spam) to verify your email, then login.");
+ setMode("login");
+
+ // Some people login with email, some with username => prefer email if present
+ setLoginUser((regEmail.trim() || regUser.trim()));
+ setLoginPass("");
+ } catch (err) {
+ console.error(err);
+ setSignupError(err.message || "Registration error.");
+ } finally {
+ setSignupLoading(false);
+ }
+ };
+
+ const toast = useMemo(() => {
+ if (lastError) {
+ const t = needsEmailVerification ? "warn" : "error";
+ const title = needsEmailVerification ? "Vérification email requise" : "Connexion impossible";
+ return { type: t, title, message: lastError };
+ }
+ if (lastInfo) return { type: "success", title: "", message: lastInfo };
+ return null;
+ }, [lastError, lastInfo, needsEmailVerification]);
+
+ const authComboLabel = authenticated ? "Log off" : (loading ? "..." : "Log on");
+ const authLine = authenticated ? "Online" : "Guest";
+ const authHandle = authenticated ? `@${username || "user"}` : "anon";
+
+ return (
+ <>
+ {/* Toast area (under topbar) */}
+ {(toast?.message) && (
+
+
{
+ if (lastError) clearError();
+ if (lastInfo) clearInfo();
+ }}
+ />
+
+ {needsEmailVerification && (
+
+
+
+
+
+ )}
+
+ )}
+
+
+
+
SW
+
+
SOCIOWIRE.com
+
Wired to life
+
+
+
+
+
+ {["dark", "blue", "light"].map((t) => (
+
+ ))}
+
+
+ {/* ONE unified auth button (guest online / log on / log off) */}
+
+
+ {!authenticated && (
+
+ )}
+
+
+
+ {showAuth && (
+
+
e.stopPropagation()}>
+
+
+
+
+
+
+ {/* Nice notices (modal) */}
+ {signupInfo ?
{signupInfo}
: null}
+
+ {mode === "login" && needsEmailVerification ? (
+
+ ⚠️ Ton compte doit confirmer l’email avant de se connecter. Vérifie ta boîte mail (et le spam),
+ clique le lien, puis reviens ici.
+
+ ) : null}
+
+ {mode === "login" && lastError ? (
+
{lastError}
+ ) : null}
+
+ {mode === "login" && lastInfo ? (
+
{lastInfo}
+ ) : null}
+
+ {mode === "login" ? (
+
+ ) : (
+
+ )}
+
+
+ )}
+ >
+ );
+}
diff --git a/src/styles/auth-modal.css b/src/styles/auth-modal.css
index 696056f..27f49ae 100644
--- a/src/styles/auth-modal.css
+++ b/src/styles/auth-modal.css
@@ -96,3 +96,80 @@ body[data-theme="light"] .auth-form input {
.auth-modal { padding:.95rem .9rem 1.1rem; }
.auth-row { flex-direction:column; }
}
+
+/* SW_AUTH_NOTICE:BEGIN */
+.auth-notice{
+ margin: .2rem 0 .65rem;
+ padding: .55rem .7rem;
+ border-radius: 14px;
+ font-size: .82rem;
+ font-weight: 800;
+ line-height: 1.2;
+ border: 1px solid rgba(148,163,184,.35);
+ background: rgba(2,6,23,.22);
+ color: #e5e7eb;
+}
+
+.auth-notice-success{
+ background: rgba(34,197,94,0.14);
+ border-color: rgba(34,197,94,0.55);
+ color: #d1fae5;
+}
+
+.auth-notice-error{
+ background: rgba(248,113,113,0.14);
+ border-color: rgba(248,113,113,0.55);
+ color: #ffe4e6;
+}
+
+.auth-notice-warn{
+ background: rgba(251,191,36,0.12);
+ border-color: rgba(251,191,36,0.40);
+ color: #fffbeb;
+}
+
+body[data-theme="light"] .auth-notice{
+ background: rgba(255,255,255,0.92);
+ border-color: rgba(148,163,184,0.75);
+ color: #0b1220;
+}
+body[data-theme="light"] .auth-notice-success{ color:#0b1220; }
+body[data-theme="light"] .auth-notice-error{ color:#0b1220; }
+body[data-theme="light"] .auth-notice-warn{ color:#0b1220; }
+/* SW_AUTH_NOTICE:END */
+
+
+/* SW_AUTH_MODAL_NOTICE_POLISH:BEGIN */
+.auth-notice{
+ margin: 0 0 .65rem 0;
+ padding: .65rem .75rem;
+ border-radius: 14px;
+ font-size: .82rem;
+ font-weight: 800;
+ line-height: 1.2;
+ border: 1px solid rgba(148,163,184,.35);
+ background: rgba(2,6,23,.22);
+ color: #e5e7eb;
+}
+
+.auth-notice-success{
+ background: rgba(34,197,94,0.14);
+ border-color: rgba(34,197,94,0.55);
+ color: #d1fae5;
+}
+.auth-notice-error{
+ background: rgba(248,113,113,0.14);
+ border-color: rgba(248,113,113,0.55);
+ color: #ffe4e6;
+}
+.auth-notice-warn{
+ background: rgba(251,191,36,0.12);
+ border-color: rgba(251,191,36,0.40);
+ color: #fffbeb;
+}
+.auth-notice-info{
+ background: rgba(56,189,248,0.14);
+ border-color: rgba(56,189,248,0.55);
+ color: #e0f2fe;
+}
+/* SW_AUTH_MODAL_NOTICE_POLISH:END */
diff --git a/src/styles/auth-modal.css.bak.1766217948 b/src/styles/auth-modal.css.bak.1766217948
new file mode 100644
index 0000000..7b18c9a
--- /dev/null
+++ b/src/styles/auth-modal.css.bak.1766217948
@@ -0,0 +1,139 @@
+.auth-modal-backdrop {
+ position: fixed;
+ inset: 0;
+ z-index: 60;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: rgba(2, 6, 23, 0.65);
+ backdrop-filter: blur(8px);
+}
+
+.auth-modal {
+ width: min(640px, 95vw);
+ border-radius: 22px;
+ padding: 1.1rem 1.25rem 1.35rem;
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.85);
+ border: 1px solid rgba(148, 163, 184, 0.7);
+}
+
+body[data-theme="dark"] .auth-modal {
+ background: radial-gradient(circle at top left, #0f172a, #020617 70%);
+}
+body[data-theme="blue"] .auth-modal {
+ background: radial-gradient(circle at top left, #0ea5e9, #020617 65%);
+ border-color: rgba(96, 165, 250, 0.9);
+}
+body[data-theme="light"] .auth-modal {
+ background: radial-gradient(circle at top left, #ffffff, #e5e7eb 70%);
+ color: #020617;
+ border-color: rgba(148, 163, 184, 0.7);
+}
+
+.auth-modal-header { display:flex; align-items:center; gap:.5rem; margin-bottom:.9rem; }
+
+.auth-tab {
+ padding: .45rem .95rem;
+ border-radius: 999px;
+ border: 1px solid transparent;
+ background: transparent;
+ font-size: .85rem;
+ color: #e5e7eb;
+ cursor: pointer;
+}
+.auth-tab-active {
+ background: linear-gradient(135deg, #1d4ed8, #38bdf8);
+ border-color: rgba(191, 219, 254, 0.9);
+ color: #f9fafb;
+}
+body[data-theme="light"] .auth-tab { color:#0f172a; }
+body[data-theme="light"] .auth-tab-active { color:#f9fafb; }
+
+.auth-close {
+ margin-left:auto;
+ width:32px; height:32px;
+ border-radius:999px;
+ border:1px solid rgba(148, 163, 184, 0.6);
+ background: rgba(15, 23, 42, 0.85);
+ color:#e5e7eb;
+ font-size:.8rem;
+ cursor:pointer;
+}
+body[data-theme="light"] .auth-close { background:#e5e7eb; color:#020617; }
+
+.auth-form { display:flex; flex-direction:column; gap:.7rem; }
+.auth-row { display:flex; gap:.6rem; }
+.auth-row label { flex:1; }
+.auth-form label { display:flex; flex-direction:column; font-size:.8rem; gap:.25rem; }
+
+.auth-form input {
+ border-radius: 999px;
+ border: 1px solid rgba(51, 65, 85, 0.9);
+ background: rgba(15, 23, 42, 0.96);
+ color: #e5e7eb;
+ padding: .55rem .85rem;
+ font-size: .85rem;
+}
+body[data-theme="light"] .auth-form input {
+ background:#f9fafb;
+ color:#020617;
+ border-color: rgba(148, 163, 184, 0.9);
+}
+
+.btn-full { width:100%; margin-top:.4rem; }
+
+.auth-error {
+ margin-top:.25rem;
+ font-size:.8rem;
+ color:#fecaca;
+ background: rgba(127, 29, 29, 0.55);
+ border-radius:.5rem;
+ padding:.4rem .6rem;
+ border: 1px solid rgba(248, 113, 113, 0.7);
+}
+
+@media (max-width:480px){
+ .auth-modal { padding:.95rem .9rem 1.1rem; }
+ .auth-row { flex-direction:column; }
+}
+
+/* SW_AUTH_NOTICE:BEGIN */
+.auth-notice{
+ margin: .2rem 0 .65rem;
+ padding: .55rem .7rem;
+ border-radius: 14px;
+ font-size: .82rem;
+ font-weight: 800;
+ line-height: 1.2;
+ border: 1px solid rgba(148,163,184,.35);
+ background: rgba(2,6,23,.22);
+ color: #e5e7eb;
+}
+
+.auth-notice-success{
+ background: rgba(34,197,94,0.14);
+ border-color: rgba(34,197,94,0.55);
+ color: #d1fae5;
+}
+
+.auth-notice-error{
+ background: rgba(248,113,113,0.14);
+ border-color: rgba(248,113,113,0.55);
+ color: #ffe4e6;
+}
+
+.auth-notice-warn{
+ background: rgba(251,191,36,0.12);
+ border-color: rgba(251,191,36,0.40);
+ color: #fffbeb;
+}
+
+body[data-theme="light"] .auth-notice{
+ background: rgba(255,255,255,0.92);
+ border-color: rgba(148,163,184,0.75);
+ color: #0b1220;
+}
+body[data-theme="light"] .auth-notice-success{ color:#0b1220; }
+body[data-theme="light"] .auth-notice-error{ color:#0b1220; }
+body[data-theme="light"] .auth-notice-warn{ color:#0b1220; }
+/* SW_AUTH_NOTICE:END */
diff --git a/src/styles/auth-toast.css b/src/styles/auth-toast.css
index f0daa28..232aa31 100644
--- a/src/styles/auth-toast.css
+++ b/src/styles/auth-toast.css
@@ -91,3 +91,14 @@ body[data-theme="light"] .sw-toast{
}
body[data-theme="light"] .sw-toast-icon{ background: rgba(255,255,255,.95); }
body[data-theme="light"] .sw-toast-x{ background: rgba(255,255,255,.95); }
+
+/* SW_TOAST_SUBACTIONS:BEGIN */
+.sw-toast-subactions{
+ max-width: 980px;
+ margin: 10px auto 0;
+ display:flex;
+ gap:10px;
+ justify-content:center;
+ pointer-events: auto;
+}
+/* SW_TOAST_SUBACTIONS:END */
diff --git a/src/styles/topbar.css b/src/styles/topbar.css
index 5926e5b..e661632 100644
--- a/src/styles/topbar.css
+++ b/src/styles/topbar.css
@@ -340,3 +340,151 @@ body[data-theme="light"] .sw-avatar{
}
/* SW_TOPBAR_POLISH:END */
+
+/* SW_TOPBAR_OVERFLOW_FIX:BEGIN */
+.topbar{
+ flex-wrap: wrap; /* ✅ allow wrap instead of overflowing right */
+ row-gap: .45rem;
+}
+
+.topbar-left{
+ display:flex;
+ align-items:center;
+ gap: .65rem;
+ min-width: 0; /* ✅ allow shrinking */
+}
+
+.title-block{ min-width:0; }
+.main-title, .sub-title{
+ max-width: 58vw;
+ overflow:hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.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;
+ 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);
+}
+
+.sw-auth-combo .sw-usertext{
+ min-width: 0;
+}
+
+.sw-auth-combo .sw-userhandle{
+ max-width: 120px;
+ overflow:hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.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-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{
+ display: flex;
+ align-items: center;
+ gap: .65rem;
+ min-width: 0;
+}
+
+.brand-under{
+ display: flex;
+ align-items: center;
+ gap: .5rem;
+ padding-left: 46px; /* aligns under title block visually */
+}
+
+/* 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: 52vw;
+ overflow: hidden;
+}
+
+/* Make user handle truncate instead of forcing width */
+.sw-userhandle{ max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.sw-userchip{ min-width: 0; }
+
+@media (max-width: 640px){
+ .main-title, .sub-title{ max-width: 62vw; }
+ .topbar-right{ max-width: 45vw; }
+ .brand-under{ padding-left: 0; }
+}
+/* SW_TOPBAR_ONE_LINE_FIX:END */
diff --git a/src/styles/topbar.css.bak.1766217948 b/src/styles/topbar.css.bak.1766217948
new file mode 100644
index 0000000..af2ccea
--- /dev/null
+++ b/src/styles/topbar.css.bak.1766217948
@@ -0,0 +1,425 @@
+.topbar{
+ position: sticky; top:0; z-index:100;
+ width:100%;
+ padding: .55rem .9rem;
+ display:flex; align-items:center; justify-content:space-between; gap:.6rem;
+ 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:hidden;
+}
+
+.logo-circle{
+ width:40px; height:40px; border-radius:50%; flex-shrink:0;
+ background-image:url("/icons/logo-master.png");
+ background-size:cover; background-position:center; background-repeat:no-repeat;
+ box-shadow: 0 0 10px rgba(37,99,235,.8), 0 0 18px rgba(56,189,248,.6);
+ color:transparent;
+}
+
+.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:flex; align-items:center; gap:.5rem; margin-left:auto; flex-wrap:wrap; }
+
+.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); }
+
+@media (max-width:640px){
+ .topbar{ padding:.5rem .7rem; border-bottom-left-radius:16px; border-bottom-right-radius:16px; }
+ .main-title{ font-size:1rem; }
+ .sub-title{ font-size:.7rem; }
+ .topbar-right{ width:100%; justify-content:flex-start; gap:.45rem; }
+}
+
+/* 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: .28rem .35rem;
+ border-radius: 999px;
+ background: rgba(2,6,23,.18);
+ border: 1px solid rgba(255,255,255,.14);
+ backdrop-filter: blur(10px);
+}
+
+/* User chip used by TopBar.jsx (missing styles before) */
+.sw-userchip{
+ display:flex;
+ align-items:center;
+ gap:.5rem;
+ padding:.28rem .55rem;
+ 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);
+}
+
+.sw-avatar{
+ width: 30px;
+ height: 30px;
+ border-radius: 999px;
+ 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;
+}
+.sw-avatar i{ font-size: 14px; }
+
+.sw-usertext{
+ display:flex;
+ flex-direction:column;
+ line-height: 1.05;
+ min-width: 0;
+}
+.sw-userline{
+ font-size: .72rem;
+ font-weight: 950;
+ color: #f9fafb;
+}
+.sw-userhandle{
+ font-size: .68rem;
+ font-weight: 800;
+ color: #dbeafe;
+ opacity: .92;
+ max-width: 160px;
+ overflow:hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+/* Mobile: dock becomes full width and nice */
+@media (max-width:640px){
+ .topbar-right{
+ width:100%;
+ border-radius: 16px;
+ justify-content: flex-start;
+ }
+}
+
+/* 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_TOPBAR_POLISH:END */
+
+/* SW_TOPBAR_OVERFLOW_FIX:BEGIN */
+.topbar{
+ flex-wrap: wrap; /* ✅ allow wrap instead of overflowing right */
+ row-gap: .45rem;
+}
+
+.topbar-left{
+ display:flex;
+ align-items:center;
+ gap: .65rem;
+ min-width: 0; /* ✅ allow shrinking */
+}
+
+.title-block{ min-width:0; }
+.main-title, .sub-title{
+ max-width: 58vw;
+ overflow:hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.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;
+ 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);
+}
+
+.sw-auth-combo .sw-usertext{
+ min-width: 0;
+}
+
+.sw-auth-combo .sw-userhandle{
+ max-width: 120px;
+ overflow:hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.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-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 */