  /* ════ chapter VICTORY (Quiet-Canvas skin): warm-gold celebration reusing modal_canvas + fx_light_burst.
     Same lavish composition as the reference (crown frame, gold stars, burst) tuned to the calm palette. ════ */
  #chapterWin { position: fixed; inset: 0; z-index: 70; display: none; flex-direction: column;
    align-items: center; justify-content: center; gap: 9px; padding: 18px 24px;
    /* ⚠️ 배경 그림은 **JS가 챕터마다 바꾼다**(game/chapterVictory.js `victoryBackdrop`). 여기 있는
       url()은 그 변수가 없을 때의 기본값이자 옛 동작이다 — 하드코딩으로 되돌리면 챕터마다 달라지는
       도착지가 사라진다(오너 2026-08-12). 그림 목록도 그 함수 하나에만 있다. */
    background: linear-gradient(rgba(8,16,28,.18), rgba(6,14,26,.42)),
                var(--victory-bg, url('../../assets/gallery/bg_victory_v2.webp')) center / cover no-repeat;
    overflow: hidden; }
  #chapterWin.show { display: flex; animation: chwFade .5s ease-out both; }
  #chapterWin::before { content: none; }  /* damask now lives in the bg image */
  #chapterWin h2 { margin: 0; font-size: 0; color: transparent; z-index: 1;
    width: min(74vw, 330px); aspect-ratio: 700 / 142;
    background: url('../../assets/win/victory_text.webp') center / contain no-repeat;
    filter: drop-shadow(0 4px 6px rgba(60,20,5,.45)) drop-shadow(0 0 18px rgba(240,160,30,.4));
    animation: chwTitlePop .84s linear both; }
  /* A cleared section that still has missing flawless stages is success, not a failed VICTORY reward.
     Use a quieter localized title; the large VICTORY artwork is reserved for the N/N window unlock. */
  #chapterWin.chw-locked h2 {
    width: auto; max-width: min(86vw, 360px); aspect-ratio: auto; background: none;
    color: #fff0c6; font-family: 'Jua', system-ui, sans-serif; font-size: clamp(30px, 9vw, 42px);
    line-height: 1; letter-spacing: 0; text-align: center;
    -webkit-text-stroke: 1.5px #7f4a16; paint-order: stroke fill;
    text-shadow: 0 3px 0 #5c3010, 0 5px 12px rgba(35,15,4,.42);
    filter: none;
  }
  #chapterWin .chwArtWrap { position: relative; width: 42vw; max-width: 172px; aspect-ratio: 421 / 432; display: flex; align-items: center; justify-content: center; z-index: 1; }
  /* soft energy halo behind the crystal frame (cyan-tinted) */
  #chapterWin .chwBurst { position: absolute; width: 220%; height: 220%; pointer-events: none;
    background: url('../../assets/win/light_burst.webp') center / contain no-repeat; opacity: .8;
    filter: hue-rotate(165deg) saturate(1.15) brightness(1.05); animation: chwBurstPulse 2.6s ease-in-out infinite; }
  /* crystal frame: always visible; the stained glass forms inside its hexagon on reveal */
  #chapterWin .artCell, #windowView .artCell { position: relative; width: 100%; aspect-ratio: 421 / 432; z-index: 1; --art-shift: 3%; }
  /* the artwork hexagon (glass + dark interior + flying shards + flash) sits inset 13%, nudged DOWN by
     --art-shift to register with frame.webp's window (its opening sits a hair below the cell's centre,
     so a centred hexagon left the bottom of the frame empty). One var tunes all four layers together. */
  /* crystal frame (frame.webp) + dark hexagon interior REMOVED (owner 2026-06-25): the artwork now shows as the
     full SQUARE picture (greyscale base + colour reveal), no crystal-shaped frame. */
  #chapterWin .artCell::before, #windowView .artCell::before,
  #chapterWin .artCell::after, #windowView .artCell::after { display: none; }
  /* reward UI stays hidden during the wind-up, then blooms in on reveal */
  #chapterWin .chwLabel, #chapterWin .chwReward, #chapterWin .chwStory, #chapterWin .chwBtns, #chapterWin .chwSeason { opacity: 0; }
  /* reward UI blooms in only at SETTLE — i.e. AFTER the quiet admire beat (chw-settled added ~1.2s after
     chw-revealed), so the artwork gets its solo moment before reward/buttons arrive. */
  #chapterWin.chw-settled .chwLabel { animation: chwUiIn .5s ease-out .18s both; }
  #chapterWin.chw-settled .chwStory { animation: chwUiIn .5s ease-out .24s both; }
  #chapterWin.chw-settled .chwReward { animation: chwUiIn .5s ease-out .30s both; }
  #chapterWin.chw-settled .chwBtns  { animation: chwUiIn .5s ease-out .38s both; }
  /* season finale (소프트런치): warm banner + Sha's promise, last to bloom — pure 여운 after the reward (§2.3) */
  #chapterWin.chw-settled .chwSeason { animation: chwUiIn .5s ease-out .46s both; }
  #chapterWin .chwSeason { display: none; flex-direction: column; align-items: center; gap: 5px; z-index: 1; width: min(86vw, 360px); }
  #chapterWin .chwSeason.on { display: flex; }
  #chapterWin .chwSeasonBanner {
    font-family: 'Jua', system-ui, sans-serif; font-weight: 400; font-size: clamp(16px, 4.6vw, 20px); letter-spacing: .3px;
    color: var(--gold); -webkit-text-stroke: 1.2px var(--gold-deep); paint-order: stroke fill;
    text-shadow: 0 2px 0 var(--gold-deep), 0 4px 7px rgba(60,34,4,.4);
  }
  #chapterWin .chwSeasonSha {
    max-width: 320px; text-align: center; color: rgba(255,250,240,.88); line-height: 1.45;
    font-size: clamp(15px, 3.3vw, 13.5px); font-weight: 700; text-shadow: 0 1px 3px rgba(0,0,0,.6);
  }
  /* full SQUARE artwork (hexagon clip + frame removed, owner 2026-06-25). VICTORY: the greyscale picture fades in,
     then the collected COLOUR blooms into it. */
  #chapterWin .artGlass, #windowView .artGlass { position: absolute; inset: 0; z-index: 1; width: auto; height: auto; border-radius: 12px; opacity: 0; }
  #windowView .artGlass { opacity: 1; }   /* viewer shows the window immediately (no reveal wind-up) */
  #chapterWin.chw-revealed .artGlass { animation: chwArtIn .84s linear both; }
  #chapterWin.chw-revealed .artColor { animation: chwColorBloom .9s ease-out .25s both; }   /* 흑백→컬러 차오름 */
  #chapterWin.chw-locked.chw-revealed .artColor { animation: none; opacity: 0; }
  /* the artwork gently leans IN during its solo admire beat (feels bigger at the peak moment), then
     settles back to rest as the reward UI arrives — emphasis without permanently crowding the layout. */
  #chapterWin.chw-revealed .chwArtWrap { animation: chwArtAdmire 1.25s cubic-bezier(.25,.8,.3,1) both; }
  @keyframes chwArtAdmire { 0% { transform: scale(.995); } 55% { transform: scale(1.05); } 100% { transform: scale(1.045); } }
  #chapterWin.chw-settled .chwArtWrap { animation: chwArtSettle .77s linear both; }
  @keyframes chwArtSettle {
    0%   { transform: scale(1.045); animation-timing-function: ease-in-out; }
    55%  { transform: scaleX(.985) scaleY(1.025); animation-timing-function: ease-in-out; }
    80%  { transform: scaleX(1.015) scaleY(.99); animation-timing-function: ease-in-out; }
    100% { transform: scale(1); }
  }
  @keyframes chwArtIn {
    0%   { opacity: 0; transform: scale(.82); animation-timing-function: ease-in-out; }
    55%  { opacity: 1; transform: scaleX(1.07) scaleY(1.11); animation-timing-function: ease-in-out; }
    78%  { transform: scaleX(1.08) scaleY(.95); animation-timing-function: ease-in-out; }
    92%  { transform: scaleX(.98) scaleY(1.02); animation-timing-function: ease-in-out; }
    100% { opacity: 1; transform: scale(1); }
  }
  @keyframes chwColorBloom { 0% { opacity: 0; filter: saturate(.25) brightness(1.45); } 60% { opacity: 1; } 100% { opacity: 1; filter: none; } }
  #chapterWin .artEmblem { font-size: 96px; }
  #chapterWin .artCell .artTitle { display: none; }  /* redundant with the chwLabel below; the frame window stays clean */
  /* thumbs-up Sha peeks from the frame's bottom-right corner, popping in after the glass forms */
  #chapterWin .chwMascot {
    position: absolute; right: -50%; bottom: -9%; width: clamp(92px, 34%, 124px); z-index: 5;
    pointer-events: none; opacity: 0; -webkit-user-drag: none;
    filter: drop-shadow(0 6px 10px rgba(14,28,10,.55));
    transform-origin: 70% 90%;
  }
  #chapterWin.chw-settled .chwMascot { animation: chwMascotIn .87s linear .45s both; }   /* Sha joins at the celebration, not during the artwork's solo admire beat. 딜레이(.45s)는 안 밀었다 — chwUiIn 카스케이드(.38s/.46s, 미변환)와 같은 물결에서 같은 시점에 시작해야 동시등장으로 읽힌다(§보고서 참조). */
  @keyframes chwMascotIn {
    0%   { opacity: 0; transform: translateY(46%) rotate(-10deg) scaleX(.52) scaleY(.58); animation-timing-function: ease-in-out; }
    62%  { opacity: 1; transform: translateY(-6%) rotate(5deg) scaleX(.99) scaleY(1.14); animation-timing-function: ease-in-out; }
    84%  { transform: translateY(0) rotate(0deg) scaleX(1.08) scaleY(.94); animation-timing-function: ease-in-out; }
    100% { opacity: 1; transform: translateY(0) rotate(0) scale(1); }
  }
  /* crown is part of canvas_art.png now — drop the CSS crown */
  #chapterWin .chwArtWrap::before, #chapterWin .chwArtWrap::after { content: none; }
  /* HERO of the card: the restored artwork's name (big). A tiny kicker labels it; the rest is meta. */
  #chapterWin .chwLabel { display: flex; flex-direction: column; align-items: center; gap: 2px; z-index: 1; }
  #chapterWin .chwKicker { color: rgba(255,233,176,.72); font-size: 12px; font-weight: 700; letter-spacing: .07em; text-shadow: 0 1px 2px rgba(50,12,4,.7); }
  /* 무결점 챕터: the chapter window is PERFECTLY restored → a golden, fully-vivid variant (CSS-only, reuses the art) */
  #chapterWin .chwFlawKicker { color: #ffe27a; font-size: 13px; letter-spacing: .12em; text-shadow: 0 1px 0 #7a5512, 0 0 9px rgba(255,224,122,.8); }
  #chapterWin.chw-flawless .artGlass { filter: saturate(1.18) brightness(1.1); }   /* vivid "golden window" — NO gold halo/border (read as an errant yellow outline, esp. before the art reveals) */
  /* locked (not-yet-all-flawless): the window shows N/M glass pieces PLACED, the rest faint gaps — via an SVG shard
     mask on .artGlass set by showChapterVictory (조각이 채워진다). Placed pieces stay vivid (the carrot). */
  /* 2026-07-21 owner: "열쇠 조각 N/M"이 작아 잠금 상태가 덜 읽힘 → 12→15px + 금빛 강화(무결점 kicker보다는 낮게 유지). */
  #chapterWin .chwLockKicker { color: #ffe0a4; font-size: 15px; font-weight: 800; letter-spacing: .05em; text-shadow: 0 1px 2px rgba(50,12,4,.7), 0 0 8px rgba(246,200,60,.45); }
  /* ── 글자 사다리 (오너 2026-08-03 "텍스트들이 오합지졸 정신없이 읽혀") ──────────────────────────
     실측한 문제: 크기가 **중요도와 반대**였다 — 열쇠 15 · **작품 이름 26** · 코인 20 · 넛지 15.
     화면에서 가장 크고 밝은 글자가 작품 이름("별")인데, 한 글자짜리인 데다 숫자 줄 둘 사이에 껴서
     이름이 아니라 부스러기로 읽혔다. 이름은 이 화면에서 **가장 행동과 무관한** 정보다(정취).
     → 사다리를 하나로 세운다: **코인 24 → 이름 19 → 상태·넛지 14.**
     ⚠️ 그림이 여전히 화면의 주인공이다(164×168) — 여기서 키우는 것은 "텍스트 중 무엇이 먼저냐"뿐이고,
        연출 헌법 §2.1(본 성취가 보상보다 먼저)은 **순서**로 이미 지켜진다(그림 → 이름 → 정산). */
  #chapterWin .chwArtName { color: var(--gold); font-family: 'Jua', system-ui, sans-serif; font-weight: 400; font-size: 19px; line-height: 1.05; text-shadow: 0 2px 5px rgba(50,12,4,.85); }
  /* progress + new-area = quiet meta, one compact row below the reward */
  /* starlight settlement on the chapter card; the balance number counts up to its new total */
  #chapterWin .chwReward { display: flex; flex-direction: column; align-items: center; gap: 1px; z-index: 1; margin-top: 1px; }
  #chapterWin .chwReward .chwRewardAmt {
    color: var(--gold); font-family: 'Jua', system-ui, sans-serif; font-weight: 400; font-size: 24px; line-height: 1;
    -webkit-text-stroke: 1.2px var(--gold-deep); paint-order: stroke fill; text-shadow: 0 2px 0 var(--gold-deep), 0 3px 6px rgba(60,34,4,.45);
  }
  #chapterWin .chwStory { width: min(86vw, 360px); min-height: 42px; padding: 9px 15px; z-index: 1;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; text-align: center;
    color: rgba(255,250,240,.82); font-size: 15px; font-weight: 600;   /* ⚠️ 2026-08-03: clamp(15px,3.3vw,13.5px)였다 — **최솟값이 최댓값보다 커서** 브라우저가 항상 min(15px)을 쓰는 죽은 clamp. 실제 렌더값 그대로 고정해 거짓말만 걷었다(시각 변화 0). */ font-style: italic; line-height: 1.4;
    border: 1px solid rgba(255,234,174,.16); border-radius: 14px;
    background: rgba(10,27,37,.42); box-shadow: inset 0 1px rgba(255,255,255,.05);
    text-shadow: 0 1px 3px rgba(0,0,0,.6); }
  /* short 무결점 nudge as its OWN line (not a run-on with the story beat) — detail guidance lives in the map window viewer */
  #chapterWin .chwNudge { font-style: normal; font-weight: 800; font-size: 15px; color: #ffe6a6;   /* ⚠️ 위와 같은 죽은 clamp(15px,3vw,12.5px)였다 — 실제 렌더값으로 고정 */
    text-shadow: 0 1px 2px rgba(50,12,4,.6); }
  #chapterWin .chwBtns { display: flex; flex-direction: column; gap: 10px; width: 100%; max-width: 260px; margin-top: 4px; z-index: 1; }
  #chapterWin .chwBtns button { width: 100%; aspect-ratio: 467 / 146; padding: 0 8% 3%; border: none; border-radius: 0;
    background: url('../../assets/common/btn_green.png') center / 100% 100% no-repeat; box-shadow: none;
    display: flex; align-items: center; justify-content: center;
    color: #fff8e9; font-weight: 900; letter-spacing: .3px;
    text-shadow: 0 2px 0 #2c7a1f, 0 3px 5px rgba(18,55,8,.5); transition: transform .08s, filter .12s; }
  #chapterWin .chwBtns button:active { transition: transform .06s ease-out; transform: scaleX(1.06) scaleY(.90); filter: brightness(.95); box-shadow: none; }
  #chapterWin #chwContinue { font-size: clamp(18px, 5.4vw, 23px); }
  /* ⚠️ #chwReplay는 **chw-locked일 때만 보인다**(hidden = allFlawless || acquisitionOnly,
     chw-locked = !allFlawless && !acquisitionOnly — 정확한 여집합). 즉 이 줄은 그 버튼에
     대해서는 실제로 안 쓰이고, 아래 chw-locked 규칙이 정본이다. 크기를 만질 땐 아래를 고쳐라. */
  #chapterWin #chwReplay { font-size: clamp(15px, 4.4vw, 19px); max-width: 80%; margin: 0 auto; }
  /* 무결점 미달성: 챕터 다시하기(재도전 유도)를 위로, 계속하기를 아래 작게 */
  /* 2026-07-21 owner: 별빛 정산(chwReward)이 넛지 문구와 재시도 버튼 사이를 끊어 유도를 방해 →
     잠금 상태에서만 정산을 넛지 위로 올려 "무결점으로 모아요 → [챕터 다시하기]"를 붙인다.
     (무결점 달성 상태는 유도할 대상이 없으므로 기존 순서 = 스토리 비트 뒤 정산으로 여운 유지.) */
  #chapterWin.chw-locked #chwStory  { order: 1; }
  #chapterWin.chw-locked #chwSeason { order: 2; }
  #chapterWin.chw-locked .chwBtns   { order: 3; }
  #chapterWin.chw-locked .chwBtns { flex-direction: column-reverse; }
  /* ⚠️ 글자 크기는 `vw`에 묶여 있는데 **버튼 상자는 260px로 고정**이다(.chwBtns max-width) — 화면이
     넓어질수록 글자만 커지고 상자는 안 커진다. 그래서 상한이 곧 오버플로 지점이다.
     안쪽 폭 = 260 − 좌우 패딩 8%씩 = **218px**. 라벨이 「챕터 다시하기」→「열쇠 조각 모으기」로 길어지면서
     (오너 2026-08-07) 옛 상한 23px에서 계산상 **영어가 101%로 넘쳤다**(ja 96%로 여유 0, ko 81%).
     상한을 20px로 내렸다. **Playwright 실측**(430×932, 상자 안쪽 218px):
       23px → ko 69% · ja 83% · **en 97%**  ← 여유 3%. 기기 폰트가 조금만 넓으면 두 줄이 된다.
       20px → ko 60% · ja 73% · **en 85%**  ← 여유 15%.
     (참고: 옛 라벨도 ja가 23px에서 이미 92%였다 — 이 버튼은 원래 여유가 없었다.)
     ⚠️ **가장 긴 언어가 기준이다** — 한국어(60%)만 보고 올리면 영어에서 넘친다. 라벨을 바꿀 때는
     세 언어를 다 재라. ⚠️ 이 버튼은 **Jua가 아니라 시스템 폰트**를 쓴다(.chwBtns button에 font-family
     없음) — 기기마다 폭이 달라지므로 여유를 넉넉히 둔다.
     ⚠️ 위계는 글자 크기가 아니라 **상자 폭**(이 버튼 100% vs 계속하기 80%)과 ctaNudge가 진다 —
     그래서 20px로 내려도 계속하기(19px)와 헷갈리지 않는다. */
  #chapterWin.chw-locked #chwReplay { font-size: clamp(16px, 4.7vw, 20px); max-width: 100%; }
  #chapterWin.chw-locked #chwContinue { font-size: clamp(15px, 4.4vw, 19px); max-width: 80%; margin: 0 auto; }
  /* ── 물러나는 버튼이 실제로 물러나게 (오너 2026-08-03 "오합지졸") ────────────────────────────────
     ⚠️ 위 2026-07-21 결정(잠금 상태에서는 「챕터 다시하기」를 위·크게 = 재도전 유도)은 **그대로 둔다.**
     바꾸는 것은 "누가 크냐"가 아니라 **"물러나는 쪽이 실제로 물러나느냐"** 다.
     문제: 보조 버튼이 **크기만** 작고 같은 초록 이미지라 "작지만 똑같이 시끄러운 두 번째 주인공"이었다.
     연출 헌법 §4.1은 주변 요소가 채도·밝기·크기·움직임 중 **최소 둘**을 낮추라고 못 박는다 → 채도·밝기 추가. */
  #chapterWin.chw-locked #chwContinue { filter: saturate(.5) brightness(.86); }
  #chapterWin.chw-locked #chwContinue:active { filter: saturate(.5) brightness(.8); }   /* 눌림 피드백을 위 filter가 먹지 않도록 */
  /* 움직임은 가장 강한 시선 채널이다. 그런데 idle 넛지가 **작고 아래에 있는 보조 버튼**에만 걸려 있어,
     크기가 말하는 위계와 정확히 반대로 시선을 끌고 있었다(주인공이 둘). 강조된 쪽으로 옮긴다. */
  #chapterWin.chw-locked .chwBtns #chwContinue { animation: none; }
  #chapterWin.chw-locked .chwBtns #chwReplay { animation: ctaNudge 5.8s ease-in-out 4.3s infinite; }
  html[data-motion="reduced"] #chapterWin.chw-locked .chwBtns #chwReplay { animation: none; }
  /* ── 자물쇠/열쇠 미스터리 시스템 ── */
  .chwLockVeil {
    position: absolute; inset: 0; z-index: 5; pointer-events: none;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
    background: linear-gradient(165deg, rgba(26,10,2,.76) 0%, rgba(11,4,1,.86) 100%);
    backdrop-filter: blur(2px) saturate(.7); -webkit-backdrop-filter: blur(2px) saturate(.7);
    border-radius: 4px;
  }
  /* Incomplete: one small status badge. It no longer covers the artwork or stages a second protagonist. */
  #chapterWin.chw-locked .chwLockVeil {
    inset: auto 7px 7px auto;
    width: 34px; height: 34px;
    border-radius: 50%;
    gap: 0;
    background: rgba(22,14,7,.76);
    border: 1px solid rgba(235,205,135,.48);
    backdrop-filter: none; -webkit-backdrop-filter: none;
    box-shadow: 0 2px 7px rgba(15,8,3,.38), inset 0 1px 0 rgba(255,244,204,.14);
  }
  #chapterWin.chw-locked .chwLockSvg { width: 20px; height: 20px; filter: none; }
  #chapterWin.chw-locked .chwKeyWrap { display: none; }
  .chwLockVeil.chwVeilOut { animation: chwVeilOut .6s ease both; }
  @keyframes chwVeilOut { to { opacity: 0; } }
  .chwLockSvg { width: 63px; height: 63px; color: #d4a855; filter: drop-shadow(0 2px 10px rgba(200,146,26,.55)); flex-shrink: 0; }
  .chwLockSvg.chwLockJiggle { animation: chwLockJiggle .55s ease both; }
  @keyframes chwLockJiggle {
    0%   { transform: rotate(0) scale(1); }
    20%  { transform: rotate(-9deg) scale(1.1); filter: drop-shadow(0 0 14px rgba(246,200,60,.85)); color: #f6c83c; }
    40%  { transform: rotate(9deg) scale(1.12); filter: drop-shadow(0 0 20px rgba(246,200,60,1)); color: #f6c83c; }
    60%  { transform: rotate(-5deg) scale(1.06); color: #edb040; }
    80%  { transform: rotate(4deg) scale(1.03); }
    100% { transform: rotate(0) scale(0); opacity: 0; }
  }
  .chwKeyWrap { display: flex; align-items: center; justify-content: center; opacity: 0; }
  .chwKeyWrap.chwKeyIn  { animation: chwKeyIn  .55s cubic-bezier(.2,.8,.3,1) .1s both; }
  .chwKeyWrap.chwKeyFly { animation: chwKeyFly .5s  cubic-bezier(.4,0,.2,1.1)   both; }
  @keyframes chwKeyIn  { from { opacity:0; transform:translateY(10px) rotate(-10deg); } to { opacity:1; transform:translateY(0) rotate(0); } }
  @keyframes chwKeyFly { 0%{transform:translateY(0) rotate(0);} 55%{transform:translateY(-24px) rotate(-8deg) scale(1.06);} 80%{transform:translateY(-28px) rotate(5deg);} 100%{transform:translateY(-26px) rotate(-2deg);} }
  /* Sha may acknowledge section completion after the artwork's solo beat. Missing shards no longer turn this
     success screen into a failure state; the N/N reveal still owns the stronger key-and-veil climax. */
  #chapterWin.chw-flawless .chwMascot { opacity: 0; transition: opacity .5s ease .1s; pointer-events: none; }
  #chapterWin.chw-flawless.chw-veil-done .chwMascot { opacity: 1; pointer-events: auto; }
  html[data-motion="reduced"] {
    .chwKeyWrap.chwKeyIn, .chwKeyWrap.chwKeyFly, .chwLockSvg.chwLockJiggle, .chwLockSvg.chwLockItch, .chwLockVeil.chwVeilOut { animation: none; opacity: 1; }
    #chapterWin.chw-flawless .chwMascot, #chapterWin.chw-locked .chwMascot { opacity: 1; }
  }
  @keyframes chwFade { from { opacity: 0; } to { opacity: 1; } }
  @keyframes chwBurstPulse { 0%,100% { opacity: .7; transform: scale(.96) rotate(0); } 50% { opacity: 1; transform: scale(1.05) rotate(8deg); } }
  @keyframes chwUiIn { 0% { opacity: 0; transform: translateY(10px); } 100% { opacity: 1; transform: translateY(0); } }
  @keyframes chwTitlePop {
    0%   { opacity: 0; transform: translateY(-20px) scale(.4); animation-timing-function: ease-in-out; }
    52%  { opacity: 1; transform: translateY(2px) scaleX(1.04) scaleY(1.18); animation-timing-function: ease-in-out; }
    74%  { transform: translateY(0) scaleX(1.10) scaleY(.93); animation-timing-function: ease-in-out; }
    90%  { transform: translateY(0) scaleX(.97) scaleY(1.02); animation-timing-function: ease-in-out; }
    100% { opacity: 1; transform: translateY(0) scale(1); }
  }
  html[data-motion="reduced"] {
    #chapterWin.show, #chapterWin h2, #chapterWin .chwBurst { animation: none; }
    /* no wind-up: show the formed glass + reward statically (frame ::after stays visible) */
    #chapterWin .artGlass, #chapterWin .chwArtWrap, #chapterWin .chwLabel, #chapterWin .chwReward, #chapterWin .chwStory, #chapterWin .chwBtns, #chapterWin .chwMascot {
      opacity: 1 !important; animation: none !important; }
  }

  /* 챕터 완주의 주 행동 「계속」 — 이 화면에서 눌러야 하는 유일한 것. */
  #chapterWin .chwBtns #chwContinue { animation: ctaNudge 5.8s ease-in-out 4.3s infinite; }
  html[data-motion="reduced"] #chapterWin .chwBtns #chwContinue { animation: none; }
