+ {/* Top Workspace Header Selector */}
+
- {/* Profile Card */}
- {user && (
-
-
- Trader Profile
-
-
-
- User: {user.username}
-
-
- Email: {user.email}
-
-
- Role: {user.role}
-
-
- Verified:{' '}
- {user.is_verified ? 'Yes' : 'No'}
-
-
+ {/* Search Input Box */}
+
- {/* Navigation Links */}
-
-
+
+
+
+
+
+ Explore Markets
+
+
-
- {/* Logout Button */}
-
{
- e.currentTarget.style.background = 'rgba(239, 68, 68, 0.2)';
- }}
- onMouseOut={(e) => {
- e.currentTarget.style.background = 'rgba(239, 68, 68, 0.1)';
- }}
- >
- Logout
-
+ {/* Pinned Logout Button at Bottom of Sidebar */}
+
+
+
+ Log Out
+
+
);
};
diff --git a/src/components/StockSearchBar.tsx b/src/components/StockSearchBar.tsx
new file mode 100644
index 0000000..cf7cbdd
--- /dev/null
+++ b/src/components/StockSearchBar.tsx
@@ -0,0 +1,155 @@
+import React, { useState, useEffect, useRef } from 'react';
+import { Search, X, Check, Plus } from 'lucide-react';
+import { marketService, type StockSearchResult } from '@/services/market.service';
+import '@/styles/components/stock-search-bar.css';
+
+interface StockSearchBarProps {
+ onAddStock: (symbol: string) => Promise
;
+ existingHoldings?: string[];
+ placeholder?: string;
+}
+
+export const StockSearchBar: React.FC = ({
+ onAddStock,
+ existingHoldings = [],
+ placeholder = 'Search stocks by name or ticker...',
+}) => {
+ const [query, setQuery] = useState('');
+ const [results, setResults] = useState([]);
+ const [isLoading, setIsLoading] = useState(false);
+ const [isOpen, setIsOpen] = useState(false);
+ const [addingSymbol, setAddingSymbol] = useState(null);
+
+ const containerRef = useRef(null);
+
+ // Debounced search logic (300ms)
+ useEffect(() => {
+ if (!query.trim()) {
+ setResults([]);
+ setIsLoading(false);
+ setIsOpen(false);
+ return;
+ }
+
+ setIsLoading(true);
+ const timer = setTimeout(async () => {
+ try {
+ const searchResults = await marketService.searchStocks(query);
+ setResults(searchResults);
+ setIsOpen(true);
+ } catch (err) {
+ console.error('Failed to search stocks:', err);
+ setResults([]);
+ } finally {
+ setIsLoading(false);
+ }
+ }, 300);
+
+ return () => clearTimeout(timer);
+ }, [query]);
+
+ // Click outside listener to close dropdown
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
+ setIsOpen(false);
+ }
+ };
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => document.removeEventListener('mousedown', handleClickOutside);
+ }, []);
+
+ const handleAdd = async (symbol: string) => {
+ setAddingSymbol(symbol);
+ try {
+ await onAddStock(symbol);
+ setIsOpen(false);
+ setQuery('');
+ } finally {
+ setAddingSymbol(null);
+ }
+ };
+
+ return (
+
+
+
+
+
+
setQuery(e.target.value)}
+ placeholder={placeholder}
+ onFocus={() => {
+ if (results.length > 0) setIsOpen(true);
+ }}
+ />
+ {isLoading ? (
+
+ ) : (
+ query && (
+
{
+ setQuery('');
+ setResults([]);
+ setIsOpen(false);
+ }}
+ >
+
+
+ )
+ )}
+
+
+ {isOpen && (
+
+ {results.length === 0 ? (
+
No matching stocks found for "{query}"
+ ) : (
+ results.map((stock) => {
+ const isAdded = existingHoldings.includes(stock.symbol);
+ const isAdding = addingSymbol === stock.symbol;
+
+ return (
+
+
+
+ {stock.symbol}
+ {stock.exchange && (
+ {stock.exchange}
+ )}
+
+
+ {stock.name}
+
+
+
+
handleAdd(stock.symbol)}
+ >
+ {isAdding ? (
+ 'Adding...'
+ ) : isAdded ? (
+
+ Added
+
+ ) : (
+
+ Add
+
+ )}
+
+
+ );
+ })
+ )}
+
+ )}
+
+ );
+};
diff --git a/src/features/globe/GlobeView.tsx b/src/features/globe/GlobeView.tsx
index 0ac459e..c6f2445 100644
--- a/src/features/globe/GlobeView.tsx
+++ b/src/features/globe/GlobeView.tsx
@@ -1,6 +1,5 @@
import React, { useRef } from 'react';
import { useGlobe } from './useGlobe';
-import { NATIONS } from './nations.constants';
import { useNavigate } from 'react-router-dom';
import { ROUTES } from '@/constants/routes.constants';
import '@/styles/components/overlay.css';
diff --git a/src/features/globe/useGlobe.ts b/src/features/globe/useGlobe.ts
index f30f812..ee05d4f 100644
--- a/src/features/globe/useGlobe.ts
+++ b/src/features/globe/useGlobe.ts
@@ -1,6 +1,6 @@
import { useEffect, useRef, useState, type RefObject } from 'react';
import Globe, { type GlobeInstance } from 'globe.gl';
-import type { GeoJSON, GeoFeature, Coordinate, PathData, LabelData } from '@/types/globe.types';
+import type { GeoJSON, GeoFeature } from '@/types/globe.types';
import { NATIONS } from './nations.constants';
import { GLOBE_CONFIG } from './globe.constants';
diff --git a/src/index.css b/src/index.css
index 0df55a9..1d38849 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,16 +1,17 @@
/* Reset margins and set core black backgrounds */
-body {
+html, body {
margin: 0;
padding: 0;
background-color: #000;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
- overflow: auto;
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
+ overflow-x: hidden;
color: #fff;
+ width: 100%;
}
#root {
- width: 100vw;
- height: 100vh;
+ width: 100%;
+ min-height: 100vh;
}
/* ==========================================================================
diff --git a/src/pages/LiveMarketDashboard.tsx b/src/pages/LiveMarketDashboard.tsx
index aaf10ed..ee6a80e 100644
--- a/src/pages/LiveMarketDashboard.tsx
+++ b/src/pages/LiveMarketDashboard.tsx
@@ -1,18 +1,40 @@
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
+import {
+ ChevronDown,
+ SlidersHorizontal,
+ LayoutGrid,
+ MoreHorizontal,
+ CheckCircle2,
+ Plus,
+ Check,
+ TrendingUp,
+ TrendingDown,
+} from 'lucide-react';
import { useUserStore } from '@/stores/userStore';
import { portfolioService } from '@/services/portfolio.service';
import { Sidebar } from '@/components/Sidebar';
+import { StockSearchBar } from '@/components/StockSearchBar';
import { ROUTES } from '@/constants/routes.constants';
import '@/styles/components/live-market.css';
const MARKET_WS_URL = import.meta.env.VITE_MARKET_WS_BASE_URL || 'ws://localhost:8001';
+interface MarketStock {
+ symbol: string;
+ price: number;
+ percent_change: number;
+}
+
export const LiveMarketDashboard: React.FC = () => {
const navigate = useNavigate();
- const [marketData, setMarketData] = useState({ gainers: [], losers: [] });
- const [activeTab, setActiveTab] = useState('Stocks');
+ const [marketData, setMarketData] = useState<{ gainers: MarketStock[]; losers: MarketStock[] }>({
+ gainers: [],
+ losers: [],
+ });
+ const [activeMarketTab, setActiveMarketTab] = useState<'gainers' | 'losers' | 'all'>('gainers');
const [portfolioHoldings, setPortfolioHoldings] = useState([]);
+ const [searchQuery] = useState('');
const [feedback, setFeedback] = useState<{ message: string; type: 'success' | 'error' } | null>(
null,
);
@@ -31,7 +53,6 @@ export const LiveMarketDashboard: React.FC = () => {
ws.onmessage = (event) => {
try {
const liveData = JSON.parse(event.data);
- console.log('Live Update Received:', liveData);
setMarketData(liveData);
} catch (err) {
console.error('Error parsing websocket message', err);
@@ -53,14 +74,13 @@ export const LiveMarketDashboard: React.FC = () => {
const data = await portfolioService.getPortfolio();
setPortfolioHoldings(data.holdings.map((h) => h.symbol));
} catch (err) {
- // 404 is normal if they haven't configured a portfolio yet
+ // 404 is normal if portfolio is not yet created
}
};
const handleAddStockToPortfolio = async (symbol: string) => {
setFeedback(null);
try {
- // Step 1: Create a default portfolio if they don't have one
try {
await portfolioService.getPortfolio();
} catch (err: any) {
@@ -71,14 +91,16 @@ export const LiveMarketDashboard: React.FC = () => {
}
}
- // Step 2: Add the holding
await portfolioService.addHolding(symbol);
setPortfolioHoldings((prev) => [...prev, symbol]);
- setFeedback({ message: `Successfully added ${symbol} to your portfolio!`, type: 'success' });
+ setFeedback({ message: `Successfully added ${symbol} to portfolio!`, type: 'success' });
setTimeout(() => setFeedback(null), 4000);
} catch (err: any) {
- const errorMsg = err.response?.data?.detail || `Failed to add ${symbol} to portfolio.`;
+ const errorMsg =
+ typeof err.response?.data?.detail === 'string'
+ ? err.response.data.detail
+ : err.message || `Failed to add ${symbol} to portfolio.`;
setFeedback({ message: errorMsg, type: 'error' });
setTimeout(() => setFeedback(null), 5000);
}
@@ -86,9 +108,6 @@ export const LiveMarketDashboard: React.FC = () => {
const formatPrice = (price: number) => {
if (!price) return '0.00';
- if (Math.abs(price) < 0.01) {
- return price.toExponential(5);
- }
return price.toFixed(2);
};
@@ -97,291 +116,252 @@ export const LiveMarketDashboard: React.FC = () => {
return percent.toFixed(2);
};
- const getInitials = (symbol: string) => {
- return symbol.substring(0, 2).toUpperCase();
+ const filterStocks = (stocks: MarketStock[]) => {
+ if (!searchQuery.trim()) return stocks;
+ return stocks.filter((s) => s.symbol.toLowerCase().includes(searchQuery.toLowerCase()));
};
- const dashboardContent = (
-
- {/* Dynamic Feedback Banner */}
- {feedback && (
-
- {feedback.type === 'success' ? 'โ
' : 'โ ๏ธ '}
- {feedback.message}
-
- )}
-
- {/* Guest Logo Header */}
- {!isAuthenticated && (
-
-
-
-
- TRADING COPILOT
-
-
- navigate(ROUTES.LOGIN)}
+ const gainersList = filterStocks(marketData.gainers);
+ const losersList = filterStocks(marketData.losers);
+
+ return (
+
+ {/* Fixed Vercel Style Sidebar */}
+
+
+ {/* Main Content Area */}
+
+ {/* Toast Feedback */}
+ {feedback && (
+ {
- e.currentTarget.style.filter = 'brightness(1.1)';
- }}
- onMouseOut={(e) => {
- e.currentTarget.style.filter = 'none';
+ position: 'fixed',
+ top: '20px',
+ right: '20px',
+ zIndex: 1000,
+ padding: '10px 18px',
+ borderRadius: '6px',
+ fontWeight: 600,
+ fontSize: '13px',
+ background: feedback.type === 'success' ? '#00e599' : '#ff4444',
+ color: '#000000',
+ boxShadow: '0 4px 16px rgba(0,0,0,0.6)',
}}
>
- Login / Signup
-
+ {feedback.message}
+
+ )}
+
+ {/* Top Header Bar */}
+
- )}
-
-
-
-
-
- {['Stocks', 'Crypto', 'Futures', 'Forex', 'Economy', 'Brokers'].map((tab) => (
+
+ {/* Body Content */}
+
+ {/* Top Alerts Card */}
+
+
+
Get alerted for anomalies
+
+ Automatically monitor market volume and price anomalies and get notified instantly.
+
+
+ Upgrade to Pro
+
+
+
+
+
+ Live WebSocket Market Stream Active (NSE / NASDAQ)
+
+
+
+
+ {/* Narrow Line Tab Navigation Bar (Gainers / Losers / All) */}
+
setActiveTab(tab)}
+ className={`vercel-tab-line-btn ${activeMarketTab === 'gainers' ? 'active' : ''}`}
+ onClick={() => setActiveMarketTab('gainers')}
>
- {tab}
+
+ Stock Gainers
+ {gainersList.length}
- ))}
-
-
- {isAuthenticated && (
navigate(ROUTES.DASHBOARD)}
- style={{
- background: 'transparent',
- border: '1.5px solid #2a2a2a',
- color: '#2a2a2a',
- borderRadius: '40px',
- padding: '8px 16px',
- fontSize: '0.9rem',
- fontWeight: 600,
- cursor: 'pointer',
- transition: 'all 0.2s',
- }}
- onMouseOver={(e) => {
- e.currentTarget.style.background = '#2a2a2a';
- e.currentTarget.style.color = '#ffffff';
- }}
- onMouseOut={(e) => {
- e.currentTarget.style.background = 'transparent';
- e.currentTarget.style.color = '#2a2a2a';
- }}
+ className={`vercel-tab-line-btn ${activeMarketTab === 'losers' ? 'active' : ''}`}
+ onClick={() => setActiveMarketTab('losers')}
>
- Dashboard ๐
+
+ Stock Losers
+ {losersList.length}
- )}
-
-
-
-
- {/* Gainers */}
-
-
-
- {activeTab === 'Stocks' ? 'Stock' : activeTab} gainers
- >
-
-
-
- {marketData.gainers && marketData.gainers.length > 0 ? (
- marketData.gainers.map((stock: any) => (
-
-
-
{getInitials(stock.symbol)}
-
-
-
- {formatPrice(stock.price)}
-
- +{formatPercent(stock.percent_change)}%
-
- {isAuthenticated && (
- handleAddStockToPortfolio(stock.symbol)}
- disabled={
- portfolioHoldings.includes(stock.symbol) || portfolioHoldings.length >= 5
- }
- style={{
- background: portfolioHoldings.includes(stock.symbol)
- ? 'rgba(0, 0, 0, 0.05)'
- : 'var(--color-brand-teal, #0d9488)',
- color: portfolioHoldings.includes(stock.symbol) ? '#888' : '#fff',
- border: portfolioHoldings.includes(stock.symbol)
- ? '1px solid rgba(0, 0, 0, 0.1)'
- : 'none',
- borderRadius: '6px',
- padding: '6px 12px',
- fontSize: '0.8rem',
- fontWeight: 700,
- cursor: portfolioHoldings.includes(stock.symbol)
- ? 'not-allowed'
- : 'pointer',
- transition: 'all 0.2s',
- }}
- >
- {portfolioHoldings.includes(stock.symbol) ? 'โ Added' : '+ Add'}
-
- )}
-
-
- ))
- ) : (
-
Waiting for data...
- )}
-
-
- {/* Losers */}
-
-
-
- {activeTab === 'Stocks' ? 'Stock' : activeTab} losers
- >
-
-
-
- {marketData.losers && marketData.losers.length > 0 ? (
- marketData.losers.map((stock: any) => (
-
-
-
{getInitials(stock.symbol)}
-
-
-
- {formatPrice(stock.price)}
-
- {formatPercent(stock.percent_change)}%
-
- {isAuthenticated && (
- handleAddStockToPortfolio(stock.symbol)}
- disabled={
- portfolioHoldings.includes(stock.symbol) || portfolioHoldings.length >= 5
- }
- style={{
- background: portfolioHoldings.includes(stock.symbol)
- ? 'rgba(0, 0, 0, 0.05)'
- : 'var(--color-brand-teal, #0d9488)',
- color: portfolioHoldings.includes(stock.symbol) ? '#888' : '#fff',
- border: portfolioHoldings.includes(stock.symbol)
- ? '1px solid rgba(0, 0, 0, 0.1)'
- : 'none',
- borderRadius: '6px',
- padding: '6px 12px',
- fontSize: '0.8rem',
- fontWeight: 700,
- cursor: portfolioHoldings.includes(stock.symbol)
- ? 'not-allowed'
- : 'pointer',
- transition: 'all 0.2s',
- }}
- >
- {portfolioHoldings.includes(stock.symbol) ? 'โ Added' : '+ Add'}
-
- )}
-
-
- ))
- ) : (
-
Waiting for data...
- )}
+
setActiveMarketTab('all')}
+ >
+ All Stocks
+ {gainersList.length + losersList.length}
+
+
+ {/* Gainers Cards Grid */}
+ {(activeMarketTab === 'gainers' || activeMarketTab === 'all') && (
+
+ {activeMarketTab === 'all' && (
+
Stock Gainers ({gainersList.length})
+ )}
+
+ {gainersList.length > 0 ? (
+ gainersList.map((stock) => {
+ const isAdded = portfolioHoldings.includes(stock.symbol);
+ return (
+
+
+
+
+ {stock.symbol.slice(0, 2).toUpperCase()}
+
+
+
+
{stock.symbol}
+
+
+
NSE ยท Equity
+
+
+
+
+
+
+
+
+
+ ${formatPrice(stock.price)}
+
+ +{formatPercent(stock.percent_change)}%
+
+
+
+
+
handleAddStockToPortfolio(stock.symbol)}
+ >
+ {isAdded ? (
+
+ In Portfolio
+
+ ) : (
+
+ Add Stock
+
+ )}
+
+
+ );
+ })
+ ) : (
+
Streaming gainers...
+ )}
+
+
+ )}
+
+ {/* Losers Cards Grid */}
+ {(activeMarketTab === 'losers' || activeMarketTab === 'all') && (
+
+ {activeMarketTab === 'all' && (
+
Stock Losers ({losersList.length})
+ )}
+
+ {losersList.length > 0 ? (
+ losersList.map((stock) => {
+ const isAdded = portfolioHoldings.includes(stock.symbol);
+ return (
+
+
+
+
+ {stock.symbol.slice(0, 2).toUpperCase()}
+
+
+
+
{stock.symbol}
+
+
+
NSE ยท Equity
+
+
+
+
+
+
+
+
+
+ ${formatPrice(stock.price)}
+
+ {formatPercent(stock.percent_change)}%
+
+
+
+
+
handleAddStockToPortfolio(stock.symbol)}
+ >
+ {isAdded ? (
+
+ In Portfolio
+
+ ) : (
+
+ Add Stock
+
+ )}
+
+
+ );
+ })
+ ) : (
+
Streaming losers...
+ )}
+
+
+ )}
-
+
);
-
- if (isAuthenticated) {
- return (
-
- );
- }
-
- return dashboardContent;
};
diff --git a/src/services/market.service.ts b/src/services/market.service.ts
new file mode 100644
index 0000000..a6ec9d3
--- /dev/null
+++ b/src/services/market.service.ts
@@ -0,0 +1,19 @@
+import { marketApiClient } from '@/lib/api.client';
+
+export interface StockSearchResult {
+ symbol: string;
+ name: string;
+ exchange?: string;
+ quote_type?: string;
+}
+
+export const marketService = {
+ // Search for stock symbols by company name or ticker
+ async searchStocks(query: string): Promise
{
+ if (!query || !query.trim()) return [];
+ const { data } = await marketApiClient.get('/dashboard/search', {
+ params: { q: query.trim() },
+ });
+ return data;
+ },
+};
diff --git a/src/styles/components/auth-layout.css b/src/styles/components/auth-layout.css
index 8d98797..bb189bd 100644
--- a/src/styles/components/auth-layout.css
+++ b/src/styles/components/auth-layout.css
@@ -1,62 +1,47 @@
/* ==========================================================================
- Shared Authentication Layout Styles
+ Shared Authentication Layout Styles โ Vercel Monochromatic Dark Theme
========================================================================== */
-:root {
- --color-bg-left: #0b1120; /* Darker blue/black background for the left panel */
- --color-bg-right: #f8fafc; /* Very light gray/blue background for the right panel forms */
- --color-text-dark: #09090b;
- --color-text-muted: #64748b;
- --color-text-grey: #475569;
- --color-brand-teal: #0d9488;
- --color-brand-teal-hover: #0f766e;
- --color-border: #e2e8f0;
- --color-border-hover: #cbd5e1;
- --color-input-focus: #0d9488;
-}
-
.auth-screen-wrapper {
display: flex;
- width: 100vw;
+ width: 100%;
min-height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 100;
- background-color: var(--color-bg-right);
- color: var(--color-text-dark);
+ background-color: #000000;
+ color: #ededed;
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
/* Left Panel Style (Brand Showcase) */
.auth-left-panel {
flex: 1;
- background-color: var(--color-bg-left);
+ background: #050505;
+ border-right: 1px solid #1a1a1a;
padding: 48px;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
min-height: 100vh;
- color: #ffffff; /* Text is white on the dark left panel */
+ color: #ffffff;
+ box-sizing: border-box;
}
.brand-header {
display: flex;
align-items: center;
- gap: 8px;
+ gap: 10px;
color: #ffffff;
}
-.brand-logo-icon {
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
.brand-logo-text {
font-weight: 700;
font-size: 1.15rem;
- letter-spacing: -0.02em;
+ letter-spacing: -0.01em;
+ color: #ffffff;
}
.banner-image-container {
@@ -64,27 +49,28 @@
display: flex;
justify-content: center;
align-items: center;
- margin: 40px 0;
+ margin: 32px 0;
}
.banner-image {
max-width: 100%;
- max-height: 480px;
+ max-height: 420px;
object-fit: contain;
- border-radius: 12px;
- box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
+ border-radius: 8px;
+ border: 1px solid #1a1a1a;
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.8);
}
.banner-text-content {
display: flex;
flex-direction: column;
- gap: 16px;
- max-width: 520px;
+ gap: 12px;
+ max-width: 500px;
flex-grow: 1;
}
.banner-title {
- font-size: 2.5rem;
+ font-size: 2rem;
font-weight: 700;
line-height: 1.25;
color: #ffffff;
@@ -93,103 +79,94 @@
}
.banner-subtitle {
- font-size: 1rem;
+ font-size: 0.95rem;
line-height: 1.6;
- color: #94a3b8;
+ color: #888888;
margin: 0;
}
-.auth-left-footer {
- margin-top: 20px;
-}
-
.secure-badge {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.75rem;
- font-weight: 700;
+ font-weight: 600;
letter-spacing: 0.05em;
- color: var(--color-brand-teal);
-}
-
-.shield-icon {
- font-size: 1rem;
+ color: #0070f3;
}
/* Right Panel Style (Form Content) */
.auth-right-panel {
flex: 1;
- background-color: var(--color-bg-right);
+ background-color: #000000;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 48px;
min-height: 100vh;
- color: var(--color-text-dark);
position: relative;
+ box-sizing: border-box;
}
-/* Card layout for the form area to match screenshots */
.auth-form-card {
width: 100%;
- max-width: 440px;
- background: #ffffff;
- padding: 48px;
- border-radius: 12px;
- box-shadow:
- 0 4px 6px -1px rgba(0, 0, 0, 0.05),
- 0 2px 4px -1px rgba(0, 0, 0, 0.03);
+ max-width: 420px;
+ background: #0a0a0a;
+ border: 1px solid #1a1a1a;
+ padding: 40px;
+ border-radius: 8px;
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
- gap: 28px;
+ gap: 24px;
}
.auth-form-card.no-card {
background: transparent;
box-shadow: none;
+ border: none;
padding: 0;
}
.form-header {
display: flex;
flex-direction: column;
- gap: 8px;
+ gap: 6px;
}
.form-title {
- font-size: 2rem;
+ font-size: 1.75rem;
font-weight: 700;
- color: var(--color-text-dark);
+ color: #ffffff;
letter-spacing: -0.02em;
margin: 0;
}
.form-subtitle {
- font-size: 0.95rem;
- color: var(--color-text-muted);
+ font-size: 0.875rem;
+ color: #888888;
line-height: 1.5;
margin: 0;
}
-/* Form Styles */
+/* Form Controls */
.auth-form {
display: flex;
flex-direction: column;
- gap: 20px;
+ gap: 18px;
}
.input-group {
display: flex;
flex-direction: column;
- gap: 8px;
+ gap: 6px;
}
.input-label {
font-size: 0.85rem;
- font-weight: 600;
- color: var(--color-text-grey);
+ font-weight: 500;
+ color: #ededed;
}
.input-wrapper {
@@ -201,72 +178,69 @@
.auth-input-field {
width: 100%;
- padding: 12px 16px;
- font-size: 0.95rem;
- border: 1.5px solid var(--color-border);
- border-radius: 8px;
+ padding: 10px 14px;
+ font-size: 0.9rem;
+ font-family: inherit;
+ border: 1px solid #222222;
+ border-radius: 6px;
outline: none;
- background-color: #ffffff;
- color: var(--color-text-dark);
- transition:
- border-color 0.2s,
- box-shadow 0.2s;
+ background: #000000;
+ color: #ffffff;
+ transition: border-color 0.15s ease;
}
.auth-input-field.has-icon-right {
- padding-right: 48px;
+ padding-right: 42px;
}
.auth-input-field.has-icon-left {
- padding-left: 48px;
+ padding-left: 42px;
}
.auth-input-field:hover {
- border-color: var(--color-border-hover);
+ border-color: #333333;
}
.auth-input-field:focus {
- border-color: var(--color-input-focus);
- box-shadow: 0 0 0 3px rgba(13, 148, 136, 0.15);
+ border-color: #555555;
}
.auth-input-field::placeholder {
- color: #a1a1aa;
+ color: #555555;
}
-.input-icon-right {
+.input-icon-right,
+.input-icon-left {
position: absolute;
- right: 16px;
- color: #a1a1aa;
+ color: #666666;
display: flex;
align-items: center;
pointer-events: none;
}
+.input-icon-right {
+ right: 12px;
+}
+
.input-icon-left {
- position: absolute;
- left: 16px;
- color: #a1a1aa;
- display: flex;
- align-items: center;
- pointer-events: none;
+ left: 12px;
}
.input-icon-btn-right {
position: absolute;
- right: 16px;
- color: #a1a1aa;
+ right: 12px;
+ color: #666666;
background: none;
border: none;
cursor: pointer;
display: flex;
align-items: center;
outline: none;
- transition: color 0.15s;
+ transition: color 0.15s ease;
}
.input-icon-btn-right:hover {
- color: var(--color-text-dark);
+ color: #ffffff;
}
/* Actions Row */
@@ -282,61 +256,55 @@
align-items: center;
gap: 8px;
cursor: pointer;
- color: var(--color-text-grey);
- font-weight: 500;
+ color: #888888;
+ font-weight: 400;
}
.custom-checkbox {
- width: 16px;
- height: 16px;
- border-radius: 4px;
- border: 1.5px solid var(--color-border);
+ width: 15px;
+ height: 15px;
+ border-radius: 3px;
+ border: 1px solid #333333;
cursor: pointer;
- accent-color: var(--color-brand-teal);
+ accent-color: #ffffff;
}
.auth-link {
- color: var(--color-text-dark);
+ color: #0070f3;
text-decoration: none;
- font-weight: 600;
- transition: color 0.15s;
- font-size: 0.9rem;
+ font-weight: 500;
+ transition: color 0.15s ease;
+ font-size: 0.85rem;
}
.auth-link:hover {
text-decoration: underline;
}
-/* Submit Button */
+/* Submit Button โ Crisp White Vercel Style */
.auth-submit-btn {
width: 100%;
- padding: 14px;
- background-color: var(--color-brand-teal);
- color: white;
+ padding: 11px;
+ background: #ffffff;
+ color: #000000;
border: none;
- border-radius: 8px;
- font-size: 0.95rem;
+ border-radius: 6px;
+ font-size: 0.9rem;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
- transition:
- background-color 0.2s,
- transform 0.1s;
+ transition: opacity 0.15s ease;
}
.auth-submit-btn:hover:not(:disabled) {
- background-color: var(--color-brand-teal-hover);
-}
-
-.auth-submit-btn:active:not(:disabled) {
- transform: scale(0.995);
+ opacity: 0.9;
}
.auth-submit-btn:disabled {
- opacity: 0.7;
+ opacity: 0.5;
cursor: not-allowed;
}
@@ -344,17 +312,17 @@
display: flex;
align-items: center;
justify-content: center;
- gap: 8px;
- color: var(--color-text-grey);
+ gap: 6px;
+ color: #888888;
text-decoration: none;
- font-weight: 600;
+ font-weight: 500;
font-size: 0.85rem;
margin-top: 16px;
- transition: color 0.15s;
+ transition: color 0.15s ease;
}
.back-link:hover {
- color: var(--color-text-dark);
+ color: #ffffff;
}
/* Footer Copyright */
@@ -364,9 +332,9 @@
display: flex;
flex-direction: column;
align-items: center;
- gap: 12px;
+ gap: 8px;
font-size: 0.75rem;
- color: #94a3b8;
+ color: #666666;
}
.auth-footer-links {
@@ -375,16 +343,72 @@
}
.auth-footer-links a {
- color: #94a3b8;
+ color: #666666;
text-decoration: none;
- font-weight: 600;
+ font-weight: 500;
}
.auth-footer-links a:hover {
- color: var(--color-text-dark);
+ color: #ffffff;
+}
+
+/* Form Divider & Social Buttons (Vercel Style) */
+.form-divider {
+ display: flex;
+ align-items: center;
+ text-align: center;
+ margin: 16px 0;
+}
+
+.form-divider::before,
+.form-divider::after {
+ content: '';
+ flex: 1;
+ border-bottom: 1px solid #1a1a1a;
+}
+
+.divider-text {
+ padding: 0 12px;
+ font-size: 11px;
+ font-weight: 600;
+ color: #666666;
+}
+
+.google-oauth-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 10px;
+ width: 100%;
+ padding: 10px 14px;
+ background-color: #0a0a0a;
+ border: 1px solid #222222;
+ border-radius: 6px;
+ color: #ffffff;
+ font-size: 0.875rem;
+ font-weight: 500;
+ font-family: inherit;
+ cursor: pointer;
+ margin-top: 12px;
+ margin-bottom: 12px;
+ transition: all 0.15s ease;
+}
+
+.google-oauth-btn:hover {
+ background-color: #141414;
+ border-color: #333333;
+}
+
+.login-footer {
+ text-align: center;
+ font-size: 0.85rem;
+ color: #888888;
+}
+
+.footer-grey-text {
+ color: #888888;
}
-/* Responsive Breakpoints */
@media (max-width: 900px) {
.auth-left-panel {
display: none;
diff --git a/src/styles/components/dashboard.css b/src/styles/components/dashboard.css
index b3b0d6d..57e3807 100644
--- a/src/styles/components/dashboard.css
+++ b/src/styles/components/dashboard.css
@@ -1,6 +1,4 @@
-/* โโ Dashboard Page โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- * Styles for the post-login dashboard landing screen.
- * โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
+/* โโ Dashboard Page Modern Glassmorphism Styles โโ */
.dashboard-page {
min-height: 100vh;
@@ -9,9 +7,12 @@
flex-direction: column;
justify-content: center;
align-items: center;
- background-color: var(--color-bg-primary, #121212);
- color: var(--color-text-primary, #ffffff);
- font-family: var(--font-family-base);
+ background-color: var(--color-bg-primary, #060913);
+ background-image:
+ radial-gradient(circle at 50% 30%, rgba(16, 185, 129, 0.1) 0%, transparent 60%),
+ radial-gradient(circle at 80% 80%, rgba(6, 182, 212, 0.08) 0%, transparent 50%);
+ color: var(--color-text-primary, #f8fafc);
+ font-family: var(--font-family-base, 'Plus Jakarta Sans', sans-serif);
padding: var(--space-10, 40px);
text-align: center;
}
@@ -20,37 +21,53 @@
display: flex;
flex-direction: column;
align-items: center;
- gap: var(--space-4, 16px);
+ gap: var(--space-6, 24px);
+ max-width: 600px;
+ background: var(--color-bg-card, rgba(15, 23, 42, 0.65));
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
+ border: 1px solid var(--color-border-subtle, rgba(255, 255, 255, 0.08));
+ border-radius: var(--radius-xl, 20px);
+ padding: 48px;
+ box-shadow: var(--shadow-card, 0 16px 40px rgba(0, 0, 0, 0.5));
}
.dashboard-title {
- font-size: var(--font-size-3xl, 2.5rem);
- font-weight: var(--font-weight-bold, 700);
+ font-size: var(--font-size-3xl, 2.25rem);
+ font-weight: var(--font-weight-extrabold, 800);
+ background: linear-gradient(135deg, #ffffff 0%, #94a3b8 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ margin: 0;
}
.dashboard-subtitle {
- color: var(--color-text-secondary, #a1a1aa);
+ color: var(--color-text-secondary, #94a3b8);
font-size: var(--font-size-lg, 1.1rem);
+ line-height: 1.6;
+ margin: 0;
}
.logout-btn {
- margin-top: var(--space-2, 8px);
- padding: 12px 24px;
- background-color: var(--color-accent-teal, #006d65);
+ margin-top: var(--space-4, 16px);
+ padding: 14px 28px;
+ background: linear-gradient(135deg, var(--color-brand-teal, #10b981) 0%, #059669 100%);
color: #ffffff;
border: none;
- border-radius: var(--radius-md, 8px);
+ border-radius: var(--radius-md, 10px);
font-size: var(--font-size-base, 1rem);
- font-weight: var(--font-weight-semibold, 600);
+ font-weight: var(--font-weight-bold, 700);
cursor: pointer;
- transition: background-color var(--transition-fast, 0.2s);
+ box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
+ transition: filter var(--transition-fast), transform var(--transition-fast);
}
.logout-btn:hover {
- background-color: var(--color-accent-teal-hover, #00564e);
+ filter: brightness(1.15);
+ transform: translateY(-1px);
}
.logout-btn:focus-visible {
- outline: 2px solid var(--color-accent-white, #ffffff);
+ outline: 2px solid var(--color-brand-teal, #10b981);
outline-offset: 3px;
}
diff --git a/src/styles/components/live-market.css b/src/styles/components/live-market.css
index e2ed349..389217e 100644
--- a/src/styles/components/live-market.css
+++ b/src/styles/components/live-market.css
@@ -1,186 +1,386 @@
-/* Ultra-Precise Match to the User's Screenshot */
+/* โโ Vercel Style Market Dashboard โโ */
-@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
-
-.market-dashboard {
- background-color: var(--color-bg-primary, #0b1120);
+.vercel-dashboard-wrapper {
+ display: flex;
min-height: 100vh;
- padding: 30px 40px;
- color: var(--color-text-primary, #ffffff);
- font-family: 'Inter', sans-serif;
- box-sizing: border-box;
+ width: 100%;
+ overflow-x: hidden;
+ background-color: #000000;
+ color: #ededed;
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
}
-.top-nav {
+.vercel-dashboard-main {
+ flex: 1;
+ margin-left: 240px;
+ background-color: #000000;
display: flex;
- justify-content: center;
- margin-bottom: 40px;
+ flex-direction: column;
+ min-width: 0;
}
-.nav-pills {
+/* Vercel Header Bar */
+.vercel-header-bar {
display: flex;
- background: var(--color-bg-secondary, #0f172a);
- border: 1px solid var(--color-border-subtle, #1e293b);
- border-radius: 40px;
- padding: 4px;
- gap: 4px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px 24px;
+ border-bottom: 1px solid #1a1a1a;
+ background-color: #000000;
}
-.nav-pill {
+.vercel-header-left {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+}
+
+.vercel-dropdown-trigger {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 14px;
+ font-weight: 600;
+ color: #ffffff;
+ cursor: pointer;
background: transparent;
border: none;
- padding: 8px 16px;
- border-radius: 40px;
- font-size: 0.9rem;
- font-weight: 500;
- color: var(--color-text-secondary, #9ca3af);
- cursor: pointer;
- transition: all 0.2s ease;
}
-.nav-pill:hover {
- color: var(--color-text-primary, #ffffff);
+.vercel-header-right {
+ display: flex;
+ align-items: center;
+ gap: 12px;
}
-.nav-pill.active {
- background: var(--color-brand-teal, #0d9488);
+.vercel-search-input-wrapper {
+ position: relative;
+ width: 320px;
+}
+
+.vercel-search-input {
+ width: 100%;
+ background: #0a0a0a;
+ border: 1px solid #222222;
+ border-radius: 6px;
+ padding: 8px 12px 8px 32px;
color: #ffffff;
+ font-size: 13px;
+ font-family: inherit;
+ outline: none;
+ transition: border-color 0.15s ease;
}
-.market-sections {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 40px;
- max-width: 1300px;
+.vercel-search-input:focus {
+ border-color: #444444;
+}
+
+.vercel-search-icon {
+ position: absolute;
+ left: 10px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: #666666;
+ font-size: 13px;
+}
+
+.vercel-btn-white {
+ background: #ffffff;
+ color: #000000;
+ border: none;
+ border-radius: 6px;
+ padding: 8px 14px;
+ font-size: 13px;
+ font-weight: 600;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ transition: opacity 0.15s ease;
+}
+
+.vercel-btn-white:hover {
+ opacity: 0.9;
+}
+
+.vercel-btn-outline {
+ background: #0a0a0a;
+ color: #ededed;
+ border: 1px solid #222222;
+ border-radius: 6px;
+ padding: 8px 12px;
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ transition: border-color 0.15s ease;
+}
+
+.vercel-btn-outline:hover {
+ border-color: #444444;
+}
+
+/* Dashboard Body Content */
+.vercel-body-content {
+ padding: 24px 32px;
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+ max-width: 1400px;
margin: 0 auto;
+ width: 100%;
+ box-sizing: border-box;
}
-.market-list-section {
- background: var(--color-bg-secondary, #0f172a);
- border: 1px solid var(--color-border-subtle, #1e293b);
- border-radius: 16px;
+/* Alerts Banner Card (Vercel Style) */
+.vercel-alert-card {
+ background: #0a0a0a;
+ border: 1px solid #1a1a1a;
+ border-radius: 8px;
padding: 24px;
- box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ gap: 12px;
}
-.section-header {
- margin-bottom: 20px;
+.vercel-alert-title {
+ font-size: 14px;
+ font-weight: 600;
+ color: #ffffff;
+ margin: 0;
}
-.section-header h2 {
- font-size: 1.5rem;
- font-weight: 700;
+.vercel-alert-desc {
+ font-size: 13px;
+ color: #888888;
margin: 0;
- color: var(--color-text-primary, #ffffff);
- display: flex;
- align-items: center;
+ max-width: 320px;
+ line-height: 1.5;
}
-.heading-arrow {
- margin-left: 6px;
- font-size: 1.4rem;
+/* Projects / Markets Grid Header */
+.vercel-grid-section-title {
+ font-size: 14px;
font-weight: 600;
- color: var(--color-brand-teal, #0d9488);
+ color: #ffffff;
+ margin-bottom: 16px;
}
-.market-list {
- display: flex;
- flex-direction: column;
+.vercel-cards-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
+ gap: 16px;
}
-.market-row {
+/* Vercel Project Card Style */
+.vercel-stock-card {
+ background: #0a0a0a;
+ border: 1px solid #1a1a1a;
+ border-radius: 8px;
+ padding: 16px;
display: flex;
+ flex-direction: column;
justify-content: space-between;
- align-items: center;
- padding: 16px 0;
- border-bottom: 1px solid var(--color-border-subtle, #1e293b);
+ gap: 16px;
+ transition: border-color 0.15s ease, background 0.15s ease;
}
-.market-row:last-child {
- border-bottom: none;
+.vercel-stock-card:hover {
+ border-color: #2e2e2e;
+ background: #0d0d0d;
}
-.stock-info-col {
+.vercel-card-top {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+}
+
+.vercel-card-meta {
display: flex;
align-items: center;
gap: 12px;
- width: 220px;
}
-.stock-icon-circle {
- width: 38px;
- height: 38px;
- border-radius: 50%;
+.vercel-card-icon {
+ width: 32px;
+ height: 32px;
+ border-radius: 6px;
+ background: #161616;
+ border: 1px solid #262626;
display: flex;
align-items: center;
justify-content: center;
- color: #ffffff;
- font-size: 0.9rem;
+ font-size: 12px;
font-weight: 700;
- background-color: rgba(13, 148, 136, 0.15);
- border: 1px solid rgba(13, 148, 136, 0.3);
- text-transform: uppercase;
+ color: #ffffff;
+}
+
+.vercel-card-title-group {
+ display: flex;
+ flex-direction: column;
}
-.stock-ticker {
- background-color: rgba(255, 255, 255, 0.05);
- color: var(--color-text-secondary, #9ca3af);
- font-size: 0.7rem;
+.vercel-card-name {
+ font-size: 14px;
font-weight: 600;
+ color: #ffffff;
+ margin: 0;
+}
+
+.vercel-card-sub {
+ font-size: 12px;
+ color: #666666;
+ margin-top: 2px;
+}
+
+.vercel-verified-badge {
+ color: #0070f3;
+ font-size: 12px;
+}
+
+.vercel-card-more-btn {
+ background: transparent;
+ border: none;
+ color: #666666;
+ cursor: pointer;
+ font-size: 14px;
+ padding: 4px;
+}
+
+.vercel-card-more-btn:hover {
+ color: #ffffff;
+}
+
+.vercel-card-middle {
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+.vercel-ticker-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ background: #141414;
+ border: 1px solid #222222;
padding: 3px 8px;
- border-radius: 6px;
- display: inline-block;
+ border-radius: 12px;
+ font-size: 11px;
+ color: #888888;
+ font-family: var(--font-family-mono);
width: fit-content;
- text-transform: uppercase;
- letter-spacing: 0.5px;
- border: 1px solid rgba(255, 255, 255, 0.08);
}
-.stock-pricing-col {
+.vercel-card-stats {
display: flex;
align-items: center;
- gap: 12px;
- flex: 1;
- justify-content: flex-end;
+ justify-content: space-between;
+ margin-top: 4px;
}
-.stock-current-price {
- font-weight: 600;
- font-size: 0.95rem;
- color: var(--color-text-primary, #ffffff);
+.vercel-price {
+ font-family: var(--font-family-mono);
+ font-size: 14px;
+ font-weight: 700;
+ color: #ffffff;
}
-.stock-change-pill {
+.vercel-change-pill {
+ font-family: var(--font-family-mono);
+ font-size: 11px;
font-weight: 600;
- font-size: 0.8rem;
- padding: 4px 8px;
+ padding: 2px 6px;
+ border-radius: 4px;
+}
+
+.vercel-change-pill.positive {
+ color: #00e599;
+ background: rgba(0, 229, 153, 0.1);
+}
+
+.vercel-change-pill.negative {
+ color: #ff4444;
+ background: rgba(255, 68, 68, 0.1);
+}
+
+.vercel-add-btn {
+ width: 100%;
+ background: #141414;
+ border: 1px solid #262626;
+ color: #ededed;
+ padding: 6px 12px;
border-radius: 6px;
- min-width: 65px;
- text-align: center;
+ font-size: 12px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.12s ease;
}
-.stock-change-pill.positive {
- background-color: rgba(16, 185, 129, 0.15);
- color: #10b981;
- border: 1px solid rgba(16, 185, 129, 0.25);
+.vercel-add-btn:hover:not(:disabled) {
+ background: #ffffff;
+ color: #000000;
+ border-color: #ffffff;
}
-.stock-change-pill.negative {
- background-color: rgba(239, 68, 68, 0.15);
- color: #ef4444;
- border: 1px solid rgba(239, 68, 68, 0.25);
+.vercel-add-btn:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+ background: #111111;
+ color: #666666;
}
-.loading-state {
- text-align: center;
- padding: 40px;
- color: var(--color-text-secondary, #9ca3af);
+/* Narrow Line Tab Navigation (Gainers / Losers / All) */
+.vercel-tabs-line-bar {
+ display: flex;
+ align-items: center;
+ gap: 24px;
+ border-bottom: 1px solid #1a1a1a;
+ margin-top: 12px;
+ margin-bottom: 24px;
+}
+
+.vercel-tab-line-btn {
+ background: transparent;
+ border: none;
+ border-bottom: 2px solid transparent;
+ color: #888888;
+ font-size: 14px;
+ font-weight: 500;
+ font-family: inherit;
+ padding: 10px 4px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ transition: color 0.15s ease, border-color 0.15s ease;
+ margin-bottom: -1px;
+}
+
+.vercel-tab-line-btn:hover {
+ color: #ededed;
}
-@media (max-width: 1200px) {
- .market-sections {
- grid-template-columns: 1fr;
- gap: 40px;
- }
+.vercel-tab-line-btn.active {
+ color: #ffffff;
+ font-weight: 600;
+ border-bottom-color: #ffffff;
+}
+
+.vercel-tab-badge {
+ font-size: 11px;
+ font-weight: 600;
+ padding: 1px 7px;
+ border-radius: 12px;
+ background: #141414;
+ border: 1px solid #222222;
+ color: #888888;
+}
+
+.vercel-tab-line-btn.active .vercel-tab-badge {
+ background: #222222;
+ color: #ffffff;
+ border-color: #333333;
}
diff --git a/src/styles/components/portfolio.css b/src/styles/components/portfolio.css
index c2bcb25..b5f3fa8 100644
--- a/src/styles/components/portfolio.css
+++ b/src/styles/components/portfolio.css
@@ -1,113 +1,122 @@
-/* Portfolio View Styling - Sleek Glassmorphism Design */
+/* โโ Portfolio View Styling โ Glassmorphic Design โโ */
.portfolio-card {
- background: var(--color-bg-secondary);
- backdrop-filter: blur(16px);
- -webkit-backdrop-filter: blur(16px);
- border: 1px solid var(--color-border-subtle);
- border-radius: 16px;
- padding: 24px;
+ background: var(--color-bg-card, rgba(15, 23, 42, 0.65));
+ backdrop-filter: blur(20px);
+ -webkit-backdrop-filter: blur(20px);
+ border: 1px solid var(--color-border-subtle, rgba(255, 255, 255, 0.08));
+ border-radius: var(--radius-xl, 20px);
+ padding: 28px;
margin-top: 24px;
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
- color: #f3f4f6;
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
+ box-shadow: var(--shadow-card, 0 12px 32px rgba(0, 0, 0, 0.4));
+ color: var(--color-text-primary, #f8fafc);
+ transition: border-color var(--transition-base), box-shadow var(--transition-base);
+}
+
+.portfolio-card:hover {
+ border-color: var(--color-border-default, rgba(255, 255, 255, 0.16));
}
.portfolio-header {
display: flex;
justify-content: space-between;
align-items: center;
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
- padding-bottom: 16px;
- margin-bottom: 20px;
+ border-bottom: 1px solid var(--color-border-subtle, rgba(255, 255, 255, 0.08));
+ padding-bottom: 18px;
+ margin-bottom: 24px;
}
.portfolio-title {
font-size: 1.5rem;
- font-weight: 700;
- color: var(--color-text-primary);
+ font-weight: 800;
+ color: var(--color-text-primary, #ffffff);
margin: 0;
+ letter-spacing: -0.01em;
}
.portfolio-date {
font-size: 0.85rem;
- color: #9ca3af;
+ color: var(--color-text-muted, #64748b);
+ font-family: var(--font-family-mono, monospace);
}
/* Capacity Indicator */
.capacity-container {
- margin: 16px 0;
+ margin: 20px 0;
}
.capacity-label {
display: flex;
justify-content: space-between;
font-size: 0.85rem;
- color: #9ca3af;
- margin-bottom: 6px;
+ font-weight: 600;
+ color: var(--color-text-secondary, #94a3b8);
+ margin-bottom: 8px;
}
.capacity-bar-bg {
width: 100%;
height: 8px;
- background: rgba(255, 255, 255, 0.05);
- border-radius: 9999px;
+ background: rgba(255, 255, 255, 0.06);
+ border-radius: var(--radius-full, 9999px);
overflow: hidden;
- border: 1px solid rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.06);
}
.capacity-bar-fill {
height: 100%;
- border-radius: 9999px;
+ border-radius: var(--radius-full, 9999px);
transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
- background: var(--color-brand-teal);
+ background: linear-gradient(90deg, var(--color-brand-teal, #10b981) 0%, var(--color-accent-cyan, #06b6d4) 100%);
+ box-shadow: 0 0 12px rgba(16, 185, 129, 0.4);
}
.capacity-bar-fill.warning {
- background: linear-gradient(90deg, #f59e0b, #ef4444);
+ background: linear-gradient(90deg, #f59e0b 0%, #f43f5e 100%);
+ box-shadow: 0 0 12px rgba(244, 63, 94, 0.4);
}
/* Forms & Inputs */
.portfolio-form {
display: flex;
gap: 12px;
- margin-top: 12px;
+ margin-top: 14px;
}
.portfolio-input {
flex: 1;
- background: rgba(255, 255, 255, 0.03);
- border: 1px solid rgba(255, 255, 255, 0.1);
- border-radius: 8px;
- padding: 10px 16px;
+ background: rgba(255, 255, 255, 0.04);
+ border: 1px solid var(--color-border-subtle, rgba(255, 255, 255, 0.12));
+ border-radius: var(--radius-md, 10px);
+ padding: 12px 18px;
color: #ffffff;
outline: none;
font-size: 0.95rem;
- transition: all 0.25s ease;
+ font-family: var(--font-family-base);
+ transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.portfolio-input:focus {
- border-color: var(--color-brand-teal);
+ border-color: var(--color-brand-teal, #10b981);
background: rgba(255, 255, 255, 0.06);
- box-shadow: 0 0 0 2px rgba(13, 148, 136, 0.2);
+ box-shadow: 0 0 16px rgba(16, 185, 129, 0.2);
}
.portfolio-btn {
- background: var(--color-brand-teal);
+ background: linear-gradient(135deg, var(--color-brand-teal, #10b981) 0%, #059669 100%);
color: #ffffff;
border: none;
- border-radius: 8px;
- padding: 10px 20px;
- font-weight: 600;
+ border-radius: var(--radius-md, 10px);
+ padding: 12px 24px;
+ font-weight: 700;
cursor: pointer;
- transition: all 0.25s ease;
- box-shadow: 0 4px 12px rgba(13, 148, 136, 0.2);
+ box-shadow: 0 4px 16px rgba(16, 185, 129, 0.3);
+ transition: filter var(--transition-fast), transform var(--transition-fast);
}
.portfolio-btn:hover:not(:disabled) {
+ filter: brightness(1.15);
transform: translateY(-1px);
- background-color: var(--color-brand-teal-hover);
- box-shadow: 0 6px 16px rgba(13, 148, 136, 0.35);
}
.portfolio-btn:active:not(:disabled) {
@@ -116,7 +125,7 @@
.portfolio-btn:disabled {
background: rgba(255, 255, 255, 0.08);
- color: #6b7280;
+ color: var(--color-text-muted, #64748b);
cursor: not-allowed;
box-shadow: none;
}
@@ -125,24 +134,24 @@
.holdings-list {
display: flex;
flex-direction: column;
- gap: 10px;
- margin-top: 20px;
+ gap: 12px;
+ margin-top: 24px;
}
.holding-item {
display: flex;
justify-content: space-between;
align-items: center;
- background: rgba(255, 255, 255, 0.02);
- border: 1px solid rgba(255, 255, 255, 0.04);
- border-radius: 12px;
- padding: 14px 20px;
- transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
+ background: rgba(255, 255, 255, 0.025);
+ border: 1px solid var(--color-border-subtle, rgba(255, 255, 255, 0.06));
+ border-radius: var(--radius-lg, 14px);
+ padding: 16px 22px;
+ transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
}
.holding-item:hover {
- background: rgba(255, 255, 255, 0.04);
- border-color: var(--color-brand-teal);
+ background: rgba(255, 255, 255, 0.05);
+ border-color: var(--color-border-teal, rgba(16, 185, 129, 0.35));
transform: translateX(4px);
}
@@ -153,18 +162,19 @@
}
.holding-avatar {
- background: rgba(13, 148, 136, 0.1);
- border: 1px solid rgba(13, 148, 136, 0.3);
- color: var(--color-brand-teal);
- font-weight: 700;
- font-size: 0.9rem;
- width: 40px;
- height: 40px;
- border-radius: 8px;
+ background: linear-gradient(135deg, rgba(16, 185, 129, 0.2) 0%, rgba(6, 182, 212, 0.15) 100%);
+ border: 1px solid rgba(16, 185, 129, 0.3);
+ color: var(--color-brand-teal, #10b981);
+ font-weight: 800;
+ font-size: 0.95rem;
+ width: 42px;
+ height: 42px;
+ border-radius: var(--radius-md, 10px);
display: flex;
justify-content: center;
align-items: center;
letter-spacing: 0.05em;
+ box-shadow: 0 0 12px rgba(16, 185, 129, 0.15);
}
.holding-details {
@@ -173,6 +183,7 @@
}
.holding-symbol {
+ font-family: var(--font-family-mono, monospace);
font-weight: 700;
font-size: 1.1rem;
color: #ffffff;
@@ -180,49 +191,46 @@
.holding-date {
font-size: 0.75rem;
- color: #9ca3af;
+ color: var(--color-text-muted, #64748b);
margin-top: 2px;
}
.remove-btn {
- background: transparent;
- color: #f87171;
- border: 1px solid rgba(248, 113, 113, 0.2);
- border-radius: 6px;
- padding: 6px 12px;
+ background: rgba(244, 63, 94, 0.1);
+ color: #fb7185;
+ border: 1px solid rgba(244, 63, 94, 0.25);
+ border-radius: var(--radius-md, 8px);
+ padding: 8px 14px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
- transition: all 0.2s ease;
+ transition: background var(--transition-fast), border-color var(--transition-fast);
}
.remove-btn:hover {
- background: rgba(248, 113, 113, 0.1);
- border-color: #ef4444;
- color: #ef4444;
+ background: rgba(244, 63, 94, 0.2);
+ border-color: #f43f5e;
+ color: #ffffff;
}
-/* Notifications / Alert Banner */
+/* Alert Banner */
.alert-banner {
- background: rgba(239, 68, 68, 0.1);
- border: 1px solid rgba(239, 68, 68, 0.25);
- color: #fca5a5;
- padding: 12px 16px;
- border-radius: 8px;
+ background: rgba(244, 63, 94, 0.12);
+ border: 1px solid rgba(244, 63, 94, 0.3);
+ color: #fb7185;
+ padding: 14px 18px;
+ border-radius: var(--radius-md, 10px);
font-size: 0.9rem;
- margin-bottom: 20px;
+ font-weight: 600;
+ margin-bottom: 24px;
display: flex;
align-items: center;
- gap: 10px;
-}
-
-.alert-icon {
- font-weight: bold;
+ gap: 12px;
}
.empty-state {
text-align: center;
- padding: 40px 20px;
- color: #9ca3af;
+ padding: 48px 24px;
+ color: var(--color-text-secondary, #94a3b8);
font-size: 0.95rem;
}
diff --git a/src/styles/components/sidebar.css b/src/styles/components/sidebar.css
new file mode 100644
index 0000000..a14c03c
--- /dev/null
+++ b/src/styles/components/sidebar.css
@@ -0,0 +1,221 @@
+/* โโ Fixed Position Sidebar (240px width, 100vh height) โโ */
+
+.vercel-sidebar {
+ width: 240px;
+ height: 100vh;
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ background-color: #000000;
+ border-right: 1px solid #1f1f1f;
+ padding: 14px 12px;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ box-sizing: border-box;
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
+ user-select: none;
+ z-index: 1000;
+}
+
+.sidebar-scrollable-content {
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ overflow-y: auto;
+ scrollbar-width: thin;
+ padding-right: 2px;
+}
+
+/* Workspace Selector Bar at Top */
+.sidebar-workspace-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 10px;
+ border-radius: 8px;
+ cursor: pointer;
+ transition: background 0.15s ease;
+ margin-bottom: 12px;
+}
+
+.sidebar-workspace-bar:hover {
+ background: #111111;
+}
+
+.sidebar-workspace-info {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ min-width: 0;
+}
+
+.sidebar-workspace-avatar {
+ width: 22px;
+ height: 22px;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #0070f3 0%, #00dfa2 100%);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #ffffff;
+ font-size: 11px;
+ font-weight: 700;
+ flex-shrink: 0;
+}
+
+.sidebar-workspace-name {
+ font-size: 13px;
+ font-weight: 600;
+ color: #ededed;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 110px;
+}
+
+.sidebar-workspace-badge {
+ font-size: 11px;
+ font-weight: 500;
+ color: #888888;
+ background: #161616;
+ border: 1px solid #262626;
+ padding: 2px 8px;
+ border-radius: 12px;
+}
+
+/* Quick Search Input */
+.sidebar-search-box {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background: #0a0a0a;
+ border: 1px solid #222222;
+ border-radius: 6px;
+ padding: 7px 10px;
+ margin-bottom: 12px;
+ cursor: pointer;
+ transition: border-color 0.15s ease;
+}
+
+.sidebar-search-box:hover {
+ border-color: #333333;
+}
+
+.sidebar-search-placeholder {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 13px;
+ color: #666666;
+}
+
+.sidebar-search-key {
+ font-size: 11px;
+ font-weight: 600;
+ color: #888888;
+ background: #161616;
+ border: 1px solid #262626;
+ padding: 1px 5px;
+ border-radius: 4px;
+}
+
+/* Sidebar Nav Items */
+.sidebar-nav-list {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+}
+
+.sidebar-nav-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 10px;
+ border-radius: 6px;
+ background: transparent;
+ border: none;
+ color: #888888;
+ font-size: 13px;
+ font-weight: 500;
+ cursor: pointer;
+ width: 100%;
+ text-align: left;
+ transition: background 0.12s ease, color 0.12s ease;
+}
+
+.sidebar-nav-item:hover {
+ background: #111111;
+ color: #ededed;
+}
+
+.sidebar-nav-item.active {
+ background: #1c1c1c;
+ color: #ffffff;
+ font-weight: 600;
+}
+
+.sidebar-item-left {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+}
+
+.sidebar-item-icon {
+ font-size: 14px;
+ width: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.sidebar-badge-beta {
+ font-size: 10px;
+ font-weight: 600;
+ color: #0070f3;
+ background: rgba(0, 112, 243, 0.12);
+ padding: 1px 6px;
+ border-radius: 4px;
+}
+
+.sidebar-arrow-icon {
+ font-size: 11px;
+ color: #555555;
+}
+
+.sidebar-divider {
+ height: 1px;
+ background: #1a1a1a;
+ margin: 10px 0;
+}
+
+/* Pinned Bottom Logout Container */
+.sidebar-pinned-bottom {
+ padding-top: 10px;
+ border-top: 1px solid #1a1a1a;
+ flex-shrink: 0;
+}
+
+.sidebar-logout-full-btn {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 8px 10px;
+ background: rgba(255, 68, 68, 0.08);
+ border: 1px solid rgba(255, 68, 68, 0.2);
+ border-radius: 6px;
+ color: #ff4444;
+ font-size: 13px;
+ font-weight: 600;
+ font-family: inherit;
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+
+.sidebar-logout-full-btn:hover {
+ background: rgba(255, 68, 68, 0.2);
+ border-color: #ff4444;
+ color: #ffffff;
+}
diff --git a/src/styles/components/stock-search-bar.css b/src/styles/components/stock-search-bar.css
new file mode 100644
index 0000000..2229d1a
--- /dev/null
+++ b/src/styles/components/stock-search-bar.css
@@ -0,0 +1,196 @@
+/* โโ Vercel Style Stock Search Bar & Dropdown โโ */
+
+.stock-search-container {
+ position: relative;
+ width: 100%;
+}
+
+.stock-search-input-wrapper {
+ position: relative;
+ display: flex;
+ align-items: center;
+ width: 100%;
+}
+
+.stock-search-icon {
+ position: absolute;
+ left: 10px;
+ color: #666666;
+ font-size: 13px;
+ pointer-events: none;
+ display: flex;
+ align-items: center;
+}
+
+.stock-search-input {
+ width: 100%;
+ padding: 7px 30px 7px 32px;
+ background: #0a0a0a;
+ border: 1px solid #222222;
+ border-radius: 6px;
+ color: #ffffff;
+ font-size: 13px;
+ font-family: inherit;
+ outline: none;
+ transition: border-color 0.15s ease;
+}
+
+.stock-search-input:focus {
+ border-color: #444444;
+}
+
+.stock-search-spinner {
+ position: absolute;
+ right: 10px;
+ width: 14px;
+ height: 14px;
+ border: 2px solid #222222;
+ border-top-color: #ffffff;
+ border-radius: 50%;
+ animation: spin 0.6s linear infinite;
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.stock-search-clear {
+ position: absolute;
+ right: 8px;
+ background: none;
+ border: none;
+ color: #666666;
+ font-size: 12px;
+ cursor: pointer;
+ padding: 2px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 4px;
+ transition: color 0.15s ease;
+}
+
+.stock-search-clear:hover {
+ color: #ffffff;
+}
+
+/* Vercel Style Dropdown Menu */
+.stock-search-dropdown {
+ position: absolute;
+ top: calc(100% + 6px);
+ left: 0;
+ right: 0;
+ background: #0a0a0a;
+ border: 1px solid #222222;
+ border-radius: 8px;
+ box-shadow: 0 16px 40px rgba(0, 0, 0, 0.85);
+ z-index: 999;
+ max-height: 320px;
+ overflow-y: auto;
+ padding: 4px;
+ scrollbar-width: thin;
+ scrollbar-color: #262626 #0a0a0a;
+}
+
+.stock-search-dropdown::-webkit-scrollbar {
+ width: 6px;
+}
+
+.stock-search-dropdown::-webkit-scrollbar-track {
+ background: #0a0a0a;
+}
+
+.stock-search-dropdown::-webkit-scrollbar-thumb {
+ background: #262626;
+ border-radius: 3px;
+}
+
+.stock-search-dropdown::-webkit-scrollbar-thumb:hover {
+ background: #333333;
+}
+
+.stock-search-empty {
+ padding: 14px;
+ text-align: center;
+ color: #666666;
+ font-size: 13px;
+}
+
+.stock-search-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 8px 10px;
+ border-radius: 6px;
+ transition: background 0.12s ease;
+}
+
+.stock-search-item:hover {
+ background: #141414;
+}
+
+.stock-search-info {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ max-width: 70%;
+}
+
+.stock-search-symbol-wrapper {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.stock-search-symbol {
+ font-family: var(--font-family-mono, monospace);
+ font-weight: 600;
+ font-size: 13px;
+ color: #ffffff;
+}
+
+.stock-search-exchange {
+ font-size: 10px;
+ font-weight: 500;
+ padding: 1px 5px;
+ background: #161616;
+ border: 1px solid #262626;
+ border-radius: 4px;
+ color: #888888;
+ text-transform: uppercase;
+}
+
+.stock-search-name {
+ font-size: 12px;
+ color: #666666;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.stock-search-add-btn {
+ background: #141414;
+ border: 1px solid #262626;
+ color: #ededed;
+ padding: 5px 10px;
+ border-radius: 6px;
+ font-size: 12px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.12s ease;
+}
+
+.stock-search-add-btn:hover:not(:disabled) {
+ background: #ffffff;
+ color: #000000;
+ border-color: #ffffff;
+}
+
+.stock-search-add-btn:disabled {
+ background: #111111;
+ border-color: #1f1f1f;
+ color: #555555;
+ cursor: not-allowed;
+}
diff --git a/src/styles/tokens.css b/src/styles/tokens.css
index ff9f0b6..43d0ed7 100644
--- a/src/styles/tokens.css
+++ b/src/styles/tokens.css
@@ -1,46 +1,51 @@
/* โโ Design Tokens โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- *
- * All design values are defined here as CSS custom properties.
- * Use these variables throughout all component CSS files.
- * DO NOT hard-code raw color values in component styles.
- *
+ * Vercel / Linear Style Ultra-Clean Monochromatic Dark Theme Design System
* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
:root {
- /* Colors โ Base */
+ /* Colors โ Base Backgrounds */
--color-bg-primary: #000000;
--color-bg-secondary: #0a0a0a;
- --color-bg-card: rgba(255, 255, 255, 0.04);
- --color-bg-card-hover: rgba(255, 255, 255, 0.08);
+ --color-bg-tertiary: #111111;
+ --color-bg-card: #0a0a0a;
+ --color-bg-card-hover: #141414;
+ --color-bg-input: #0e0e0e;
/* Colors โ Text */
- --color-text-primary: #ffffff;
- --color-text-secondary: #a1a1aa;
- --color-text-muted: #71717a;
+ --color-text-primary: #ededed;
+ --color-text-secondary: #888888;
+ --color-text-muted: #555555;
+ --color-text-white: #ffffff;
- /* Colors โ Accents */
- --color-accent-white: #ffffff;
- --color-accent-silver: rgba(255, 255, 255, 0.7);
- --color-accent-teal: #006d65;
- --color-accent-teal-hover: #00564e;
+ /* Colors โ Accents & Indicators */
+ --color-brand-primary: #ffffff;
+ --color-brand-primary-text: #000000;
+ --color-accent-teal: #10b981;
+ --color-accent-blue: #0070f3;
+ --color-accent-rose: #ff4444;
+
+ /* Colors โ Market Status */
+ --color-positive: #00e599;
+ --color-positive-bg: rgba(0, 229, 153, 0.1);
+ --color-negative: #ff4444;
+ --color-negative-bg: rgba(255, 68, 68, 0.1);
/* Colors โ Borders */
- --color-border-subtle: rgba(255, 255, 255, 0.1);
- --color-border-default: rgba(255, 255, 255, 0.2);
- --color-border-strong: rgba(255, 255, 255, 0.4);
+ --color-border-subtle: #1a1a1a;
+ --color-border-default: #262626;
+ --color-border-strong: #333333;
+ --color-border-white: #ffffff;
/* Typography */
- --font-family-base:
- -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
- --font-family-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace;
+ --font-family-base: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+ --font-family-mono: 'JetBrains Mono', 'SF Mono', Consolas, monospace;
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
- --font-size-base: 1rem; /* 16px */
- --font-size-lg: 1.125rem; /* 18px */
+ --font-size-base: 0.9375rem; /* 15px */
+ --font-size-lg: 1.0625rem; /* 17px */
--font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px */
- --font-size-3xl: 2rem; /* 32px */
--font-weight-normal: 400;
--font-weight-medium: 500;
@@ -55,25 +60,21 @@
--space-5: 20px;
--space-6: 24px;
--space-8: 32px;
- --space-10: 40px;
- --space-12: 48px;
- /* Border Radius */
- --radius-sm: 4px;
+ /* Border Radius (Vercel Style) */
+ --radius-sm: 6px;
--radius-md: 8px;
- --radius-lg: 12px;
- --radius-xl: 16px;
+ --radius-lg: 10px;
+ --radius-xl: 12px;
--radius-full: 9999px;
/* Shadows / Glows */
- --glow-white-sm: 0 0 8px rgba(255, 255, 255, 0.15);
- --glow-white-md: 0 0 16px rgba(255, 255, 255, 0.2);
- --glow-white-lg: 0 0 24px rgba(255, 255, 255, 0.3);
+ --shadow-card: 0 4px 12px rgba(0, 0, 0, 0.5);
+ --shadow-dropdown: 0 12px 32px rgba(0, 0, 0, 0.8);
/* Transitions */
- --transition-fast: 150ms ease;
- --transition-base: 250ms ease;
- --transition-slow: 400ms ease;
+ --transition-fast: 120ms cubic-bezier(0.4, 0, 0.2, 1);
+ --transition-base: 200ms cubic-bezier(0.4, 0, 0.2, 1);
/* Z-index layers */
--z-base: 0;