diff --git a/frontend/public/splash-hero.png b/frontend/public/splash-hero.png new file mode 100644 index 0000000..8e048b2 Binary files /dev/null and b/frontend/public/splash-hero.png differ diff --git a/frontend/src/components/PaperTradingPage.tsx b/frontend/src/components/PaperTradingPage.tsx index f21db25..f1e7362 100644 --- a/frontend/src/components/PaperTradingPage.tsx +++ b/frontend/src/components/PaperTradingPage.tsx @@ -297,10 +297,10 @@ const PaperTradingPage: React.FC = ({
- - - - + + + +
@@ -375,17 +375,13 @@ const PaperTradingPage: React.FC = ({ ); }; -function MetricCard({ icon, title, value, sub, tone }: { - icon: string; title: string; value: string; sub: string; tone: 'up' | 'down'; +function MetricCard({ label, value, tone }: { + label: string; value: string; tone: 'up' | 'down'; }) { return (
- {icon} -
-
{title}
-
{value}
-
{sub}
-
+ {label} + {value}
); } diff --git a/frontend/src/components/SplashScreen.tsx b/frontend/src/components/SplashScreen.tsx index 894c959..019b1b8 100644 --- a/frontend/src/components/SplashScreen.tsx +++ b/frontend/src/components/SplashScreen.tsx @@ -1,9 +1,9 @@ /** - * μ„œλΉ„μŠ€ μ§„μž… μŠ€ν”Œλž˜μ‹œ β€” κΈ€λž˜μŠ€λͺ¨ν”Όμ¦˜ 둜그인 + * μ„œλΉ„μŠ€ μ§„μž… μŠ€ν”Œλž˜μ‹œ β€” μ°Έμ‘° 컨셉 둜그인 */ import React, { useState } from 'react'; import { loginUser, type LoginResponse } from '../utils/backendApi'; -import SplashGradientBackdrop from './splash/SplashGradientBackdrop'; +import SplashConceptBackdrop from './splash/SplashConceptBackdrop'; import '../styles/splashScreen.css'; const DEFAULT_USERNAME = 'admin'; @@ -37,10 +37,10 @@ const SplashScreen: React.FC = ({ onLoginSuccess, onGuest }) => { return (
- +
-
+

GoldenChart

@@ -51,7 +51,7 @@ const SplashScreen: React.FC = ({ onLoginSuccess, onGuest }) => { value={username} onChange={e => setUsername(e.target.value)} disabled={loading} - placeholder="ID" + aria-label="아이디" /> = ({ onLoginSuccess, onGuest }) => { value={password} onChange={e => setPassword(e.target.value)} disabled={loading} - placeholder="β€’β€’β€’β€’β€’β€’β€’β€’" + aria-label="λΉ„λ°€λ²ˆν˜Έ" /> {error &&

{error}

}
diff --git a/frontend/src/components/paper/PaperAssetTrendChart.tsx b/frontend/src/components/paper/PaperAssetTrendChart.tsx index 7a7f512..6099743 100644 --- a/frontend/src/components/paper/PaperAssetTrendChart.tsx +++ b/frontend/src/components/paper/PaperAssetTrendChart.tsx @@ -2,6 +2,8 @@ import React, { useEffect, useMemo, useState } from 'react'; import { loadPaperDailySnapshots, type PaperDailySnapshotDto } from '../../utils/backendApi'; import { fmtKrw } from '../TradeOrderPanel'; +const EMPTY_HINT = '일별 μŠ€λƒ…μƒ·μ΄ μŒ“μ΄λ©΄ μžμ‚° 좔이가 ν‘œμ‹œλ©λ‹ˆλ‹€.'; + interface Props { refreshKey?: number; } @@ -34,27 +36,32 @@ const PaperAssetTrendChart: React.FC = ({ refreshKey = 0 }) => { return { path: `M ${pts.join(' L ')}`, min: mn, max: mx, last: vals[vals.length - 1] }; }, [snapshots]); - if (snapshots.length < 2) { - return ( -
- 일별 μŠ€λƒ…μƒ·μ΄ μŒ“μ΄λ©΄ μžμ‚° 좔이가 ν‘œμ‹œλ©λ‹ˆλ‹€. -
- ); - } + const hasChart = snapshots.length >= 2; return (
-
- μžμ‚° 좔이 - {fmtKrw(last)} -
- - - -
- {fmtKrw(min)} - {fmtKrw(max)} +
+
+ μžμ‚°μΆ”μ΄ + {!hasChart && ( + {EMPTY_HINT} + )} +
+ {hasChart && ( + {fmtKrw(last)} + )}
+ {hasChart && ( +
+ + + +
+ {fmtKrw(min)} + {fmtKrw(max)} +
+
+ )}
); }; diff --git a/frontend/src/components/splash/SplashConceptBackdrop.tsx b/frontend/src/components/splash/SplashConceptBackdrop.tsx new file mode 100644 index 0000000..874a4ae --- /dev/null +++ b/frontend/src/components/splash/SplashConceptBackdrop.tsx @@ -0,0 +1,65 @@ +/** + * 둜그인 μŠ€ν”Œλž˜μ‹œ β€” μ°Έμ‘° 컨셉: μ€μ€ν•œ κ·ΈλΌλ°μ΄μ…˜ + νλ¦Ών•œ λŒ€κ°μ„  폰 λͺ©μ—… + * (이미지 파일 λ―Έμ‚¬μš©, CSS/SVG만) + */ +import React from 'react'; +import SplashPhoneMockup, { type SplashPhoneVariant } from './SplashPhoneMockup'; + +interface PhonePlacement { + variant: SplashPhoneVariant; + left: string; + top: string; + rotateY: number; + rotateZ: number; + scale: number; + opacity: number; +} + +/** μ€‘μ•™μ—μ„œ μš°μƒλ‹¨Β·μ’Œν•˜λ‹¨μœΌλ‘œ νΌμ§€λŠ” λͺ©μ—… 배치 */ +const PHONES: PhonePlacement[] = [ + { variant: 'chart', left: '4%', top: '68%', rotateY: 22, rotateZ: -14, scale: 0.72, opacity: 0.14 }, + { variant: 'watchlist', left: '11%', top: '54%', rotateY: 18, rotateZ: -10, scale: 0.78, opacity: 0.16 }, + { variant: 'orderbook', left: '18%', top: '40%', rotateY: 14, rotateZ: -6, scale: 0.84, opacity: 0.18 }, + { variant: 'trade', left: '52%', top: '38%', rotateY: -8, rotateZ: 4, scale: 0.88, opacity: 0.2 }, + { variant: 'chart', left: '62%', top: '26%', rotateY: -14, rotateZ: 8, scale: 0.92, opacity: 0.22 }, + { variant: 'watchlist', left: '72%', top: '14%', rotateY: -18, rotateZ: 12, scale: 0.96, opacity: 0.2 }, + { variant: 'orderbook', left: '82%', top: '4%', rotateY: -22, rotateZ: 14, scale: 1, opacity: 0.17 }, + { variant: 'chart', left: '90%', top: '-2%', rotateY: -26, rotateZ: 16, scale: 0.88, opacity: 0.12 }, +]; + +const SplashConceptBackdrop: React.FC = () => ( +
+
+ +
+ + +
+ +
+ +
+
+ {PHONES.map((p, i) => ( + + ))} +
+
+ +
+
+
+
+
+); + +export default SplashConceptBackdrop; diff --git a/frontend/src/components/splash/SplashPhoneMockup.tsx b/frontend/src/components/splash/SplashPhoneMockup.tsx new file mode 100644 index 0000000..47ebfc9 --- /dev/null +++ b/frontend/src/components/splash/SplashPhoneMockup.tsx @@ -0,0 +1,142 @@ +import React from 'react'; + +export type SplashPhoneVariant = 'chart' | 'orderbook' | 'watchlist' | 'trade'; + +interface Props { + variant: SplashPhoneVariant; + style?: React.CSSProperties; + className?: string; +} + +const MiniChart: React.FC = () => ( + + + {[28, 52, 76, 100, 124, 148, 172].map(y => ( + + ))} + {[ + { x: 12, h: 90, l: 118, up: true }, + { x: 22, h: 82, l: 112, up: true }, + { x: 32, h: 95, l: 125, up: false }, + { x: 42, h: 78, l: 108, up: true }, + { x: 52, h: 70, l: 100, up: true }, + { x: 62, h: 88, l: 118, up: false }, + { x: 72, h: 65, l: 95, up: true }, + { x: 82, h: 58, l: 88, up: true }, + { x: 92, h: 72, l: 102, up: true }, + { x: 102, h: 48, l: 78, up: true }, + ].map((c, i) => ( + + + + + ))} + + +); + +const MiniOrderbook: React.FC = () => ( + + + {Array.from({ length: 8 }, (_, i) => { + const y = 24 + i * 20; + const askW = 18 + (i % 4) * 8; + const bidW = 22 + ((i + 2) % 4) * 6; + return ( + + + + + ); + })} + + +); + +const MiniWatchlist: React.FC = () => ( + + + {[0, 1, 2, 3, 4, 5].map(i => ( + + + + 005930 + + + {i % 2 === 0 ? '+1.2%' : '-0.4%'} + + + ))} + +); + +const MiniTrade: React.FC = () => ( + + + + {[ + { x: 20, h: 100, l: 118, up: true }, + { x: 40, h: 85, l: 105, up: true }, + { x: 60, h: 92, l: 112, up: false }, + { x: 80, h: 72, l: 95, up: true }, + ].map((c, i) => ( + + ))} + + + +); + +const SCREENS: Record = { + chart: MiniChart, + orderbook: MiniOrderbook, + watchlist: MiniWatchlist, + trade: MiniTrade, +}; + +const SplashPhoneMockup: React.FC = ({ variant, style, className = '' }) => { + const Screen = SCREENS[variant]; + return ( +
+
+
+
+ +
+
+
+ ); +}; + +export default SplashPhoneMockup; diff --git a/frontend/src/styles/paperDashboard.css b/frontend/src/styles/paperDashboard.css index 59455e9..7d1452f 100644 --- a/frontend/src/styles/paperDashboard.css +++ b/frontend/src/styles/paperDashboard.css @@ -742,7 +742,7 @@ .bps-footer .ptd-metrics-grid { display: grid; - grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; } @@ -764,23 +764,37 @@ .se-page .down { color: var(--se-down, #ef4444); } @media (max-width: 1200px) { - .bps-footer .ptd-metrics-grid { grid-template-columns: repeat(2, 1fr); } } /* legacy layout removed β€” shell handles page structure */ .ptd-metric { display: flex; - align-items: flex-start; - gap: 8px; + align-items: center; + justify-content: space-between; + gap: 10px; padding: 8px 10px; border-radius: 10px; background: var(--bg2); border: 1px solid var(--border); + min-width: 0; +} +.ptd-metric-label { + flex-shrink: 0; + font-size: 10px; + font-weight: 600; + color: var(--text3); + white-space: nowrap; +} +.ptd-metric-value { + flex: 1; + min-width: 0; + font-size: 17px; + font-weight: 800; + line-height: 1.1; + text-align: right; + font-variant-numeric: tabular-nums; + color: var(--text); } -.ptd-metric-icon { font-size: 16px; line-height: 1; } -.ptd-metric-title { font-size: 10px; color: var(--text3); margin-bottom: 2px; } -.ptd-metric-value { font-size: 17px; font-weight: 800; line-height: 1.1; color: var(--text); } -.ptd-metric-sub { font-size: 9px; color: var(--text3); margin-top: 2px; } .ptd-metric--up .ptd-metric-value { color: #22c55e; } .ptd-metric--down .ptd-metric-value { color: #ef4444; } diff --git a/frontend/src/styles/splashScreen.css b/frontend/src/styles/splashScreen.css index 0488b40..f91aa8a 100644 --- a/frontend/src/styles/splashScreen.css +++ b/frontend/src/styles/splashScreen.css @@ -1,4 +1,4 @@ -/* GoldenChart splash β€” 프리미엄 흐림 κ·ΈλΌλ°μ΄μ…˜ + κΈ€λž˜μŠ€ 둜그인 */ +/* GoldenChart splash β€” μ€μ€ν•œ κ·ΈλΌλ°μ΄μ…˜ + νλ¦Ών•œ 폰 λͺ©μ—… λ°°κ²½ */ .splash { position: fixed; @@ -7,13 +7,13 @@ display: flex; align-items: center; justify-content: center; - background: #05070c; + background: #06080e; color: #e8eaed; overflow: hidden; font-family: var(--font, 'Noto Sans KR', 'Inter', sans-serif); } -/* ── λ°°κ²½ λ ˆμ΄μ–΄ ─────────────────────────────────────────────────────────── */ +/* ── λ°°κ²½ ─────────────────────────────────────────────────────────────────── */ .splash-backdrop { position: absolute; @@ -26,237 +26,149 @@ .splash-backdrop__base { position: absolute; inset: 0; - background: - linear-gradient(155deg, #06080f 0%, #0a0e18 38%, #070a12 68%, #05070c 100%); + background: linear-gradient(160deg, #05070c 0%, #0a0e16 42%, #070a12 100%); +} + +.splash-backdrop__aurora { + position: absolute; + inset: 0; +} + +.splash-backdrop__aurora--teal, +.splash-backdrop__aurora--gold { + position: absolute; + border-radius: 50%; + filter: blur(80px); +} + +.splash-backdrop__aurora--teal { + width: min(58vw, 520px); + height: min(58vw, 520px); + left: 8%; + top: 38%; + background: radial-gradient(circle, rgba(34, 197, 94, 0.14) 0%, rgba(45, 212, 191, 0.05) 45%, transparent 70%); +} + +.splash-backdrop__aurora--gold { + width: min(50vw, 460px); + height: min(50vw, 460px); + right: 6%; + top: 8%; + background: radial-gradient(circle, rgba(249, 226, 156, 0.18) 0%, rgba(212, 175, 55, 0.08) 42%, transparent 72%); } .splash-backdrop__mesh { position: absolute; - inset: -20%; - opacity: 0.45; - background: - conic-gradient( - from 38deg at 58% 42%, - rgba(212, 175, 55, 0.12) 0deg, - transparent 48deg, - rgba(34, 197, 94, 0.07) 95deg, - transparent 165deg, - rgba(56, 189, 248, 0.05) 240deg, - transparent 360deg + inset: -15%; + opacity: 0.35; + background: conic-gradient( + from 42deg at 55% 40%, + rgba(212, 175, 55, 0.1) 0deg, + transparent 55deg, + rgba(34, 197, 94, 0.06) 110deg, + transparent 200deg, + rgba(56, 189, 248, 0.04) 280deg, + transparent 360deg + ); + filter: blur(48px); +} + +/* λŒ€κ°μ„  폰 λͺ©μ—… β€” μ€‘μ•™β†’μš°μƒλ‹¨ κ·ΈλΌλ°μ΄μ…˜ 마슀크 */ +.splash-backdrop__phones { + position: absolute; + inset: 0; + perspective: 1100px; + mask-image: + radial-gradient(ellipse 42% 38% at 50% 48%, transparent 0%, rgba(0, 0, 0, 0.15) 42%, #000 58%), + linear-gradient( + 125deg, + rgba(0, 0, 0, 0.25) 0%, + #000 18%, + #000 42%, + rgba(0, 0, 0, 0.45) 58%, + transparent 78% + ); + -webkit-mask-image: + radial-gradient(ellipse 42% 38% at 50% 48%, transparent 0%, rgba(0, 0, 0, 0.15) 42%, #000 58%), + linear-gradient( + 125deg, + rgba(0, 0, 0, 0.25) 0%, + #000 18%, + #000 42%, + rgba(0, 0, 0, 0.45) 58%, + transparent 78% ); - filter: blur(52px); } -.splash-backdrop__orbs { +.splash-backdrop__phones-blur { position: absolute; - inset: 0; + inset: -5%; + filter: blur(10px) saturate(0.75) brightness(0.82); } -.splash-backdrop__orb { +.splash-phone { position: absolute; - border-radius: 50%; - filter: blur(72px); + width: clamp(88px, 10vw, 148px); + aspect-ratio: 9 / 19.5; + transform-origin: center center; will-change: transform; - animation: splash-orb-float 22s ease-in-out infinite; } -.splash-backdrop__orb--gold { - width: min(52vw, 480px); - height: min(52vw, 480px); - top: -6%; - right: 2%; - background: radial-gradient(circle, rgba(249, 226, 156, 0.32) 0%, rgba(212, 175, 55, 0.12) 45%, transparent 72%); - animation-delay: 0s; +.splash-phone__frame { + height: 100%; + padding: 5px; + border-radius: clamp(16px, 2.2vw, 24px); + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(14, 18, 28, 0.42); + box-shadow: + 0 16px 48px rgba(0, 0, 0, 0.45), + 0 0 0 1px rgba(255, 255, 255, 0.04) inset; + backdrop-filter: blur(6px); + -webkit-backdrop-filter: blur(6px); } -.splash-backdrop__orb--teal { - width: min(44vw, 400px); - height: min(44vw, 400px); - top: 18%; - right: -6%; - background: radial-gradient(circle, rgba(34, 197, 94, 0.16) 0%, rgba(45, 212, 191, 0.06) 50%, transparent 70%); - animation-delay: -8s; - animation-duration: 24s; +.splash-phone__notch { + width: 36%; + height: 5px; + margin: 2px auto 4px; + border-radius: 4px; + background: rgba(0, 0, 0, 0.35); } -.splash-backdrop__orb--indigo { - width: min(38vw, 340px); - height: min(38vw, 340px); - bottom: -10%; - left: -8%; - background: radial-gradient(circle, rgba(99, 102, 241, 0.14) 0%, transparent 68%); - animation-delay: -14s; - animation-duration: 26s; -} - -@keyframes splash-orb-float { - 0%, 100% { - transform: translate(0, 0) scale(1); - } - 33% { - transform: translate(1.5%, -1%) scale(1.03); - } - 66% { - transform: translate(-1%, 1.5%) scale(0.98); - } -} - -/* ── 쀑앙 β†’ 우츑 상단: μΊ”λ“€Β·ν˜Έκ°€ 싀루엣 ───────────────────────────────────── */ - -.splash-backdrop__market-flow { - position: absolute; - inset: 0; +.splash-phone__screen { + height: calc(100% - 14px); + border-radius: clamp(12px, 1.6vw, 18px); overflow: hidden; } +.splash-phone__svg { + display: block; + width: 100%; + height: 100%; +} + .splash-backdrop__flow-glow { position: absolute; - left: 42%; - top: 38%; - width: min(95vw, 920px); - height: min(72vh, 640px); - transform: translate(-18%, -22%); + left: 38%; + top: 32%; + width: min(88vw, 840px); + height: min(68vh, 580px); + transform: translate(-12%, -8%); background: linear-gradient( 128deg, - rgba(34, 197, 94, 0.07) 0%, - rgba(212, 175, 55, 0.1) 32%, - rgba(56, 189, 248, 0.05) 58%, - transparent 78% + rgba(34, 197, 94, 0.06) 0%, + rgba(212, 175, 55, 0.09) 35%, + rgba(249, 226, 156, 0.05) 55%, + transparent 75% ); - filter: blur(56px); - opacity: 0.9; + filter: blur(64px); pointer-events: none; } -.splash-backdrop__flow-inner { - position: absolute; - left: 50%; - top: 50%; - width: min(128vw, 1680px); - height: min(96vh, 920px); - transform: translate(-42%, -48%); - transform-origin: center center; - pointer-events: none; - /* 쀑앙(둜그인 μΉ΄λ“œ λΆ€κ·Ό)μ—μ„œ 우츑 μƒλ‹¨μœΌλ‘œ 갈수둝 μ„œμ„œνžˆ 사라짐 */ - mask-image: linear-gradient( - 125deg, - #000 0%, - #000 14%, - rgba(0, 0, 0, 0.62) 32%, - rgba(0, 0, 0, 0.28) 48%, - rgba(0, 0, 0, 0.08) 58%, - transparent 72% - ); - -webkit-mask-image: linear-gradient( - 125deg, - #000 0%, - #000 14%, - rgba(0, 0, 0, 0.62) 32%, - rgba(0, 0, 0, 0.28) 48%, - rgba(0, 0, 0, 0.08) 58%, - transparent 72% - ); -} - -.splash-backdrop__chart-layer { - position: absolute; - inset: 0; - opacity: 0.38; - filter: blur(22px) saturate(0.72) brightness(0.78); -} - -.splash-backdrop__orderbook-layer { - position: absolute; - right: 2%; - top: 6%; - width: min(36vw, 340px); - height: min(52vh, 480px); - opacity: 0.32; - filter: blur(14px) saturate(0.65); -} - -.splash-chart-bg { - display: block; - width: 100%; - height: 100%; -} - -.splash-orderbook-bg { - display: block; - width: 100%; - height: 100%; -} - -.splash-ob-mid { - stroke: rgba(255, 255, 255, 0.08); - stroke-width: 1; - stroke-dasharray: 4 6; -} - -.splash-ob-ask-bar { - fill: rgba(239, 68, 68, 0.35); -} - -.splash-ob-bid-bar { - fill: rgba(34, 197, 94, 0.32); -} - -.splash-ob-ask-txt, -.splash-ob-bid-txt { - font-size: 9px; - font-family: ui-monospace, 'SF Mono', Menlo, monospace; - fill: rgba(255, 255, 255, 0.12); -} - -.splash-ob-spread { - fill: rgba(212, 175, 55, 0.08); - stroke: rgba(212, 175, 55, 0.15); - stroke-width: 1; -} - -.splash-chart-grid { - stroke: rgba(255, 255, 255, 0.04); - stroke-width: 1; -} - -.splash-vol-bar { - fill: rgba(255, 255, 255, 0.06); -} - -.splash-ichi--tenkan { stroke: rgba(250, 204, 21, 0.35); stroke-width: 1.2; fill: none; } -.splash-ichi--kijun { stroke: rgba(96, 165, 250, 0.3); stroke-width: 1.2; fill: none; } -.splash-ichi--senkou-a { stroke: rgba(34, 197, 94, 0.22); stroke-width: 1; fill: none; } -.splash-ichi--senkou-b { stroke: rgba(239, 68, 68, 0.2); stroke-width: 1; fill: none; } - -.splash-candle-wick { - stroke: rgba(255, 255, 255, 0.2); - stroke-width: 1; -} - -.splash-candle-up { - fill: rgba(34, 197, 94, 0.42); -} - -.splash-candle-down { - fill: rgba(239, 68, 68, 0.38); -} - -.splash-backdrop__grid { - position: absolute; - inset: 0; - opacity: 0.35; - background-image: - linear-gradient(rgba(255, 255, 255, 0.028) 1px, transparent 1px), - linear-gradient(90deg, rgba(255, 255, 255, 0.028) 1px, transparent 1px); - background-size: 56px 56px; - mask-image: radial-gradient(ellipse 90% 80% at 50% 50%, #000 20%, transparent 85%); - -webkit-mask-image: radial-gradient(ellipse 90% 80% at 50% 50%, #000 20%, transparent 85%); -} - .splash-backdrop__grain { position: absolute; inset: 0; - opacity: 0.045; + opacity: 0.04; background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); background-size: 180px 180px; } @@ -265,27 +177,20 @@ position: absolute; inset: 0; background: - radial-gradient(ellipse 68% 58% at 50% 50%, transparent 0%, rgba(5, 7, 12, 0.42) 62%, rgba(2, 3, 6, 0.9) 100%), - linear-gradient(128deg, transparent 0%, rgba(5, 7, 12, 0.15) 55%, rgba(5, 7, 12, 0.35) 100%), - linear-gradient(180deg, rgba(5, 7, 12, 0.45) 0%, transparent 30%, transparent 70%, rgba(5, 7, 12, 0.5) 100%); + radial-gradient(ellipse 70% 62% at 50% 50%, transparent 0%, rgba(5, 7, 12, 0.5) 65%, rgba(2, 3, 6, 0.92) 100%), + linear-gradient(128deg, transparent 0%, rgba(5, 7, 12, 0.2) 50%, rgba(5, 7, 12, 0.35) 100%); } .splash-backdrop__spotlight { position: absolute; inset: 0; background: radial-gradient( - ellipse 42% 38% at 50% 46%, - rgba(255, 255, 255, 0.06) 0%, + ellipse 40% 36% at 50% 46%, + rgba(255, 255, 255, 0.05) 0%, transparent 100% ); } -@media (prefers-reduced-motion: reduce) { - .splash-backdrop__orb { - animation: none; - } -} - /* ── 둜그인 μΉ΄λ“œ ───────────────────────────────────────────────────────────── */ .splash-center { @@ -294,37 +199,35 @@ display: flex; flex-direction: column; align-items: center; - gap: 18px; - width: min(92vw, 380px); - padding: 24px 16px; + gap: 16px; + width: min(92vw, 400px); + padding: 20px 16px; } -.splash-glass { +.splash-card { width: 100%; - padding: 36px 32px 28px; - border-radius: 20px; - border: 1px solid rgba(255, 255, 255, 0.12); - background: rgba(10, 12, 18, 0.52); - backdrop-filter: blur(24px) saturate(1.15); - -webkit-backdrop-filter: blur(24px) saturate(1.15); + padding: 38px 36px 30px; + border-radius: 18px; + border: 1px solid rgba(212, 175, 55, 0.55); + background: rgba(11, 14, 22, 0.97); box-shadow: - 0 0 0 1px rgba(212, 175, 55, 0.06) inset, - 0 28px 72px rgba(0, 0, 0, 0.55), - 0 8px 24px rgba(0, 0, 0, 0.35); + 0 0 0 1px rgba(212, 175, 55, 0.08) inset, + 0 0 40px rgba(212, 175, 55, 0.1), + 0 24px 64px rgba(0, 0, 0, 0.65); } .splash-brand { - margin: 0 0 28px; + margin: 0 0 30px; text-align: center; - font-size: 2rem; + font-size: 2.15rem; font-weight: 800; letter-spacing: -0.02em; line-height: 1.1; - background: linear-gradient(180deg, #fce9a8 0%, #e8c547 38%, #c9a227 72%, #a67c00 100%); + background: linear-gradient(180deg, #fce9a8 0%, #e8c547 40%, #c9a227 78%, #a67c00 100%); -webkit-background-clip: text; background-clip: text; color: transparent; - filter: drop-shadow(0 2px 16px rgba(212, 175, 55, 0.28)); + filter: drop-shadow(0 2px 12px rgba(212, 175, 55, 0.35)); } .splash-form { @@ -336,24 +239,19 @@ .splash-input { width: 100%; box-sizing: border-box; - padding: 13px 14px; + padding: 14px 16px; border-radius: 10px; - border: 1px solid rgba(255, 255, 255, 0.1); - background: rgba(0, 0, 0, 0.38); + border: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(22, 26, 36, 0.95); color: #f3f4f6; font-size: 0.95rem; - transition: border-color 0.15s, box-shadow 0.15s, background 0.15s; -} - -.splash-input::placeholder { - color: rgba(255, 255, 255, 0.32); + transition: border-color 0.15s, box-shadow 0.15s; } .splash-input:focus { outline: none; - border-color: rgba(212, 175, 55, 0.5); - background: rgba(0, 0, 0, 0.48); - box-shadow: 0 0 0 3px rgba(212, 175, 55, 0.14); + border-color: rgba(212, 175, 55, 0.45); + box-shadow: 0 0 0 3px rgba(212, 175, 55, 0.12); } .splash-input:disabled { @@ -369,26 +267,23 @@ .splash-login-btn { width: 100%; - margin-top: 4px; - padding: 13px 16px; + margin-top: 6px; + padding: 14px 16px; border: none; border-radius: 10px; cursor: pointer; - font-size: 1rem; + font-size: 1.05rem; font-weight: 800; - color: #1a1408; - background: linear-gradient(180deg, #fce9a8 0%, #e0c04a 42%, #c9a227 100%); + color: #141008; + background: linear-gradient(90deg, #f5e6a8 0%, #e8c84a 48%, #d4af37 100%); box-shadow: - 0 1px 0 rgba(255, 255, 255, 0.25) inset, - 0 6px 22px rgba(201, 162, 39, 0.38); + 0 1px 0 rgba(255, 255, 255, 0.3) inset, + 0 6px 24px rgba(201, 162, 39, 0.4); transition: transform 0.12s, filter 0.12s, box-shadow 0.12s; } .splash-login-btn:hover:not(:disabled) { - filter: brightness(1.06); - box-shadow: - 0 1px 0 rgba(255, 255, 255, 0.3) inset, - 0 8px 28px rgba(201, 162, 39, 0.48); + filter: brightness(1.05); } .splash-login-btn:active:not(:disabled) { @@ -401,17 +296,16 @@ } .splash-version { - margin: 22px 0 0; + margin: 24px 0 0; text-align: center; - font-size: 0.68rem; - color: rgba(255, 255, 255, 0.34); - letter-spacing: 0.01em; + font-size: 0.7rem; + color: rgba(255, 255, 255, 0.38); } .splash-guest-link { border: none; background: transparent; - color: rgba(255, 255, 255, 0.4); + color: rgba(255, 255, 255, 0.38); font-size: 0.78rem; cursor: pointer; padding: 4px 8px; @@ -427,28 +321,32 @@ cursor: not-allowed; } -@media (max-width: 420px) { - .splash-glass { - padding: 28px 22px 22px; - border-radius: 16px; +@media (max-width: 480px) { + .splash-card { + padding: 30px 24px 24px; } + .splash-brand { - font-size: 1.65rem; - margin-bottom: 22px; + font-size: 1.75rem; + margin-bottom: 24px; } - .splash-backdrop__orb { - filter: blur(56px); + + .splash-phone { + width: clamp(72px, 18vw, 110px); } - .splash-backdrop__flow-inner { - mask-image: radial-gradient( - ellipse 90% 85% at 24% 56%, - #000 0%, - transparent 75% - ); - -webkit-mask-image: radial-gradient( - ellipse 90% 85% at 24% 56%, - #000 0%, - transparent 75% - ); + + .splash-backdrop__phones-blur { + filter: blur(12px) saturate(0.7) brightness(0.78); + } + + .splash-backdrop__aurora--teal, + .splash-backdrop__aurora--gold { + filter: blur(64px); + } +} + +@media (prefers-reduced-motion: reduce) { + .splash-phone { + will-change: auto; } } diff --git a/frontend/src/styles/virtualTradingDashboard.css b/frontend/src/styles/virtualTradingDashboard.css index dfb19d0..d56e835 100644 --- a/frontend/src/styles/virtualTradingDashboard.css +++ b/frontend/src/styles/virtualTradingDashboard.css @@ -2834,6 +2834,54 @@ padding-top: 8px; border-top: 1px solid var(--se-border); } + +.ptd-invest-metrics .ptd-metrics-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; +} + +.ptd-invest-metrics .ptd-metric { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + padding: 10px 12px; + border-radius: 6px; + background: var(--gc-surface-2, rgba(255, 255, 255, 0.04)); + border: 1px solid var(--se-border, var(--border)); + min-width: 0; +} + +.ptd-invest-metrics .ptd-metric-label { + flex-shrink: 0; + font-size: 11px; + font-weight: 600; + color: var(--text3); + white-space: nowrap; +} + +.ptd-invest-metrics .ptd-metric-value { + flex: 1; + min-width: 0; + font-size: 15px; + font-weight: 800; + text-align: right; + font-variant-numeric: tabular-nums; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + color: var(--text); +} + +.ptd-invest-metrics .ptd-metric--up .ptd-metric-value { + color: #22c55e; +} + +.ptd-invest-metrics .ptd-metric--down .ptd-metric-value { + color: #ef4444; +} + .bps-page--ptd .ptd-right-history { flex: 1; min-height: 0; @@ -2920,24 +2968,79 @@ gap: 10px; } .ptd-asset-trend { - padding: 8px 12px; - border-radius: 6px; - background: var(--gc-surface-2, rgba(255,255,255,0.04)); -} -.ptd-asset-trend-head { display: flex; - justify-content: space-between; - font-size: 12px; - margin-bottom: 4px; + flex-direction: column; + border-radius: 6px; + background: var(--gc-surface-2, rgba(255, 255, 255, 0.04)); + border: 1px solid var(--se-border, var(--border)); + overflow: hidden; + min-width: 0; } + +.ptd-asset-trend-titlebar { + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + min-height: 24px; + padding: 3px 10px; + border-bottom: 1px solid color-mix(in srgb, var(--se-border, var(--border)) 65%, transparent); +} + +.ptd-asset-trend-titlegroup { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + min-width: 0; + flex: 1; +} + +.ptd-asset-trend-title { + flex-shrink: 0; + font-size: 14px; + font-weight: 700; + color: #ff9800; + letter-spacing: 0.04em; + line-height: 1.2; +} + +.ptd-asset-trend-hint { + font-size: 11px; + font-weight: 400; + color: var(--text3); + opacity: 0.78; + line-height: 1.3; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.ptd-asset-trend-body { + padding: 8px 12px 10px; + min-width: 0; +} + +.ptd-asset-trend-last { + flex-shrink: 0; + font-size: 11px; + font-weight: 600; + color: var(--text2); + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + .ptd-asset-trend-svg { width: 100%; height: 48px; display: block; } + .ptd-asset-trend-range { display: flex; justify-content: space-between; font-size: 10px; opacity: 0.6; + margin-top: 2px; }