diff --git a/src/hooks/useRegister.js b/src/hooks/useRegister.js
new file mode 100644
index 0000000..2a361af
--- /dev/null
+++ b/src/hooks/useRegister.js
@@ -0,0 +1,69 @@
+import { useState, useEffect } from "react";
+import {API_URL} from "../config/constants";
+
+
+export function useCheckLogin(login) {
+ const [checking, setChecking] = useState(false);
+ const [exists, setExists] = useState(false);
+
+ useEffect(() => {
+ if (!login || login.length < 3) {
+ setExists(false);
+ return;
+ }
+
+ const timer = setTimeout(async () => {
+ try {
+ setChecking(true);
+ const res = await fetch(`${API_URL}/api/v1/auth/check-login?login=${login}`);
+ const json = await res.json();
+ setExists(json.exists);
+ } catch (e) {
+ console.error(e);
+ } finally {
+ setChecking(false);
+ }
+ }, 400);
+
+ return () => clearTimeout(timer);
+ }, [login]);
+
+ return { checking, exists };
+}
+
+
+export function useRegister() {
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [success, setSuccess] = useState(false);
+
+ const register = async ({ name, login, password }) => {
+ setLoading(true);
+ setError(null);
+
+ try {
+ const res = await fetch(`${API_URL}/api/v1/auth/register`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ name, login, password }),
+ });
+
+ const data = await res.json();
+
+ if (!res.ok) {
+ throw new Error(data.message || "Ошибка регистрации");
+ }
+
+ setSuccess(true);
+ setTimeout(() => {
+ window.location.href = "/register";
+ }, 2500);
+ } catch (e) {
+ setError(e.message);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ return { register, loading, error, success };
+}
\ No newline at end of file
diff --git a/src/pages/AuthPage.jsx b/src/pages/AuthPage.jsx
new file mode 100644
index 0000000..6374036
--- /dev/null
+++ b/src/pages/AuthPage.jsx
@@ -0,0 +1,380 @@
+import { useState, useCallback } from "react";
+import MagnifierLogo from "../components/MagnifierLogo";
+import { useAuth } from "../hooks/useAuth";
+import { useRegister } from "../hooks/useRegister";
+import {API_URL, FLOAT_ICONS} from "../config/constants";
+import "../styles/global.css";
+import "../styles/auth.css";
+import likeSmile from '../assets/success.png';
+import { useEffect } from "react";
+import { useCheckLogin } from "../hooks/useRegister";
+
+// ─── helpers ──────────────────────────────────────────────────────────────────
+function getStrength(val) {
+ if (!val) return { level: 0, label: "", color: "transparent", cls: "" };
+ let s = 0;
+ if (val.length >= 6) s++;
+ if (val.length >= 10) s++;
+ if (/[A-Z]/.test(val) || /[0-9]/.test(val)) s++;
+ if (/[^A-Za-z0-9]/.test(val)) s++;
+ const labels = ["", "Слабый", "Средний", "Хороший", "Отличный"];
+ const colors = ["", "#ff6b6b", "#ffd166", "#2de0c8", "#2de0c8"];
+ const cls = ["", "sw", "sm", "ss", "ss"];
+ return { level: s, label: labels[s], color: colors[s], cls: cls[s] };
+}
+
+// ─── Shared eye button ────────────────────────────────────────────────────────
+function EyeBtn({ show, onToggle}) {
+ return (
+
+ );
+}
+
+// ─── Step dots ────────────────────────────────────────────────────────────────
+function StepDots({ current, total }) {
+ return (
+
+ {Array.from({ length: total }).map((_, i) => (
+
+ ))}
+
+ );
+}
+
+// ═══════════════════════════════════════════════════════════════════════════════
+// LOGIN FORM
+// ═══════════════════════════════════════════════════════════════════════════════
+function LoginForm({ onSwitchToRegister }) {
+ const [email, setEmail] = useState("");
+ const [password, setPassword] = useState("");
+ const [showPass, setShowPass] = useState(false);
+ const { login, loading, error } = useAuth();
+
+ return (
+
+
С возвращением
+
+
+
+
+
+
+ Нет аккаунта?{" "}
+
+
+
+ );
+}
+
+// ─── step 0+1: name + login + passwords ───────────────────────────────────────
+function RegStep01({ data, onChange, onNext }) {
+ const [show1, setShow1] = useState(false);
+ const [show2, setShow2] = useState(false);
+ const [errors, setErrors] = useState({});
+ const strength = getStrength(data.password);
+ const matched = data.password && data.password === data.password2;
+
+ const { checking: checkingLogin, exists: loginExists } = useCheckLogin(data.login);
+
+ const validate = () => {
+ const e = {};
+ if (!data.name.trim()) e.name = "Введите имя";
+ if (!data.login.trim()) e.login = "Введите логин";
+ else if (data.login.length < 3) e.login = "Минимум 3 символа";
+ if (data.password.length < 6) e.password = "Минимум 6 символов";
+ else if (data.password !== data.password2) e.password2 = "Пароли не совпадают";
+
+ setErrors(e);
+ return !Object.keys(e).length;
+ };
+
+ return (
+ <>
+
+
+
{
+ onChange("name", e.target.value);
+ setErrors(p => ({...p, name: ""}));
+ }}
+ autoComplete="off"
+ />
+ {errors.name &&
{errors.name}
}
+
+
+
+
+
{
+ onChange("login", e.target.value);
+ setErrors(p => ({...p, login: ""}));
+ }}
+ autoComplete="off"
+ />
+
+ {checkingLogin &&
Проверяем...
}
+
+ {!checkingLogin && data.login.length >= 3 && (
+
+ {loginExists ? "✗ Логин занят" : "✓ Логин свободен"}
+
+ )}
+
+ {errors.login &&
{errors.login}
}
+
+
+
+
+
+
+ {
+ onChange("password", e.target.value);
+ setErrors(p => ({...p, password: ""}));
+ }}
+ autoComplete="new-password"
+ />
+ setShow1(v => !v)}/>
+
+
+ {data.password && (
+ <>
+
+ {[0, 1, 2, 3].map(i => (
+
+ ))}
+
+
+ {strength.label}
+
+ >
+ )}
+
+ {errors.password &&
{errors.password}
}
+
+
+
+
+
+
+
+ {
+ onChange("password2", e.target.value);
+ setErrors(p => ({...p, password2: ""}));
+ }}
+ autoComplete="new-password"
+ />
+ setShow2(v => !v)}/>
+
+
+ {data.password2 && (
+
+ {matched ? "✓ Совпадают" : "✗ Не совпадают"}
+
+ )}
+
+ {errors.password2 &&
{errors.password2}
}
+
+
+
+ >
+ );
+}
+
+// ─── step 2: confirm ──────────────────────────────────────────────────────────
+function RegStep2({data, onSubmit, onBack, loading, error}) {
+ return (
+ <>
+
+
+ Имя
+ {data.name}
+
+
+
+ Логин
+ @{data.login}
+
+
+ {error && {error}
}
+
+
+ >
+ );
+}
+
+// ─── success ──────────────────────────────────────────────────────────────────
+function RegSuccess({name, onLogin}) {
+ return (
+
+

+
Добро пожаловать, {name}!
+
Аккаунт создан успешно.
+
+
+ );
+}
+
+function RegisterForm({onSwitchToLogin}) {
+ const [step, setStep] = useState(0);
+ const [form, setForm] = useState(
+ {name: "", login: "", password: "", password2: ""});
+ const {register, loading, error, success} = useRegister();
+
+ const setField = useCallback((key, val) => setForm(p => ({ ...p, [key]: val })), []);
+
+ if (success) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+
Создайте аккаунт
+
+
+ {step === 0 && (
+
setStep(1)} />
+ )}
+ {step === 1 && (
+ register({ name: form.name, login: form.login, password: form.password })}
+ onBack={() => setStep(0)}
+ loading={loading}
+ error={error}
+ />
+ )}
+
+ {step === 0 && (
+
+ Уже есть аккаунт?{" "}
+
+
+ )}
+
+ );
+}
+
+// ═══════════════════════════════════════════════════════════════════════════════
+// AUTH PAGE — единственная страница, переключает login ↔ register
+// ═══════════════════════════════════════════════════════════════════════════════
+export default function AuthPage() {
+ const [mode, setMode] = useState("login"); // "login" | "register"
+ const [animating, setAnimating] = useState(false);
+
+ const switchTo = (next) => {
+ if (animating) return;
+ setAnimating(true);
+ // Небольшая задержка — карточка уходит, потом приходит новая
+ setTimeout(() => {
+ setMode(next);
+ setAnimating(false);
+ }, 320);
+ };
+
+ return (
+
+
+
+ {FLOAT_ICONS.map(({ icon, delay, size, ...pos }, i) => (
+

+ ))}
+
+
+
+
+
+
+
+
Находка
+
+ {mode === "login"
+ ?
switchTo("register")} />
+ : switchTo("login")} />
+ }
+
+
+ );
+}
diff --git a/src/pages/LoginPage.jsx b/src/pages/LoginPage.jsx
deleted file mode 100644
index 9b2a347..0000000
--- a/src/pages/LoginPage.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { useState } from "react";
-import MagnifierLogo from "../components/MagnifierLogo";
-import { useAuth } from "../hooks/useAuth";
-import { FLOAT_ICONS } from "../config/constants";
-import { s } from "../styles/loginStyles";
-import "../styles/global.css";
-
-export default function LoginPage() {
- const [loginValue, setEmail] = useState("");
- const [password, setPassword] = useState("");
- const [showPass, setShowPass] = useState(false);
-
- const { login, loginGoogle, loginYandex, loginVK, loading, error } = useAuth();
-
- return (
-
-
-
-
- {FLOAT_ICONS.map(({ icon, delay, size, ...pos }, i) => (
-

- ))}
-
-
-
-
-
-
-
-
-
Находка
-
-
-
-
-
-
- Нет аккаунта? Зарегистрироваться
-
-
-
-
- );
-}
\ No newline at end of file
diff --git a/src/styles/auth.css b/src/styles/auth.css
new file mode 100644
index 0000000..d7f5ec4
--- /dev/null
+++ b/src/styles/auth.css
@@ -0,0 +1,289 @@
+@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800;900&display=swap');
+
+/* ─── Page ──────────────────────────────────────────────────────────────────── */
+.auth-page {
+ font-family: 'Nunito', sans-serif;
+ min-height: 100vh;
+ display: flex; align-items: center; justify-content: center;
+ background: radial-gradient(ellipse at 30% 40%, #1a2340 0%, #0d1018 60%);
+ overflow: hidden; position: relative;
+}
+
+.bg-glow {
+ position: fixed; top: 40%; right: 0;
+ width: 500px; height: 400px;
+ background: radial-gradient(ellipse, #0f2a22 0%, transparent 70%);
+ pointer-events: none; opacity: 0.7;
+}
+
+/* ─── Floating icons ────────────────────────────────────────────────────────── */
+.fi {
+ position: fixed;
+ opacity: 0.13;
+ pointer-events: none;
+ user-select: none;
+ animation: float 7s ease-in-out infinite;
+}
+@keyframes float {
+ 0%, 100% { transform: translateY(0) rotate(-6deg); }
+ 50% { transform: translateY(-18px) rotate(6deg); }
+}
+
+/* ─── Card ──────────────────────────────────────────────────────────────────── */
+.auth-card {
+ position: relative; z-index: 10; width: 375px;
+ background: linear-gradient(155deg, #1d2436 0%, #131720 100%);
+ border: 1px solid rgba(255,255,255,0.08);
+ border-radius: 30px; padding: 36px 38px 30px;
+ box-shadow: 0 40px 100px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.03);
+ /* height transition — карточка плавно меняет размер при смене формы */
+ transition: height 0.35s ease;
+ overflow: hidden;
+}
+
+/* Появление карточки / контента */
+.card-in {
+ animation: cardIn .45s cubic-bezier(.34,1.56,.64,1) both;
+}
+@keyframes cardIn {
+ from { opacity: 0; transform: scale(.92) translateY(30px); }
+ to { opacity: 1; transform: scale(1) translateY(0); }
+}
+
+/* Уход карточки при переключении */
+.card-out {
+ animation: cardOut .3s cubic-bezier(.4,0,.6,1) both;
+}
+@keyframes cardOut {
+ from { opacity: 1; transform: scale(1) translateY(0); }
+ to { opacity: 0; transform: scale(.94) translateY(-20px); }
+}
+
+/* Контент формы — появляется снизу при смене */
+.form-body {
+ animation: formIn .4s cubic-bezier(.34,1.56,.64,1) both;
+}
+@keyframes formIn {
+ from { opacity: 0; transform: translateY(22px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+/* Переход между шагами регистрации */
+@keyframes stepIn {
+ from { opacity: 0; transform: translateX(18px) scale(.98); }
+ to { opacity: 1; transform: translateX(0) scale(1); }
+}
+
+/* ─── Logo ──────────────────────────────────────────────────────────────────── */
+.logo-wrap { text-align: center; margin-bottom: 2px; }
+
+@keyframes logoPulse {
+ 0%, 100% { filter: drop-shadow(0 0 18px rgba(45,224,200,.45)); }
+ 50% { filter: drop-shadow(0 0 38px rgba(45,224,200,.8)); }
+}
+/* Apply this class to your MagnifierLogo svg if needed */
+.logo-pulse { animation: logoPulse 3s ease-in-out infinite; }
+
+/* ─── Typography ────────────────────────────────────────────────────────────── */
+.auth-title {
+ text-align: center; color: #fff;
+ font-size: 2rem; font-weight: 900;
+ letter-spacing: -0.5px; margin: 12px 0 0;
+}
+.form-subtitle {
+ text-align: center; color: rgba(255,255,255,0.35);
+ font-size: 0.83rem; margin: 4px 0 20px;
+}
+
+/* ─── Step dots ─────────────────────────────────────────────────────────────── */
+.step-dots {
+ display: flex; align-items: center; justify-content: center;
+ gap: 6px; margin-bottom: 18px;
+}
+.dot {
+ width: 8px; height: 8px; border-radius: 50%;
+ background: rgba(255,255,255,0.15);
+ transition: all 0.35s cubic-bezier(.34,1.56,.64,1);
+}
+.dot-active {
+ width: 26px; border-radius: 4px;
+ background: #2de0c8;
+}
+.dot-done {
+ background: rgba(45,224,200,0.4);
+}
+
+/* ─── Fields ────────────────────────────────────────────────────────────────── */
+.field-wrap { margin-bottom: 12px; }
+
+.field-label {
+ display: block; color: rgba(255,255,255,0.45);
+ font-size: 0.73rem; font-weight: 700;
+ letter-spacing: 0.6px; margin-bottom: 5px;
+ text-transform: uppercase; font-family: 'Nunito', sans-serif;
+}
+
+.field {
+ width: 100%; box-sizing: border-box;
+ background: rgba(255,255,255,0.055);
+ border: 1.5px solid rgba(255,255,255,0.09);
+ border-radius: 14px; padding: 13px 18px;
+ color: #fff; font-family: 'Nunito', sans-serif;
+ font-size: 0.93rem; outline: none;
+ transition: border-color .2s, background .2s, box-shadow .2s;
+}
+.field:focus {
+ border-color: #2de0c8;
+ background: rgba(45,224,200,.07);
+ box-shadow: 0 0 0 3px rgba(45,224,200,.12);
+}
+.field::placeholder { color: rgba(255,255,255,.32); }
+
+.field-err { border-color: rgba(255,107,107,0.55) !important; box-shadow: 0 0 0 3px rgba(255,107,107,0.09) !important; }
+.field-ok { border-color: rgba(45,224,200,0.45) !important; }
+
+.eye-btn {
+ position: absolute; right: 13px; top: 50%;
+ transform: translateY(-50%);
+ background: none; border: none; cursor: pointer;
+ color: rgba(255,255,255,0.35); font-size: 1.05rem; line-height: 1;
+ padding: 0;
+}
+
+.input-wrap {
+ position: relative;
+}
+
+.input-wrap .eye-btn {
+ position: absolute;
+ right: 13px;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+.input-wrap .field {
+ padding-right: 44px;
+}
+
+/* ─── Password strength ──────────────────────────────────────────────────────── */
+.strength-bar { display: flex; gap: 4px; margin-top: 7px; }
+.seg {
+ flex: 1; height: 3px; border-radius: 2px;
+ background: rgba(255,255,255,0.1);
+ transition: background 0.3s;
+}
+.sw { background: #ff6b6b; }
+.sm { background: #ffd166; }
+.ss { background: #2de0c8; }
+.strength-label { font-size: 0.72rem; text-align: right; margin-top: 3px; }
+
+/* ─── Messages ──────────────────────────────────────────────────────────────── */
+.err-msg {
+ color: #ff6b6b; font-size: 0.8rem;
+ margin-top: 5px; padding-left: 2px;
+ font-family: 'Nunito', sans-serif;
+}
+
+/* ─── Confirm box ───────────────────────────────────────────────────────────── */
+.confirm-box {
+ background: rgba(255,255,255,0.04);
+ border: 1px solid rgba(255,255,255,0.08);
+ border-radius: 18px; padding: 16px 20px; margin-bottom: 14px;
+}
+.confirm-row { display: flex; justify-content: space-between; align-items: center; }
+.confirm-label { color: rgba(255,255,255,0.4); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.5px; }
+.confirm-val { color: #fff; font-weight: 700; }
+.confirm-val.accent { color: #2de0c8; }
+.confirm-divider { height: 1px; background: rgba(255,255,255,0.06); margin: 10px 0; }
+
+/* ─── Buttons ───────────────────────────────────────────────────────────────── */
+.btn-primary {
+ width: 100%;
+ background: linear-gradient(90deg, #1fc9b0, #2de0c8, #1fc9b0);
+ background-size: 200% 100%;
+ border: none; border-radius: 14px; padding: 15px;
+ color: #082320; font-family: 'Nunito', sans-serif;
+ font-size: 1.05rem; font-weight: 900; cursor: pointer;
+ margin-top: 6px;
+ box-shadow: 0 6px 24px rgba(45,224,200,0.32);
+ animation: shimmer 3s linear infinite;
+ transition: opacity .15s, transform .15s;
+}
+.btn-primary:hover:not(:disabled) { opacity: .88; transform: translateY(-2px); }
+.btn-primary:active:not(:disabled) { transform: translateY(0); }
+.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }
+
+@keyframes shimmer {
+ 0% { background-position: 200% 0; }
+ 100% { background-position: -200% 0; }
+}
+
+.ghost-btn {
+ display: block; width: 100%; text-align: center;
+ color: #2de0c8; font-size: 0.87rem; margin-top: 13px;
+ background: none; border: none; cursor: pointer;
+ font-family: 'Nunito', sans-serif;
+ transition: opacity .15s;
+}
+.ghost-btn:hover { opacity: 0.75; }
+
+.back-btn {
+ display: block; width: 100%; text-align: center;
+ color: rgba(255,255,255,0.35); font-size: 0.85rem; margin-top: 11px;
+ background: none; border: none; cursor: pointer;
+ font-family: 'Nunito', sans-serif;
+ transition: color .15s;
+}
+.back-btn:hover { color: rgba(255,255,255,0.6); }
+
+/* ─── Switch row ────────────────────────────────────────────────────────────── */
+.switch-row {
+ text-align: center; color: rgba(255,255,255,0.4);
+ font-size: 0.87rem; margin-top: 13px;
+}
+.link-btn {
+ color: #2de0c8; background: none; border: none;
+ cursor: pointer; font-family: 'Nunito', sans-serif;
+ font-size: inherit; font-weight: 700; padding: 0;
+ transition: opacity .15s;
+}
+.link-btn:hover { opacity: 0.75; text-decoration: underline; }
+
+/* ─── Dots btn ──────────────────────────────────────────────────────────────── */
+.dots-btn {
+ position: absolute; top: 18px; right: 20px;
+ background: none; border: none;
+ color: rgba(255,255,255,0.25); font-size: 1.3rem;
+ cursor: pointer; letter-spacing: 3px;
+}
+
+/* ─── Success ───────────────────────────────────────────────────────────────── */
+.success-wrap { text-align: center; padding: 16px 0 8px; }
+.success-icon {
+ font-size: 3.8rem; display: block; margin-bottom: 14px;
+ animation: pop .55s cubic-bezier(.34,1.56,.64,1) both;
+}
+@keyframes pop {
+ from { transform: scale(0) rotate(-20deg); opacity: 0; }
+ to { transform: scale(1) rotate(0deg); opacity: 1; }
+}
+.success-title { color: #2de0c8; font-size: 1.45rem; font-weight: 900; margin-bottom: 6px; }
+.success-sub { color: rgba(255,255,255,0.4); font-size: 0.88rem; line-height: 1.5; }
+
+.success-wrap {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+.success-icon {
+ background-color: #2de0c8;
+ -webkit-mask: url("../assets/success.png") no-repeat center;
+ mask: url("../assets/success.png") no-repeat center;
+}
+
+.logoSvg {
+ width: 130px;
+ height: 130px;
+ animation: logoPulse 3s ease-in-out infinite;
+}
\ No newline at end of file
diff --git a/src/styles/loginStyles.js b/src/styles/loginStyles.js
deleted file mode 100644
index ba45b63..0000000
--- a/src/styles/loginStyles.js
+++ /dev/null
@@ -1,88 +0,0 @@
-export const s = {
- page: {
- fontFamily: "'Nunito', sans-serif",
- minHeight: "100vh",
- display: "flex", alignItems: "center", justifyContent: "center",
- background: "radial-gradient(ellipse at 30% 40%, #1a2340 0%, #0d1018 60%)",
- overflow: "hidden", position: "relative",
- },
- bgGlow: {
- position: "fixed", top: "40%", right: 0,
- width: "500px", height: "400px",
- background: "radial-gradient(ellipse, #0f2a22 0%, transparent 70%)",
- pointerEvents: "none", opacity: 0.7,
- },
- card: {
- position: "relative", zIndex: 10, width: "360px",
- background: "linear-gradient(155deg, #1d2436 0%, #131720 100%)",
- border: "1px solid rgba(255,255,255,0.08)",
- borderRadius: "30px", padding: "40px 38px 34px",
- boxShadow: "0 40px 100px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.03)",
- },
- dotsBtn: {
- position: "absolute", top: "18px", right: "20px",
- background: "none", border: "none",
- color: "rgba(255,255,255,0.25)", fontSize: "1.3rem",
- cursor: "pointer", letterSpacing: "3px",
- },
- logoWrap: { textAlign: "center", marginBottom: "2px" },
- logoSvg: {
- width: "130px", height: "130px",
- animation: "logoPulse 3s ease-in-out infinite",
- },
- title: {
- textAlign: "center", color: "#fff",
- fontSize: "2rem", fontWeight: 900,
- letterSpacing: "-0.5px", margin: "14px 0 26px",
- },
- inputWrap: { marginBottom: "13px" },
- input: {
- width: "100%", boxSizing: "border-box",
- background: "rgba(255,255,255,0.055)",
- border: "1.5px solid rgba(255,255,255,0.09)",
- borderRadius: "14px", padding: "14px 18px",
- color: "#fff", fontFamily: "'Nunito', sans-serif",
- fontSize: "0.93rem", outline: "none",
- },
- eyeBtn: {
- position: "absolute", right: "13px", top: "50%",
- transform: "translateY(-50%)",
- background: "none", border: "none", cursor: "pointer",
- color: "rgba(255,255,255,0.35)", fontSize: "1.05rem", lineHeight: 1,
- },
- errMsg: {
- color: "#ff6b6b", fontSize: "0.83rem",
- textAlign: "center", margin: "6px 0 10px",
- },
- btnLogin: {
- width: "100%",
- background: "linear-gradient(90deg, #1fc9b0, #2de0c8, #1fc9b0)",
- backgroundSize: "200% 100%",
- border: "none", borderRadius: "14px", padding: "15px",
- color: "#082320", fontFamily: "'Nunito', sans-serif",
- fontSize: "1.05rem", fontWeight: 900, cursor: "pointer", marginTop: "6px",
- boxShadow: "0 6px 24px rgba(45,224,200,0.35)",
- animation: "shimmer 3s linear infinite",
- },
- forgotBtn: {
- display: "block", width: "100%", textAlign: "center",
- color: "#2de0c8", fontSize: "0.87rem", marginTop: "14px",
- background: "none", border: "none", cursor: "pointer",
- fontFamily: "'Nunito', sans-serif",
- },
- regRow: {
- textAlign: "center", color: "rgba(255,255,255,0.4)",
- fontSize: "0.87rem", marginTop: "9px",
- },
- link: { color: "#2de0c8", textDecoration: "none" },
- divider: { display: "flex", alignItems: "center", gap: "10px", margin: "18px 0 14px" },
- divText: { color: "rgba(255,255,255,0.25)", fontSize: "0.78rem" },
- socials: { display: "flex", gap: "10px" },
- socBtn: {
- flex: 1, padding: "11px 0", borderRadius: "12px",
- border: "1.5px solid rgba(255,255,255,0.09)",
- background: "rgba(255,255,255,0.04)",
- cursor: "pointer", fontWeight: 800,
- fontFamily: "'Nunito', sans-serif", fontSize: "0.88rem", color: "#fff",
- },
-};
\ No newline at end of file