/* stock-crawler 개인 대시보드 스타일 — 외부 폰트·이미지·CDN 없음, 인라인 style 속성 없음(CSP style-src 'self').
 *
 * 레이아웃: ≥1024px 왼쪽 사이드바(브랜드·메뉴·테마/로그아웃) + 본문 최대 1280px·24px 거터 / <1024px 상단 바(브랜드·테마) + 하단 고정 탭 바(.nav, safe-area 반영).
 * 다크 모드는 자동 반전이 아니라 별도 토큰값이며, prefers-color-scheme 과 수동 토글(html[data-theme]) 두 경로 모두 같은 값을 쓴다.
 *
 * ── 색 팔레트 검증 로그 (dataviz validate_palette.js, 2026-11-01 재검증) ────────────────────────
 *  범주색은 팔레트 슬롯을 순서대로 쓴다(순환·생성 금지). 다크는 자동 반전이 아니라 별도 단계값이다.
 *  표면(차트 카드): 라이트 #ffffff / 다크 #171a21  (페이지 배경: 라이트 #f4f5f8 / 다크 #0f1115)
 *
 *  [A] 투자자 3계열 = 슬롯 1·2·3 (파랑·주황·아쿠아), --pairs all
 *      light "#2a78d6,#eb6834,#1baf7a"  → ALL CHECKS PASS
 *            밝기대·채도 PASS / CVD 최악 쌍 #1baf7a↔#eb6834 ΔE 9.2 / 정상시야 최악 24.0 PASS /
 *            대비 WARN(아쿠아 2.82:1 — 구제 규칙: 끝점 직접 라벨 + 범례 + 표 보기 제공)
 *      dark  "#3987e5,#d95926,#199e70"  → ALL CHECKS PASS (CVD 9.4 / 정상시야 20.9 / 대비 3:1 이상 전부 PASS)
 *
 *  [B] 캔들 상승/하락 = 슬롯 8(빨강)·슬롯 1(파랑), --pairs all
 *      light "#e34948,#2a78d6"          → ALL CHECKS PASS (CVD 21.6 / 정상시야 32.3)
 *      dark  "#e66767,#3987e5"          → ALL CHECKS PASS (CVD 19.2 / 정상시야 29.0)
 *
 *  [C] 가격 패널 전체 = 슬롯 1·3·4·7·8 (파랑=하락, MA5=아쿠아, MA20=노랑, MA60=보라, 빨강=상승), 슬롯 순서 고정, 인접쌍 기준
 *      (선·막대 계열의 표준 쌍목록. MA 선은 상승/하락 두 색을 쓰지 않는다)
 *      light "#2a78d6,#1baf7a,#eda100,#4a3aa7,#e34948" → ALL CHECKS PASS (CVD 최악 인접 9.1 / 정상시야 22.9 /
 *            대비 WARN: 아쿠아 2.82·노랑 2.17 — MA 끝점 라벨 + 범례 + 표 보기로 구제)
 *      dark  "#3987e5,#199e70,#c98500,#9085e9,#e66767" → ALL CHECKS PASS (CVD 8.4 / 정상시야 19.8 / 대비 전부 3:1 이상)
 *      ※ 5색 전수쌍(--pairs all) 은 팔레트 규칙상 통과할 수 없다(다크 파랑↔보라 ΔE 9.8). 그래서 MA 는 몸통이 없는
 *        2px 선이라 모양으로 캔들과 구분되고, 범례·끝점 라벨·툴팁·표가 색 외 채널을 맡는다.
 *
 *  텍스트 대비(WCAG, 실측): 라이트 본문 #111318 18.6 · 보조 #4b5160 7.9 · 흐림 #667085 5.0(페이지 배경 #f4f5f8 위 4.6) ·
 *      상승 글자 #c93a3a 5.1 · 하락 글자 #1f6bc4 5.3 (마크색 #e34948·#2a78d6 은 글자엔 쓰지 않음)
 *      다크 본문 #f3f4f6 15.8 · 보조 #b4bac6 8.9 · 흐림 #8b93a3 5.6 · 상승 글자 #e66767 5.4 · 하락 글자 #3987e5 4.8
 *  목록 행 hover 배경(--row-hover) 위의 글자 대비(실측, 4.5:1 이상): 라이트 흐림 #5f6675 5.4 · 상승 #c23535 5.1 · 하락 #1f6bc4 4.9,
 *      다크 흐림 #99a1b0 6.0 · 상승 #e66767 4.8 · 하락 #4a94ea 5.0 (hover 때만 한 단계 진한/밝은 글자 토큰으로 바꾼다)
 *  등락 pill(목록·스캔): 배경은 마크색 9% 를 **불투명 표면에** 섞은 값이라 행 hover 와 무관하다. 글자 = 라이트 #c23535 4.8 · #1f6bc4 4.7,
 *      다크 #e66767 4.8 · #4a94ea 4.9 (전부 pill 배경 기준 실측)
 *  거래량 막대(비텍스트 3:1): 라이트 불투명도 0.92 → 상승 3.5 · 하락 3.8 · 보합 3.1 / 다크 0.75 → 상승 3.6 · 하락 3.2 · 보합 3.3
 *  상태색(good/warning/critical)은 팔레트 고정값이며 아이콘 + 라벨과 항상 짝을 이룬다(색 단독 전달 금지). 아이콘 글자는 본문색을 25% 섞어 라이트에서도 읽힌다.
 *  한국식 색: 상승=빨강·하락=파랑·보합=회색, ▲ ▼ − 기호와 +/− 부호를 항상 함께 쓴다.
 *  [D] 볼린저 타점(종목 상세 토글): BB 밴드=슬롯5, 타점 마커=슬롯6(기호+약자 동반) — 색 추가 없음, 기존 검증값 그대로.
 *  [E] RSI(14) 패널 선 = 슬롯2(주황, 투자자 '기관' 과 같은 슬롯 — 다른 차트 카드라 같은 화면에서 겹치지 않는다). 패널 라벨·범례·툴팁 행·표 열이 색 외 채널.
 */

/* ============================================================ 토큰 (라이트 / 다크 / 수동 토글 3중 스코프) */
:root {
  color-scheme: light;
  --page: #f4f5f8;
  --surface: #ffffff;
  --surface-2: #f3f4f7;
  --surface-3: #e9ebf0;
  --hover: rgba(17, 20, 27, 0.05);
  --row-hover: rgba(17, 20, 27, 0.035);
  --border: #e4e6ec;
  --border-strong: rgba(17, 20, 27, 0.18);
  --text: #111318;
  --text-2: #4b5160;
  --text-3: #667085;
  --text-3-hover: #5f6675;
  --grid: #eceef2;
  --axis: #cfd3db;
  --ink-bg: #111318;
  --ink-fg: #ffffff;
  --focus: #111318;
  --star: #a86a00;
  --shadow-card: 0 1px 2px rgba(17, 20, 27, 0.04), 0 6px 20px -12px rgba(17, 20, 27, 0.12);
  --shadow-pop: 0 10px 30px -10px rgba(17, 20, 27, 0.25), 0 2px 6px rgba(17, 20, 27, 0.06);
  --blur-bg: rgba(244, 245, 248, 0.78);

  --series-1: #2a78d6;
  --series-2: #eb6834;
  --series-3: #1baf7a;
  --series-4: #eda100;
  --series-5: #e87ba4;
  --series-6: #008300;
  --series-7: #4a3aa7;
  --series-8: #e34948;

  --up: var(--series-8);
  --down: var(--series-1);
  --flat: #898781;
  --up-text: #c93a3a;
  --down-text: #1f6bc4;
  --up-text-hover: #c23535;
  --down-text-hover: #1f6bc4;
  --up-pill-text: #c23535;
  --down-pill-text: #1f6bc4;
  --vbar-opacity: 0.92;
  --ma5: var(--series-3);
  --ma20: var(--series-4);
  --ma60: var(--series-7);
  --bb: var(--series-5);
  --bb-signal: var(--series-6);
  --rsi: var(--series-2);

  --good: #0ca30c;
  --warning: #fab219;
  --serious: #ec835a;
  --critical: #d03b3b;

  --sidebar-w: 240px;
  --topbar-h: 56px;
  --tabbar-h: 58px;
  --gutter: 24px;
  --card-pad: 20px;
  --card-gap: 20px;
  --radius: 16px;
  --radius-sm: 10px;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --page: #0f1115;
    --surface: #171a21;
    --surface-2: #1f232c;
    --surface-3: #272c37;
    --hover: rgba(255, 255, 255, 0.06);
    --row-hover: rgba(255, 255, 255, 0.045);
    --border: rgba(255, 255, 255, 0.08);
    --border-strong: rgba(255, 255, 255, 0.2);
    --text: #f3f4f6;
    --text-2: #b4bac6;
    --text-3: #8b93a3;
    --text-3-hover: #99a1b0;
    --grid: #252a34;
    --axis: #353b48;
    --ink-bg: #f3f4f6;
    --ink-fg: #0f1115;
    --focus: #f3f4f6;
    --star: #eda100;
    --shadow-card: none;
    --shadow-pop: 0 12px 32px -8px rgba(0, 0, 0, 0.6);
    --blur-bg: rgba(15, 17, 21, 0.78);

    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --series-4: #c98500;
    --series-5: #d55181;
    --series-6: #008300;
    --series-7: #9085e9;
    --series-8: #e66767;

    --flat: #898781;
    --up-text: #e66767;
    --down-text: #3987e5;
    --up-text-hover: #e66767;
    --down-text-hover: #4a94ea;
    --up-pill-text: #e66767;
    --down-pill-text: #4a94ea;
    --vbar-opacity: 0.75;
    --bb: var(--series-5);
    --bb-signal: var(--series-6);
    --rsi: var(--series-2);

    --good: #2fb344;
    --warning: #f2b53a;
    --serious: #ec835a;
    --critical: #ef5350;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --page: #0f1115;
  --surface: #171a21;
  --surface-2: #1f232c;
  --surface-3: #272c37;
  --hover: rgba(255, 255, 255, 0.06);
  --row-hover: rgba(255, 255, 255, 0.045);
  --border: rgba(255, 255, 255, 0.08);
  --border-strong: rgba(255, 255, 255, 0.2);
  --text: #f3f4f6;
  --text-2: #b4bac6;
  --text-3: #8b93a3;
  --text-3-hover: #99a1b0;
  --grid: #252a34;
  --axis: #353b48;
  --ink-bg: #f3f4f6;
  --ink-fg: #0f1115;
  --focus: #f3f4f6;
  --star: #eda100;
  --shadow-card: none;
  --shadow-pop: 0 12px 32px -8px rgba(0, 0, 0, 0.6);
  --blur-bg: rgba(15, 17, 21, 0.78);

  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #008300;
  --series-7: #9085e9;
  --series-8: #e66767;

  --flat: #898781;
  --up-text: #e66767;
  --down-text: #3987e5;
  --up-text-hover: #e66767;
  --down-text-hover: #4a94ea;
  --up-pill-text: #e66767;
  --down-pill-text: #4a94ea;
  --vbar-opacity: 0.75;
  --bb: var(--series-5);
  --bb-signal: var(--series-6);
  --rsi: var(--series-2);

  --good: #2fb344;
  --warning: #f2b53a;
  --serious: #ec835a;
  --critical: #ef5350;
}

/* ============================================================ 기본 */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--page);
  color: var(--text);
  font-family: "Pretendard", "Noto Sans KR", "Malgun Gothic", "Apple SD Gothic Neo", system-ui, sans-serif;
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p { margin: 0; }
a { color: inherit; }
button, input { font: inherit; color: inherit; }
code, pre { font-family: ui-monospace, "SF Mono", "D2Coding", Menlo, Consolas, monospace; }
svg { display: block; }

:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 8px; top: -48px; z-index: 50; padding: 8px 12px; border-radius: 8px;
  background: var(--ink-bg); color: var(--ink-fg); text-decoration: none;
}
.skip-link:focus { top: 8px; }

[hidden] { display: none !important; }

/* ============================================================ 상단 바 / 사이드바 / 탭 바 (한 DOM, 두 레이아웃) */
.topbar { position: sticky; top: 0; z-index: 30; background: var(--surface); border-bottom: 1px solid var(--border); }
.topbar-inner { display: flex; align-items: center; gap: 12px; height: var(--topbar-h); padding: 0 16px; }

.brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; flex: none; border-radius: 8px; }
.brand-mark { width: 28px; height: 28px; flex: none; }
.bm-bg { fill: var(--ink-bg); }
.bm-up { fill: var(--series-8); }
.bm-down { fill: var(--series-1); }
.brand-text { font-weight: 700; font-size: 15px; letter-spacing: -0.01em; white-space: nowrap; display: flex; flex-direction: column; line-height: 1.15; }
.brand-sub { color: var(--text-3); font-weight: 500; font-size: 11px; letter-spacing: 0; }

/* 메뉴: 아이콘 + 라벨. 사이드바(세로)·탭 바(가로) 공용 */
.nav { display: flex; gap: 2px; }
.nav a {
  display: inline-flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 10px; text-decoration: none;
  color: var(--text-2); font-weight: 500; font-size: 14px; white-space: nowrap; transition: background 0.12s ease, color 0.12s ease;
}
.nav-ico { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.nav a:hover { background: var(--hover); color: var(--text); }
.nav a[aria-current="page"] { background: var(--surface-3); color: var(--text); font-weight: 600; }

.topbar-right { margin-left: auto; display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-width: 0; flex: 1 1 auto; }
.topbar-right > .seg, .topbar-right > .btn { flex: none; }

.demo-chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; padding: 3px 9px; border-radius: 999px;
  background: color-mix(in srgb, var(--warning) 18%, var(--surface)); border: 1px solid color-mix(in srgb, var(--warning) 55%, transparent); color: var(--text);
  white-space: nowrap; min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis;
}
.demo-chip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--warning); flex: none; }

/* 세그먼트 컨트롤 — overflow:hidden 을 쓰지 않는다(부모가 자르면 포커스 링이 거의 보이지 않는다, WCAG 2.4.7). 둥근 모서리는 버튼 자신이 가진다. */
.seg { display: inline-flex; align-items: center; gap: 2px; padding: 3px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border); }
.seg button {
  appearance: none; border: 0; background: transparent; color: var(--text-2); cursor: pointer; position: relative;
  display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 10px; border-radius: 999px; font-size: 12px; font-weight: 500; white-space: nowrap;
  transition: background 0.12s ease, color 0.12s ease;
}
.seg-ico { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.seg button:focus-visible { z-index: 1; outline-offset: 1px; }
.seg button:hover { color: var(--text); }
.seg button[aria-pressed="true"] { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: 0 1px 2px rgba(17, 20, 27, 0.12), 0 0 0 1px var(--border); }
:root[data-theme="dark"] .seg button[aria-pressed="true"] { background: var(--surface-3); }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .seg button[aria-pressed="true"] { background: var(--surface-3); } }

#logout-btn { gap: 6px; }

/* 사이드바 접기 토글 — ≥1024px 에서만 보인다(아래 레이아웃 분기에서 표시) */
.sb-toggle { display: none; }
.btn-ico { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; flex: none; }

/* ============================================================ 본문·푸터 */
.page { flex: 1; width: 100%; max-width: calc(1280px + var(--gutter) * 2); margin: 0 auto; padding: 24px var(--gutter) 48px; }
.page:focus { outline: none; }

.notice {
  margin-bottom: 16px; padding: 10px 14px; border-radius: var(--radius-sm); font-size: 13px; color: var(--text);
  background: color-mix(in srgb, var(--warning) 16%, var(--surface)); border: 1px solid color-mix(in srgb, var(--warning) 55%, transparent);
}

.footer { border-top: 1px solid var(--border); color: var(--text-3); font-size: 12px; }
.footer-inner { max-width: calc(1280px + var(--gutter) * 2); margin: 0 auto; padding: 16px var(--gutter); }

/* ============================================================ 공통 요소 */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--card-pad); box-shadow: var(--shadow-card); }
.card + .card, .stack > * + * { margin-top: var(--card-gap); }

.page-title { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.25; }
.page-head { display: flex; align-items: baseline; gap: 6px 14px; flex-wrap: wrap; margin-bottom: 16px; }
.page-head .muted { font-size: 13px; }
.muted { color: var(--text-3); }
.num { text-align: right; font-variant-numeric: tabular-nums; }

.crumb { margin-bottom: 12px; font-size: 13px; }
.crumb a {
  display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px 4px 8px; border-radius: 999px; color: var(--text-2); text-decoration: none;
  background: var(--surface); border: 1px solid var(--border); font-weight: 500;
}
.crumb a:hover { color: var(--text); background: var(--surface-3); }

/* 필터 줄: 상단 바 아래 sticky + backdrop blur. 본문 폭을 그대로 쓰고 아래 카드와 20px 간격 */
.filters {
  position: sticky; top: 0; z-index: 15; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px;
  margin: 0 0 var(--card-gap); padding: 10px 0; background: var(--blur-bg); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.filter-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; min-width: 0; flex: 1 1 auto; }
.chip-group { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chip-label { font-size: 12px; font-weight: 500; color: var(--text-3); margin-right: 2px; }

.chip {
  appearance: none; cursor: pointer; background: var(--surface); color: var(--text-2);
  border: 1px solid var(--border); border-radius: 999px; padding: 0 12px; height: 32px; font-size: 13px; font-weight: 500; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 4px; transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.chip:hover { background: var(--surface-3); color: var(--text); }
.chip[aria-pressed="true"] { background: var(--ink-bg); border-color: var(--ink-bg); color: var(--ink-fg); font-weight: 600; }

.search { position: relative; display: inline-flex; align-items: center; }
.search::before {
  content: ""; position: absolute; left: 12px; top: 50%; width: 15px; height: 15px; margin-top: -8px; pointer-events: none; opacity: 0.55;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.8-3.8'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M20 20l-3.8-3.8'/%3E%3C/svg%3E") center / contain no-repeat;
}
.search input {
  width: 240px; max-width: 100%; height: 40px; padding: 0 12px 0 36px; border-radius: var(--radius-sm); background: var(--surface);
  border: 1px solid var(--border); color: var(--text); transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.search input::placeholder { color: var(--text-3); }
.search input:focus { border-color: var(--border-strong); }
.search input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.btn {
  appearance: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; cursor: pointer; text-decoration: none;
  background: var(--surface); color: var(--text-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  height: 36px; padding: 0 14px; font-size: 13px; font-weight: 500; line-height: 1; white-space: nowrap;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.btn:hover { background: var(--surface-3); color: var(--text); }
.btn:disabled { opacity: 0.45; cursor: default; background: var(--surface); color: var(--text-2); }
.btn-sm { height: 30px; padding: 0 10px; font-size: 12px; border-radius: 8px; }
.btn[aria-pressed="true"] { background: var(--ink-bg); color: var(--ink-fg); border-color: var(--ink-bg); }
.btn[aria-pressed="true"]:hover { background: var(--ink-bg); color: var(--ink-fg); opacity: 0.9; }

.tag {
  display: inline-flex; align-items: center; font-size: 12px; font-weight: 500; line-height: 1.5; height: 22px; padding: 0 8px; border-radius: 6px;
  background: var(--surface-2); color: var(--text-2); white-space: nowrap; vertical-align: middle;
}
.tag-warn {
  background: color-mix(in srgb, var(--warning) 18%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--warning) 55%, transparent); color: var(--text);
}
.tag-muted { background: transparent; border: 1px dashed var(--border-strong); color: var(--text-3); }

.badge {
  display: inline-flex; align-items: center; font-size: 11px; font-weight: 600; line-height: 1; height: 20px; padding: 0 8px; border-radius: 999px;
  border: 1px solid var(--border-strong); color: var(--text-2); white-space: nowrap;
}

/* 상태 pill: 아이콘 글자 + 라벨 (색만으로 구분하지 않는다) */
.status {
  display: inline-flex; align-items: center; gap: 6px; padding: 0 10px 0 8px; height: 26px; border-radius: 999px; font-size: 12px; font-weight: 600;
  color: var(--text); white-space: nowrap;
  background: color-mix(in srgb, var(--st, var(--axis)) 14%, var(--surface)); border: 1px solid color-mix(in srgb, var(--st, var(--axis)) 45%, transparent);
}
.status .ico { color: color-mix(in srgb, var(--st, var(--text-2)) 75%, var(--text)); font-size: 12px; line-height: 1; }
.st-ok { --st: var(--good); }
.st-warn { --st: var(--warning); }
.st-stale, .st-failed { --st: var(--critical); }
.st-partial { --st: var(--serious); }
.st-interrupted { --st: var(--text-3); }
.st-running { --st: var(--series-1); }

.chg-up { color: var(--up-text); }
.chg-down { color: var(--down-text); }
.chg-flat { color: var(--text-2); }
.chg-na { color: var(--text-3); }

/* 등락 pill(목록·스캔 표): 배경을 불투명 표면에 섞어 행 hover 와 무관하게 대비가 유지된다 */
.chg-pill {
  display: inline-flex; align-items: center; justify-content: center; min-width: 76px; height: 26px; padding: 0 9px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; background: var(--surface-2);
}
.chg-pill.chg-up { background: color-mix(in srgb, var(--up) 9%, var(--surface)); color: var(--up-pill-text); }
.chg-pill.chg-down { background: color-mix(in srgb, var(--down) 9%, var(--surface)); color: var(--down-pill-text); }
.chg-pill.chg-flat { color: var(--text-2); }
.chg-pill.chg-na { color: var(--text-3); }

/* 로딩: 기존 is-loading 훅은 유지하고, 시각만 스켈레톤(shimmer) 으로 */
.is-loading { position: relative; }
.is-loading > *:not(.skeleton-list) { opacity: 0.55; transition: opacity 0.15s ease; }
.skeleton, .skeleton-list { pointer-events: none; }
.skeleton {
  display: block; border-radius: 8px; background: var(--surface-3);
  background-image: linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--surface) 70%, transparent) 50%, transparent 100%);
  background-size: 200% 100%; animation: shimmer 1.3s ease-in-out infinite;
}
.skeleton-title { width: 36%; height: 18px; margin-bottom: 16px; }
.skeleton-row { height: 14px; margin-top: 14px; }
.skeleton-row:nth-child(3n) { width: 82%; }
.skeleton-row:nth-child(3n + 1) { width: 94%; }
.skeleton-list .skeleton-row { height: 16px; margin-top: 18px; }
.skeleton-list .skeleton-row:first-child { margin-top: 4px; }
.skeleton-block { height: 220px; border-radius: 12px; }
.chart-card.is-loading .chart-body { min-height: 180px; }     /* 첫 로드(SVG 없음)에도 shimmer 블록이 보이도록 */
.chart-card.is-loading .chart-body::after {
  content: ""; position: absolute; inset: 0; border-radius: 12px; z-index: 2;
  background: linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--surface-3) 60%, transparent) 50%, transparent 100%);
  background-size: 200% 100%; animation: shimmer 1.3s ease-in-out infinite;
}
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* 빈 상태: 아이콘 + 제목 + 설명 + 명령 코드블록 */
.empty { text-align: center; padding: 44px 20px; }
.empty-ico { width: 44px; height: 44px; margin: 0 auto 14px; color: var(--text-3); fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.empty-title { font-size: 16px; font-weight: 650; margin-bottom: 6px; }
.empty-msg { color: var(--text-2); max-width: 520px; margin: 0 auto; word-break: keep-all; }
.empty .btn { margin-top: 16px; }

.cmd {
  display: block; text-align: left; margin: 16px auto 0; max-width: 560px; padding: 12px 14px; border-radius: var(--radius-sm);
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text); font-size: 12px; line-height: 1.75; white-space: pre-wrap; word-break: break-all;
}
.cmd code { font-family: inherit; }

.card .card.empty { border: 0; background: transparent; padding: 28px 0; box-shadow: none; }
.index-grid > .empty { grid-column: 1 / -1; }

.error-card { border-color: color-mix(in srgb, var(--critical) 45%, var(--border)); }
.error-card .empty-ico { color: var(--critical); }

/* ============================================================ 표 */
/* position:relative — 표 머리글의 sr-only(절대 배치) 글자가 스크롤 상자 밖(문서 폭)으로 새어 나가 가로 스크롤을 만들지 않게 한다 */
/* 카드 안쪽 여백만큼 밖으로 내밀어(음수 margin) 행 hover 배경·가로 스크롤이 카드 가장자리까지 닿는다. 첫·끝 칸이 그 여백을 패딩으로 되돌린다. */
.table-wrap { overflow-x: auto; position: relative; margin: 0 calc(var(--card-pad) * -1); }
.table-wrap > .data-table th:first-child, .table-wrap > .data-table td:first-child { padding-left: var(--card-pad); }
.table-wrap > .data-table th:last-child, .table-wrap > .data-table td:last-child { padding-right: var(--card-pad); }
.data-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.data-table th {
  text-align: left; font-size: 12px; font-weight: 500; color: var(--text-3); padding: 8px 12px; white-space: nowrap;
  box-shadow: inset 0 -1px 0 var(--border); background: var(--surface);
}
.data-table td { padding: 12px; border-bottom: 1px solid var(--grid); vertical-align: middle; font-variant-numeric: tabular-nums; }
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table th.num, .data-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.recent .data-table td, .chart-table .data-table td { white-space: nowrap; }
.err-count { font-weight: 650; }
.err-zero { color: var(--text-3); }
.data-table .mono { font-variant-numeric: tabular-nums; letter-spacing: 0.01em; white-space: nowrap; }
.data-table .dim { color: var(--text-3); }
.data-table .wrap { white-space: normal; }

.stock-table tbody tr.row { cursor: pointer; transition: background 0.1s ease; }
/* hover 배경 위에서도 흐린 글자·등락 글자가 4.5:1 을 넘도록 hover 때만 글자 토큰을 한 단계 바꾼다 */
.stock-table tbody tr.row:hover { background: var(--row-hover); --text-3: var(--text-3-hover); --up-text: var(--up-text-hover); --down-text: var(--down-text-hover); }
.stock-name { font-weight: 600; text-decoration: none; word-break: break-word; }
.stock-name:hover { text-decoration: underline; }
.sub-sm { display: none; color: var(--text-3); font-size: 12px; font-weight: 400; }
.sub-line { display: block; color: var(--text-3); font-size: 12px; font-weight: 400; margin-top: 1px; }     /* 가상화폐 목록: 이름 아래 영문명 · 마켓(항상 표시) */
.sub-sm .tag { margin-top: 2px; }

.th-btn {
  appearance: none; background: transparent; border: 0; padding: 0; cursor: pointer; color: inherit; font: inherit;
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; border-radius: 4px;
}
.th-btn:hover { color: var(--text); }
th[aria-sort="ascending"] .th-btn, th[aria-sort="descending"] .th-btn { color: var(--text); font-weight: 650; }
.sort-ind { font-size: 11px; min-width: 10px; display: inline-block; }

.star {
  appearance: none; background: transparent; border: 0; cursor: pointer; font-size: 17px; line-height: 1; width: 32px; height: 32px; padding: 0;
  color: var(--text-3); border-radius: 8px; display: inline-flex; align-items: center; justify-content: center;
}
.star:hover { background: var(--hover); color: var(--text); }
.star[aria-pressed="true"] { color: var(--star); }

.list-meta { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; color: var(--text-2); font-size: 13px; }
.list-meta .count { font-weight: 500; color: var(--text); }
.pager { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 16px; color: var(--text-2); font-size: 13px; font-variant-numeric: tabular-nums; }

.foot-note { margin-top: 12px; color: var(--text-3); font-size: 12px; line-height: 1.55; }

/* ============================================================ 종목 상세 히어로 (KPI 타일 4개) */
.hero { display: grid; gap: 18px; margin-bottom: var(--card-gap); }
.hero-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px 24px; flex-wrap: wrap; }
.hero-name { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.hero-name h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; word-break: break-word; line-height: 1.25; }
.hero-code { color: var(--text-3); font-variant-numeric: tabular-nums; font-weight: 500; }
.hero-sub { color: var(--text-2); font-size: 15px; }                      /* 가상화폐 상세: 영문명 */
.utc-note { white-space: normal; }
.hero-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 8px; }
.hero-side { display: flex; align-items: flex-start; flex: none; }

.hero-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.kpi { padding: 14px 16px; border-radius: 12px; background: var(--surface-2); min-width: 0; }
.kpi-label { font-size: 12px; font-weight: 500; color: var(--text-3); }
.kpi-value { display: flex; align-items: baseline; gap: 4px; flex-wrap: wrap; margin-top: 4px; font-size: 24px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.15; font-variant-numeric: tabular-nums; }
.kpi-value.kpi-primary { font-size: clamp(24px, 2.2vw, 30px); letter-spacing: -0.03em; }
.kpi-sub { margin-top: 4px; font-size: 12px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.hero-num { font-variant-numeric: tabular-nums; }
.hero-unit { font-size: 14px; font-weight: 500; color: var(--text-2); }
.hero-change { font-size: 20px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; line-height: 1.15; }
.hero-meta { display: flex; gap: 6px 8px; flex-wrap: wrap; align-items: center; color: var(--text-2); font-size: 13px; }
.hero-meta + .hero-meta { margin-top: -8px; }

.charts > * + * { margin-top: var(--card-gap); }

/* ============================================================ 차트 카드 */
.chart-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px 12px; flex-wrap: wrap; }
.chart-titles { display: flex; align-items: center; gap: 4px 8px; flex-wrap: wrap; min-width: 0; }
.chart-title { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }
.chart-sub { color: var(--text-3); font-size: 12px; flex-basis: 100%; }
.chart-actions { display: flex; gap: 6px; flex: none; }

.legend { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0 4px; font-size: 12px; color: var(--text-2); }
.legend-item { display: inline-flex; align-items: center; height: 24px; padding: 0 9px; border-radius: 999px; background: var(--surface-2); font-weight: 500; }

.s1 { --c: var(--series-1); }
.s2 { --c: var(--series-2); }
.s3 { --c: var(--series-3); }
.s4 { --c: var(--series-4); }
.s5 { --c: var(--series-5); }
.s6 { --c: var(--series-6); }
.s7 { --c: var(--series-7); }
.s8 { --c: var(--series-8); }
.up { --c: var(--up); }
.down { --c: var(--down); }
.flat { --c: var(--flat); }
.ma5 { --c: var(--ma5); }
.ma20 { --c: var(--ma20); }
.ma60 { --c: var(--ma60); }

.key { display: inline-block; margin-right: 6px; background: var(--c); flex: none; }
.key-line { width: 14px; height: 2px; border-radius: 1px; }
.key-rect { width: 10px; height: 10px; border-radius: 3px; }
.key-tri { width: 0; height: 0; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 10px solid var(--c); background: none; border-radius: 0; }

.chart-body { position: relative; margin-top: 8px; touch-action: pan-y; border-radius: 12px; }
.chart-svg { display: block; max-width: 100%; height: auto; }

.grid { stroke: var(--grid); stroke-width: 1; shape-rendering: crispEdges; }
.axis { stroke: var(--axis); stroke-width: 1; shape-rendering: crispEdges; }
.t-axis { fill: var(--text-3); font-size: 11px; font-variant-numeric: tabular-nums; }
.t-panel { font-weight: 500; }
.t-end { fill: var(--text-2); font-size: 11px; font-weight: 500; }
.t-end-val { fill: var(--text); font-size: 12px; font-weight: 650; font-variant-numeric: tabular-nums; }

.ln { fill: none; stroke: var(--c); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.area { fill: var(--c); fill-opacity: 0.1; stroke: none; }
.dot { fill: var(--c); stroke: var(--surface); stroke-width: 2; }
.wick { fill: none; stroke: var(--c); stroke-width: 1.5; }
.cbody { fill: var(--c); stroke: none; }
.vbar { fill: var(--c); fill-opacity: var(--vbar-opacity); stroke: none; }
.dense .wick { stroke-width: 1; }        /* 일봉이 아주 촘촘해 몸통이 2px 안팎이면 심지(1.5px)와 구분되지 않는다 — 심지만 1px 로 */
/* 볼린저 밴드(슬롯5) + 매수 타점 마커(슬롯6). 마커는 ▲ 기호 + 약자 글자(텍스트 토큰 색)로 색 외 채널을 갖는다. */
.bb-fill { fill: var(--bb); fill-opacity: 0.08; stroke: none; }
.bb-fill-key { --c: var(--bb); }
.bb-line { --c: var(--bb); stroke-width: 1.5; }
.bb-mid { --c: var(--bb); stroke-width: 1.5; stroke-dasharray: 5 3; }   /* 중심선(n≠20 일 때만) — 상·하단선과 같은 색이라 점선으로 구분 */
.bb-mark { --c: var(--bb-signal); fill: var(--bb-signal); stroke: var(--surface); stroke-width: 1.5; }
.bb-mark-text { fill: var(--text); font-size: 10px; font-weight: 700; text-anchor: middle; }
.rsi-line { --c: var(--rsi); stroke-width: 1.5; }                        /* RSI(14) 패널 선(슬롯2) — 범례·툴팁 키도 같은 클래스 */
.hover-band { fill: var(--text); fill-opacity: 0.05; }
.crosshair { stroke: var(--text-3); stroke-width: 1; shape-rendering: crispEdges; stroke-dasharray: 3 3; }
.is-off { display: none; }

.tooltip {
  position: absolute; z-index: 5; min-width: 172px; max-width: 280px; padding: 10px 12px; pointer-events: none;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px; font-size: 12px; box-shadow: var(--shadow-pop);
}
.tt-title { color: var(--text-2); font-size: 11px; font-weight: 600; margin-bottom: 6px; padding-bottom: 6px; border-bottom: 1px solid var(--grid); }
.tt-row { display: flex; align-items: baseline; gap: 8px; line-height: 1.7; }
.tt-key { width: 10px; height: 3px; border-radius: 2px; background: var(--c); align-self: center; flex: none; }
.tt-key-none { background: transparent; }
.tooltip:not(.has-keys) .tt-key-none { display: none; }
.tt-label { color: var(--text-2); flex: 1; white-space: nowrap; }
.tt-value { font-weight: 650; text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

.chart-empty { padding: 28px 8px; text-align: center; color: var(--text-2); }
.chart-table { margin-top: 10px; max-height: 360px; overflow: auto; border: 1px solid var(--border); border-radius: 12px; }
.chart-table .data-table th { position: sticky; top: 0; background: var(--surface); z-index: 1; }

/* ============================================================ 볼린저 타점 (종목 상세 토글 · 스캔 화면) */
.bb-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin: calc(var(--card-gap) * -1 + 8px) 0 var(--card-gap); }
.bb-settings { font-size: 13px; }
.bb-settings > summary {
  cursor: pointer; display: inline-flex; align-items: center; gap: 4px; padding: 0 12px; height: 32px;
  border: 1px solid var(--border); background: var(--surface); border-radius: 999px; color: var(--text-2); font-weight: 500; list-style: none; user-select: none;
}
.bb-settings > summary::-webkit-details-marker { display: none; }
.bb-settings > summary::before { content: "▸"; font-size: 11px; }
.bb-settings[open] > summary::before { content: "▾"; }
.bb-settings > summary:hover { background: var(--surface-3); color: var(--text); }
.bb-settings[open] > summary { background: var(--surface-3); color: var(--text); }
.bb-settings-body {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; margin-top: 10px; padding: 12px 14px;
  border: 1px solid var(--border); border-radius: 12px; background: var(--surface); box-shadow: var(--shadow-card);
}
.check-group { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.check { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; color: var(--text-2); white-space: nowrap; }
.check input { margin: 0; width: 16px; height: 16px; accent-color: var(--text); }
.check:hover { color: var(--text); }
.bb-cards > * + * { margin-top: var(--card-gap); }
.bb-card-head { display: flex; align-items: center; gap: 8px 12px; flex-wrap: wrap; margin-bottom: 12px; }
.bb-card-head .card-title { margin-bottom: 0; }
.bb-stats .note-warn { color: var(--text-3); }
.bb-signals .tag-muted { margin-left: 6px; font-size: 11px; height: 20px; }
.bb-strategy { white-space: nowrap; font-weight: 500; }
.bb-scan-table tbody tr.row { cursor: pointer; transition: background 0.1s ease; }
.bb-scan-table tbody tr.row:hover { background: var(--row-hover); --text-3: var(--text-3-hover); --up-text: var(--up-text-hover); --down-text: var(--down-text-hover); }
.bb-disclaimer { margin-top: 4px; }
.view-bb .page-head .bb-disclaimer { flex-basis: 100%; font-size: 13px; line-height: 1.55; word-break: keep-all; }
.bb-scan-table .bb-sub { display: block; }
.bb-scan-table th, .bb-scan-table td { white-space: nowrap; }
.bb-scan-table td .stock-name { white-space: normal; }

/* ============================================================ 지수·상태 */
.index-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--card-gap); align-items: start; }
.index-col > * + * { margin-top: var(--card-gap); }
.stat-label { color: var(--text-2); font-size: 13px; font-weight: 500; }
.stat-value { font-size: 32px; line-height: 1.15; font-weight: 700; letter-spacing: -0.02em; margin-top: 4px; font-variant-numeric: tabular-nums; }
.stat-delta { display: inline-flex; font-size: 14px; font-weight: 600; height: 28px; padding: 0 10px; margin-top: 8px; font-variant-numeric: tabular-nums; }
.stat-date { color: var(--text-3); font-size: 12px; margin-top: 6px; }

.fresh { display: flex; align-items: center; gap: 10px 14px; flex-wrap: wrap; }
.fresh .status { height: 30px; font-size: 13px; padding: 0 12px 0 10px; }
.fresh-msg { color: var(--text-2); font-size: 14px; }
.fresh-msg code { font-size: 12px; padding: 2px 6px; border-radius: 6px; background: var(--surface-2); color: var(--text); }
.card-title { font-size: 15px; font-weight: 650; margin-bottom: 12px; letter-spacing: -0.01em; }
.kv { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; color: var(--text-2); font-size: 13px; margin-top: 16px; }
.kv > span { padding: 10px 12px; border-radius: 10px; background: var(--surface-2); font-variant-numeric: tabular-nums; }
.run-msg { display: block; color: var(--text-3); font-size: 12px; max-width: 520px; white-space: normal; word-break: break-word; }
.notes { margin: 0; padding-left: 18px; color: var(--text-2); }
.notes li + li { margin-top: 6px; }
.mix-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px 16px; margin: 0; padding: 0; list-style: none; }
.mix-list li { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px; border-radius: 10px; background: var(--surface-2); }
.mix-list a { font-weight: 600; text-decoration: none; word-break: break-word; }
.mix-list a:hover { text-decoration: underline; }
.audit-list { grid-template-columns: 1fr; gap: 6px; }
.audit-list li { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 4px 12px; }
.audit-meta { overflow-wrap: anywhere; font-size: 12px; }
.mix-tags { display: flex; gap: 4px; flex-wrap: wrap; }

/* ============================================================ 레이아웃 분기 */
/* ---- ≥1024px: 왼쪽 사이드바 */
@media (min-width: 1024px) {
  html[data-sidebar="collapsed"] { --sidebar-w: 72px; }
  body { padding-left: var(--sidebar-w); transition: padding-left 0.2s ease; }
  .topbar { position: fixed; top: 0; left: 0; bottom: 0; width: var(--sidebar-w); border-bottom: 0; border-right: 1px solid var(--border); overflow: visible; transition: width 0.2s ease; }
  .topbar-inner { flex-direction: column; align-items: stretch; height: 100%; padding: 20px 14px 18px; gap: 0; }
  .brand { padding: 4px 6px; margin-bottom: 22px; }
  /* 접기/펼치기 토글: 사이드바 오른쪽 가장자리에 걸친 둥근 버튼(브랜드 줄 높이). 쉐브론은 접히면 180° */
  .sb-toggle {
    display: inline-flex; align-items: center; justify-content: center; position: absolute; top: 24px; right: -14px; z-index: 2; width: 28px; height: 28px; padding: 0;
    border-radius: 50%; background: var(--surface); border: 1px solid var(--border); color: var(--text-2); cursor: pointer; box-shadow: var(--shadow-pop);
    transition: background 0.12s ease, color 0.12s ease;
  }
  .sb-toggle:hover { background: var(--surface-3); color: var(--text); }
  .sb-toggle-ico { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.2s ease; }
  html[data-sidebar="collapsed"] .sb-toggle-ico { transform: rotate(180deg); }
  /* 접힌 상태(72px): 아이콘만. 라벨은 시각적으로만 숨겨 접근 가능한 이름은 유지하고, title 이 툴팁을 맡는다 */
  html[data-sidebar="collapsed"] .topbar-inner { padding-left: 12px; padding-right: 12px; }
  html[data-sidebar="collapsed"] .brand { justify-content: center; padding: 4px 0; gap: 0; }
  html[data-sidebar="collapsed"] .brand-text, html[data-sidebar="collapsed"] .nav-label, html[data-sidebar="collapsed"] .seg-label, html[data-sidebar="collapsed"] #logout-btn .btn-label {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
  }
  html[data-sidebar="collapsed"] .nav a { justify-content: center; padding: 10px 0; gap: 0; }
  html[data-sidebar="collapsed"] .topbar-right { align-items: center; }
  html[data-sidebar="collapsed"] .topbar-right .seg { flex-direction: column; gap: 2px; width: 100%; }
  html[data-sidebar="collapsed"] .topbar-right .seg button { width: 100%; height: 32px; padding: 0; gap: 0; }
  html[data-sidebar="collapsed"] .demo-chip { font-size: 0; gap: 0; padding: 0; width: 24px; height: 24px; justify-content: center; align-self: center; }
  html[data-sidebar="collapsed"] .demo-chip::before { width: 8px; height: 8px; }
  html[data-sidebar="collapsed"] #logout-btn { width: 40px; padding: 0; align-self: center; }
  .nav { flex-direction: column; gap: 2px; }
  .nav a { padding: 10px 12px; font-size: 14px; }
  .nav a[aria-current="page"] { box-shadow: inset 3px 0 0 var(--ink-bg); }
  .topbar-right { margin-left: 0; margin-top: auto; flex-direction: column; align-items: stretch; gap: 10px; padding-top: 16px; border-top: 1px solid var(--border); }
  .topbar-right .seg { justify-content: stretch; }
  .topbar-right .seg button { flex: 1 1 0; justify-content: center; padding: 0 4px; gap: 4px; }
  .demo-chip { align-self: flex-start; }
  #logout-btn { width: 100%; height: 36px; font-size: 13px; }
  .page { padding-top: 32px; }
}

/* ---- ≥1200px: 목록 표 머리글 sticky(표가 카드 폭에 들어가므로 가로 스크롤 상자를 풀고 뷰포트 기준으로 고정) */
@media (min-width: 1200px) {
  .list-card .table-wrap { overflow: visible; }
  .view-stocks .list-card .data-table thead th, .view-crypto .list-card .data-table thead th { position: sticky; top: 60px; z-index: 2; }
}

/* ---- <1024px: 상단 바 + 하단 탭 바 */
@media (max-width: 1023.98px) {
  .filters { top: var(--topbar-h); }
  .page { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px) + 32px); }
  .footer { padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px)); }
  .nav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; display: flex; justify-content: space-around; gap: 0;
    height: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px)); padding: 6px 4px calc(env(safe-area-inset-bottom, 0px) + 4px);
    background: var(--surface); border-top: 1px solid var(--border);
  }
  .nav a {
    flex: 1 1 0; min-width: 0; flex-direction: column; justify-content: center; gap: 3px; padding: 4px 2px; border-radius: 10px;
    font-size: 11px; font-weight: 500; color: var(--text-3);
  }
  .nav-ico { width: 22px; height: 22px; }
  .nav a[aria-current="page"] { background: transparent; color: var(--text); font-weight: 650; }
  .nav a[aria-current="page"] .nav-ico { stroke-width: 2.2; }
  .nav a:hover { background: transparent; }
  .nav a:focus-visible { outline-offset: -2px; }
}

@media (max-width: 860px) {
  .index-grid { grid-template-columns: minmax(0, 1fr); }
  .hero-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---- 640~1023px(태블릿): 표는 유지하되 열이 짓눌리지 않게 최소 폭을 주고 카드 안에서만 가로 스크롤한다 */
@media (min-width: 640px) and (max-width: 1023.98px) {
  .stock-table { min-width: 700px; }
  .bb-scan-table { min-width: 640px; }
  .data-table th, .data-table td { padding-left: 8px; padding-right: 8px; }
}

/* ---- <640px: 모바일 — 컴팩트 거터·카드, 세그먼트는 아이콘만, 목록 표는 카드 리스트 */
@media (max-width: 639.98px) {
  :root { --gutter: 16px; --card-pad: 16px; --card-gap: 16px; }
  .page { padding-top: 16px; }
  .topbar-inner { padding: 0 12px; gap: 8px; }
  .brand-text { font-size: 14px; }
  .brand-sub { display: none; }
  .seg button { padding: 0 8px; height: 30px; }
  .seg-label { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
  .seg-ico { width: 16px; height: 16px; }
  #logout-btn { height: 34px; width: 34px; padding: 0; border-radius: 999px; }
  #logout-btn .btn-label { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
  .page-title { font-size: 20px; }
  .search { flex: 1 1 100%; }
  .search input { width: 100%; }
  .hide-sm { display: none; }
  .sub-sm { display: block; }
  .crypto-table .sub-sm { display: none; }        /* 가상화폐 카드: 유의 태그 열이 보이므로 영문명 · 마켓 줄(.sub-line)을 그대로 둔다 */
  .crypto-table .stock-name { word-break: keep-all; }
  .kpi { padding: 12px 14px; }
  .kpi-value { font-size: 20px; }
  .kpi-value.kpi-primary { font-size: 26px; }
  .hero-change { font-size: 18px; }
  .hero-name h1 { font-size: 20px; }
  .chip { height: 34px; }
  .chart-actions { margin-left: auto; }
  .chart-sub { word-break: keep-all; }
  .filters { gap: 8px 10px; }
  .filter-chips { flex-wrap: nowrap; overflow-x: auto; gap: 10px; margin: -4px calc(var(--gutter) * -1); padding: 4px var(--gutter); scrollbar-width: none; }
  .filter-chips::-webkit-scrollbar { display: none; }
  .filter-chips > .chip-group { flex-wrap: nowrap; flex: none; }
  .filter-chips > .chip, .filter-chips > .btn { flex: none; }
  .view-bb .filters { position: static; background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; padding: 0; }
  .view-bb .filter-chips { flex-wrap: wrap; overflow: visible; margin: 0; padding: 0; gap: 8px 12px; }
  .view-bb .filter-chips > .chip-group { flex-wrap: wrap; flex: 0 1 auto; max-width: 100%; }
  /* 볼린저 설정 패널: 좁은 화면에서는 세로 배치(가로 스크롤 없이) */
  .bb-bar { align-items: flex-start; }
  .bb-settings { width: 100%; }
  .bb-settings-body { flex-direction: column; align-items: flex-start; gap: 10px; }
  .bb-settings-body .chip-group { max-width: 100%; }
  .check-group { flex-direction: column; gap: 8px; }
  .check { white-space: normal; }
  .kv { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .tooltip { max-width: 240px; }

  /* 목록 표(종목·가상화폐·스캔) → 카드 리스트: <table> 구조는 유지하고(정렬·접근성·테스트 훅), 행을 그리드 카드로 바꾼다.
     머리글은 정렬 버튼이 있는 열만 가로 스크롤 칩 줄로 남긴다. */
  .list-card .data-table, .list-card .data-table tbody { display: block; }
  .list-card .data-table thead { display: block; }
  .list-card .data-table thead tr { display: flex; gap: 6px; overflow-x: auto; padding: 2px 0 12px; scrollbar-width: none; }
  .list-card .data-table thead tr::-webkit-scrollbar { display: none; }
  .list-card .data-table thead th { display: none; box-shadow: none; background: transparent; padding: 0; }
  .list-card .data-table thead th:has(.th-btn) { display: block; flex: none; }
  .list-card .data-table thead th .th-btn { height: 30px; padding: 0 11px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface); color: var(--text-2); font-size: 12px; }
  .list-card .data-table thead th[aria-sort="ascending"] .th-btn, .list-card .data-table thead th[aria-sort="descending"] .th-btn { background: var(--ink-bg); border-color: var(--ink-bg); color: var(--ink-fg); }
  .list-card .data-table thead th[aria-sort="ascending"] .th-btn:hover, .list-card .data-table thead th[aria-sort="descending"] .th-btn:hover { color: var(--ink-fg); }
  .list-card .data-table thead th.num .th-btn { text-align: left; }
  .list-card .data-table tbody tr {
    display: grid; grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "name close star" "name chg star" "meta1 meta2 meta3";
    column-gap: 10px; row-gap: 3px; align-items: center; padding: 12px var(--card-pad); border-bottom: 1px solid var(--grid);
  }
  .list-card .data-table tbody tr:last-child { border-bottom: 0; }
  .list-card .data-table thead tr { padding-left: var(--card-pad); padding-right: var(--card-pad); }
  .list-card .data-table tbody td { display: block; padding: 0; border: 0; text-align: left; white-space: normal; min-width: 0; }
  .list-card .table-wrap > .data-table tbody td:first-child, .list-card .table-wrap > .data-table tbody td:last-child { padding-left: 0; padding-right: 0; }
  .list-card .data-table tbody td.num { text-align: right; }
  .list-card .data-table td[data-label]::before { content: attr(data-label) " "; color: var(--text-3); font-size: 12px; }
  .list-card .data-table td[data-label] { font-size: 12px; color: var(--text-2); }

  /* 종목: 1 코드 · 2 이름 · 3 시장 · 4 종가 · 5 등락률 · 6 거래량 · 7 최신일 · 8 출처 · 9 관심 */
  .stock-table:not(.crypto-table) tbody td:nth-child(1), .stock-table:not(.crypto-table) tbody td:nth-child(3) { display: none; }
  .stock-table:not(.crypto-table) tbody td:nth-child(2) { grid-area: name; }
  .stock-table:not(.crypto-table) tbody td:nth-child(4) { grid-area: close; font-size: 15px; font-weight: 650; }
  .stock-table:not(.crypto-table) tbody td:nth-child(5) { grid-area: chg; }
  .stock-table:not(.crypto-table) tbody td:nth-child(6) { grid-area: meta1; text-align: left; }
  .stock-table:not(.crypto-table) tbody td:nth-child(7) { grid-area: meta2; text-align: right; }
  .stock-table:not(.crypto-table) tbody td:nth-child(8) { grid-area: meta3; justify-self: center; }
  .stock-table:not(.crypto-table) tbody td:nth-child(9) { grid-area: star; justify-self: center; }
  /* 가상화폐: 1 마켓 · 2 이름 · 3 종가 · 4 등락률 · 5 거래대금 · 6 거래량 · 7 최신일 · 8 유의 · 9 관심 */
  .list-card .crypto-table tbody td:nth-child(1), .crypto-table tbody td:nth-child(6) { display: none; }
  .list-card .crypto-table tbody td:nth-child(2) { grid-area: name; }
  .list-card .crypto-table tbody td:nth-child(3) { grid-area: close; font-size: 15px; font-weight: 650; }
  .list-card .crypto-table tbody td:nth-child(4) { grid-area: chg; }
  .list-card .crypto-table tbody td:nth-child(5) { grid-area: meta1; text-align: left; }
  .list-card .crypto-table tbody td:nth-child(7) { grid-area: meta2; text-align: right; }
  .list-card .crypto-table tbody td:nth-child(8) { grid-area: meta3; justify-self: center; display: flex; gap: 4px; }
  .list-card .crypto-table tbody td:nth-child(9) { grid-area: star; justify-self: center; }
  /* 스캔: 1 날짜 · 2 종목명 · 3 전략 · 4 종가 · 5 %B · 6 밴드폭 · 7 확인 · 8 관심 */
  .bb-scan-table thead { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; }
  .list-card .bb-scan-table tbody tr { grid-template-areas: "name close star" "strategy pctb star" "meta1 meta2 meta3"; }
  .list-card .bb-scan-table tbody td:nth-child(1) { grid-area: meta1; color: var(--text-3); font-size: 12px; }
  .list-card .bb-scan-table tbody td:nth-child(2) { grid-area: name; }
  .list-card .bb-scan-table tbody td:nth-child(3) { grid-area: strategy; display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
  .list-card .bb-scan-table tbody td:nth-child(4) { grid-area: close; font-size: 15px; font-weight: 650; }
  .list-card .bb-scan-table tbody td:nth-child(5) { grid-area: pctb; }
  .list-card .bb-scan-table tbody td:nth-child(6) { grid-area: meta2; }
  .list-card .bb-scan-table tbody td:nth-child(7) { grid-area: meta3; }
  .list-card .bb-scan-table tbody td:nth-child(8) { grid-area: star; justify-self: center; }

  /* 최근 실행 표: 좁은 화면에서는 한 행을 3줄 카드로 접는다(표가 가로로 길어져 오류 칸이 한 글자씩 꺾이는 것을 막음) */
  .runs-table thead {
    position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
  }
  .runs-table, .runs-table tbody { display: block; }
  .runs-table tr.run-row {
    display: grid; grid-template-columns: 2.8em minmax(0, 1fr) auto auto; gap: 4px 10px; align-items: center;
    grid-template-areas: "id cmd src st" "time time req rows" "err err err err";
    padding: 12px var(--card-pad); border-bottom: 1px solid var(--grid);
  }
  .runs-table tbody tr.run-row:last-child { border-bottom: 0; }
  .runs-table td, .runs-table td.num, .table-wrap > .runs-table tbody td:first-child, .table-wrap > .runs-table tbody td:last-child { display: block; padding: 0; border: 0; text-align: left; white-space: normal; }
  .runs-table .run-id { grid-area: id; font-weight: 650; }
  .runs-table .run-cmd { grid-area: cmd; font-weight: 500; }
  .runs-table .run-src { grid-area: src; }
  .runs-table .run-st { grid-area: st; justify-self: end; }
  .runs-table .run-time { grid-area: time; white-space: nowrap; color: var(--text-2); }
  .runs-table .run-req { grid-area: req; white-space: nowrap; color: var(--text-2); }
  .runs-table .run-rows { grid-area: rows; white-space: nowrap; color: var(--text-2); }
  .runs-table td[data-label]::before { content: attr(data-label) " "; color: var(--text-3); }
  .runs-table .run-err { grid-area: err; }
  .runs-table .run-msg { max-width: none; }
}

@media (max-width: 400px) {
  .hero-kpis { gap: 8px; }
  .kpi { padding: 10px 12px; }
}

/* 아주 좁은 폭(≤374px)에서 로그아웃 버튼까지 붙으면 상단 바가 모자란다 — 데모 칩은 점만 남긴다(글자는 font-size 0 으로 시각만 숨겨 접근 가능한 이름은 유지) */
@media (max-width: 374px) {
  .topbar-right:has(#logout-btn) .demo-chip { font-size: 0; gap: 0; padding: 0 7px; height: 22px; }
  .topbar-right:has(#logout-btn) .demo-chip::before { width: 8px; height: 8px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; scroll-behavior: auto !important; }
}

@media print {
  body { padding-left: 0; }
  .topbar, .filters, .chart-actions, .pager, .nav { display: none; }
  .card { box-shadow: none; }
}

/* 로그인 화면 스타일 — worker/scripts/sync-static.mjs 가 Worker 빌드(worker/public/style.css)의 끝에 이어 붙인다.
 * 로컬 대시보드의 style.css(정본)에는 들어가지 않는다. 인증 전에 열리는 자산은 /style.css 하나뿐이라(src/assets.ts 공개 목록) 별도 파일로 둘 수 없다.
 * 토큰(--surface·--border·--ink-bg 등)과 브랜드 마크 클래스(.brand-mark·.bm-*)는 위 본문과 같은 것을 쓰므로 라이트·다크·수동 테마가 그대로 따라간다. 인라인 style 속성 없음.
 * 배경: 페이지색 위에 상승(빨강)·하락(파랑) 마크색을 아주 옅게 섞은 방사형 그라디언트 두 겹 — background-color 는 --page 그대로라 테마 판정이 바뀌지 않는다. */

.login-body {
  background-color: var(--page);
  background-image:
    radial-gradient(640px 420px at 12% 0%, color-mix(in srgb, var(--series-1) 11%, transparent), transparent 70%),
    radial-gradient(560px 400px at 92% 100%, color-mix(in srgb, var(--series-8) 9%, transparent), transparent 70%);
  background-repeat: no-repeat;
}
.login-main { flex: 1; display: flex; align-items: center; justify-content: center; padding: 40px 16px 64px; }
.login-card { width: 100%; max-width: 400px; padding: 32px 28px 28px; border-radius: 20px; }

.login-brand { display: flex; align-items: center; gap: 12px; }
.login-brand .brand-mark { width: 40px; height: 40px; flex: none; }
.login-title { display: flex; flex-direction: column; font-size: 20px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.15; }
.login-title .brand-sub { margin: 2px 0 0; font-size: 12px; }
.login-lead { margin-top: 16px; color: var(--text-2); font-size: 13px; line-height: 1.6; word-break: keep-all; }
.login-form { margin-top: 24px; display: grid; gap: 14px; }

.field { display: grid; gap: 6px; }
.field label { font-size: 13px; font-weight: 600; color: var(--text-2); }
.field input {
  width: 100%; height: 44px; padding: 0 14px; border-radius: var(--radius-sm); background: var(--surface);
  border: 1px solid var(--border); color: var(--text); font-size: 16px; transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
.field input:focus { border-color: var(--border-strong); }
.field input:disabled { opacity: 0.6; }
.field input[aria-invalid="true"] { border-color: var(--critical); box-shadow: 0 0 0 3px color-mix(in srgb, var(--critical) 18%, transparent); }

.login-error {
  display: flex; align-items: flex-start; gap: 8px; padding: 10px 12px; border-radius: var(--radius-sm); font-size: 13px; line-height: 1.5; color: var(--text); word-break: keep-all;
  background: color-mix(in srgb, var(--critical) 10%, var(--surface)); border: 1px solid color-mix(in srgb, var(--critical) 45%, transparent);
}
.login-error::before { content: "!"; flex: none; width: 18px; height: 18px; border-radius: 50%; background: var(--critical); color: #fff; font-size: 12px; font-weight: 700; line-height: 18px; text-align: center; margin-top: 1px; }

.btn-primary {
  margin-top: 4px; height: 44px; font-size: 14px; font-weight: 600; border-radius: var(--radius-sm);
  background: var(--ink-bg); color: var(--ink-fg); border-color: var(--ink-bg);
}
.btn-primary:hover { background: var(--ink-bg); color: var(--ink-fg); opacity: 0.88; }
.btn-primary:disabled { background: var(--ink-bg); color: var(--ink-fg); }

.login-foot { margin-top: 22px; font-size: 12px; color: var(--text-3); text-align: center; }

@media (max-width: 639.98px) {
  .login-main { padding: 24px 16px 48px; }
  .login-card { padding: 26px 20px 22px; }
}
