/* ══════════════════════════════════════════════════════════════════ TradingView-style Chart App · Global Styles ══════════════════════════════════════════════════════════════════ */ *,*::before,*::after { box-sizing: border-box; margin: 0; padding: 0; } :root { --font: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif; --radius: 3px; --toolbar-h: 44px; --sidebar-w: 44px; --bottombar-h:28px; /* 기본 테마 변수 (다크 테마) — document.body 로 포털된 컴포넌트에서도 사용 가능하도록 :root에 선언 */ --bg: #1a1b26; --bg1: #1a1b26; --bg2: #24283b; --bg3: #1f2335; --bg4: #414868; --text: #c0caf5; --text2: #9aa5ce; --text3: #6272a4; --border: rgba(122, 162, 247, 0.15); --accent: #7aa2f7; --accent-h: #5a7dc7; --up: #ff6b6b; --down: #4dabf7; --panel-bg: #24283bee; --sep: rgba(122, 162, 247, 0.15); --panel: #24283b; --text-muted: #6272a4; --btn-bg: rgba(255, 255, 255, 0.07); --accent-muted: color-mix(in srgb, var(--accent) 22%, transparent); --popup-shadow: 0 8px 32px rgba(0, 0, 0, 0.55); } /* ── Dark Theme: 도쿄 나이트 (THEME_SETTINGS.md §2.2) ───────────── */ .app.dark, html.theme-dark { --bg: #1a1b26; --bg1: #1a1b26; --bg2: #24283b; --bg3: #1f2335; --bg4: #414868; --text: #c0caf5; --text2: #9aa5ce; --text3: #6272a4; --border: rgba(122, 162, 247, 0.15); --accent: #7aa2f7; --accent-h: #5a7dc7; --up: #ff6b6b; --down: #4dabf7; --panel-bg: #24283bee; --sep: rgba(122, 162, 247, 0.15); --panel: #24283b; --text-muted: #6272a4; --btn-bg: rgba(255, 255, 255, 0.07); --accent-muted: color-mix(in srgb, var(--accent) 22%, transparent); --popup-shadow: 0 8px 32px rgba(0, 0, 0, 0.55); } /* ── Light Theme (THEME_SETTINGS.md §2.1) ──────────────────────── */ .app.light, html.theme-light { --bg: #f5f5f5; --bg1: #f5f5f5; --bg2: #ffffff; --bg3: #f0f0f0; --bg4: #e0e0e0; --text: #212121; --text2: #757575; --text3: #9e9e9e; --border: rgba(0, 0, 0, 0.10); --accent: #1976d2; --accent-h: #1565c0; --up: #c62828; --down: #1565c0; --panel-bg: #ffffffee; --sep: rgba(0, 0, 0, 0.10); --panel: #ffffff; --text-muted: #757575; --btn-bg: rgba(0, 0, 0, 0.06); --accent-muted: color-mix(in srgb, var(--accent) 14%, transparent); --popup-shadow: 0 8px 32px rgba(0, 0, 0, 0.12); } /* ── Blue Theme: 딥 네이비 (THEME_SETTINGS.md §2.3) ─────────────── */ .app.blue, html.theme-blue { --bg: #0c1929; --bg1: #0c1929; --bg2: #15273d; --bg3: #0f1e30; --bg4: #1e3a5f; --text: #e8f4ff; --text2: #b8d4f0; --text3: #7aaed4; --border: rgba(94, 181, 255, 0.15); --accent: #5eb5ff; --accent-h: #3a9ae0; --up: #ff5555; --down: #55aaff; --panel-bg: #15273dee; --sep: rgba(94, 181, 255, 0.15); --panel: #15273d; --text-muted: #7aaed4; --btn-bg: rgba(255, 255, 255, 0.07); --accent-muted: color-mix(in srgb, var(--accent) 22%, transparent); --popup-shadow: 0 8px 32px rgba(0, 0, 0, 0.55); } /* ── App Root ───────────────────────────────────────────────────── */ .app { display: flex; flex-direction: column; height: 100vh; overflow: hidden; background: var(--bg); color: var(--text); font-family: var(--font); font-size: 13px; line-height: 1; } /* ══════════════════════════════════════════════════════════════════ TOP MENU BAR (글로벌 네비게이션) ══════════════════════════════════════════════════════════════════ */ .top-menubar { display: flex; align-items: center; height: 46px; flex-shrink: 0; background: var(--bg3); border-bottom: 1px solid var(--border); padding: 0 12px; gap: 4px; z-index: 200; } /* 로고 */ .tmb-logo { display: flex; align-items: center; gap: 7px; margin-right: 4px; text-decoration: none; } .tmb-logo-text { font-size: 14px; font-weight: 700; letter-spacing: 0.3px; color: var(--text); white-space: nowrap; } /* 구분선 */ .tmb-divider { width: 1px; height: 20px; background: var(--border); margin: 0 8px; flex-shrink: 0; } .tmb-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; flex-shrink: 0; } /* 네비게이션 */ .tmb-nav { display: flex; align-items: center; gap: 2px; flex: 1; } .tmb-nav-btn { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 12px; border: none; border-radius: 6px; background: none; color: var(--text2); font-size: 13px; font-weight: 500; cursor: pointer; white-space: nowrap; transition: background 0.15s, color 0.15s; } .tmb-nav-btn:hover { background: var(--bg4); color: var(--text); } .tmb-nav-btn--active { background: rgba(var(--accent-rgb, 122, 162, 247), 0.15); color: var(--accent); } .app.dark .tmb-nav-btn--active { background: rgba(122, 162, 247, 0.13); } .app.blue .tmb-nav-btn--active { background: rgba(94, 181, 255, 0.13); } .app.light .tmb-nav-btn--active { background: rgba(25, 118, 210, 0.10); } .tmb-nav-icon { display: flex; align-items: center; opacity: 0.85; } .tmb-nav-btn--active .tmb-nav-icon { opacity: 1; } .tmb-nav-label { font-size: 13px; } /* 우측 영역 */ .tmb-right { display: flex; align-items: center; gap: 4px; margin-left: auto; flex-shrink: 0; } /* 테마 버튼 */ .tmb-theme-btn { display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 10px; border-radius: 5px; border: 1px solid var(--border); background: none; font-size: 12px; cursor: pointer; color: var(--text2); transition: background 0.15s, color 0.15s, border-color 0.15s; white-space: nowrap; } .tmb-theme-btn:hover { background: var(--bg4); color: var(--text); } .tmb-theme-btn--dark { border-color: #7aa2f7; color: #7aa2f7; } .tmb-theme-btn--blue { border-color: #5eb5ff; color: #5eb5ff; } .tmb-theme-btn--light { border-color: #1976d2; color: #1976d2; background: rgba(25,118,210,0.06); } .tmb-theme-icon { font-size: 13px; line-height: 1; } .tmb-theme-label { font-size: 12px; font-weight: 500; } /* 로그인 버튼 */ .tmb-login-btn { display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 12px; border-radius: 5px; border: 1px solid var(--accent); background: none; color: var(--accent); font-size: 12px; font-weight: 600; cursor: pointer; transition: background 0.15s, color 0.15s; white-space: nowrap; } .tmb-login-btn:hover { background: var(--accent); color: #fff; } .app.light .tmb-login-btn:hover { color: #fff; } /* ══════════════════════════════════════════════════════════════════ TOP TOOLBAR ══════════════════════════════════════════════════════════════════ */ .tv-toolbar { display: flex; align-items: center; height: var(--toolbar-h); background: var(--bg2); border-bottom: 1px solid var(--border); padding: 0 8px; flex-shrink: 0; gap: 2px; /* overflow-x: auto는 overflow-y: visible을 무력화하므로 팝업이 toolbar 아래로 보일 수 있도록 overflow: visible 사용. toolbar 자체 가로 스크롤이 필요한 경우 내부 left/right 섹션에서 처리. */ overflow: visible; } .tv-toolbar-left { display: flex; align-items: center; gap: 2px; flex: 1; overflow: visible; } .tv-toolbar-right { display: flex; align-items: center; gap: 2px; flex-shrink: 0; } /* Separator */ .tv-sep { width: 1px; height: 22px; background: var(--sep); margin: 0 4px; flex-shrink: 0; } /* Generic icon button */ .tv-icon-btn { display: flex; align-items: center; justify-content: center; width: 30px; height: 30px; background: transparent; color: var(--text2); border: none; border-radius: var(--radius); cursor: pointer; transition: background 0.12s, color 0.12s; flex-shrink: 0; } .tv-icon-btn:hover { background: var(--bg3); color: var(--text); } .tv-icon-btn.active, .tv-icon-btn--active { background: var(--accent); color: #fff; } .tv-icon-btn--active:hover { background: var(--accent-h); } /* Symbol button */ .tv-sym-wrap { position: relative; } .tv-sym-btn { display: flex; align-items: center; gap: 6px; padding: 5px 10px; background: transparent; color: var(--text); border: none; border-radius: var(--radius); cursor: pointer; font-size: 14px; font-weight: 700; letter-spacing: 0.3px; transition: background 0.12s; white-space: nowrap; } .tv-sym-btn:hover { background: var(--bg3); } .tv-sym-btn svg { color: var(--text2); flex-shrink: 0; } .tv-sym-text { color: var(--text); } .tv-sym-input { font-size: 14px; font-weight: 700; background: var(--bg3); color: var(--text); border: 1.5px solid var(--accent); border-radius: var(--radius); padding: 4px 10px; width: 120px; outline: none; } /* Timeframe dropdown */ .tv-dropdown-wrap { position: relative; } .tv-tf-btn { display: flex; align-items: center; padding: 5px 8px; background: transparent; color: var(--text); border: none; border-radius: var(--radius); cursor: pointer; font-size: 13px; font-weight: 600; transition: background 0.12s; white-space: nowrap; } .tv-tf-btn:hover { background: var(--bg3); } .tv-dropdown { position: absolute; top: calc(100% + 4px); left: 0; background: var(--bg2); border: 1px solid var(--border); border-radius: 4px; box-shadow: 0 4px 16px rgba(0,0,0,0.3); z-index: 200; min-width: 80px; padding: 4px; display: flex; flex-direction: column; gap: 1px; } .tv-dropdown-item { display: flex; align-items: center; padding: 6px 10px; background: transparent; color: var(--text); border: none; border-radius: 2px; cursor: pointer; font-size: 12px; text-align: left; transition: background 0.1s; white-space: nowrap; } .tv-dropdown-item:hover { background: var(--bg3); } .tv-dropdown-item.active { background: var(--accent); color: #fff; } /* Chart type icon button */ .tv-ct-btn { width: 32px; } /* Indicators button */ .tv-indicators-btn { display: flex; align-items: center; gap: 5px; padding: 5px 10px; background: transparent; color: var(--text2); border: none; border-radius: var(--radius); cursor: pointer; font-size: 12px; font-weight: 500; transition: background 0.12s, color 0.12s; white-space: nowrap; } .tv-indicators-btn:hover { background: var(--bg3); color: var(--text); } .tv-ind-badge { display: inline-flex; align-items: center; justify-content: center; background: var(--accent); color: #fff; border-radius: 9px; padding: 0 5px; min-width: 17px; height: 15px; font-size: 10px; font-weight: 700; } /* Save / Mode button */ .tv-save-btn { display: flex; align-items: center; gap: 4px; padding: 5px 12px; background: transparent; color: var(--text2); border: 1px solid var(--sep); border-radius: var(--radius); cursor: pointer; font-size: 12px; font-weight: 600; transition: all 0.12s; white-space: nowrap; } .tv-save-btn:hover { background: var(--bg3); color: var(--text); } .tv-save-btn.trading { border-color: var(--accent); color: var(--accent); background: #2962ff18; } .tv-save-btn.trading:hover { background: #2962ff28; } /* Theme Cycle Button */ .tv-theme-cycle { display: flex; align-items: center; gap: 4px; padding: 5px 10px; border: 1px solid var(--sep); border-radius: var(--radius); background: transparent; color: var(--text2); cursor: pointer; font-size: 12px; font-weight: 500; white-space: nowrap; transition: all 0.15s; } .tv-theme-cycle:hover { background: var(--bg3); color: var(--text); } .tv-theme-cycle.theme-dark { border-color: #7aa2f7; color: #7aa2f7; } .tv-theme-cycle.theme-blue { border-color: #5eb5ff; color: #5eb5ff; } .tv-theme-cycle.theme-light { border-color: #1976d2; color: #1976d2; background: rgba(25,118,210,0.06); } /* ══════════════════════════════════════════════════════════════════ UPBIT STATUS BAR ══════════════════════════════════════════════════════════════════ */ .upbit-bar { display: flex; align-items: center; gap: 10px; padding: 3px 12px; height: 28px; flex-shrink: 0; border-bottom: 1px solid var(--border); background: var(--bg2); font-size: 12px; } .upbit-bar.connected { border-bottom-color: #69f0ae44; } .upbit-bar.disconnected { border-bottom-color: #ef535044; } .upbit-bar.error { border-bottom-color: #ef535088; background: #ef535010; } .ws-badge { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; color: var(--text2); } /* 연두색 (연결 정상) */ .ws-badge.dot-lime { color: #69f0ae; } .ws-badge.dot-yellow { color: #FFB800; } .ws-badge.dot-red { color: var(--down); } /* 기본 상태 표시 점 */ .ws-dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; transition: box-shadow 0.4s ease-out, transform 0.3s ease-out, background 0.3s ease-out; } /* 연결됨: 천천히 페이드 pulse (idle 상태) */ .ws-badge.dot-lime .ws-dot { animation: ws-idle-lime 2.5s ease-in-out infinite; } /* ─── 데이터 수신 중: 형광 연두색 glow ─── */ .ws-dot.receiving { animation: none !important; /* idle 애니메이션 일시 중단 */ background: #b9f6ca !important; /* 밝은 연두 */ transform: scale(1.4); box-shadow: 0 0 6px 3px #69f0ae, /* 내부 glow */ 0 0 14px 6px #69f0ae66, /* 외부 glow */ 0 0 24px 10px #b9f6ca22; /* 넓은 음영 */ } @keyframes ws-idle-lime { 0%, 100% { opacity: 1; box-shadow: 0 0 3px 1px #69f0ae55; } 50% { opacity: 0.4; box-shadow: none; } } .upbit-market { font-weight: 700; color: var(--text); } .upbit-price { font-weight: 700; font-size: 13px; } .upbit-change.up { color: var(--up); font-weight: 600; } .upbit-change.down { color: var(--down); font-weight: 600; } .upbit-loading { color: var(--text2); } .upbit-error { color: var(--down); } .upbit-hint { margin-left: auto; color: var(--text3); font-size: 11px; white-space: nowrap; } /* ══════════════════════════════════════════════════════════════════ MAIN AREA (sidebar + chart) ══════════════════════════════════════════════════════════════════ */ .tv-main { display: flex; flex: 1; min-height: 0; overflow: hidden; } /* ── Left Drawing Sidebar ───────────────────────────────────────── */ .tv-drawing-sidebar { display: flex; flex-direction: column; align-items: center; width: var(--sidebar-w); background: var(--bg2); border-right: 1px solid var(--border); padding: 6px 0; flex-shrink: 0; overflow-y: auto; overflow-x: hidden; } .tv-side-btn { display: flex; align-items: center; justify-content: center; width: 36px; height: 36px; background: transparent; color: var(--text3); border: none; border-radius: var(--radius); cursor: pointer; margin: 1px 0; transition: background 0.12s, color 0.12s; flex-shrink: 0; } .tv-side-btn:hover { background: var(--bg3); color: var(--text); } .tv-side-btn.active { background: var(--accent); color: #fff; } .tv-side-btn.active:hover { background: var(--accent-h); } /* Chart mode: all tools dimmed */ .tv-drawing-sidebar.chart-mode .tv-side-btn { opacity: 0.4; cursor: default; pointer-events: none; } .tv-drawing-sidebar.chart-mode .tv-side-btn:first-child { /* cursor button always active */ opacity: 1; pointer-events: auto; } .tv-side-sep { width: 24px; height: 1px; background: var(--sep); margin: 4px auto; } .tv-side-spacer { flex: 1; } .tv-side-clear:hover { color: var(--down) !important; } /* 잠금 활성화 시 주황 강조 */ .tv-side-btn.tv-side-lock-on { background: #FF6D0033 !important; color: #FF6D00 !important; } .tv-side-btn.tv-side-lock-on:hover { background: #FF6D0055 !important; } /* 숨기기 활성화 시 회색 강조 */ .tv-side-btn.tv-side-eye-off { background: var(--bg3) !important; color: var(--text3) !important; opacity: 0.6; } /* ── 툴 그룹 래퍼 ──────────────────────────────────────────────── */ .tv-side-group { position: relative; display: contents; } /* 서브툴 보유 버튼 우하단 작은 삼각 표시 */ .tv-side-group-btn { position: relative !important; } .tv-side-group-btn--favorite.active { background: #FFB30033 !important; color: #FFB300 !important; } .tv-side-group-btn--favorite.active:hover { background: #FFB30055 !important; } .tv-side-expand-arrow { position: absolute; bottom: 3px; right: 3px; width: 0; height: 0; border-style: solid; border-width: 0 0 5px 5px; border-color: transparent transparent currentColor transparent; opacity: 0.45; pointer-events: none; } .tv-side-group-btn.active .tv-side-expand-arrow { opacity: 0.8; } /* ── 플라이아웃 팝업 ─────────────────────────────────────────────── */ .tv-side-flyout { position: fixed; z-index: 9900; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 5px 4px; min-width: 230px; box-shadow: 0 10px 32px rgba(0,0,0,.55); pointer-events: auto; animation: flyout-in 0.1s ease; } @keyframes flyout-in { from { opacity: 0; transform: translateX(-6px); } to { opacity: 1; transform: translateX(0); } } .tv-side-flyout-header { font-size: 10.5px; font-weight: 700; color: var(--text3); padding: 3px 10px 5px; text-transform: uppercase; letter-spacing: 0.06em; border-bottom: 1px solid var(--border); margin-bottom: 3px; } .tv-side-flyout-item { display: flex; align-items: center; gap: 9px; width: 100%; padding: 6px 10px; background: transparent; border: none; border-radius: 7px; cursor: pointer; color: var(--text2); font-size: 12.5px; text-align: left; transition: background 0.1s, color 0.1s; } .tv-side-flyout-item:hover { background: var(--bg3); color: var(--text); } .tv-side-flyout-item.active { background: rgba(122,162,247,.15); color: var(--accent); } .tv-side-flyout-item.active:hover { background: rgba(122,162,247,.22); } .tv-side-flyout-icon { display: flex; align-items: center; justify-content: center; flex-shrink: 0; width: 20px; height: 20px; color: inherit; } .tv-side-flyout-title { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .tv-side-flyout-shortcut { font-size: 10.5px; color: var(--text3); background: var(--bg3); border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; flex-shrink: 0; font-family: monospace; letter-spacing: 0.04em; } /* ── 플라이아웃 섹션 구분선 ─────────────────────────────────────── */ .tv-side-flyout-sep { display: flex; align-items: center; gap: 6px; margin: 4px 6px; height: 18px; } .tv-side-flyout-sep::before { content: ''; flex: 1; height: 1px; background: var(--border); opacity: 0.7; } .tv-side-flyout-sep:empty::after { content: none; } .tv-side-flyout-sec-label { font-size: 10px; color: var(--text3); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; white-space: nowrap; } .tv-side-flyout-sec-label::before { content: none !important; } /* ── 플라이아웃 토글 행 ────────────────────────────────────────── */ .tv-side-flyout-toggle-row { display: flex; align-items: center; justify-content: space-between; padding: 6px 10px; gap: 10px; } .tv-side-flyout-toggle-row .tv-side-flyout-title { font-size: 12px; color: var(--text2); } /* ── 토글 스위치 버튼 ──────────────────────────────────────────── */ .tv-flyout-toggle { position: relative; width: 34px; height: 18px; border-radius: 9px; border: none; background: var(--bg3); cursor: pointer; flex-shrink: 0; transition: background 0.2s; padding: 0; } .tv-flyout-toggle::after { content: ''; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; border-radius: 50%; background: var(--text3); transition: transform 0.2s, background 0.2s; } .tv-flyout-toggle.on { background: var(--accent); } .tv-flyout-toggle.on::after { transform: translateX(16px); background: #fff; } /* ── 눈 부분 활성 표시 ─────────────────────────────────────────── */ .tv-side-btn.tv-side-eye-partial { color: var(--text3); opacity: 0.7; } /* ── Chart Column ───────────────────────────────────────────────── */ .tv-chart-col { flex: 1; display: flex; flex-direction: column; position: relative; overflow: hidden; border-right: 1px solid var(--border); min-width: 0; } /* ── Chart Legend ───────────────────────────────────────────────── */ .tv-legend { position: absolute; top: 6px; left: 8px; z-index: 10; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; pointer-events: none; font-size: 12px; max-width: calc(100% - 80px); } .tv-legend-sym { display: flex; align-items: center; gap: 5px; font-weight: 700; font-size: 13px; color: var(--text); } .tv-legend-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .tv-legend-tf { color: var(--text2); font-size: 12px; } .tv-legend-badge { padding: 1px 6px; border-radius: 2px; font-size: 10px; font-weight: 700; background: var(--accent); color: #fff; } .tv-legend-badge.trading { background: #ff6d0020; color: #FF6D00; border: 1px solid #FF6D0044; } .tv-legend-ohlcv { display: flex; align-items: center; gap: 8px; color: var(--text2); font-size: 12px; } .tv-legend-ohlcv b { font-weight: 600; } .tv-legend-chg { font-weight: 600; } .tv-legend-ind { padding: 1px 5px; background: var(--bg3); border-radius: 2px; font-size: 11px; color: var(--text2); display: inline-flex; align-items: center; gap: 4px; } .tv-legend-ind-name { color: var(--text2); } .tv-legend-ind-vals { display: inline-flex; gap: 5px; } .tv-legend-ind-vals b { font-weight: 600; font-size: 11px; } /* 차트 스크롤 래퍼 - position: relative : DrawingCanvas 절대좌표 기준 - overflow-y: auto : 보조지표 많을 때 세로 스크롤 - flex: 1 / min-height:0 : 상위 flex 컨테이너에서 가용 높이 확보 - display: block (flex 아님): flex+overflow 조합 시 자식 height 계산 오류 방지 */ .tv-chart-wrap { flex: 1; min-height: 0; position: relative; overflow-y: auto; overflow-x: hidden; } .tv-chart-wrap::-webkit-scrollbar { width: 6px; } .tv-chart-wrap::-webkit-scrollbar-track { background: transparent; } .tv-chart-wrap::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 3px; } /* Chart container - height: 100% : 기본 상태에서 래퍼를 가득 채움 - JS 에서 스크롤 필요 시 명시적 height (e.g. 900px)로 전환 */ .chart-container { width: 100%; height: 100%; } /* Loading overlay */ /* 과거 데이터 추가 로드 중 표시 (차트 좌상단 소형 배지) */ .chart-history-loading { position: absolute; top: 6px; left: 8px; z-index: 30; display: flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 6px; background: var(--bg3, rgba(30,30,46,0.85)); color: var(--text2, #9a9cad); font-size: 11px; pointer-events: none; } .chart-loading { position: absolute; inset: 0; z-index: 50; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; background: var(--bg)cc; color: var(--text2); font-size: 13px; } .loading-spinner { width: 32px; height: 32px; border: 3px solid var(--bg4); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.8s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* ══════════════════════════════════════════════════════════════════ BOTTOM BAR ══════════════════════════════════════════════════════════════════ */ .tv-bottom-bar { display: flex; align-items: center; height: var(--bottombar-h); background: var(--bg2); border-top: 1px solid var(--border); padding: 0 8px; flex-shrink: 0; gap: 2px; overflow-x: auto; overflow-y: visible; position: relative; z-index: 120; } .tv-period-group { display: flex; align-items: center; gap: 1px; } .tv-period-btn { display: flex; align-items: center; justify-content: center; padding: 3px 7px; background: transparent; color: var(--text2); border: none; border-radius: 2px; cursor: pointer; font-size: 12px; font-weight: 500; transition: background 0.1s, color 0.1s; white-space: nowrap; height: 22px; } .tv-period-btn:hover { background: var(--bg3); color: var(--text); } .tv-period-btn.active { color: var(--accent); font-weight: 700; } .tv-toggle-btn.active { color: var(--accent); font-weight: 700; } .tv-bottom-spacer { flex: 1; } .tv-time-display { font-size: 12px; color: var(--text2); padding: 0 8px; white-space: nowrap; } .tv-right-toggles { margin-left: 4px; } /* 시간대 선택 (하단 바) */ .tz-picker { position: relative; flex-shrink: 0; } .tz-picker-trigger { display: inline-flex; align-items: center; gap: 6px; background: transparent; border: none; cursor: pointer; font-size: 12px; color: var(--text2); padding: 3px 8px; border-radius: 2px; white-space: nowrap; } .tz-picker-trigger:hover { background: var(--bg3); color: var(--text); } .tz-picker-clock { font-variant-numeric: tabular-nums; } .tz-picker-abbr { color: var(--text); font-weight: 600; } .tz-picker-caret { font-size: 9px; opacity: 0.7; } .tz-picker-menu { position: absolute; bottom: calc(100% + 4px); right: 0; min-width: 240px; max-height: 280px; overflow-y: auto; margin: 0; padding: 4px 0; list-style: none; background: var(--bg2); border: 1px solid var(--border); border-radius: 4px; box-shadow: var(--popup-shadow); z-index: 600; } /* 하단 바 — overflow 클리핑 회피 (body 포털) */ .tz-picker-menu--portal { position: fixed; bottom: auto; right: auto; z-index: 9900; } .tz-picker-item { display: flex; align-items: center; justify-content: space-between; width: 100%; padding: 7px 12px; background: transparent; border: none; color: var(--text); font-size: 12px; cursor: pointer; text-align: left; } .tz-picker-item:hover { background: var(--bg3); } .tz-picker-item.active { color: var(--accent); } .tz-picker-item-abbr { color: var(--text2); font-size: 11px; margin-left: 8px; } /* ══════════════════════════════════════════════════════════════════ FLOATING PANELS (Stats / Watchlist / Alert) ══════════════════════════════════════════════════════════════════ */ .stats-panel, .watchlist-panel, .alert-panel { position: fixed; top: calc(var(--toolbar-h) + 8px); right: 10px; z-index: 500; background: var(--bg2); border: 1px solid var(--border); border-radius: 6px; box-shadow: 0 6px 24px rgba(0,0,0,.35); padding: 12px; width: 240px; max-height: 420px; overflow-y: auto; } .panel-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; font-weight: 700; font-size: 13px; } .panel-close { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 16px; line-height: 1; padding: 0 2px; } .panel-close:hover { color: var(--text); } .panel-row { display: flex; justify-content: space-between; align-items: center; padding: 4px 0; border-bottom: 1px solid var(--border); font-size: 12px; } .panel-row:last-child { border-bottom: none; } .panel-label { color: var(--text2); } .panel-val { font-weight: 600; } .panel-val.up { color: var(--up); } .panel-val.down { color: var(--down); } .watchlist-item { display: flex; align-items: center; gap: 6px; padding: 5px 0; cursor: pointer; border-bottom: 1px solid var(--border); } .watchlist-item:last-child { border-bottom: none; } .watchlist-item:hover .wl-sym { color: var(--accent); } .wl-sym { font-weight: 700; font-size: 12px; flex: 1; } .wl-price { font-size: 12px; font-weight: 600; } .wl-chg { font-size: 11px; min-width: 52px; text-align: right; } .wl-rm { background: none; border: none; color: var(--text3); cursor: pointer; font-size: 12px; padding: 0 2px; } .wl-rm:hover { color: var(--down); } .wl-add { display: flex; gap: 4px; margin-top: 8px; } .wl-add input { flex: 1; background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: 2px; padding: 4px 8px; font-size: 12px; outline: none; } .wl-add input:focus { border-color: var(--accent); } .wl-add-btn { background: var(--accent); color: #fff; border: none; border-radius: 2px; padding: 4px 10px; cursor: pointer; font-size: 12px; } .alert-input-row { display: flex; gap: 4px; margin-bottom: 8px; } .alert-input-row input { flex: 1; background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: 2px; padding: 4px 8px; font-size: 12px; outline: none; } .alert-input-row input:focus { border-color: var(--accent); } .alert-add-btn { background: var(--accent); color: #fff; border: none; border-radius: 2px; padding: 4px 10px; cursor: pointer; font-size: 12px; } .alert-item { display: flex; align-items: center; gap: 6px; padding: 4px 0; border-bottom: 1px solid var(--border); } .alert-item:last-child { border-bottom: none; } .alert-price { font-weight: 700; flex: 1; font-size: 12px; } .alert-label { color: var(--text2); font-size: 11px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .alert-rm { background: none; border: none; color: var(--text3); cursor: pointer; font-size: 12px; padding: 0 2px; } .alert-rm:hover { color: var(--down); } /* ══════════════════════════════════════════════════════════════════ INDICATOR PANEL (fixed overlay) ══════════════════════════════════════════════════════════════════ */ /* 반투명 배경 오버레이 */ .ind-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.5); z-index: 2000; } /* 패널 본체 */ .ind-panel { position: relative; width: min(520px, 95vw); max-height: calc(100vh - 48px); background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6); display: flex; flex-direction: column; overflow: hidden; } /* 검색 행 */ .ind-panel-search-row { display: flex; align-items: center; gap: 8px; padding: 12px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .ind-panel-search-wrap { flex: 1; display: flex; align-items: center; gap: 8px; background: var(--bg3); border: 1.5px solid var(--border); border-radius: 5px; padding: 0 10px; color: var(--text2); transition: border-color 0.15s; } .ind-panel-search-wrap:focus-within { border-color: var(--accent); } .ind-panel-search { flex: 1; background: transparent; border: none; color: var(--text); font-size: 14px; outline: none; padding: 9px 0; } .ind-panel-search::placeholder { color: var(--text2); } .ind-panel-clear { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 13px; padding: 0; line-height: 1; } .ind-panel-clear:hover { color: var(--text); } .ind-panel-close { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 18px; line-height: 1; padding: 4px 6px; border-radius: 4px; flex-shrink: 0; transition: background 0.1s; } .ind-panel-close:hover { background: var(--bg4); color: var(--text); } /* 카테고리 탭 */ .ind-panel-cats-row { display: flex; align-items: stretch; gap: 6px; padding: 7px 10px; border-bottom: 1px solid var(--border); flex-shrink: 0; min-height: 0; } .ind-panel-cats { display: flex; gap: 2px; overflow-x: auto; overflow-y: hidden; flex: 1; min-width: 0; flex-wrap: nowrap; scrollbar-width: thin; scrollbar-color: var(--bg4) transparent; -webkit-overflow-scrolling: touch; } .ind-panel-cats-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; padding-left: 4px; border-left: 1px solid var(--border); } .ind-panel-cat-action { padding: 4px 8px; background: var(--bg3); color: var(--text2); border: 1px solid var(--border); border-radius: 4px; cursor: pointer; font-size: 11px; font-weight: 500; white-space: nowrap; transition: all 0.1s; } .ind-panel-cat-action:hover:not(:disabled) { background: var(--bg4); color: var(--text); } .ind-panel-cat-action:disabled { opacity: 0.35; cursor: not-allowed; } .ind-panel-cat-action.danger:hover:not(:disabled) { background: rgba(239, 68, 68, 0.15); color: #ef4444; border-color: rgba(239, 68, 68, 0.35); } .ind-panel-cats::-webkit-scrollbar { height: 5px; } .ind-panel-cats::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 3px; } .ind-panel-cat { padding: 5px 10px; background: transparent; color: var(--text2); border: 1px solid transparent; border-radius: 4px; cursor: pointer; font-size: 12px; font-weight: 500; white-space: nowrap; flex-shrink: 0; transition: all 0.1s; } .ind-panel-cat:hover { background: var(--bg3); color: var(--text); } .ind-panel-cat.active { background: var(--accent); color: #fff; } .ind-panel-cat-cnt { font-size: 10px; opacity: 0.75; } /* 사용자 정의 탭 편집 */ .ind-tab-editor-overlay { position: absolute; inset: 0; z-index: 10; display: flex; align-items: center; justify-content: center; background: rgba(0, 0, 0, 0.55); border-radius: inherit; } .ind-tab-editor { display: flex; flex-direction: column; width: min(420px, calc(100% - 24px)); max-height: calc(100% - 24px); background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45); overflow: hidden; } .ind-tab-editor-header { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .ind-tab-editor-title { font-size: 14px; font-weight: 600; color: var(--text); } .ind-tab-editor-body { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: 10px; padding: 12px; overflow: hidden; } .ind-tab-editor-field { display: flex; flex-direction: column; gap: 6px; flex-shrink: 0; } .ind-tab-editor-label-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; } .ind-tab-editor-label { font-size: 11px; font-weight: 600; color: var(--text2); flex: 1; } .ind-tab-editor-link { background: none; border: none; color: var(--accent); font-size: 11px; cursor: pointer; padding: 0; } .ind-tab-editor-link:hover { text-decoration: underline; } .ind-tab-editor-input { width: 100%; padding: 7px 10px; background: var(--bg3); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 13px; box-sizing: border-box; } .ind-tab-editor-input:focus { outline: none; border-color: var(--accent); } .ind-tab-editor-list { flex: 1; min-height: 120px; overflow-y: auto; border: 1px solid var(--border); border-radius: 4px; background: var(--bg1); } .ind-tab-editor-item { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; cursor: pointer; border-bottom: 1px solid var(--border); transition: background 0.1s; } .ind-tab-editor-item:last-child { border-bottom: none; } .ind-tab-editor-item:hover { background: var(--bg3); } .ind-tab-editor-item.checked { background: #2962ff12; } .ind-tab-editor-item input { margin-top: 3px; flex-shrink: 0; accent-color: var(--accent); } .ind-tab-editor-item-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .ind-tab-editor-item-name { font-size: 13px; font-weight: 500; color: var(--text); } .ind-tab-editor-item-desc { font-size: 11px; color: var(--text2); } .ind-tab-editor-footer { display: flex; justify-content: flex-end; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--border); flex-shrink: 0; } .ind-tab-editor-btn { padding: 7px 16px; border-radius: 4px; font-size: 13px; font-weight: 500; cursor: pointer; border: 1px solid var(--border); } .ind-tab-editor-btn.cancel { background: var(--bg3); color: var(--text2); } .ind-tab-editor-btn.cancel:hover { color: var(--text); } .ind-tab-editor-btn.save { background: var(--accent); color: #fff; border-color: var(--accent); } .ind-tab-editor-btn.save:hover { filter: brightness(1.08); } /* 목록 */ .ind-panel-list { flex: 1; overflow-y: auto; padding: 6px 8px; } .ind-panel-section-title { font-size: 10px; font-weight: 700; color: var(--text2); text-transform: uppercase; letter-spacing: 0.6px; padding: 6px 8px 4px; } .ind-panel-divider { height: 1px; background: var(--border); margin: 6px 0; } .ind-panel-item { display: flex; align-items: center; padding: 9px 10px; border-radius: 5px; gap: 10px; transition: background 0.1s; } .ind-panel-item:hover { background: var(--bg3); } .ind-panel-item.active { background: #2962ff0e; } .ind-panel-item-info { flex: 1; overflow: hidden; display: flex; flex-direction: column; gap: 3px; } .ind-panel-name { font-size: 13px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .ind-panel-desc { font-size: 11px; color: var(--text2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .ind-panel-item-right { display: flex; align-items: center; gap: 5px; flex-shrink: 0; } .ind-panel-badge { padding: 2px 6px; border-radius: 3px; font-size: 10px; font-weight: 600; background: #2962ff1a; color: var(--accent); } .ind-panel-add { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; background: var(--accent); color: #fff; border: none; border-radius: 5px; cursor: pointer; transition: background 0.1s; } .ind-panel-add:hover { background: var(--accent-h); } .ind-panel-rm { padding: 4px 10px; background: var(--down); color: #fff; border: none; border-radius: 4px; cursor: pointer; font-size: 11px; font-weight: 600; white-space: nowrap; } .ind-panel-rm:hover { opacity: 0.85; } .ind-panel-settings { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg3); color: var(--text2); cursor: pointer; flex-shrink: 0; line-height: 0; } .ind-panel-settings:hover { border-color: var(--accent); color: var(--accent); background: rgba(122, 162, 247, 0.12); } .ind-panel-empty { padding: 40px; text-align: center; color: var(--text2); font-size: 13px; } /* tv-indicators-btn 활성 상태 */ .tv-indicators-btn.active { background: var(--bg3); color: var(--text); } /* ══════════════════════════════════════════════════════════════════ INDICATOR MODAL (레거시, 사용 안함) ══════════════════════════════════════════════════════════════════ */ .modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.55); z-index: 500; } .modal-box { background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; width: min(780px, 95vw); height: min(540px, 90vh); display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.5); } .modal-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; cursor: grab; user-select: none; background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .modal-header:active { cursor: grabbing; } .modal-title { flex: 1; font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); min-width: 0; } .modal-close-btn { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 20px; line-height: 1; padding: 2px; } .modal-close-btn:hover { color: var(--text); } .modal-search-row { padding: 10px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .modal-search { width: 100%; background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: var(--radius); padding: 7px 12px; font-size: 13px; outline: none; } .modal-search:focus { border-color: var(--accent); } .modal-body { display: flex; flex: 1; min-height: 0; } .modal-cats { width: 140px; border-right: 1px solid var(--border); padding: 8px; overflow-y: auto; flex-shrink: 0; } .modal-cat-btn { display: block; width: 100%; padding: 7px 10px; background: transparent; color: var(--text2); border: none; border-radius: 3px; cursor: pointer; text-align: left; font-size: 12px; transition: background 0.1s; margin-bottom: 1px; } .modal-cat-btn:hover { background: var(--bg3); color: var(--text); } .modal-cat-btn.active { background: var(--accent); color: #fff; } .modal-list { flex: 1; overflow-y: auto; padding: 6px; } .indicator-item { display: flex; align-items: center; padding: 8px 10px; border-radius: 4px; cursor: pointer; transition: background 0.1s; gap: 10px; } .indicator-item:hover { background: var(--bg3); } .indicator-item.in-use { opacity: 0.6; } .indicator-item-left { display: flex; flex-direction: column; gap: 2px; overflow: hidden; flex: 1; } .indicator-name { font-size: 12px; font-weight: 600; color: var(--text); } .indicator-desc { font-size: 11px; color: var(--text2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .indicator-item-right { display: flex; align-items: center; gap: 5px; flex-shrink: 0; } .badge { padding: 1px 5px; border-radius: 2px; font-size: 10px; font-weight: 600; } .badge.overlay { background: #2962ff1a; color: var(--accent); } .badge.markers { background: #ff980018; color: #FF9800; } .add-btn { background: var(--accent); color: #fff; border: none; border-radius: 3px; padding: 3px 10px; cursor: pointer; font-size: 11px; font-weight: 600; } .rm-btn { background: var(--down); color: #fff; border: none; border-radius: 3px; padding: 3px 8px; cursor: pointer; font-size: 11px; } .indicator-settings { width: 210px; flex-shrink: 0; overflow-y: auto; padding: 12px; border-left: 1px solid var(--border); } .settings-title { font-size: 12px; font-weight: 700; margin-bottom: 4px; } .settings-desc { font-size: 11px; color: var(--text2); margin-bottom: 10px; line-height: 1.4; } .param-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; } .param-label { font-size: 11px; color: var(--text2); } .param-input { width: 75px; background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: 2px; padding: 3px 6px; font-size: 12px; outline: none; } .param-input:focus { border-color: var(--accent); } .param-row .ism-num-combo { width: 75px; } .param-row .ism-num-combo .param-input { width: 100%; } .settings-actions { display: flex; gap: 6px; margin-top: 10px; } .settings-add-btn { flex: 1; background: var(--accent); color: #fff; border: none; border-radius: 3px; padding: 6px; cursor: pointer; font-weight: 600; font-size: 12px; } .settings-cancel { background: var(--bg3); color: var(--text2); border: none; border-radius: 3px; padding: 6px 10px; cursor: pointer; font-size: 12px; } .plot-preview { margin-top: 10px; border-top: 1px solid var(--border); padding-top: 8px; } .plot-legend-row { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; } .plot-color { width: 18px; height: 3px; border-radius: 1px; } .plot-title { font-size: 11px; color: var(--text2); } .no-results { padding: 30px; text-align: center; color: var(--text2); font-size: 13px; } .modal-active { padding: 8px 12px; border-top: 1px solid var(--border); flex-shrink: 0; } .active-title { font-size: 11px; font-weight: 700; color: var(--text2); margin-bottom: 5px; } .active-list { display: flex; flex-wrap: wrap; gap: 4px; max-height: 55px; overflow-y: auto; } .active-tag { display: flex; align-items: center; gap: 4px; background: var(--bg3); border-radius: 2px; padding: 2px 8px; font-size: 11px; color: var(--text); } .active-tag button { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 11px; padding: 0 1px; } /* ══════════════════════════════════════════════════════════════════ DRAWING CANVAS ══════════════════════════════════════════════════════════════════ */ .drawing-overlay { position: absolute; inset: 0; pointer-events: none; z-index: 20; } .drawing-overlay canvas { position: absolute; inset: 0; } /* ══════════════════════════════════════════════════════════════════ UTILITY ══════════════════════════════════════════════════════════════════ */ .up { color: var(--up); } .down { color: var(--down); } ::-webkit-scrollbar { width: 5px; height: 5px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 3px; } ::-webkit-scrollbar-thumb:hover { background: var(--text3); } /* Responsive */ @media (max-width: 600px) { :root { --sidebar-w: 36px; } .tv-sym-text { max-width: 70px; overflow: hidden; text-overflow: ellipsis; } .tv-theme-label { display: none; } .tv-indicators-btn span:first-of-type { display: none; } } /* ═══════════════════════════════════════════════════════════════ Market Search Panel (msp-*) ═══════════════════════════════════════════════════════════════ */ /* 배경 반투명 오버레이 */ .msp-backdrop { position: fixed; inset: 0; /* 기본값: 전체화면 투명 backdrop (툴바용) */ z-index: 1200; background: transparent; } /* 슬롯용 backdrop/panel은 인라인 z-index(99999) 로 override됨 */ /* 메인 패널 (툴바에서 열릴 때 기본 위치 - 전체화면 좌측 고정) */ .msp-panel { position: fixed; top: 40px; left: 0; width: 480px; max-width: 95vw; height: calc(100vh - 40px); background: var(--bg2); border-right: 1px solid var(--border); border-bottom: 1px solid var(--border); z-index: 1201; display: flex; flex-direction: column; box-shadow: 6px 0 24px var(--popup-shadow); } /* 슬롯 내 심볼 버튼에서 열릴 때: 인라인 스타일로 위치 override됨. 공통 시각 스타일만 여기서 재정의 */ .msp-panel--slot { border-right: none; border: 1px solid var(--border); border-radius: 6px; box-shadow: var(--popup-shadow); /* top/left/width/height 는 JS 인라인 스타일로 지정됨 */ } .msp-panel--dropdown { border-radius: 8px; box-shadow: var(--popup-shadow); overflow: hidden; display: flex; flex-direction: column; } .msp-header--compact, .msp-item--compact { grid-template-columns: minmax(160px, 1fr) 92px 68px; } .msp-header--compact .msp-col-name { min-width: 0; } .msp-item--compact .msp-col-name { flex-direction: row; align-items: center; min-width: 0; } .msp-item--compact .msp-kor { font-size: 13px; font-weight: 600; overflow: visible; text-overflow: clip; white-space: nowrap; } /* 검색 입력 행 */ .msp-search-row { display: flex; align-items: center; gap: 4px; padding: 8px 12px; border-bottom: 1px solid var(--border); background: var(--bg2); } .msp-search-icon { color: var(--text3); flex-shrink: 0; display: flex; align-items: center; } .msp-input { flex: 1; background: var(--bg3); border: 1px solid var(--border); border-radius: 4px; color: var(--text); padding: 6px 10px; font-size: 13px; outline: none; min-width: 0; } .msp-input:focus { border-color: var(--accent); } .msp-input::placeholder { color: var(--text3); } .msp-btn-icon { background: none; border: none; color: var(--text3); cursor: pointer; padding: 5px 7px; border-radius: 3px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .msp-btn-icon:hover { background: var(--bg4); color: var(--text); } /* 컬럼 헤더 */ .msp-header { display: grid; grid-template-columns: 32px 1fr 90px 74px 72px; padding: 5px 12px; font-size: 11px; color: var(--text3); border-bottom: 1px solid var(--border); background: var(--bg2); user-select: none; } /* 목록 */ .msp-list { flex: 1; overflow-y: auto; } .msp-list::-webkit-scrollbar { width: 4px; } .msp-list::-webkit-scrollbar-track { background: transparent; } .msp-list::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 2px; } /* 빈 상태 */ .msp-empty { padding: 24px 16px; text-align: center; color: var(--text3); font-size: 13px; } /* 각 종목 행 */ .msp-item { display: grid; grid-template-columns: 32px 1fr 90px 74px 72px; padding: 7px 12px; cursor: pointer; border-bottom: 1px solid var(--border); align-items: center; transition: background 0.1s; } .msp-item:hover { background: var(--bg3); } .msp-item.active { background: color-mix(in srgb, var(--accent) 18%, transparent); } /* 컬럼 공통 */ .msp-col { font-size: 12px; } /* 즐겨찾기 별 */ .msp-col-fav { text-align: center; font-size: 16px; line-height: 1; } .msp-star { color: var(--text3); cursor: pointer; transition: color 0.15s; } .msp-star:hover { color: #FFB800; } .msp-star.starred { color: #FFB800; } /* 종목명 컬럼 */ .msp-col-name { display: flex; flex-direction: column; gap: 1px; min-width: 0; } .msp-kor { font-size: 13px; color: var(--text); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .msp-sym { font-size: 11px; color: var(--text3); } /* 현재가 */ .msp-col-price { text-align: right; color: var(--text); font-variant-numeric: tabular-nums; } /* 전일대비 */ .msp-col-change { text-align: right; font-variant-numeric: tabular-nums; } .msp-col-change.up { color: var(--up); } .msp-col-change.down { color: var(--down); } /* 거래대금 */ .msp-col-vol { text-align: right; color: var(--text2); font-size: 11px; } /* 반응형 - 작은 화면 */ @media (max-width: 520px) { .msp-panel { width: 100vw; } } /* ── ObjectTree (오브젝트 트리) ─────────────────────────────────────── */ .obj-tree-overlay { position: fixed; inset: 0; z-index: 3000; pointer-events: none; } .obj-tree-panel { position: absolute; top: 48px; right: 8px; width: 260px; max-height: 420px; background: var(--bg2); border: 1px solid var(--sep); border-radius: 6px; box-shadow: 0 8px 28px rgba(0,0,0,0.35); display: flex; flex-direction: column; pointer-events: auto; overflow: hidden; } .obj-tree-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--sep); flex-shrink: 0; cursor: grab; user-select: none; background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .obj-tree-header:active { cursor: grabbing; } .obj-tree-title { flex: 1; font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); } .obj-tree-close { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 14px; padding: 0 2px; line-height: 1; } .obj-tree-close:hover { color: var(--text); } .obj-tree-empty { padding: 16px 12px; color: var(--text3); font-size: 12px; text-align: center; } .obj-tree-list { overflow-y: auto; flex: 1; } .obj-tree-list::-webkit-scrollbar { width: 4px; } .obj-tree-list::-webkit-scrollbar-track { background: transparent; } .obj-tree-list::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 2px; } .obj-tree-item { display: flex; align-items: center; gap: 6px; padding: 6px 10px; border-bottom: 1px solid var(--sep); cursor: default; transition: background 0.1s; } .obj-tree-item:hover { background: var(--bg3); } .obj-tree-item.hidden { opacity: 0.38; } .obj-tree-swatch { width: 8px; height: 8px; border-radius: 2px; flex-shrink: 0; } .obj-tree-icon { display: flex; align-items: center; flex-shrink: 0; } .obj-tree-name { flex: 1; font-size: 11px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .obj-tree-text-preview { color: var(--text2); font-size: 10px; } .obj-tree-num { font-size: 10px; color: var(--text3); flex-shrink: 0; } .obj-tree-btn { background: none; border: none; cursor: pointer; color: var(--text2); padding: 2px; border-radius: 3px; display: flex; align-items: center; flex-shrink: 0; } .obj-tree-btn:hover { background: var(--bg4); color: var(--text); } .obj-tree-del:hover { color: var(--down) !important; } /* Toolbar active 버튼 스타일 (그리드 토글 등) */ .tv-icon-btn.active { background: var(--accent); color: #fff; } .tv-icon-btn.active:hover { background: var(--accent-h); } .tv-btn-disabled { cursor: default !important; } /* ── PaneLegend (보조지표 pane 좌측 상단 레전드) ─────────────────────── */ .pane-legend-row { display: flex; align-items: center; gap: 6px; line-height: 1; cursor: default; user-select: none; pointer-events: auto; } .pane-legend-name--hidden { opacity: 0.42; color: var(--text-muted, #787b86); } .pane-legend-name { font-size: 11px; font-weight: 600; color: var(--text2); padding: 2px 4px; border-radius: 3px; cursor: pointer; transition: background 0.12s, color 0.12s; } .pane-legend-row:hover .pane-legend-name, .pane-legend-name:hover { background: var(--bg3); color: var(--text); } .pane-legend-val { font-size: 11px; font-weight: 700; } /* ── Pane 배경색 오버레이 ───────────────────────────────────────────── */ /* position:fixed + pointer-events:none 으로 차트 캔버스 위에 투명 색상 레이어 */ .pane-bg-overlay { pointer-events: none; transition: opacity 0.2s; /* 캔버스 위에 렌더되도록 높은 z-index 이지만 버튼보다는 아래 */ } /* ── Pane 버튼 공통 ─────────────────────────────────────────────────── */ .pane-btn { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; background: rgba(20, 24, 40, 0.82); border: 1px solid rgba(255, 255, 255, 0.18); border-radius: 4px; color: rgba(255, 255, 255, 0.65); cursor: pointer; padding: 0; transition: color 0.15s, background 0.15s, border-color 0.15s; pointer-events: auto; opacity: 0.65; } .pane-btn:hover { opacity: 1; color: #ffffff; background: rgba(122, 162, 247, 0.3); border-color: rgba(122, 162, 247, 0.7); } .pane-btn.active { opacity: 1; color: var(--accent); background: rgba(122, 162, 247, 0.22); border-color: var(--accent); } /* 닫기 버튼: 호버 시 빨간 계열 */ .pane-btn-close:hover { color: #ff6b6b; background: rgba(255, 107, 107, 0.22); border-color: rgba(255, 107, 107, 0.6); } /* 캔들 pane 좌측 하단 — 전체보기 / 원복 */ .candle-pane-controls { display: flex; flex-direction: column; gap: 4px; pointer-events: auto; opacity: 0.72; transition: opacity 0.15s; } .candle-pane-controls:hover { opacity: 1; } .tv-chart-wrap:hover .candle-pane-controls, .slot-chart-wrap:hover .candle-pane-controls { opacity: 1; } /* ── PaneLegend 드래그 핸들 ─────────────────────────────────────────── */ .pane-legend-item { /* fixed position 은 인라인 style 로 지정되므로 여기선 공통 속성만 */ user-select: none; } .pane-drag-handle { width: 22px; height: 26px; display: flex; align-items: center; justify-content: center; cursor: grab; touch-action: none; color: rgba(255, 255, 255, 0.65); opacity: 1; flex-shrink: 0; transition: color 0.15s, background 0.15s, box-shadow 0.15s; border-radius: 4px; pointer-events: auto; background: rgba(20, 24, 40, 0.82); border: 1px solid rgba(255, 255, 255, 0.18); } .pane-drag-handle:hover { color: #ffffff; background: rgba(122, 162, 247, 0.3); border-color: rgba(122, 162, 247, 0.7); } .pane-drag-handle:active { cursor: grabbing !important; color: #ffffff; background: rgba(122, 162, 247, 0.4); } /* ── 원본 위치 플레이스홀더 ─────────────────────────────────────────── */ .pane-drag-placeholder { background: repeating-linear-gradient( 45deg, transparent, transparent 8px, rgba(122, 162, 247, 0.04) 8px, rgba(122, 162, 247, 0.04) 16px ); border: 1px dashed rgba(122, 162, 247, 0.3); pointer-events: none; z-index: 495; } /* ── 드롭 위치 표시선 ────────────────────────────────────────────────── */ .pane-drop-line { position: fixed; height: 3px; background: linear-gradient(90deg, transparent 0%, var(--accent) 8%, var(--accent) 92%, transparent 100% ); border-radius: 2px; z-index: 600; pointer-events: none; animation: pane-drop-line-pulse 0.45s ease-in-out infinite alternate; } @keyframes pane-drop-line-pulse { from { opacity: 0.8; box-shadow: 0 0 8px var(--accent), 0 0 2px var(--accent); } to { opacity: 1; box-shadow: 0 0 16px var(--accent), 0 0 4px #fff; } } /* ── 드롭: 합치기(+) ─────────────────────────────────────────────────── */ .pane-drop-merge { z-index: 598; pointer-events: none; border: 2px dashed rgba(122, 200, 120, 0.85); border-radius: 4px; background: rgba(80, 180, 100, 0.12); box-sizing: border-box; display: flex; align-items: center; justify-content: center; } .pane-drop-merge-badge { display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 10px 16px; border-radius: 8px; background: rgba(20, 36, 28, 0.88); border: 1px solid rgba(120, 220, 140, 0.55); color: #9ee8a8; font-size: 12px; font-weight: 700; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.45); } .pane-drop-merge-badge svg { opacity: 0.95; } /* ── 드롭: 이동 힌트 ─────────────────────────────────────────────────── */ .pane-drop-move-hint { position: fixed; z-index: 601; pointer-events: none; font-size: 11px; font-weight: 700; color: var(--accent); background: rgba(20, 24, 40, 0.9); padding: 2px 8px; border-radius: 4px; border: 1px solid rgba(122, 162, 247, 0.45); } .pane-btn-split:hover { color: #9ee8a8; background: rgba(80, 180, 100, 0.28); border-color: rgba(120, 220, 140, 0.65); } .pane-btn-copy:hover { color: #a8c8ff; background: rgba(122, 162, 247, 0.32); border-color: rgba(122, 162, 247, 0.75); } .pane-drag-ghost-mode { margin-left: 4px; font-weight: 500; opacity: 0.85; } /* ── 차트 내용 이미지 고스트 ─────────────────────────────────────────── */ .pane-drag-ghost-chart { pointer-events: none; z-index: 700; border: 1px solid rgba(122, 162, 247, 0.7); border-radius: 3px; box-shadow: 0 8px 28px rgba(0,0,0,0.55), 0 2px 8px rgba(0,0,0,0.4); overflow: hidden; opacity: 0.88; } /* 고스트 이미지 위에 겹치는 레이블 배지 */ .pane-drag-ghost-label { position: absolute; top: 5px; left: 6px; background: rgba(30, 34, 54, 0.82); color: var(--text); font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 3px; pointer-events: none; border: 1px solid rgba(122, 162, 247, 0.35); white-space: nowrap; } /* ── 색상 블록 고스트 (캔버스 캡처 실패 fallback) ───────────────────── */ /* inline style 로 대부분 지정되므로 여기선 공통 속성만 */ .pane-drag-ghost-block { overflow: hidden; } /* ── 텍스트 고스트 (구 fallback, 미사용) ────────────────────────────── */ .pane-drag-ghost { position: fixed; background: var(--bg2); border: 1px solid var(--accent); border-radius: var(--radius); padding: 3px 10px; font-size: 11px; font-weight: 600; color: var(--text); pointer-events: none; z-index: 700; opacity: 0.92; white-space: nowrap; box-shadow: 0 3px 10px rgba(0,0,0,0.35); transform: translateY(-50%); } /* ── IndicatorContextToolbar (인디케이터 클릭 플로팅 툴바) ─────────── */ .ind-ctx-toolbar { position: fixed; z-index: 4000; display: flex; align-items: center; gap: 2px; padding: 4px 8px; background: var(--bg2); border: 1px solid var(--sep); border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,0.35); font-size: 12px; white-space: nowrap; user-select: none; pointer-events: auto; animation: ctxFadeIn 0.12s ease; } @keyframes ctxFadeIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } } .ind-ctx-name { color: var(--text); font-weight: 600; font-size: 12px; padding: 0 6px 0 2px; max-width: 120px; overflow: hidden; text-overflow: ellipsis; border-right: 1px solid var(--sep); margin-right: 4px; } .ind-ctx-btn { background: none; border: none; cursor: pointer; color: var(--text2); padding: 4px 5px; border-radius: 4px; display: flex; align-items: center; justify-content: center; transition: background 0.1s, color 0.1s; } .ind-ctx-btn:hover { background: var(--bg3); color: var(--text); } .ind-ctx-del:hover { color: var(--down) !important; } /* ── IndicatorSettingsModal ───────────────────────────────────────── */ .ism-overlay { position: fixed; inset: 0; z-index: 5000; background: rgba(0,0,0,0.45); animation: ismFadeIn 0.15s ease; } @keyframes ismFadeIn { from { opacity: 0; } to { opacity: 1; } } .ism-dialog { background: var(--bg); border: 1px solid var(--sep); border-radius: 10px; box-shadow: 0 16px 48px rgba(0,0,0,0.5); width: 720px; max-width: 96vw; max-height: 85vh; display: flex; flex-direction: column; overflow: hidden; animation: ismSlideIn 0.18s ease; } @keyframes ismSlideIn { from { transform: scale(0.95) translateY(8px); } to { transform: scale(1) translateY(0); } } .ism-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--sep); flex-shrink: 0; cursor: grab; user-select: none; background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .ism-header:active { cursor: grabbing; } .ism-title { flex: 1; font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .ism-close { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 16px; padding: 4px; border-radius: 4px; line-height: 1; } .ism-close:hover { color: var(--text); background: var(--bg3); } .ism-tabs { display: flex; gap: 0; padding: 0 20px; border-bottom: 1px solid var(--sep); flex-shrink: 0; } .ism-tab { background: none; border: none; border-bottom: 2px solid transparent; padding: 10px 16px; font-size: 13px; font-weight: 600; color: var(--text2); cursor: pointer; transition: color 0.15s, border-color 0.15s; margin-bottom: -1px; } .ism-tab.active { color: var(--text); border-bottom-color: var(--accent); } .ism-tab:hover:not(.active) { color: var(--text); } .ism-body { flex: 1; overflow-y: auto; padding: 16px 0; } .ism-body::-webkit-scrollbar { width: 4px; } .ism-body::-webkit-scrollbar-track { background: transparent; } .ism-body::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 2px; } .ism-section { padding: 0 20px; } .ism-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid var(--sep); } .ism-row:last-child { border-bottom: none; } .ism-label { font-size: 13px; color: var(--text); display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 120px; max-width: 58%; line-height: 1.35; } .ism-control { display: flex; align-items: center; gap: 8px; } .ism-input { background: var(--bg2); border: 1px solid var(--sep); border-radius: 5px; padding: 5px 10px; font-size: 13px; color: var(--text); width: 140px; outline: none; } .ism-input.ism-narrow { width: 84px; } .ism-input:focus { border-color: var(--accent); } /* 숫자 combobox — 입력란 클릭 시 목록 펼침, 직접 입력 가능 */ .ism-num-combo { position: relative; display: inline-flex; align-items: stretch; width: 140px; max-width: 100%; flex-shrink: 0; } .ism-num-combo .ism-input { flex: 1; min-width: 0; box-sizing: border-box; border-top-right-radius: 0; border-bottom-right-radius: 0; } .ism-num-combo-toggle { flex-shrink: 0; width: 22px; padding: 0; border: 1px solid var(--sep); border-left: none; border-radius: 0 5px 5px 0; background: var(--bg3); color: var(--text2); font-size: 10px; line-height: 1; cursor: pointer; } .ism-num-combo-toggle:hover:not(:disabled) { background: var(--bg2); color: var(--text); } .ism-num-combo-toggle:disabled { opacity: 0.45; cursor: not-allowed; } .ism-num-combo:has(.ism-narrow) { width: 106px; } .ism-num-combo-list { position: absolute; z-index: 6100; top: calc(100% + 2px); left: 0; right: 0; margin: 0; padding: 4px 0; list-style: none; max-height: 200px; overflow-y: auto; background: var(--bg2); border: 1px solid var(--sep); border-radius: 5px; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35); } .ism-num-combo-opt { display: block; width: 100%; padding: 6px 10px; border: none; background: transparent; color: var(--text); font-size: 13px; text-align: left; cursor: pointer; } .ism-num-combo-opt:hover { background: var(--bg3); } .ism-num-combo-opt.selected { color: var(--accent); font-weight: 600; } .ism-num-combo-spacer { width: 84px; height: 31px; flex-shrink: 0; } .ism-color-wrap .ism-num-combo { width: 72px; } .ism-color-wrap .ism-num-combo .ism-input.ism-alpha-input { width: 100%; text-align: right; font-size: 12px; padding: 4px 6px; } .ism-input:focus { border-color: var(--accent); } .ism-select { background: var(--bg2); border: 1px solid var(--sep); border-radius: 5px; padding: 5px 8px; font-size: 13px; color: var(--text); outline: none; cursor: pointer; } .ism-select.ism-narrow { width: 96px; min-width: 96px; flex-shrink: 0; } .ism-select:focus { border-color: var(--accent); } /* 스타일 탭 — 타이틀 열 너비를 섹션 내 최장 라벨에 맞춰 컨트롤 상하 정렬 */ .ism-style-tab-section { padding-bottom: 8px; } .ism-plot-title-measure { position: absolute; visibility: hidden; pointer-events: none; height: 0; overflow: hidden; white-space: nowrap; } .ism-plot-title-measure .ism-plot-title { display: inline-block; font-size: 13px; font-weight: 600; padding-right: 10px; } .ism-style-section { --ism-plot-title-width: 13.5rem; display: grid; grid-template-columns: var(--ism-plot-title-width) minmax(0, auto) minmax(0, auto) minmax(0, auto); column-gap: 14px; align-items: center; } .ism-style-section > .ism-style-row:not(.ism-hline-row) { display: contents; } .ism-style-section > .ism-style-row:not(.ism-hline-row) > * { padding: 10px 0; border-bottom: 1px solid var(--sep); min-width: 0; } .ism-style-section > .ism-style-row:not(.ism-hline-row):last-child:not(:has(+ .ism-hline-divider)) > * { border-bottom: none; } .ism-style-section > .ism-hline-divider, .ism-style-section > .ism-hline-header-row, .ism-style-section > .ism-hline-row { grid-column: 1 / -1; } /* 스타일 탭 행 — 수평선 등 (플롯 행은 grid + display:contents) */ .ism-style-row { display: flex; flex-wrap: nowrap; align-items: center; gap: 10px 14px; padding: 10px 0; border-bottom: 1px solid var(--sep); overflow-x: auto; } .ism-style-row:last-child { border-bottom: none; } .ism-style-field-spacer { visibility: hidden; pointer-events: none; } .ism-plot-title-cell { display: flex; align-items: center; width: var(--ism-plot-title-width); max-width: var(--ism-plot-title-width); min-width: var(--ism-plot-title-width); flex-shrink: 0; box-sizing: border-box; padding-right: 4px; } .ism-style-plot-toggle { flex-shrink: 0; } .ism-plot-title { font-size: 13px; font-weight: 600; color: var(--text); white-space: nowrap; line-height: 1.35; overflow: hidden; text-overflow: ellipsis; } .ism-style-section > .ism-style-row:not(.ism-hline-row) > .ism-plot-title-cell { justify-self: start; } .ism-style-width-select { width: 52px; min-width: 52px; flex-shrink: 0; } .ism-style-type-select { min-width: 72px; flex-shrink: 0; } .ism-style-type-static { font-size: 12px; color: var(--text2); min-width: 72px; } .ism-hline-row--off { opacity: 0.45; } .ism-hline-price-readonly { font-size: 13px; color: var(--text2); } .ism-style-field { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; white-space: nowrap; } .ism-style-label { font-size: 11px; color: var(--text2); flex-shrink: 0; } /* 색상 입력 */ .ism-color-wrap { display: flex; align-items: center; gap: 4px; position: relative; } .ism-color-swatch-btn { width: 36px; height: 28px; padding: 3px; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg2); cursor: pointer; flex-shrink: 0; } .ism-color-swatch-btn:hover { border-color: var(--text3); } .ism-color-swatch-preview { display: block; width: 100%; height: 100%; border-radius: 2px; border: 1px solid rgba(255, 255, 255, 0.12); } .ism-color-picker { width: 36px; height: 28px; border: 1px solid var(--sep); border-radius: 4px; padding: 1px; background: none; cursor: pointer; flex-shrink: 0; } .ism-color-picker--compact { width: 32px; height: 28px; } .ism-color-popover { position: fixed; z-index: 6200; width: 280px; max-width: calc(100vw - 16px); padding: 12px; background: var(--bg); border: 1px solid var(--sep); border-radius: 8px; box-shadow: var(--popup-shadow); } .ism-color-popover-native { margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid var(--sep); } .ism-color-native-label { display: flex; align-items: center; gap: 8px; } .ism-alpha-input { width: 68px; background: var(--bg2); border: 1px solid var(--sep); border-radius: 4px; padding: 4px 6px; font-size: 12px; color: var(--text); outline: none; text-align: right; } .ism-alpha-label { font-size: 11px; color: var(--text2); } /* 토글 스위치 */ .ism-toggle { position: relative; display: inline-block; width: 38px; height: 22px; cursor: pointer; } .ism-toggle input { opacity: 0; width: 0; height: 0; } .ism-toggle-slider { position: absolute; inset: 0; background: var(--bg4); border-radius: 11px; transition: background 0.2s; } .ism-toggle-slider::before { content: ''; position: absolute; width: 16px; height: 16px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform 0.2s; } .ism-toggle input:checked + .ism-toggle-slider { background: var(--accent); } .ism-toggle input:checked + .ism-toggle-slider::before { transform: translateX(16px); } /* plot swatch */ .ism-plot-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0; } /* empty */ .ism-empty { text-align: center; color: var(--text3); font-size: 12px; padding: 20px; } /* ── 수평선 (과열선·중앙선·침체선) ──────────────────────────────────────── */ .ism-hline-divider { border: none; border-top: 1px solid var(--sep); margin: 10px 0 6px; } /* 헤더 행 */ .ism-hline-header-row { display: grid; grid-template-columns: 1fr 70px minmax(200px, 1fr); gap: 6px; padding: 2px 2px 4px; font-size: 10px; font-weight: 700; color: var(--text3); text-transform: uppercase; letter-spacing: .4px; border-bottom: 1px solid var(--sep); margin-bottom: 2px; } /* 각 hline 행 */ .ism-hline-row { display: grid; grid-template-columns: 1fr 70px minmax(200px, 1fr); gap: 6px; align-items: center; padding: 4px 2px; border-radius: 4px; transition: background .1s; } .ism-hline-row:hover { background: var(--bg3); } /* 이름 셀 (토글 + 레이블) */ .ism-hline-name-cell { display: flex; align-items: center; gap: 7px; min-width: 0; } .ism-hline-label-text { font-size: 12px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* 일반 셀 */ .ism-hline-cell { display: flex; align-items: center; } .ism-hline-cell .ism-input, .ism-hline-cell .ism-select { width: 100%; } .ism-hline-cell--style .plsp-inline { width: 100%; max-width: 100%; } .ism-hline-toggle { flex-shrink: 0; } /* 비활성 상태 */ .ism-hline-disabled .ism-hline-label-text { opacity: 0.45; } .ism-hline-disabled .ism-hline-cell { opacity: 0.35; pointer-events: none; } /* 일목균형표 구름 영역 색상 */ .ism-ichimoku-cloud-divider { grid-column: 1 / -1; margin: 12px 0 8px; border: none; border-top: 1px solid var(--sep); } .ism-ichimoku-cloud-section { grid-column: 1 / -1; padding: 0 0 8px; } .ism-ichimoku-cloud-title { margin: 0 0 6px; font-size: 14px; font-weight: 700; color: var(--text); } .ism-ichimoku-cloud-hint { margin: 0 0 12px; padding: 8px 10px; font-size: 12px; line-height: 1.45; color: var(--text2); background: rgba(255, 193, 7, 0.08); border: 1px solid rgba(255, 193, 7, 0.35); border-radius: 6px; } .ism-ichimoku-cloud-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } @media (max-width: 560px) { .ism-ichimoku-cloud-grid { grid-template-columns: 1fr; } } .ism-ichimoku-cloud-card { padding: 10px 12px; border: 1px solid var(--sep); border-radius: 8px; background: var(--bg2); } .ism-ichimoku-cloud-card-label { display: block; margin-bottom: 8px; font-size: 12px; font-weight: 600; color: var(--text); } .ism-ichimoku-cloud-card-row { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; } .ism-ichimoku-cloud-meta { font-size: 11px; color: var(--text3); line-height: 1.4; word-break: break-all; } /* ── Hlines Background / 출력값 / 타임프레임 가시성 ──────────────────── */ .ism-output-section-title { padding: 10px 0 6px; font-size: 11px; font-weight: 600; color: var(--text3); text-transform: uppercase; letter-spacing: 0.5px; } .ism-output-row .ism-plot-title { flex: 1; font-size: 13px; } /* 타임프레임 체크박스 그리드 */ .ism-tf-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px 4px; padding: 4px 0 10px; } .ism-tf-item { display: flex; align-items: center; gap: 5px; cursor: pointer; font-size: 12px; color: var(--text2); user-select: none; } .ism-tf-item input[type="checkbox"] { width: 13px; height: 13px; cursor: pointer; accent-color: var(--accent, #2196F3); flex-shrink: 0; } .ism-tf-label { white-space: nowrap; } /* SMA MA1~8 입력 행 */ .sma-inputs-section { --ism-row-label-width: 13.5rem; } .sma-inputs-section .ism-sma-ma-row { display: grid; grid-template-columns: 38px var(--ism-row-label-width) minmax(0, 1fr); align-items: center; gap: 10px 14px; justify-content: start; } .sma-inputs-section .ism-sma-ma-label { width: 100%; min-width: 0; max-width: none; flex: none; } .sma-inputs-section .ism-sma-ma-control { justify-content: flex-start; } .ism-sma-divider { height: 1px; background: var(--sep); margin: 8px 0 12px; } .ism-sma-ma-row { flex-wrap: nowrap; gap: 10px; justify-content: flex-start; } .ism-sma-ma-row.ism-sma-ma-off .ism-sma-ma-label, .ism-sma-ma-row.ism-sma-ma-off .ism-control { opacity: 0.45; } .ism-sma-ma-toggle { flex-shrink: 0; } .ism-sma-ma-label { min-width: 0; max-width: none; flex: 0 0 auto; white-space: nowrap; } .ism-sma-ma-control .plsp-inline { flex-wrap: nowrap; } .ism-sma-ma-control { display: flex; align-items: center; justify-content: flex-end; gap: 10px; flex: 1; min-width: 0; } .ism-sma-period-input { width: 72px; flex-shrink: 0; } /* 보조지표 통합 설정 (일괄 설정·embedded) — 라벨 열 고정 */ .unified-settings-section { padding-bottom: 8px; --ism-row-label-width: 13.5rem; } .unified-settings-section .ism-sma-ma-row { display: grid; grid-template-columns: 38px var(--ism-row-label-width) minmax(0, 1fr); align-items: center; gap: 10px 14px; justify-content: start; } .unified-settings-section .ism-sma-ma-label { width: 100%; min-width: 0; max-width: none; flex: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .unified-settings-section .ism-sma-ma-control { justify-content: flex-start; } .unified-settings-section .ism-global-param-row { display: grid; grid-template-columns: var(--ism-row-label-width) minmax(0, 1fr); gap: 10px 14px; } .unified-settings-section .ism-global-param-row .ism-sma-ma-label { width: 100%; } .ism-global-param-row { gap: 10px; } .ism-global-param-row .ism-sma-ma-label { min-width: 120px; } /* 볼린저밴드 — 업비트 심볼 선택 */ .ism-bb-symbol-section { display: flex; flex-direction: column; gap: 10px; margin-bottom: 4px; } .ism-bb-symbol-option { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--text); cursor: pointer; } .ism-bb-symbol-option input[type="radio"] { accent-color: var(--text); flex-shrink: 0; } .ism-bb-symbol-hint { font-size: 12px; color: var(--text2); margin-left: 4px; } .ism-bb-symbol-other { flex-wrap: wrap; } .ism-bb-ref-symbol { flex: 1; min-width: 140px; max-width: 200px; } .ism-bb-ref-symbol:disabled { opacity: 0.45; cursor: not-allowed; } .ism-plot-param-inputs { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center; } .ism-param-inline-select { min-width: 100px; max-width: 160px; } .ism-hlines-bg-spacer { visibility: hidden; pointer-events: none; } /* 일목균형표 — SMA와 동일 행 레이아웃 */ .ichimoku-inputs-section { padding-bottom: 8px; } .ichimoku-inputs-section .ism-ichimoku-cloud-divider { margin: 14px 0 10px; } .ichimoku-inputs-section .ism-ichimoku-cloud-section { padding: 0 0 4px; } .ism-ichimoku-auto-param { display: inline-flex; align-items: center; justify-content: center; min-width: 72px; height: 28px; padding: 0 8px; font-size: 12px; color: var(--text3); background: var(--bg3); border: 1px solid var(--sep); border-radius: 5px; flex-shrink: 0; } .ism-ichimoku-extra-row { border-bottom: none; } .ism-ichimoku-tf-grid { margin-top: 4px; padding-bottom: 8px; } /* PlotLineStylePicker — 색상·선 굵기·선 유형 */ .plsp-inline { display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; } .plsp-inline--disabled { opacity: 0.4; pointer-events: none; } .plsp-inline-select { height: 28px; min-width: 44px; padding: 0 6px; background: var(--bg2); border: 1px solid var(--sep); border-radius: 4px; font-size: 12px; color: var(--text); cursor: pointer; outline: none; } .plsp-inline-select--style { min-width: 64px; } .plsp-inline-select:hover:not(:disabled) { border-color: var(--text3); } .plsp-inline-select:focus { border-color: var(--accent); } .plsp-inline-select:disabled { opacity: 0.5; cursor: not-allowed; } .ism-style-field--line-picker .plsp-inline { flex-wrap: nowrap; } .plsp-swatch { flex-shrink: 0; width: 28px; height: 28px; padding: 3px; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg2); cursor: pointer; display: flex; align-items: center; justify-content: center; } .plsp-swatch:disabled { opacity: 0.4; cursor: not-allowed; } .plsp-swatch-inner { display: block; width: 100%; height: 100%; border-radius: 2px; border: 1px solid rgba(255,255,255,0.15); } .plsp-portal-root { position: fixed; inset: 0; z-index: 6000; pointer-events: none; } .plsp-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); pointer-events: auto; animation: plspFadeIn 0.12s ease; } .plsp-popup { position: fixed; z-index: 6001; width: min(320px, calc(100vw - 32px)); max-height: calc(100vh - 48px); overflow-y: auto; padding: 14px 16px 12px; background: var(--bg); border: 1px solid var(--sep); border-radius: 10px; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.55); pointer-events: auto; animation: plspPopIn 0.15s ease; } @keyframes plspFadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes plspPopIn { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: scale(1); } } .plsp-popup-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: -14px -16px 12px; padding: 10px 14px; cursor: grab; user-select: none; border-bottom: 1px solid var(--sep); background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); border-bottom: 1px solid var(--sep); } .plsp-popup-title { font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); } /* 드로잉 설정 팝업 */ .dsm-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); z-index: 5000; } .dsm-dialog { display: flex; flex-direction: column; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5); max-width: 96vw; max-height: 90vh; overflow: hidden; } .dsm-body { padding: 16px 20px 20px; overflow-y: auto; color: var(--text); } .dsm-footer { display: flex; justify-content: flex-end; gap: 8px; padding-top: 12px; } .plsp-popup-close { background: none; border: none; color: var(--text2); font-size: 16px; line-height: 1; padding: 4px 6px; border-radius: 4px; cursor: pointer; } .plsp-popup-close:hover { color: var(--text); background: var(--bg3); } .plsp-popup-footer { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--sep); display: flex; justify-content: flex-end; } .plsp-popup-ok { padding: 7px 20px; font-size: 13px; font-weight: 600; color: #fff; background: var(--accent, #2196F3); border: none; border-radius: 5px; cursor: pointer; } .plsp-popup-ok:hover { filter: brightness(1.08); } .plsp-palette { display: grid; grid-template-columns: repeat(10, 1fr); gap: 3px; margin-bottom: 0; } /* ColorPickerPanel — 스와치 팔레트 + 고급 선택기 */ .cpp-panel { display: flex; flex-direction: column; gap: 0; } .cpp-quick-palette .cpp-palette-grid { margin-bottom: 0; } .cpp-advanced-divider { height: 1px; background: var(--sep); margin: 12px 0; } .plsp-popup .cpp-panel { margin-bottom: 12px; } /* AdvancedColorPicker */ .acp-root { display: flex; flex-direction: column; gap: 10px; } .acp-sv-panel { position: relative; width: 100%; height: 160px; border-radius: 6px; cursor: crosshair; touch-action: none; border: 1px solid var(--sep); } .acp-sv-pointer { position: absolute; width: 14px; height: 14px; margin: -7px 0 0 -7px; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.45), 0 1px 4px rgba(0, 0, 0, 0.35); pointer-events: none; } .acp-controls-row { display: flex; align-items: center; gap: 10px; } .acp-eyedropper { flex-shrink: 0; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; border: 1px solid var(--sep); border-radius: 50%; background: var(--bg2); color: var(--text); cursor: pointer; padding: 0; } .acp-eyedropper:hover { background: var(--bg3); } .acp-preview { flex-shrink: 0; width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--sep); } .acp-hue-track { position: relative; flex: 1; height: 14px; border-radius: 7px; cursor: pointer; touch-action: none; border: 1px solid rgba(255, 255, 255, 0.08); } .acp-hue-thumb { position: absolute; top: 50%; width: 16px; height: 16px; margin: -8px 0 0 -8px; border: 2px solid #fff; border-radius: 50%; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4); pointer-events: none; background: transparent; } .acp-rgb-row { display: flex; align-items: flex-end; gap: 8px; } .acp-rgb-field { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; } .acp-hex-field { flex: 3; } .acp-rgb-input { width: 100%; box-sizing: border-box; background: var(--bg2); border: 1px solid var(--sep); border-radius: 4px; padding: 6px 8px; font-size: 13px; color: var(--text); text-align: center; outline: none; } .acp-rgb-input:focus { border-color: var(--accent); } .acp-rgb-input::-webkit-outer-spin-button, .acp-rgb-input::-webkit-inner-spin-button { opacity: 1; } .acp-rgb-label { font-size: 11px; color: var(--text2); font-weight: 600; } .acp-mode-toggle { flex-shrink: 0; width: 28px; height: 32px; border: none; background: transparent; color: var(--text2); font-size: 12px; cursor: pointer; padding: 0; align-self: center; } .acp-mode-toggle:hover { color: var(--text); } .plsp-color-cell { width: 100%; aspect-ratio: 1; border: 1px solid rgba(255,255,255,0.08); border-radius: 2px; cursor: pointer; padding: 0; } .plsp-color-cell:hover { transform: scale(1.08); z-index: 1; } .plsp-color-cell.selected { outline: 2px solid var(--accent, #2196F3); outline-offset: 1px; } .plsp-section { margin-bottom: 10px; } .plsp-section:last-child { margin-bottom: 0; } .plsp-section-label { display: block; font-size: 11px; font-weight: 600; color: var(--text2); margin-bottom: 6px; } .plsp-opacity-row { display: flex; align-items: center; gap: 8px; } .plsp-opacity-slider { flex: 1; accent-color: var(--accent, #2196F3); } .plsp-opacity-pct { font-size: 12px; color: var(--text2); min-width: 36px; text-align: right; } .plsp-btn-group { display: flex; gap: 4px; } .plsp-icon-btn { flex: 1; display: flex; align-items: center; justify-content: center; height: 32px; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg2); color: var(--text); cursor: pointer; padding: 0 4px; } .plsp-icon-btn:hover { background: var(--bg3); } .plsp-icon-btn.active { background: var(--bg4); border-color: var(--accent, #2196F3); color: var(--accent, #2196F3); } /* 하단 버튼 */ .ism-footer { display: flex; align-items: center; justify-content: space-between; padding: 12px 20px; border-top: 1px solid var(--sep); flex-shrink: 0; } .ism-footer-right { display: flex; gap: 8px; } .ism-btn-defaults { background: var(--bg2); border: 1px solid var(--sep); border-radius: 5px; padding: 7px 14px; font-size: 13px; color: var(--text); cursor: pointer; } .ism-btn-defaults:hover { background: var(--bg3); } .ism-btn-cancel { background: var(--bg2); border: 1px solid var(--sep); border-radius: 5px; padding: 7px 18px; font-size: 13px; color: var(--text); cursor: pointer; } .ism-btn-cancel:hover { background: var(--bg3); } .ism-btn-ok { background: var(--text); border: 1px solid var(--text); border-radius: 5px; padding: 7px 22px; font-size: 13px; font-weight: 600; color: var(--bg); cursor: pointer; } .ism-btn-ok:hover { opacity: 0.85; } /* ── IndicatorBulkSettingsModal (보조지표 일괄 설정) ───────────────────── */ .ibsm-overlay { position: fixed; inset: 0; z-index: 5100; background: transparent; pointer-events: none; } .ibsm-dialog { pointer-events: auto; width: min(720px, 96vw); max-height: 85vh; display: flex; flex-direction: column; background: var(--bg); border: 2px solid rgba(80, 100, 160, 0.45); border-radius: 8px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35); overflow: hidden; } .ibsm-dialog-wide { width: min(760px, 96vw); } .ibsm-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; cursor: grab; user-select: none; flex-shrink: 0; border-bottom: 1px solid var(--border); background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .ibsm-header:active { cursor: grabbing; } .ibsm-header-title { flex: 1; font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); } .ibsm-header-actions { display: flex; gap: 4px; } .ibsm-icon-btn { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 16px; padding: 4px 8px; border-radius: 4px; line-height: 1; } .ibsm-icon-btn:hover { background: var(--bg4); color: var(--text); } .ibsm-main-tab-bar { display: flex; align-items: center; gap: 6px; padding: 8px 14px 0; flex-shrink: 0; } .ibsm-main-tab { font-size: 12px; font-weight: 700; color: var(--accent); padding: 4px 10px; border-radius: 4px; background: rgba(122, 162, 247, 0.15); } .ibsm-main-tab-count { font-size: 11px; color: var(--text3); } .ibsm-hint { font-size: 11px; color: var(--text2); padding: 8px 16px 0; flex-shrink: 0; line-height: 1.45; } /* 보조지표 설정 목록 검색 (일괄·설정 화면 공통) */ .ind-settings-search-wrap { display: flex; flex-direction: column; gap: 6px; flex-shrink: 0; } .ibsm-search-block { padding: 10px 14px 0; border-bottom: 1px solid var(--sep); } .stg-ind-search-block { margin-bottom: 10px; } .modal-search-input, .ind-settings-search-input { width: 100%; box-sizing: border-box; background: var(--bg3); color: var(--text); border: 1px solid var(--sep); border-radius: 6px; padding: 8px 12px; font-size: 13px; outline: none; } .modal-search-input:focus, .ind-settings-search-input:focus { border-color: var(--accent); } .ind-settings-search-meta { font-size: 11px; color: var(--text3); } .ind-settings-section { display: flex; flex-direction: column; gap: 8px; } .ind-settings-section + .ind-settings-section { margin-top: 14px; padding-top: 4px; border-top: 1px solid var(--sep); } .ind-settings-section-title { margin: 0 0 4px; padding: 0 2px; font-size: 12px; font-weight: 700; color: var(--text2); } .ind-settings-section-count { font-weight: 600; color: var(--text3); } .ind-settings-no-results { padding: 24px 12px; text-align: center; font-size: 13px; color: var(--text3); } .ibsm-main-row--active { border-color: rgba(122, 162, 247, 0.4); } .ibsm-main-row-head { flex-wrap: wrap; gap: 8px; } .ibsm-main-row-info { flex: 1; min-width: 160px; display: flex; flex-direction: column; gap: 2px; } .ibsm-main-row-ko { font-size: 13px; font-weight: 600; color: var(--text); } .ibsm-main-row-en { font-size: 11px; color: var(--text3); } .ibsm-main-row-badges { display: flex; align-items: center; gap: 6px; flex-shrink: 0; } .ibsm-main-badge { font-size: 10px; padding: 2px 8px; border-radius: 3px; background: var(--bg3); color: var(--text3); } .ibsm-main-badge--on { background: rgba(122, 162, 247, 0.2); color: var(--accent); } .ibsm-main-row .ind-panel-badge { font-size: 10px; padding: 2px 6px; border-radius: 3px; background: rgba(41, 98, 255, 0.12); color: var(--accent); } .ibsm-body { flex: 1; overflow-y: auto; padding: 12px 14px 16px; } .ibsm-body::-webkit-scrollbar { width: 5px; } .ibsm-body::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 3px; } .ibsm-empty { text-align: center; color: var(--text3); font-size: 13px; padding: 24px 8px; } .ibsm-card { margin-bottom: 6px; border: 1px solid var(--sep); border-radius: 6px; background: var(--bg2); transition: border-color 0.12s, opacity 0.12s; } .ibsm-card-off { opacity: 0.65; } .ibsm-card-drag-over { border-color: var(--accent); } .ibsm-card-main { display: flex; align-items: center; gap: 8px; padding: 8px 10px; min-height: 48px; flex-wrap: wrap; } .ibsm-drag { cursor: grab; color: var(--text3); font-size: 14px; user-select: none; flex-shrink: 0; } .ibsm-drag:active { cursor: grabbing; } .ibsm-name { font-size: 13px; font-weight: 700; color: var(--text); min-width: 72px; flex-shrink: 0; } .ibsm-name-sub { font-size: 11px; color: var(--text3); flex: 1; min-width: 40px; } .ibsm-card-expanded { border-color: var(--accent); } .ibsm-embedded-form { padding: 0 !important; } .ibsm-embedded-form .ism-section { padding: 0; } .ibsm-form-toolbar { display: flex; justify-content: flex-end; margin-bottom: 8px; } .ibsm-form-defaults { font-size: 11px; padding: 4px 10px; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg2); color: var(--text2); cursor: pointer; } .ibsm-form-defaults:hover { color: var(--text); border-color: var(--accent); } .ibsm-fields { display: flex; flex: 1; flex-wrap: wrap; align-items: center; gap: 10px; min-width: 120px; } .ibsm-field { display: flex; align-items: center; gap: 4px; } .ibsm-field-label { font-size: 11px; color: var(--text2); min-width: 28px; } .ibsm-mini-input { background: var(--bg); border: 1px solid var(--sep); border-radius: 4px; padding: 3px 6px; font-size: 11px; color: var(--text); outline: none; } .ibsm-mini-num { width: 48px; text-align: center; } .ibsm-color-swatch { position: relative; display: inline-block; width: 22px; height: 22px; border-radius: 3px; border: 1px solid var(--sep); overflow: hidden; cursor: pointer; } .ibsm-color-swatch span { display: block; width: 100%; height: 100%; } .ibsm-color-swatch input[type="color"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; } .ibsm-width { display: flex; align-items: center; gap: 6px; min-width: 130px; flex-shrink: 0; } .ibsm-width input[type="range"] { width: 72px; } .ibsm-width span { font-size: 10px; color: var(--text2); } .ibsm-line-preview { display: inline-block; width: 28px; border-radius: 2px; flex-shrink: 0; } .ibsm-toggle { position: relative; display: inline-block; width: 36px; height: 20px; flex-shrink: 0; } .ibsm-toggle input { opacity: 0; width: 0; height: 0; } .ibsm-toggle .ism-toggle-slider { position: absolute; inset: 0; background: var(--bg4); border-radius: 10px; transition: background 0.2s; } .ibsm-toggle .ism-toggle-slider::before { content: ''; position: absolute; width: 14px; height: 14px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform 0.2s; } .ibsm-toggle input:checked + .ism-toggle-slider { background: var(--accent); } .ibsm-toggle input:checked + .ism-toggle-slider::before { transform: translateX(16px); } .ibsm-expand, .ibsm-expand-spacer { width: 22px; flex-shrink: 0; text-align: center; } .ibsm-expand { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 10px; padding: 2px; } .ibsm-card-expand { padding: 10px 12px 12px; border-top: 1px solid var(--sep); background: var(--bg3); } .ibsm-hlines-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; font-size: 12px; font-weight: 700; color: var(--text2); } .ibsm-hlines-add { font-size: 11px; padding: 2px 8px; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg2); color: var(--text); cursor: pointer; } .ibsm-hlines-empty { font-size: 11px; color: var(--text3); text-align: center; margin: 4px 0; } .ibsm-hlines-table-head, .ibsm-hlines-row { display: grid; grid-template-columns: 1.2fr 0.8fr 0.7fr 1fr 32px; gap: 6px; align-items: center; } .ibsm-hlines-table-head { font-size: 10px; font-weight: 700; color: #fff; background: var(--accent); padding: 4px 6px; border-radius: 4px; margin-bottom: 4px; opacity: 0.9; } .ibsm-hlines-row { margin-bottom: 4px; padding: 4px; background: var(--bg2); border: 1px solid var(--sep); border-radius: 4px; } .ibsm-mini-select { font-size: 10px; padding: 3px 4px; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg); color: var(--text); } .ibsm-hlines-del { background: none; border: none; cursor: pointer; font-size: 14px; opacity: 0.7; } .ibsm-hlines-del:hover { opacity: 1; } .ibsm-detail-btn { margin-top: 8px; font-size: 12px; color: var(--accent); background: none; border: none; cursor: pointer; text-decoration: underline; } .ibsm-footer { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--sep); flex-shrink: 0; } /* ── MainChartSettingsModal ─────────────────────────────────────────────── */ .mcs-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 3000; } .mcs-dialog { background: var(--panel-bg, #1e222d); border: 1px solid var(--border, #333); border-radius: 12px; width: 640px; max-width: 96vw; max-height: 80vh; display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 8px 40px rgba(0,0,0,.6); } .mcs-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border, #2a2e39); flex-shrink: 0; cursor: grab; user-select: none; background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .mcs-header:active { cursor: grabbing; } .mcs-title { flex: 1; font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); } .mcs-close { background: none; border: none; cursor: pointer; color: var(--text-muted, #888); font-size: 18px; padding: 2px 6px; } .mcs-close:hover { color: var(--text); } .mcs-tabs { display: flex; gap: 0; border-bottom: 1px solid var(--border, #2a2e39); padding: 0 22px; } .mcs-tab { background: none; border: none; cursor: pointer; padding: 10px 16px; font-size: 14px; font-weight: 500; color: var(--text-muted, #888); border-bottom: 2px solid transparent; margin-bottom: -1px; } .mcs-tab.active { color: var(--accent, #2962ff); border-bottom-color: var(--accent, #2962ff); } .mcs-tab:hover { color: var(--text); } .mcs-body { flex: 1; overflow-y: auto; padding: 20px 28px; display: flex; flex-direction: column; gap: 4px; } .mcs-section-label { font-size: 10px; font-weight: 700; letter-spacing: .08em; color: var(--text-muted, #888); text-transform: uppercase; margin-bottom: 12px; margin-top: 4px; } .mcs-row { display: flex; align-items: center; padding: 10px 0; border-bottom: 1px solid var(--border, #2a2e3922); } .mcs-row-label { flex: 1; font-size: 14px; color: var(--text); } .mcs-row-colors { display: flex; gap: 8px; } /* 색상 스와치 */ .mcs-swatch { position: relative; cursor: pointer; } .mcs-swatch input[type=color] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; } .mcs-swatch span { display: block; width: 38px; height: 28px; border-radius: 5px; border: 2px solid var(--border, #444); transition: border-color .15s; } .mcs-swatch:hover span { border-color: var(--accent, #2962ff); } .mcs-footer { display: flex; align-items: center; justify-content: space-between; padding: 14px 22px; border-top: 1px solid var(--border, #2a2e39); } .mcs-footer-right { display: flex; gap: 10px; align-items: center; } .mcs-btn-defaults { background: var(--btn-bg, #2a2e3a); border: 1px solid var(--border, #444); border-radius: 6px; padding: 7px 14px; font-size: 13px; color: var(--text); cursor: pointer; } .mcs-btn-defaults:hover { background: var(--btn-hover, #333); } .mcs-btn-cancel { background: none; border: 1px solid var(--border, #555); border-radius: 6px; padding: 7px 18px; font-size: 13px; color: var(--text); cursor: pointer; } .mcs-btn-cancel:hover { background: var(--btn-bg, #2a2e3a); } .mcs-btn-ok { background: var(--text, #fff); border: 1px solid var(--text, #fff); border-radius: 6px; padding: 7px 22px; font-size: 13px; font-weight: 600; color: var(--bg, #131722); cursor: pointer; } .mcs-btn-ok:hover { opacity: .88; } /* ══════════════════════════════════════════════════════════════════ Layout Picker · LayoutPicker.tsx ══════════════════════════════════════════════════════════════════ */ /* 팝업 컨테이너 */ .lp-popup { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--popup-shadow); padding: 12px 0 8px; width: 420px; max-height: 80vh; overflow-y: auto; color: var(--text); font-size: 13px; user-select: none; } /* 레이아웃 그리드 행 */ .lp-grid-section { padding: 0 12px; } .lp-row { display: flex; align-items: center; gap: 4px; padding: 4px 0; border-bottom: 1px solid var(--border); } .lp-row:last-child { border-bottom: none; } .lp-row-num { width: 20px; text-align: center; font-size: 11px; color: var(--text-muted); flex-shrink: 0; } .lp-row-icons { display: flex; flex-wrap: wrap; gap: 3px; } /* 레이아웃 아이콘 버튼 */ .lp-icon-btn { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; border: 1px solid transparent; border-radius: 4px; background: none; color: var(--text); cursor: pointer; transition: background .12s, border-color .12s; } .lp-icon-btn:hover { background: var(--btn-bg); border-color: var(--border); } .lp-icon-btn.active { background: var(--accent-muted); border-color: var(--accent); color: var(--accent); } /* 구분선 */ .lp-divider { height: 1px; background: var(--border); margin: 6px 0; } /* SYNC IN LAYOUT */ .lp-sync-section { padding: 4px 16px 8px; } .lp-sync-label { font-size: 10px; font-weight: 600; letter-spacing: .08em; color: var(--text-muted); margin-bottom: 8px; text-transform: uppercase; } .lp-sync-row { display: flex; align-items: center; justify-content: space-between; padding: 5px 0; } .lp-sync-name { font-size: 13px; color: var(--text); } /* 토글 스위치 */ .lp-toggle { position: relative; width: 36px; height: 20px; border: none; border-radius: 10px; background: var(--btn-bg); cursor: pointer; transition: background .2s; flex-shrink: 0; } .lp-toggle::after { content: ''; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: var(--text-muted); transition: transform .2s, background .2s; } .lp-toggle.on { background: var(--accent); } .lp-toggle.on::after { transform: translateX(16px); background: #fff; } /* ── 레이아웃 버튼 (툴바 오른쪽) ──────────────────────────────────── */ .lp-trigger-btn { position: relative; } .lp-trigger-btn.active { color: var(--accent); } /* ══════════════════════════════════════════════════════════════════ Multi-Chart Grid Layout ══════════════════════════════════════════════════════════════════ */ .multi-chart-grid { display: grid; flex: 1; height: 100%; min-height: 0; min-width: 0; gap: 12px; padding: 8px 10px 12px; background: var(--bg, #131722); overflow: hidden; align-content: stretch; } .multi-slot-wrap { position: relative; overflow: hidden; background: var(--panel, #1e222d); min-width: 0; min-height: 0; display: flex; flex-direction: column; border: 1px solid var(--se-border, var(--border, #2a2e3a)); border-radius: 12px; transition: box-shadow 0.15s ease-out, border-color 0.15s ease-out; } /* 개별 차트 슬롯 */ .chart-slot { display: flex; flex-direction: column; width: 100%; flex: 1; min-height: 0; border: 2px solid transparent; transition: border-color .15s, box-shadow .15s; } .chart-slot.active { border-color: var(--accent, #2962ff); } /* 멀티차트 컴팩트 — 가상투자 카드 차트 스타일 */ .chart-slot--compact { border: none; border-radius: 0; min-height: 360px; } .chart-slot--compact.active { border: none; box-shadow: inset 0 0 0 1px var(--accent, #2962ff); } /* 멀티차트 추세색 — 가상투자 vtd-card--live / timing 과 동일하게 얇고 흐릿한 아웃라인 */ .multi-slot-wrap:has(.chart-slot--trend-up:not(.chart-slot--receiving)), .chart-slot--compact.chart-slot--trend-up:not(.chart-slot--receiving) { border-color: color-mix(in srgb, var(--up, #ff6b6b) 35%, var(--se-border, var(--border, #2a2e3a))); box-shadow: 0 0 0 1px color-mix(in srgb, var(--up, #ff6b6b) 12%, transparent); } .multi-slot-wrap:has(.chart-slot--trend-down:not(.chart-slot--receiving)), .chart-slot--compact.chart-slot--trend-down:not(.chart-slot--receiving) { border-color: color-mix(in srgb, var(--down, #4dabf7) 35%, var(--se-border, var(--border, #2a2e3a))); box-shadow: 0 0 0 1px color-mix(in srgb, var(--down, #4dabf7) 12%, transparent); } .chart-slot--compact.chart-slot--trend-up:not(.chart-slot--receiving) { background: linear-gradient( 165deg, color-mix(in srgb, var(--up, #ff6b6b) 10%, var(--panel, #1e222d)) 0%, var(--panel, #1e222d) 55% ); } .chart-slot--compact.chart-slot--trend-down:not(.chart-slot--receiving) { background: linear-gradient( 165deg, color-mix(in srgb, var(--down, #4dabf7) 10%, var(--panel, #1e222d)) 0%, var(--panel, #1e222d) 55% ); } .chart-slot--compact.chart-slot--trend-up.active:not(.chart-slot--receiving) { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--up, #ff6b6b) 45%, var(--accent, #2962ff)); } .chart-slot--compact.chart-slot--trend-down.active:not(.chart-slot--receiving) { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--down, #4dabf7) 45%, var(--accent, #2962ff)); } .chart-slot--compact.chart-slot--trend-up:not(.chart-slot--receiving) .slot-header--compact { border-bottom-color: color-mix(in srgb, var(--up, #ff6b6b) 18%, var(--se-border, var(--border, #2a2e3a))); } .chart-slot--compact.chart-slot--trend-down:not(.chart-slot--receiving) .slot-header--compact { border-bottom-color: color-mix(in srgb, var(--down, #4dabf7) 18%, var(--se-border, var(--border, #2a2e3a))); } /* 실시간 수신 — 가상투자 vtd-card--receiving 와 동일 형광 연두 */ .multi-slot-wrap:has(.chart-slot--receiving), .chart-slot--compact.chart-slot--receiving { border-color: #69f0ae !important; box-shadow: 0 0 0 1px #69f0ae, 0 0 10px 4px #69f0ae66, 0 0 22px 8px #b9f6ca33, inset 0 0 48px color-mix(in srgb, #b9f6ca 14%, transparent); transition: box-shadow 0.15s ease-out, border-color 0.15s ease-out; } .chart-slot--compact.chart-slot--receiving { background: linear-gradient( 165deg, color-mix(in srgb, #b9f6ca 14%, #131722) 0%, color-mix(in srgb, #69f0ae 5%, var(--panel, #1e222d)) 40%, var(--panel, #1e222d) 65% ); } .chart-slot--compact.chart-slot--receiving.active { box-shadow: 0 0 0 1px #69f0ae, 0 0 10px 4px #69f0ae66, 0 0 22px 8px #b9f6ca33, inset 0 0 0 1px color-mix(in srgb, #69f0ae 55%, var(--accent, #2962ff)); } .chart-slot--compact.chart-slot--receiving .slot-chart-wrap--compact { box-shadow: inset 0 0 24px color-mix(in srgb, #b9f6ca 8%, transparent); } .slot-header--compact { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px 10px; padding: 8px 10px; min-height: unset; border-bottom: 1px solid var(--border, #2a2e3a); } .slot-compact-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; width: 100%; min-width: 0; } .slot-compact-name { display: inline-flex; align-items: center; gap: 5px; flex: 0 1 auto; max-width: 42%; background: none; border: 1px solid transparent; border-radius: 6px; padding: 2px 6px; margin: -2px -6px; cursor: pointer; color: var(--text, #d1d4dc); font-size: 13px; font-weight: 700; white-space: nowrap; overflow: hidden; text-align: left; transition: background 0.12s, border-color 0.12s, color 0.12s; } .slot-compact-name-text { overflow: hidden; text-overflow: ellipsis; min-width: 0; } .slot-compact-name:hover { background: color-mix(in srgb, var(--accent, #2962ff) 8%, transparent); border-color: color-mix(in srgb, var(--accent, #2962ff) 22%, transparent); } .slot-compact-name.open { color: var(--accent, #2962ff); background: color-mix(in srgb, var(--accent, #2962ff) 12%, transparent); border-color: color-mix(in srgb, var(--accent, #2962ff) 35%, transparent); } .slot-compact-quote { display: flex; align-items: baseline; gap: 6px; flex: 0 1 auto; min-width: 0; white-space: nowrap; } .slot-compact-price { font-size: 13px; font-weight: 700; } .slot-compact-change { font-size: 11px; font-weight: 600; opacity: 0.92; } .slot-compact-tf { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; } .slot-compact-tf-label { font-size: 10px; color: var(--text-muted, #787b86); flex-shrink: 0; } .slot-compact-tf-select { appearance: none; padding: 3px 22px 3px 8px; border-radius: 6px; border: 1px solid var(--border, #2a2e3a); background: var(--bg, #131722) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23787b86' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 6px center; color: var(--text, #d1d4dc); font-size: 11px; font-weight: 600; cursor: pointer; min-width: 52px; } .slot-compact-tf-select:focus { outline: none; border-color: var(--accent, #2962ff); } .slot-compact-status { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; margin-left: auto; } @media (max-width: 420px) { .slot-compact-row { row-gap: 6px; } .slot-compact-name { max-width: 55%; } .slot-compact-status { width: 100%; justify-content: flex-end; } } .chart-slot--compact .slot-chart-wrap--compact { flex: 1; min-height: 240px; height: auto !important; border: none !important; border-radius: 0 !important; border-top: none !important; } .chart-slot--compact .slot-chart-wrap--compact .chart-hover-toolbar { display: none !important; } .chart-slot--compact .ws-badge { font-size: 9px; padding: 2px 6px; } /* 슬롯 미니 헤더 */ .slot-header { display: flex; align-items: center; gap: 6px; padding: 3px 8px; background: var(--panel, #1e2130); border-bottom: 1px solid var(--border, #2a2e3a); flex-shrink: 0; min-height: 30px; flex-wrap: wrap; } .slot-sym-btn { display: flex; align-items: center; gap: 4px; background: none; border: 1px solid transparent; color: var(--text, #d1d4dc); cursor: pointer; font-size: 12px; font-weight: 600; padding: 3px 7px; border-radius: 4px; transition: background .12s, border-color .12s; max-width: 160px; overflow: hidden; } .slot-sym-btn:hover { background: var(--btn-bg, rgba(255,255,255,.08)); border-color: var(--border, #3a3e4a); } .slot-sym-btn.open { background: var(--accent-muted, rgba(41,98,255,.15)); border-color: var(--accent, #2962ff); color: var(--accent, #2962ff); } .slot-sym-kr { color: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .slot-sym-code { font-size: 10px; opacity: .55; margin-left: 2px; white-space: nowrap; flex-shrink: 0; } /* 타임프레임 버튼 */ .slot-tf-row { display: flex; gap: 1px; } .slot-tf-btn { background: none; border: none; color: var(--text-muted, #787b86); font-size: 10px; padding: 2px 4px; border-radius: 2px; cursor: pointer; } .slot-tf-btn:hover { color: var(--text, #d1d4dc); background: var(--btn-bg, rgba(255,255,255,.07)); } .slot-tf-btn.active { color: var(--accent, #2962ff); font-weight: 700; } /* 현재가 */ .slot-price { font-size: 12px; font-weight: 600; margin-left: auto; } .slot-change { font-size: 10px; margin-left: 4px; } .slot-loading { font-size: 10px; color: var(--text-muted, #787b86); } /* 차트 래퍼 (TradingChart가 flex로 차오르게) */ .slot-chart-wrap { flex: 1; min-height: 0; position: relative; overflow: hidden; display: flex; flex-direction: column; } /* TradingChart가 내부에서 tv-chart-wrap을 flex:1로 렌더하므로 이 div도 stretch */ .slot-chart-wrap > div, .slot-chart-wrap > .tv-chart-wrap { flex: 1; min-height: 0; } /* ══════════════════════════════════════════════════════════════════ Chart Hover Toolbar (차트 마우스오버 플로팅 버튼바) ══════════════════════════════════════════════════════════════════ */ .chart-hover-toolbar { position: absolute; bottom: 36px; /* BottomBar / X축 레이블 위 */ left: 50%; transform: translateX(-50%); z-index: 200; display: flex; align-items: center; gap: 4px; background: var(--bg2, #1e2130); border: 1px solid var(--border, #2a2e3a); border-radius: 10px; padding: 5px 8px; box-shadow: 0 4px 16px rgba(0,0,0,0.45); /* 진입/이탈 애니메이션 */ opacity: 0; pointer-events: none; transition: opacity 0.15s ease; } /* 부모 .tv-chart-wrap 또는 .slot-chart-wrap 에 hover 시 표시 */ .tv-chart-wrap:hover .chart-hover-toolbar, .slot-chart-wrap:hover .chart-hover-toolbar { opacity: 1; pointer-events: auto; } .cht-btn { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 7px; background: var(--bg, #131722); color: var(--text, #c0caf5); cursor: pointer; transition: background 0.12s, color 0.12s, transform 0.1s; flex-shrink: 0; } .cht-btn:hover { background: var(--accent, #2962ff); color: #fff; transform: scale(1.08); } .cht-btn:active { transform: scale(0.95); } /* 라이트 테마 override */ .app.light .chart-hover-toolbar { background: #f5f5f5; border-color: #d0d0d0; box-shadow: 0 4px 16px rgba(0,0,0,0.15); } .app.light .cht-btn { background: #ffffff; color: #212121; border: 1px solid #e0e0e0; } .app.light .cht-btn:hover { background: #2962ff; color: #fff; border-color: #2962ff; } /* ─── Chart Magnifier (확대경) ──────────────────────────────────────────── */ .chart-magnifier { position: fixed; /* wrapper 밖으로도 자유롭게 이동 */ z-index: 2000; border-radius: 6px; cursor: grab; overflow: hidden; box-shadow: 0 4px 24px rgba(0,0,0,0.55), 0 0 0 1px rgba(255,200,50,0.45); background: #111218; display: flex; flex-direction: column; /* pointer-events: all — 내부 drag/resize 가 동작하도록 */ user-select: none; } /* 헤더 (드래그 바) */ .chart-magnifier-header { height: 30px; background: linear-gradient(90deg, #1a1d2e 0%, #1e2035 100%); border-bottom: 1px solid rgba(255,200,50,0.3); display: flex; align-items: center; gap: 6px; padding: 0 8px; flex-shrink: 0; } .chart-magnifier:active { cursor: grabbing; } /* 리사이즈 핸들 위에서는 grab 커서 대신 방향 커서 표시 */ .chart-magnifier-handle { cursor: inherit; } .chart-magnifier-icon { opacity: 0.75; flex-shrink: 0; } .chart-magnifier-title { font-size: 11px; font-weight: 600; color: rgba(255,200,50,0.9); letter-spacing: 0.03em; flex: 1; } /* LIVE 지시등 */ .chart-magnifier-live { font-size: 9px; font-weight: 700; letter-spacing: 0.04em; color: rgba(255,255,255,0.25); background: rgba(255,255,255,0.07); border-radius: 3px; padding: 1px 4px; flex-shrink: 0; transition: color 0.1s, background 0.1s; } .chart-magnifier-live.live-on { color: #00e676; background: rgba(0, 230, 118, 0.15); animation: magnifier-live-pulse 0.6s ease-out; } @keyframes magnifier-live-pulse { 0% { box-shadow: 0 0 0 0 rgba(0,230,118,0.6); } 60% { box-shadow: 0 0 0 5px rgba(0,230,118,0); } 100% { box-shadow: 0 0 0 0 rgba(0,230,118,0); } } /* 줌 컨트롤 (XY / Y 공통) */ .chart-magnifier-zoom, .chart-magnifier-yzoom { display: flex; align-items: center; gap: 3px; } /* Y-Zoom 구분선 */ .chart-magnifier-yzoom { border-left: 1px solid rgba(255,255,255,0.12); padding-left: 6px; } .chart-magnifier-zoom-btn { width: 18px; height: 18px; border-radius: 3px; border: 1px solid rgba(255,255,255,0.15); background: rgba(255,255,255,0.06); color: rgba(255,255,255,0.75); font-size: 14px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; transition: background 0.1s; } .chart-magnifier-zoom-btn:hover { background: rgba(255,200,50,0.25); color: #fff; } /* Y-Zoom 버튼은 주황 계열 */ .chart-magnifier-yzoom-btn { border-color: rgba(255,150,30,0.35); } .chart-magnifier-yzoom-btn:hover { background: rgba(255,150,30,0.3); } .chart-magnifier-zoom-val { font-size: 11px; font-weight: 600; color: rgba(255,200,50,0.9); min-width: 30px; text-align: center; } .chart-magnifier-yzoom .chart-magnifier-zoom-val { color: rgba(255,150,30,0.95); min-width: 28px; } /* 닫기 버튼 */ .chart-magnifier-close { width: 18px; height: 18px; border-radius: 3px; border: none; background: transparent; color: rgba(255,255,255,0.5); font-size: 14px; line-height: 1; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; transition: background 0.1s, color 0.1s; } .chart-magnifier-close:hover { background: rgba(220,60,60,0.5); color: #fff; } /* 확대 캔버스 */ .chart-magnifier-canvas { flex: 1; display: block; width: 100%; height: 0; /* flex:1 로 채워짐 */ } /* 리사이즈 핸들 */ .chart-magnifier-handle { background: rgba(255,200,50,0.6); border-radius: 2px; z-index: 10; } .chart-magnifier-handle:hover { background: rgba(255,200,50,1); } /* 라이트 테마 오버라이드 */ .app.light .chart-magnifier { background: #f0f2f5; box-shadow: 0 4px 24px rgba(0,0,0,0.22), 0 0 0 1px rgba(41,98,255,0.35); } .app.light .chart-magnifier-header { background: linear-gradient(90deg, #e8eaf0 0%, #eceef5 100%); border-bottom-color: rgba(41,98,255,0.25); } .app.light .chart-magnifier-title { color: rgba(41,98,255,0.9); } .app.light .chart-magnifier-zoom-val { color: rgba(41,98,255,0.9); } .app.light .chart-magnifier-zoom-btn { border-color: rgba(0,0,0,0.15); background: rgba(0,0,0,0.04); color: rgba(0,0,0,0.7); } .app.light .chart-magnifier-zoom-btn:hover { background: rgba(41,98,255,0.2); } .app.light .chart-magnifier-live { color: rgba(0,0,0,0.3); background: rgba(0,0,0,0.06); } .app.light .chart-magnifier-live.live-on { color: #00a854; background: rgba(0,168,84,0.12); } .app.light .chart-magnifier-yzoom { border-left-color: rgba(0,0,0,0.12); } .app.light .chart-magnifier-yzoom .chart-magnifier-zoom-val { color: rgba(200,90,0,0.9); } .app.light .chart-magnifier-yzoom-btn { border-color: rgba(200,90,0,0.3); } .app.light .chart-magnifier-yzoom-btn:hover { background: rgba(200,90,0,0.15); } /* ══════════════════════════════════════════════════════════════════ MARKET PANEL (좌측 접이식 마켓 패널) ══════════════════════════════════════════════════════════════════ */ /* ── 패널 컨테이너 ─────────────────────────────────────────────── */ .market-panel { flex-shrink: 0; width: 0; overflow: hidden; background: var(--bg2); border-right: 1px solid var(--border); transition: width 0.22s cubic-bezier(0.4, 0, 0.2, 1); } .market-panel--open { width: 268px; } /* ── 패널 본문 (스크롤 포함) ──────────────────────────────────── */ .mp-body { display: flex; flex-direction: column; width: 268px; min-width: 268px; height: 100%; overflow: hidden; background: var(--bg2); } /* ── 탭 ───────────────────────────────────────────────────────── */ .mp-tabs { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; background: var(--bg3); } .mp-tab { flex: 1; padding: 9px 0; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--text3); font-size: 12px; font-weight: 500; cursor: pointer; transition: color 0.12s, border-color 0.12s; letter-spacing: 0.2px; } .mp-tab:hover { color: var(--text); } .mp-tab--active { color: var(--text); border-bottom-color: var(--accent); font-weight: 600; } /* ── 검색 ─────────────────────────────────────────────────────── */ .mp-search-row { padding: 7px 8px; flex-shrink: 0; border-bottom: 1px solid var(--border); } .mp-search-box { display: flex; align-items: center; gap: 6px; background: var(--bg3); border: 1px solid var(--border); border-radius: 5px; padding: 5px 8px; } .mp-search-input { flex: 1; background: transparent; border: none; outline: none; color: var(--text); font-size: 12px; min-width: 0; } .mp-search-input::placeholder { color: var(--text3); } .mp-search-clear { background: transparent; border: none; color: var(--text3); cursor: pointer; font-size: 13px; padding: 0 2px; line-height: 1; } .mp-search-clear:hover { color: var(--text); } /* ── 컬럼 헤더 ────────────────────────────────────────────────── */ .mp-list-header { display: flex; align-items: center; padding: 5px 8px 5px 28px; border-bottom: 1px solid var(--border); flex-shrink: 0; background: var(--bg3); } .mp-h-name { flex: 1; } .mp-h-price { width: 80px; text-align: right; } .mp-h-change { width: 62px; text-align: right; padding-right: 4px; } /* 정렬 버튼 공통 */ .mp-h-sort-btn { display: inline-flex; align-items: center; gap: 2px; background: none; border: none; padding: 0; cursor: pointer; font-size: 10px; color: var(--text3); letter-spacing: 0.3px; white-space: nowrap; user-select: none; transition: color 0.15s; } .mp-h-sort-btn:hover { color: var(--text1); } .mp-h-sort-btn--active { color: var(--accent, #2196f3); } .mp-sort-icon { font-size: 9px; opacity: 0.6; line-height: 1; } .mp-h-sort-btn--active .mp-sort-icon { opacity: 1; } /* ── 보유 추가 영역 ───────────────────────────────────────────── */ .mp-hold-add-area { padding: 6px 8px; border-bottom: 1px solid var(--border); flex-shrink: 0; position: relative; } .mp-hold-add-btn { width: 100%; background: transparent; border: 1px dashed var(--border); border-radius: 4px; color: var(--text3); font-size: 11px; padding: 5px; cursor: pointer; transition: color 0.12s, border-color 0.12s; } .mp-hold-add-btn:hover { color: var(--accent); border-color: var(--accent); } .mp-hold-add-form { display: flex; gap: 6px; align-items: center; } .mp-hold-add-input { flex: 1; background: var(--bg3); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 12px; padding: 4px 8px; outline: none; min-width: 0; } .mp-hold-add-cancel { background: transparent; border: none; color: var(--text3); font-size: 11px; cursor: pointer; white-space: nowrap; } .mp-hold-add-cancel:hover { color: var(--text); } .mp-hold-add-dropdown { position: absolute; top: calc(100% - 6px); left: 8px; right: 8px; background: var(--bg2); border: 1px solid var(--border); border-radius: 5px; z-index: 100; max-height: 200px; overflow-y: auto; box-shadow: 0 4px 16px rgba(0,0,0,0.3); } .mp-hold-add-item { display: flex; justify-content: space-between; align-items: center; padding: 7px 10px; font-size: 12px; cursor: pointer; color: var(--text); } .mp-hold-add-item:hover { background: var(--bg3); } .mp-hold-add-code { color: var(--text3); font-size: 11px; } /* ── 목록 스크롤 영역 ─────────────────────────────────────────── */ .mp-list { flex: 1; overflow-y: auto; overflow-x: hidden; } .mp-list::-webkit-scrollbar { width: 4px; } .mp-list::-webkit-scrollbar-track { background: transparent; } .mp-list::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 2px; } .mp-loading { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 32px 0; color: var(--text3); font-size: 11px; } .mp-empty { text-align: center; padding: 32px 12px; color: var(--text3); font-size: 12px; } /* ── 개별 행 ──────────────────────────────────────────────────── */ .mp-row { display: flex; align-items: center; padding: 6px 6px 6px 0; cursor: pointer; border-bottom: 1px solid rgba(122,162,247,0.06); transition: background 0.1s; gap: 0; } .mp-row:hover { background: var(--bg3); } .mp-row--active { background: rgba(122,162,247,0.1); } .mp-row--active:hover { background: rgba(122,162,247,0.14); } /* 별 버튼 */ .mp-star { width: 24px; min-width: 24px; background: transparent; border: none; color: var(--text3); font-size: 13px; cursor: pointer; padding: 0 2px; line-height: 1; transition: color 0.12s; text-align: center; } .mp-star:hover { color: #f0b040; } .mp-star--on { color: #f0b040; } /* 이름 컬럼 */ .mp-name { flex: 1; display: flex; flex-direction: column; gap: 1px; min-width: 0; overflow: hidden; } .mp-korean { font-size: 12px; color: var(--text); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .mp-code { font-size: 10px; color: var(--text3); white-space: nowrap; } /* 가격 / 등락 */ .mp-price { width: 80px; text-align: right; font-size: 12px; font-weight: 500; white-space: nowrap; font-variant-numeric: tabular-nums; } .mp-change { width: 58px; text-align: right; font-size: 11px; white-space: nowrap; font-variant-numeric: tabular-nums; padding-right: 4px; } .mp-up { color: var(--up); } .mp-dn { color: var(--down); } /* 보유 토글 버튼 */ .mp-hold-btn { width: 30px; min-width: 30px; background: transparent; border: none; color: var(--text3); font-size: 10px; cursor: pointer; padding: 0 2px; white-space: nowrap; transition: color 0.12s; } .mp-hold-btn:hover { color: var(--accent); } .mp-hold-btn--on { color: var(--accent); font-weight: 700; } /* 보유 탭 제거 버튼 */ .mp-hold-rm { width: 22px; min-width: 22px; background: transparent; border: none; color: var(--text3); font-size: 14px; cursor: pointer; padding: 0; line-height: 1; transition: color 0.12s; } .mp-hold-rm:hover { color: var(--down); } /* ── 패널 접기/펼치기 핸들 (tv-main flex 자식, 항상 표시) ─────── */ .mp-panel-handle { /* flex 자식으로 배치 – 패널 바로 오른쪽 */ align-self: center; flex-shrink: 0; position: relative; z-index: 20; width: 16px; height: 56px; /* 패널 경계에 완전히 붙도록 음수 마진으로 겹치기 */ margin-left: -1px; background: var(--bg2); border: 1px solid var(--border); border-left: none; border-radius: 0 8px 8px 0; color: var(--text3); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.15s, color 0.15s, box-shadow 0.15s; box-shadow: 2px 0 10px rgba(0, 0, 0, 0.35); padding: 0; } .mp-panel-handle:hover { background: var(--bg3); color: var(--text); box-shadow: 3px 0 14px rgba(0, 0, 0, 0.45); } .mp-panel-handle--open { /* 패널 열렸을 때: 살짝 강조 */ border-color: rgba(122, 162, 247, 0.3); } /* ── 라이트 테마 오버라이드 ───────────────────────────────────── */ .app.light .mp-tabs { background: #f0f0f0; } .app.light .mp-list-header { background: #f5f5f5; } .app.light .mp-search-box { background: #f5f5f5; } .app.light .mp-row { border-bottom-color: rgba(0,0,0,0.05); } .app.light .mp-row:hover { background: #f5f5f5; } .app.light .mp-row--active { background: rgba(25,118,210,0.08); } .app.light .mp-panel-handle { background: #fff; border-color: rgba(0,0,0,0.15); box-shadow: 2px 0 8px rgba(0,0,0,0.12); } /* ══════════════════════════════════════════════════════════════════ MARKET PANEL – 상단/하단 분할 레이아웃 ══════════════════════════════════════════════════════════════════ */ /* 마켓 목록만 전체 높이 사용 */ .mp-body--full { display: flex; flex-direction: column; height: 100%; } .mp-body--full .mp-list { flex: 1; min-height: 0; overflow-y: auto; } /* ══════════════════════════════════════════════════════════════════ ORDERBOOK PANEL (실시간 호가창) ══════════════════════════════════════════════════════════════════ */ .ob-panel { display: flex; flex-direction: column; height: 100%; background: var(--bg2); font-size: 11px; } /* 헤더 */ .ob-header { display: flex; align-items: center; justify-content: space-between; padding: 5px 8px 4px; flex-shrink: 0; border-bottom: 1px solid var(--border); background: var(--bg3); } .ob-header-title { font-size: 12px; font-weight: 600; color: var(--text); } .ob-header-market { color: var(--accent); font-size: 11px; margin-left: 4px; } /* WS 연결 상태 점 */ .ob-dot { display: flex; align-items: center; gap: 4px; font-size: 10px; color: var(--text3); } .ob-dot-circle { width: 6px; height: 6px; border-radius: 50%; background: var(--text3); } .ob-dot--ok .ob-dot-circle { background: #22c55e; } .ob-dot--ok { color: #22c55e; } .ob-dot--wait .ob-dot-circle { background: #eab308; } .ob-dot--wait { color: #eab308; } .ob-dot--err .ob-dot-circle { background: #ef4444; } .ob-dot--err { color: #ef4444; } /* ── 실시간 호가 (증권앱형 통합) ── */ .ob-panel--classic { display: flex; flex-direction: column; height: 100%; background: var(--bg2); font-size: 11px; } .ob-quote-header { flex-shrink: 0; display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; padding: 10px 12px 8px; border-bottom: 1px solid var(--border); background: var(--bg3); } .ob-quote-name { display: block; font-size: 11px; color: var(--text2); margin-bottom: 4px; } .ob-quote-price-row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; } .ob-quote-price { font-size: 22px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.1; } .ob-quote-price--up { color: var(--up); } .ob-quote-price--dn { color: var(--down); } .ob-quote-change, .ob-quote-rate { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; } .ob-quote-change--up, .ob-quote-rate--up { color: var(--up); } .ob-quote-change--dn, .ob-quote-rate--dn { color: var(--down); } .ob-quote-right { text-align: right; flex-shrink: 0; } .ob-quote-vol, .ob-quote-ratio { margin-bottom: 4px; } .ob-quote-vol-label, .ob-quote-ratio-label { font-size: 9px; color: var(--text3); margin-right: 6px; } .ob-quote-vol-val, .ob-quote-ratio-val { font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; } .ob-quote-ratio-val--up { color: var(--up); } .ob-subtabs { flex-shrink: 0; display: flex; border-bottom: 1px solid var(--border); background: var(--bg2); } .ob-subtab { flex: 1; padding: 8px 4px; border: none; background: transparent; color: var(--text3); font-size: 11px; cursor: default; border-bottom: 2px solid transparent; margin-bottom: -1px; } .ob-subtab--active { color: var(--text); font-weight: 700; border-bottom-color: var(--accent); cursor: default; } .ob-subtab:disabled:not(.ob-subtab--active) { opacity: 0.45; } .ob-body { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; } .ob-block { flex: 1 1 50%; min-height: 0; display: flex; overflow: hidden; } .ob-block--ask { background: rgba(77, 171, 247, 0.1); } .ob-block--bid { background: rgba(255, 107, 107, 0.08); } .ob-block-table { flex: 1; min-width: 0; display: flex; flex-direction: column; overflow: hidden; } .ob-table-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; } .ob-table-scroll::-webkit-scrollbar { width: 4px; } .ob-table-scroll::-webkit-scrollbar-thumb { background: var(--bg4); border-radius: 2px; } .ob-table-scroll--ask { display: flex; flex-direction: column; justify-content: flex-end; } .ob-table--hoga { width: 100%; border-collapse: collapse; table-layout: fixed; font-variant-numeric: tabular-nums; } .ob-col-side { width: 32%; } .ob-col-price { width: 36%; } .ob-table--mid { display: none; } .ob-td-price--live { box-shadow: inset 0 0 0 2px #1565c0; font-weight: 800; background: rgba(21, 101, 192, 0.12); text-align: center; } .app.light .ob-td-price--live { box-shadow: inset 0 0 0 2px #1976d2; background: rgba(25, 118, 210, 0.1); } .ob-tr-mid .ob-td-price--current { border: 2px solid #1565c0; text-align: center; vertical-align: middle; padding: 5px 4px; background: var(--bg2); } .app.light .ob-tr-mid .ob-td-price--current { border-color: #1976d2; } .ob-mid-price { display: block; font-size: 13px; font-weight: 800; } .ob-mid-pct { display: block; font-size: 9px; margin-top: 1px; } .ob-td-price--up .ob-mid-price { color: var(--up); } .ob-td-price--dn .ob-mid-price { color: var(--down); } .ob-tr--clickable { cursor: pointer; } .ob-tr--clickable:hover { background: rgba(255, 255, 255, 0.06); } .ob-td { height: 21px; padding: 0 3px; vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; border: none; font-size: 10px; } .ob-td--pad { padding: 0; } .ob-td-empty { text-align: center; color: var(--text3); padding: 6px; } .ob-td-price { text-align: center; font-weight: 700; font-size: 11px; color: var(--text); } .ob-td-price-sm { font-size: 9px; font-weight: 500; color: var(--text); text-align: left; } .ob-td-pct { text-align: right; font-size: 9px; color: var(--text3); padding-right: 5px; } .ob-td-pct--left { text-align: left; padding-left: 5px; padding-right: 0; } .ob-td-pct--up { color: var(--up); } .ob-td-pct--dn { color: var(--down); } .ob-td-qty { position: relative; padding: 0; } .ob-td-qty--ask .ob-td-bar-text { text-align: right; padding-right: 5px; } .ob-td-qty--bid .ob-td-bar-text { text-align: left; padding-left: 5px; } .ob-td-bar-wrap { position: relative; height: 21px; display: flex; align-items: center; } .ob-td-bar-wrap--right { justify-content: flex-end; } .ob-td-bar { position: absolute; top: 0; height: 100%; opacity: 0.28; pointer-events: none; max-width: 92%; } .ob-td-bar--ask { left: 0; background: #4dabf7; } .ob-td-bar--bid { right: 0; background: #ff6b6b; } .ob-td-bar-text { position: relative; z-index: 1; font-size: 10px; color: var(--text); width: 100%; } /* 우측 시세 (매도 구간) */ .ob-stats-rail { flex-shrink: 0; width: 72px; padding: 6px 5px; border-left: 1px solid var(--border); background: rgba(0, 0, 0, 0.08); font-size: 9px; overflow-y: auto; } .ob-stat-row { display: flex; flex-direction: column; margin-bottom: 8px; gap: 1px; } .ob-stat-k { color: var(--text3); font-size: 8px; } .ob-stat-v { font-weight: 700; font-variant-numeric: tabular-nums; font-size: 9px; word-break: break-all; } .ob-stat-v--up { color: var(--up); } .ob-stat-v--dn { color: var(--down); } /* 좌측 체결 (매수 구간) */ .ob-trades-panel { flex-shrink: 0; width: 88px; padding: 5px 4px; border-right: 1px solid var(--border); background: rgba(0, 0, 0, 0.06); overflow: hidden; display: flex; flex-direction: column; } .ob-trades-strength { margin-bottom: 5px; padding-bottom: 4px; border-bottom: 1px solid var(--border); } .ob-trades-strength-k { display: block; font-size: 8px; color: var(--text3); } .ob-trades-strength-v { font-size: 11px; font-weight: 800; color: var(--text); } .ob-trades-strength-v--up { color: var(--up); } .ob-table--trades { width: 100%; border-collapse: collapse; font-size: 9px; } .ob-table--trades thead th { font-weight: 500; color: var(--text3); padding: 2px 0; text-align: left; font-size: 8px; } .ob-table--trades thead th:last-child { text-align: right; } .ob-trades-vol--buy { color: var(--up); text-align: right; } .ob-trades-vol--sell { color: var(--down); text-align: right; } /* 하단 합계 바 */ .ob-summary-bar { flex-shrink: 0; display: grid; grid-template-columns: 1fr auto 1fr; align-items: stretch; border-top: 1px solid var(--border); min-height: 32px; } .ob-summary { display: flex; align-items: center; justify-content: center; padding: 4px 8px; font-variant-numeric: tabular-nums; } .ob-summary--ask { background: rgba(77, 171, 247, 0.35); justify-content: flex-start; padding-left: 12px; } .ob-summary--bid { background: rgba(255, 107, 107, 0.35); justify-content: flex-end; padding-right: 12px; } .ob-summary--time { background: var(--bg3); font-size: 11px; font-weight: 600; color: var(--text); padding: 0 14px; border-left: 1px solid var(--border); border-right: 1px solid var(--border); } .ob-summary-time-wrap { position: relative; } .ob-summary-time-btn { display: inline-flex; align-items: center; gap: 4px; padding: 0; border: none; background: transparent; color: inherit; font: inherit; cursor: pointer; line-height: 1.2; } .ob-summary-time-btn:hover { color: var(--accent, #2962ff); } .ob-summary-time-caret { font-size: 9px; opacity: 0.75; } .ob-summary-mode-menu { position: absolute; bottom: calc(100% + 4px); left: 50%; transform: translateX(-50%); z-index: 20; min-width: 72px; padding: 4px 0; border-radius: 6px; border: 1px solid var(--border); background: var(--bg2, #1e222d); box-shadow: 0 4px 16px rgba(0, 0, 0, 0.35); } .ob-summary-mode-item { display: block; width: 100%; padding: 6px 12px; border: none; background: transparent; color: var(--text); font-size: 11px; font-weight: 600; text-align: center; cursor: pointer; } .ob-summary-mode-item:hover { background: var(--bg3); } .ob-summary-mode-item--active { color: var(--accent, #2962ff); } .ob-summary-num { font-size: 12px; font-weight: 700; color: var(--text); } .app.light .ob-block--ask { background: #ebf2fa; } .app.light .ob-block--bid { background: #fdf0f0; } .app.light .ob-stats-rail, .app.light .ob-trades-panel { background: rgba(255, 255, 255, 0.6); } .app.light .ob-summary--ask { background: #bbdefb; } .app.light .ob-summary--bid { background: #ffcdd2; } .app.light .ob-panel--classic { background: #fff; } /* 로딩/빈 상태 */ .ob-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 20px 0; color: var(--text3); font-size: 11px; flex: 1; } /* 푸터 총 잔량 */ .ob-footer { display: flex; align-items: center; gap: 6px; padding: 4px 6px; border-top: 1px solid var(--border); flex-shrink: 0; background: var(--bg3); } .ob-footer-ask { font-size: 10px; color: var(--up); white-space: nowrap; } .ob-footer-bid { font-size: 10px; color: var(--down); white-space: nowrap; } .ob-footer-bar { flex: 1; height: 4px; background: rgba(77, 171, 247, 0.3); border-radius: 2px; overflow: hidden; } .ob-footer-ask-fill { height: 100%; background: rgba(255, 107, 107, 0.7); border-radius: 2px; transition: width 0.3s ease; } /* ── 라이트 테마 오버라이드 ───────────────────────────────────── */ .app.light .ob-panel { background: #fff; } .app.light .ob-header { background: #f5f5f5; } .app.light .ob-col-header { background: #f5f5f5; } .app.light .ob-spread-bar { background: #f0f0f0; } .app.light .ob-footer { background: #f5f5f5; } /* ══════════════════════════════════════════════════════════════════ MARKET ROW – 실시간 가격 변동 플래시 (frontend_golden 동일 로직) ══════════════════════════════════════════════════════════════════ */ /* 상승 플래시: 빨강 → 투명 (0.7s) */ @keyframes mp-flash-rise { 0% { background-color: rgba(255, 82, 82, 0.28); } 100% { background-color: transparent; } } /* 하락 플래시: 파랑 → 투명 (0.7s) */ @keyframes mp-flash-fall { 0% { background-color: rgba(59, 130, 246, 0.28); } 100% { background-color: transparent; } } .mp-row--flash-rise { animation: mp-flash-rise 0.7s ease-out forwards; } .mp-row--flash-fall { animation: mp-flash-fall 0.7s ease-out forwards; } /* 보합(EVEN) 색상 */ .mp-even { color: var(--text3); } /* 방향 지시자 삼각형 */ .mp-arrow { font-size: 8px; line-height: 1; flex-shrink: 0; margin-right: 2px; } .mp-arrow--rise { color: var(--up); } .mp-arrow--fall { color: var(--down); } .mp-arrow--even { color: var(--text3); font-size: 10px; } /* 한글명 + 삼각형 가로 배치 */ .mp-korean-row { display: flex; align-items: center; gap: 1px; overflow: hidden; } .mp-korean-row .mp-korean { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ═══════════════════════════════════════════════════════════════════════════ chart-screen — 실시간 차트 화면 래퍼 hidden 상태에서도 chart 인스턴스가 유지되도록 display:none 대신 visibility+pointer-events 를 사용해 WebSocket 연결을 끊지 않는다. ═══════════════════════════════════════════════════════════════════════════ */ .chart-screen { display: contents; /* flex/grid 레이아웃에 영향 없이 자식 직통 */ } /* WebSocket 훅은 React에서 관리되므로 DOM 숨김과 무관하게 유지됨 */ .chart-screen--hidden { display: none; } /* ═══════════════════════════════════════════════════════════════════════════ StrategyPage — 투자전략 화면 ═══════════════════════════════════════════════════════════════════════════ */ .strat-page { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: var(--bg); color: var(--text); } /* ── 상단 요약 카드 바 ──────────────────────────────────────────────────── */ .strat-summary-bar { display: flex; gap: 12px; padding: 16px 20px 0; flex-shrink: 0; } .strat-summary-card { flex: 1; background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; padding: 14px 18px; display: flex; flex-direction: column; gap: 4px; min-width: 0; } .strat-summary-num { font-size: 28px; font-weight: 700; color: var(--text); line-height: 1; } .strat-summary-label { font-size: 11px; color: var(--text2); letter-spacing: .04em; } .strat-summary-card--active { border-left: 3px solid var(--up); } .strat-summary-card--paused { border-left: 3px solid var(--text3); } .strat-summary-card--backtest { border-left: 3px solid var(--accent); } /* ── 바디 (사이드바 + 메인) ─────────────────────────────────────────────── */ .strat-body { flex: 1; display: flex; gap: 0; overflow: hidden; margin-top: 16px; } /* ── 좌측 사이드바 ──────────────────────────────────────────────────────── */ .strat-sidebar { width: 280px; flex-shrink: 0; display: flex; flex-direction: column; background: var(--bg2); border-right: 1px solid var(--border); overflow: hidden; } .strat-sidebar-toolbar { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .strat-sidebar-title { font-size: 13px; font-weight: 600; color: var(--text); } .strat-new-btn { display: flex; align-items: center; gap: 5px; padding: 5px 10px; background: var(--accent); color: #fff; border: none; border-radius: 5px; font-size: 12px; cursor: pointer; font-weight: 500; transition: background .15s; } .strat-new-btn:hover { background: var(--accent-h); } /* 필터 탭 */ .strat-filter-tabs { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; } .strat-filter-tab { flex: 1; padding: 7px 4px; font-size: 11px; background: none; border: none; color: var(--text2); cursor: pointer; border-bottom: 2px solid transparent; transition: color .15s, border-color .15s; } .strat-filter-tab:hover { color: var(--text); } .strat-filter-tab--on { color: var(--accent); border-bottom-color: var(--accent); } /* 목록 */ .strat-list { flex: 1; overflow-y: auto; } .strat-list-empty { padding: 20px; text-align: center; color: var(--text3); font-size: 13px; } .strat-list-item { padding: 10px 14px; border-bottom: 1px solid var(--border); cursor: pointer; transition: background .12s; } .strat-list-item:hover { background: var(--bg3); } .strat-list-item--selected { background: var(--bg3); } .strat-item-row1 { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-bottom: 4px; } .strat-item-name { font-size: 13px; font-weight: 500; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; } .strat-item-row2 { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; } .strat-item-symbol { font-size: 11px; color: var(--accent); font-weight: 500; } .strat-item-date { font-size: 10px; color: var(--text3); } .strat-item-actions { display: flex; gap: 4px; } .strat-item-btn { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; border: 1px solid var(--border); border-radius: 4px; background: var(--bg); color: var(--text2); cursor: pointer; transition: background .12s, color .12s; } .strat-item-btn:hover { background: var(--bg4); color: var(--text); } .strat-item-btn--play:hover { color: var(--up); border-color: var(--up); } .strat-item-btn--pause:hover { color: var(--text3); } .strat-item-btn--delete:hover { color: var(--down); border-color: var(--down); } /* 상태 배지 */ .strat-badge { display: inline-block; padding: 2px 7px; border-radius: 20px; font-size: 10px; font-weight: 600; letter-spacing: .03em; white-space: nowrap; flex-shrink: 0; } .strat-badge--active { background: rgba(var(--up-rgb,255,107,107), .15); color: var(--up); } .strat-badge--paused { background: var(--bg4); color: var(--text3); } .strat-badge--backtest { background: rgba(var(--accent-rgb,122,162,247), .15); color: var(--accent); } /* ── 우측 메인 영역 ──────────────────────────────────────────────────────── */ .strat-main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: var(--bg); } /* 빈 상태 */ .strat-empty-detail { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--text3); } .strat-empty-title { font-size: 15px; font-weight: 500; color: var(--text2); margin: 0; } .strat-empty-sub { font-size: 13px; color: var(--text3); margin: 0; } /* 전략 상세 */ .strat-detail { flex: 1; display: flex; flex-direction: column; padding: 20px 24px; overflow-y: auto; gap: 0; } .strat-detail-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 12px; } .strat-detail-title { display: flex; align-items: center; gap: 10px; } .strat-detail-name { font-size: 18px; font-weight: 700; color: var(--text); } .strat-detail-close { background: none; border: none; color: var(--text3); font-size: 15px; cursor: pointer; padding: 4px 8px; border-radius: 4px; line-height: 1; transition: background .12s, color .12s; } .strat-detail-close:hover { background: var(--bg3); color: var(--text); } .strat-detail-meta { display: flex; gap: 20px; margin-bottom: 12px; } .strat-meta-item { display: flex; gap: 6px; align-items: center; } .strat-meta-key { font-size: 11px; color: var(--text3); } .strat-meta-val { font-size: 12px; color: var(--text); font-weight: 500; } .strat-detail-desc { font-size: 13px; color: var(--text2); line-height: 1.6; padding: 10px 14px; background: var(--bg2); border-left: 3px solid var(--accent); border-radius: 0 5px 5px 0; margin: 0 0 20px; } /* 조건 영역 */ .strat-detail-conditions { display: flex; gap: 16px; margin-bottom: 20px; } .strat-cond-section { flex: 1; background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; padding: 14px; display: flex; flex-direction: column; gap: 8px; min-width: 0; } .strat-cond-section-title { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 600; color: var(--text2); margin-bottom: 2px; } .strat-cond-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; } .strat-cond-dot--buy { background: var(--up); } .strat-cond-dot--sell { background: var(--down); } .strat-cond-empty { font-size: 12px; color: var(--text3); font-style: italic; } .strat-cond-card { display: flex; align-items: center; gap: 6px; padding: 7px 10px; background: var(--bg); border-radius: 5px; font-size: 12px; } .strat-cond-label { color: var(--text); font-weight: 500; } .strat-cond-op { color: var(--text3); } .strat-cond-value { color: var(--accent); font-weight: 500; margin-left: auto; } /* 액션 버튼 */ .strat-detail-actions { display: flex; gap: 8px; margin-top: auto; padding-top: 10px; border-top: 1px solid var(--border); } .strat-act-btn { display: flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: 6px; font-size: 13px; font-weight: 500; cursor: pointer; border: 1px solid var(--border); background: var(--bg2); color: var(--text); transition: background .12s, border-color .12s; } .strat-act-btn:hover { background: var(--bg3); } .strat-act-btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; } .strat-act-btn--primary:hover { background: var(--accent-h); border-color: var(--accent-h); } .strat-act-btn--test { color: var(--accent); border-color: var(--accent); } .strat-act-btn--chart { color: var(--text2); } /* ═══════════════════════════════════════════════════════════════════════════ StrategyPage (sp-*) — frontend_golden 완전 재현, 좌우 반전 Layout: [전략목록탭(L, 360px)] [편집기(C, 1fr)] [전략구성요소(R, 340px)] ═══════════════════════════════════════════════════════════════════════════ */ /* ── 페이지 래퍼 ──────────────────────────────────────────────────────────── */ .sp-page { flex: 1; display: flex; flex-direction: column; height: calc(100vh - 44px); overflow: hidden; background: var(--bg); color: var(--text); } /* ── 상단 툴바 ────────────────────────────────────────────────────────────── */ .sp-topbar { display: flex; align-items: center; gap: 6px; padding: 6px 12px; border-bottom: 1px solid var(--border); background: var(--bg2); min-height: 44px; flex-shrink: 0; } .sp-topbar-title { font-size: 15px; font-weight: 600; white-space: nowrap; } .sp-topbar-chip { font-size: 12px; padding: 2px 8px; border: 1px solid var(--accent); border-radius: 99px; color: var(--accent); } .sp-topbar-spacer { flex: 1; } .sp-tb { padding: 5px 12px; font-size: 13px; border-radius: var(--radius); border: 1px solid var(--border); background: transparent; color: var(--text); cursor: pointer; white-space: nowrap; } .sp-tb:hover:not(:disabled) { background: var(--bg3); } .sp-tb:disabled { opacity: .45; cursor: not-allowed; } .sp-tb-icon { padding: 4px 8px; font-size: 14px; } .sp-tb-save { background: var(--accent); border-color: var(--accent); color: #fff; font-weight: 600; } .sp-tb-save:hover:not(:disabled) { background: var(--accent-h); } /* ── 본문 3컬럼 ───────────────────────────────────────────────────────────── */ .sp-body { flex: 1; display: grid; grid-template-columns: 420px 1fr 390px; overflow: hidden; } /* ── 좌측 패널 (전략목록/상세보기/알림목록) ─────────────────────────────── */ .sp-left { display: flex; flex-direction: column; border-right: 1px solid var(--border); background: var(--bg2); overflow: hidden; } /* ── 패널 탭 (좌측 패널 + 우측 패널 공용) ──────────────────────────────── */ .sp-panel-tabs { display: flex; border-bottom: 1px solid var(--border); background: var(--bg3); flex-shrink: 0; } .sp-panel-tab { flex: 1; padding: 10px 4px; font-size: 13px; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--text2); cursor: pointer; } .sp-panel-tab--on { color: var(--text); border-bottom-color: var(--accent); font-weight: 600; } .sp-panel-body { flex: 1; overflow: hidden; display: flex; flex-direction: column; min-height: 0; padding: 0; } .sp-panel-body > .sp-preview, .sp-panel-body > div:not(.sp-strat-panel) { flex: 1; min-height: 0; overflow-y: auto; padding: 12px 14px 16px; } /* ── 전략 목록 (카드형 — 전략편집기와 동일) ───────────────────────────────── */ .sp-strat-panel { display: flex; flex-direction: column; min-height: 0; height: 100%; padding: 14px 12px 12px; margin: 8px; border-radius: 14px; background: color-mix(in srgb, var(--bg2) 92%, transparent); border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18), inset 0 1px 0 color-mix(in srgb, var(--text) 4%, transparent); } .sp-strat-panel-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--border); } .sp-strat-panel-title { margin: 0; font-size: 0.88rem; font-weight: 700; letter-spacing: 0.02em; color: var(--text); } .sp-strat-sort { flex-shrink: 0; background: var(--bg3); border: 1px solid var(--border); color: var(--text2); font-size: 0.68rem; padding: 3px 6px; border-radius: 6px; } .sp-new-strat-btn { flex-shrink: 0; width: 100%; margin: 0 0 12px; padding: 11px 12px; border-radius: 10px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: background 0.15s, border-color 0.15s, color 0.15s; } .sp-new-strat-btn:hover { background: var(--bg4); border-color: color-mix(in srgb, var(--accent) 28%, transparent); color: var(--accent); } .sp-strat-list { flex: 1; overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 10px; padding: 2px 1px 4px; } .sp-strat-item { display: flex; align-items: center; gap: 8px; padding: 12px 13px; cursor: pointer; border-radius: 12px; border: 1px solid var(--border); background: color-mix(in srgb, var(--bg2) 88%, transparent); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2), inset 0 1px 0 color-mix(in srgb, var(--text) 5%, transparent); transition: background 0.15s, border-color 0.15s, box-shadow 0.15s, transform 0.12s; outline: none; } .sp-strat-item:hover { background: var(--bg3); border-color: color-mix(in srgb, var(--accent) 28%, transparent); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.25); transform: translateY(-1px); } .sp-strat-item--sel { background: color-mix(in srgb, var(--accent) 12%, var(--bg2)); border-color: color-mix(in srgb, var(--accent) 45%, transparent); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.25), 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent); transform: translateY(-1px); } .sp-strat-item--sel:hover { background: color-mix(in srgb, var(--accent) 14%, var(--bg2)); } .sp-strat-item:focus-visible { outline: 2px solid color-mix(in srgb, var(--accent) 55%, transparent); outline-offset: 2px; } .sp-strat-name { flex: 1; min-width: 0; font-size: 0.82rem; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .sp-strat-item--sel .sp-strat-name { color: var(--accent); } .sp-strat-item-actions { flex-shrink: 0; display: flex; align-items: center; gap: 6px; } .sp-strat-action { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; padding: 0; border: none; border-radius: 6px; background: transparent; color: var(--text3); font-size: 0.85rem; cursor: pointer; transition: color 0.12s, background 0.12s; } .sp-strat-action:hover { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); } .sp-strat-del { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; padding: 0; border: none; border-radius: 6px; background: transparent; color: var(--text3); cursor: pointer; transition: color 0.12s, background 0.12s; } .sp-strat-item--sel .sp-strat-del { color: color-mix(in srgb, var(--accent) 85%, transparent); } .sp-strat-del:hover { color: #ff6b6b; background: color-mix(in srgb, #ff6b6b 15%, transparent); } .sp-strat-status { flex-shrink: 0; min-width: 36px; text-align: center; font-size: 0.65rem; font-weight: 700; padding: 3px 7px; border-radius: 999px; color: var(--text3); background: color-mix(in srgb, var(--text3) 10%, transparent); border: 1px solid var(--border); } .sp-strat-status--on { color: #48c774; background: color-mix(in srgb, #48c774 10%, transparent); border-color: color-mix(in srgb, #48c774 28%, transparent); } .sp-strat-item--sel .sp-strat-status--on { color: var(--accent); background: color-mix(in srgb, var(--accent) 15%, transparent); border-color: color-mix(in srgb, var(--accent) 35%, transparent); } .sp-strat-empty { font-size: 0.78rem; color: var(--text3); text-align: center; padding: 20px 8px; margin: 0; } /* ── 전략 목록 (레거시) ─────────────────────────────────────────────────── */ .sp-list-header { display: flex; align-items: center; justify-content: space-between; padding: 9px 14px; border-bottom: 1px solid var(--border); font-size: 13px; color: var(--text2); } .sp-sort-sel { background: var(--bg3); border: 1px solid var(--border); color: var(--text); font-size: 11px; padding: 2px 4px; border-radius: var(--radius); } .sp-list-item { display: flex; flex-direction: column; gap: 5px; padding: 10px 14px; border-bottom: 1px solid var(--border); cursor: pointer; user-select: none; } .sp-list-item:hover { background: var(--bg3); } .sp-list-item--sel { background: rgba(122,162,247,.1); border-left: 2px solid var(--accent); } .sp-li-row1 { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; } .sp-li-name { font-size: 14px; font-weight: 500; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .sp-li-chip { font-size: 11px; padding: 2px 8px; border-radius: 99px; background: var(--bg4); color: var(--text2); } .sp-li-chip--type { border: 1px solid var(--accent); color: var(--accent); background: transparent; } .sp-li-chip--on { background: rgba(72,199,116,.2); color: #48c774; } .sp-li-chip--off { background: var(--bg3); color: var(--text3); } .sp-li-actions { display: flex; justify-content: flex-end; gap: 2px; } .sp-li-btn { background: none; border: none; color: var(--text2); cursor: pointer; padding: 3px 6px; font-size: 14px; border-radius: var(--radius); } .sp-li-btn:hover { color: var(--text); background: var(--bg3); } .sp-li-btn--del:hover { color: #ff6b6b; } /* ── 상세보기 / 미리보기 ──────────────────────────────────────────────────── */ .sp-preview { padding: 12px; } .sp-prev-sec { margin-bottom: 12px; } .sp-prev-badge { display: inline-block; font-size: 12px; padding: 3px 10px; border-radius: 99px; margin-bottom: 8px; } .sp-prev-badge--buy { background: rgba(72,199,116,.2); color: #48c774; } .sp-prev-badge--sell { background: rgba(255,107,107,.2); color: #ff6b6b; } .sp-prev-text { background: var(--bg3); border: 1px solid var(--border); padding: 12px; font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; border-radius: var(--radius); } .sp-prev-section-title { font-size: 13px; font-weight: 600; color: var(--accent); border-bottom: 2px solid var(--border); padding-bottom: 4px; margin-bottom: 10px; } .sp-prev-formula { font-size: 13px; font-family: monospace; line-height: 1.6; margin-bottom: 6px; } .sp-prev-buy { color: #48c774; font-weight: 700; } .sp-prev-sell { color: #ff6b6b; font-weight: 700; } .sp-validation { margin-bottom: 8px; } .sp-val-head { font-size: 12px; font-weight: 600; margin-bottom: 4px; } .sp-val-ok { color: #48c774; font-size: 13px; padding: 5px 10px; background: rgba(72,199,116,.1); border-radius: var(--radius); } .sp-val-err { color: #ff6b6b; font-size: 13px; padding: 2px 0; } .sp-val-warn { color: #f7a140; font-size: 13px; padding: 2px 0; } /* ── 알림 목록 ────────────────────────────────────────────────────────────── */ .sp-alert-item { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--border); } .sp-alert-dot { width: 8px; height: 8px; border-radius: 50%; background: #48c774; flex-shrink: 0; } .sp-alert-name { flex: 1; font-size: 14px; } /* ── 빈 상태 안내 ─────────────────────────────────────────────────────────── */ .sp-empty-info { color: var(--text2); font-size: 14px; padding: 18px 14px; line-height: 1.6; } .sp-loading { text-align: center; padding: 24px; color: var(--text2); font-size: 13px; } /* ── 중앙 편집기 ──────────────────────────────────────────────────────────── */ .sp-editor { display: flex; flex-direction: column; border-left: 1px solid var(--border); border-right: 1px solid var(--border); overflow: hidden; background: var(--bg2); } /* 매수/매도 탭 + 우측 액션(저장·새로고침) */ .sp-signal-tabs-bar { display: flex; align-items: stretch; border-bottom: 1px solid var(--border); background: var(--bg3); flex-shrink: 0; } .sp-signal-tabs { display: flex; flex: 1; min-width: 0; } .sp-signal-tab-actions { display: flex; align-items: center; gap: 6px; padding: 6px 10px; flex-shrink: 0; border-left: 1px solid var(--border); } .sp-signal-tab { flex: 1; padding: 11px 8px; font-size: 14px; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--text2); cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 4px; } .sp-signal-tab--buy { color: #ff6b6b; border-bottom-color: #ff6b6b; font-weight: 600; background: rgba(255,107,107,.06); } .sp-signal-tab--sell { color: #4dabf7; border-bottom-color: #4dabf7; font-weight: 600; background: rgba(77,171,247,.06); } .sp-signal-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; } .sp-signal-dot--buy { background: #48c774; } .sp-signal-dot--sell { background: #ff6b6b; } /* 드롭존 */ .sp-dropzone { flex: 1; overflow-y: auto; padding: 12px; } .sp-drop-empty { color: var(--text2); font-size: 14px; text-align: center; margin-top: 48px; padding: 28px; border: 2px dashed var(--border); border-radius: 8px; line-height: 1.6; } /* ── 트리 노드 ────────────────────────────────────────────────────────────── */ .sp-tree-node { margin-bottom: 8px; border-radius: var(--radius); border: 1px solid var(--border); background: var(--bg3); transition: border-color .15s; } .sp-tree-node--over { border-color: var(--accent) !important; box-shadow: 0 0 0 2px rgba(122,162,247,.25); } .sp-node-head { display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-left: 3px solid transparent; border-radius: var(--radius) var(--radius) 0 0; background: rgba(0,0,0,.15); } .sp-node-head--cond { position: relative; flex-wrap: wrap; } .sp-node-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; margin-left: auto; } .sp-node-settings { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; padding: 0; border: none; border-radius: var(--radius); background: rgba(230, 194, 0, 0.12); color: #e6c200; cursor: pointer; flex-shrink: 0; } .sp-node-settings:hover { background: rgba(230, 194, 0, 0.22); } .sp-node-settings-pop { position: absolute; top: calc(100% + 4px); right: 8px; z-index: 50; min-width: 160px; padding: 8px 10px; border-radius: 8px; border: 1px solid color-mix(in srgb, #e6c200 45%, transparent); background: var(--bg2); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45); } .sp-node-settings-pop .se-flow-settings-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 0.62rem; font-weight: 700; color: #e6c200; margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.06em; } .sp-node-settings-pop .se-flow-settings-close, .se-flow-settings-close { border: none; background: transparent; color: var(--text2); cursor: pointer; font-size: 1rem; line-height: 1; padding: 0 2px; flex-shrink: 0; } .sp-node-settings-pop .se-flow-settings-close:hover, .se-flow-settings-close:hover { color: #e6c200; } .sp-node-settings-pop .se-flow-settings-field { display: flex; flex-direction: column; gap: 3px; margin-bottom: 6px; font-size: 0.62rem; color: var(--text2); } .sp-node-settings-pop .se-flow-settings-field input, .se-flow-settings-field .se-combo-num-input, .sp-node-settings-pop .se-combo-num-input { width: 100%; box-sizing: border-box; padding: 4px 6px; border-radius: 4px; border: 1px solid var(--border); background: var(--bg3); color: var(--text); font-size: 0.72rem; } .se-combo-num { width: 100%; display: flex; flex-direction: column; gap: 6px; } .se-combo-num-select { width: 100%; } .se-combo-num-input { width: 100%; box-sizing: border-box; padding: 4px 6px; border-radius: 4px; border: 1px solid var(--se-input-border, var(--border)); background: var(--se-input-bg, var(--bg3)); color: var(--se-text, var(--text)); font-size: 0.72rem; } .se-combo-num-input:focus { outline: none; border-color: var(--se-input-focus, var(--accent)); } .se-flow-settings-field .se-combo-num-input { border-color: var(--se-input-border); background: var(--se-input-bg); } .sp-node-settings-pop .se-flow-settings-hint { margin: 4px 0 0; font-size: 0.58rem; color: var(--text3); } .sp-node-badge { font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 99px; color: #fff; white-space: nowrap; } .sp-node-label { flex: 1; font-size: 13px; color: var(--text2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .sp-node-del { background: none; border: none; color: var(--text3); cursor: pointer; font-size: 12px; padding: 2px 4px; border-radius: var(--radius); line-height: 1; flex-shrink: 0; } .sp-node-del:hover { color: #ff6b6b; background: rgba(255,107,107,.1); } /* 자식 영역 */ .sp-node-children { padding: 8px 8px 8px 20px; border-top: 1px solid var(--border); } .sp-drop-hint-inner { border: 2px dashed var(--accent); border-radius: var(--radius); padding: 8px 12px; font-size: 12px; color: var(--accent); text-align: center; margin-top: 6px; } /* ── 조건 인라인 편집기 ──────────────────────────────────────────────────── */ .sp-cond-editor { padding: 10px 12px; } .sp-cond-row4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; } .sp-cond-field { display: flex; flex-direction: column; gap: 3px; } .sp-cond-lbl { font-size: 12px; color: var(--text2); font-weight: 500; } .sp-cond-sel { font-size: 13px; padding: 5px 7px; background: var(--bg2); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); appearance: none; cursor: pointer; } .sp-cond-sel:hover { border-color: var(--accent); } .sp-cond-sel:focus { outline: none; border-color: var(--accent); } .sp-cond-extra { margin-top: 6px; display: flex; align-items: center; gap: 8px; } .sp-cond-num { font-size: 12px; padding: 4px 8px; width: 120px; background: var(--bg2); border: 1px solid var(--border); color: var(--text); border-radius: var(--radius); } .sp-cond-num:focus { outline: none; border-color: var(--accent); } .sp-cond-editor--composite { padding-top: 6px; } .sp-cond-composite-badge { margin-bottom: 8px; padding: 4px 8px; border-radius: 6px; font-size: 11px; font-weight: 600; color: #c084fc; background: color-mix(in srgb, #c084fc 12%, transparent); border: 1px solid color-mix(in srgb, #c084fc 28%, transparent); } .sp-cond-composite-val { font-size: 12px; font-weight: 600; color: var(--text); padding: 4px 0 2px; } .sp-cond-num--inline { margin-top: 2px; width: 100%; box-sizing: border-box; } /* ── 우측 팔레트 ──────────────────────────────────────────────────────────── */ .sp-palette { display: flex; flex-direction: column; background: var(--bg2); overflow: hidden; } .sp-pal-header { font-size: 14px; font-weight: 600; padding: 11px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .sp-pal-tabs { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; } .sp-pal-tab { flex: 1; padding: 9px 4px; font-size: 13px; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--text2); cursor: pointer; } .sp-pal-tab--on { color: var(--text); border-bottom-color: var(--accent); font-weight: 600; } .sp-pal-body { flex: 1; overflow-y: auto; padding: 10px 10px 16px; } /* 팔레트 섹션 */ .sp-pal-sec { margin-bottom: 12px; } .sp-pal-sec-title { font-size: 12px; color: var(--text2); font-weight: 600; margin-bottom: 8px; } .sp-pal-chips { display: flex; flex-wrap: wrap; gap: 5px; } /* 팔레트 칩 */ .sp-chip { display: inline-flex; align-items: center; gap: 4px; padding: 5px 12px; border-radius: 99px; font-size: 13px; font-weight: 500; cursor: grab; user-select: none; border: 1px solid transparent; transition: transform .1s, box-shadow .1s; } .sp-chip:hover { transform: translateY(-1px); box-shadow: 0 2px 8px rgba(0,0,0,.3); } .sp-chip:active { cursor: grabbing; transform: scale(.96); } .sp-chip--green { background: rgba(72,199,116,.2); border-color: rgba(72,199,116,.4); color: #48c774; } .sp-chip--blue { background: rgba(77,171,247,.2); border-color: rgba(77,171,247,.4); color: #4dabf7; } .sp-chip--orange { background: rgba(247,161,64,.2); border-color: rgba(247,161,64,.4); color: #f7a140; } .sp-chip--primary { background: rgba(122,162,247,.15); border-color: rgba(122,162,247,.35); color: var(--accent); } .sp-chip--ind { background: rgba(156,39,176,.15); border-color: rgba(156,39,176,.35); color: #ce93d8; } /* 자동설정 템플릿 */ .sp-pal-auto { padding: 0; } .sp-pal-auto-info { font-size: 12px; color: var(--text2); padding: 10px; margin-bottom: 6px; background: var(--bg3); border-radius: var(--radius); } .sp-pal-tmpl { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; padding: 10px 8px; border-bottom: 1px solid var(--border); cursor: pointer; font-size: 13px; } .sp-pal-tmpl:hover { background: var(--bg3); } .sp-tmpl-badge { font-size: 11px; padding: 3px 8px; border-radius: 99px; white-space: nowrap; font-weight: 600; } .sp-tmpl-badge--buy { background: rgba(72,199,116,.2); color: #48c774; } .sp-tmpl-badge--sell { background: rgba(255,107,107,.2); color: #ff6b6b; } .sp-tmpl-name { flex: 1 1 auto; color: var(--text); } .sp-tmpl-desc { flex: 1 1 100%; font-size: 11px; line-height: 1.35; color: var(--text2); } /* ── 모달 ─────────────────────────────────────────────────────────────────── */ .sp-modal-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.6); z-index: 1000; } .sp-modal { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; width: 440px; max-width: calc(100vw - 32px); display: flex; flex-direction: column; overflow: hidden; box-shadow: 0 16px 48px rgba(0,0,0,0.5); } .sp-modal-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; flex-shrink: 0; cursor: grab; user-select: none; border-bottom: 1px solid var(--border); background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .sp-modal-header:active { cursor: grabbing; } .sp-modal-title { flex: 1; font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); margin: 0; } .sp-modal-body { padding: 16px 20px 20px; } .sp-modal-info { font-size: 12px; color: var(--text2); background: var(--bg3); padding: 8px; border-radius: var(--radius); margin-bottom: 10px; } .sp-modal-chips { display: flex; gap: 6px; margin-bottom: 12px; } .sp-modal-chip { font-size: 11px; padding: 2px 8px; border-radius: 99px; border: 1px solid var(--border); color: var(--text2); } .sp-modal-chip--buy { border-color: #48c774; color: #48c774; } .sp-modal-chip--sell { border-color: #ff6b6b; color: #ff6b6b; } .sp-modal-lbl { display: block; font-size: 12px; color: var(--text2); margin: 10px 0 4px; } .sp-modal-inp { width: 100%; padding: 8px 10px; font-size: 13px; background: var(--bg3); border: 1px solid var(--border); border-radius: var(--radius); color: var(--text); font-family: var(--font); } .sp-modal-inp:focus { outline: none; border-color: var(--accent); } .sp-modal-ta { resize: vertical; min-height: 72px; } .sp-modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; } .sp-modal-btn { padding: 7px 18px; font-size: 13px; border-radius: var(--radius); cursor: pointer; font-weight: 500; } .sp-modal-btn--cancel { background: transparent; border: 1px solid var(--border); color: var(--text); } .sp-modal-btn--cancel:hover { background: var(--bg3); } .sp-modal-btn--ok { background: var(--accent); border: none; color: #fff; } .sp-modal-btn--ok:hover { background: var(--accent-h); } .sp-modal-btn--ok:disabled { opacity: .5; cursor: not-allowed; } .sp-modal-btn--del { background: #ff6b6b; border: none; color: #fff; } .sp-modal-btn--del:hover { background: #e05555; } /* ── 스낵바 ───────────────────────────────────────────────────────────────── */ .sp-snack { position: fixed; bottom: 32px; left: 50%; transform: translateX(-50%); padding: 11px 22px; border-radius: 20px; font-size: 14px; font-weight: 500; z-index: 2000; box-shadow: 0 4px 16px rgba(0,0,0,.4); animation: sp-fadein .25s ease; } .sp-snack--ok { background: rgba(72,199,116,.9); color: #fff; } .sp-snack--err { background: rgba(255,107,107,.9); color: #fff; } @keyframes sp-fadein { from { opacity:0; transform: translateX(-50%) translateY(12px); } to { opacity:1; transform: translateX(-50%) translateY(0); } } /* ── Light Theme 오버라이드 ──────────────────────────────────────────────── */ .app.light .sp-node-head { background: rgba(0,0,0,.04); } .app.light .sp-cond-sel { background: #fff; } .app.light .sp-modal-inp { background: #fff; } .app.light .sp-pal-tmpl:hover { background: #f0f0f0; } /* ══════════════════════════════════════════════════════════════════ 백테스팅 패널 (BacktestPanel) ══════════════════════════════════════════════════════════════════ */ /* ══════════════════════════════════════════════ 백테스팅 — 툴바 버튼 ══════════════════════════════════════════════ */ .bt-toolbar-btn { display: flex; align-items: center; gap: 5px; padding: 4px 10px; background: transparent; border: 1px solid var(--border); border-radius: 4px; color: var(--text2); font-size: 12px; font-weight: 600; cursor: pointer; white-space: nowrap; transition: background .12s, color .12s; } .bt-toolbar-btn:hover { background: var(--bg3); color: var(--text); } .bt-toolbar-btn--active { background: rgba(122,162,247,.18); border-color: var(--accent); color: var(--accent); } /* ── 백테스팅 버튼 그룹 (백테스팅 버튼 + 설정 버튼 가로 배치) */ .bt-group { display: flex; align-items: center; gap: 2px; } /* ── 백테스팅 버튼 + 드롭다운 래퍼 */ .bt-drop-wrap { position: relative; } /* ── 전략 드롭다운 */ .bt-strategy-drop { position: absolute; top: calc(100% + 6px); left: 0; z-index: 500; min-width: 260px; background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; box-shadow: 0 8px 28px rgba(0,0,0,.45); overflow: hidden; } .bt-drop-header { display: flex; align-items: center; justify-content: space-between; padding: 8px 12px; background: var(--bg3); border-bottom: 1px solid var(--sep); font-size: 11px; font-weight: 700; color: var(--text2); text-transform: uppercase; letter-spacing: .5px; } .bt-drop-refresh { background: transparent; border: none; color: var(--text2); font-size: 14px; cursor: pointer; padding: 0 2px; line-height: 1; } .bt-drop-refresh:hover { color: var(--accent); } .bt-drop-empty { padding: 16px 14px; font-size: 12px; color: var(--text3); text-align: center; line-height: 1.6; } .bt-drop-list { list-style: none; margin: 0; padding: 4px 0; max-height: 280px; overflow-y: auto; } .bt-drop-item { display: flex; align-items: center; justify-content: space-between; padding: 7px 12px; gap: 8px; transition: background .1s; } .bt-drop-item:hover { background: var(--bg3); } .bt-drop-name { flex: 1; font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: flex; align-items: center; gap: 5px; } .bt-drop-local-badge { font-size: 9px; background: rgba(255,200,0,.2); color: #FFC107; border: 1px solid rgba(255,200,0,.3); border-radius: 3px; padding: 1px 4px; flex-shrink: 0; } .bt-drop-run { flex-shrink: 0; padding: 4px 12px; background: var(--accent); color: #fff; border: none; border-radius: 4px; font-size: 12px; font-weight: 600; cursor: pointer; transition: opacity .12s; white-space: nowrap; } .bt-drop-run:hover:not(:disabled) { opacity: .82; } .bt-drop-run:disabled { opacity: .45; cursor: not-allowed; } .bt-drop-run.running { background: var(--bg4); color: var(--text2); } /* ══════════════════════════════════════════════════════════════════ 실시간 전략 체크 패널 (LiveStrategyPanel) — TradeAlertModal 스타일 ══════════════════════════════════════════════════════════════════ */ .lsp-overlay { position: fixed; inset: 0; z-index: 9998; pointer-events: none; } .lsp-overlay > .lsp-modal { pointer-events: auto; } .lsp-modal { position: fixed; width: 400px; max-width: calc(100vw - 24px); max-height: calc(100vh - 24px); display: flex; flex-direction: column; background: var(--bg2, #24283b); border: 1px solid var(--lsp-accent, var(--border, rgba(122,162,247,0.15))); border-radius: 12px; box-shadow: 0 0 0 1px var(--lsp-accent-glow, rgba(122,162,247,0.08)), 0 20px 60px rgba(0,0,0,0.65), 0 0 40px var(--lsp-accent-glow, rgba(122,162,247,0.06)); overflow: hidden; font-size: 13px; color: var(--text, #c0caf5); font-family: var(--font, 'Noto Sans KR', sans-serif); } .lsp-header { flex-shrink: 0; } .lsp-header-left { display: flex; align-items: center; gap: 9px; flex: 1; min-width: 0; } .lsp-badge { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: 11px; font-weight: 800; color: #fff; letter-spacing: 1.2px; flex-shrink: 0; } .lsp-header-title { font-size: 14px; font-weight: 700; color: var(--text, #c0caf5); letter-spacing: 0.4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .lsp-header-ko { font-size: 12px; font-weight: 400; color: var(--text2, #9aa5ce); } .lsp-saving { font-size: 10px; color: var(--text3, #6272a4); flex-shrink: 0; } .lsp-close { background: none; border: none; color: var(--text3, #6272a4); font-size: 16px; cursor: pointer; padding: 2px 6px; line-height: 1; border-radius: 4px; transition: color 0.15s, background 0.15s; flex-shrink: 0; } .lsp-close:hover { color: var(--text, #c0caf5); background: var(--bg4, rgba(255,255,255,0.07)); } .lsp-summary-section { padding: 12px 16px 10px; background: linear-gradient( 135deg, var(--lsp-accent-glow, rgba(122,162,247,0.08)) 0%, transparent 60% ); border-bottom: 1px solid var(--border, rgba(122,162,247,0.1)); flex-shrink: 0; } .lsp-summary-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 4px; } .lsp-summary-label { font-size: 11.5px; color: var(--text2, #9aa5ce); } .lsp-summary-value { font-size: 15px; font-weight: 800; color: var(--text, #c0caf5); letter-spacing: -0.3px; } .lsp-summary-value--active { color: var(--lsp-accent, #3f7ef5); } .lsp-summary-hint { margin: 6px 0 0; font-size: 10.5px; color: var(--text3, #6272a4); line-height: 1.45; } .lsp-info-card { display: flex; align-items: flex-start; gap: 12px; margin: 12px 14px 0; padding: 11px 14px; background: var(--bg3, #1f2335); border: 1px solid var(--border, rgba(122,162,247,0.12)); border-radius: 9px; flex-shrink: 0; } .lsp-info-icon { flex-shrink: 0; display: flex; align-items: center; } .lsp-info-body { display: flex; flex-direction: column; gap: 6px; flex: 1; min-width: 0; } .lsp-info-row { display: flex; flex-direction: column; gap: 4px; } .lsp-info-label { font-size: 11px; color: var(--text3, #6272a4); } .lsp-info-val { font-size: 12.5px; font-weight: 600; color: var(--text, #c0caf5); } .lsp-body { display: flex; flex-direction: column; gap: 10px; padding: 12px 14px 14px; overflow-y: auto; flex: 1; min-height: 0; } .lsp-field-row { display: flex; align-items: center; gap: 8px; } .lsp-field-row--disabled, .lsp-section--disabled { opacity: 0.45; pointer-events: none; } .lsp-field-label, .lsp-section-label { font-size: 11.5px; color: var(--text2, #9aa5ce); flex-shrink: 0; min-width: 62px; } .lsp-section-label { display: block; margin-bottom: 6px; } .lsp-toggle { position: relative; display: inline-flex; align-items: center; cursor: pointer; margin-left: auto; } .lsp-toggle input { opacity: 0; width: 0; height: 0; position: absolute; } .lsp-toggle-slider { width: 38px; height: 20px; background: var(--bg3, #1f2335); border: 1px solid var(--border, rgba(122,162,247,0.18)); border-radius: 10px; transition: background 0.2s, border-color 0.2s; position: relative; } .lsp-toggle-slider::after { content: ''; position: absolute; width: 14px; height: 14px; border-radius: 50%; background: #fff; top: 2px; left: 2px; transition: transform 0.2s; } .lsp-toggle input:checked + .lsp-toggle-slider { background: var(--lsp-accent, #3f7ef5); border-color: var(--lsp-accent, #3f7ef5); } .lsp-toggle input:checked + .lsp-toggle-slider::after { transform: translateX(18px); } .lsp-select { flex: 1; min-width: 0; padding: 7px 10px; background: var(--bg3, #1f2335); border: 1px solid var(--border, rgba(122,162,247,0.18)); border-radius: 6px; color: var(--text, #c0caf5); font-size: 12.5px; font-weight: 600; cursor: pointer; outline: none; transition: border-color 0.15s; } .lsp-select:focus { border-color: var(--lsp-accent, #3f7ef5); } .lsp-select:disabled { cursor: not-allowed; } .lsp-section { display: flex; flex-direction: column; } .lsp-option-group { display: flex; flex-direction: column; gap: 6px; } .lsp-option { display: flex; align-items: flex-start; gap: 8px; padding: 9px 11px; border: 1px solid var(--border, rgba(122,162,247,0.12)); border-radius: 8px; background: var(--bg3, #1f2335); cursor: pointer; transition: border-color 0.15s, background 0.15s; } .lsp-option:hover { border-color: var(--lsp-accent, rgba(63,126,245,0.35)); background: var(--bg4, #414868); } .lsp-option--active { border-color: var(--lsp-accent, #3f7ef5); background: rgba(63, 126, 245, 0.1); box-shadow: inset 0 0 0 1px rgba(63, 126, 245, 0.15); } .lsp-option input { margin-top: 3px; accent-color: var(--lsp-accent, #3f7ef5); flex-shrink: 0; } .lsp-option-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .lsp-option-title { font-size: 12px; font-weight: 700; color: var(--text, #c0caf5); } .lsp-option-desc { font-size: 10.5px; color: var(--text3, #6272a4); line-height: 1.4; } .lsp-hint { font-size: 10.5px; color: var(--text3, #6272a4); margin: 0; line-height: 1.45; } .lsp-monitor-chips { display: flex; flex-wrap: wrap; gap: 4px; font-weight: 400; } .lsp-monitor-chip { font-size: 10px; padding: 2px 7px; border-radius: 4px; background: rgba(63, 126, 245, 0.12); color: var(--lsp-accent, #3f7ef5); border: 1px solid rgba(63, 126, 245, 0.25); font-weight: 600; } .lsp-status-bar { display: flex; align-items: center; gap: 8px; padding: 9px 11px; background: var(--bg3, #1f2335); border: 1px solid var(--border, rgba(122,162,247,0.12)); border-radius: 8px; } .lsp-status-text { font-size: 11px; color: var(--text2, #9aa5ce); line-height: 1.4; min-width: 0; } .lsp-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--text3, #6272a4); flex-shrink: 0; } .lsp-dot--on { background: var(--lsp-accent, #3f7ef5); box-shadow: 0 0 6px var(--lsp-accent-glow, rgba(63,126,245,0.5)); animation: lsp-pulse 1.5s ease-in-out infinite; } @keyframes lsp-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } } .lsp-disclaimer { font-size: 10.5px; color: var(--text3, #6272a4); text-align: center; margin: 2px 0 0; line-height: 1.5; } /* 라이트 테마 */ .app.light .lsp-modal { background: #ffffff; border-color: rgba(25,118,210,0.35); color: #212121; box-shadow: 0 20px 60px rgba(0,0,0,0.18), 0 0 40px rgba(25,118,210,0.08); } .app.light .lsp-header-title { color: #1a237e; } .app.light .lsp-header-ko { color: #546e7a; } .app.light .lsp-close { color: #78909c; } .app.light .lsp-close:hover { background: rgba(0,0,0,0.06); color: #37474f; } .app.light .lsp-summary-section { border-color: rgba(0,0,0,0.08); } .app.light .lsp-summary-label { color: #546e7a; } .app.light .lsp-summary-value { color: #212121; } .app.light .lsp-info-card { background: #f5f7fa; border-color: rgba(0,0,0,0.1); } .app.light .lsp-info-label { color: #78909c; } .app.light .lsp-info-val { color: #212121; } .app.light .lsp-field-label, .app.light .lsp-section-label { color: #546e7a; } .app.light .lsp-select { background: #f0f3f8; border-color: rgba(0,0,0,0.12); color: #212121; } .app.light .lsp-option { background: #f5f7fa; border-color: rgba(0,0,0,0.1); } .app.light .lsp-option:hover { background: #eef2f7; } .app.light .lsp-option--active { background: rgba(25,118,210,0.08); border-color: rgba(25,118,210,0.45); } .app.light .lsp-option-title { color: #212121; } .app.light .lsp-status-bar { background: #f5f7fa; border-color: rgba(0,0,0,0.1); } .app.light .lsp-status-text { color: #546e7a; } .app.light .lsp-monitor-chip { background: rgba(25,118,210,0.1); color: #1976d2; border-color: rgba(25,118,210,0.25); } .lsp-monitor-stats { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text2); margin-bottom: 6px; } .lsp-monitor-sep { opacity: 0.5; } .lsp-monitor-on { color: #3f7ef5; font-weight: 600; } .lsp-monitor-warn { font-size: 10.5px; color: #ff9800; line-height: 1.45; margin-bottom: 8px; padding: 6px 8px; background: rgba(255, 152, 0, 0.08); border: 1px solid rgba(255, 152, 0, 0.25); border-radius: 4px; } .lsp-apply-all-btn { display: block; margin-top: 6px; width: 100%; padding: 5px 8px; font-size: 11px; font-weight: 600; color: #fff; background: #3f7ef5; border: none; border-radius: 4px; cursor: pointer; } .lsp-apply-all-btn:hover:not(:disabled) { background: #5a92f7; } .lsp-apply-all-btn:disabled { opacity: 0.5; cursor: not-allowed; } .lsp-monitor-hint { color: var(--text3); } .lsp-monitor-list { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px; } .stg-btn-secondary { background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: 4px; cursor: pointer; } .stg-btn-secondary:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); } .stg-btn-secondary:disabled { opacity: 0.45; cursor: not-allowed; } .stg-sound-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; } .stg-sound-row .stg-select--wide { min-width: 160px; flex: 1; max-width: 220px; } .stg-sound-row .stg-btn-secondary { flex-shrink: 0; font-size: 12px; padding: 6px 12px; } /* ══════════════════════════════════════════════ 백테스팅 결과 통계 배지 (차트 위 오버레이) ══════════════════════════════════════════════ */ .bt-result-badge { position: absolute; top: calc(var(--toolbar-h, 40px) + 8px); left: 50%; transform: translateX(-50%); z-index: 200; display: flex; align-items: center; gap: 10px; background: var(--bg2); border: 1px solid var(--border); border-radius: 20px; padding: 5px 14px 5px 12px; box-shadow: 0 4px 16px rgba(0,0,0,.35); font-size: 12px; color: var(--text); white-space: nowrap; } .bt-result-sep { width: 1px; height: 14px; background: var(--sep); flex-shrink: 0; } .bt-result-row { display: flex; align-items: center; gap: 4px; } .bt-result-label { font-size: 10px; color: var(--text3); } .bt-result-val { font-size: 12px; font-weight: 600; } .bt-result-clear { background: transparent; border: none; color: var(--text3); font-size: 11px; cursor: pointer; padding: 1px 3px; margin-left: 2px; border-radius: 3px; line-height: 1; } .bt-result-clear:hover { color: #EF5350; background: rgba(239,83,80,.1); } /* ══════════════════════════════════════════════ 백테스팅 설정 버튼 (툴바) ══════════════════════════════════════════════ */ .bt-settings-btn { display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; background: transparent; border: 1px solid var(--border); border-radius: 5px; color: var(--text2); cursor: pointer; margin-left: 3px; flex-shrink: 0; transition: background .15s, color .15s, border-color .15s; } .bt-settings-btn:hover { background: var(--bg3); color: var(--text); border-color: var(--text3); } /* ══════════════════════════════════════════════ 백테스팅 설정 모달 (드래그 이동 가능, 2열 레이아웃) ══════════════════════════════════════════════ */ .bts-modal { width: 800px; max-width: 98vw; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 24px 64px rgba(0,0,0,.55); display: flex; flex-direction: column; overflow: hidden; user-select: none; } /* 타이틀바 — 드래그 핸들 */ .bts-header { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0; cursor: grab; user-select: none; background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .bts-header:active { cursor: grabbing; } .bts-title { font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); flex: 1; } .bts-close { background: transparent; border: none; color: var(--text3); font-size: 13px; cursor: pointer; padding: 3px 6px; border-radius: 4px; flex-shrink: 0; } .bts-close:hover { background: rgba(239,83,80,.18); color: #EF5350; } /* ── 본문: 섹션들이 2열 마소리 배치 ── */ .bts-body { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1px; overflow-y: auto; max-height: calc(100vh - 200px); background: var(--border); /* 열 구분선 */ padding: 0; } .bts-section { background: var(--bg2); padding: 6px 0 2px; } .bts-section-title { font-size: 10px; font-weight: 700; color: var(--text3); padding: 4px 12px 3px; letter-spacing: .5px; text-transform: uppercase; border-bottom: 1px solid var(--border); margin-bottom: 2px; } /* 섹션 내부: 필드들을 1열로 */ .bts-section-grid { display: flex; flex-direction: column; } .bts-row { display: flex; align-items: center; padding: 5px 12px; gap: 6px; cursor: pointer; transition: background .1s; border-left: 2px solid transparent; } .bts-row:hover { background: var(--bg3); } .bts-row-focused { background: rgba(33,150,243,.1); border-left-color: #2196F3; } .bts-row-label { flex: 1; font-size: 11.5px; color: var(--text2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .bts-row-ctrl { display: flex; align-items: center; flex-shrink: 0; } /* 입력 컨트롤 */ .bts-input { width: 90px; padding: 3px 7px; background: var(--bg1); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 12px; text-align: right; } .bts-input:focus { outline: none; border-color: #2196F3; } .bts-pct-wrap { display: flex; align-items: center; gap: 3px; } .bts-unit { font-size: 11px; color: var(--text3); } .bts-select { padding: 3px 6px; background: var(--bg1); border: 1px solid var(--border); border-radius: 4px; color: var(--text); font-size: 11.5px; cursor: pointer; max-width: 160px; } .bts-select:focus { outline: none; border-color: #2196F3; } .bts-toggle { padding: 2px 10px; border-radius: 10px; border: 1px solid var(--border); background: var(--bg3); color: var(--text3); font-size: 11px; font-weight: 600; cursor: pointer; transition: all .15s; min-width: 42px; text-align: center; } .bts-toggle-on { background: rgba(33,150,243,.2); border-color: #2196F3; color: #2196F3; } /* ── 하단 설명 패널 ── */ .bts-desc-panel { display: flex; align-items: flex-start; gap: 6px; padding: 8px 14px; background: var(--bg1); border-top: 1px solid var(--border); min-height: 62px; max-height: 110px; overflow-y: auto; flex-shrink: 0; } .bts-desc-label { font-size: 11px; font-weight: 700; color: #2196F3; white-space: nowrap; flex-shrink: 0; padding-top: 1px; } .bts-desc-sep { font-size: 11px; color: var(--text3); flex-shrink: 0; padding-top: 1px; } .bts-desc-text { font-size: 11.5px; color: var(--text2); line-height: 1.65; white-space: pre-wrap; word-break: keep-all; } .bts-desc-placeholder { font-size: 11.5px; color: var(--text3); font-style: italic; padding-top: 1px; } /* ── 푸터 ── */ .bts-footer { display: flex; align-items: center; padding: 8px 14px; border-top: 1px solid var(--border); gap: 8px; flex-shrink: 0; } .bts-btn { padding: 6px 16px; border-radius: 6px; border: 1px solid var(--border); font-size: 12px; cursor: pointer; font-weight: 500; transition: background .15s, border-color .15s; } .bts-btn-reset { background: var(--bg1); color: var(--text2); } .bts-btn-reset:hover { background: var(--bg3); } .bts-btn-cancel { background: var(--bg3); color: var(--text2); } .bts-btn-cancel:hover { background: var(--bg4); } .bts-btn-save { background: #2196F3; color: #fff; border-color: #2196F3; } .bts-btn-save:hover:not(:disabled) { background: #1976D2; } .bts-btn-save:disabled { opacity: .6; cursor: not-allowed; } /* ═══════════════════════════════════════════════════════════════════════════ CSS 변수 — 대시보드 색상 토큰 ─────────────────────────────────────────────────────────────────────────── */ :root { --brd-pos: #26c97e; --brd-neg: #f04e5e; --brd-warn: #ff9f43; --brd-blue: #3d9fff; --brd-purple:#a855f7; --brd-teal: #14b8a6; --brd-yellow:#fbbf24; --brd-green: #22c55e; } /* ═══════════════════════════════════════════════════════════════════════════ BacktestResultModal (.brm-*) — 모달 껍데기 ─────────────────────────────────────────────────────────────────────────── */ .brm-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 9500; backdrop-filter: blur(2px); } .brm-modal { background: var(--bg1); border: 1px solid var(--border); border-radius: 14px; width: 960px; max-width: 96vw; max-height: 90vh; display: flex; flex-direction: column; box-shadow: 0 24px 70px rgba(0,0,0,.6); overflow: hidden; user-select: none; } .brm-modal--embedded { width: 100%; max-width: 100%; max-height: 100%; height: 100%; border-radius: 0; border: none; box-shadow: none; } .brm-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border); cursor: grab; user-select: none; flex-shrink: 0; background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .brm-header:active { cursor: grabbing; } .brm-modal--embedded .brm-header { cursor: default; display: none; } .brm-header-left { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; } .brm-header-title { font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); } .brm-close { background: none; border: none; color: var(--text3); font-size: 16px; cursor: pointer; padding: 3px 8px; border-radius: 5px; transition: background .15s; } .brm-close:hover { background: rgba(240,78,94,.15); color: #f04e5e; } .brm-body { flex: 1; overflow-y: auto; } /* ═══════════════════════════════════════════════════════════════════════════ 대시보드 공통 (.brd-*) ─────────────────────────────────────────────────────────────────────────── */ .brd-pos { color: var(--brd-pos) !important; } .brd-neg { color: var(--brd-neg) !important; } .brd-warn { color: var(--brd-warn) !important; } /* ── 대시보드 래퍼 ── */ .brd-dashboard { display: flex; flex-direction: column; gap: 12px; padding: 14px 16px 20px; background: var(--bg1); min-height: 100%; } /* ── 대시보드 헤더 ── */ .brd-dash-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; background: linear-gradient(135deg, rgba(61,159,255,.10) 0%, rgba(168,85,247,.06) 100%); border: 1px solid rgba(61,159,255,.2); border-radius: 12px; padding: 14px 18px; } .brd-dash-header-left { display: flex; flex-direction: column; gap: 6px; } .brd-dash-strategy { font-size: 16px; font-weight: 800; color: var(--text); letter-spacing: -.3px; } .brd-dash-meta { display: flex; flex-wrap: wrap; gap: 5px; } .brd-dash-badge { display: inline-flex; align-items: center; padding: 2px 9px; border-radius: 10px; font-size: 11px; font-weight: 500; background: rgba(61,159,255,.12); color: var(--brd-blue); border: 1px solid rgba(61,159,255,.25); } .brd-dash-badge--time { background: rgba(128,128,128,.1); color: var(--text3); border-color: var(--border); } .brd-dash-header-kpi { display: flex; gap: 28px; } .brd-dash-big-kpi { text-align: right; } .brd-dash-big-val { font-size: 26px; font-weight: 900; letter-spacing: -1px; line-height: 1; } .brd-dash-big-label { font-size: 10.5px; color: var(--text3); margin-top: 3px; } /* ── 행(Row) ── */ .brd-row { display: flex; flex-direction: column; gap: 10px; } .brd-row--3col { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; } .brd-row--2col { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } @media (max-width: 820px) { .brd-row--3col { grid-template-columns: 1fr 1fr; } .brd-row--2col { grid-template-columns: 1fr; } } @media (max-width: 560px) { .brd-row--3col { grid-template-columns: 1fr; } } /* ── KPI 그리드 (6개) ── */ .brd-kpi-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; } @media (max-width: 900px) { .brd-kpi-grid { grid-template-columns: repeat(3, 1fr); } } @media (max-width: 560px) { .brd-kpi-grid { grid-template-columns: repeat(2, 1fr); } } .brd-kpi-card { position: relative; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; overflow: hidden; transition: transform .15s, box-shadow .15s; } .brd-kpi-card:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0,0,0,.25); } .brd-kpi-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px; border-radius: 10px 10px 0 0; } .brd-kpi-card--blue::before { background: var(--brd-blue); } .brd-kpi-card--red::before { background: var(--brd-neg); } .brd-kpi-card--yellow::before { background: var(--brd-yellow); } .brd-kpi-card--purple::before { background: var(--brd-purple); } .brd-kpi-card--green::before { background: var(--brd-green); } .brd-kpi-card--teal::before { background: var(--brd-teal); } .brd-kpi-top { display: flex; align-items: center; gap: 5px; margin-bottom: 5px; } .brd-kpi-icon { font-size: 14px; } .brd-kpi-label { font-size: 10px; color: var(--text3); font-weight: 500; } .brd-kpi-value { font-size: 18px; font-weight: 800; color: var(--text); line-height: 1; margin-bottom: 3px; } .brd-kpi-sub { font-size: 9.5px; color: var(--text3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ── 카드 공통 ── */ .brd-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; } .brd-card--full { width: 100%; } .brd-section-title { display: flex; align-items: center; gap: 6px; padding: 8px 12px 7px; background: var(--bg3); border-bottom: 1px solid var(--border); font-size: 11.5px; font-weight: 700; color: var(--text2); } .brd-section-icon { font-size: 13px; } .brd-section-text { flex: 1; } .brd-section-right { margin-left: auto; } .brd-section-count { font-size: 10.5px; font-weight: 400; color: var(--text3); background: var(--bg4); padding: 1px 8px; border-radius: 8px; } .brd-badge-inline { font-size: 10.5px; font-weight: 600; background: var(--bg4); padding: 1px 8px; border-radius: 8px; } .brd-card-body { padding: 8px 12px 10px; } .brd-card-body--center { display: flex; align-items: flex-start; gap: 12px; padding: 10px 12px; } /* ── MetricRow ── */ .brd-metric-row { display: flex; align-items: center; justify-content: space-between; padding: 4.5px 0; border-bottom: 1px solid rgba(128,128,128,.06); } .brd-metric-row:last-child { border-bottom: none; } .brd-metric-label { font-size: 11.5px; color: var(--text3); display: flex; flex-direction: column; gap: 1px; } .brd-metric-note { font-size: 9px; color: var(--text3); opacity: .7; } .brd-metric-value { font-size: 12px; font-weight: 600; color: var(--text); } /* ── 승률 도넛 ── */ .brd-donut-wrap { display: flex; flex-direction: column; align-items: center; gap: 5px; flex-shrink: 0; } .brd-donut-detail { display: flex; gap: 8px; font-size: 10.5px; font-weight: 600; } .brd-trade-stats { flex: 1; } /* ── 벤치마크 비교 바 ── */ .brd-compare { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; } .brd-compare-row { display: flex; align-items: center; gap: 8px; } .brd-compare-label{ font-size: 11px; color: var(--text3); width: 70px; flex-shrink: 0; } .brd-compare-track{ flex: 1; height: 8px; background: var(--bg3); border-radius: 4px; overflow: hidden; } .brd-compare-bar { height: 100%; border-radius: 4px; transition: width .5s ease; } .brd-compare-val { font-size: 12px; font-weight: 700; width: 60px; text-align: right; flex-shrink: 0; } .brd-bench-summary{ display: flex; align-items: center; gap: 0; background: var(--bg3); border-radius: 8px; overflow: hidden; margin-top: 6px; } .brd-bench-item { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 8px 6px; gap: 2px; } .brd-bench-label { font-size: 9.5px; color: var(--text3); } .brd-bench-val { font-size: 14px; font-weight: 800; } .brd-bench-divider{ width: 1px; background: var(--border); align-self: stretch; } /* ── 손익 분석 바 ── */ .brd-pnl-bar-section { margin-bottom: 8px; display: flex; flex-direction: column; gap: 7px; } .brd-pnl-row { display: flex; align-items: center; gap: 8px; } .brd-pnl-label{ font-size: 11px; font-weight: 600; width: 44px; flex-shrink: 0; } .brd-pnl-track{ flex: 1; height: 10px; background: var(--bg3); border-radius: 5px; overflow: hidden; } .brd-pnl-bar { height: 100%; border-radius: 5px; transition: width .5s; } .brd-pnl-bar--pos { background: var(--brd-pos); } .brd-pnl-bar--neg { background: var(--brd-neg); } .brd-pnl-val { font-size: 11.5px; font-weight: 700; width: 64px; text-align: right; flex-shrink: 0; } .brd-pnl-net { display: flex; justify-content: space-between; align-items: center; padding: 6px 10px; background: var(--bg3); border-radius: 6px; margin-bottom: 8px; } .brd-pnl-net-label{ font-size: 11.5px; color: var(--text3); } .brd-pnl-net-val { font-size: 15px; font-weight: 800; } /* ── 시그널 테이블 ── */ .brd-sig-scroll { max-height: 200px; overflow-y: auto; } .brd-sig-table { width: 100%; border-collapse: collapse; font-size: 11.5px; } .brd-sig-table th { position: sticky; top: 0; padding: 6px 10px; background: var(--bg3); color: var(--text3); font-size: 10.5px; font-weight: 600; text-align: left; border-bottom: 1px solid var(--border); white-space: nowrap; } .brd-sig-table td { padding: 4.5px 10px; color: var(--text); border-bottom: 1px solid rgba(128,128,128,.06); } .brd-sig-table tr:last-child td { border-bottom: none; } .brd-sig-even td { background: rgba(128,128,128,.025); } .brd-sig-table tr:hover td { background: rgba(61,159,255,.04); } .brd-sig-badge { display: inline-flex; align-items: center; padding: 1px 8px; border-radius: 8px; font-size: 10px; font-weight: 600; } .brd-sig-badge.brd-pos { background: rgba(38,201,126,.12); } .brd-sig-badge.brd-neg { background: rgba(240,78,94,.12); } .brd-sig-badge.brd-warn{ background: rgba(255,159,67,.12); } .brd-expand-btn { display: block; width: 100%; padding: 7px; background: var(--bg3); border: none; border-top: 1px solid var(--border); color: var(--text3); font-size: 11.5px; cursor: pointer; transition: background .15s, color .15s; } .brd-expand-btn:hover { background: var(--bg4); color: var(--text); } .brd-empty-msg { text-align: center; color: var(--text3); padding: 24px; font-size: 12px; } .brd-empty-state { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 200px; color: var(--text3); font-size: 13px; } .brd-empty-state div { font-size: 40px; } /* ── 결과보기 버튼 강조 ── */ .bt-settings-btn--has-result { color: #3d9fff !important; border-color: #3d9fff !important; background: rgba(61,159,255,.1) !important; } /* ── 매수/매도 마커 삭제 버튼 ── */ .bt-settings-btn--clear { color: #ef9a9a; border-color: rgba(239,83,80,.4); } .bt-settings-btn--clear:hover { color: #ef5350 !important; border-color: #ef5350 !important; background: rgba(239,83,80,.12) !important; } /* ── 실시간 전략 체크 토글 버튼 활성 ── */ .bt-settings-btn--live-on { color: #00BCD4 !important; border-color: #00BCD4 !important; background: rgba(0,188,212,.12) !important; } /* ═══════════════════════════════════════════════════════════════════════════ BacktestHistoryPage (.bh-*) ─────────────────────────────────────────────────────────────────────────── */ .bh-page { display: flex; height: calc(100vh - var(--tmb-h, 44px)); overflow: hidden; background: var(--bg1); } /* ── 좌측 사이드바 ── */ .bh-sidebar { width: 272px; min-width: 220px; border-right: 1px solid var(--border); display: flex; flex-direction: column; overflow: hidden; background: var(--bg2); flex-shrink: 0; } .bh-sidebar-header { padding: 10px 12px 8px; background: var(--bg3); border-bottom: 1px solid var(--border); flex-shrink: 0; } .bh-sidebar-title-row { display: flex; align-items: center; gap: 6px; margin-bottom: 7px; } .bh-sidebar-title { font-size: 13px; font-weight: 700; color: var(--text); } .bh-sidebar-count { font-size: 10.5px; font-weight: 600; background: rgba(61,159,255,.15); color: var(--brd-blue); padding: 1px 7px; border-radius: 8px; } .bh-sidebar-actions { display: flex; gap: 5px; } .bh-act-btn { position: relative; display: flex; align-items: center; justify-content: center; gap: 4px; padding: 5px 9px; background: var(--bg4); border: 1px solid var(--border); border-radius: 6px; color: var(--text2); font-size: 11.5px; cursor: pointer; transition: all .15s; } .bh-act-btn:hover:not(:disabled) { background: var(--bg1); color: var(--text); } .bh-act-btn:disabled { opacity: .35; cursor: not-allowed; } .bh-act-btn--danger:hover:not(:disabled) { background: rgba(240,78,94,.12); color: var(--brd-neg); border-color: var(--brd-neg); } .bh-act-badge { position: absolute; top: -4px; right: -4px; background: var(--brd-neg); color: #fff; font-size: 9px; font-weight: 700; min-width: 15px; height: 15px; border-radius: 8px; display: flex; align-items: center; justify-content: center; padding: 0 3px; } /* ── 전체 선택 바 ── */ .bh-select-all-bar { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: var(--bg3); border-bottom: 1px solid var(--border); cursor: pointer; font-size: 11.5px; color: var(--text3); transition: background .12s; flex-shrink: 0; } .bh-select-all-bar:hover { background: var(--bg4); color: var(--text); } .bh-select-all-label { font-size: 11px; } /* ── 체크박스 ── */ .bh-cb { width: 14px; height: 14px; flex-shrink: 0; border: 1.5px solid var(--border); border-radius: 3px; background: var(--bg2); display: flex; align-items: center; justify-content: center; transition: all .12s; } .bh-cb--on { background: var(--brd-blue); border-color: var(--brd-blue); color: #fff; } .bh-cb--indeterminate { background: var(--brd-blue); border-color: var(--brd-blue); } .bh-cb-dash { width: 8px; height: 2px; background: #fff; border-radius: 1px; } /* ── 목록 ── */ .bh-list { flex: 1; overflow-y: auto; } /* ── 아이템 ── */ .bh-item { display: flex; align-items: flex-start; gap: 8px; padding: 9px 12px; border-bottom: 1px solid var(--border); cursor: pointer; transition: background .12s; } .bh-item:hover { background: var(--bg3); } .bh-item--active { background: rgba(61,159,255,.08) !important; border-left: 3px solid var(--brd-blue); padding-left: 9px; } .bh-item--checked { background: rgba(61,159,255,.05); } .bh-item-cb-wrap { padding-top: 2px; flex-shrink: 0; } .bh-item-body { flex: 1; min-width: 0; } .bh-item-row1 { display: flex; align-items: center; justify-content: space-between; gap: 6px; margin-bottom: 3px; } .bh-item-name { font-size: 12.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; } .bh-item-ret { font-size: 13px; font-weight: 800; flex-shrink: 0; } .bh-item-row2 { display: flex; align-items: center; gap: 3px; font-size: 10.5px; color: var(--text3); margin-bottom: 2px; } .bh-item-sep { opacity: .4; } .bh-item-row3 { display: flex; align-items: center; gap: 6px; font-size: 10px; color: var(--text3); } .bh-item-wr { margin-left: auto; font-size: 9.5px; font-weight: 600; background: rgba(61,159,255,.1); color: var(--brd-blue); padding: 1px 6px; border-radius: 6px; } .bh-pos { color: var(--brd-pos); } .bh-neg { color: var(--brd-neg); } /* ── 로딩 ── */ .bh-loading, .bh-empty-list { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--text3); font-size: 13px; gap: 8px; padding: 24px; text-align: center; } .bh-loading-spinner { width: 24px; height: 24px; border: 2px solid var(--border); border-top-color: var(--brd-blue); border-radius: 50%; animation: bh-spin .7s linear infinite; } @keyframes bh-spin { to { transform: rotate(360deg); } } .bh-empty-icon { font-size: 40px; opacity: .5; } .bh-empty-sub { font-size: 11.5px; opacity: .7; line-height: 1.6; } /* ── 우측 ── */ .bh-content { flex: 1; overflow: hidden; display: flex; flex-direction: column; } .bh-detail { flex: 1; overflow-y: auto; } .bh-no-selection { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--text3); gap: 12px; } .bh-no-sel-icon { font-size: 56px; opacity: .3; } /* ══════════════════════════════════════════════════════════════════ SETTINGS PAGE — 카드 2분할 레이아웃 ══════════════════════════════════════════════════════════════════ */ /* ── 페이지 배경 ── */ .stg-page { display: flex; height: calc(100vh - var(--tmb-h, 44px)); overflow: hidden; background: var(--bg); /* 바깥 배경 */ color: var(--text); padding: 20px; gap: 16px; box-sizing: border-box; } /* ════════ 좌측 카드 — 카테고리 목록 ════════ */ .stg-sidebar { width: 210px; min-width: 180px; flex-shrink: 0; /* 카드 박스 */ background: var(--bg2); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 2px 12px rgba(0,0,0,0.18); display: flex; flex-direction: column; overflow: hidden; } .stg-sidebar-title { font-size: 16px; font-weight: 700; color: var(--text); padding: 20px 18px 14px; border-bottom: 1px solid var(--border); letter-spacing: -0.3px; flex-shrink: 0; } .stg-sidebar-nav { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; padding: 10px 8px 10px; } .stg-sidebar-item { display: flex; align-items: center; gap: 10px; padding: 11px 12px; border-radius: 9px; border: none; background: transparent; color: var(--text2); cursor: pointer; text-align: left; transition: background 0.14s, color 0.14s; font-size: 13.5px; width: 100%; } .stg-sidebar-item:hover { background: var(--bg3); color: var(--text); } .stg-sidebar-item--active { background: rgba(var(--accent-rgb, 122, 162, 247), 0.15); color: var(--accent); font-weight: 600; } .app.light .stg-sidebar-item--active { background: rgba(25, 118, 210, 0.09); color: #1565C0; } .stg-sidebar-icon { display: flex; align-items: center; opacity: 0.75; flex-shrink: 0; } .stg-sidebar-item--active .stg-sidebar-icon { opacity: 1; } .stg-sidebar-item--active .stg-sidebar-label { letter-spacing: -0.1px; } /* ════════ 우측 카드 — 상세 설정 ════════ */ .stg-content { flex: 1; min-width: 0; /* 카드 박스 */ background: var(--bg2); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 2px 12px rgba(0,0,0,0.18); display: flex; flex-direction: column; overflow: hidden; } /* 카드 헤더 */ .stg-content-header { display: flex; align-items: center; gap: 14px; padding: 20px 24px 16px; border-bottom: 1px solid var(--border); background: var(--bg2); flex-shrink: 0; } .stg-content-icon { display: flex; align-items: center; justify-content: center; width: 42px; height: 42px; border-radius: 10px; background: rgba(var(--accent-rgb, 122, 162, 247), 0.13); color: var(--accent); flex-shrink: 0; } .stg-content-title { font-size: 17px; font-weight: 700; color: var(--text); margin: 0 0 2px; letter-spacing: -0.3px; } .stg-content-desc { font-size: 12px; color: var(--text3); margin: 0; } /* 스크롤 바디 */ .stg-content-body { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 18px 24px 24px; display: flex; flex-direction: column; gap: 16px; background: var(--bg); /* 섹션들이 놓이는 배경 */ } /* ── 섹션 (설정 그룹) ── */ .stg-section { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; overflow: visible; } .stg-section-title { font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.9px; color: var(--text3); padding: 9px 16px 7px; border-bottom: 1px solid var(--border); background: var(--bg3); } .stg-section-body { display: flex; flex-direction: column; } .stg-section-body--grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; padding: 12px 14px 14px; } @media (max-width: 720px) { .stg-section-body--grid { grid-template-columns: 1fr; } } .stg-section-hint { display: flex; align-items: center; gap: 8px; margin: 0 14px 12px; padding: 9px 12px; border-radius: 6px; font-size: 11.5px; color: var(--text2); line-height: 1.45; } /* ── 설정 행 ── */ .stg-row { display: flex; align-items: flex-start; justify-content: space-between; padding: 14px 16px; gap: 16px; min-height: 52px; border-bottom: 1px solid var(--border); transition: background 0.1s; } .stg-row:last-child { border-bottom: none; } .stg-row:hover { background: var(--bg3); } .stg-row--block { flex-direction: column; align-items: stretch; gap: 10px; } .stg-row--block .stg-row-ctrl { width: 100%; justify-content: flex-start; align-self: stretch; } .stg-row-label { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; } .stg-row-title { font-size: 13px; color: var(--text); font-weight: 500; } .stg-row-desc { font-size: 11px; color: var(--text3); line-height: 1.45; white-space: normal; overflow: visible; } .stg-row-ctrl { display: flex; align-items: center; gap: 8px; flex-shrink: 0; padding-top: 2px; } .stg-row--block .stg-row-ctrl { padding-top: 0; } /* 가로 배치 라디오 옵션 (전략 설정 등) */ .stg-radio-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; width: 100%; } @media (max-width: 640px) { .stg-radio-row { grid-template-columns: 1fr; } } .stg-radio-row--disabled { opacity: 0.45; pointer-events: none; } .stg-radio-option { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg3); cursor: pointer; transition: border-color 0.15s, background 0.15s; } .stg-radio-option:hover { border-color: color-mix(in srgb, var(--accent) 35%, var(--border)); } .stg-radio-option:has(input:checked) { border-color: color-mix(in srgb, var(--accent) 60%, var(--border)); background: color-mix(in srgb, var(--bg3) 75%, var(--accent) 25%); } .stg-radio-option input { margin-top: 3px; flex-shrink: 0; accent-color: var(--accent); } .stg-radio-option--cyan input { accent-color: #00bcd4; } .stg-radio-option--cyan:has(input:checked) { border-color: rgba(0, 188, 212, 0.5); background: rgba(0, 188, 212, 0.08); } .stg-radio-option--blue input { accent-color: #3f7ef5; } .stg-radio-option--blue:has(input:checked) { border-color: rgba(63, 126, 245, 0.5); background: rgba(63, 126, 245, 0.08); } .stg-radio-option--orange input { accent-color: #ff9800; } .stg-radio-option--orange:has(input:checked) { border-color: rgba(255, 152, 0, 0.5); background: rgba(255, 152, 0, 0.08); } .stg-radio-option-text { display: flex; flex-direction: column; gap: 4px; min-width: 0; } .stg-radio-option-text strong { font-size: 12.5px; font-weight: 600; color: var(--text); line-height: 1.35; } .stg-radio-option-text span { font-size: 11px; color: var(--text3); line-height: 1.45; } /* ── 컨트롤: select ── */ .stg-select { background: var(--bg3); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-size: 12.5px; padding: 5px 24px 5px 9px; cursor: pointer; min-width: 130px; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' stroke='%23888' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 7px center; transition: border-color 0.15s; } .stg-select:focus { outline: none; border-color: var(--accent); } /* ── 컨트롤: input ── */ .stg-input { background: var(--bg3); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-size: 12.5px; padding: 5px 9px; width: 96px; transition: border-color 0.15s; } .stg-input--wide { width: 100%; max-width: 220px; min-width: 120px; } .stg-input:focus { outline: none; border-color: var(--accent); } .stg-input--sensitive { font-family: ui-monospace, 'SF Mono', Menlo, monospace; letter-spacing: 0.02em; } .stg-select--wide { width: 100%; max-width: 220px; min-width: 140px; } /* ════════ 백테스팅 설정 패널 (2열 카드) ════════ */ .stg-bt-panel { display: flex; flex-direction: column; gap: 14px; } .stg-bt-status { font-size: 11.5px; color: var(--text3); padding: 4px 2px; } .stg-bt-status--ok { color: #4caf50; } .stg-bt-section { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; overflow: visible; } .stg-bt-section-title { margin: 0; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.9px; color: var(--text3); padding: 10px 16px 8px; border-bottom: 1px solid var(--border); background: var(--bg3); } .stg-bt-section-body { padding: 12px 14px 14px; } .stg-bt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: stretch; } @media (max-width: 720px) { .stg-bt-grid { grid-template-columns: 1fr; } } .stg-bt-field, .stg-card { display: flex; flex-direction: column; gap: 10px; min-height: 88px; padding: 12px 14px; background: var(--bg3); border: 1px solid var(--border); border-radius: 8px; transition: border-color 0.15s, background 0.15s; } .stg-bt-field:hover, .stg-card:hover { border-color: color-mix(in srgb, var(--accent) 35%, var(--border)); background: color-mix(in srgb, var(--bg3) 85%, var(--accent) 15%); } .stg-bt-field--full { grid-column: 1 / -1; min-height: auto; } .stg-bt-field--placeholder { visibility: hidden; pointer-events: none; min-height: 0; padding: 0; border: none; background: transparent; } .stg-bt-field-head { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; } .stg-bt-field-label { font-size: 13px; font-weight: 600; color: var(--text); line-height: 1.35; } .stg-bt-field-desc { font-size: 11px; color: var(--text3); line-height: 1.5; white-space: normal; word-break: keep-all; overflow-wrap: break-word; } .stg-bt-field-ctrl { display: flex; align-items: center; justify-content: flex-start; flex-shrink: 0; margin-top: auto; } .stg-bt-radio-group { display: flex; flex-direction: column; gap: 10px; width: 100%; } .stg-bt-radio { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; padding: 10px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg3); transition: border-color 0.15s, background 0.15s; } .stg-bt-radio:hover { background: var(--bg3); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); } .stg-bt-radio input { margin-top: 3px; flex-shrink: 0; accent-color: var(--accent); } .stg-bt-radio-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; } .stg-bt-radio-text strong { font-size: 12.5px; font-weight: 600; color: var(--text); } .stg-bt-radio-text span { font-size: 11px; color: var(--text3); line-height: 1.45; } .stg-bt-hint { margin-top: 10px; padding: 9px 12px; border-radius: 6px; font-size: 11.5px; color: var(--text2); line-height: 1.45; } .stg-bt-hint--warn { background: rgba(255, 152, 0, 0.1); border: 1px solid rgba(255, 152, 0, 0.35); } .app.light .stg-bt-field, .app.light .stg-card { background: #f5f5f7; } .app.light .stg-bt-radio { background: #fff; } /* 공통 2열 카드 (전략 설정 등) */ .stg-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: stretch; } @media (max-width: 720px) { .stg-grid { grid-template-columns: 1fr; } } .stg-card--full { grid-column: 1 / -1; min-height: auto; } .stg-card-head { display: flex; flex-direction: column; gap: 5px; flex: 1; min-width: 0; } .stg-card-label { font-size: 13px; font-weight: 600; color: var(--text); line-height: 1.35; } .stg-card-desc { font-size: 11px; color: var(--text3); line-height: 1.5; white-space: normal; word-break: keep-all; overflow-wrap: break-word; } .stg-card-ctrl { display: flex; align-items: center; justify-content: flex-start; flex-shrink: 0; margin-top: auto; } /* ── 컨트롤: color picker ── */ .stg-color-row { display: flex; align-items: center; gap: 8px; } .stg-color { width: 32px; height: 26px; border: 1px solid var(--border); border-radius: 6px; padding: 2px; background: var(--bg3); cursor: pointer; } .stg-color-label { font-size: 12px; font-family: monospace; color: var(--text2); min-width: 60px; } /* ── 컨트롤: 토글 스위치 ── */ .stg-toggle { position: relative; display: inline-block; width: 40px; height: 22px; flex-shrink: 0; } .stg-toggle input { opacity: 0; width: 0; height: 0; position: absolute; } .stg-toggle-slider { position: absolute; inset: 0; background: var(--bg4); border-radius: 11px; cursor: pointer; transition: background 0.2s; border: 1px solid var(--border); } .stg-toggle-slider::before { content: ''; position: absolute; width: 16px; height: 16px; left: 2px; top: 2px; background: var(--text3); border-radius: 50%; transition: transform 0.2s, background 0.2s; } .stg-toggle input:checked + .stg-toggle-slider { background: var(--accent); border-color: var(--accent); } .stg-toggle input:checked + .stg-toggle-slider::before { transform: translateX(18px); background: #fff; } /* ── 뱃지 (연결 상태) ── */ .stg-badge { font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 20px; } .stg-badge--ok { background: rgba(76,175,80,0.15); color: #4CAF50; } .stg-badge--err { background: rgba(239,83,80,0.15); color: #EF5350; } .stg-badge--on { background: rgba(76,175,80,0.15); color: #4CAF50; margin-left: 8px; } .stg-badge--off { background: rgba(158,158,158,0.2); color: var(--text2); margin-left: 8px; } .stg-hint { margin: 0 0 8px; padding: 0 4px; font-size: 12px; color: var(--text2); line-height: 1.5; } /* ── 연결 테스트 버튼 ── */ .stg-btn-test { padding: 5px 12px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text); font-size: 12px; cursor: pointer; transition: border-color 0.15s; } .stg-btn-test:hover { border-color: var(--accent); color: var(--accent); } /* ── 하단 푸터 (저장/초기화) ── */ .stg-footer { display: flex; justify-content: flex-end; align-items: center; gap: 10px; padding: 13px 24px; border-top: 1px solid var(--border); background: var(--bg2); flex-shrink: 0; } .stg-btn-reset { padding: 7px 16px; border-radius: 7px; border: 1px solid var(--border); background: transparent; color: var(--text2); font-size: 13px; cursor: pointer; transition: background 0.15s; } .stg-btn-reset:hover { background: var(--bg3); } .stg-btn-save { padding: 7px 22px; border-radius: 7px; border: none; background: var(--accent); color: #fff; font-size: 13px; font-weight: 600; cursor: pointer; transition: opacity 0.15s; } .stg-btn-save:hover { opacity: 0.88; } /* ── 라이트 테마 ── */ .app.light .stg-page { background: #f0f2f5; } .app.light .stg-sidebar, .app.light .stg-content { box-shadow: 0 2px 10px rgba(0,0,0,0.08); } .app.light .stg-content-body { background: #f5f5f7; } /* ── 설정: 보조지표 Main 탭 기본값 ───────────────────────────────────── */ .stg-ind-intro { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 12px 14px; background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; font-size: 12px; color: var(--text2); line-height: 1.5; } .stg-ind-intro p { margin: 0; flex: 1; min-width: 200px; } .stg-ind-reset-all { font-size: 12px; padding: 6px 12px; border: 1px solid var(--sep); border-radius: 6px; background: var(--bg3); color: var(--text); cursor: pointer; flex-shrink: 0; } .stg-ind-reset-all:hover { border-color: var(--accent); color: var(--accent); } .stg-ind-list { display: flex; flex-direction: column; gap: 8px; } .stg-ind-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; overflow: hidden; } .stg-ind-card--expanded { border-color: rgba(122, 162, 247, 0.35); } .stg-ind-card--on-chart { border-color: rgba(122, 162, 247, 0.35); } .stg-ind-card-badges { display: flex; align-items: center; gap: 6px; flex-shrink: 0; margin-right: 8px; } .stg-ind-badge { font-size: 10px; padding: 2px 8px; border-radius: 3px; color: var(--text-muted, #888); background: rgba(255, 255, 255, 0.06); } .stg-ind-badge--on { background: rgba(122, 162, 247, 0.2); color: var(--accent, #7aa2f7); } .stg-ind-toggle { flex-shrink: 0; margin-right: 8px; } .stg-ind-card-head { display: flex; align-items: center; gap: 10px; padding: 10px 14px; min-height: 44px; } .stg-ind-card-titles { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; } .stg-ind-card-name { font-size: 13px; font-weight: 700; color: var(--text); } .stg-ind-card-sub { font-size: 11px; color: var(--text3); } .stg-ind-card-defaults { font-size: 11px; padding: 4px 10px; border: 1px solid var(--sep); border-radius: 4px; background: var(--bg3); color: var(--text2); cursor: pointer; } .stg-ind-card-defaults:hover { color: var(--text); border-color: var(--accent); } .stg-ind-card-expand { background: none; border: none; color: var(--text2); cursor: pointer; font-size: 10px; padding: 4px 8px; } .stg-ind-card-body { border-top: 1px solid var(--border); padding: 8px 12px 14px; background: var(--bg3); } .stg-ind-card-body .ibsm-embedded-form { padding: 0; } .stg-ind-unavailable { color: var(--text3); font-size: 13px; padding: 16px; } .stg-footer--hint { justify-content: flex-end; } .stg-footer-hint { font-size: 12px; color: var(--text3); } .app.light .stg-sidebar-item--active { color: #1565C0; } .app.light .stg-btn-save { color: #fff; } /* ══════════════════════════════════════════════════════════════════ RIGHT SIDE PANEL (매매 탭 + 호가 탭) ══════════════════════════════════════════════════════════════════ */ /* ── 래퍼: flex 자식, 핸들(좌) + 패널(우) 가로 배치 ── */ .rsp-wrap { display: flex; flex-direction: row; align-items: stretch; align-self: stretch; flex-shrink: 0; min-height: 0; position: relative; z-index: 15; } /* ── 접기/펼치기 핸들 ── */ .rsp-handle { align-self: center; flex-shrink: 0; position: relative; z-index: 20; width: 16px; height: 56px; margin-right: -1px; /* 패널 왼쪽 테두리와 겹치도록 */ background: var(--bg2); border: 1px solid var(--border); border-right: none; border-radius: 8px 0 0 8px; color: var(--text3); cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 0.15s, color 0.15s, box-shadow 0.15s; box-shadow: -2px 0 10px rgba(0, 0, 0, 0.30); padding: 0; } .rsp-handle:hover { background: var(--bg3); color: var(--text); box-shadow: -3px 0 14px rgba(0, 0, 0, 0.45); } .rsp-wrap--open .rsp-handle { border-color: rgba(122, 162, 247, 0.35); } /* ── 패널 본체 (슬라이드 애니메이션) ── */ .rsp-panel { width: 0; overflow: hidden; display: flex; flex-direction: column; height: 100%; min-height: 0; background: var(--bg2); border-left: 1px solid var(--border); transition: width 0.22s cubic-bezier(0.4, 0, 0.2, 1); } .rsp-wrap--open .rsp-panel { width: 420px; } /* ── 탭 헤더 ── */ .rsp-tabs { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; background: var(--bg3); min-width: 420px; } .rsp-tab { flex: 1; padding: 10px 0; background: transparent; border: none; border-bottom: 2px solid transparent; color: var(--text3); font-size: 13px; cursor: pointer; transition: color 0.12s, border-color 0.12s; white-space: nowrap; } .rsp-tab:hover { color: var(--text); } .rsp-tab--active { color: var(--accent); border-bottom-color: var(--accent); font-weight: 600; } /* 탭 본문 */ .rsp-body { flex: 1; min-height: 0; min-width: 420px; display: flex; flex-direction: column; overflow: hidden; } /* 매매 탭: 매수·매도 카드 분리 */ .rsp-trade-stack { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; gap: 8px; padding: 8px 10px 6px; } .rsp-trade-stack .rsp-trade-card { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; } .rsp-trade-stack .rsp-trade-card-body { flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column; container-type: size; container-name: trade-card; } .rsp-trade-card { flex-shrink: 0; border-radius: 10px; border: 1px solid var(--border); background: var(--bg3); overflow: hidden; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18); } .rsp-trade-card--buy { border-color: rgba(255, 107, 107, 0.35); background: linear-gradient(180deg, rgba(255, 107, 107, 0.08) 0%, var(--bg3) 48px); } .rsp-trade-card--sell { border-color: rgba(77, 171, 247, 0.35); background: linear-gradient(180deg, rgba(77, 171, 247, 0.08) 0%, var(--bg3) 48px); } .rsp-trade-card-title { padding: 7px 12px 5px; font-size: 13px; font-weight: 700; border-bottom: 1px solid var(--border); } .rsp-trade-card--buy .rsp-trade-card-title { color: var(--up); } .rsp-trade-card--sell .rsp-trade-card-title { color: var(--down); } .rsp-trade-card-body .top-panel { flex: 1 1 auto; min-height: 0; height: 100%; display: flex; flex-direction: column; justify-content: flex-start; gap: 0; background: transparent; padding: 6px 10px 6px; } .rsp-trade-card-body .top-panel-fields { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; justify-content: space-evenly; gap: clamp(4px, 1.2cqi, 10px); overflow-y: auto; overflow-x: hidden; } .rsp-trade-card-body .top-field { margin-bottom: 0; flex-shrink: 0; } .rsp-trade-card-body .top-field:has(.top-order-kind) { margin-bottom: 0; } .rsp-trade-card-body .top-label { margin-bottom: 3px; font-size: 10px; } .rsp-trade-card-body .top-row--balance { margin-top: 0; margin-bottom: 0; flex-shrink: 0; } .rsp-trade-card-body .top-input { padding: 6px 8px; font-size: 12px; } .rsp-trade-card-body .top-kind-btn { padding: 5px 3px; font-size: 10px; } .rsp-trade-card-body .top-pct-row { margin-top: 4px; } .rsp-trade-card-body .top-pct-btn { padding: 4px 2px; font-size: 9px; } .rsp-trade-card-body .top-step { width: 28px; font-size: 14px; } .rsp-trade-card-body .top-meta { margin: 0; flex-shrink: 0; } .rsp-trade-card-body .top-actions { flex-shrink: 0; margin-top: clamp(6px, 1.5cqi, 12px); padding-top: clamp(4px, 1cqi, 8px); border-top: 1px solid color-mix(in srgb, var(--border) 65%, transparent); } .rsp-trade-card-body .top-reset, .rsp-trade-card-body .top-submit { padding: 7px 10px; font-size: 13px; } .rsp-trade-card-body .top-price-qty-block { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; justify-content: space-evenly; gap: clamp(4px, 1cqi, 8px); } /* 가격·수량: 기본 세로 배치 */ .top-price-qty-block { display: flex; flex-direction: column; gap: 0; flex-shrink: 0; } .top-price-qty-block .top-field { margin-bottom: 10px; } .top-price-qty-block .top-pct-row--block { margin-top: 0; margin-bottom: 10px; } .rsp-trade-card-body .top-price-qty-block .top-field { margin-bottom: 0; } .rsp-trade-card-body .top-price-qty-block .top-pct-row--block { margin-top: 4px; margin-bottom: 0; } @container trade-card (max-height: 360px) { .rsp-trade-card-body .top-price-qty-block { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 8px; row-gap: 4px; } .rsp-trade-card-body .top-price-qty-block .top-field--price { grid-column: 1; grid-row: 1; } .rsp-trade-card-body .top-price-qty-block .top-field--qty { grid-column: 2; grid-row: 1; } .rsp-trade-card-body .top-price-qty-block .top-pct-row--block { grid-column: 1 / -1; grid-row: 2; margin-top: 0; } } @media (max-height: 780px) { @supports not (container-type: size) { .rsp-trade-card-body .top-price-qty-block { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 8px; row-gap: 4px; } .rsp-trade-card-body .top-price-qty-block .top-field--price { grid-column: 1; grid-row: 1; } .rsp-trade-card-body .top-price-qty-block .top-field--qty { grid-column: 2; grid-row: 1; } .rsp-trade-card-body .top-price-qty-block .top-pct-row--block { grid-column: 1 / -1; grid-row: 2; margin-top: 0; } } } /* 호가 탭: 카드 박스 + 실시간 호가 */ .rsp-ob-stack { flex: 1; min-height: 0; display: flex; flex-direction: column; padding: 10px 12px 12px; overflow: hidden; } .rsp-ob-card { flex: 1; min-height: 0; display: flex; flex-direction: column; border-color: rgba(122, 162, 247, 0.35); background: linear-gradient(180deg, rgba(122, 162, 247, 0.08) 0%, var(--bg3) 48px); } .rsp-ob-card-title { color: var(--accent); } .rsp-ob-card-body { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; padding: 0; } .rsp-ob-card-body .ob-panel--classic { height: 100%; background: transparent; border-radius: 0 0 9px 9px; } .rsp-ob-card-body .ob-quote-header { background: transparent; border-bottom-color: rgba(255, 255, 255, 0.06); padding-top: 2px; } .rsp-ob-card-body .ob-subtabs { background: transparent; } .rsp-ob-card-body .ob-table--mid, .rsp-ob-card-body .ob-tr-mid .ob-td-price--current { background: transparent; } .rsp-ob-card-body .ob-summary-bar { border-radius: 0 0 9px 9px; } .app.light .rsp-ob-card { border-color: rgba(21, 101, 192, 0.28); background: linear-gradient(180deg, rgba(21, 101, 192, 0.06) 0%, #fff 48px); } .app.light .rsp-ob-card-body .ob-quote-header { border-bottom-color: rgba(0, 0, 0, 0.08); } .app.light .rsp-ob-card-body .ob-panel--classic { background: transparent; } /* ── 매수/매도 주문 폼 (top-) ── */ .top-panel { padding: 8px 12px 10px; font-size: 12px; color: var(--text); } .top-paper-hint { margin: 0 0 8px; padding: 6px 8px; font-size: 11px; line-height: 1.45; color: var(--text2); background: rgba(77, 171, 247, 0.08); border-radius: 4px; border: 1px solid rgba(77, 171, 247, 0.2); } .top-field { margin-bottom: 10px; } .top-label { display: block; font-size: 11px; color: var(--text2); margin-bottom: 5px; } .top-label-help { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; margin-left: 4px; border-radius: 50%; border: 1px solid var(--border); font-size: 9px; color: var(--text3); cursor: help; } .top-order-kind { display: flex; gap: 4px; } .top-kind-btn { flex: 1; padding: 6px 4px; font-size: 11px; border: 1px solid var(--border); border-radius: 4px; background: var(--bg); color: var(--text2); cursor: pointer; white-space: nowrap; } .top-kind-btn--wide { flex: 1.2; } .top-kind-btn--active { border-color: #1976d2; color: #1976d2; background: rgba(25, 118, 210, 0.08); font-weight: 600; } .top-kind-arrow { margin-left: 2px; font-size: 9px; } .top-row--balance { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .top-balance { font-weight: 700; font-size: 13px; } .top-input-group { display: flex; gap: 0; border: 1px solid var(--border); border-radius: 4px; overflow: hidden; background: var(--bg); } .top-input { flex: 1; min-width: 0; border: none; background: transparent; padding: 8px 10px; font-size: 13px; color: var(--text); outline: none; } .top-input--full { width: 100%; border: 1px solid var(--border); border-radius: 4px; box-sizing: border-box; } .top-input--readonly { background: var(--bg3); color: var(--text2); } .top-input:disabled { opacity: 0.55; } .top-step { flex-shrink: 0; width: 32px; border: none; border-left: 1px solid var(--border); background: var(--bg3); color: var(--text2); font-size: 16px; cursor: pointer; padding: 0; } .top-step:hover:not(:disabled) { background: var(--bg2); color: var(--text); } .top-step:disabled { opacity: 0.4; cursor: not-allowed; } .top-pct-row { display: flex; gap: 4px; margin-top: 6px; } .top-pct-btn { flex: 1; padding: 5px 2px; font-size: 10px; border: 1px solid var(--border); border-radius: 3px; background: var(--bg3); color: var(--text2); cursor: pointer; } .top-pct-btn--direct { flex: 1.3; } .top-pct-btn--active { border-color: var(--accent); color: var(--accent); background: rgba(122, 162, 247, 0.12); } .top-meta { display: flex; justify-content: flex-end; font-size: 9px; color: var(--text3); margin: 4px 0 8px; line-height: 1.2; } .top-meta-line { display: flex; flex-wrap: nowrap; align-items: center; justify-content: flex-end; gap: 4px; white-space: nowrap; } .top-meta-sep { opacity: 0.45; user-select: none; } .top-meta-q { display: inline-block; width: 12px; height: 12px; line-height: 12px; text-align: center; border-radius: 50%; border: 1px solid var(--border); font-size: 8px; } .top-actions { display: flex; gap: 8px; } .top-reset { flex: 0 0 auto; display: flex; align-items: center; gap: 4px; padding: 10px 12px; border: none; border-radius: 4px; background: #4a4a4a; color: #fff; font-size: 12px; cursor: pointer; } .top-reset-icon { font-size: 14px; } .top-submit { flex: 1; padding: 10px; border: none; border-radius: 4px; font-size: 14px; font-weight: 700; color: #fff; cursor: pointer; } .top-submit--buy { background: #ef5350; } .top-submit--buy:hover { background: #e53935; } .top-submit--sell { background: #2962ff; } .top-submit--sell:hover { background: #1e53e5; } .app.light .top-kind-btn--active { border-color: #1976d2; color: #1976d2; } .app.light .top-reset { background: #616161; } .top-symbol-field { display: flex; align-items: stretch; gap: 0; border: 1px solid var(--border); border-radius: 4px; overflow: hidden; background: var(--bg); } .top-symbol-field:focus-within { border-color: var(--accent); } .top-symbol-input { flex: 1; min-width: 0; border: none; background: transparent; padding: 8px 10px; font-size: 13px; font-weight: 500; color: var(--text); outline: none; cursor: text; } .top-symbol-input::placeholder { color: var(--text3); font-weight: 400; } .top-symbol-search-btn { flex-shrink: 0; width: 36px; border: none; border-left: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; } .top-symbol-search-btn:hover { background: var(--bg2); color: var(--accent); } .ob-row--clickable { cursor: pointer; } .ob-row--clickable:hover { filter: brightness(1.08); } .chart-ctx-menu { position: fixed; z-index: 10050; min-width: 160px; background: var(--bg2); border: 1px solid var(--border); border-radius: 6px; box-shadow: var(--popup-shadow); padding: 4px 0; overflow: hidden; } .chart-ctx-menu-hint { display: flex; flex-direction: column; gap: 2px; padding: 8px 12px 6px; font-size: 11px; color: var(--text3); border-bottom: 1px solid var(--border); } .chart-ctx-menu-price { font-weight: 600; color: var(--text); } .chart-ctx-menu-item { display: block; width: 100%; padding: 9px 14px; border: none; background: transparent; text-align: left; font-size: 13px; font-weight: 600; cursor: pointer; } .chart-ctx-menu-item:hover { background: var(--bg3); } .chart-ctx-menu-item--buy { color: #ef5350; } .chart-ctx-menu-item--sell { color: #2962ff; } .app.light .chart-ctx-menu { background: #fff; box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); } /* ── 라이트 테마 ── */ .app.light .rsp-handle { background: #fff; border-color: rgba(0,0,0,0.15); box-shadow: -2px 0 8px rgba(0,0,0,0.12); } .app.light .rsp-tab--active { color: #1565C0; border-bottom-color: #1565C0; } /* ════════════════════════════════════════════════════════════════════════════ TradeAlertModal (tam-) — 매매 알림 팝업 (이미지 디자인 기준 재설계) ════════════════════════════════════════════════════════════════════════════ */ /* 오버레이 — 클릭 투과, 모달만 이벤트 수신 */ .tam-overlay { position: fixed; inset: 0; z-index: 9999; pointer-events: none; } .tam-overlay > .tam-modal { pointer-events: auto; } /* 알림 목록 상세 — 화면 중앙 */ .tam-overlay--center { display: flex; align-items: center; justify-content: center; } .tam-overlay--center > .tam-modal--centered { position: relative; left: auto; top: auto; flex-shrink: 0; } /* ── 모달 컨테이너 ── */ .tam-modal { position: fixed; width: 360px; display: flex; flex-direction: column; background: var(--bg2, #24283b); border: 1px solid var(--tam-accent, var(--border, rgba(122,162,247,0.15))); border-radius: 12px; box-shadow: 0 0 0 1px var(--tam-accent-glow, rgba(122,162,247,0.08)), 0 20px 60px rgba(0,0,0,0.65), 0 0 40px var(--tam-accent-glow, rgba(122,162,247,0.06)); overflow: hidden; font-size: 13px; color: var(--text, #c0caf5); font-family: var(--font, 'Noto Sans KR', sans-serif); } /* ── 헤더 ── */ .tam-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; border-bottom: 1px solid var(--border, rgba(122,162,247,0.12)); cursor: grab; user-select: none; flex-shrink: 0; background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3, #1f2335) 100% ); } .tam-header:active { cursor: grabbing; } .tam-header-left { display: flex; align-items: center; gap: 9px; } .tam-badge { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: 11px; font-weight: 800; color: #fff; letter-spacing: 1.2px; } .tam-header-title { font-size: 14px; font-weight: 700; color: var(--text, #c0caf5); letter-spacing: 0.4px; } .tam-header-ko { font-size: 12px; font-weight: 400; color: var(--text2, #9aa5ce); } .tam-close { background: none; border: none; color: var(--text3, #6272a4); font-size: 16px; cursor: pointer; padding: 2px 6px; line-height: 1; border-radius: 4px; transition: color 0.15s, background 0.15s; } .tam-close:hover { color: var(--text, #c0caf5); background: var(--bg4, rgba(255,255,255,0.07)); } /* ── 가격 섹션 ── */ .tam-price-section { padding: 14px 16px 12px; background: linear-gradient( 135deg, var(--tam-accent-glow, rgba(122,162,247,0.08)) 0%, transparent 60% ); border-bottom: 1px solid var(--border, rgba(122,162,247,0.1)); } .tam-price-row { display: flex; align-items: center; gap: 8px; } .tam-market-name { font-size: 15px; font-weight: 700; color: var(--text, #c0caf5); letter-spacing: 0.3px; } .tam-price-arrow { font-size: 18px; font-weight: 800; line-height: 1; } .tam-price-value { font-size: 20px; font-weight: 800; letter-spacing: -0.5px; } .tam-price-time { margin-top: 5px; font-size: 11.5px; color: var(--text3, #6272a4); } /* ── 전략 카드 ── */ .tam-strategy-card { display: flex; align-items: center; gap: 12px; margin: 12px 14px; padding: 11px 14px; background: var(--bg3, #1f2335); border: 1px solid var(--border, rgba(122,162,247,0.12)); border-radius: 9px; } .tam-strategy-icon { flex-shrink: 0; display: flex; align-items: center; } .tam-strategy-info { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; } .tam-strategy-name, .tam-strategy-exec { display: flex; align-items: baseline; gap: 6px; } .tam-strategy-label { font-size: 11px; color: var(--text3, #6272a4); flex-shrink: 0; min-width: 50px; } .tam-strategy-val { font-size: 12.5px; font-weight: 600; color: var(--text, #c0caf5); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .tam-strategy-exec-val { font-size: 12px; color: var(--text2, #9aa5ce); font-weight: 400; } /* ── 주문 섹션 ── */ .tam-order-section { display: flex; flex-direction: column; gap: 10px; padding: 0 14px 14px; } /* 필드 행 */ .tam-field-row { display: flex; align-items: center; gap: 8px; } .tam-field-row--memo { align-items: center; } .tam-field-label { font-size: 11.5px; color: var(--text2, #9aa5ce); flex-shrink: 0; min-width: 42px; } /* 자산비율 버튼 그룹 */ .tam-pct-group { display: flex; gap: 6px; flex: 1; } .tam-pct-btn2 { flex: 1; padding: 6px 4px; border: 1px solid var(--border, rgba(122,162,247,0.18)); border-radius: 6px; background: var(--bg3, #1f2335); color: var(--text2, #9aa5ce); font-size: 12.5px; font-weight: 600; cursor: pointer; transition: border-color 0.15s, color 0.15s, background 0.15s; } .tam-pct-btn2:hover { border-color: var(--tam-accent, var(--accent, #7aa2f7)); color: var(--text, #c0caf5); background: var(--bg4, #414868); } .tam-pct-btn2--active { font-weight: 700; background: var(--bg4, #414868); } /* 지정가 입력 */ .tam-price-input-wrap { flex: 1; min-width: 0; } .tam-price-input { width: 100%; box-sizing: border-box; background: var(--bg3, #1f2335); border: 1px solid var(--border, rgba(122,162,247,0.18)); border-radius: 6px; outline: none; color: var(--text, #c0caf5); font-size: 13px; font-weight: 600; text-align: right; padding: 7px 10px; transition: border-color 0.15s; } .tam-price-input:focus { border-color: var(--tam-accent, var(--accent, #7aa2f7)); } /* 시장가 주문 버튼 */ .tam-market-btn { flex-shrink: 0; padding: 7px 11px; border: 1px solid var(--border, rgba(122,162,247,0.18)); border-radius: 6px; background: var(--bg3, #1f2335); color: var(--text2, #9aa5ce); font-size: 11.5px; font-weight: 600; cursor: pointer; white-space: nowrap; transition: border-color 0.15s, color 0.15s, background 0.15s; } .tam-market-btn:hover { border-color: var(--tam-accent, var(--accent, #7aa2f7)); color: var(--text, #c0caf5); background: var(--bg4, #414868); } /* 메모 입력 */ .tam-memo-input { flex: 1; box-sizing: border-box; background: var(--bg3, #1f2335); border: 1px solid var(--border, rgba(122,162,247,0.18)); border-radius: 6px; outline: none; color: var(--text, #c0caf5); font-size: 12.5px; padding: 7px 10px; transition: border-color 0.15s; } .tam-memo-input::placeholder { color: var(--text3, #6272a4); } .tam-memo-input:focus { border-color: var(--tam-accent, var(--accent, #7aa2f7)); } /* CTA 버튼 */ .tam-cta-btn { width: 100%; padding: 12px; border: none; border-radius: 8px; color: #fff; font-size: 14.5px; font-weight: 800; letter-spacing: 0.5px; cursor: pointer; margin-top: 2px; transition: opacity 0.15s, transform 0.1s; box-shadow: 0 4px 16px var(--tam-accent-glow, rgba(122,162,247,0.25)); } .tam-cta-btn:hover { opacity: 0.9; } .tam-cta-btn:active { transform: scale(0.98); opacity: 0.85; } /* 면책 고지 */ .tam-disclaimer { font-size: 10.5px; color: var(--text3, #6272a4); text-align: center; margin: 0; line-height: 1.5; } /* ── 라이트 테마 오버라이드 ── */ html.theme-light .tam-modal { background: #ffffff; border-color: rgba(25,118,210,0.35); color: #212121; box-shadow: 0 20px 60px rgba(0,0,0,0.18), 0 0 40px rgba(25,118,210,0.08); } html.theme-light .tam-header { background: #f5f7fa; border-color: rgba(0,0,0,0.1); } html.theme-light .tam-header-title { color: #1a237e; } html.theme-light .tam-header-ko { color: #546e7a; } html.theme-light .tam-close { color: #78909c; } html.theme-light .tam-close:hover { background: rgba(0,0,0,0.06); color: #37474f; } html.theme-light .tam-price-section { border-color: rgba(0,0,0,0.08); } html.theme-light .tam-market-name { color: #212121; } html.theme-light .tam-price-time { color: #78909c; } html.theme-light .tam-strategy-card { background: #f5f7fa; border-color: rgba(0,0,0,0.1); } html.theme-light .tam-strategy-label { color: #78909c; } html.theme-light .tam-strategy-val { color: #212121; } html.theme-light .tam-strategy-exec-val { color: #546e7a; } html.theme-light .tam-field-label { color: #546e7a; } html.theme-light .tam-pct-btn2 { background: #f0f3f8; border-color: rgba(0,0,0,0.12); color: #546e7a; } html.theme-light .tam-pct-btn2:hover { background: #e3eaf6; } html.theme-light .tam-price-input, html.theme-light .tam-memo-input { background: #f5f7fa; border-color: rgba(0,0,0,0.14); color: #212121; } html.theme-light .tam-market-btn { background: #f0f3f8; border-color: rgba(0,0,0,0.12); color: #546e7a; } html.theme-light .tam-market-btn:hover { background: #e3eaf6; color: #212121; } html.theme-light .tam-disclaimer { color: #90a4ae; } /* ═══════════════════════════════════════════════════════════════════════════ Trade signal notifications (tsn- / tnl- / tmb-notify-) ═══════════════════════════════════════════════════════════════════════════ */ /* 전역 알림 레이어 (body 포털) — 모든 메뉴 화면 위 */ .app-notification-layer { position: relative; z-index: 20000; pointer-events: none; } .app-notification-layer > * { pointer-events: auto; } .tsn-stack { position: fixed; top: 52px; right: 16px; z-index: 20001; display: flex; flex-direction: column; align-items: flex-end; gap: 0; max-width: min(400px, calc(100vw - 32px)); pointer-events: none; } /* 그리드·가로열 — 넓은 레이아웃 허용 */ .tsn-stack--right.tsn-layout--grid, .tsn-stack--right.tsn-layout--strip { max-width: calc(100vw - 32px); } /* 슬라이드 버튼(‹ ›) — 그리드·가로열·스택 공통 */ .tsn-stack--right.tsn-stack--has-nav { max-width: calc(100vw - 32px); } .tsn-stack--right.tsn-stack--has-nav .tsn-stack-toolbar { width: auto; max-width: calc(100vw - 32px - var(--tsn-nav-reserve, 80px)); margin-right: calc(32px + 6px); } .tsn-stack--left.tsn-stack--has-nav .tsn-stack-toolbar { margin-left: calc(32px + 6px); max-width: calc(100vw - 32px - var(--tsn-nav-reserve, 80px)); } .tsn-stack--right.tsn-stack--has-nav.tsn-layout--grid .tsn-stack-toolbar, .tsn-stack--right.tsn-stack--has-nav.tsn-layout--strip .tsn-stack-toolbar { max-width: min( calc(100vw - 32px - var(--tsn-nav-reserve, 80px)), calc(var(--tsn-grid-cols, 2) * 210px) ); } .tsn-stack--left { right: auto; left: 16px; align-items: flex-start; } .tsn-stack--bottom { top: auto; bottom: 16px; left: 50%; right: auto; transform: translateX(-50%); align-items: center; max-width: calc(100vw - 32px); } .tsn-stack--preview { position: absolute; top: 0; left: 0; right: 0; bottom: 0; transform: none; max-width: none; z-index: 1; } .tsn-stack--preview.tsn-stack--bottom { top: auto; bottom: 8px; left: 50%; transform: translateX(-50%); } .tsn-stack--preview.tsn-stack--left { left: 8px; right: auto; } .tsn-stack--preview.tsn-stack--right { right: 8px; left: auto; } .tsn-layout--stack.tsn-stack--bottom .tsn-cards { flex-direction: column-reverse; } .tsn-stack-toolbar { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; width: 380px; padding-bottom: 8px; flex-shrink: 0; pointer-events: auto; } .tsn-stack--left .tsn-stack-toolbar { align-items: flex-start; } .tsn-stack--bottom .tsn-stack-toolbar { align-items: center; width: auto; max-width: calc(100vw - 32px); } .tsn-toolbar-actions { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; width: 100%; } .tsn-stack--left .tsn-toolbar-actions { justify-content: flex-start; } .tsn-stack--bottom .tsn-toolbar-actions { justify-content: center; } .tsn-dismiss-page { font-size: 11px; padding: 5px 12px; border-radius: 6px; border: 1px solid var(--border, rgba(122,162,247,0.2)); background: var(--bg3, #1a1b26); color: var(--text2, #a9b1d6); cursor: pointer; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); } .tsn-dismiss-page:hover { background: var(--bg4); color: var(--text); border-color: rgba(122, 162, 247, 0.45); } .tsn-pager { display: inline-flex; align-items: center; gap: 6px; } .tsn-pager-btn { width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; font-size: 18px; line-height: 1; padding: 0; } .tsn-pager-btn:hover:not(:disabled) { background: var(--bg4); color: var(--text); } .tsn-pager-btn:disabled { opacity: 0.35; cursor: not-allowed; } .tsn-pager-label { font-size: 11px; color: var(--text2); text-align: center; } .tsn-pager-sub { opacity: 0.7; font-size: 10px; } .tsn-slide-row { display: flex; align-items: stretch; gap: 0; pointer-events: none; max-width: 100%; } .tsn-slide-row--nav { display: flex; flex-direction: row; align-items: center; gap: 6px; width: fit-content; max-width: calc(100vw - 32px); --tsn-nav-reserve: 80px; pointer-events: none; } .tsn-slide-body { flex: 1 1 auto; min-width: 0; max-width: calc(100vw - 32px - var(--tsn-nav-reserve)); pointer-events: none; } .tsn-slide-body .tsn-cards { width: 100% !important; max-width: 100% !important; min-width: 0; overflow-x: hidden; position: relative; z-index: 1; } .tsn-slide-row--nav .tsn-slide-nav { position: static; flex: 0 0 32px; transform: none; } .tsn-slide-nav { flex-shrink: 0; position: relative; z-index: 100100; display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; border-radius: 50%; border: 1px solid var(--border, rgba(122,162,247,0.25)); background: var(--bg2, #1e2030); color: var(--text2, #a9b1d6); cursor: pointer; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35); pointer-events: auto; transition: background 0.15s, color 0.15s, border-color 0.15s; } .tsn-slide-nav:hover:not(:disabled) { background: var(--bg4); color: var(--accent, #7aa2f7); border-color: var(--accent, #7aa2f7); } .tsn-slide-nav:disabled { opacity: 0.28; cursor: not-allowed; box-shadow: none; } .tsn-slide-row .tsn-cards { flex: 1; min-width: 0; } /* 슬라이드 행 안 — 카드 영역 너비 (slide-body 기준) */ .tsn-slide-row--nav .tsn-cards:not(.tsn-cards--grid):not(.tsn-cards--strip):not(.tsn-cards--single) { max-width: min(380px, 100%) !important; } .tsn-slide-row--nav .tsn-cards--grid { max-width: min(100%, calc(var(--tsn-grid-cols, 2) * 210px)) !important; } .tsn-slide-row--nav .tsn-cards--strip { max-width: 100% !important; } .tsn-slide-row--nav .tsn-cards--single { max-width: min(380px, 100%) !important; } .tsn-slide-row--nav .tsn-card { z-index: auto; } .tsn-card--dragging { z-index: 10050 !important; } .tsn-stack--bottom .tsn-slide-row { max-width: calc(100vw - 32px); } .tsn-stack--bottom .tsn-slide-row--nav .tsn-slide-nav { width: 28px; height: 28px; } .tsn-pager-dots { display: flex; justify-content: center; gap: 5px; padding: 4px 0 8px; pointer-events: auto; } .tsn-pager-dot { width: 7px; height: 7px; border-radius: 50%; border: none; padding: 0; background: var(--border); cursor: pointer; } .tsn-pager-dot--active { background: var(--accent, #7aa2f7); transform: scale(1.15); } .tsn-cards--paged { touch-action: pan-y; } .tsn-layout--grid .tsn-stack-toolbar { width: auto; max-width: min(calc(100vw - 32px), calc(var(--tsn-grid-cols, 2) * 210px)); } .tsn-cards { display: flex; flex-direction: column; align-items: stretch; gap: 10px; width: 380px; max-height: calc(100vh - 96px); overflow-y: auto; overflow-x: hidden; pointer-events: auto; padding-bottom: 12px; scrollbar-width: thin; } /* 세로 스택 — 스크롤바 숨김 (페이지 슬라이드로 탐색) */ .tsn-layout--stack .tsn-cards { scrollbar-width: none; -ms-overflow-style: none; } .tsn-layout--stack .tsn-cards::-webkit-scrollbar { display: none; width: 0; height: 0; } .tsn-stack--left .tsn-cards { align-items: stretch; } .tsn-stack--bottom .tsn-cards { max-height: min(50vh, 420px); } .tsn-cards--grid { display: grid; grid-template-columns: repeat(var(--tsn-grid-cols, 2), minmax(0, 1fr)); gap: 8px; width: auto; max-width: min(calc(100vw - 32px), calc(var(--tsn-grid-cols, 2) * 210px)); overflow-y: auto; } .tsn-stack--has-nav .tsn-cards--grid { max-width: min( calc(100vw - 32px - var(--tsn-nav-reserve, 80px)), calc(var(--tsn-grid-cols, 2) * 210px) ); } .tsn-cards--grid .tsn-card { width: auto; min-width: 0; } .tsn-cards--strip { flex-direction: row; align-items: stretch; width: auto; max-width: calc(100vw - 32px); overflow-x: auto; overflow-y: hidden; padding-bottom: 8px; } .tsn-stack--has-nav .tsn-cards--strip { max-width: calc(100vw - 32px - var(--tsn-nav-reserve, 80px)); } .tsn-cards--strip .tsn-card { width: 280px; flex-shrink: 0; } .tsn-cards--single { width: 380px; } .tsn-single-more { font-size: 11px; color: var(--text2, #a9b1d6); padding: 0 4px; } .tsn-cards--preview { max-height: none; overflow: visible; pointer-events: none; } .tsn-cards--preview.tsn-cards--grid { max-width: 100%; } .tsn-cards--preview.tsn-cards--strip { max-width: 100%; } .tsn-cards--preview.tsn-cards--strip .tsn-card { width: 120px; } .tsn-cards--preview.tsn-cards--grid .tsn-card { min-width: 0; } .tsn-cards--preview.tsn-cards--single { width: 160px; } .tsn-cards::-webkit-scrollbar { width: 5px; } .tsn-cards::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; } .tsn-dismiss-all { font-size: 11px; padding: 5px 12px; border-radius: 6px; border: 1px solid var(--border, rgba(122,162,247,0.2)); background: var(--bg3, #1a1b26); color: var(--text2, #a9b1d6); cursor: pointer; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25); } .tsn-dismiss-all:hover { background: var(--bg4); color: var(--text); } @keyframes tsn-slide-in { from { opacity: 0; transform: translateX(28px) scale(0.96); } to { opacity: 1; transform: translateX(0) scale(1); } } @keyframes tsn-slide-in-left { from { opacity: 0; transform: translateX(-28px) scale(0.96); } to { opacity: 1; transform: translateX(0) scale(1); } } @keyframes tsn-slide-in-bottom { from { opacity: 0; transform: translateY(20px) scale(0.96); } to { opacity: 1; transform: translateY(0) scale(1); } } .tsn-stack--left .tsn-card:not(.tsn-card--preview) { animation: tsn-slide-in-left 0.28s cubic-bezier(0.22, 1, 0.36, 1); transform-origin: top left; } .tsn-stack--bottom .tsn-card:not(.tsn-card--preview) { animation: tsn-slide-in-bottom 0.28s cubic-bezier(0.22, 1, 0.36, 1); transform-origin: bottom center; } .tsn-card { position: relative; width: 100%; flex-shrink: 0; border-radius: 10px; border: 1px solid var(--border, rgba(122,162,247,0.25)); background: var(--bg2, #1e2030); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45); overflow: hidden; animation: tsn-slide-in 0.28s cubic-bezier(0.22, 1, 0.36, 1); transform-origin: top right; } .tsn-card--latest { box-shadow: 0 14px 44px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(77, 171, 247, 0.12); } .tsn-card--buy { --tsn-accent: #3f7ef5; } .tsn-card--sell { --tsn-accent: #ef5350; } .tsn-card-header { cursor: grab; user-select: none; touch-action: none; margin: 0; border-radius: 0; } .tsn-card-header:active { cursor: grabbing; } .tsn-card-header .tsn-badge { flex-shrink: 0; } .tsn-card-header .tsn-card-title { flex: 1; min-width: 0; } .tsn-badge { font-size: 10px; font-weight: 700; padding: 2px 6px; border-radius: 3px; letter-spacing: 0.04em; } .tsn-badge--buy { background: rgba(63,126,245,0.2); color: #7aa2f7; } .tsn-badge--sell { background: rgba(239,83,80,0.2); color: #f7768e; } .tsn-card-title { flex: 1; font-size: 13px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .tsn-icon-btn { border: none; background: transparent; color: var(--text3); font-size: 18px; line-height: 1; cursor: pointer; padding: 0 4px; } .tsn-icon-btn:hover { color: var(--text); } /* 매매 시그널 상세 본문 (스낵바·공통) */ .tsd-body { padding: 10px 14px 12px; border-bottom: 1px solid var(--border); } .tsd-body--compact { padding: 10px 14px 8px; } .tsd-headline { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 6px; } .tsd-direction { font-size: 15px; font-weight: 700; } .tsd-direction--buy { color: var(--up, #ff6b6b); } .tsd-direction--sell { color: var(--down, #4dabf7); } .tsd-headline-price { font-size: 18px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; } .tsd-summary { margin: 0 0 10px; font-size: 12px; color: var(--text2); line-height: 1.4; } .tsd-detail-grid { display: grid; grid-template-columns: 72px 1fr; gap: 5px 10px; margin: 0; } .tsd-dt { margin: 0; font-size: 11px; color: var(--text3); font-weight: 500; } .tsd-dd { margin: 0; font-size: 12px; color: var(--text); line-height: 1.35; word-break: break-word; } .tsd-dd--highlight { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; } .tsn-card-actions { display: flex; gap: 6px; padding: 8px 10px 10px; border-top: 1px solid var(--border); } .tsn-action-btn { flex: 1; font-size: 11px; padding: 6px 8px; border-radius: 4px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; } .tsn-action-btn:hover { background: var(--bg4); color: var(--text); } .tsn-action-btn--primary { border-color: var(--tsn-accent, #7aa2f7); color: var(--tsn-accent, #7aa2f7); } .tsn-card--compact .tsn-card-header { padding: 6px 8px; } .tsn-card--compact .tsn-card-title { font-size: 11px; } .tsn-card--compact .tsd-body { padding: 8px 10px 6px; } .tsn-card--compact .tsd-headline-price { font-size: 16px; } .tsn-card--compact .tsd-detail-grid { grid-template-columns: 64px 1fr; gap: 4px 8px; } .tsn-card--compact .tsd-dt { font-size: 10px; } .tsn-card--compact .tsd-dd { font-size: 11px; } .tsn-card-actions--compact { padding: 6px 8px 8px; gap: 4px; } .tsn-card-actions--compact .tsn-action-btn { padding: 4px 6px; font-size: 10px; } .tsn-card--preview { animation: none; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); pointer-events: none; } .tsn-card--preview.tsn-card--compact .tsn-card-title { font-size: 9px; } .tsn-card-header--preview { cursor: default; padding: 4px 6px; } .tsn-preview-body { padding: 4px 8px 6px; font-size: 10px; color: var(--text2); } /* 설정 — 알림 팝업 미리보기 */ .stg-alert-preview { margin-top: 4px; } .stg-alert-preview--off { opacity: 0.45; } .stg-alert-preview-frame { border: 1px solid var(--border); border-radius: 8px; background: var(--bg3); overflow: hidden; } .stg-alert-preview-screen { position: relative; height: 180px; background: linear-gradient(180deg, var(--bg2) 0%, var(--bg) 100%); } .stg-alert-preview-label { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 11px; color: var(--text3, rgba(169,177,214,0.35)); pointer-events: none; user-select: none; } .stg-alert-layout-options { display: flex; flex-wrap: wrap; gap: 8px; } .stg-alert-layout-option { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 8px 12px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; font-size: 12px; min-width: 100px; transition: border-color 0.15s, background 0.15s; } .stg-alert-layout-option:hover { border-color: var(--accent, #7aa2f7); color: var(--text); } .stg-alert-layout-option--active { border-color: var(--accent, #7aa2f7); background: rgba(122, 162, 247, 0.1); color: var(--text); } .stg-alert-layout-option strong { font-size: 12px; font-weight: 600; } .stg-alert-layout-option span { font-size: 10px; opacity: 0.75; line-height: 1.3; } /* 알림 목록 페이지 */ .tnl-page { flex: 1; min-height: 0; display: flex; flex-direction: column; background: var(--bg); color: var(--text); overflow: hidden; } .tnl-header { padding: 20px 24px 12px; border-bottom: 1px solid var(--border); flex-shrink: 0; } .tnl-title { font-size: 20px; font-weight: 700; margin: 0 0 6px; } .tnl-sub { font-size: 13px; color: var(--text3); margin: 0 0 14px; } .tnl-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; } .tnl-chip { font-size: 12px; padding: 4px 10px; border-radius: 12px; background: var(--bg3); } .tnl-chip--warn { background: rgba(239,83,80,0.15); color: #f7768e; } .tnl-filter { display: flex; gap: 4px; } .tnl-filter button, .tnl-btn { font-size: 12px; padding: 6px 12px; border-radius: 4px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; } .tnl-filter-btn--active, .tnl-btn--primary { border-color: #7aa2f7; color: #7aa2f7; background: rgba(122,162,247,0.12); } .tnl-list-wrap { flex: 1; overflow-y: auto; padding: 12px 24px 24px; } .tnl-empty { text-align: center; color: var(--text3); padding: 48px; } .tnl-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; } .tnl-row { display: flex; align-items: stretch; border-radius: 8px; border: 1px solid var(--border); background: var(--bg2); overflow: hidden; } .tnl-row--unread { border-color: rgba(122,162,247,0.45); } .tnl-row-main { flex: 1; display: flex; align-items: center; gap: 12px; padding: 12px 14px; border: none; background: transparent; color: inherit; text-align: left; cursor: pointer; } .tnl-row-main:hover { background: var(--bg3); } .tnl-signal { font-size: 11px; font-weight: 700; padding: 4px 8px; border-radius: 4px; flex-shrink: 0; } .tnl-signal--buy { background: rgba(63,126,245,0.2); color: #7aa2f7; } .tnl-signal--sell { background: rgba(239,83,80,0.2); color: #f7768e; } .tnl-row-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; } .tnl-row-title { font-size: 14px; font-weight: 600; } .tnl-row-price { font-size: 15px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; } .tnl-row-detail-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 14px; margin-top: 4px; } .tnl-row-detail-item { display: flex; flex-direction: column; gap: 2px; min-width: 0; } .tnl-row-detail-lbl { font-size: 10px; color: var(--text3); font-weight: 500; } .tnl-row-detail-val { font-size: 11px; color: var(--text2); line-height: 1.3; word-break: break-word; } .tnl-row-meta { font-size: 12px; color: var(--text3); } .tnl-dot { width: 8px; height: 8px; border-radius: 50%; background: #7aa2f7; flex-shrink: 0; } .tnl-row-chart { padding: 0 16px; border: none; border-left: 1px solid var(--border); background: var(--bg3); color: var(--text2); font-size: 12px; cursor: pointer; } .tnl-row-chart:hover { background: var(--bg4); color: var(--text); } /* TopMenuBar 알림 버튼 */ .tmb-notify-group { display: inline-flex; align-items: center; gap: 4px; } .tmb-notify-btn { position: relative; display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; } .tmb-notify-btn:hover { background: var(--bg4); color: var(--text); } .tmb-notify-dismiss-btn { display: flex; align-items: center; justify-content: center; width: 34px; height: 34px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; } .tmb-notify-dismiss-btn:hover:not(:disabled) { background: rgba(239, 83, 80, 0.12); border-color: rgba(239, 83, 80, 0.45); color: #ef5350; } .tmb-notify-dismiss-btn:disabled { opacity: 0.35; cursor: not-allowed; } .tmb-notify-badge { position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background: #ef5350; color: #fff; font-size: 10px; font-weight: 700; line-height: 16px; text-align: center; } .tmb-notify-layout { position: relative; display: inline-flex; align-items: center; } .tmb-notify-layout-trigger { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; padding: 0; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); cursor: pointer; } .tmb-notify-layout-trigger:hover, .tmb-notify-layout-trigger--open { background: var(--bg4); color: var(--text); border-color: var(--accent, #7aa2f7); } .tmb-notify-layout-menu { position: absolute; top: calc(100% + 6px); right: 0; z-index: 30000; min-width: 220px; max-height: min(70vh, 420px); overflow-y: auto; padding: 6px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg2, #1e2030); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45); } .tmb-notify-layout-option { display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--text2); font-size: 12px; text-align: left; cursor: pointer; } .tmb-notify-layout-option:hover { background: var(--bg3); color: var(--text); } .tmb-notify-layout-option--active { background: rgba(122, 162, 247, 0.12); color: var(--accent, #7aa2f7); } .tmb-notify-layout-option-icon { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 28px; height: 22px; color: inherit; } .tmb-notify-layout-option-label { flex: 1; line-height: 1.35; } .tmb-notify-layout-cols-row { display: flex; align-items: center; gap: 8px; margin-top: 4px; padding: 8px 10px 4px; border-top: 1px solid var(--border); } .tmb-notify-layout-cols-label { font-size: 10px; color: var(--text3, #6b7280); white-space: nowrap; } .tmb-notify-layout-cols-btns { display: flex; gap: 4px; margin-left: auto; } .tmb-notify-layout-col-btn { padding: 3px 8px; border-radius: 4px; border: 1px solid var(--border); background: var(--bg3); color: var(--text2); font-size: 10px; cursor: pointer; } .tmb-notify-layout-col-btn--active, .tmb-notify-layout-col-btn:hover { border-color: var(--accent, #7aa2f7); color: var(--accent, #7aa2f7); background: rgba(122, 162, 247, 0.1); } /* Toolbar 매매 알림 배지 */ .tv-trade-notify-wrap { position: relative; display: inline-flex; } .tv-trade-notify-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 7px; background: #ef5350; color: #fff; font-size: 9px; font-weight: 700; line-height: 14px; text-align: center; pointer-events: none; } /* ═══════════════════════════════════════════════════════════════════════════ 공통 팝업 (gc-popup-*) — 그라데이션 타이틀바 + 드래그 ═══════════════════════════════════════════════════════════════════════════ */ .gc-popup-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.45); z-index: 5000; } .gc-popup-panel { display: flex; flex-direction: column; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5); max-width: 96vw; max-height: 90vh; overflow: hidden; } .gc-popup-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px; flex-shrink: 0; cursor: grab; user-select: none; touch-action: none; border-bottom: 1px solid var(--border); background: linear-gradient( 180deg, rgba(77, 171, 247, 0.12) 0%, rgba(77, 171, 247, 0.04) 28px, var(--bg3) 100% ); } .gc-popup-header:active { cursor: grabbing; } .gc-popup-title { flex: 1; font-size: 14px; font-weight: 700; color: var(--down, #4dabf7); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .gc-popup-close { background: none; border: none; color: var(--text3); cursor: pointer; font-size: 16px; padding: 2px 6px; border-radius: 4px; line-height: 1; flex-shrink: 0; } .gc-popup-close:hover { color: var(--text); background: var(--bg4); } .mcs-dialog, .ism-dialog, .indicator-modal, .obj-tree-panel, .ibsm-dialog, .sp-modal, .brm-modal, .plsp-popup, .ind-panel { position: fixed; } /* ── 모의투자 페이지 ───────────────────────────────────────────────────── */ .paper-page { flex: 1; min-height: 0; overflow: auto; padding: 20px 24px 32px; background: var(--bg); } .paper-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 20px; } .paper-title { font-size: 22px; font-weight: 700; margin: 0 0 6px; color: var(--text); } .paper-subtitle { margin: 0; font-size: 13px; color: var(--text2); line-height: 1.5; } .paper-header-actions { display: flex; gap: 8px; flex-shrink: 0; } .paper-btn { padding: 8px 14px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text); font-size: 13px; cursor: pointer; } .paper-btn:hover { background: var(--bg4); } .paper-btn--danger { border-color: rgba(239, 83, 80, 0.5); color: #ef5350; } .paper-banner { padding: 10px 14px; border-radius: 8px; margin-bottom: 16px; font-size: 13px; } .paper-banner--warn { background: rgba(255, 193, 7, 0.12); border: 1px solid rgba(255, 193, 7, 0.35); color: #ffc107; } .paper-banner--info { background: rgba(77, 171, 247, 0.1); border: 1px solid rgba(77, 171, 247, 0.35); color: var(--text); } .paper-banner--error { background: rgba(239, 83, 80, 0.12); border: 1px solid rgba(239, 83, 80, 0.35); color: #ef5350; } .paper-summary-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; margin-bottom: 20px; } .paper-card { padding: 14px 16px; border-radius: 8px; background: var(--bg2); border: 1px solid var(--border); } .paper-card-label { display: block; font-size: 11px; color: var(--text2); margin-bottom: 6px; } .paper-card-value { font-size: 17px; font-weight: 700; color: var(--text); } .paper-tabs { display: flex; gap: 4px; margin-bottom: 12px; } .paper-tab { padding: 8px 16px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--text2); cursor: pointer; font-size: 13px; } .paper-tab.active { background: var(--bg2); color: var(--text); font-weight: 600; } .paper-panel { padding: 16px; border-radius: 0 8px 8px 8px; background: var(--bg2); border: 1px solid var(--border); min-height: 200px; overflow: auto; } .paper-table { width: 100%; border-collapse: collapse; font-size: 13px; } .paper-table th, .paper-table td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); } .paper-table th { color: var(--text2); font-weight: 600; font-size: 12px; } .paper-sym { display: block; font-size: 11px; color: var(--text2); } .paper-muted { color: var(--text2); text-align: center; padding: 24px; } .paper-dl { display: grid; grid-template-columns: 140px 1fr; gap: 8px 16px; font-size: 13px; } .paper-dl dt { color: var(--text2); } .paper-dl dd { margin: 0; color: var(--text); } .paper-link { background: none; border: none; color: var(--accent, #4dabf7); cursor: pointer; font-size: 12px; } .paper-time { font-size: 12px; color: var(--text2); white-space: nowrap; } .stg-btn { padding: 8px 14px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text); font-size: 13px; cursor: pointer; } .stg-btn--danger { border-color: rgba(239, 83, 80, 0.5); color: #ef5350; } .stg-btn--danger:hover { background: rgba(239, 83, 80, 0.12); } /* ── Dashboard ── */ .dashboard-page { padding: 24px 32px; max-width: 1200px; margin: 0 auto; } .dashboard-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; } .dashboard-header h1 { font-size: 22px; font-weight: 600; margin: 0; color: var(--text); } .dashboard-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; } .dashboard-card { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 16px; } .dashboard-card--wide { grid-column: 1 / -1; } .dashboard-card h2 { font-size: 14px; margin: 0 0 12px; color: var(--text2); font-weight: 600; } .dashboard-kv { list-style: none; margin: 0; padding: 0; } .dashboard-kv li { display: flex; justify-content: space-between; padding: 6px 0; font-size: 13px; border-bottom: 1px solid var(--border); } .dashboard-kv li:last-child { border-bottom: none; } .dashboard-kv--cols { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; } .dashboard-kv--cols li { border: none; flex-direction: column; gap: 4px; } .dashboard-table { width: 100%; border-collapse: collapse; font-size: 13px; } .dashboard-table th, .dashboard-table td { padding: 8px 10px; text-align: left; border-bottom: 1px solid var(--border); } .dashboard-table .buy { color: #26a69a; } .dashboard-table .sell { color: #ef5350; } .dashboard-link { background: none; border: none; color: var(--accent); cursor: pointer; padding: 0; } .dashboard-muted { color: var(--text2); font-size: 13px; } .dashboard-error { color: #ef5350; font-size: 13px; } .dashboard-header-actions { display: flex; align-items: center; gap: 12px; } .dashboard-live { font-size: 12px; color: var(--text2); } .dash-monitor-top { margin-bottom: 4px; } .dash-jvm-row { display: flex; flex-wrap: wrap; gap: 20px; align-items: flex-start; } .dash-jvm-heap { flex: 1; min-width: 220px; } .dash-jvm-label { font-size: 12px; color: var(--text2); margin-bottom: 8px; } .dash-jvm-bar { height: 10px; background: var(--bg3); border-radius: 5px; overflow: hidden; } .dash-jvm-fill { height: 100%; background: #26a69a; border-radius: 5px; transition: width 0.3s ease; } .dash-jvm-fill--warn { background: #ef5350; } .dash-traffic-kv { flex: 1; min-width: 280px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; } .dash-traffic-kv li { border: none; } .dash-proc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; } .dash-proc { border: 1px solid var(--border); border-radius: 8px; padding: 12px; background: var(--bg3); } .dash-proc--ok { border-left: 3px solid #26a69a; } .dash-proc--warn { border-left: 3px solid #ffb74d; } .dash-proc--down { border-left: 3px solid #ef5350; } .dash-proc--off { border-left: 3px solid var(--text3); opacity: 0.85; } .dash-proc-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; } .dash-proc-layer { font-size: 10px; text-transform: uppercase; color: var(--text3); letter-spacing: 0.04em; } .dash-proc-badge { font-size: 10px; font-weight: 600; padding: 2px 6px; border-radius: 4px; } .dash-proc--ok .dash-proc-badge { background: rgba(38, 166, 154, 0.2); color: #26a69a; } .dash-proc--warn .dash-proc-badge { background: rgba(255, 183, 77, 0.2); color: #ffb74d; } .dash-proc--down .dash-proc-badge { background: rgba(239, 83, 80, 0.2); color: #ef5350; } .dash-proc--off .dash-proc-badge { background: var(--bg2); color: var(--text3); } .dash-proc-name { font-size: 13px; font-weight: 600; margin: 0 0 8px; color: var(--text); } .dash-proc-metrics { list-style: none; margin: 0; padding: 0; font-size: 11px; } .dash-proc-metrics li { display: flex; justify-content: space-between; padding: 3px 0; color: var(--text2); } .dash-proc-metrics strong { color: var(--text); font-weight: 500; } .dashboard-table--compact { font-size: 12px; } .dashboard-table--compact code { font-size: 11px; } .dashboard-kv .warn { color: #ef5350; } .dash-stale { border-color: rgba(255, 183, 77, 0.4); } /* ══════════════════════════════════════════════════════════════════ LOGIN MODAL ══════════════════════════════════════════════════════════════════ */ .login-modal-backdrop { position: fixed; inset: 0; z-index: 12000; background: rgba(0, 0, 0, 0.55); display: flex; align-items: center; justify-content: center; padding: 16px; } .login-modal { width: 100%; max-width: 380px; background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45); padding: 20px 22px 22px; } .login-modal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; } .login-modal-header h2 { margin: 0; font-size: 18px; font-weight: 600; color: var(--text); } .login-modal-close { background: transparent; border: none; color: var(--text3); font-size: 22px; line-height: 1; cursor: pointer; padding: 0 4px; } .login-modal-close:hover { color: var(--text); } .login-modal-hint { font-size: 12px; line-height: 1.5; color: var(--text3); margin: 0 0 16px; } .login-modal-form { display: flex; flex-direction: column; gap: 12px; } .login-modal-field { display: flex; flex-direction: column; gap: 6px; font-size: 12px; color: var(--text2); } .login-modal-field input { padding: 9px 11px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg3); color: var(--text); font-size: 14px; } .login-modal-field input:focus { outline: none; border-color: var(--accent); } .login-modal-error { margin: 0; font-size: 12px; color: #ef5350; } .login-modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; } .login-modal-btn { padding: 8px 16px; border-radius: 6px; font-size: 13px; font-weight: 500; cursor: pointer; border: 1px solid var(--border); } .login-modal-btn--ghost { background: transparent; color: var(--text2); } .login-modal-btn--ghost:hover { background: var(--bg3); color: var(--text); } .login-modal-btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; } .login-modal-btn--primary:hover { background: var(--accent-h); } .login-modal-btn:disabled { opacity: 0.55; cursor: not-allowed; } .tmb-user-role { margin-left: 6px; font-size: 10px; font-weight: 600; opacity: 0.65; text-transform: uppercase; } .tmb-user-role { margin-left: 6px; font-size: 10px; font-weight: 600; opacity: 0.65; text-transform: uppercase; } .tmb-user-badge { font-size: 12px; color: var(--accent); max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 6px; } .tmb-login-btn--out { background: transparent; border: 1px solid var(--border); color: var(--text2); padding: 5px 12px; border-radius: 6px; font-size: 12px; cursor: pointer; } .tmb-login-btn--out:hover { background: var(--bg3); color: var(--text); } /* ══════════════════════════════════════════════════════════════════ MOBILE LAYOUT (≤768px, .app--mobile) ══════════════════════════════════════════════════════════════════ */ .app--mobile { height: 100dvh; max-height: 100dvh; -webkit-tap-highlight-color: transparent; } /* ── 글로벌 상단 메뉴: 가로 스크롤 + 아이콘 중심 ── */ .app--mobile .top-menubar { height: 44px; padding: 0 8px; padding-left: max(8px, env(safe-area-inset-left)); padding-right: max(8px, env(safe-area-inset-right)); overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; scrollbar-width: none; } .app--mobile .top-menubar::-webkit-scrollbar { display: none; } .app--mobile .tmb-logo-text { display: none; } .app--mobile .tmb-nav { flex: 1; min-width: 0; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none; } .app--mobile .tmb-nav::-webkit-scrollbar { display: none; } .app--mobile .tmb-nav-btn { flex-shrink: 0; padding: 6px 10px; font-size: 11px; } .app--mobile .tmb-nav-label { display: none; } .app--mobile .tmb-theme-label, .app--mobile .tmb-login-btn span { display: none; } .app--mobile .tmb-right { flex-shrink: 0; } /* ── 차트 툴바: 가로 스크롤 ── */ .app--mobile .tv-toolbar { height: 40px; min-height: 40px; overflow-x: auto; overflow-y: hidden; flex-wrap: nowrap; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding: 0 4px; gap: 0; } .app--mobile .tv-toolbar::-webkit-scrollbar { display: none; } .app--mobile .tv-toolbar-left, .app--mobile .tv-toolbar-right { flex-shrink: 0; } .app--mobile .tv-sym-input { width: 88px; min-width: 72px; } .app--mobile .tv-sym-text { max-width: 56px; } .app--mobile .upbit-bar { height: 26px; font-size: 11px; padding: 0 8px; overflow: hidden; } .app--mobile .upbit-hint { display: none; } .app--mobile .upbit-market { max-width: 42vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* ── 메인: 차트 전체 너비, 사이드 패널 오버레이 ── */ .app--mobile .tv-main { position: relative; flex: 1; min-height: 0; } .app--mobile .tv-drawing-sidebar, .app--mobile .mp-panel-handle, .app--mobile .rsp-handle { display: none !important; } /* 좌측 마켓 패널 — 슬라이드 오버레이 */ .app--mobile .market-panel { position: fixed; left: 0; top: 0; bottom: 0; z-index: 400; width: 0 !important; max-width: min(92vw, 320px); border-right: 1px solid var(--border); box-shadow: 4px 0 24px rgba(0, 0, 0, 0.45); transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1); } .app--mobile .market-panel--open { width: min(92vw, 320px) !important; } .app--mobile .mp-body { width: min(92vw, 320px); min-width: 0; height: 100%; padding-top: env(safe-area-inset-top, 0); padding-bottom: calc(52px + env(safe-area-inset-bottom, 0)); } /* 우측 매매·호가 — 전체 너비 슬라이드 */ .app--mobile .rsp-wrap { position: fixed; right: 0; top: 0; bottom: 0; z-index: 400; width: auto; pointer-events: none; } .app--mobile .rsp-wrap--open { pointer-events: auto; } .app--mobile .rsp-panel { position: fixed; right: 0; top: 0; bottom: 0; height: 100% !important; max-height: 100%; border-left: 1px solid var(--border); box-shadow: -4px 0 24px rgba(0, 0, 0, 0.45); transition: width 0.25s cubic-bezier(0.4, 0, 0.2, 1); } .app--mobile .rsp-wrap--open .rsp-panel { width: min(100vw, 400px) !important; } .app--mobile .rsp-tabs, .app--mobile .rsp-body { min-width: 0; width: 100%; } .app--mobile .rsp-body { padding-bottom: calc(52px + env(safe-area-inset-bottom, 0)); } /* 패널 뒤 어두운 배경 */ .mobile-panel-backdrop { position: fixed; inset: 0; z-index: 350; border: none; padding: 0; margin: 0; background: rgba(0, 0, 0, 0.52); cursor: pointer; -webkit-tap-highlight-color: transparent; } /* 차트 영역 */ .app--mobile .tv-chart-col, .app--mobile .multi-chart-grid, .app--mobile .multi-slot-wrap { min-width: 0; width: 100%; } .app--mobile .multi-chart-grid { display: flex !important; flex-direction: column !important; grid-template-columns: none !important; grid-template-rows: none !important; grid-template-areas: none !important; overflow-y: auto; -webkit-overflow-scrolling: touch; } .app--mobile .multi-slot-wrap { flex: 1 1 auto; min-height: 220px; grid-area: unset !important; } /* 하단 기간 바 + 모바일 도크 */ .app--mobile .tv-bottom-bar { flex-shrink: 0; margin-bottom: calc(48px + env(safe-area-inset-bottom, 0)); } .mobile-chart-dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: 500; display: flex; align-items: stretch; justify-content: space-around; height: calc(48px + env(safe-area-inset-bottom, 0)); padding-bottom: env(safe-area-inset-bottom, 0); background: var(--bg2); border-top: 1px solid var(--border); box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.35); } .mcd-btn { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; min-width: 0; padding: 4px 2px; background: transparent; border: none; color: var(--text3); font-size: 10px; cursor: pointer; -webkit-tap-highlight-color: transparent; } .mcd-btn.active { color: var(--accent); background: rgba(122, 162, 247, 0.12); } .mcd-icon { font-size: 18px; line-height: 1; } .mcd-label { font-size: 10px; font-weight: 500; letter-spacing: -0.2px; } /* 비차트 페이지: 전체 너비·패딩 */ .app--mobile .dashboard-page, .app--mobile .strategy-page, .app--mobile .stg-page, .app--mobile .paper-page, .app--mobile .brd-page { padding: 12px 12px max(16px, env(safe-area-inset-bottom)); max-width: 100%; overflow-x: hidden; } .app--mobile .dashboard-grid, .app--mobile .brd-kpi-grid { grid-template-columns: 1fr !important; } /* 플로팅 패널: 모바일에서 거의 전체 너비 */ .app--mobile .stats-panel, .app--mobile .watch-panel, .app--mobile .alert-panel, .app--mobile .object-tree-panel { left: 8px !important; right: 8px !important; width: auto !important; max-width: none !important; } /* 터치 타겟 확대 */ .app--mobile .tv-icon-btn, .app--mobile .tv-side-btn { min-width: 36px; min-height: 36px; } /* 기존 600px 규칙 유지 (모바일 중첩) */ @media (max-width: 600px) { :root { --sidebar-w: 36px; } .tv-sym-text { max-width: 70px; overflow: hidden; text-overflow: ellipsis; } .tv-theme-label { display: none; } .tv-indicators-btn span:first-of-type { display: none; } } /* ── 관리자 설정 ── */ .admin-gate { display: flex; align-items: center; justify-content: center; min-height: 280px; padding: 24px; } .admin-gate-card { max-width: 360px; width: 100%; padding: 24px; background: var(--bg3); border: 1px solid var(--border); border-radius: 8px; } .admin-gate-title { margin: 0 0 8px; font-size: 16px; } .admin-gate-desc { margin: 0 0 16px; font-size: 13px; color: var(--text2); line-height: 1.5; } .admin-gate-form { display: flex; flex-direction: column; gap: 12px; } .admin-gate-field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; } .admin-gate-field input { padding: 8px 10px; border: 1px solid var(--border); border-radius: 4px; background: var(--bg2); color: var(--text); } .admin-gate-error { color: var(--down); font-size: 12px; margin: 0; } .admin-gate-btn { padding: 8px 16px; background: var(--accent); color: #fff; border: none; border-radius: 4px; cursor: pointer; font-weight: 600; } .admin-gate-btn:disabled { opacity: 0.5; cursor: not-allowed; } .admin-settings { display: flex; flex-direction: column; gap: 8px; } .admin-msg { padding: 8px 12px; border-radius: 4px; font-size: 13px; margin: 0 0 8px; } .admin-msg--ok { background: rgba(38, 166, 154, 0.15); color: var(--up); } .admin-msg--err { background: rgba(239, 83, 80, 0.15); color: var(--down); } .admin-toolbar { margin-bottom: 12px; } .admin-table-wrap { overflow-x: auto; } .admin-table { width: 100%; border-collapse: collapse; font-size: 13px; } .admin-table th, .admin-table td { padding: 8px 12px; border-bottom: 1px solid var(--border); text-align: left; } .admin-table th { color: var(--text2); font-weight: 600; } .admin-actions { white-space: nowrap; } .admin-link { background: none; border: none; color: var(--accent); cursor: pointer; font-size: 12px; margin-right: 8px; } .admin-link--danger { color: var(--down); } .admin-role { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 600; } .admin-role--admin { background: rgba(33, 150, 243, 0.2); color: #64b5f6; } .admin-role--user { background: rgba(158, 158, 158, 0.2); color: var(--text2); } .admin-role--guest { background: rgba(255, 193, 7, 0.15); color: #ffc107; } .admin-form-section { border-top: 1px solid var(--border); padding-top: 16px; } .admin-form-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; } .admin-form-grid label { display: flex; flex-direction: column; gap: 4px; font-size: 13px; } .admin-form-grid input, .admin-form-grid select { padding: 6px 8px; border: 1px solid var(--border); border-radius: 4px; background: var(--bg2); color: var(--text); } .admin-check { flex-direction: row !important; align-items: center; gap: 8px !important; } .admin-form-actions { display: flex; gap: 8px; margin-top: 12px; } .admin-perm-role-tabs { display: flex; gap: 4px; margin-bottom: 12px; } .admin-perm-tab { padding: 6px 14px; border: 1px solid var(--border); background: var(--bg2); color: var(--text2); border-radius: 4px; cursor: pointer; font-size: 13px; } .admin-perm-tab.active { background: var(--accent); border-color: var(--accent); color: #fff; } .admin-perm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 6px 12px; max-height: 360px; overflow-y: auto; padding: 8px; background: var(--bg3); border-radius: 6px; border: 1px solid var(--border); } .admin-perm-item { display: flex; align-items: center; gap: 8px; font-size: 12px; cursor: pointer; } /* splash styles moved to styles/splashScreen.css */ .tmb-guest-badge { font-size: 12px; font-weight: 600; color: #ffc107; padding: 0 8px; border: 1px solid rgba(255, 193, 7, 0.35); border-radius: 10px; background: rgba(255, 193, 7, 0.1); }