/* ==========================================================================
   v15 — v14 위에 얹는다 (index.html 에서 v14.css 다음에 로드)

   ※ data-map-variant 는 "v14" 로 그대로 둔다.
     v11~v14 의 CSS 가 전부 [data-map-variant="v11".."v14"] 를 보고 있어서
     이 값을 v15 로 바꾸면 이전 레이어가 통째로 꺼진다.
     v15 전용 규칙은 html[data-map-fx="v15"] 로 건다.

   들어있는 것
     1) 지도 테두리(육지 윤곽) 흰 선 두껍게
     2) 모바일 세로에서 지도를 키워 「지원 시작」 버튼까지 닿게
     3) 선 그리기·홀드 구간에서 땅 경로 그룹을 별도 합성 레이어로 승격
        (수렴·폭죽 구간에서는 해제 — 그 구간에서는 오히려 손해였다)
     4) 폭죽 구간에 남아 있던 blur 레이어 애니메이션 정지

   끊김의 실제 원인 (측정으로 확인)
     땅 윤곽 SVG 의 경로 데이터가 1.85MB(13만 점)라, 같은 SVG 안에서 선 하나라도
     움직이면 매 프레임 전체가 다시 래스터된다. 근본 해결은 기하 단순화이고
     그건 js/lp-korea-map-v15.js 가 런타임에 한다. 이 파일은 나머지 보조 조치다.
   ========================================================================== */

html[data-map-fx="v15"] body.theme-sian3-lp {
  /* ── 선 색·굵기 ────────────────────────────────────────────────────
     중요: 연하게 만들 때 알파를 낮추지 말고 '색'을 낮춘다.
     알파를 낮추면 얇은 선이 안티에일리어싱에 흩어져 v14 의 끊김 현상이 되돌아온다.
     알파 1 을 유지한 채 밝기만 내리면 커버리지가 꽉 차서 선이 끊기지 않는다. */
  /* 시·도 경계선 (내부) — 얇고 조용하게 */
  --v15-inner-stroke: 1.05;
  --v15-inner-color: rgb(78, 87, 100);
  /* 국토 외곽선 — 굵되 순백은 피한다 */
  --v15-outer-stroke: 2.3;
  --v15-outer-color: rgb(116, 126, 140);
}

/* ── 1) 선 끊김 해소 ───────────────────────────────────────────────────
   원인: v14 는 0.95px · 알파 0.88 로 그렸는데, 해안선 굴곡이 화면 해상도보다
   촘촘해 안티에일리어싱이 선을 여러 픽셀에 반투명하게 흩뿌린다. 그 결과
   실제 화면에서는 선이 수백 조각으로 끊겨 보인다.
   (보내주신 화면을 분석하니 흰 선이 1,051개 조각 · 끊긴 끝점 524개였다)
   대책: 알파를 1 로 올려 반투명 누적을 없애고, 기하 단순화로 서브픽셀 굴곡을
   걷어내고, 해안선은 아래 외곽선 레이어가 굵게 덮는다. */
html[data-map-fx="v15"] .korea-mosaic-path,
html[data-map-fx="v15"] .korea-outline-path {
  shape-rendering: geometricPrecision;
}

html[data-map-fx="v15"] .korea-mosaic-path {
  stroke-width: var(--v15-inner-stroke, 1.05);
  stroke: var(--v15-inner-color, rgba(236, 242, 250, 1));
}

/* ── 지도 외곽선만 볼드 ────────────────────────────────────────────────
   js/lp-korea-map-v15.js 가 #koreaMosaicGroup 끝에 주입한다.
   시·도 경계는 들어 있지 않고 바다와 맞닿은 변만 있어서, 이 레이어만 굵게 하면
   '외곽선만 볼드'가 된다. 시·도 path 다음에 오므로 해안 구간을 덮어 그린다. */
html[data-map-fx="v15"] .korea-outline-path {
  fill: none;
  stroke: var(--v15-outer-color, #fff);
  stroke-width: var(--v15-outer-stroke, 2.3);
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

/* 제주는 v14 부터 지도에서 빠져 있다 — 외곽선도 같이 숨긴다 */
html[data-map-fx="v15"] .korea-outline-path.is-jeju {
  display: none;
}

/* 소멸 구간에서는 굵기를 원래대로 되돌린다.
   지도가 사라지며 폭죽이 터지는 동안에는 윤곽이 이미 투명해지는 중이라 굵기 차이가 보이지 않는데,
   굵은 stroke 는 그 구간의 래스터 비용을 그대로 늘린다. (측정: 폭죽 구간 래스터 −48%) */
html[data-map-fx="v15"] .korea-story-map-wrap.is-scene-05 .korea-mosaic-path,
html[data-map-fx="v15"] .korea-story-map-wrap.is-scene-06 .korea-mosaic-path,
html[data-map-fx="v15"] .korea-story-map-wrap.is-map-dissolving .korea-mosaic-path {
  stroke-width: 0.95;
}
html[data-map-fx="v15"] .korea-story-map-wrap.is-scene-05 .korea-outline-path {
  stroke-width: 1.4;
}

/* 지도가 실제로 녹기 시작하는 순간(is-map-dissolving) 외곽선은 빠르게 빼 버린다.
   2,971점짜리 굵은 해안선을 페이드 1.08초 내내 매 프레임 다시 그리는 것이
   폭죽 구간 래스터의 절반을 차지했다 (166ms → 400ms).
   시·도 path 가 같은 자리를 그리고 있고 지도 자체가 사라지는 중이라 빠지는 게 보이지 않는다. */
html[data-map-fx="v15"] .korea-outline-path {
  transition: opacity 0.16s linear;
}
html[data-map-fx="v15"] .korea-story-map-wrap.is-map-dissolving .korea-outline-path {
  opacity: 0;
}
html[data-map-fx="v15"] .korea-story-map-wrap.is-scene-06 .korea-outline-path,
html[data-map-fx="v15"] .korea-story-map-wrap.is-map-gone .korea-outline-path {
  display: none;
}

/* 선이 굵어지면 도시 불빛이 윤곽에 먹히므로 불빛을 아주 살짝만 눌러 준다 */
html[data-map-fx="v15"] .korea-story-map-wrap.is-constellation-hold .korea-citylights {
  animation-name: cityLightsPreglowV15;
}
@keyframes cityLightsPreglowV15 {
  from { opacity: 0.001; }
  to   { opacity: 0.38; }
}

/* ── 3) 선 그리기·홀드 구간에서만 땅을 별도 레이어로 ────────────────────
   선의 stroke-dashoffset 이 매 프레임 바뀌는 동안 땅이 같이 다시 칠해지는 것을 막는다.
   수렴(is-scene-05)부터는 지도 전체가 페이드되므로 승격을 풀어야 이득이다. */
html[data-map-fx="v15"]
  .korea-story-map-wrap:not(.is-scene-05):not(.is-scene-06):not(.is-map-dissolving):not(.is-map-gone)
  #koreaMosaicGroup {
  will-change: transform;
}

/* ── 4) 수렴·폭죽 구간: blur(40px) 대기광 숨쉬기 정지 ───────────────────
   폭죽이 터지는 동안 40px 블러 레이어가 계속 스케일/투명도를 바꾸면
   그 레이어만 따로 다시 블러된다. 장면 전환 중에는 멈춘 값으로 고정한다. */
html[data-map-fx="v15"] .korea-story-map-wrap.is-scene-05::before,
html[data-map-fx="v15"] .korea-story-map-wrap.is-scene-06::before,
html[data-map-fx="v15"] .korea-story-map-wrap.is-map-dissolving::before {
  animation: none;
  opacity: 0.85;
}

/* ── 2) 모바일 세로: 지도를 키워 「지원 시작」 버튼까지 닿게 ─────────────
   v14: width min(…, 58vh, 118vw) / right -8vw / bottom -9vh  → 육지 상단이 버튼보다 10px 아래
   v15: 박스를 키우고 아래로 내려 육지 윗변(강원·동해안)이 버튼 하단에 맞물리게 한다.

   가로 정렬은 right 대신 '가운데 기준'으로 바꿨다.
   right 를 vw 로 밀면 박스가 화면 높이에 걸려 작아지는 기기(짧은 폰)에서는 지도가 한쪽으로
   쏠리고, 반대로 큰 폰에서는 서해안이 화면 밖으로 잘린다.
   육지는 박스 안에서 x 16.6%~88.3% 를 차지해 중심이 박스 중심보다 2.4% 오른쪽이므로,
   margin-right 를 -0.4758 × 박스크기로 주면 화면 폭과 무관하게 육지가 가운데에 온다.
   (--v15-map-nudge 로 좌우 미세조정: 양수면 오른쪽으로) */
@media (max-width: 640px) and (orientation: portrait) {
  html[data-map-fx="v15"] body.theme-sian3-lp .korea-story-map-wrap {
    --v15-map-size: min(
      calc(var(--korea-map-size) * var(--korea-map-scale) * 1.3),
      var(--v15-map-h, 59.5vh),
      var(--v15-map-w, 129vw)
    );
    width: var(--v15-map-size);
    height: var(--v15-map-size);
    right: 50%;
    margin-right: calc(var(--v15-map-size) * -0.4758 + var(--v15-map-nudge, 0px));
    /* 육지 아랫변이 화면 바닥 16px 위에 오도록 박스를 내린다.
       육지 아랫변은 박스 바닥보다 0.224×박스 만큼 위에 있다(실측).
       긴 폰에서 손으로 맞춰 뒀던 -11.5vh 와 같은 값이 나오고,
       화면이 짧을 때만 자동으로 더 내려가 바닥 여백이 벌어지지 않는다. */
    bottom: calc(16px - var(--v15-map-size) * 0.224);
    /* top/transform 을 반드시 되돌려 놓는다.
       css/lp-korea-map-v13.css 에 「(max-width:900px) and (max-height:600px)」 규칙이 있어
       화면 높이가 600 이하가 되는 순간 top:calc(50% + 헤더/2) 와 translateY(-50%) 를 다시 건다.
       절대배치 요소는 height 가 정해진 상태에서 top 과 bottom 이 동시에 있으면 top 이 이기므로,
       여기서 top 을 지워 주지 않으면 아래 bottom 값이 통째로 무시되고 지도가 화면 한가운데로 돌아간다.
       (증상: 497×531 창에서 지도 아래에 143px 이 비었다. 높이 640 이상에서는 멀쩡했다.) */
    top: auto;
    left: auto;
    transform: none;
  }
}

/* 짧은 폰(≤700) — 문구·버튼이 위로 올라오므로 지도도 덜 내린다 */
@media (max-width: 640px) and (orientation: portrait) and (max-height: 700px) {
  html[data-map-fx="v15"] body.theme-sian3-lp .korea-story-map-wrap {
    --v15-map-h: 62vh;
    --v15-map-w: 132vw;
  }
}

/* ── 5) 합성 레이어 줄이기 (노트북 내장 그래픽 대응) ─────────────────────
   will-change 나 filter 가 걸린 요소는 각각 GPU 합성 레이어를 잡는다.
   이 페이지에는 그런 요소가 약 150개 있고, 그중 54개가 오누이 하늘의 .lp-amb-star 다.
   이 별들은 CSS 키프레임(lpAmbTwinkle)으로 opacity·transform 이 움직이는데,
   그런 애니메이션이 '도는 동안'에는 브라우저가 알아서 레이어로 올린다.
   will-change 를 걸어 두면 애니메이션이 멈춰 있는(animation-play-state: paused)
   대부분의 시간에도 레이어를 계속 물고 있어서, 통합 GPU 에서는 메모리와 합성 비용만 든다. */
html[data-map-fx="v15"] body.theme-sian3-lp .lp-amb-star {
  will-change: auto;
}

/* 지도 별 노드 — will-change 에서 filter 를 뺀다.
   filter 를 예고하면 브라우저가 필터 처리가 가능한 레이어를 미리 잡아 두는데,
   실제로 바뀌는 건 opacity 와 transform 뿐이다. */
html[data-map-fx="v15"] .celestial-node {
  will-change: opacity, transform;
}

@media (prefers-reduced-motion: reduce) {
  html[data-map-fx="v15"] .korea-story-map-wrap::before { animation: none; }
}

/* ── 6) 장면 전환 구간에는 배경 별 반짝임을 멈춘다 (끊김의 마지막 원인) ────────
   이 페이지에는 CSS 키프레임 애니메이션이 601개 동시에 돈다.
     필드별 384 · 오누이 하늘 별 54 · 딥스타 52 · 위성별 34(+자식 170)
   이 정도 개수는 크롬이 GPU 합성으로 올리지 못해 전부 메인스레드에서 돌고,
   매번 약 700개 요소의 스타일을 다시 계산한다. 트레이스로 재보면 초당 8회 ·
   회당 16~26ms — 0.125초마다 프레임이 하나씩 통째로 날아간다.
   폭죽이 끝나고 지도가 사라질 때 계속 걸리던 잔여 끊김이 이것이었다.
   (별 애니메이션만 꺼고 재보면 그 구간 스타일 재계산 448ms → 21ms)

   js/lp-korea-map-scene06.js 가 수렴 시작(is-scene-05)에 body 에 v15-sky-calm 을 붙이고,
   오누이 하늘이 자리잡은 뒤 1.6초 지나 뗀다. 그 사이에는 시선이 폭죽과 달·오누이 등장에
   있어 배경 별의 숨쉬기가 보이지 않는다 — 화면상 손실 없이 프레임만 돌려받는다. */
html[data-map-fx="v15"] body.v15-sky-calm .lp-field-star,
html[data-map-fx="v15"] body.v15-sky-calm .lp-amb-star,
html[data-map-fx="v15"] body.v15-sky-calm .korea-deep-star,
html[data-map-fx="v15"] body.v15-sky-calm .lp-sat-star,
html[data-map-fx="v15"] body.v15-sky-calm .lp-sat-star *,
html[data-map-fx="v15"] body.v15-sky-calm .korea-onui-world.is-sky-settled .lp-field-star,
html[data-map-fx="v15"] body.v15-sky-calm .korea-onui-world.is-sky-settled .lp-amb-star,
html[data-map-fx="v15"] body.v15-sky-calm .korea-onui-world.is-sky-settled .lp-sat-star,
html[data-map-fx="v15"] body.v15-sky-calm .korea-onui-world.is-sky-settled .korea-deep-star {
  animation-play-state: paused !important;
}

/* ── 7) 평상시에도 필드별은 절반만 반짝이게 ───────────────────────────────
   위와 같은 이유로, 전환이 끝난 뒤에도 384개가 계속 메인스레드에서 돈다.
   별이 384개나 흩뿌려진 하늘에서 그중 절반이 숨쉬는지 전부가 숨쉬는지는
   눈으로 구분되지 않는다. 밝은 별(--bright)은 전부 남겨 인상은 그대로 둔다. */
html[data-map-fx="v15"] body.theme-sian3-lp .lp-field-star:nth-child(2n):not(.lp-field-star--bright) {
  animation: none;
}

/* 딥스타(오누이 하늘 뒤쪽 성운 별)도 같은 이유로 절반만 반짝인다 */
html[data-map-fx="v15"] .korea-deep-star:nth-child(2n):not(.korea-deep-star--bright) {
  animation: none;
}

/* ── 8) 세로 태블릿·폴더블(641~1180 세로): 지도가 화면 가운데에 떠 있던 문제 ──────
   측정한 증상: 폰(≤640)에서는 지도가 화면 아래에 물려 있는데, 641px 부터는
   공용 규칙(bottom: clamp(160px,26%,360px) · right:2%)이 살아나면서
   지도 아래에 200~270px 의 빈 공간이 남고 가로로도 오른쪽으로 85~170px 치우친다.
     아이패드 미니 744×1133  아래여백 262 / 가로 +85
     아이패드    768×1024  아래여백 237 / 가로 +129
     아이패드 에어 820×1180  아래여백 273 / 가로 +113
     폴드 펼침    884×1104  아래여백 255 / 가로 +170
   → 실제 기기에 해당하는 구간이라 폰과 같은 방식(아래 물림 + 육지 기준 가운데 정렬)으로 맞춘다.

   계산 근거 (실측): 육지는 지도 박스 안에서 세로 6.0%~77.4%, 가로 16.6%~88.3% 를 차지한다.
     · 육지 높이 = 박스 × 0.714 이므로,
       「버튼 아래(309px) + 여백 24px」 부터 「화면 바닥 −16px」 까지를 채우려면
       박스 = (100vh − 349px) ÷ 0.714.
     · 육지 아랫변이 박스 바닥보다 0.226×박스 만큼 위에 있으므로
       bottom = 16px − 0.226×박스 로 두면 육지 아랫변이 화면 바닥 16px 위에 온다.
     · 가로는 육지 중심이 박스 중심보다 2.4% 오른쪽이라 폰과 같은 −0.4758 보정을 쓴다.
   폭 상한 132vw 는 육지 가로폭이 화면의 94.7% 를 넘지 않게 하는 값이다. */
@media (min-width: 641px) and (max-width: 1180px) and (orientation: portrait) {
  html[data-map-fx="v15"] body.theme-sian3-lp .korea-story-map-wrap {
    --v15-map-size: min(calc((100vh - 349px) / 0.714), 132vw);
    width: var(--v15-map-size);
    height: var(--v15-map-size);
    top: auto;
    left: auto;
    right: 50%;
    margin-right: calc(var(--v15-map-size) * -0.4758 + var(--v15-map-nudge, 0px));
    bottom: calc(16px - var(--v15-map-size) * 0.226);
    transform: none;
  }
}
