  /* ════════════════════════════════════════════════════════════════════════════════════════════
     런 마감 카드 (2026-08-25) — 연속 기록이 끊긴 순간의 「탐사 기록」 석판.
     정본·근거 = game/runEndCard.js 머리 주석. 표면 유형 = **연출 표면(D)**이지 모달이 아니다
     (modal_design_system.md §2.2·§10-3: #win류는 모달 문법 관할 밖).

     ⚠️ **새 색·새 부품을 만들지 않았다.** 프레임은 모달과 같은 `modal_canvas.webp` 9-slice,
        글자색은 `--gold` 계열과 `--text`/`--muted`, 깊이는 공용 depth kit(`--lift-lg`/`--sheen`)이다.
     ⚠️ **애니 길이를 JS에 복제하지 않는다** — 길이는 여기에만 있고 JS는 `playClass`로 읽는다
        (연출 헌법 §4.6 · `npm run check:anim`이 대조한다).
     ⚠️ **애니가 걸린 요소에 기본 transform을 두지 않았다** — 이 저장소에서 6회 재발한
        transform 덮어쓰기 함정을 원천 차단하려고, 중앙정렬은 전부 flex가 맡는다
        (`strokeGates.js`의 「함정이다!」 도장이 같은 이유로 같은 선택을 했다).
     ════════════════════════════════════════════════════════════════════════════════════════════ */

  #runEndCard {
    /* ── 석판 치수는 **한 곳에서만** 정한다 (2026-08-25, 전용 에셋 도착) ───────────────────────
       `assets/win/run_end_tablet_landscape.webp` = 1120 × 960 (**7 : 6 가로형**, 세로/가로 0.8571).
       폭을 먼저 정하고 높이를 비율로 따라오게 한다 — 순환 없이 **비율이 항상 지켜진다.**
         · 86vw   = 좁은 화면에서 가장자리 여백
         · 340px  = 큰 화면에서의 상한
       ⚠️ **세로 제약(`64vh`)이 사라진 이유**: 옛 세로형(1:1.79)은 최대 591px까지 커져 짧은 화면에서
          카드 기둥이 넘쳤다. 가로형은 340폭에서도 높이가 291px뿐이라(기둥 총 423px) 320×568에서도
          남는다 — 그래서 제약이 하나 줄었다. 세로형으로 되돌리면 그 제약을 **같이** 되살려야 한다.
       ⚠️ 안쪽 글자 크기도 전부 이 폭에서 나온다(`--reW` 비례). 뷰포트 단위로 따로 매기면 석판과
          글자가 다른 속도로 줄어 카르투슈 밖으로 새어 나간다. */
    --reW: min(86vw, 340px);
    --reH: calc(var(--reW) * 0.8571);
    position: fixed; inset: 0; z-index: 70; display: none;
    flex-direction: column; align-items: center; justify-content: center; gap: 18px;
    padding: 24px 20px calc(24px + env(safe-area-inset-bottom));
    /* #win과 같은 문법의 국소 암전 — 가운데만 눌러 초점을 주고 가장자리는 열어 둔다.
       (전면 불투명 암전은 "화면이 꺼졌다"로 읽혀 정산 표면의 여운을 지운다.) */
    background:
      radial-gradient(circle at 50% 44%, rgba(255,238,150,.16), transparent 54%),
      radial-gradient(ellipse 82% 66% at 50% 46%,
        rgba(8,12,6,.9) 0%, rgba(8,12,6,.84) 46%, rgba(8,12,6,.56) 74%, rgba(8,12,6,.24) 100%);
    backdrop-filter: none;   /* 모바일 perf: blur 없이 그라디언트만 (#win과 동일 판단) */
    opacity: 0;
  }
  #runEndCard.show { animation: reVeilIn .30s ease-out forwards; }
  @keyframes reVeilIn { from { opacity: 0 } to { opacity: 1 } }

  /* ── 기록판 = 오너 제작 석판 한 장 ──────────────────────────────────────────────────────────
     ⚠️ **9-slice(border-image)에서 배경 이미지로 갈아탔다.** 배경은 요소에 고유 높이를 주지 않으므로
        높이를 `--reH`가 직접 물린다 — 감사 4번이 경고한 「배경으로 바꾸면 높이가 무너진다」를 그렇게 막는다.
     ⚠️ **행 비율은 그림에서 실측한 값이다** (PIL로 세로 중앙선 밝기 경계를 읽었다):
          8.8% 위 여백 · 26.9% 열린 돌면(각인+제목) · **27.7% 음각 카르투슈** ·
          28.5% 아래 돌면(연속+구분선+최고기록) · 8.1% 아래 여백
        카르투슈 가로 범위는 20.2~78.8%라 `.reBody`만 좌우를 9% 더 물린다(총 21%).
        석판을 새로 만들면 **이 다섯 값을 다시 재라.** 안 재면 글자가 음각 자리에서 빗나간다.
     ⚠️ 옛 세로형(768×1376)에는 상단 각인 띠와 **금빛 선이 구워져 있었다.** 가로형에는 둘 다 없어
        ⑴ 제목이 열린 돌면에 놓이고 ⑵ **CSS 구분선(`.reRule`)이 되살아났다**(아래). */
  #runEndCard .reTablet {
    position: relative;
    width: var(--reW); height: var(--reH);
    box-sizing: border-box;
    background: url('../../assets/win/run_end_tablet_landscape.webp') center / 100% 100% no-repeat;
    display: grid;
    grid-template-rows: 8.8% 26.9% 27.7% 28.5% 8.1%;
    padding: 0 12%;
    text-align: center;
    filter: drop-shadow(0 18px 44px rgba(0,0,0,.45));
  }
  /* ⚠️ `overflow: hidden`은 **가드다.** 320폭 영어처럼 제목이 두 줄이 되는 조합에서 각인 띠를
     넘치면 글자가 음각 카르투슈 위로 흘러내린다 — 넘칠 바에는 잘리는 편이 낫다(자리가 곧 의미다). */
  #runEndCard .reHead { grid-row: 2; display: flex; flex-direction: column; justify-content: center; overflow: hidden; }
  /* 카르투슈 = 숫자만. 「N판 연속」은 아래 돌면으로 내렸다 — 음각 자리 높이가 27.7%(≈80px)라
     54px 숫자와 나란히 두면 여백이 0이 된다(실측). 숫자만 두면 정확히 가운데 앉는다. */
  #runEndCard .reBody { grid-row: 3; display: flex; flex-direction: column; justify-content: center;
    padding: 0 9%; overflow: hidden; }
  #runEndCard .reFoot { grid-row: 4; display: flex; flex-direction: column; justify-content: center; overflow: hidden; }

  /* 착지 — 「쫀득 물리」(연출 헌법 §4.6). 부피 보존(scaleX × scaleY ≈ 1) · 감쇠 3단 ·
     단계마다 ease-in-out · 착지 후 이동 0. 정본 곡선 = 타이틀 PLAY 버튼 btnNudge.
     ⚠️ fill-mode는 `backwards`다. `both`면 끝난 뒤에도 100% 프레임이 눌러앉아 이후 상태를 이긴다. */
  #runEndCard.show .reTablet { animation: reTabletLand .92s cubic-bezier(.22,.9,.3,1) backwards; }
  @keyframes reTabletLand {
    0%   { opacity: 0; transform: translateY(-26px) scaleX(.90) scaleY(1.12); animation-timing-function: ease-in }
    38%  { opacity: 1; transform: translateY(0)     scaleX(1.10) scaleY(.90); animation-timing-function: ease-in-out }
    62%  { transform: scaleX(.965) scaleY(1.04); animation-timing-function: ease-in-out }
    82%  { transform: scaleX(1.018) scaleY(.985); animation-timing-function: ease-in-out }
    100% { transform: scaleX(1) scaleY(1) }
  }

  /* ── 새겨진 글자 ────────────────────────────────────────────────────────────────────────────
     "새김"은 색이 아니라 **음각 그림자**로 만든다 — 아래로 밝은 선, 위로 어두운 선. */
  #runEndCard .reKicker {
    display: block; font-size: max(9px, calc(var(--reW) * .0353)); letter-spacing: .22em; font-weight: 800;
    color: #b6a480; text-shadow: 0 1px 0 rgba(0,0,0,.42);
  }
  #runEndCard .reTitle {
    margin: 1% 0 0; font-family: 'Jua', system-ui, sans-serif;
    font-size: max(12px, calc(var(--reW) * .0618)); line-height: 1.18;
    color: var(--gold-pale);
    text-shadow: 0 2px 0 var(--gold-deep), 0 -1px 0 rgba(0,0,0,.35);
  }
  /* 큰 숫자 + 단위는 **베이스라인으로 묶는다** — 단위를 아래로 흘리면 두 줄로 읽혀 숫자의 크기가 죽는다. */
  #runEndCard .reScoreRow {
    display: flex; align-items: baseline; justify-content: center; gap: 3px;
  }
  #runEndCard .reScore {
    font-family: 'Jua', system-ui, sans-serif;
    font-size: max(26px, calc(var(--reW) * .1470)); line-height: 1.05;
    color: var(--gold);
    text-shadow: 0 3px 0 var(--gold-deep), 0 0 18px rgba(255,224,122,.35), 0 -1px 0 rgba(0,0,0,.4);
    font-variant-numeric: tabular-nums;   /* 카운트업 중 자릿수가 흔들리지 않는다 */
  }
  /* 단위는 **작고 조용하다.** 숫자를 설명할 뿐 숫자와 경쟁하면 안 된다(연출 헌법 §4.1 「주인공은 하나」). */
  #runEndCard .reUnit {
    font-family: 'Jua', system-ui, sans-serif; font-size: max(11px, calc(var(--reW) * .0470));
    color: var(--gold-pale); opacity: .82; text-shadow: 0 2px 0 var(--gold-deep);
  }
  /* ── 신기록 정점은 **큰 숫자에서** 일어난다 (2026-08-25 감사) ──────────────────────────────────
     옛 구현은 15px짜리 「새 최고 기록」 줄만 금빛이 되고 주인공인 숫자는 가만히 있었다 — 스윕이 판
     전체를 지나가는데 화면이 무엇을 축하하는지 안 가리켰다. 이제 숫자가 **한 번 더 깊이 새겨진다**:
     살짝 눌렸다가(부피 보존: 가로가 퍼지면 세로가 눌린다) 제자리로 돌아오며 발광이 한 번 밝아진다.
     ⚠️ 파티클·화면 흔들림은 쓰지 않는다 — 이 화면에는 흔들 카메라가 없고, 헌법 §4.6이 「자리를 잡은
        뒤에는 이동도 회전도 없다」로 못박는다. 여기서 변하는 것은 **깊이와 빛**뿐이다. */
  #runEndCard .reScore.engrave { animation: reScoreEngrave .78s ease-out backwards; }
  @keyframes reScoreEngrave {
    0%   { transform: scaleX(1) scaleY(1);
           text-shadow: 0 3px 0 var(--gold-deep), 0 0 18px rgba(255,224,122,.35), 0 -1px 0 rgba(0,0,0,.4);
           animation-timing-function: ease-in }
    26%  { transform: scaleX(1.05) scaleY(.94);
           text-shadow: 0 2px 0 var(--gold-deep), 0 0 34px rgba(255,238,170,.9), 0 -1px 0 rgba(0,0,0,.5);
           animation-timing-function: ease-in-out }
    58%  { transform: scaleX(.985) scaleY(1.02);
           text-shadow: 0 3px 0 var(--gold-deep), 0 0 26px rgba(255,238,170,.6), 0 -1px 0 rgba(0,0,0,.42);
           animation-timing-function: ease-in-out }
    100% { transform: scaleX(1) scaleY(1);
           text-shadow: 0 3px 0 var(--gold-deep), 0 0 18px rgba(255,224,122,.35), 0 -1px 0 rgba(0,0,0,.4) }
  }
  #runEndCard .reStats {
    display: block; font-size: max(11px, calc(var(--reW) * .0412)); font-weight: 800;
    color: #efe3c6; text-shadow: 0 1px 0 rgba(0,0,0,.45);
  }
  /* 구분선 — **가로형 석판에는 금빛 선이 구워져 있지 않아 되살렸다.** CSS가 그리므로 글자 사이에서
     콘텐츠를 따라간다. ⚠️ 세로형(`run_end_tablet.webp`)으로 되돌리면 그림의 선과 겹쳐 두 줄이 된다. */
  #runEndCard .reRule {
    display: block; height: 1px; margin: 5% 14% 4%;
    background: linear-gradient(90deg, transparent, rgba(120,96,52,.42), transparent);
  }
  #runEndCard .reBest {
    display: block; font-size: max(10px, calc(var(--reW) * .0382)); font-weight: 800;
    color: #d9cba9; text-shadow: 0 1px 0 rgba(0,0,0,.4);
  }
  /* 신기록 티어에서만 최고 기록 줄이 금빛으로 승격된다 — 「기록을 깬 순간」이 이 화면의 정점이다. */
  #runEndCard.isBest .reBest {
    color: var(--gold-pale); font-size: max(11px, calc(var(--reW) * .0441));
    text-shadow: 0 2px 0 var(--gold-deep), 0 0 14px rgba(255,224,122,.45);
  }

  /* 박자별 등장. 이동은 아주 짧게(6px) — 「새겨진다」는 인상이라 날아 들어오면 안 된다. */
  #runEndCard .reTitle,
  #runEndCard .reScoreRow,
  #runEndCard .reStats,
  #runEndCard .reRule,
  #runEndCard .reBest,
  #runEndCard .reSha { opacity: 0; transform: translateY(6px); transition: opacity .34s ease, transform .34s ease; }
  #runEndCard.beat1 .reTitle,
  #runEndCard.beat1 .reScoreRow { opacity: 1; transform: none; }
  #runEndCard.beat2 .reStats,
  #runEndCard.beat2 .reRule { opacity: 1; transform: none; }
  #runEndCard.beat3 .reBest { opacity: 1; transform: none; }
  #runEndCard.beat4 .reSha { opacity: 1; transform: none; }

  /* ── 금빛 스윕 (신기록 전용) ────────────────────────────────────────────────────────────────
     기록판 위를 한 번 훑고 사라진다. 빛은 「눌릴 몸이 없는 것」이라 쫀득 물리 대상이 아니다
     (연출 헌법 §4.6 적용 제외 목록). */
  /* 🚨 **자르는 층과 움직이는 막대를 갈랐다 (2026-08-25 감사).** 옛 구조는 스윕 자신이
     `inset:-40% -60%`로 넘쳐 흘러, 석판의 **투명한 바깥 모서리 허공에도** 빛이 보였다.
     이제 `.reSweep`은 절대배치라 **패딩 상자**(= 36px 테두리 안쪽 = 돌 표면) 기준으로 앉고
     그 자리에서 자른다. 전용 석판(투명 외곽)으로 갈아도 이 층이 곧 「안전 영역」이라 그대로 유효하다.
     ⚠️ 불규칙한 알파 외곽까지 정확히 따라가야 하면 이 층에 `mask-image: url(<석판>)`을 주면 된다 —
        `.reSweepBar`가 아니라 **이 층**에 준다(막대는 움직이므로 마스크가 같이 움직인다). */
  #runEndCard .reSweep {
    position: absolute; inset: 0; overflow: hidden; pointer-events: none;
    /* 석판의 **알파 모양 그대로** 자른다. 직사각형으로만 자르면 투명한 바깥 모서리 허공에 빛이 보인다
       (감사 6번). 마스크는 **자르는 층**에 준다 — 막대에 주면 마스크가 막대를 따라 움직인다. */
    -webkit-mask-image: url('../../assets/win/run_end_tablet_landscape.webp');
    mask-image: url('../../assets/win/run_end_tablet_landscape.webp');
    -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  }
  #runEndCard .reSweepBar {
    position: absolute; inset: -40% -60%; opacity: 0;
    background: linear-gradient(105deg, transparent 38%, rgba(255,240,180,.55) 50%, transparent 62%);
  }
  #runEndCard .reSweepBar.run { animation: reSweepRun .82s ease-out backwards; }
  @keyframes reSweepRun {
    0%   { opacity: 0; transform: translateX(-58%) }
    22%  { opacity: 1 }
    100% { opacity: 0; transform: translateX(58%) }
  }

  /* ── 샤 ─────────────────────────────────────────────────────────────────────────────────────
     기록판 **바깥 아래 오른쪽**에 선다. 안에 두면 숫자와 자리를 다투고(연출 헌법 §5 "핵심 보상 숫자를
     가리지 않게"), 기록판이 세로로 늘어나 짧은 화면에서 버튼을 밀어낸다. */
  #runEndCard .reShaWrap { position: relative; width: var(--reW); height: 0; }
  #runEndCard .reSha {
    position: absolute; right: 2px; bottom: -6px;
    width: clamp(84px, 24vw, 108px); height: auto;
    filter: drop-shadow(0 8px 14px rgba(0,0,0,.45));
    pointer-events: none;
  }

  /* ── 유일한 출구 ────────────────────────────────────────────────────────────────────────────
     ⚠️ 처음부터 보이고 처음부터 눌린다 — 「읽기 시간 게이트」 금지(tutorial_redesign_plan.md §7).
        연출이 도는 중에 눌러도 즉시 다음 판으로 간다. */
  #runEndCard .reBtn {
    position: relative; z-index: 2;
    min-width: 168px; min-height: 48px; padding: 12px 26px;
    font-family: 'Jua', system-ui, sans-serif; font-size: 17px;
    color: var(--gold-pale); text-shadow: 0 2px 0 var(--gold-deep);
    background: url('../../assets/common/btn_green.png') center/100% 100% no-repeat;
    border: 0; border-radius: 14px; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform .32s cubic-bezier(.22,1.7,.38,1);
  }
  /* 누름/놓음 = 「쫀득 물리」의 특수형(연출 헌법 §4.6): 누를 때 짧고 단호, 놓을 때 오버슈트 스프링. */
  #runEndCard .reBtn:active { transform: scaleX(1.06) scaleY(.90); transition-duration: .06s; }

  /* ── 저감 모션 ──────────────────────────────────────────────────────────────────────────────
     이동·되튐·스윕만 걷고 **정보는 그대로 남긴다**(연출 헌법 §4.5: 하드 컷으로 문맥을 끊지 않는다).
     JS 쪽도 같은 모드에서 박자 간격을 120ms로 줄이고 카운트업을 즉시 최종값으로 넣는다. */
  html[data-motion="reduced"] #runEndCard.show { animation: none; opacity: 1; }
  html[data-motion="reduced"] #runEndCard.show .reTablet { animation: none; }
  html[data-motion="reduced"] #runEndCard .reSweepBar.run,
  html[data-motion="reduced"] #runEndCard .reScore.engrave { animation: none; }
  html[data-motion="reduced"] #runEndCard .reTitle,
  html[data-motion="reduced"] #runEndCard .reScoreRow,
  html[data-motion="reduced"] #runEndCard .reStats,
  html[data-motion="reduced"] #runEndCard .reRule,
  html[data-motion="reduced"] #runEndCard .reBest,
  html[data-motion="reduced"] #runEndCard .reSha { transition-duration: .14s; transform: none; }

  /* ⚠️ 옛 `@media (max-height: 700px)` 블록은 **삭제했다.** 지금은 `--reW`의 셋째 제약
     (`64vh × 0.558`)이 짧은 화면에서 석판을 먼저 줄이고, 안쪽 글자가 전부 그 폭에 비례하므로
     화면 높이별 예외가 필요 없다. 다시 만들면 두 곳이 어긋난다. */
