/* 오늘의 빙고 — 기본(에메랄드) 테마. 그림: assets/ui/*.webp (tools/build-assets.py가 today-bingo-ui-assets/에서 만든다)
   숫자 · 문구 · 날짜는 모두 런타임 텍스트.

   크기: 시안(440×880)의 1px = --u. 화면 폭과 (쓸 수 있는) 높이의 절반 중 작은 쪽을 시안 폭 440으로 보고
   모든 크기를 그 배율로 정한다. 그래서 시안에서 잰 값을 그대로 쓰고, 낮은 화면에서는 같은 비율로 줄어든다. */

:root {
  --ink: #1b2a1f;          /* 시안의 숫자 · 문구: 거의 검정에 가까운 진초록 */
  --ink-soft: #4b5f50;
  --cream: #fff8e4;
  --gold: #ffd84a;
  --lime: #e6f45e;         /* 상태 바 숫자 */
  --on-green: #fffbe9;
  --font: 'Jua', 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', sans-serif;

  /* Safe Area: 브라우저 env() 기본, 앱인토스는 SDK 값으로 덮어쓴다 (net/platform.js) */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  /* 화면 맨 위의 플랫폼 바 높이: 앱인토스 게임은 오른쪽 위에 더보기 · 닫기(X)가 떠 있어 그 아래부터 쓴다 */
  --bar: 0px;
  --avail-h: calc(100dvh - var(--safe-t) - var(--bar) - var(--safe-b));
  /* 높이의 48%까지만: 시안 비율(440 × 860)을 지키고 남는 높이는 위아래 여백 (배너 광고 자리).
     더 낮추면 1:2 비율 화면에서 게임 전체가 좁아져 양옆이 비어 보인다 */
  --W: min(100vw, 480px, calc(var(--avail-h) * 0.48));
  --u: calc(var(--W) / 440);
  --board: calc(var(--u) * 404);
  /* 글자를 한 단계 굵게 (글꼴을 정하기 전까지 Jua 한 가지 굵기를 획으로 보강) */
  --stroke: calc(var(--u) * 0.9);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  background: #0b4a32 url('../../assets/ui/background_emerald.webp') center / cover no-repeat;
  color: var(--ink);
  font-family: var(--font);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

button {
  font: inherit;
  color: inherit;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  touch-action: manipulation;
}
button:disabled { cursor: default; }
button:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; border-radius: 14px; }

img { display: block; pointer-events: none; }

/* 굵은 글자: 숫자 · 버튼 · 제목 */
.tile > .num, .btn, .wbtn, .pill, .prompt, .title-pill, .goal-pill, .result-title .text, .slot, .stats strong, .status-bar {
  -webkit-text-stroke: var(--stroke) currentColor;
  paint-order: stroke fill;
}

#app {
  position: relative;
  width: var(--W);
  height: 100%;
  margin: 0 auto;
  padding: calc(var(--safe-t) + var(--bar)) calc(var(--u) * 10) var(--safe-b);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* 토스 X 버튼: top + 5~10px, 높이 약 34px → 그 아래 4px부터 게임 머리 줄 */
html[data-platform='toss'] { --bar: 44px; }

/* 화면은 시안 비율(440 × 860)로 고정하고 가운데. 남는 높이는 위아래 여백 (배너 광고 자리) */
.screen {
  width: 100%;
  height: min(100%, calc(var(--u) * 860));
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: calc(var(--u) * 14);
}

/* ── 머리 ─────────────────────────────────────────────────────────── */

.top {
  width: 100%;
  height: calc(var(--u) * 78);
  flex: none;
  display: grid;
  grid-template-columns: calc(var(--u) * 58) 1fr calc(var(--u) * 58);
  align-items: center;
}
/* 타이틀 로고: 그림(2094 × 751)에 양옆 노란 장식까지 들어 있다. 위아래 투명 여백이 약 21%라 높이를 넉넉히 */
.title-logo { justify-self: center; display: flex; align-items: center; justify-content: center; }
.title-logo .logo { width: calc(var(--u) * 236); height: auto; filter: drop-shadow(0 2px 2px #0005); }

.icon-btn {
  width: calc(var(--u) * 58);
  height: calc(var(--u) * 58);
  display: grid;
  place-items: center;
  background: url('../../assets/ui/button_icon.webp') center / 100% 100% no-repeat;
  transition: transform 0.08s;
}
.icon-btn:active { transform: scale(0.92); }
.icon-btn img { width: 58%; height: 58%; object-fit: contain; }

/* 머리 아래: 시안처럼 위에서부터 붙여 쌓고, 남는 높이는 위아래로 나눈다 */
.stage {
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--u) * 16);
}

/* ── 상태 줄: 남은 턴 · 완성한 줄 · 도장 ───────────────────────────── */

.status {
  width: var(--board);
  height: calc(var(--u) * 56);
  flex: none;
  display: flex;
  gap: calc(var(--u) * 6);
  align-items: center;
}
/* status_bar.png는 폭이 원본의 2배 넘게 늘어나 9-slice 이음선이 보여서, 같은 색 · 입체감을 CSS로 그린다 */
.status-bar {
  flex: 1;
  min-width: 0;
  height: calc(var(--u) * 54);
  display: flex;
  align-items: center;
  justify-content: space-evenly;
  border-radius: calc(var(--u) * 27);
  background: linear-gradient(#fffcef, #f6ecc9);
  box-shadow: inset 0 2px 0 #fff, inset 0 calc(var(--u) * -4) 0 #e2d4a6, 0 calc(var(--u) * 4) 0 #0a3a2633, 0 4px 8px #0002;
  font-size: calc(var(--u) * 20);
  color: var(--ink);
  white-space: nowrap;
  --stroke: calc(var(--u) * 0.5);
}
.status-bar .item { display: flex; align-items: center; gap: calc(var(--u) * 7); }
/* 글꼴의 위 여백이 커서 상자 가운데에 두면 글자가 2u쯤 떠 보인다 (실측): 글자만 내린다 */
.status-bar .label, .pill > span { position: relative; top: calc(var(--u) * 2.5); }
.status-bar .sep { width: 2px; height: calc(var(--u) * 26); background: #ddd0a4; border-radius: 1px; }
.pill {
  min-width: calc(var(--u) * 50);
  height: calc(var(--u) * 36);
  padding: 0 calc(var(--u) * 11);
  display: inline-grid;
  place-items: center;
  /* 진초록 알약 그림(554 × 191)을 9-slice로: 양 끝 둥근 부분(95px)은 그대로, 가운데만 늘린다.
     그림 둘레의 투명 여백(12px)만큼 바깥으로 내어 그려 보이는 알약이 상자에 맞게 */
  border-image: url('../../assets/ui/pill_deep_green.webp') 95 fill / calc(var(--u) * 18) / calc(var(--u) * 2.2);
  color: var(--lime);
  font-size: calc(var(--u) * 24);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* 도장: 크림 칸, 줄을 완성하면 진초록 체크 (시안) */
.stamp {
  position: relative;
  width: calc(var(--u) * 50);
  height: calc(var(--u) * 50);
  flex: none;
  background: url('../../assets/ui/stamp_socket.webp') center / 100% 100% no-repeat;
}
.stamp.on::after {
  content: '';
  position: absolute;
  inset: 20%;
  background: url('../../assets/ui/icon_check.webp') center / contain no-repeat;
  animation: stamp 0.45s cubic-bezier(0.3, 1.6, 0.5, 1);
}
@keyframes stamp { 0% { transform: scale(1.8); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }

/* ── 판 ──────────────────────────────────────────────────────────── */

.board-wrap {
  position: relative;
  width: var(--board);
  height: var(--board);
  flex: none;
}
/* 판 테두리(9-slice)와 그 위의 4×4 타일. 시안처럼 타일을 크게, 틈은 좁게 */
.board {
  position: absolute;
  inset: 0;
  border-style: solid;
  border-width: calc(var(--board) * 0.1);
  border-image: url('../../assets/ui/board_emerald.webp') 46 fill / calc(var(--board) * 0.1);
}
.board-inner {
  /* 시안 판(판 폭 기준): 가장자리 7.3% · 칸 20.3% · 칸 사이 좁게 */
  --g: 1%;
  position: absolute;
  inset: calc(var(--board) * 0.073);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
  gap: var(--g);
}

.tile {
  position: relative;
  display: grid;
  place-items: center;
  /* 타일 그림(339 × 324)에서 보이는 부분은 폭 91.2% · 높이 90.4%(실측)라 110%로 그려 칸에 꼭 맞게 */
  background: url('../../assets/ui/tile_cream.webp') center / 110% 110% no-repeat;
  color: var(--ink);
  font-size: calc(var(--u) * 44);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  transition: filter 0.2s, opacity 0.2s;
  --stroke: calc(var(--u) * 1.4);
}
/* 숫자는 보정 없이 두면 타일 윗면(아래 받침을 뺀 부분) 가운데에 온다: 윗면 가운데는 칸 가운데보다 4% 위 (실측) */
.tile > .num { transform: none; }
.tile.candidate { background-image: url('../../assets/ui/tile_candidate.webp'); color: #2c2108; animation: breathe 1.4s ease-in-out infinite; }
/* 후보는 골드(완성 줄)와 색이 가까워서 흰 테두리로도 구분한다 (기획서 2-4, 시안에는 없음: 검토 6번) */
.tile.candidate::before {
  content: '';
  position: absolute;
  /* 보이는 타일과 같은 모양: 110%로 그린 타일은 칸에 꼭 맞고(아래만 0.5% 덜 내려옴), 모서리는 폭의 24% (실측) */
  inset: 0 0 0.5%;
  border: calc(var(--board) * 0.009) solid #fff;
  border-radius: 24%;
  box-shadow: 0 0 calc(var(--board) * 0.03) #fff9, inset 0 0 calc(var(--board) * 0.02) #fff6;
  pointer-events: none;
}
.tile.marked { background-image: url('../../assets/ui/tile_mint.webp'); color: #10301f; }
/* 제외: 시안처럼 판을 밝게 두고(크림), 숫자만 흐리게 해서 구분한다 */
.tile.excluded { color: #8f8670; }
.tile.excluded > .num { opacity: 0.45; }
.tile.bingo { background-image: url('../../assets/ui/tile_bingo.webp'); color: #2c1f05; }
/* 선택(표시)한 칸의 체크: 색 외에 모양으로도 구분 (기획서 2-4) */
.tile.marked::after {
  content: '';
  position: absolute;
  /* 시안: 칸의 약 19% 크기로 타일 윗면 안쪽 오른쪽 위 */
  top: 8%;
  right: 8%;
  width: 19%;
  height: 19%;
  background: url('../../assets/ui/icon_check.webp') center / contain no-repeat;
  filter: drop-shadow(0 1px 0 #fffa);
}
.tile.prefilled > .num { opacity: 0.85; }
.tile.pop { animation: pop 0.32s cubic-bezier(0.3, 1.7, 0.5, 1); }
.tile.drop { animation: drop 0.35s ease-out; }
.tile.gild { animation: gild 0.5s cubic-bezier(0.3, 1.6, 0.5, 1) both; }

@keyframes breathe { 50% { filter: brightness(1.08); transform: scale(1.03); } }
@keyframes pop { 0% { transform: scale(0.82); } 100% { transform: scale(1); } }
@keyframes drop { 0% { transform: scale(1); } 40% { transform: scale(0.9) rotate(-3deg); } 100% { transform: scale(1); } }
@keyframes gild { 0% { transform: scale(1); filter: brightness(1.6); } 40% { transform: scale(1.12); } 100% { transform: scale(1); filter: none; } }

.fx {
  position: absolute;
  inset: calc(var(--board) * -0.08);
  width: calc(100% + var(--board) * 0.16);
  height: calc(100% + var(--board) * 0.16);
  pointer-events: none;
  z-index: 2;
}

/* ── 안내 문구 · 후보 버튼 ─────────────────────────────────────────── */

.prompt {
  height: calc(var(--u) * 46);
  flex: none;
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 12);
  color: var(--on-green);
  font-size: calc(var(--u) * 27);
}
/* 초록 바탕에서 흰 글자가 묻혀서 진초록 외곽선 + 아래 그림자 (외곽선은 글자 아래에 그려 굵기가 반만 보인다) */
.prompt > span {
  -webkit-text-stroke: calc(var(--u) * 3.4) #0a3a24;
  paint-order: stroke fill;
  text-shadow: 0 calc(var(--u) * 2) calc(var(--u) * 1.5) #04200fb3;
}
.prompt .rays { width: auto; height: calc(var(--u) * 36); }
/* 빛 장식 그림(fx_gold_rays)은 왼쪽이 굵고 오른쪽으로 가늘어진다: 글자 오른쪽 것만 뒤집어 양쪽 모두 바깥으로 */
.prompt .rays.r { transform: scaleX(-1); }

.actions {
  width: var(--board);
  flex: none;
  display: flex;
  gap: calc(var(--u) * 12);
}

/* 버튼: 원본(291×121)과 비율이 비슷해서 9-slice 대신 통째로 늘린다 (border-image는 이음선이 보였다).
   넓은 버튼은 .wbtn (캔버스 9-slice) */
.btn {
  position: relative;
  flex: 1;
  height: calc(var(--u) * 82);
  display: grid;
  place-items: center;
  padding: 0 0 calc(var(--u) * 7);
  background: url('../../assets/ui/button_primary.webp') center / 100% 100% no-repeat;
  color: #2c2108;
  font-size: calc(var(--u) * 28);
  white-space: nowrap;
  transition: transform 0.08s, filter 0.15s;
}
.btn.secondary { background-image: url('../../assets/ui/button_secondary.webp'); color: var(--ink); }
.btn.num { height: calc(var(--u) * 94); font-size: calc(var(--u) * 54); --stroke: calc(var(--u) * 1.6); }
.btn:active:not(:disabled) { transform: translateY(2px) scale(0.98); filter: brightness(0.96); }
.btn:disabled { filter: grayscale(0.5) brightness(0.9); opacity: 0.8; }

/* ── 결과 ────────────────────────────────────────────────────────── */

.result-title {
  height: calc(var(--u) * 56);
  margin-bottom: calc(var(--u) * -8);
  flex: none;
  display: grid;
  place-items: center;
}
.result-title img:not(.rt-glint) { height: calc(var(--u) * 58); animation: pop-in 0.5s cubic-bezier(0.3, 1.6, 0.5, 1) both; }
.result-title .text {
  color: var(--gold);
  font-size: calc(var(--u) * 34);
  text-shadow: 0 3px 0 #0006;
  animation: pop-in 0.5s cubic-bezier(0.3, 1.6, 0.5, 1) both;
}
.result-title .text.fail { color: var(--on-green); font-size: calc(var(--u) * 30); }
.result-sub {
  color: #d7ecd9;
  font-size: calc(var(--u) * 17);
  -webkit-text-stroke: 0;
}
@keyframes pop-in { 0% { transform: scale(0.4); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }

.boot {
  height: 100%;
  display: grid;
  place-items: center;
  color: var(--on-green);
  font-size: 18px;
}

/* ── 9-slice 캔버스 (ninepatch.js) · 패널 · 넓은 버튼 ─────────────────── */

.has-np { position: relative; isolation: isolate; }
canvas.np { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; }

.panel { width: var(--board); padding: 24px 22px 26px; color: var(--ink); }

.wbtn {
  width: 100%;
  height: 64px;
  display: grid;
  place-items: center;
  position: relative;
  color: #3a2a06;
  font-size: 22px;
  white-space: nowrap;
  transition: transform 0.08s, filter 0.15s;
}
/* 글자를 버튼 면(아래 입체 받침을 뺀 부분)의 가운데에. 버튼 그림은 높이에 맞춰 그려지고,
   노랑 · 크림 모두 면 가운데가 높이의 41.6% (그림 실측) → 글자 칸을 위 83.2%로.
   글꼴 위 여백 때문에 글자가 2.5u쯤 떠 보이는 만큼은 위쪽 여백으로 보정 */
.wbtn > span {
  position: absolute;
  inset: 0 0 16.8% 0;
  display: grid;
  place-items: center;
  padding-top: calc(var(--u) * 5);
}
.wbtn.secondary { color: var(--ink); height: 56px; font-size: 19px; }
.wbtn:active { transform: translateY(2px) scale(0.98); filter: brightness(0.96); }

.title-pill {
  margin: 0 auto 12px;
  width: fit-content;
  min-width: 60%;
  padding: 6px 22px 8px;
  border-radius: 999px;
  background: #cdeccb;
  color: var(--ink);
  font-size: 26px;
  text-align: center;
}
.section-pill {
  margin: 0 0 12px;
  padding: 6px 0 8px;
  border-radius: 999px;
  background: #cdeccb;
  font-size: 22px;
  text-align: center;
}

.row { display: flex; gap: 10px; }
.row > * { flex: 1; }

/* 창 (설정 · 확인). 시안 "설정 팝업"(폭 448)에서 잰 값을 폭 440 기준으로 */
.sheet-dim {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: grid;
  place-items: center;
  padding: 16px;
  /* 시안: 따뜻한 회갈색으로 덮어 뒤 화면이 바래 보이게 */
  background: rgba(58, 52, 34, 0.5);
  animation: fade 0.15s;
}
@keyframes fade { from { opacity: 0; } }
.panel.dialog {
  width: calc(var(--u) * 346);
  max-width: calc(100vw - 32px);
  padding: calc(var(--u) * 22) calc(var(--u) * 28) calc(var(--u) * 26);
  animation: pop-in 0.25s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.dialog .title-pill {
  width: 100%;
  min-width: 0;
  height: calc(var(--u) * 50);
  margin: 0 0 calc(var(--u) * 8);
  padding: 0;
  display: grid;
  place-items: center;
  background: #c8ebc0;
  font-size: calc(var(--u) * 33);
}
.dialog .msg { margin: calc(var(--u) * 14) 0 calc(var(--u) * 18); font-size: calc(var(--u) * 23); text-align: center; line-height: 1.45; }
.dialog .row { margin-top: calc(var(--u) * 14); gap: calc(var(--u) * 12); }
.dialog .col { display: flex; flex-direction: column; gap: calc(var(--u) * 10); margin-top: calc(var(--u) * 10); }
.dialog .col .wbtn, .dialog .col .wbtn.secondary { height: calc(var(--u) * 60); font-size: calc(var(--u) * 26); }
.dialog .wbtn { height: calc(var(--u) * 67); font-size: calc(var(--u) * 31); }
.dialog .wbtn.secondary { height: calc(var(--u) * 67); font-size: calc(var(--u) * 28); }
.settings .setting-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: calc(var(--u) * 72);
  padding: 0 calc(var(--u) * 6);
  font-size: calc(var(--u) * 29);
  -webkit-text-stroke: calc(var(--u) * 0.8) currentColor;
  border-bottom: 2px solid #eadfba;
}
.settings .setting-row:last-of-type { border-bottom: 0; }
.toggle { height: calc(var(--u) * 43); }
/* 토글 그림(482 × 217)의 비율 그대로 */
.toggle img { height: 100%; width: auto; }
/* 계정 번호: 시안에는 없지만 테스터 등록 · 문의에 필요해서 작고 흐리게 */
.settings .account { margin: calc(var(--u) * 2) 0 0; font-size: calc(var(--u) * 14); color: #8d8a76; text-align: center; }

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--safe-b) + 28px);
  transform: translateX(-50%);
  z-index: 20;
  padding: 10px 18px;
  border-radius: 999px;
  background: #102d20ee;
  color: var(--on-green);
  font-size: 16px;
  white-space: nowrap;
  animation: fade 0.2s;
}

/* 개발 메뉴 */
.sheet { width: min(calc(100vw - 32px), 420px); max-height: calc(100dvh - 80px); display: flex; flex-direction: column; }
.sheet h2 { margin: 0 0 8px; font-size: 22px; font-weight: normal; text-align: center; }
.sheet .list { overflow-y: auto; display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; padding: 2px; }
.sheet .list h3 { grid-column: 1 / -1; margin: 8px 0 0; font-size: 15px; font-weight: normal; color: var(--ink-soft); }
.sheet .list button {
  height: 54px;
  border-radius: 12px;
  background: url('../../assets/ui/tile_cream.webp') center / 100% 100%;
  font-size: 14px;
  line-height: 1.1;
}
.sheet .list button small { display: block; font-size: 11px; color: var(--ink-soft); }

/* ── 로비 ─────────────────────────────────────────────────────────── */
/* 시안: 패널이 머리 아래를 거의 다 채우고(420u), 버튼까지 그 안에. 미니 보드는 남는 높이만큼 크게 */

.lobby .stage { justify-content: flex-start; gap: calc(var(--u) * 6); padding-top: calc(var(--u) * 14); }
/* 시안 로비(440 기준)의 세로 배치: 날짜 50 · 목표 46 · 연속 40 · 판 338 · 시작 70 · 연습/기록 67 */
.lobby-card {
  width: 100%;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: calc(var(--u) * 20) calc(var(--u) * 22) calc(var(--u) * 24);
}
.lobby-card .title-pill {
  width: 100%;
  height: calc(var(--u) * 50);
  margin: 0;
  padding: 0;
  display: grid;
  place-items: center;
  font-size: calc(var(--u) * 32);
}
.goal { display: flex; align-items: center; gap: calc(var(--u) * 10); margin-top: calc(var(--u) * 16); }
.goal .rays { width: auto; height: calc(var(--u) * 36); }
/* 빛 장식 그림은 왼쪽이 굵고 오른쪽으로 가늘어진다: 글자 오른쪽 것만 뒤집어 양쪽 모두 바깥으로 */
.goal .rays.r { transform: scaleX(-1); }
.goal-pill {
  height: calc(var(--u) * 46);
  padding: 0 calc(var(--u) * 24);
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: linear-gradient(#ffe95a, #ffd21c);
  box-shadow: inset 0 2px 0 #fff8, inset 0 calc(var(--u) * -4) 0 #f0a514, 0 2px 0 #0002;
  font-size: calc(var(--u) * 27);
  color: #2c2108;
}
.streak {
  height: calc(var(--u) * 40);
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 7);
  margin-top: calc(var(--u) * 13);
  padding: 0 calc(var(--u) * 22);
  border-radius: 999px;
  background: linear-gradient(#fbecc6, #f3dfae);
  box-shadow: inset 0 1px 0 #fff8, inset 0 calc(var(--u) * -3) 0 #e6cd93;
  font-size: calc(var(--u) * 22);
}
.streak.quiet { color: var(--ink-soft); }
.mini-slot { margin-top: calc(var(--u) * 10); flex: none; }
.mini-board { --board: calc(var(--u) * 338); position: relative; width: var(--board); height: var(--board); }
/* 첫 시도 기록 줄이 붙으면 그만큼 판을 줄여 화면 높이(860)를 넘지 않게 */
.lobby-card.has-note .mini-board { --board: calc(var(--u) * 312); }
/* 시안 미니 보드(판 폭 기준): 가장자리 8% · 칸 20.3% · 칸 사이 1.1% */
.mini-grid {
  position: absolute;
  inset: calc(var(--board) * 0.078);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
  gap: 1.3%;
}
/* 타일 그림(339 × 324)은 가장자리 약 8%가 투명이라 109%로 그려 눈에 보이는 칸이 칸 크기와 같게 */
.mini { background: center / 109% 109% no-repeat; position: relative; }
.mini.dot { background-image: url('../../assets/ui/tile_mint.webp'); }
.mini.dot::after { content: ''; position: absolute; inset: 42%; background: url('../../assets/ui/lobby_tile_dot.webp') center / contain no-repeat; }
.mini.open, .mini.excluded { background-image: url('../../assets/ui/tile_cream.webp'); }
.mini.marked { background-image: url('../../assets/ui/tile_mint.webp'); }
.mini.bingo { background-image: url('../../assets/ui/tile_bingo.webp'); }
.lobby-card .note { margin-top: calc(var(--u) * 8); font-size: calc(var(--u) * 19); line-height: 1; color: var(--ink-soft); }
.lobby-actions { width: 100%; flex: none; display: flex; flex-direction: column; gap: calc(var(--u) * 18); margin-top: calc(var(--u) * 20); }
.lobby-actions .row { gap: calc(var(--u) * 18); }
.lobby-actions .wbtn { height: calc(var(--u) * 70); font-size: calc(var(--u) * 30); }
.lobby-actions .wbtn.secondary { height: calc(var(--u) * 67); font-size: calc(var(--u) * 27); }
.dev-link { flex: none; font-size: 13px; color: #cfe8d5; text-decoration: underline; }

/* ── 하위 화면 (연습 · 지난 기록) ─────────────────────────────────────
   시안(폭 485)에서 잰 값을 폭 440 기준(× 0.907)으로 옮겼다. 두 화면의 패널은 같은 높이(597). */

.top.sub .icon-btn { width: calc(var(--u) * 52); height: calc(var(--u) * 52); }
.top.sub .title-pill.head {
  justify-self: center;
  width: calc(var(--u) * 213);
  min-width: 0;
  height: calc(var(--u) * 56);
  margin: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: linear-gradient(#fffcef, #f6ecc9);
  box-shadow: inset 0 2px 0 #fff, inset 0 calc(var(--u) * -4) 0 #e2d4a6, 0 calc(var(--u) * 4) 0 #0a3a2633;
  font-size: calc(var(--u) * 33);
  /* 글꼴 위 여백 때문에 가운데에 두면 3u쯤 떠 보인다 (실측): 글자만 내린다 */
  padding-top: calc(var(--u) * 6);
}
.screen.sub .stage { gap: calc(var(--u) * 20); justify-content: flex-start; padding-top: calc(var(--u) * 22); }
.screen.sub .panel {
  width: 100%;
  border-radius: calc(var(--u) * 28);
  padding: calc(var(--u) * 45) calc(var(--u) * 30) calc(var(--u) * 54);
}

/* 연습 */
.practice-card .section-pill {
  height: calc(var(--u) * 53);
  margin: 0;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: #c8ebc0;
  font-size: calc(var(--u) * 31);
}
.practice-card hr { border: 0; border-top: 2px solid #eadfba; margin: calc(var(--u) * 36) calc(var(--u) * -12) calc(var(--u) * 32); }
.slots { display: grid; margin-top: calc(var(--u) * 30); }
.slots.intro { grid-template-columns: repeat(3, calc(var(--u) * 107)); justify-content: center; gap: calc(var(--u) * 5); margin-top: calc(var(--u) * 36); }
.slots.normal { grid-template-columns: repeat(5, 1fr); gap: calc(var(--u) * 4); }
.slot {
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  /* 타일 그림의 투명 여백(약 8%) 때문에 110%로 그려야 칸에 꼭 맞는다 (플레이 판과 같음) */
  background: url('../../assets/ui/tile_cream.webp') center / 110% 110% no-repeat;
  font-size: calc(var(--u) * 29);
  --stroke: calc(var(--u) * 0.9);
  transition: transform 0.08s;
}
.slots.intro .slot { font-size: calc(var(--u) * 49); --stroke: calc(var(--u) * 1.4); }
.slot:active { transform: scale(0.94); }
.slot.done { background-image: url('../../assets/ui/tile_mint.webp'); }
.slot.done::after {
  content: '';
  position: absolute;
  top: 8%;
  right: 8%;
  width: 22%;
  height: 22%;
  background: url('../../assets/ui/icon_check.webp') center / contain no-repeat;
}
.slot.next { background-image: url('../../assets/ui/tile_candidate.webp'); }
.practice-actions { width: 100%; }
.practice-actions .wbtn { height: calc(var(--u) * 80); font-size: calc(var(--u) * 33); }
.all-done { margin: 0; color: var(--on-green); text-align: center; font-size: calc(var(--u) * 19); }

/* 지난 기록: 패널 높이는 연습 패널과 같게 고정, 날짜 줄이 많으면 안에서 스크롤 */
.history-card {
  height: calc(var(--u) * 597);
  display: flex;
  flex-direction: column;
  padding: calc(var(--u) * 20) calc(var(--u) * 26) calc(var(--u) * 24) !important;
}
.stats { flex: none; display: flex; align-items: stretch; text-align: center; height: calc(var(--u) * 215); padding: calc(var(--u) * 18) 0; }
.stats > div:not(.vsep) { flex: 1; display: flex; flex-direction: column; justify-content: center; gap: calc(var(--u) * 24); }
.stats span { font-size: calc(var(--u) * 25); -webkit-text-stroke: calc(var(--u) * 0.8) currentColor; }
.stats strong { font-size: calc(var(--u) * 68); font-weight: normal; line-height: 1; --stroke: calc(var(--u) * 2.2); }
.stats .vsep { width: 2px; background: #e7d6a6; }
.hlist { flex: 1; min-height: 0; overflow-y: auto; border-top: 2px solid #eadfba; scrollbar-width: none; }
.hlist::-webkit-scrollbar { display: none; }
.hrow {
  display: grid;
  /* 시안: 날짜(왼쪽 정렬) | 결과(가운데) · 체크(오른쪽 끝) */
  grid-template-columns: calc(var(--u) * 140) 2px 1fr calc(var(--u) * 32);
  align-items: center;
  gap: calc(var(--u) * 10);
  height: calc(var(--u) * 62);
  padding: 0 calc(var(--u) * 2) 0 calc(var(--u) * 8);
  border-bottom: 2px solid #eadfba;
  font-size: calc(var(--u) * 25);
  -webkit-text-stroke: calc(var(--u) * 0.9) currentColor;
}
.hrow .bar { height: calc(var(--u) * 30); background: #e2cf8f; }
.hrow .what { text-align: center; white-space: nowrap; }
/* 체크 그림(171 × 140)은 가로가 길어서 폭만 정하고 높이는 그림 비율대로 */
.hrow .mark img { width: calc(var(--u) * 30); height: auto; }
.hrow.today { cursor: pointer; }
.hrow.missed { color: #a69e86; }

/* 상점: 시안(폭 487)에서 잰 값. 미리보기 판의 조각 위치는 판 그림(1254 정사각) 기준 % */
.shop-card { display: flex; flex-direction: column; align-items: center; gap: calc(var(--u) * 26); }
.shop-card .section-pill {
  align-self: stretch;
  height: calc(var(--u) * 53);
  margin: 0;
  padding: 0;
  display: grid;
  place-items: center;
  background: #c8ebc0;
  font-size: calc(var(--u) * 31);
}
.parts-pill {
  align-self: stretch;
  height: calc(var(--u) * 44);
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: #d6efcf;
  font-size: calc(var(--u) * 21);
  -webkit-text-stroke: calc(var(--u) * 0.6) currentColor;
}
.theme-preview { --board: calc(var(--u) * 344); position: relative; width: var(--board); height: var(--board); flex: none; }
.theme-preview > img { position: absolute; max-width: none; }
/* 판 테두리: 플레이 판과 같은 9-slice (board_starlight는 board_emerald와 같은 크기 · 모양) */
.theme-preview .frame {
  position: absolute;
  inset: 0;
  border-style: solid;
  border-width: calc(var(--board) * 0.1);
  border-image: url('../../assets/ui/board_starlight.webp') 46 fill / calc(var(--board) * 0.1);
}
/* 타일 · 장식: 플레이 판과 같은 자리 (.board-inner: 가장자리 7.3% · 칸 사이 1%, .board-fx) */
.theme-preview .grid {
  position: absolute;
  inset: calc(var(--board) * 0.073);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(4, 1fr);
  gap: 1%;
}
.theme-preview .cell { background: center / 110% 110% no-repeat; }
.theme-preview .board-fx { display: block; }
/* 별빛 도장: 오른쪽 아래 모서리에 걸쳐 (그림 속 도장은 가로 15 ~ 83%, 세로 6 ~ 95%) */
.theme-preview .seal { width: 34.5%; left: 72.5%; top: 66.5%; filter: drop-shadow(0 calc(var(--u) * 4) calc(var(--u) * 6) #0005); }
.shop-actions { width: 100%; display: flex; flex-direction: column; align-items: center; gap: calc(var(--u) * 14); }
.shop-actions .wbtn { height: calc(var(--u) * 80); font-size: calc(var(--u) * 35); }
.shop-actions .owned { margin: 0; color: var(--on-green); font-size: calc(var(--u) * 24); }
button.link {
  color: var(--on-green);
  font-size: calc(var(--u) * 21);
  text-decoration: underline;
  text-underline-offset: calc(var(--u) * 4);
  padding: calc(var(--u) * 4) calc(var(--u) * 10);
}

/* ── 타이틀 (시안 "9 타일의 순간", 910 × 1820을 440 기준으로) ──────────── */
/* 로고 가운데 205, 판(궤적 포함) 334 ~ 672. 판 그림에 떠 있는 9 · 빈 칸 · 궤적이 들어 있다 */

.screen.title { position: relative; justify-content: flex-start; cursor: pointer; }
.title-glow {
  position: absolute;
  left: 50%;
  top: calc(var(--u) * 205);
  width: calc(var(--u) * 520);
  height: calc(var(--u) * 520);
  transform: translate(-50%, -50%);
  opacity: 0.55;
}
.screen.title .title-logo { position: relative; margin-top: calc(var(--u) * 130); }
.screen.title .title-logo .logo { width: calc(var(--u) * 418); }
/* 장식 판: 그림 비율 1412 × 1114 */
.hero {
  position: relative;
  width: calc(var(--u) * 418);
  aspect-ratio: 1412 / 1114;
  margin-top: calc(var(--u) * 38);
}
.hero-board { position: absolute; inset: 0; width: 100%; height: 100%; filter: drop-shadow(0 calc(var(--u) * 10) calc(var(--u) * 14) #0004); }
.hero-glow {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 130%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  opacity: 0.35;
}

/* ── 튜토리얼 안내 ─────────────────────────────────────────────────── */

.tile.coach { z-index: 1; animation: coach 1.1s ease-in-out infinite; }
@keyframes coach { 50% { transform: scale(1.08); filter: brightness(1.1); } }
.btn { position: relative; }
.btn.dim { filter: grayscale(0.8) brightness(0.85); opacity: 0.55; }
.btn .ripple {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 70px;
  height: 70px;
  margin: -35px 0 0 -35px;
  animation: ripple 1.2s ease-out infinite;
}
@keyframes ripple { 0% { transform: scale(0.5); opacity: 0.9; } 100% { transform: scale(1.6); opacity: 0; } }
.prompt.coach-text { color: var(--gold); font-size: 20px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
}

/* ── 별빛 테마 (상점) ─────────────────────────────────────────────────
   <html data-theme="starlight"> (ui/theme.js). 판 테두리 · 고른 칸 · 줄 도장이 바뀌고 판 장식(ui/boardfx.js)이 붙는다.
   화면 배경 · 로고 · 아이콘 · 알약 · 토글 · 설정 창도 별빛 그림(sprites/starlight-ui/, 이름_starlight)으로 바뀐다:
   <img>로 그리는 것은 assets.js themed()가, CSS url() 그림은 여기서 덮어쓴다.
   판 그림(board_starlight)은 기본 판(board_emerald)과 같은 크기 · 모양이라 같은 9-slice를 그대로 쓴다. */
[data-theme='starlight'] body,
html[data-theme='starlight'] { background: #1b0a45 url('../../assets/ui/background_starlight.webp') center / cover no-repeat; }
/* 글자색: 진초록 대신 거의 검정에 가까운 진보라 (숫자 · 문구 · 크림 버튼 글자 모두 --ink를 쓴다) */
html[data-theme='starlight'] { --ink: #24113f; --ink-soft: #5b4a7a; }
[data-theme='starlight'] .pill { border-image-source: url('../../assets/ui/pill_deep_green_starlight.webp'); }
/* 연초록 알약(날짜 · 구역 이름 · 창 제목)은 별빛 연보라 알약(pill_mint_starlight)과 같은 색으로 */
[data-theme='starlight'] .title-pill:not(.head),
[data-theme='starlight'] .section-pill,
[data-theme='starlight'] .practice-card .section-pill,
[data-theme='starlight'] .parts-pill { background: #e6cffd; }
[data-theme='starlight'] .prompt > span { -webkit-text-stroke-color: #22094d; text-shadow: 0 calc(var(--u) * 2) calc(var(--u) * 1.5) #12052bb3; }
[data-theme='starlight'] .board { border-image-source: url('../../assets/ui/board_starlight.webp'); }
[data-theme='starlight'] .tile.marked,
[data-theme='starlight'] .mini.marked,
[data-theme='starlight'] .slot.done { background-image: url('../../assets/ui/tile_lavender.webp'); }
[data-theme='starlight'] .tile.marked { color: #2a1050; }
/* 로비 미니 보드: 오늘 아직 안 한 판(점 찍힌 칸)은 연한 라벤더로 가볍게 (고른 칸의 진한 라벤더와 구분) */
[data-theme='starlight'] .mini.dot { background-image: url('../../assets/ui/tile_lavender_light.webp'); }
[data-theme='starlight'] .mini.dot::after { filter: hue-rotate(150deg) saturate(1.2); }
/* 고른 칸 표시: 체크 대신 별빛 인장 (그림이 거의 꽉 차서 체크보다 조금 크게, 모서리 쪽으로) */
[data-theme='starlight'] .tile.marked::after {
  top: 5%;
  right: 5%;
  width: 25%;
  height: 25%;
  background-image: url('../../assets/ui/theme_starlight_seal.webp');
  filter: drop-shadow(0 1px 1px #2a105080);
}
/* 연습: 깬 판 표시는 리본 달린 별빛 도장 (그림 속 도장은 가로 15 ~ 83%, 세로 6 ~ 95%) */
[data-theme='starlight'] .slot.done::after {
  top: 0;
  right: 0;
  width: 36%;
  height: 36%;
  background-image: url('../../assets/ui/theme_starlight_stamp.webp');
  filter: drop-shadow(0 1px 2px #2a105066);
}
/* 줄 도장: 체크 대신 별빛 인장 (그림이 거의 꽉 차서 칸 안쪽 10%만 띄운다) */
[data-theme='starlight'] .stamp.on::after { inset: 10%; background-image: url('../../assets/ui/theme_starlight_seal.webp'); }

/* 판 장식: 기본 테마에서는 숨긴다. 위치는 판(--board) 기준 */
.board-fx { display: none; position: absolute; inset: 0; pointer-events: none; }
[data-theme='starlight'] .board-fx { display: block; }
.board-fx > img { position: absolute; max-width: none; }
/* 구름: 그림 속 구름은 가로 5 ~ 95%, 세로 37 ~ 66% → 아래 테두리 위(판의 89 ~ 98%)에, 타일 뒤로 */
.board-fx .cloud { left: 6%; width: 88%; top: 79%; }
/* 별: 그림 속 별은 가운데 42% → 보이는 폭 판의 7.5%, 아래 테두리 가운데 */
.board-fx .star { width: 18%; left: 41%; top: 87%; }
/* 빛: 왼쪽 위 모서리 (그림 속 빛은 가로 23 ~ 80%, 세로 25 ~ 64%) */
.board-fx .rays { width: 19%; left: -5.5%; top: -8.5%; }
/* 반짝이: fx_board_starlight_glint (64 정사각, 네 갈래 빛) */
.board-fx .s1 { right: 0.5%; top: 0.5%; width: 9%; }
.board-fx .s2 { right: -1.5%; top: 8%; width: 5.5%; }
.board-fx .s3 { left: -0.5%; top: 50%; width: 5.5%; }

/* 별빛 판 움직임 (가만히 있을 때): 반짝이 깜빡임 · 별 숨쉬기 · 빛 장식 번쩍 · 테두리를 스치는 빛.
   상점 미리보기 · 로비 미니 보드 · 플레이 판에 같이 걸린다. 동작 줄이기 설정이면 멈춘다 */
.board-fx .sparkle { animation: twinkle 2.6s ease-in-out infinite; }
.board-fx .s2 { animation-delay: -0.9s; animation-duration: 2.1s; }
.board-fx .s3 { animation-delay: -1.7s; animation-duration: 3.1s; }
@keyframes twinkle {
  0%, 100% { opacity: 0.35; transform: scale(0.7) rotate(0deg); }
  50% { opacity: 1; transform: scale(1.15) rotate(20deg); }
}
.board-fx .star { animation: star-breathe 2.8s ease-in-out infinite; }
@keyframes star-breathe {
  0%, 100% { transform: scale(1); filter: drop-shadow(0 0 0 #ffe38a00); }
  50% { transform: scale(1.08); filter: drop-shadow(0 0 calc(var(--board) * 0.02) #ffe38acc); }
}
.board-fx .rays { transform-origin: 70% 70%; animation: rays-flash 4.2s ease-in-out infinite; }
@keyframes rays-flash {
  0%, 70%, 100% { opacity: 0.85; transform: scale(1); filter: brightness(1); }
  80% { opacity: 1; transform: scale(1.12); filter: brightness(1.35); }
}
/* 테두리를 따라 흐르는 빛: 왼쪽 위 모서리에서 나타난 빛 두 줄기가 한쪽은 위 · 오른쪽 테두리로,
   한쪽은 왼쪽 · 아래 테두리로 흘러 오른쪽 아래 모서리에서 만나며 사라진다.
   판 가운데를 중심으로 도는 원뿔 그라데이션(--rim: 왼쪽 위에서 잰 각도)을 테두리 띠 모양으로만 보이게 가운데를 뚫는다.
   --rim을 움직이려면 @property 등록이 필요하다: 지원하지 않는 브라우저에서는 처음 값(안 보임)에 머문다 */
@property --rim { syntax: '<angle>'; inherits: false; initial-value: 0deg; }
.board-fx.front::before {
  content: '';
  position: absolute;
  inset: 1.5%;
  padding: 4.8%;
  border-radius: 11%;
  --rim: 0deg;
  background: conic-gradient(
    from 315deg,
    transparent 0deg,
    transparent calc(var(--rim) - 40deg),
    #fff3c4e6 var(--rim),
    transparent calc(var(--rim) + 4deg),
    transparent calc(356deg - var(--rim)),
    #fff3c4e6 calc(360deg - var(--rim)),
    transparent calc(400deg - var(--rim))
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  mix-blend-mode: screen;
  opacity: 0;
  animation: rim-flow 6s ease-in-out infinite;
}
/* 0 ~ 45%: 왼쪽 위(0°)에서 오른쪽 아래(180°)까지 흐른다. 처음엔 안 보이다가 밝아지고, 끝 모서리에 닿으며 완전히 사라진다 */
@keyframes rim-flow {
  0% { --rim: 0deg; opacity: 0; }
  10% { opacity: 1; }
  33% { opacity: 1; }
  45% { --rim: 176deg; opacity: 0; }
  100% { --rim: 176deg; opacity: 0; }
}

/* 줄 도장: 별빛 인장이 위에서 떨어지며 쾅 찍히고, 빛 고리가 퍼진다 */
[data-theme='starlight'] .stamp.on::after { animation: star-stamp 0.55s cubic-bezier(0.3, 1.5, 0.5, 1); }
@keyframes star-stamp {
  0% { transform: translateY(-140%) scale(1.9) rotate(-35deg); opacity: 0; }
  55% { transform: translateY(0) scale(0.85) rotate(6deg); opacity: 1; }
  100% { transform: none; opacity: 1; }
}
[data-theme='starlight'] .stamp.on::before {
  content: '';
  position: absolute;
  inset: -30%;
  border-radius: 50%;
  background: radial-gradient(circle, #fff6c8 0 20%, #ffd84a88 35%, #b07bff44 55%, transparent 70%);
  opacity: 0;
  pointer-events: none;
  animation: stamp-glow 0.75s ease-out 0.25s;
}
@keyframes stamp-glow {
  0% { opacity: 0; transform: scale(0.3); }
  30% { opacity: 1; }
  100% { opacity: 0; transform: scale(1.6); }
}

@media (prefers-reduced-motion: reduce) {
  .board-fx *, .board-fx::before,
  [data-theme='starlight'] .stamp.on::after,
  [data-theme='starlight'] .stamp.on::before { animation: none; }
}

/* ── 별빛 결과 화면 ───────────────────────────────────────────────────
   색: 안내 문구는 연보라, 글자 제목은 진보라 외곽선. 연출(클리어): 로고 위를 스치는 빛 · 양옆 반짝이 ·
   줄 도장이 함께 한 번 빛남. 못 깨면 판 아래 별이 잠깐 흐려진다. 기본 테마에서는 꾸밈을 숨긴다 */
.rt-wrap { position: relative; display: grid; place-items: center; }
.rt-shine, .rt-glint { display: none; }
[data-theme='starlight'] .result-sub { color: #e6d8ff; }
[data-theme='starlight'] .result-title .text {
  -webkit-text-stroke: calc(var(--u) * 4.5) #22094d;
  paint-order: stroke fill;
  text-shadow: 0 calc(var(--u) * 3) calc(var(--u) * 2) #12052bb3;
}
[data-theme='starlight'] .rt-shine {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(105deg, transparent 38%, #fffbe6 50%, transparent 62%) 120% 0 / 250% 100% no-repeat;
  -webkit-mask: var(--logo) center / contain no-repeat;
  mask: var(--logo) center / contain no-repeat;
  mix-blend-mode: screen;
  animation: rt-shine 0.9s ease-in-out 0.45s both;
}
@keyframes rt-shine {
  0% { background-position: 120% 0; opacity: 1; }
  100% { background-position: -20% 0; opacity: 0.6; }
}
[data-theme='starlight'] .rt-glint {
  display: block;
  position: absolute;
  pointer-events: none;
  opacity: 0;
  animation: rt-glint 0.9s ease-out both;
}
.rt-glint.g1 { width: calc(var(--u) * 26); left: -6%; top: -18%; animation-delay: 0.35s; }
.rt-glint.g2 { width: calc(var(--u) * 18); right: -4%; top: -6%; animation-delay: 0.55s; }
.rt-glint.g3 { width: calc(var(--u) * 14); right: 14%; bottom: -16%; animation-delay: 0.75s; }
@keyframes rt-glint {
  0% { opacity: 0; transform: scale(0.2) rotate(-30deg); }
  35% { opacity: 1; transform: scale(1.15) rotate(10deg); }
  100% { opacity: 0; transform: scale(0.6) rotate(25deg); }
}
/* 클리어: 줄 도장 둘이 함께 쿵 빛난다 (찍히는 연출이 끝난 뒤) */
[data-theme='starlight'] .stamp.on.cheer::after { animation: stamp-cheer 0.6s ease-out 0.3s; }
@keyframes stamp-cheer {
  0%, 100% { transform: none; filter: none; }
  40% { transform: scale(1.25); filter: brightness(1.35) drop-shadow(0 0 calc(var(--u) * 6) #ffe38a); }
}
/* 못 깸: 판 아래 별이 잠깐 흐려졌다 돌아온다 */
[data-theme='starlight'] .board-wrap.dim .board-fx .star { animation: star-dim 1.6s ease-in-out, star-breathe 2.8s ease-in-out 1.6s infinite; }
@keyframes star-dim {
  0%, 100% { opacity: 1; filter: none; }
  40% { opacity: 0.35; filter: grayscale(0.6); }
}
@media (prefers-reduced-motion: reduce) {
  [data-theme='starlight'] .rt-shine, [data-theme='starlight'] .rt-glint,
  [data-theme='starlight'] .stamp.on.cheer::after,
  [data-theme='starlight'] .board-wrap.dim .board-fx .star { animation: none; }
  [data-theme='starlight'] .rt-glint { display: none; }
}

/* ── 별빛 연습 화면 ───────────────────────────────────────────────────
   구분선은 연보라, 다음에 할 판(노란 칸)은 금빛이 숨 쉬고 오른쪽 위에 반짝이가 깜빡인다 */
[data-theme='starlight'] .practice-card hr { border-top-color: #e2d2f7; }
/* 누를 때 줄어드는 효과(transform)를 막지 않게 빛만 숨 쉰다 */
[data-theme='starlight'] .slot.next { animation: slot-glow 1.6s ease-in-out infinite; }
@keyframes slot-glow {
  0%, 100% { filter: brightness(1) drop-shadow(0 0 0 #ffe38a00); }
  50% { filter: brightness(1.07) drop-shadow(0 0 calc(var(--u) * 8) #ffe38acc); }
}
[data-theme='starlight'] .slot.next::after {
  content: '';
  position: absolute;
  top: -11%;
  right: -11%;
  width: 36%;
  height: 36%;
  background: url('../../assets/ui/fx_board_starlight_glint.webp') center / contain no-repeat;
  /* 노란 칸 위에서도 보이게 보라 테두리빛 */
  filter: drop-shadow(0 0 calc(var(--u) * 2) #8a4dffcc);
  pointer-events: none;
  animation: twinkle 2.2s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  [data-theme='starlight'] .slot.next, [data-theme='starlight'] .slot.next::after { animation: none; }
}

/* ── 별빛 지난 기록 ───────────────────────────────────────────────────
   황토색 선을 연보라로, 쉬어 간 날은 보랏빛 회색. 연속 클리어 숫자 옆에 반짝이가 깜빡인다 */
[data-theme='starlight'] .stats .vsep { background: #e2d2f7; }
[data-theme='starlight'] .hlist,
[data-theme='starlight'] .hrow { border-color: #e9dcf8; }
[data-theme='starlight'] .hrow .bar { background: #cdb6ef; }
[data-theme='starlight'] .hrow.missed { color: #a497bd; }
/* 클리어 표시: 별빛 인장(정사각)은 체크보다 조금 크게 */
[data-theme='starlight'] .hrow .mark img { width: calc(var(--u) * 34); }
/* 숫자 상자를 글자 폭으로 (세로 정렬 칸에서 늘어나지 않게) 해야 반짝이가 숫자 바로 옆에 붙는다 */
[data-theme='starlight'] .stats > div:first-child strong { position: relative; align-self: center; }
[data-theme='starlight'] .stats > div:first-child strong::after {
  content: '';
  position: absolute;
  top: -22%;
  right: -26%;
  width: 0.5em;
  height: 0.5em;
  background: url('../../assets/ui/fx_board_starlight_glint.webp') center / contain no-repeat;
  filter: drop-shadow(0 0 calc(var(--u) * 2) #8a4dffcc);
  animation: twinkle 2.4s ease-in-out infinite;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  [data-theme='starlight'] .stats > div:first-child strong::after { animation: none; }
}

/* ── 별빛 설정 창 · 확인 창 ────────────────────────────────────────────
   뒤를 덮는 색은 회갈색 대신 짙은 남보라, 구분선 · 계정 번호는 연보라 톤, 창 제목 알약 오른쪽 위에 반짝이 */
[data-theme='starlight'] .sheet-dim { background: rgba(22, 9, 56, 0.58); }
[data-theme='starlight'] .settings .setting-row { border-bottom-color: #e2d2f7; }
[data-theme='starlight'] .settings .account { color: #8f80ad; }
[data-theme='starlight'] .dialog .title-pill { position: relative; }
[data-theme='starlight'] .dialog .title-pill::after {
  content: '';
  position: absolute;
  top: -22%;
  right: 3%;
  width: calc(var(--u) * 26);
  height: calc(var(--u) * 26);
  background: url('../../assets/ui/fx_board_starlight_glint.webp') center / contain no-repeat;
  filter: drop-shadow(0 0 calc(var(--u) * 2) #8a4dffcc);
  animation: twinkle 2.4s ease-in-out infinite;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  [data-theme='starlight'] .dialog .title-pill::after { animation: none; }
}

/* ── 상점 꾸밈 ────────────────────────────────────────────────────────
   미리보기의 별빛 도장 배지는 천천히 둥실거린다 (상품 진열이라 테마와 상관없이).
   적용 중인 테마 이름 옆에 "적용 중" 꼬리표, 별빛 테마에서는 이름 알약에 반짝이 */
.theme-preview .seal { animation: seal-float 3.2s ease-in-out infinite; transform-origin: 50% 20%; }
@keyframes seal-float {
  0%, 100% { transform: translateY(0) rotate(-3deg); }
  50% { transform: translateY(-4%) rotate(3deg); }
}
.shop-card .section-pill { position: relative; display: flex; justify-content: center; align-items: center; gap: calc(var(--u) * 10); }
.applied-tag {
  padding: calc(var(--u) * 3) calc(var(--u) * 10) calc(var(--u) * 2);
  border-radius: 999px;
  background: var(--ink);
  color: #fff6d8;
  font-size: calc(var(--u) * 15);
  -webkit-text-stroke: 0;
}
[data-theme='starlight'] .shop-card .section-pill::after {
  content: '';
  position: absolute;
  top: -20%;
  right: 4%;
  width: calc(var(--u) * 28);
  height: calc(var(--u) * 28);
  background: url('../../assets/ui/fx_board_starlight_glint.webp') center / contain no-repeat;
  filter: drop-shadow(0 0 calc(var(--u) * 2) #8a4dffcc);
  animation: twinkle 2.4s ease-in-out infinite;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .theme-preview .seal, [data-theme='starlight'] .shop-card .section-pill::after { animation: none; }
}

/* ── 결과: 별 점수 · 오늘의 순위 (docs/GAME-PLAN.md 2.2 · 2.3) ─────────────
   별 그림(fx_board_starlight_star)은 가운데 42%만 별이라 240%로 키워 칸에 꽉 차게. 못 딴 별은 흐린 회색 */
.prompt > .result-stars { display: inline-flex; gap: calc(var(--u) * 3); -webkit-text-stroke: 0; text-shadow: none; }
.result-stars .star {
  width: calc(var(--u) * 22);
  height: calc(var(--u) * 22);
  background: url('../../assets/ui/fx_board_starlight_star.webp') center / 240% 240% no-repeat;
  filter: grayscale(1) brightness(0.55) opacity(0.55);
}
.result-stars .star.on { filter: none; animation: star-pop 0.4s cubic-bezier(0.3, 1.6, 0.5, 1) both; }
.result-stars .star.on:nth-child(2) { animation-delay: 0.12s; }
.result-stars .star.on:nth-child(3) { animation-delay: 0.24s; }
@keyframes star-pop { 0% { transform: scale(0.2); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
.prompt > .result-rank {
  padding: calc(var(--u) * 3) calc(var(--u) * 10) calc(var(--u) * 2);
  border-radius: 999px;
  background: var(--gold);
  color: #2c2108;
  font-size: calc(var(--u) * 15);
  -webkit-text-stroke: 0;
  text-shadow: none;
  white-space: nowrap;
  animation: pop-in 0.35s cubic-bezier(0.3, 1.5, 0.5, 1);
}
.prompt > .result-rank[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .result-stars .star.on, .result-rank { animation: none; }
}
/* 연습 칸: 깬 판의 최고 별 (아래 가운데, 작은 금별 셋). 별이 있으면 숫자를 조금 올린다 */
.slot.has-stars > span:first-of-type { transform: translateY(-14%); }
.slot-stars {
  position: absolute;
  left: 50%;
  bottom: 9%;
  transform: translateX(-50%);
  display: flex;
  gap: 2%;
  width: 54%;
  height: 18%;
  pointer-events: none;
}
.slot-stars i {
  flex: 1;
  background: url('../../assets/ui/fx_board_starlight_star.webp') center / 240% 240% no-repeat;
  filter: grayscale(1) brightness(0.6) opacity(0.45);
}
.slot-stars i.on { filter: drop-shadow(0 1px 0 #fff8); }

/* ── 지난 기록: 날짜별 · 달력 탭, 도장 달력 (docs/GAME-PLAN.md 2.2-2) ──────────
   달력 칸: 깬 날 = 도장(기본 초록 체크 · 별빛 인장), 도전만 한 날 = 작은 점, 오늘 = 테두리, 앞으로 올 날 = 흐리게 */
.hview {
  flex: none;
  display: flex;
  gap: calc(var(--u) * 4);
  margin: calc(var(--u) * 6) auto calc(var(--u) * 8);
  padding: calc(var(--u) * 4);
  border-radius: 999px;
  background: #efe3c2;
}
.hview-tab {
  min-width: calc(var(--u) * 96);
  height: calc(var(--u) * 34);
  border-radius: 999px;
  font-size: calc(var(--u) * 18);
  color: var(--ink-soft);
}
.hview-tab.on { background: #fffaf0; color: var(--ink); box-shadow: 0 1px 2px #0002; -webkit-text-stroke: calc(var(--u) * 0.5) currentColor; }
.hbody { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.cal { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.cal-head { flex: none; display: flex; align-items: center; gap: calc(var(--u) * 8); height: calc(var(--u) * 36); padding: 0 calc(var(--u) * 4); }
.cal-title { font-size: calc(var(--u) * 24); -webkit-text-stroke: calc(var(--u) * 0.8) currentColor; }
.cal-count { flex: 1; text-align: right; font-size: calc(var(--u) * 17); color: var(--ink-soft); }
.cal-nav { width: calc(var(--u) * 34); height: calc(var(--u) * 34); border-radius: 50%; font-size: calc(var(--u) * 26); line-height: 1; color: var(--ink); }
.cal-nav:disabled { opacity: 0.25; }
.cal-week { flex: none; display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: calc(var(--u) * 14); color: var(--ink-soft); padding-bottom: calc(var(--u) * 4); }
.cal-week span:first-child { color: #c0564b; }
.cal-grid { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(7, 1fr); grid-auto-rows: 1fr; gap: calc(var(--u) * 3); }
.cal-day { position: relative; display: grid; place-items: center; border-radius: calc(var(--u) * 10); }
.cal-day .n { position: relative; z-index: 1; font-size: calc(var(--u) * 15); color: var(--ink-soft); }
.cal-day.cleared::before {
  content: '';
  position: absolute;
  inset: 4%;
  background: url('../../assets/ui/stamp_checked.webp') center / contain no-repeat;
  animation: stamp 0.45s cubic-bezier(0.3, 1.6, 0.5, 1) both;
}
.cal-day.cleared .n { position: absolute; top: -6%; left: 4%; font-size: calc(var(--u) * 11); }
.cal-day.played::before { content: ''; position: absolute; bottom: 14%; width: calc(var(--u) * 6); height: calc(var(--u) * 6); border-radius: 50%; background: #c9b98f; }
.cal-day.today { box-shadow: inset 0 0 0 calc(var(--u) * 2) var(--gold); }
.cal-day.today .n { color: var(--ink); -webkit-text-stroke: calc(var(--u) * 0.5) currentColor; }
.cal-day.future .n, .cal-day.before .n { opacity: 0.35; }
.cal-day.missed .n { opacity: 0.6; }
[data-theme='starlight'] .hview { background: #ece0fb; }
[data-theme='starlight'] .cal-day.cleared::before { background-image: url('../../assets/ui/theme_starlight_seal.webp'); }
[data-theme='starlight'] .cal-day.played::before { background: #b9a3dc; }
@media (prefers-reduced-motion: reduce) { .cal-day.cleared::before { animation: none; } }

/* ── 연속 기록 보호권 (로비 연속 클리어 알약) ── */
button.streak { font: inherit; color: var(--ink); cursor: pointer; }
button.streak:active { transform: scale(0.97); }
.shield-count {
  margin-left: calc(var(--u) * 8);
  padding: calc(var(--u) * 2) calc(var(--u) * 8);
  border-radius: 999px;
  background: var(--ink);
  color: #fff6d8;
  font-size: calc(var(--u) * 14);
  -webkit-text-stroke: 0;
}

/* ── 상점: 묶음 상품 + 상품 줄 (P3) ──────────────────────────────────────
   대표(별빛 + 광고 제거)는 미리보기 판과 큰 버튼, 그 아래 광고 제거 · 보호권은 한 줄씩. 화면이 낮으면 안에서 스크롤 */
.screen.shop .stage { overflow-y: auto; scrollbar-width: none; padding-bottom: calc(var(--u) * 16); }
.screen.shop .stage::-webkit-scrollbar { display: none; }
.screen.shop .shop-card { gap: calc(var(--u) * 16); padding-top: calc(var(--u) * 26); padding-bottom: calc(var(--u) * 30); }
.screen.shop .theme-preview { --board: calc(var(--u) * 290); }
.shop-note { margin: 0; color: var(--on-green); font-size: calc(var(--u) * 20); text-align: center; }
.shop-rows { width: 100%; display: flex; flex-direction: column; gap: calc(var(--u) * 10); }
.shop-row {
  display: flex;
  align-items: center;
  gap: calc(var(--u) * 12);
  min-height: calc(var(--u) * 70);
  padding: calc(var(--u) * 10) calc(var(--u) * 12) calc(var(--u) * 10) calc(var(--u) * 20);
  border-radius: calc(var(--u) * 22);
  background: linear-gradient(#fffaf0, #f7ead0);
  box-shadow: inset 0 calc(var(--u) * -3) 0 #e2cf9f, 0 calc(var(--u) * 3) 0 #0a3a2633;
  color: var(--ink);
}
.shop-row-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: calc(var(--u) * 3); }
.shop-row-text strong { font-weight: normal; font-size: calc(var(--u) * 22); -webkit-text-stroke: calc(var(--u) * 0.7) currentColor; }
.shop-row-text span { font-size: calc(var(--u) * 14); color: var(--ink-soft); }
.shop-row-buy {
  flex: none;
  min-width: calc(var(--u) * 96);
  height: calc(var(--u) * 46);
  padding: 0 calc(var(--u) * 14);
  border-radius: 999px;
  background: linear-gradient(#ffe36b, #ffc928);
  box-shadow: inset 0 calc(var(--u) * -3) 0 #e9a515;
  color: #3a2a06;
  font-size: calc(var(--u) * 19);
  -webkit-text-stroke: calc(var(--u) * 0.5) currentColor;
}
.shop-row-buy:disabled { filter: grayscale(0.7) opacity(0.6); }
.shop-row-buy:not(:disabled):active { transform: scale(0.96); }
.shop-row-owned { flex: none; padding: calc(var(--u) * 6) calc(var(--u) * 14); border-radius: 999px; background: var(--ink); color: #fff6d8; font-size: calc(var(--u) * 16); }
[data-theme='starlight'] .shop-row { background: linear-gradient(#fffaf0, #f3e8fb); box-shadow: inset 0 calc(var(--u) * -3) 0 #d9c4f0, 0 calc(var(--u) * 3) 0 #12052b33; }

/* 로비 날짜 알약의 요일 꼬리표: 금요일(쉬움)은 초록, 주말 도전판은 금색 */
.lobby-card .title-pill { gap: calc(var(--u) * 10); grid-auto-flow: column; justify-content: center; }
.day-tag {
  padding: calc(var(--u) * 3) calc(var(--u) * 10) calc(var(--u) * 2);
  border-radius: 999px;
  font-size: calc(var(--u) * 15);
  -webkit-text-stroke: 0;
  background: #fffaf0;
  color: var(--ink-soft);
}
.day-tag.hard { background: var(--gold); color: #2c2108; }

/* ── 닉네임 창 (ui/nickname.js) ── */
.nick-input {
  display: block;
  width: 100%;
  height: calc(var(--u) * 58);
  margin: calc(var(--u) * 14) 0 calc(var(--u) * 6);
  padding: 0 calc(var(--u) * 18);
  border: calc(var(--u) * 2.5) solid #e2cf9f;
  border-radius: calc(var(--u) * 16);
  background: #fffdf6;
  color: var(--ink);
  font: inherit;
  font-size: calc(var(--u) * 26);
  text-align: center;
  -webkit-user-select: text;
  user-select: text;
}
.nick-input:focus { outline: none; border-color: var(--gold); box-shadow: 0 0 0 calc(var(--u) * 3) #ffd84a55; }
.nick-msg { min-height: calc(var(--u) * 40); margin: 0 0 calc(var(--u) * 4); font-size: calc(var(--u) * 16); line-height: 1.35; color: var(--ink-soft); text-align: center; }
.nick-msg.bad { color: #c0453a; }
[data-theme='starlight'] .nick-input { border-color: #d9c4f0; }
.nick-change {
  max-width: 60%;
  padding: calc(var(--u) * 6) calc(var(--u) * 14);
  border-radius: 999px;
  background: #efe3c2;
  color: var(--ink);
  font-size: calc(var(--u) * 20);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-theme='starlight'] .nick-change { background: #ece0fb; }

/* ── 지난 기록: 이번 달 랭킹 탭 (api/ranking.php) ── */
.rank { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: calc(var(--u) * 8); }
.rank-head { flex: none; display: flex; align-items: baseline; justify-content: space-between; padding: 0 calc(var(--u) * 6); }
.rank-title { font-size: calc(var(--u) * 22); -webkit-text-stroke: calc(var(--u) * 0.7) currentColor; }
.rank-count { font-size: calc(var(--u) * 15); color: var(--ink-soft); }
.rank-list { flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: none; display: flex; flex-direction: column; gap: calc(var(--u) * 4); }
.rank-list::-webkit-scrollbar { display: none; }
.rank-row {
  flex: none;
  display: grid;
  grid-template-columns: calc(var(--u) * 40) 1fr auto;
  align-items: center;
  gap: calc(var(--u) * 10);
  height: calc(var(--u) * 42);
  padding: 0 calc(var(--u) * 12);
  border-radius: calc(var(--u) * 12);
  font-size: calc(var(--u) * 19);
}
.rank-row:nth-child(odd) { background: #f8eccd; }
.rank-row.me { background: var(--gold); color: #2c2108; -webkit-text-stroke: calc(var(--u) * 0.5) currentColor; }
.rank-no { text-align: center; font-size: calc(var(--u) * 18); color: var(--ink-soft); }
.rank-no.top1, .rank-no.top2, .rank-no.top3 { color: #fff; border-radius: 50%; width: calc(var(--u) * 30); height: calc(var(--u) * 30); line-height: calc(var(--u) * 30); justify-self: center; }
.rank-no.top1 { background: #e9b20e; }
.rank-no.top2 { background: #a7a9ac; }
.rank-no.top3 { background: #c68443; }
.rank-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rank-days { font-size: calc(var(--u) * 17); color: var(--ink-soft); }
.rank-row.me .rank-days, .rank-row.me .rank-no { color: #2c2108; }
.rank-msg { margin: calc(var(--u) * 10) 0; text-align: center; font-size: calc(var(--u) * 16); color: var(--ink-soft); }
.rank-cta {
  flex: none;
  min-height: calc(var(--u) * 46);
  padding: calc(var(--u) * 8) calc(var(--u) * 14);
  border-radius: calc(var(--u) * 14);
  background: var(--gold);
  color: #2c2108;
  font-size: calc(var(--u) * 16);
  box-shadow: inset 0 calc(var(--u) * -3) 0 #e9a515;
}
.hview-tab { min-width: calc(var(--u) * 84); }
[data-theme='starlight'] .rank-row:nth-child(odd) { background: #f1e6fb; }

/* ── 기록 화면: 크림 패널 위쪽 "기록 · 랭킹" 탭 ──
   패널 높이(597)는 그대로라 위 탭 자리만큼 연속 · 이번 달 칸을 줄였다 */
.htabs {
  flex: none;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: calc(var(--u) * 6);
  margin-top: calc(var(--u) * 4);
  padding: calc(var(--u) * 5);
  border-radius: 999px;
  background: #efe3c2;
}
.htabs-tab {
  height: calc(var(--u) * 48);
  border-radius: 999px;
  font-size: calc(var(--u) * 25);
  color: var(--ink-soft);
}
.htabs-tab.on {
  background: #c8ebc0;
  color: var(--ink);
  box-shadow: inset 0 2px 0 #fff8, 0 calc(var(--u) * 2) 0 #0a3a2622;
  -webkit-text-stroke: calc(var(--u) * 0.8) currentColor;
}
.htab { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.htab > .rank { margin-top: calc(var(--u) * 14); }
.history-card .stats { height: calc(var(--u) * 168); padding: calc(var(--u) * 10) 0; }
.history-card .stats > div:not(.vsep) { gap: calc(var(--u) * 16); }
[data-theme='starlight'] .htabs { background: #ece0fb; }
[data-theme='starlight'] .htabs-tab.on { background: #dcc8fa; }
