world-map.scss 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // ─────────────────────────────────────────────────────────────
  2. // 메인 세계지도 (WorldMarketMap) — 주요국 증시지수 핀
  3. // 색은 토큰/반투명 리터럴만 사용(라이트·다크 양립). 등락색은 --price-up/down/flat(상승 적/하락 청)
  4. // ─────────────────────────────────────────────────────────────
  5. .world-map {
  6. // 지도 전용 반투명 톤 — 패널 배경 위에 얹혀 양 테마에서 자연스럽게 블렌딩
  7. --az-map-ocean-1: rgba(46, 110, 190, 0.20);
  8. --az-map-ocean-2: rgba(46, 110, 190, 0.04);
  9. --az-map-land: rgba(140, 158, 180, 0.32);
  10. --az-map-land-edge: rgba(150, 168, 190, 0.55);
  11. --az-map-grid: rgba(130, 145, 170, 0.16);
  12. margin-bottom: var(--sp-6);
  13. padding: var(--sp-4);
  14. background: var(--bg-elevated);
  15. border: 1px solid var(--border-default);
  16. border-radius: var(--radius);
  17. &__head {
  18. display: flex;
  19. align-items: center;
  20. justify-content: space-between;
  21. flex-wrap: wrap;
  22. gap: var(--sp-3);
  23. margin-bottom: var(--sp-3);
  24. }
  25. &__title {
  26. font-size: var(--fs-lg);
  27. font-weight: 700;
  28. color: var(--text-primary);
  29. }
  30. &__meta {
  31. display: flex;
  32. align-items: center;
  33. gap: var(--sp-4);
  34. font-size: var(--fs-xs);
  35. color: var(--text-muted);
  36. }
  37. &__legend {
  38. display: inline-flex;
  39. align-items: center;
  40. gap: var(--sp-2);
  41. }
  42. &__dot {
  43. display: inline-block;
  44. width: 8px;
  45. height: 8px;
  46. border-radius: 50%;
  47. &--up {
  48. background: var(--price-up);
  49. margin-left: var(--sp-2);
  50. }
  51. &--down {
  52. background: var(--price-down);
  53. margin-left: var(--sp-3);
  54. }
  55. }
  56. &__asof {
  57. font-variant-numeric: tabular-nums;
  58. }
  59. // 무대 — 등거리 크롭 비율(1000×400) 고정, 툴팁 기준 컨테이너
  60. &__stage {
  61. position: relative;
  62. width: 100%;
  63. aspect-ratio: 1000 / 400;
  64. }
  65. &__svg {
  66. width: 100%;
  67. height: 100%;
  68. display: block;
  69. }
  70. &__empty {
  71. display: flex;
  72. align-items: center;
  73. justify-content: center;
  74. width: 100%;
  75. height: 100%;
  76. font-size: var(--fs-sm);
  77. color: var(--text-muted);
  78. }
  79. // 격자
  80. &__grid line {
  81. stroke: var(--az-map-grid);
  82. stroke-width: 1;
  83. }
  84. // 대륙 (실제 지형 path)
  85. &__land path {
  86. fill: var(--az-map-land);
  87. stroke: var(--az-map-land-edge);
  88. stroke-width: 0.6;
  89. stroke-linejoin: round;
  90. vector-effect: non-scaling-stroke;
  91. }
  92. // 핀 — 그룹 color 로 방향색을 상속, dot/pulse 는 currentColor
  93. &__pin {
  94. cursor: pointer;
  95. outline: none;
  96. &--up {
  97. color: var(--price-up);
  98. }
  99. &--down {
  100. color: var(--price-down);
  101. }
  102. &--flat {
  103. color: var(--price-flat);
  104. }
  105. }
  106. &__pin-dot {
  107. fill: currentColor;
  108. filter: drop-shadow(0 0 3px currentColor);
  109. transition: r 0.15s ease;
  110. }
  111. &__pin-core {
  112. fill: rgba(255, 255, 255, 0.92);
  113. pointer-events: none;
  114. }
  115. // 확산 링 (상승/하락 핀) — 중심 기준 확대·소멸 반복
  116. &__pulse {
  117. fill: currentColor;
  118. opacity: 0.5;
  119. transform-box: fill-box;
  120. transform-origin: center;
  121. animation: wm-pulse 2.4s ease-out infinite;
  122. pointer-events: none;
  123. }
  124. // 활성(hover/focus) 핀 강조 링
  125. &__pin.is-active &__pin-dot {
  126. stroke: rgba(255, 255, 255, 0.9);
  127. stroke-width: 1.5;
  128. }
  129. // 툴팁 — 활성 핀 위에 부유
  130. &__tip {
  131. position: absolute;
  132. transform: translate(-50%, -128%);
  133. min-width: 132px;
  134. padding: var(--sp-3) var(--sp-4);
  135. background: var(--bg-page);
  136. border: 1px solid var(--border-strong);
  137. border-radius: var(--radius);
  138. box-shadow: 0 var(--sp-2) var(--sp-4) var(--shadow-color);
  139. pointer-events: none;
  140. z-index: 2;
  141. }
  142. &__tip-head {
  143. display: flex;
  144. align-items: baseline;
  145. gap: var(--sp-2);
  146. margin-bottom: var(--sp-2);
  147. }
  148. &__tip-country {
  149. font-size: var(--fs-xs);
  150. font-weight: 700;
  151. color: var(--text-primary);
  152. }
  153. &__tip-name {
  154. font-size: var(--fs-2xs);
  155. color: var(--text-muted);
  156. white-space: nowrap;
  157. }
  158. &__tip-close {
  159. font-size: var(--fs-lg);
  160. font-weight: 700;
  161. font-variant-numeric: tabular-nums;
  162. color: var(--text-primary);
  163. }
  164. &__tip-change {
  165. display: flex;
  166. align-items: baseline;
  167. justify-content: space-between;
  168. gap: var(--sp-3);
  169. margin-top: var(--sp-1);
  170. font-size: var(--fs-sm);
  171. font-weight: 600;
  172. font-variant-numeric: tabular-nums;
  173. &--up {
  174. color: var(--price-up);
  175. }
  176. &--down {
  177. color: var(--price-down);
  178. }
  179. &--flat {
  180. color: var(--price-flat);
  181. }
  182. }
  183. &__tip-exch {
  184. font-size: var(--fs-2xs);
  185. font-weight: 400;
  186. color: var(--text-muted);
  187. }
  188. }
  189. @keyframes wm-pulse {
  190. 0% {
  191. transform: scale(1);
  192. opacity: 0.5;
  193. }
  194. 100% {
  195. transform: scale(2.6);
  196. opacity: 0;
  197. }
  198. }
  199. @media (prefers-reduced-motion: reduce) {
  200. .world-map__pulse {
  201. animation: none;
  202. opacity: 0;
  203. }
  204. }