/* ─────────────────────────────────────────────
   MUSTER Web — 취향의 발견 + 카드 꾸미기
   토큰·간격·타입은 Muster 앱 DESIGN_SYSTEM.md 규칙을 웹 화면 폭에 맞춰 확장했다.
   ───────────────────────────────────────────── */

:root {
  --bg: #fbfbfb;
  --surface: #ffffff;
  --subtle: #f5f6f8;
  --chip: #f2f4f6;
  --line: #e5e8eb;
  --t1: #191f28;
  --t2: #6b7684;
  --t3: #b0b8c1;
  --ink: #191f28;
  --logo: #34393e;
  --on-ink: #ffffff;
  --lime: #e4f6a0;
  --shadow-1: 0 1px 3px rgba(25, 31, 40, 0.08);
  --shadow-2: 0 4px 16px rgba(25, 31, 40, 0.12);
  --shadow-3: 0 10px 26px rgba(25, 31, 40, 0.14);
  /* 워드마크 크기 — 창 폭을 따라간다. 1440px 에서 지금까지의 104px 과 같다.
     헤더 높이·햄버거 크기가 전부 여기서 나온다. 3.81 은 마크 SVG 의 가로세로 비율. */
  --brand-w: clamp(84px, calc(var(--vw, 100vw) * 0.072), 190px);
  --brand-h: calc(var(--brand-w) / 3.81);
  /* 헤더 = 로고 위 여백 + 워드마크 높이 + 아래 여백.
     여백은 창 높이에 비례한다 — 낮은 창에서 헤더가 화면을 다 먹지 않게.
     890px 이상 높으면 지금까지의 64/40 그대로다. */
  --nav-top: clamp(22px, calc(var(--vh, 100vh) * 0.072), 64px);
  --nav-bottom: clamp(14px, calc(var(--vh, 100vh) * 0.045), 40px);
  --nav-h: calc(var(--nav-top) + var(--brand-h) + var(--nav-bottom));
  /* 화면 양옆 여백 — 폭에 비례해 늘고, 너무 좁거나 넓어지지 않게 양쪽을 묶어 둔다 */
  --gutter: clamp(28px, calc(var(--vw, 100vw) * 0.085), 200px);
  /* 글을 읽는 화면(보관함)만 이 폭으로 묶는다.
     발견·내비는 폭 제한 없이 --gutter 만큼만 비우므로, 화면이 커져도 여백 비율이 그대로다. */
  --page: 1600px;
  --font: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont,
    "Apple SD Gothic Neo", "Noto Sans KR", sans-serif;
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #161617;
    --surface: #1f1f21;
    --subtle: #232326;
    --chip: #26272c;
    --line: #2e2f34;
    --t1: #f3f4f6;
    --t2: #9a9aa2;
    --t3: #6b6c72;
    --ink: #f3f4f6;
    --logo: #f3f4f6;
    --on-ink: #161617;
    --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.4);
    --shadow-2: 0 4px 16px rgba(0, 0, 0, 0.5);
    --shadow-3: 0 10px 26px rgba(0, 0, 0, 0.55);
    color-scheme: dark;
  }
}

*, *::before, *::after {
  box-sizing: border-box;
  /* 한글 자간 -5% — em 이라 글자 크기마다 제 비율로 계산된다.
     라틴 대문자처럼 트래킹이 필요한 몇 곳은 아래에서 따로 지정한다. */
  letter-spacing: -0.05em;
}

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--t1);
  font-family: var(--font);
  word-break: keep-all;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden;
}

/* 폼 요소는 브라우저 기본값이 글꼴·자간을 되돌린다 (자간은 위 * 규칙이 다시 잡아 준다) */
button, input, textarea, select { font: inherit; color: inherit; }
button { border: none; background: none; padding: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }
p, h1, h2, h3 { margin: 0; }
img { display: block; user-select: none; -webkit-user-drag: none; }

/* ── 상단 내비 ───────────────────────────── */
.topnav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 30;
  height: var(--nav-h);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(14px);
}
/* 발견 화면 — 카드가 헤더 뒤로 지나가야 하므로 배경을 거의 비운다.
   글자가 묻히지 않게 위쪽만 아주 옅은 그라데이션을 둔다. */
body[data-tab='discover'] .topnav,
body[data-tab='shelf'] .topnav {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--bg) 72%, transparent) 0%,
    color-mix(in srgb, var(--bg) 34%, transparent) 55%,
    transparent 100%);
  backdrop-filter: none;
}
.nav-in {
  height: 100%;
  padding: var(--nav-top) var(--gutter) var(--nav-bottom);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  grid-template-areas: "menu brand end";
  align-items: center;
  gap: 16px;
}
/* 워드마크는 화면 가운데 — 좌우 칸이 같은 1fr 이라 늘 정중앙에 온다 */
.brand { grid-area: brand; justify-self: center; display: block; width: var(--brand-w); color: var(--logo); }
.brand svg { display: block; width: 100%; height: auto; }

/* 마이 갤러리에서 꾸미러 들어왔을 때 — 햄버거 자리에 놓이는 '갤러리로 돌아가기' */
.nav-back {
  /* 바탕 없이 화살표와 글자만 — 햄버거가 있던 자리라 헤더가 조용해야 한다 */
  grid-area: menu; justify-self: start;
  display: inline-flex; align-items: center; gap: 5px;
  height: 34px; padding: 0; background: none;
  color: var(--t1); font-size: 13px; font-weight: 600; white-space: nowrap;
  transition: color 0.15s;
}
.nav-back:hover { color: var(--t2); }
.nav-back:active { opacity: 0.6; }
.nav-back svg { width: 16px; height: 16px; flex: 0 0 auto; }
body.has-back .hamburger { display: none; }

/* 햄버거 — 세 줄이 열리면 X 로 접힌다 */
.hamburger {
  grid-area: menu; justify-self: start; position: relative;
  /* 높이를 워드마크와 같게 둬야 로고 위 여백(--nav-top)이 그대로 지켜진다.
     누르는 범위는 아래 ::after 로 넓힌다(레이아웃에는 영향 없음) */
  /* 막대 굵기와 간격도 워드마크를 따라간다. X 로 접을 때 옮기는 거리가
     이 둘에서 나오므로(간격 + 굵기 = 막대 사이 중심거리) 한 곳에 모아 둔다.
     1440px 에서 굵기 2px · 간격 5px · 이동 7px 로, 예전 값과 같다. */
  --bar-h: max(1.5px, calc(var(--brand-h) * 0.073));
  /* 두 줄이라 간격을 조금 넓게 — 3줄 때 값 그대로면 등호처럼 붙어 보인다 */
  --bar-gap: calc(var(--brand-h) * 0.26);
  /* 두 선의 중심 사이 거리. X 로 접을 때 각자 이 절반씩 가운데로 온다 */
  --bar-step: calc(var(--bar-gap) + var(--bar-h));
  width: calc(var(--brand-h) * 0.8); height: var(--brand-h); padding: 0;
  display: grid; align-content: center; justify-items: start; gap: var(--bar-gap);
}
/* 누르는 범위는 버튼보다 넉넉하게 (레이아웃에는 영향 없음) */
.hamburger::after {
  content: ''; position: absolute;
  inset: calc(var(--brand-h) * -0.4) calc(var(--brand-h) * -0.47);
}
.hamburger span {
  display: block; width: 100%; height: var(--bar-h);
  border-radius: 999px; background: var(--t1);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.18s;
}
.hamburger:hover span { background: var(--t2); }
/* 두 줄이 똑같은 굵기로 보이게 — 굵기와 간격을 정수 픽셀로 맞춘다.
   소수점(예: 굵기 1.99px · 간격 7.07px)으로 두면 두 줄이 서로 다른 소수 자리에 놓여,
   아래 줄만 반 픽셀에 걸쳐 흐리게(=얇게) 그려진다.
   굵기와 '간격 + 굵기'가 모두 정수면 두 줄이 같은 소수 자리에 놓여 똑같이 보인다. */
@supports (height: round(nearest, 3.3px, 1px)) {
  .hamburger {
    --bar-h: max(2px, round(nearest, calc(var(--brand-h) * 0.073), 1px));
    --bar-gap: round(nearest, calc(var(--brand-h) * 0.26), 1px);
  }
}
/* X — 두 선이 가운데로 모여 교차한다. 각자 중심거리의 절반만 움직이면 정확히 만난다.
   고정 px 로 두면 크기가 바뀔 때 팔이 어긋난다 */
.hamburger.is-open span:nth-child(1) { transform: translateY(calc(var(--bar-step) / 2)) rotate(45deg); }
.hamburger.is-open span:nth-child(2) { transform: translateY(calc(var(--bar-step) / -2)) rotate(-45deg); }

/* 메뉴가 열려 있으면 헤더도 불투명하게 — 뒤로 지나가는 카드가 비치지 않도록 */
body.menu-open .topnav,
body[data-tab='discover'].menu-open .topnav,
body[data-tab='shelf'].menu-open .topnav {
  background: var(--bg);
  backdrop-filter: none;
}

/* 메뉴 — 헤더 아래를 덮는 큰 글씨 패널 */
.menu {
  position: fixed; z-index: 29;
  top: var(--nav-h); left: 0; right: 0; bottom: 0;
  padding: clamp(32px, 7vh, 88px) var(--gutter) 0;
  background: var(--bg);
  display: flex; flex-direction: column; align-items: flex-start; gap: clamp(4px, 1vh, 14px);
  animation: menuIn 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes menuIn { from { opacity: 0; transform: translateY(-12px); } to { opacity: 1; transform: none; } }
.menu[hidden] { display: none; }

/* 선택은 상자가 아니라 글자색으로 — 나머지는 연한 회색 */
.nlink {
  padding: 6px 0;
  font-size: clamp(34px, 5vw, 72px);
  font-weight: 400;
  /* 큰 글씨는 자간이 넓어 보여서 본문(-5%)보다 조금 더 좁힌다 */
  letter-spacing: -0.07em;
  line-height: 1.15;
  color: var(--t3);
  background: none;
  transition: color 0.2s ease, transform 0.2s cubic-bezier(0.22, 1, 0.36, 1);
  transform-origin: left center;
}
.nlink:hover { color: var(--t2); }
.nlink.is-on { color: var(--t1); }
.nlink:active { transform: scale(0.985); }

/* 하나씩 차례로 올라오게 */
.menu .nlink { animation: itemIn 0.42s cubic-bezier(0.22, 1, 0.36, 1) backwards; }
.menu .nlink:nth-child(1) { animation-delay: 0.04s; }
.menu .nlink:nth-child(2) { animation-delay: 0.09s; }
.menu .nlink:nth-child(3) { animation-delay: 0.14s; }
.menu .nlink:nth-child(4) { animation-delay: 0.19s; }
.menu .nlink:nth-child(5) { animation-delay: 0.24s; }
@keyframes itemIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* ── 화면 ────────────────────────────────── */
.screen {
  position: fixed;
  top: var(--nav-h); left: 0; right: 0; bottom: 0;
}
.view { position: absolute; inset: 0; }
.view[hidden] { display: none; }

/* ── 발견(취향의 발견) ───────────────────── */
/* 카드 벽은 헤더 높이만큼 위로 더 뻗는다 — 카드가 햄버거·워드마크·커스텀 뒤로 지나간다 */
.dc {
  position: absolute; left: 0; right: 0; bottom: 0;
  top: calc(-1 * var(--nav-h));
  overflow: hidden; touch-action: none;
}
/* 헤더 오른쪽 칸 — 화면별 도구가 들어간다 (지금은 발견의 '커스텀') */
.nav-end { grid-area: end; justify-self: end; }
.dc-custom { position: relative; display: flex; flex-direction: column; align-items: flex-end; }
.dc-custom-btn {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: clamp(12px, calc(var(--vw, 100vw) * 0.0097), 20px); font-weight: 700; color: var(--t1);
}
.dc-custom-btn:hover { color: var(--t2); }
.dc-custom-btn:active { opacity: 0.6; }
.dc-caret { display: inline-block; transform: scaleY(1.2); transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); }
.dc-custom.is-open .dc-caret { transform: scaleY(1.2) rotate(180deg); }

/* 커스텀 패널 — 헤더 높이를 밀지 않게 버튼 아래에 띄운다 */
.dc-panel {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 2;
  /* 버튼 폭에 갇히지 않게 내용 폭을 쓴다 */
  width: max-content;
  overflow: hidden;
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows 0.35s cubic-bezier(0.4, 0, 0.2, 1);
  border-radius: 12px;
}
.dc-custom.is-open .dc-panel {
  grid-template-rows: 1fr;
  background: color-mix(in srgb, var(--surface) 96%, transparent);
  backdrop-filter: blur(12px);
  box-shadow: var(--shadow-2);
  padding: 0 14px 14px;
}
.dc-panel > div { overflow: hidden; }
.mixrow { margin-top: 14px; width: 190px; }
.mixrow-top { display: flex; align-items: center; justify-content: space-between; }
.mixrow-top span { font-size: 13px; font-weight: 600; color: var(--t1); }
.mixbar { margin-top: 8px; height: 16px; display: flex; align-items: center; cursor: pointer; touch-action: none; }
.mixbar-track { position: relative; width: 100%; height: 3px; background: var(--line); }
.mixbar-fill { position: absolute; left: 0; top: 0; height: 100%; background: var(--t1); }
.mixbar-knob {
  position: absolute; top: 50%; width: 12px; height: 12px; margin: -6px 0 0 -6px;
  border-radius: 9999px; background: var(--t1);
}

/* 카드가 흐르는 벽 */
.dc-wall { position: absolute; inset: 0; overflow: hidden; }
/* will-change 를 두지 않는다 — 두면 브라우저가 배율 1 에서 한 번 그린 그림을 그대로 늘려 써서,
   핀치로 확대하면 카드가 뿌옇게 번진다. 없으면 확대가 끝날 때 그 배율로 다시 선명하게 그린다 */
.dc-zoom { position: absolute; inset: 0; }
/* 카드 벽 — 가로 배치는 전부 CSS 가 맡는다.
   JS 가 잰 픽셀 폭을 카드에 박아 넣으면 그 값이 낡았을 때 창 밖으로 삐져나가므로,
   JS 는 열 수(--cols)만 정하고 실제 폭은 늘 지금 컨테이너 기준으로 계산되게 한다. */
.dc-track {
  position: absolute; left: 0; right: 0; top: 0;
  padding: 0 var(--gutter);
  display: flex; flex-direction: column; will-change: transform;
}
/* 열 간격은 % — 상한에 걸리지 않으면 양끝이 여백선에 딱 맞고, 걸리면 가운데 정렬된다 */
.dc-row { display: flex; justify-content: center; align-items: flex-start; column-gap: var(--card-gap, 14%); }
.wcard {
  position: relative;
  /* 폭을 %로 잡아 두면 창이 바뀌어도 늘 지금 컨테이너 안에 들어간다 (양끝은 여백선에 딱 맞음) */
  flex: 0 0 auto;
  width: var(--card-w, 8.8%);
  min-width: 0;
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
.wcard:hover { transform: translateY(-4px); }
.wcard:active { transform: scale(0.95); }
.dc-fade {
  position: absolute; left: 0; right: 0; height: 64px; z-index: 10; pointer-events: none;
}
.dc-fade-b { bottom: 0; background: linear-gradient(0deg, var(--bg) 0%, transparent 100%); }
.dc-hint {
  position: absolute; left: 50%; bottom: 20px; transform: translateX(-50%);
  z-index: 12; pointer-events: none; padding: 8px 16px; border-radius: 9999px;
  background: color-mix(in srgb, var(--ink) 84%, transparent); color: var(--on-ink);
  font-size: 12px; font-weight: 600; transition: opacity 0.6s;
}

/* ── 카드 케이스 (앱 CardCase 창 비율 그대로) ── */
.case { position: relative; width: 100%; aspect-ratio: 1200 / 2016; container-type: inline-size; }
.case-card {
  /* 좌표는 js/case.js 의 CASE.card 와 같은 값이다 — 케이스 PNG 의 흰 창을 딱 덮는다.
     창은 모서리가 각진 직사각형이라 여백 없이 채워도 모서리가 튀지 않는다. */
  position: absolute; top: 27.7%; left: 12.0%; width: 76.17%; height: 63.87%;
  /* 창을 꽉 채운다. contain 으로 두면 카드 비율(0.706~0.744)과 창 비율(0.709)이
     미세하게 달라 위아래에 흰 여백이 남는다 — 케이스의 흰 창이 비쳐 보인다.
     cover 로 잘리는 건 한쪽 1% 남짓이라 눈에 띄지 않는다.
     padding 은 두지 않는다. 조금이라도 남기면 그 틈으로 흰 창이 다시 보인다. */
  object-fit: cover;
  background: transparent;
}
.case-label {
  /* js/case.js 의 CASE.label 과 같은 값 — 케이스 PNG 의 흰 라벨 상자를 빈틈없이 덮는다 */
  position: absolute; top: 4.415%; left: 9.333%; width: 81.833%; height: 14.087%;
  overflow: hidden; background: #ffffff; transition: background 0.2s ease; container-type: inline-size;
  /* 카드가 <button> 안에 놓이는 화면(발견 벽·전시실)에서는 브라우저 기본값 때문에
     글이 가운데로 몰린다 — 라벨은 어디에 놓이든 왼쪽 정렬로 고정한다 */
  text-align: left;
}
.case-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; pointer-events: none; }
/* 배경 연장 — 카드 그림을 케이스 둘레로 이어 그린 층. 케이스 PNG 아래에 깔린다.
   바깥(.case-ext)은 케이스 실루엣으로 자르고, 안쪽(.ext-in)은 흐리게 한다.
   안쪽에 overflow 를 두지 않는 이유 — 잘린 뒤에 흐리면 케이스 가장자리가 투명하게 바랜다 */
.case-ext {
  position: absolute; inset: 0; pointer-events: none;
  -webkit-mask: var(--mask) center / 100% 100% no-repeat;
  mask: var(--mask) center / 100% 100% no-repeat;
}
.ext-in { position: absolute; inset: 0; filter: blur(1cqw) saturate(1.08); }
.ext-tile { position: absolute; overflow: hidden; }
.ext-tile img {
  position: absolute; left: -5.55%; top: -5.55%; width: 111.1%; height: 111.1%;
  object-fit: cover; display: block;
}
/* 범퍼 — PA:V 스냅 케이스. 슬랩을 감싸는 알루미늄 틀 + 그 안쪽의 검은 고무 테.
   색은 js 가 --rim 으로 넣고, 마감(rim-metal · rim-anod · rim-matte)은 빛만 바꾼다.
   ::before = 금속 틀(가운데를 mask 로 뚫은 고리), ::after = 검은 고무 테.
   그림자는 틀 자신이 아니라 부모의 drop-shadow 로 낸다 — mask 가 box-shadow 를 지운다.
   두께·반지름은 js/export.js 의 RIM 과 같은 값이다. */
.case-rim {
  --rim: #a8232a;
  --rim-w: 2.8cqw;      /* 알루미늄 틀 */
  --rim-gasket: 1.4cqw; /* 검은 고무 테 */
  --rim-r: 4.6cqw;
  position: absolute; inset: 0; border-radius: var(--rim-r);
  filter: drop-shadow(0 0.5cqw 0.9cqw rgba(16, 14, 12, 0.24));
  pointer-events: none;
}
.case-rim::before, .case-rim::after { content: ''; position: absolute; }
.case-rim::before {
  inset: 0; border-radius: inherit; padding: var(--rim-w);
  /* 위·왼쪽에서 빛이 온다 — 윗변·왼변은 밝고, 아랫변·오른변은 어둡다 */
  background:
    linear-gradient(to bottom, rgba(255,255,255,var(--rim-hi)), rgba(255,255,255,0) 14%, rgba(0,0,0,0) 86%, rgba(0,0,0,var(--rim-lo))),
    linear-gradient(to right, rgba(255,255,255,calc(var(--rim-hi) * 0.6)), rgba(255,255,255,0) 12%, rgba(0,0,0,0) 88%, rgba(0,0,0,calc(var(--rim-lo) * 0.8))),
    var(--rim-sheen, none),
    var(--rim);
  /* 바깥 모서리의 모따기 — 빛을 받아 가늘게 반짝인다 */
  box-shadow: inset 0 0 0 0.3cqw rgba(255,255,255,var(--rim-edge));
  -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 exclude, linear-gradient(#000 0 0);
}
.case-rim::after {
  inset: var(--rim-w);
  border: var(--rim-gasket) solid #0e0f11;
  border-radius: calc(var(--rim-r) - var(--rim-w));
  /* 틀 안쪽 모서리의 모따기(outline) + 고무 테가 슬랩 위에 드리우는 얕은 그늘 */
  outline: 0.16cqw solid color-mix(in srgb, var(--rim), #fff calc(var(--rim-edge) * 60%));
  box-shadow: inset 0 0.35cqw 0.7cqw rgba(0, 0, 0, 0.28);
}
/* 마감별 빛 — hi 윗변 밝기 · lo 아랫변 어둠 · edge 모서리 반짝임 */
.rim-anod  { --rim-hi: 0.20; --rim-lo: 0.26; --rim-edge: 0.30; }
.rim-matte { --rim-hi: 0.16; --rim-lo: 0.14; --rim-edge: 0.18; }
.rim-metal {
  --rim-hi: 0.45; --rim-lo: 0.30; --rim-edge: 0.55;
  /* 골드·실버는 광이 비스듬히 두 번 흐른다 */
  --rim-sheen: linear-gradient(118deg,
    rgba(255,255,255,0) 18%, rgba(255,255,255,0.42) 30%, rgba(255,255,255,0) 40%,
    rgba(0,0,0,0.14) 55%, rgba(255,255,255,0.3) 72%, rgba(255,255,255,0) 82%);
}
/* 실제 등급 레이블 사진 — 창을 꽉 채운다 */
/* 실제 등급 레이블 사진 — 창을 꽉 채운다.
   contain 으로 두면 사진 비율이 창(3.614)과 조금만 달라도 양옆에 흰 띠가 남는다
   (케이스 창이 흰색이라 그대로 비쳐 보인다). 라벨 사진은 전부 창 비율에 맞춰
   테두리 색을 늘려 두었으므로 cover 여도 잘리는 곳이 없다. */
.lb-real { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 라벨 안쪽 — 카드 설명이 왼쪽 위, 마크가 왼쪽 아래.
   예전엔 오른쪽에 등급(D · DECO)이 있었는데, 뜻이 없어서 뺐다 */
.lb-l {
  position: absolute; left: 4.2%; top: 9%; bottom: 9%; right: 4.2%;
  display: flex; flex-direction: column; justify-content: space-between;
}
/* 글줄은 오른쪽 '00' 앞에서 끊는다 — 00 이 라벨 폭의 약 26% 를 차지한다 */
.lb-txt { min-width: 0; max-width: 64%; }
.lb-line { font-size: 3.6cqw; font-weight: 600; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* 워드마크는 라벨 왼쪽 아래 — 글줄 바로 밑, 같은 왼쪽 선에 맞춘다 */
.lb-mark { line-height: 0; flex: 0 0 auto; align-self: flex-start; }
.lb-mark svg { display: block; }
/* 오른쪽 '00' — 라벨 높이의 82%, 위아래 가운데. 높이 27.67cqw(라벨 비율 3.614) × 0.82 */
.lb-num {
  position: absolute; right: 4.2%; top: 50%; transform: translateY(-50%);
  height: 22.7cqw; aspect-ratio: 135 / 120; line-height: 0;
}
.lb-num svg { display: block; width: 100%; height: 100%; }

/* 스티커 */
.case-stickers { position: absolute; inset: 0; }
.stk {
  position: absolute; display: grid; place-items: center; line-height: 1; will-change: transform;
  user-select: none;
}
.stk-emoji { line-height: 1; }
/* 보석 — 사진에서 오려낸 그림. 카드 위에 얹힌 것처럼 보이도록 그림자를 한 겹 깐다.
   높이는 js 가 정하고(이모지 글자 크기와 같은 기준) 가로는 비율이 따라온다. */
.stk-img { display: block; width: auto; pointer-events: none; filter: drop-shadow(0 0.06em 0.09em rgba(20, 16, 12, 0.45)); }
.stk-tag {
  display: inline-block; padding: 0.45em 0.85em; border-radius: 9999px;
  font-weight: 800; letter-spacing: 0.06em; white-space: nowrap; line-height: 1;
}

/* ── 꾸미기 ──────────────────────────────── */
/* ── 꾸미기 — 왼쪽 세로 레일(내 카드) · 화면 정중앙 카드 · 오른쪽 도구 박스 ── */
/* overflow 를 잘라내지 않는다 — 카드 그림자가 아래로 뻗어야 한다 */
.dz { position: absolute; inset: 0; }

/* 카드 판은 화면 전체를 차지하고 그 한가운데에 놓인다 → 카드가 화면 정중앙 */
.dz-main { position: absolute; inset: 0; display: flex; flex-direction: column; }
/* 꾸미기 화면의 여백·칸 높이는 창 크기를 따라간다.
   낮은 창에서는 줄어들어 도구가 잘리지 않고, 넉넉한 창에서는 원래 값 그대로다. */
.dz {
  --stage-pad-y: clamp(12px, calc(var(--vh, 100vh) * 0.026), 24px);
  --panel-gap: clamp(14px, calc(var(--vh, 100vh) * 0.026), 24px);
  --btn-h: clamp(30px, calc(var(--vh, 100vh) * 0.044), 36px);
}
.dz-stage {
  flex: 1 1 auto; min-height: 0;
  display: grid; place-items: center;
  /* 아래 여백에 헤더의 '로고 아래 여백'을 더해 로고↔카드 와 카드↔화면 아래를 같게 맞춘다.
     여백도 창 크기를 따라간다 — 좁거나 낮은 창에서 카드가 쓸 자리를 뺏지 않게 */
  padding: var(--stage-pad-y) clamp(16px, calc(var(--vw, 100vw) * 0.044), 64px)
           calc(var(--stage-pad-y) + var(--nav-bottom));
  container-type: size;
}
/* 카드 그림자 — 창으로 들어온 햇살처럼 (해는 작고 먼 광원이라 경계가 또렷하다).
   케이스 PNG 는 테두리가 반투명(알파 60~90)이라 뒤에 그림자를 깔면 그대로 비쳐 케이스가 어두워진다.
   그래서 케이스 뒤에 '페이지 배경색의 불투명 판'을 두고 그 판이 그림자를 만들게 한다.
   판은 배경과 같은 색이라 보이지 않고, 그림자가 케이스를 통과하지도 못한다. */
.dz-canvas .case::before {
  content: '';
  position: absolute;
  /* 케이스 몸통 안쪽으로 살짝 넣어 판이 실루엣 밖으로 삐져나오지 않게 */
  top: 2.4%; left: 5.4%; right: 5.2%; bottom: 1.8%;
  border-radius: 3cqw;
  background: var(--bg);
  /* 진짜 그림자처럼 — 카드에 닿는 곳은 진하고 또렷하게, 멀어질수록 길어지며 옅어진다.
     한 층씩 조금 더 밀고·조금 더 번지고·조금 더 옅게 겹쳐서 자연스러운 감쇠를 만든다. */
  box-shadow:
    0 0 2px rgba(24, 24, 27, 0.17),        /* 사방으로 닿는 접지 그늘 */
    0 2px 3px rgba(24, 24, 27, 0.15),
    7px 9px 6px rgba(24, 24, 27, 0.15),
    14px 18px 10px rgba(24, 24, 27, 0.12),
    23px 29px 16px rgba(24, 24, 27, 0.095),
    33px 42px 24px rgba(24, 24, 27, 0.07),
    45px 57px 34px rgba(24, 24, 27, 0.045),
    58px 74px 46px rgba(24, 24, 27, 0.025); /* 끝은 거의 사라진다 */
}

.dz-canvas {
  position: relative;
  width: min(100cqw, calc(100cqh * 0.5952), clamp(240px, calc(var(--vw, 100vw) * 0.26), 560px));
  aspect-ratio: 1200 / 2016;
  min-width: 0;
  touch-action: none;
}

/* 왼쪽 세로 레일 — 담은 카드 */
.dz-rail {
  position: absolute; z-index: 2;
  /* .mycard 안쪽 여백 9px 만큼 당겨서, 카드 그림의 왼쪽 끝이 정확히 --gutter 선에 온다 */
  left: calc(var(--gutter) - 9px); top: var(--panel-top, 44px); bottom: var(--stage-pad-y);
  width: clamp(72px, calc(var(--vw, 100vw) * 0.0667), 130px);
  display: flex; flex-direction: column;
  /* 제목은 붙박이로 두고 목록만 스크롤한다 */
  overflow: hidden;
  scrollbar-width: none;
}
.dz-rail::-webkit-scrollbar { display: none; }
.dz-rail .mycards {
  margin-top: 14px;
  /* 남는 높이를 다 쓰고, 넘치면 이 안에서만 스크롤된다 — 밖으로 잘리지 않게 */
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; gap: clamp(14px, calc(var(--vh, 100vh) * 0.028), 28px);
  padding: 4px 0 24px;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none;
}
.dz-rail .mycards::-webkit-scrollbar { display: none; }
/* '내 카드 N장' 글자를 카드 그림의 왼쪽 끝에 맞춘다 (카드 둘레 여백만큼 들여쓰기) */
.dz-rail .side-h { padding-left: 9px; }
.dz-rail .mycard { width: 100%; }

/* 오른쪽 도구 — 상자 없이 배경 위에 그대로 */
.dz-side {
  position: absolute; z-index: 2;
  right: var(--gutter); top: var(--panel-top, 44px); bottom: var(--stage-pad-y);
  width: clamp(168px, calc(var(--vw, 100vw) * 0.155), 300px);
  /* 도구·스티커·아이콘을 위에서 아래로 놓고, 남는 높이는 스티커 칸이 가져간다 */
  display: flex; flex-direction: column;
  overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none;
}
.dz-side::-webkit-scrollbar { display: none; }
.bar-sec { min-width: 0; }
.bar-sec + .bar-sec { margin-top: var(--panel-gap); }
.bar-label, .bar-tools, .bar-case, .bar-actions { flex: 0 0 auto; }
/* 스티커 — 자리가 넉넉하면 제 높이 그대로, 모자라면 줄어들면서
   상자 안에서만 스크롤된다 (늘리지는 않는다: 넓은 창에서 빈 상자가 생기지 않게) */
/* 최소 높이 — 카테고리 네 줄 + 스티커 두 줄. 이보다 모자라면 줄이지 않고 오른쪽 칸 전체가 스크롤된다 */
.bar-stickers { flex: 0 1 auto; min-height: 300px; display: flex; flex-direction: column; }
.bar-stickers .tray-box { flex: 0 1 auto; min-height: 0; display: flex; flex-direction: column; }
.bar-stickers .tray-cats { flex: 0 0 auto; }
.bar-stickers .tray-grid {
  flex: 1 1 auto; min-height: 0; align-content: start;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none;
}
.bar-stickers .tray-grid::-webkit-scrollbar { display: none; }

/* 좁은 화면(보이는 폭 1024px 미만) — 위에서 아래로 쌓고 페이지가 스크롤된다.
   미디어 쿼리 대신 속성을 쓰는 이유: 미디어 쿼리는 창 전체 폭만 보므로,
   창이 모니터 밖으로 걸쳐 실제로는 좁아진 경우를 놓친다.
   보이는 폭은 js/fit.js 가 재서 data-fit-narrow 로 알려 준다
   (화면을 전부 JS 가 그리는 앱이라 이 속성은 첫 그리기 전에 이미 붙어 있다). */
html[data-fit-narrow] {
  .dz { display: flex; flex-direction: column; overflow-y: auto; overscroll-behavior: contain; }
  .dz-rail, .dz-main, .dz-side { position: static; width: auto; }
  /* 쌓을 때는 저마다 제 높이를 지킨다. flex 가 눌러서 줄이면
     레일과 도구가 납작해진 채 잘려 보이고, 그러면 스크롤도 생기지 않는다 */
  .dz-rail, .dz-side { flex: 0 0 auto; overflow: visible; }
  .dz-rail { margin: 4px 20px 0; }
  .dz-rail .mycards {
    flex: 0 0 auto;
    flex-direction: row; gap: 16px;
    overflow-x: auto; overflow-y: hidden;
    padding: 6px 8px;
  }
  .dz-rail .mycard { width: 44px; flex: 0 0 auto; }
  /* 카드 판은 창 높이에 맞춰 제 몫만 쓰고, 나머지는 도구 자리로 남긴다 */
  .dz-main { flex: 0 0 auto; height: clamp(240px, calc(var(--vh, 100vh) * 0.52), 520px); min-height: 0; }
  .dz-stage { padding: 16px 20px 24px; }
  .dz-side { margin: 8px 20px 24px; }
  /* 여기서는 페이지 전체가 스크롤되므로 스티커 칸은 제 높이대로 펼쳐 둔다 */
  .bar-stickers, .bar-stickers .tray-box { display: block; }
  .bar-stickers .tray-grid { overflow: visible; }
}

.dz-empty { text-align: center; max-width: 420px; }
.dz-empty h2 { font-size: 20px; font-weight: 700; color: var(--t1); }
.dz-empty p { margin-top: 10px; font-size: 15px; color: var(--t2); line-height: 1.6; }
.dz-empty button {
  margin-top: 20px; height: 52px; padding: 0 24px; border-radius: 12px;
  background: var(--ink); color: var(--on-ink); font-size: 15px; font-weight: 700;
}

.stk.sel { outline: 2px dashed color-mix(in srgb, var(--t1) 55%, transparent); outline-offset: 3px; border-radius: 4px; }
.stk-tool {
  position: absolute; width: 28px; height: 28px; border-radius: 9999px;
  background: var(--ink); color: var(--on-ink); display: grid; place-items: center;
  font-size: 13px; font-weight: 700; box-shadow: var(--shadow-2); touch-action: none; z-index: 5;
}
.stk-del { background: #f04452; color: #fff; }

.dz-empty { text-align: center; max-width: 420px; }
.dz-empty h2 { font-size: 20px; font-weight: 700; color: var(--t1); }
.dz-empty p { margin-top: 10px; font-size: 15px; color: var(--t2); line-height: 1.6; }
.dz-empty button {
  margin-top: 20px; height: 52px; padding: 0 24px; border-radius: 12px;
  background: var(--ink); color: var(--on-ink); font-size: 15px; font-weight: 700;
}

/* 도구 */
.side-h { font-size: 12px; font-weight: 700; color: var(--t3); }
.side-h { font-size: 13px; font-weight: 700; color: var(--t2); }
/* 도구 — 한 박스로 묶고 버튼끼리 붙인다.
   틈(gap 1px)으로 박스 배경색이 비쳐 보이게 해서 그게 곧 칸 사이 구분선이 된다. */
.dz-tools {
  margin-top: 10px;
  display: grid;
  /* 칸 폭을 글자 수와 무관하게 똑같이 — 항목 수에 맞춰 열을 정한다(빈 칸이 생기지 않게) */
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
}
/* 아이콘 묶음은 칸을 늘리지 않고 아이콘 크기 그대로 */
.dz-tools-icons { display: flex; grid-template-columns: none; }
/* 도구 버튼 — 박스 안의 한 칸. 개별 테두리 없이 서로 붙어 있다 */
.tool {
  height: var(--btn-h, 36px); padding: 0 8px;
  border-radius: 0;
  background: var(--bg);
  color: var(--t2);
  font-size: 13px; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  transition: background 0.15s, color 0.15s;
}
.tool:hover { background: var(--chip); color: var(--t1); }
/* 아이콘 묶음 — 패널 맨 아래 칸. 스티커 칸이 안에서 스크롤되므로 늘 보인다
   (예전엔 sticky 라 낮은 창에서 스티커 상자 위에 겹쳐 보였다) */
.bar-actions { margin-top: var(--panel-gap); padding: 12px 0 2px; background: var(--bg); }
/* 케이스 칸이 생기면서 오른쪽 칸이 창보다 길어질 수 있다 — 그때는 칸 전체가 스크롤되고,
   되돌리기·비우기·저장은 맨 아래에 붙어 늘 보인다(스크롤되는 내용은 그 뒤로 지나간다) */
.bar-actions { position: sticky; bottom: 0; z-index: 1; }
html[data-fit-narrow] .bar-actions { position: static; }
.dz-tools-icons { margin-top: 0; width: max-content; max-width: 100%; }
/* 아이콘 버튼 — 글자 버튼처럼 늘어나지 않고 정사각에 가깝게 */
.tool-icon { flex: 0 0 auto; width: 42px; padding: 0; }
.tool-icon svg { width: 19px; height: 19px; display: block; }
/* 켜진 상태 — 면을 채우지 않고 글씨와 아래 밑줄로 표시 */
.tool.on { color: var(--t1); font-weight: 700; box-shadow: inset 0 -2px 0 var(--t1); }
.tool:active { background: var(--line); }
.tool[disabled] { opacity: 0.4; pointer-events: none; }

/* 카드 보정 칸 — 오른쪽 맨 위. Muster 앱 '카드 보정' 시트와 같은 구성(js/adjust.js):
   라벨 색(색상·밝기 막대) + 자동 맞춤, 사진(밝기·채도·대비). 창을 띄우지 않으니 카드를 보면서 고친다 */
.lb-inline {
  margin-top: 10px; padding: 10px 12px 8px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--bg);
}
.adj-h { display: flex; align-items: center; min-height: 26px; }
.adj-h b { font-size: 13px; font-weight: 700; color: var(--t1); }
.adj-h-2 { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
/* 자동 맞춤 — 앱처럼 파란 글자 + 요술봉 */
.adj-auto {
  margin-left: auto; padding: 0; background: none;
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; font-weight: 600; color: #4a64c8;
}
.adj-auto svg { width: 14px; height: 14px; }
.adj-auto:disabled { opacity: 0.5; }
.adj-auto:active { opacity: 0.6; }
.adj-row { display: flex; align-items: center; gap: 10px; }
.adj-name {
  flex: 0 0 auto; width: 52px; display: flex; align-items: baseline; gap: 4px;
  font-size: 12px; font-weight: 500; color: var(--t1);
}
.adj-name i { font-style: normal; font-size: 11px; color: var(--t3); font-variant-numeric: tabular-nums; }
.adj-name i.on { color: var(--t1); }
/* 막대 — 트랙 6 · 손잡이 16 (앱은 8 · 22, 웹 도구 칸 폭에 맞춰 줄였다) */
.adj-sl { position: relative; flex: 1 1 auto; min-width: 0; height: 24px; cursor: pointer; touch-action: none; outline: none; }
.adj-track, .adj-fill { position: absolute; left: 0; top: 9px; height: 6px; border-radius: 9999px; }
.adj-track { right: 0; background: var(--line); }
.adj-fill { background: var(--t1); }
.adj-knob {
  position: absolute; top: 4px; width: 16px; height: 16px; margin-left: -8px; border-radius: 9999px;
  background: var(--t1); border: 2px solid #ffffff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
.adj-sl:focus-visible .adj-knob { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--t1); }
/* 도구 칸에 버튼이 하나뿐이면 한 줄을 다 쓴다(빈 칸이 생기지 않게) */
.bar-tools .dz-tools:has(> .tool:only-child) { grid-template-columns: 1fr; }

/* 스티커 트레이 */
/* 스티커 — 한 박스. 위에 카테고리 줄, 아래에 그 카테고리의 스티커 */
.tray-box {
  margin-top: 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
}
/* 카테고리 줄 — 도구 상자와 같은 방식(1px 틈이 구분선) */
.tray-cats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  margin: 0;
  background: var(--line);
  border-bottom: 1px solid var(--line);
}
.tcat {
  /* 도구 버튼과 같은 크기·여백 */
  height: var(--btn-h, 36px); padding: 0 8px;
  border-radius: 0; background: var(--bg);
  font-size: 13px; font-weight: 600; color: var(--t2);
  transition: background 0.15s, color 0.15s;
}
.tcat:hover { background: var(--chip); color: var(--t1); }
/* 고른 카테고리 — 면을 채우지 않고 글씨와 밑줄로 */
.tcat.on { color: var(--t1); font-weight: 700; box-shadow: inset 0 -2px 0 var(--t1); }
.tray-grid {
  margin: 0; padding: 10px; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(clamp(34px, calc(var(--vw, 100vw) * 0.032), 44px), 1fr));
  gap: 8px;
}
/* 스티커 칸 — 박스 안이므로 칸마다 테두리를 두르지 않는다 */
.tstk {
  aspect-ratio: 1; border-radius: 6px;
  background: none;
  display: grid; place-items: center; font-size: clamp(19px, calc(var(--vh, 100vh) * 0.026), 26px); position: relative;
  transition: transform 0.15s, background 0.15s;
}
/* 보석 칸 — 칸을 꽉 채우되 비율은 지킨다 */
.tstk-img { width: 100%; height: 100%; object-fit: contain; }
.tstk:hover { background: var(--chip); }
.tstk:active { transform: scale(0.9); }

/* 케이스 색 — 도구와 스티커 사이의 제 칸.
   칸마다 작은 케이스 모양(금속 틀 + 검은 고무 테)을 그려 둔다 */
.bar-case .tray-cats { display: block; background: var(--bg); }
/* 한 줄에 셋 — 칸이 커지는 만큼 케이스 모양도 따라 커진다 */
.bar-case .tray-grid { grid-template-columns: repeat(3, 1fr); }
.tframe-cap {
  height: var(--btn-h, 36px); padding: 0 10px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 12px; color: var(--t3); white-space: nowrap; overflow: hidden;
}
.tframe-cap b { font-size: 13px; font-weight: 700; color: var(--t1); }
.tframe-cap span { overflow: hidden; text-overflow: ellipsis; }
.tframe {
  /* 가로로 넓은 칸 — 정사각이면 네 줄이 스티커 칸을 밀어낸다 */
  aspect-ratio: 3 / 2; border-radius: 6px; background: none;
  display: grid; place-items: center;
  transition: transform 0.15s, background 0.15s;
}
.tframe:hover { background: var(--chip); }
.tframe:active { transform: scale(0.9); }
.tframe.on { background: var(--chip); box-shadow: inset 0 0 0 2px var(--t1); }
.tframe-chip, .tframe-none span {
  position: relative; height: 84%; aspect-ratio: 1200 / 2016; border-radius: 18% / 11%;
}
.tframe-chip { box-shadow: 0 1px 2px rgba(16, 14, 12, 0.25); }
/* 고무 테 — 틀 안쪽의 검은 띠, 그 안은 비어 있는 슬랩 자리 */
.tframe-chip::after {
  content: ''; position: absolute; inset: 11%;
  border: 2px solid #0e0f11; border-radius: 10% / 6%; background: #f4f4f2;
}
/* 구매하기 — 색 목록 맨 아래, 한 줄을 다 쓴다 */
.tframe-buy {
  grid-column: 1 / -1; margin-top: 4px; height: var(--btn-h, 36px); border-radius: 6px;
  display: flex; align-items: center; justify-content: center; gap: 5px;
  background: var(--ink); color: var(--on-ink); font-size: 13px; font-weight: 700;
  text-decoration: none; transition: opacity 0.15s;
}
.tframe-buy:hover { opacity: 0.86; }
.tframe-buy svg { width: 14px; height: 14px; }
/* 없음 — 점선 테두리만 */
.tframe-none span { border: 1.5px dashed var(--t3); }

/* ── 보관함 ──────────────────────────────── */
/* 아치가 워드마크 뒤로 지나가며 스크롤되게 — 발견 화면(.dc)과 같은 방식이다.
   스크롤 영역을 헤더 높이만큼 위로 늘리고, 그만큼을 안쪽 여백으로 되돌린다
   (그래야 맨 위로 올렸을 때 첫 줄이 헤더에 가리지 않는다) */
.sf { position: absolute; inset: 0; top: calc(-1 * var(--nav-h)); overflow-y: auto; }
.sf-in {
  max-width: calc(var(--page) + var(--gutter) * 2); margin: 0 auto;
  padding: calc(var(--nav-h) + 48px) var(--gutter) 96px;
}
.sf-h1 { font-size: 32px; font-weight: 700; color: var(--t1); }
.sf-sub { margin-top: 8px; font-size: 14px; font-weight: 500; color: var(--t2); }
/* 상자 없이 배경 위에 그대로 */
/* 아치 입구와 취향 리포트 사이 — 창 높이에 비례해 벌린다(낮은 창에서도 최소 64px) */
.taste { margin-top: clamp(64px, calc(var(--vh, 100vh) * 0.105), 140px); }
.taste-h { font-size: 17px; font-weight: 700; color: var(--t1); }
/* 카테고리를 한 줄에 나란히 — 바가 모두 같은 선 위에 온다 */
.taste-rows {
  margin-top: 8px;
  display: grid; gap: 12px clamp(24px, 4vw, 56px);
  grid-auto-flow: column; grid-auto-columns: 1fr;
}
@media (max-width: 620px) {
  .taste-rows { grid-auto-flow: row; grid-auto-columns: auto; }
}
.taste-row { margin-top: 8px; }
.taste-row .l { display: flex; justify-content: space-between; font-size: 13px; font-weight: 600; color: var(--t2); }
.taste-row .l b { color: var(--t1); font-variant-numeric: tabular-nums; }
.taste-bar { margin-top: 8px; height: 8px; border-radius: 9999px; background: var(--line); overflow: hidden; }
.taste-bar i { display: block; height: 100%; border-radius: 9999px; transition: width 0.5s cubic-bezier(0.22, 1, 0.36, 1); }
.taste-tag { margin-top: 18px; font-size: 14px; line-height: 1.65; color: var(--t2); }
.taste-tag b { color: var(--t1); font-weight: 700; }

.sec-h { margin-top: 40px; display: flex; align-items: baseline; justify-content: space-between; }
/* 첫 번째 섹션은 제목 바로 아래라 위 여백을 줄인다 */
/* 연동 버튼이 함께 놓이는 줄이라 baseline 대신 가운데로 맞춘다 */
.sec-h.sec-first { margin-top: 0; align-items: center; }
.sec-h-l { display: flex; align-items: baseline; gap: 10px; }
.sec-h h2 { font-size: 20px; font-weight: 700; color: var(--t1); }
.sec-h span { font-size: 13px; font-weight: 500; color: var(--t2); }
/* ── 전시실 입구 ──────────────────────────
   문짝은 없다. 벽에 낸 아치형 개구부 너머로 그 방이 들여다보이고,
   아래에 전시 라벨처럼 이름을 둔다. */
.hall { margin-top: 56px; }
.arches {
  /* 아치 폭은 창의 폭과 높이를 함께 본다. 아치 높이가 폭의 1.75배라서
     폭만 보고 정하면 낮은 창에서 아래가 잘린다.
     175px = 아치 위(제목 줄)와 아래(카테고리 이름)가 쓰는 자리. 남는 높이를 1.75 로 나눈 게 폭의 상한.
     830px 이상 높은 창에서는 상한 290px 에 걸려 지금까지와 똑같다. */
  /* 아치는 넷(분류 셋 + 특별전)이다. 넷이 한 줄에 서도록 '줄 폭 − 간격 셋 ÷ 4' 도 상한으로 둔다 */
  --arch-gap: clamp(36px, calc(var(--vw, 100vw) * 0.05), 96px);
  --arch-w: clamp(120px, min(calc(var(--vw, 100vw) * 0.26), calc((var(--vh, 100vh) - var(--nav-h) - 175px) / 1.75), calc((min(var(--page), var(--vw, 100vw) - var(--gutter) * 2) - var(--arch-gap) * 3) / 4)), clamp(220px, calc(var(--vw, 100vw) * 0.2), 460px));
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(120px, var(--arch-w)), var(--arch-w)));
  justify-content: center;
  gap: var(--arch-gap);
  margin: 0 auto;
}
.arch {
  padding: 0; background: none;
  display: grid; gap: 18px;
  text-align: center;
}
.arch.is-empty { opacity: 0.34; pointer-events: none; }

/* 개구부 — 위가 완전한 반원인 아치.
   테두리선 없이, 가장자리를 따라 안쪽으로 스며드는 그늘만으로 깊이를 만든다. */
.ar-way {
  position: relative;
  aspect-ratio: 1 / 1.75;
  /* 세로 반지름 = 가로의 절반 (0.5W ÷ 1.75W = 28.57%) → 정확한 반원 */
  border-radius: 50% 50% 0 0 / 28.57% 28.57% 0 0;
  background: radial-gradient(64% 46% at 50% 56%,
    color-mix(in srgb, var(--subtle) 45%, var(--surface)) 0%,
    var(--subtle) 62%,
    color-mix(in srgb, var(--line) 45%, var(--subtle)) 100%);
  box-shadow:
    inset 0 0 16px -2px rgba(25, 31, 40, 0.16),
    inset 0 0 46px -6px rgba(25, 31, 40, 0.22),
    inset 0 0 78px -20px rgba(25, 31, 40, 0.22);
  transition: box-shadow 0.35s, transform 0.42s cubic-bezier(0.22, 1, 0.36, 1), opacity 0.32s;
}

/* 들여다볼 때 — 그늘이 조금 물러나 안이 깊어 보인다 */
.arch:hover .ar-way {
  box-shadow:
    inset 0 0 16px -2px rgba(25, 31, 40, 0.12),
    inset 0 0 52px -6px rgba(25, 31, 40, 0.18),
    inset 0 0 92px -22px rgba(25, 31, 40, 0.2);
  transform: translateY(-4px);
}
/* 들어갈 때 — 입구가 눈앞으로 다가온다 */
.arch.is-open .ar-way { transform: scale(1.18); opacity: 0; }

/* 전시 라벨 */
.ar-cap {
  font-size: 13px; font-weight: 600; color: var(--t2);
  display: flex; align-items: baseline; justify-content: center; gap: 8px;
  transition: color 0.2s;
}
.ar-cap b { font-size: 12px; font-weight: 500; color: var(--t3); font-variant-numeric: tabular-nums; }
.arch:hover .ar-cap { color: var(--t1); }

/* ── 방 ───────────────────────────────────
   천장·바닥으로 나뉜 면 없이, 휘어진 벽 하나가 화면을 가득 채운다.
   벽은 가운데가 밝고 양옆으로 감기며 어두워지고, 선반도 그 곡률을 따라 휜다. */
.room {
  position: fixed; z-index: 45;
  inset: 0;
  /* 방의 색은 여기서만 정한다 — 흰 벽.
     --sun / --shade 는 rgb 세 값이라 alpha 를 붙여 쓴다.
     벽을 완전한 순백 하나로 칠하면 빛을 얹을 여지가 없어 천창이 안 보인다.
     그래서 빛 닿는 쪽만 순백이고, 기본·그늘 쪽은 아주 조금 낮춰 둔다. */
  --wall-lit: #ffffff;   /* 빛이 닿는 벽 */
  --wall: #f8f8f9;       /* 벽 기본 */
  --wall-dim: #ededee;   /* 양옆으로 감기며 살짝 가라앉는 쪽 */
  --sun: 255, 255, 255;  /* 햇빛 */
  --shade: 74, 72, 68;   /* 그늘 — 푸른 회색이면 추워 보여서 중성으로 */
  /* 천창으로 드는 낮 빛의 세기. 야간 모드(.is-night)에서 0 이 되면
     천창 빛·빛줄기가 모두 꺼지고, 대신 선반의 숨은 조명이 켜진다 */
  --daylight: 1;
  --glow: 255, 196, 122;   /* 숨은 조명 — 따뜻한 전구색 */
  background: var(--wall);
  animation: roomIn 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}
@media (prefers-color-scheme: dark) {
  .room {
    --wall-lit: #3a3a3c;
    --wall: #2b2b2d;
    --wall-dim: #1e1e20;
    --sun: 255, 255, 255;
    --shade: 8, 8, 10;
  }
}
/* ── 야간 모드 ──
   천창 빛을 끄고 방을 어둡게 한 뒤, 선반 아래 숨은 띠 조명만 남긴다.
   방 안의 글자·패널 색도 같이 어두운 쪽으로 바꾼다(방 안에서만 쓰는 값이다). */
.room.is-night {
  --wall-lit: #23262c;
  --wall: #191b20;
  --wall-dim: #0e1013;
  --shade: 0, 0, 0;
  --daylight: 0;
  --t1: #f2f4f7;
  --t2: #c6cbd3;
  --t3: #959ba4;
  --line: rgba(255, 255, 255, 0.16);
  --chip: rgba(255, 255, 255, 0.09);
  --subtle: rgba(255, 255, 255, 0.06);
  --bg: #15171b;
  --ink: #f2f4f7;
  --on-ink: #15171b;
  color-scheme: dark;
}
/* 방 바닥께에 고이는 아주 옅은 조명빛 — 어둠이 새카맣게 죽지 않게 */
.room.is-night .rw-wall {
  background-image:
    radial-gradient(70% 38% at 50% 78%, rgba(var(--glow), 0.10), rgba(var(--glow), 0) 72%),
    linear-gradient(180deg, #0b0d10 0%, var(--wall-dim) 34%, var(--wall) 72%, #101216 100%);
}
.room.is-night .rw-wall::after { background: none; }
/* 천창에서 들어오던 빛줄기 — 밤에는 꺼진다 */
.room.is-night .rw-wall::before { opacity: 0; }

/* 숨은 띠 조명 — 선반 바 아래에 붙어 있어, 빛이 아래로 퍼지며 벽을 훑는다.
   낮에는 이 자리가 선반 그늘(.shelf::after)이었다. */
.room.is-night .room-shelves .shelf::after {
  background: linear-gradient(180deg,
    rgba(var(--glow), 0.34) 0%,
    rgba(var(--glow), 0.18) 16%,
    rgba(var(--glow), 0.07) 42%,
    rgba(var(--glow), 0.02) 72%,
    rgba(var(--glow), 0) 100%);
}
/* 조명 자체 — 선반 아래 가늘게 빛나는 줄 */
.room.is-night .room-shelves .shelf::before {
  content: '';
  position: absolute; left: 0; right: 0; top: 100%;
  height: max(2px, calc(var(--slot, 64px) * 0.022));
  background: rgba(var(--glow), 0.85);
  box-shadow: 0 0 calc(var(--slot, 64px) * 0.4) rgba(var(--glow), 0.55);
  filter: blur(0.5px);
  pointer-events: none;
}
/* 한 줄 위에도 숨은 조명이 있다 — 카드 머리 위에서 빛이 내려와 카드를 밝힌다.
   (칸마다 조명이 숨어 있는 장식장처럼 보이게 하는 몫이다) */
.room.is-night .room-shelves .shelf-cards { position: relative; }
.room.is-night .room-shelves .shelf-cards::before {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 100%;
  height: calc(var(--slot, 64px) * 0.85);
  background: linear-gradient(180deg,
    rgba(var(--glow), 0) 0%,
    rgba(var(--glow), 0.05) 48%,
    rgba(var(--glow), 0.16) 100%);
  pointer-events: none;
}
/* 카드는 위아래 조명을 함께 받아 낮보다 조금 더 밝고 따뜻하게 보인다 */
.room.is-night .room-shelves .gitem .case { filter: brightness(1.12) saturate(1.05); }
/* 벽걸이 모드에는 선반이 없다 — 대신 카드마다 뒤에서 빛이 새어 나온다 */
.room.is-night.is-wall .room-shelves .gitem {
  filter: drop-shadow(0 0 calc(var(--slot, 64px) * 0.34) rgba(var(--glow), 0.22));
}

@keyframes roomIn {
  from { opacity: 0; transform: scale(1.14); }
  to { opacity: 1; transform: none; }
}
.room-scene { position: absolute; inset: 0; overflow: hidden; }
.rw { position: absolute; }

/* 벽 — 원통 안쪽. 가운데가 밝고 양옆으로 감기며 어두워진다.
   여기에 천창(원형) 자연광을 얹는다. 겹치는 순서는 아래에서 위로:
     ① 원통 벽 바탕
     ② 바닥에 고이는 빛
     ③ 천창 빛무리 — 개구부 둘레로 넓게 번지는 부분
     ④ 천창이 벽에 그리는 타원 — 원형 개구부라 벽에 닿으면 세로로 눌린 타원이 된다
   빛줄기와 구석 그늘은 ::before / ::after 로 따로 얹는다. */
.rw-wall {
  inset: 0;
  background:
    /* ④ 개구부에서 곧장 온 빛 */
    radial-gradient(30% 17% at 55% 19%,
      rgba(var(--sun), calc(0.95 * var(--daylight))),
      rgba(var(--sun), calc(0.5 * var(--daylight))) 55%, rgba(var(--sun), 0) 78%),
    /* ③ 그 둘레로 번지는 무리 */
    radial-gradient(62% 44% at 53% 24%,
      rgba(var(--sun), calc(0.55 * var(--daylight))), rgba(var(--sun), 0) 76%),
    /* ② 바닥에 고이는 빛 */
    radial-gradient(46% 16% at 57% 88%,
      rgba(var(--sun), calc(0.42 * var(--daylight))), rgba(var(--sun), 0) 80%),
    /* ①-b 천장 가까이와 바닥 가까이는 조금 가라앉는다 */
    linear-gradient(180deg,
      rgba(var(--shade), 0.05) 0%,
      rgba(var(--shade), 0) 26%,
      rgba(var(--shade), 0) 62%,
      rgba(var(--shade), 0.05) 100%),
    /* ① 원통 벽 — 흰 벽이 아니라 베이지. 이래야 천창 빛이 '빛'으로 읽힌다 */
    linear-gradient(90deg,
      var(--wall-dim) 0%,
      color-mix(in srgb, var(--wall-dim) 55%, var(--wall)) 15%,
      var(--wall) 34%,
      var(--wall-lit) 50%,
      var(--wall) 66%,
      color-mix(in srgb, var(--wall-dim) 55%, var(--wall)) 85%,
      var(--wall-dim) 100%);
}

/* 비스듬히 지나가는 빛줄기 — 개구부를 지난 빛이 벽을 훑고 내려간다.
   가로 줄무늬를 만든 다음 박스째 기울여서 대각선으로 만든다.
   각도를 직접 주는 편이 gradient 각도를 계산하는 것보다 다루기 쉽다. */
.rw-wall::before {
  content: '';
  position: absolute;
  inset: -60%;
  transform: rotate(-32deg);
  background: linear-gradient(to right,
    rgba(255, 255, 255, 0) 33%,
    rgba(255, 255, 255, 0.95) 39.5%,
    rgba(255, 255, 255, 0.28) 44%,
    rgba(255, 255, 255, 0) 47.5%,
    rgba(255, 255, 255, 0) 53%,
    rgba(255, 255, 255, 0.62) 58%,
    rgba(255, 255, 255, 0.14) 62%,
    rgba(255, 255, 255, 0) 66%);
  filter: blur(9px);
  opacity: var(--daylight);
  transition: opacity 0.5s;
  /* 천창에서 멀어질수록 옅어진다 */
  -webkit-mask-image: linear-gradient(to bottom, #000 22%, rgba(0,0,0,0.8) 50%, rgba(0,0,0,0.3) 70%, transparent 84%);
  mask-image: linear-gradient(to bottom, #000 22%, rgba(0,0,0,0.8) 50%, rgba(0,0,0,0.3) 70%, transparent 84%);
  pointer-events: none;
}

/* 구석 그늘 — 빛이 닿지 않는 곳은 차갑게 가라앉는다.
   이게 있어야 밝은 쪽이 '빛'으로 읽힌다 */
.rw-wall::after {
  content: '';
  position: absolute; inset: 0;
  background:
    radial-gradient(115% 82% at 55% 18%,
      rgba(var(--shade), 0) 38%,
      rgba(var(--shade), 0.045) 66%,
      rgba(var(--shade), 0.11) 88%,
      rgba(var(--shade), 0.17) 100%);
  pointer-events: none;
}

/* 카드가 걸리는 벽면 — 위아래로 나뉜 면 없이 벽 하나가 화면을 채운다.
   좌우로도 화면 끝까지 이어져서, 카드가 많아지면 선반이 화면 밖으로 계속 뻗는다. */
.rw-back {
  /* 방 전체를 덮는다. 카드가 놓이는 자리는 .room-shelves 의 안쪽 여백이 정한다 —
     이 상자를 6% 씩 줄여서 자리를 잡으면, 확대해서 위아래로 훑을 때
     그 6% 경계에서 카드가 일직선으로 뚝 잘린다(벽 한가운데에 없던 선이 생긴다). */
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  overflow: hidden;
}


/* 카드 앞에 섰을 때 뜨는 설명 */
.room-info {
  position: fixed; z-index: 3;
  left: 50%; bottom: 40px; transform: translateX(-50%) translateY(10px);
  display: grid; justify-items: center; gap: 14px;
  opacity: 0; pointer-events: none;
  transition: opacity 0.4s 0.3s, transform 0.4s 0.3s;
}
.room.is-near .room-info { opacity: 1; transform: translateX(-50%); pointer-events: auto; }
.ri-name { text-align: center; font-size: 15px; font-weight: 700; color: var(--t1); }
.ri-name span { display: block; margin-top: 4px; font-size: 12px; font-weight: 500; color: var(--t3); }
.ri-act { display: flex; gap: 8px; }
.ri-btn {
  height: 38px; padding: 0 16px; border-radius: 8px;
  box-shadow: inset 0 0 0 1px var(--line);
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  font-size: 13px; font-weight: 600; color: var(--t2);
  transition: box-shadow 0.15s, color 0.15s;
}
.ri-btn:hover { box-shadow: inset 0 0 0 1px var(--t3); color: var(--t1); }
.ri-btn-p { background: var(--ink); color: var(--on-ink); box-shadow: none; }
.ri-btn-p:hover { color: var(--on-ink); box-shadow: none; opacity: 0.85; }
/* 방 안 진열대 — 카드는 모두 같은 폭(--slot).
   다가설 때 폭 자체가 커지므로 브라우저가 그 크기로 다시 그린다. 확대가 아니라 늘 선명하다. */
.room-shelves {
  position: relative;
  /* 벽을 따라 옆으로 걷는다 — 휠·드래그·방향키 */
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none; overscroll-behavior: contain;
  cursor: grab;
  /* 벽에서 진열대가 차지하는 높이 — 카드 크기를 이 높이에서 잡는다.
     위아래 여백은 방 높이의 6%. 상자를 줄이는 대신 여백으로 두면
     확대해서 훑을 때 카드가 화면 끝에서 자연스럽게 사라진다(중간에 잘리는 선이 없다). */
  flex: 1; min-height: 0;
  padding-block: calc(var(--vh, 100vh) * 0.06);
  transition: padding 0.62s cubic-bezier(0.3, 0, 0.2, 1);
  /* 갤러리처럼 벽 한가운데 — 눈높이에 걸린다 */
  display: flex; align-items: center;
}
.room-shelves::-webkit-scrollbar { display: none; }
.room-shelves:active { cursor: grabbing; }
/* 진열대는 카드 전체 길이만큼 — flex 안에서 줄어들면 바가 화면 폭에서 잘린다 */
/* 여러 줄이면 세로로 쌓는다. 가로 스크롤은 바깥(.room-shelves)이 맡는다 */
/* 줄 사이 간격은 js 가 벽 높이에서 계산해 --row-gap 으로 넘긴다 (높이 계산과 같은 값을 써야 한다) */
/* safe center — 확대해서 줄이 벽보다 길어지면 가운데 정렬이 위쪽을 스크롤 밖으로 밀어낸다.
   safe 를 붙이면 그때만 위에 붙어서, 첫째 줄 윗부분까지 끝까지 볼 수 있다 */
.room-shelves { flex-direction: column; justify-content: safe center; gap: var(--row-gap, 0px); }
/* 줄이 벽보다 길어졌을 때만 세로로 열어 준다 (js 가 붙인다) */
.room-shelves.is-tall { overflow-y: auto; }
/* 가까이 갔을 때 첫 줄 위·마지막 줄 아래에 숨 쉴 자리를 더 준다 —
   안 그러면 스크롤을 끝까지 올려도 카드가 벽 위쪽에 바짝 붙는다.
   카드 크기에 비례하고, 확대하지 않았을 때는(is-tall 이 아닐 때) 없다. */
.room-shelves.is-tall .shelf:first-child { margin-top: calc(var(--slot, 64px) * 0.2); }
.room-shelves.is-tall .shelf:last-child { margin-bottom: calc(var(--slot, 64px) * 0.2); }
/* 벽 앞까지 다가서면 여백을 걷어 카드가 방을 꽉 채운다 */
.room.is-near .room-shelves { padding-block: 0; }
.room-shelves .shelf { flex: 0 0 auto; min-width: 100%; width: max-content; margin: 0 auto; position: relative; }
/* 선반 아래 그늘 — 바가 벽에 붙어 있고 그 아래로 빛이 가려진다.
   천창이 높이 있어서 그림자가 길게 떨어진다. 카드 크기(--slot)에 비례해
   어느 화면에서나 같은 비율로 보인다. 위쪽은 진하고 아래로 길게 풀어진다. */
.room-shelves .shelf::after {
  content: '';
  position: absolute; left: 0; right: 0; top: 100%;
  height: calc(var(--slot, 64px) * 1.15);
  background: linear-gradient(180deg,
    rgba(var(--shade), 0.13) 0%,
    rgba(var(--shade), 0.07) 22%,
    rgba(var(--shade), 0.03) 50%,
    rgba(var(--shade), 0.008) 78%,
    rgba(var(--shade), 0) 100%);
  pointer-events: none;
}
/* 양끝 여백 — js 가 카드 크기에서 잡아 --edge 로 넘긴다(applySlot).
   확대했을 때 첫 장·마지막 장도 화면 한가운데로 끌어올 수 있어야 해서,
   여백이 최소한 '화면 절반에서 카드 반쪽을 뺀 만큼'은 돼야 한다. */
.room-shelves .shelf-cards { padding: 0 var(--edge, clamp(24px, 5vw, 96px)); }
/* 빈 칸 — 줄마다 칸 수를 맞추려고 넣는다. 자리만 차지하고 아무것도 그리지 않는다 */
.room-shelves .gslot { width: var(--slot, 64px); flex: 0 0 auto; pointer-events: none; }
.room-shelves .gitem {
  width: var(--slot, 64px); flex: 0 0 auto;
  /* 폭에는 전환을 걸지 않는다 — 확대는 js 가 프레임마다 --slot 을 움직여 그린다.
     둘이 겹치면 한 박자 늦게 따라오면서 끊겨 보인다 */
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
/* 카드 크기에 비례해서 뜬다 — 다가서면 더 크게 들린다 */
/* 떠오르는 거리는 js 가 정한다 — 위에 남은 자리만큼만 띄워야 윗부분이 안 잘린다 */
.room-shelves .gitem:hover { transform: translateY(calc(var(--lift, 0px) * -1)); }
/* 선반 — 벽을 가로지르는 일자 바 */
.shelf-arc { display: block; width: 100%; overflow: visible; }
/* 선반 바도 벽과 같은 계열 */
.arc-face { fill: var(--wall-dim, var(--line)); }
.arc-top { fill: var(--wall-lit, color-mix(in srgb, var(--line) 35%, var(--bg))); }
.shelf-arc {
  filter:
    drop-shadow(0 1px 1px rgba(25, 31, 40, 0.22))
    drop-shadow(0 6px 7px rgba(25, 31, 40, 0.12))
    drop-shadow(0 18px 18px rgba(25, 31, 40, 0.08));
}

.room-empty { text-align: center; font-size: 13px; color: var(--t3); }

.room-exit {
  position: fixed; z-index: 2;
  left: var(--gutter); top: var(--nav-top);
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; color: var(--t2);
  transition: color 0.15s;
}
.room-exit:hover { color: var(--t1); }
.room-exit svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.room-exit:hover svg { transform: translateX(-3px); transition: transform 0.18s; }

/* 방 이름 — 나가기 버튼과 같은 줄 가운데. 마이 갤러리는 문에 이름이 적혀 있지만
   카드쇼에서 열면 어느 부스의 방인지 여기서만 알 수 있다 */
.room-title {
  position: fixed; z-index: 2;
  left: 50%; top: var(--nav-top); transform: translateX(-50%);
  max-width: 46vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: 13px; font-weight: 700; color: var(--t2);
}

/* 보기 설정 — 방 우측 상단. 버튼 하나를 누르면 아래로 패널이 펼쳐진다
   (발견 화면의 '커스텀'과 같은 방식) */
.room-opts {
  position: fixed; z-index: 4; right: var(--gutter); bottom: var(--nav-top);
  --opts-icon: 20px;   /* 아이콘 크기 */
  --sw-h: 36px;        /* 스위치 알약 높이 (글자칸 30 + 안쪽 여백 3×2) */
}
/* 아이콘만 — 나가기 버튼처럼 배경 없이 놓는다 */
.room-opts-btn {
  position: relative;
  display: block; padding: 0;
  color: var(--t2);
  transition: color 0.15s;
}
.room-opts-btn svg {
  display: block;
  width: 20px; height: 20px; fill: none; stroke: currentColor;
  stroke-width: 1.7; stroke-linecap: round;
}
/* 누르는 범위는 아이콘보다 넉넉하게 (레이아웃에는 영향 없음) */
.room-opts-btn::after { content: ''; position: absolute; inset: -11px -13px; }
.room-opts-btn:hover { color: var(--t1); }
.room-opts.is-open .room-opts-btn { color: var(--t1); }

/* 버튼 왼쪽으로 슉 나온다.
   폭을 0에서 늘리는 방법(grid-template-columns: 0fr→1fr)은 세로에선 되지만
   가로에선 안 된다 — 절대배치라 fr 이 기댈 기준 폭이 없어 0으로 굳는다.
   그래서 제 폭 그대로 두고 오른쪽에서부터 벗겨내듯 보여 준다. */
.room-panel {
  /* 패널 전체가 아니라 **알약이** 아이콘과 같은 높이에 오게 맞춘다.
     라벨이 알약 위에 있어서 패널 가운데를 맞추면 알약이 아래로 밀린다.
     알약 아랫변을 패널 아랫변에 두고, 그 차이만큼 패널을 내린다. */
  position: absolute; right: calc(100% + 12px);
  bottom: calc((var(--sw-h) - var(--opts-icon)) / -2);
  width: max-content;
  transform: translateX(10px);
  clip-path: inset(0 0 0 100%);      /* 다 가려 둔 상태 */
  opacity: 0; pointer-events: none;
  transition:
    clip-path 0.36s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.36s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.24s ease;
}
.room-opts.is-open .room-panel {
  transform: translateX(0);
  clip-path: inset(0 0 0 0);
  opacity: 1; pointer-events: auto;
}
/* 상자 없이 벽 위에 그대로 — 아이콘 아래 오른쪽으로 맞춘다 */
.ro-in {
  /* 항목을 가로로 나란히. 접힐 때 줄바꿈이 생기지 않게 내용 폭을 쓴다 */
  display: grid; grid-auto-flow: column; gap: 18px;
  width: max-content;
  justify-items: end; align-items: end;
}
.ro-row { display: grid; gap: 7px; justify-items: end; }
.ro-label { font-size: 12px; font-weight: 600; color: var(--t3); }
/* 슬라이드 스위치 — 손잡이가 두 자리 사이를 오간다.
   눌러도 넘어가고, 손잡이를 끌어서 옮길 수도 있다. */
.ro-switch {
  position: relative;
  display: grid; grid-template-columns: repeat(var(--sw-n, 2), 1fr);
  padding: 3px;
  border-radius: 9999px;
  background: color-mix(in srgb, var(--wall-lit) 66%, transparent);
  box-shadow: inset 0 0 0 1px rgba(var(--shade), 0.14);
  backdrop-filter: blur(8px);
  cursor: grab;
  touch-action: none;          /* 끄는 동안 화면이 따라 움직이지 않게 */
  user-select: none;
}
.ro-switch:active, .ro-switch.is-drag { cursor: grabbing; }
.ro-switch:focus-visible { outline: 2px solid var(--t1); outline-offset: 2px; }
/* 손잡이 — 절반을 덮는 알약. --sw-x 는 0(왼쪽) ~ 1(오른쪽) */
.sw-knob {
  position: absolute; left: 3px; top: 3px; bottom: 3px;
  width: calc((100% - 6px) / var(--sw-n, 2));
  border-radius: 9999px;
  background: var(--ink);
  transform: translateX(calc(var(--sw-x, 0) * 100%));
  transition: transform 0.26s cubic-bezier(0.22, 1, 0.36, 1);
}
/* 끄는 동안에는 손을 그대로 따라온다 */
.ro-switch.is-drag .sw-knob { transition: none; }
.sw-opt {
  position: relative; z-index: 1;
  padding: 0 13px; height: 30px;
  display: grid; place-items: center;
  font-size: 13px; font-weight: 600; color: var(--t2);
  white-space: nowrap;
  transition: color 0.2s;
}
/* 손잡이가 덮은 칸의 글씨를 밝게 */
.sw-opt.on { color: var(--on-ink); }
/* 줄 수 바 — 스위치와 같은 알약 위에서 손잡이가 1~5줄 눈금 사이를 미끄러진다.
   보이는 손잡이는 .rr-knob 이고, 실제로 끌고 키보드로 움직이는 건 그 위에 겹친
   투명한 range 다. range 의 손잡이 폭을 .rr-knob 과 같게 맞춰 두면
   누른 자리와 손잡이가 가는 자리가 정확히 겹친다. */
.ro-range {
  --rr-knob: 38px;
  position: relative;
  width: calc(var(--rr-knob) * 4.2); height: var(--sw-h);
  border-radius: 9999px;
  background: color-mix(in srgb, var(--wall-lit) 66%, transparent);
  box-shadow: inset 0 0 0 1px rgba(var(--shade), 0.14);
  backdrop-filter: blur(8px);
}
/* 눈금 — 손잡이 가운데가 설 수 있는 다섯 자리에 점을 찍는다 */
.rr-ticks {
  position: absolute; top: 0; bottom: 0;
  left: calc(3px + var(--rr-knob) / 2); right: calc(3px + var(--rr-knob) / 2);
  display: flex; justify-content: space-between; align-items: center;
  pointer-events: none;
}
.rr-ticks i {
  width: 4px; height: 4px; margin: 0 -2px;
  border-radius: 50%;
  background: rgba(var(--shade), 0.32);
}
.rr-knob {
  position: absolute; top: 3px; bottom: 3px;
  left: calc(3px + var(--rr-x, 0) * (100% - 6px - var(--rr-knob)));
  width: var(--rr-knob);
  display: grid; place-items: center;
  border-radius: 9999px;
  background: var(--ink); color: var(--on-ink);
  font-size: 13px; font-weight: 600; white-space: nowrap;
  pointer-events: none;
  transition: left 0.26s cubic-bezier(0.22, 1, 0.36, 1);
}
.ro-range input {
  position: absolute; top: 0; bottom: 0; left: 3px; right: 3px;
  width: calc(100% - 6px); height: 100%;
  margin: 0; opacity: 0;
  -webkit-appearance: none; appearance: none; background: none;
  cursor: grab;
  touch-action: none;          /* 끄는 동안 화면이 따라 움직이지 않게 */
}
.ro-range.is-drag input { cursor: grabbing; }
.ro-range input::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: var(--rr-knob); height: var(--sw-h);
}
.ro-range input::-moz-range-thumb { width: var(--rr-knob); height: var(--sw-h); border: 0; }
.ro-range:has(input:focus-visible) { outline: 2px solid var(--t1); outline-offset: 2px; }
/* ── 벽걸이 — 바 없이 벽에 그대로 건다 ── */
.room.is-wall .shelf-arc { display: none; }
/* 바가 없으니 바 아래 그늘도, 카드 아랫변의 바 그늘도 없다 */
.room.is-wall .room-shelves .shelf::after,
.room.is-wall .room-shelves .gitem .case::after { display: none; }
/* 걸려 있는 카드라 아래로도 그림자가 떨어진다 — 자르지 않고 세로 성분을 준다 */
.room.is-wall .room-shelves .gitem .case::before {
  clip-path: none;
  box-shadow:
    calc(var(--slot, 64px) * 0.09) calc(var(--slot, 64px) * 0.05)
      calc(var(--slot, 64px) * 0.10) rgba(var(--shade), 0.24),
    calc(var(--slot, 64px) * 0.40) calc(var(--slot, 64px) * 0.20)
      calc(var(--slot, 64px) * 0.26) rgba(var(--shade), 0.16),
    calc(var(--slot, 64px) * 1.00) calc(var(--slot, 64px) * 0.48)
      calc(var(--slot, 64px) * 0.58) rgba(var(--shade), 0.10),
    calc(var(--slot, 64px) * 2.00) calc(var(--slot, 64px) * 0.94)
      calc(var(--slot, 64px) * 1.10) rgba(var(--shade), 0.055);
}
.room.is-wall .room-shelves .gitem:hover .case::before {
  box-shadow:
    calc(var(--slot, 64px) * 0.11) calc(var(--slot, 64px) * 0.06)
      calc(var(--slot, 64px) * 0.13) rgba(var(--shade), 0.22),
    calc(var(--slot, 64px) * 0.52) calc(var(--slot, 64px) * 0.26)
      calc(var(--slot, 64px) * 0.34) rgba(var(--shade), 0.15),
    calc(var(--slot, 64px) * 1.30) calc(var(--slot, 64px) * 0.62)
      calc(var(--slot, 64px) * 0.76) rgba(var(--shade), 0.095),
    calc(var(--slot, 64px) * 2.60) calc(var(--slot, 64px) * 1.22)
      calc(var(--slot, 64px) * 1.45) rgba(var(--shade), 0.05);
}

/* 진열대 한 벌 — 카드 줄 아래에 바가 벽을 가로지른다 */
.shelf { display: flex; flex-direction: column; }
.shelf-cards {
  display: flex; align-items: flex-end; justify-content: center;
  gap: var(--room-gap, 18px);
}
.gitem {
  position: relative;
  /* 카드 그림자가 바 위로 떨어지도록 바보다 앞에 둔다 */
  z-index: 1;
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
/* 집어 드는 것처럼 뜬다 */
.gitem:hover { transform: translateY(-24px); }
/* 카드 아래 그림자는 두지 않는다 — 바에 그대로 놓인 모습만 */
.gitem .case { border-radius: 10px; }
/* 해질 무렵처럼 낮게 든 빛 — 카드마다 오른쪽으로 길게 눕는 그림자.
   가로로 균일한 띠는 기울여도 변화가 없다. 그림자가 '길다'고 읽히려면
   카드 하나하나가 제 실루엣으로 드리워야 한다.

   그림자는 case 에 filter 로 걸지 않고, 케이스 뒤에 깐 불투명 판이 만든다.
   케이스 PNG 는 테두리가 반투명(알파 60~90)이라 뒤에 그림자를 깔면 그대로 비쳐
   카드가 어두워진다 — 꾸미기 화면(.dz-canvas .case::before)에서 쓰는 방법과 같다. */
.room-shelves .gitem .case::before {
  content: '';
  position: absolute;
  /* 케이스 몸통 안쪽으로 살짝 넣어 판이 실루엣 밖으로 삐져나오지 않게 */
  top: 2.4%; left: 5.4%; right: 5.2%; bottom: 1.8%;
  border-radius: 3cqw;
  background: var(--wall);
  /* 한 덩어리로 이어지는 그림자 — 겹끼리 간격을 두지 않고 겹쳐서 번지게 한다.
     떨어진 자리에 따로 생기면 그림자가 두 개로 보인다.
     세로로는 거의 내려가지 않는다. 바가 카드보다 앞으로 나와 있어서
     카드 아래로는 그림자가 떨어질 자리가 없기 때문이다. */
  box-shadow:
    calc(var(--slot, 64px) * 0.09) calc(var(--slot, 64px) * 0.015)
      calc(var(--slot, 64px) * 0.10) rgba(var(--shade), 0.24),
    calc(var(--slot, 64px) * 0.40) calc(var(--slot, 64px) * 0.05)
      calc(var(--slot, 64px) * 0.26) rgba(var(--shade), 0.16),
    calc(var(--slot, 64px) * 1.00) calc(var(--slot, 64px) * 0.11)
      calc(var(--slot, 64px) * 0.58) rgba(var(--shade), 0.10),
    calc(var(--slot, 64px) * 2.00) calc(var(--slot, 64px) * 0.20)
      calc(var(--slot, 64px) * 1.10) rgba(var(--shade), 0.055);
  /* 카드 아랫변에서 그림자를 자른다 — 그 아래는 바가 가리는 자리다.
     자르지 않으면 바 밑으로 줄기가 삐져나와 그림자가 둘로 갈라져 보인다. */
  clip-path: inset(-400% -400% 0 -400%);
  transition:
    box-shadow 0.22s cubic-bezier(0.22, 1, 0.36, 1),
    clip-path 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
/* 카드를 들어 올리면 그림자도 함께 길어진다.
   자르는 선은 카드가 아니라 '바의 윗면'에 걸려 있어야 한다 —
   카드가 --slot*0.28 만큼 떠오르므로 그만큼 아래로 늘려서 선을 제자리에 붙잡는다.
   안 그러면 들린 카드 밑 허공에서 그림자가 뚝 잘린다. */
.room-shelves .gitem:hover .case::before {
  clip-path: inset(-400% -400% calc(var(--slot, 64px) * -0.28) -400%);
  box-shadow:
    calc(var(--slot, 64px) * 0.11) calc(var(--slot, 64px) * 0.02)
      calc(var(--slot, 64px) * 0.13) rgba(var(--shade), 0.22),
    calc(var(--slot, 64px) * 0.52) calc(var(--slot, 64px) * 0.07)
      calc(var(--slot, 64px) * 0.34) rgba(var(--shade), 0.15),
    calc(var(--slot, 64px) * 1.30) calc(var(--slot, 64px) * 0.15)
      calc(var(--slot, 64px) * 0.76) rgba(var(--shade), 0.095),
    calc(var(--slot, 64px) * 2.60) calc(var(--slot, 64px) * 0.27)
      calc(var(--slot, 64px) * 1.45) rgba(var(--shade), 0.05);
}
/* 카드 아랫변 — 바가 앞을 가려 빛이 덜 든다.
   여기가 환하면 카드가 허공에 떠 있는 것처럼 보인다. */
.room-shelves .gitem .case::after {
  content: '';
  position: absolute;
  left: 5.4%; right: 5.2%; bottom: 1.8%;
  height: 13%;
  border-radius: 0 0 3cqw 3cqw;
  background: linear-gradient(to top,
    rgba(var(--shade), 0.17), rgba(var(--shade), 0.06) 45%, rgba(var(--shade), 0) 100%);
  pointer-events: none;
}
.empty { margin-top: 16px; padding: 48px 24px; border-radius: 16px; background: var(--subtle); text-align: center; }
.empty p { font-size: 15px; color: var(--t2); line-height: 1.6; }
.empty button {
  margin-top: 20px; height: 52px; padding: 0 24px; border-radius: 12px;
  background: var(--ink); color: var(--on-ink); font-size: 15px; font-weight: 700;
}
/* 미션 — 가로로 긴 줄이 아니라 정사각형에 가까운 카드로 늘어놓는다.
   칸 폭(--mcol)은 창 폭을 따라가고, 높이는 그 폭의 95% 를 최소로 잡는다.
   min-height 라서 글이 길어지면 카드가 늘어날 뿐 잘리지 않는다. */
.mission {
  --mcol: clamp(150px, calc(var(--vw, 100vw) * 0.12), 200px);
  margin-top: 16px; display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fill, minmax(var(--mcol), 1fr));
}
.mrow {
  display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
  min-height: calc(var(--mcol) * 0.95);
  padding: 16px; border-radius: 12px; background: var(--surface); box-shadow: var(--shadow-1);
}
.mrow .ck { width: 24px; height: 24px; flex: 0 0 auto; border-radius: 9999px; display: grid; place-items: center; background: var(--line); color: var(--surface); font-size: 13px; font-weight: 700; }
.mrow.done .ck { background: #00c471; color: #fff; }
/* 가운데를 채워서 보상이 카드 아래에 붙는다 */
.mrow .mtxt { flex: 1; min-width: 0; }
.mrow .mtxt b { display: block; font-size: 14px; font-weight: 600; line-height: 1.35; color: var(--t1); }
.mrow .mtxt small { display: block; margin-top: 5px; font-size: 12px; line-height: 1.45; color: var(--t2); }
.mrow .mrew { font-size: 14px; font-weight: 700; color: #f0a72a; font-variant-numeric: tabular-nums; }
.mrow.done .mtxt b { color: var(--t2); text-decoration: line-through; }

/* ── 시트 · 모달 · 토스트 ────────────────── */
.sheet-scrim, .modal-scrim {
  position: fixed; inset: 0; z-index: 40; background: rgba(15, 18, 22, 0.5);
  animation: fadeIn 0.2s ease;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.sheet {
  position: fixed; z-index: 41; background: var(--surface); box-shadow: var(--shadow-3);
  left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(520px, calc(var(--vw, 100vw) - 48px));
  max-height: min(calc(var(--vh, 100vh) * 0.86), 900px); overflow-y: auto;
  border-radius: 16px; padding: 28px 28px 0;
  animation: popIn 0.3s cubic-bezier(0.22, 1.2, 0.36, 1);
}
.sheet-grip { display: none; }
.sheet h3 { font-size: 22px; font-weight: 700; color: var(--t1); line-height: 1.35; }
.sheet .meta { margin-top: 8px; font-size: 14px; font-weight: 500; color: var(--t2); }
.sheet-preview { width: 180px; margin: 0 auto 20px; }
.sheet-actions {
  position: sticky; bottom: 0; z-index: 2;
  margin-top: 24px; padding: 16px 0 28px;
  display: flex; gap: 8px; background: var(--surface);
}
.btn { flex: 1; height: 52px; border-radius: 12px; display: grid; place-items: center; font-size: 15px; font-weight: 700; }
.btn-p { background: var(--ink); color: var(--on-ink); }
.btn-s { background: var(--chip); color: var(--t1); }
.btn:active { opacity: 0.75; }

.modal {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 41;
  width: min(400px, calc(var(--vw, 100vw) - 48px));
  background: var(--surface); border-radius: 16px; padding: 32px 24px; text-align: center;
  box-shadow: var(--shadow-3); animation: popIn 0.34s cubic-bezier(0.22, 1.4, 0.36, 1);
}
@keyframes popIn { from { transform: translate(-50%, -50%) scale(0.88); opacity: 0; } to { transform: translate(-50%, -50%) scale(1); opacity: 1; } }
.pack {
  width: 140px; height: 140px; margin: 0 auto 20px; border-radius: 18px;
  display: grid; place-items: center; font-size: 60px;
  background: linear-gradient(150deg, #2b303a, #12141a); box-shadow: var(--shadow-3);
}
.pack.shake { animation: packShake 0.55s ease-in-out 3; }
@keyframes packShake {
  0%, 100% { transform: rotate(0deg) scale(1); }
  25% { transform: rotate(-7deg) scale(1.04); }
  75% { transform: rotate(7deg) scale(1.04); }
}
.pack-burst { animation: burst 0.5s cubic-bezier(0.22, 1.5, 0.36, 1); }
@keyframes burst { from { transform: scale(0.3); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.modal h3 { font-size: 22px; font-weight: 700; color: var(--t1); }
.modal p { margin-top: 8px; font-size: 14px; color: var(--t2); line-height: 1.6; }
.modal .rtag { display: inline-block; margin-top: 12px; padding: 4px 12px; border-radius: 9999px; font-size: 12px; font-weight: 700; color: #fff; }

.field {
  width: 100%; height: 52px; margin-top: 8px; padding: 0 16px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--subtle);
  font-family: var(--font); font-size: 15px; color: var(--t1);
}
.field:focus { outline: 2px solid var(--t1); outline-offset: -2px; }
.flabel { margin-top: 18px; font-size: 13px; font-weight: 600; color: var(--t2); }
.flabel-sub { font-weight: 500; color: var(--t3); }

/* 라벨 미리보기 — 케이스 창 밖으로 꺼내 눕힌 것 */
.lb-preview { margin-top: 14px; }
.case-label.preview {
  position: relative; top: auto; left: auto; width: 100%; height: auto;
  aspect-ratio: 965 / 267; border-radius: 6px; box-shadow: var(--shadow-1);
}

/* ── 컬러 피커 ──────────────────────────── */
.cp { margin-top: 12px; }
.cp-sv {
  position: relative; width: 100%; height: 148px; border-radius: 10px; cursor: crosshair; touch-action: none;
  background-image: linear-gradient(to top, #000, rgba(0, 0, 0, 0)), linear-gradient(to right, #fff, var(--cp-hue, #ff0000));
  box-shadow: inset 0 0 0 1px rgba(15, 18, 22, 0.1);
}
.cp-sv-cursor {
  position: absolute; width: 18px; height: 18px; margin: -9px 0 0 -9px; border-radius: 9999px;
  border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35), 0 2px 6px rgba(0, 0, 0, 0.35);
  pointer-events: none;
}
.cp-row { margin-top: 12px; display: flex; align-items: center; gap: 10px; }
.cp-eye {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9999px; background: var(--chip);
  display: grid; place-items: center; color: var(--t1);
}
.cp-eye:hover { background: var(--line); }
.cp-hue {
  position: relative; flex: 1; height: 14px; border-radius: 9999px; cursor: pointer; touch-action: none;
  background: linear-gradient(to right, #f00 0%, #ff0 17%, #0f0 33%, #0ff 50%, #00f 67%, #f0f 83%, #f00 100%);
  box-shadow: inset 0 0 0 1px rgba(15, 18, 22, 0.1);
}
.cp-hue-knob {
  position: absolute; top: 50%; width: 20px; height: 20px; margin: -10px 0 0 -10px; border-radius: 9999px;
  background: #fff; box-shadow: 0 0 0 1px rgba(15, 18, 22, 0.22), 0 2px 6px rgba(0, 0, 0, 0.28);
  pointer-events: none;
}
.cp-chip { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 9999px; box-shadow: inset 0 0 0 1px rgba(15, 18, 22, 0.12); }
.cp-hexlabel { font-size: 13px; font-weight: 600; color: var(--t2); }
.cp-hex {
  flex: 1; min-width: 0; height: 40px; padding: 0 14px; border-radius: 8px;
  border: 1px solid var(--line); background: var(--subtle);
  font-size: 15px; font-weight: 600; color: var(--t1); text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.cp-hex:focus { outline: 2px solid var(--t1); outline-offset: -2px; }

/* 카드색으로 되돌리는 칩 */
.sw-auto {
  height: 32px; padding: 0 12px; border-radius: 9999px; background: var(--chip);
  font-size: 13px; font-weight: 600; color: var(--t2);
}
.sw-auto.on { background: var(--ink); color: var(--on-ink); }
.swatches { margin-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.sw { width: 32px; height: 32px; border-radius: 9999px; box-shadow: inset 0 0 0 1px rgba(15,18,22,0.12); }
.sw.on { box-shadow: inset 0 0 0 1px rgba(15,18,22,0.12), 0 0 0 3px var(--t1); }
/* PA:V 케이스 색 — 칩에도 마감이 보이게 빛을 얹는다 */
.sw-anod  { background: linear-gradient(160deg, rgba(255,255,255,0.28), rgba(255,255,255,0) 45%, rgba(0,0,0,0.2)), var(--c); }
.sw-matte { background: linear-gradient(160deg, rgba(255,255,255,0.14), rgba(0,0,0,0.08)), var(--c); }
.sw-metal {
  background: linear-gradient(125deg, rgba(255,255,255,0) 20%, rgba(255,255,255,0.55) 40%, rgba(255,255,255,0) 58%, rgba(0,0,0,0.18)), var(--c);
}

.toast-wrap {
  position: fixed; left: 0; right: 0; bottom: 32px; z-index: 60;
  display: flex; flex-direction: column; align-items: center; gap: 8px; pointer-events: none;
}
.toast {
  max-width: min(calc(var(--vw, 100vw) * 0.9), 480px); padding: 12px 20px; border-radius: 9999px;
  background: color-mix(in srgb, var(--ink) 94%, transparent); color: var(--on-ink);
  font-size: 14px; font-weight: 600;
  box-shadow: var(--shadow-2); animation: toastIn 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.toast.out { animation: toastOut 0.24s ease forwards; }
@keyframes toastIn { from { transform: translateY(12px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes toastOut { to { transform: translateY(-6px); opacity: 0; } }

.pop-fly { position: fixed; z-index: 70; pointer-events: none; animation: popFly 0.7s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
@keyframes popFly {
  from { transform: translate(0, 0) scale(1); opacity: 1; }
  to { transform: translate(var(--dx), var(--dy)) scale(0.12); opacity: 0.2; }
}

/* 보상 받았을 때 보관함 탭이 살짝 튄다 (코인 칩 대신) */
.nlink.bump { animation: navBump 0.32s cubic-bezier(0.22, 1.4, 0.36, 1); }
@keyframes navBump {
  0% { transform: scale(1); }
  45% { transform: scale(1.14); }
  100% { transform: scale(1); }
}

/* 꾸미기 트레이 — 보유 코인 */

/* 보관함 맨 아래 — 처음부터 다시 */
/* 앱 연동 — '내 카드' 제목과 같은 줄, 오른쪽 끝 */
.sf-link-btn {
  flex: 0 0 auto; padding: 0;
  background: none; color: var(--t2);
  /* 헤더 줄에 놓인다 — 발견 화면의 '커스텀' 버튼과 같은 크기 곡선을 쓴다 */
  font-size: clamp(12px, calc(var(--vw, 100vw) * 0.0089), 18px); font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px;
  transition: color 0.15s;
}
.sf-link-btn:hover { color: var(--t1); }
/* 화살표만 살짝 밀린다 */
.sf-link-btn svg {
  width: 1.15em; height: 1.15em; fill: none;
  stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
  transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
.sf-link-btn:hover svg { transform: translateX(3px); }
/* 앱과 연동하기 (js/applink.js) */
/* 연동 전 꾸미기 — 카드 대신 빈 케이스 하나와 안내 */
.dz-gate .dz-main { flex: 1 1 auto; }
.lk-in {
  display: flex; align-items: center; justify-content: center;
  gap: clamp(32px, calc(var(--vw, 100vw) * 0.06), 120px);
}
.lk-demo { flex: 0 0 auto; margin: 0; display: flex; flex-direction: column; align-items: center; gap: 20px; }
.lk-case { height: clamp(260px, calc(var(--vh, 100vh) * 0.56), 600px); aspect-ratio: 1200 / 2016; }
.lk-case .case { height: 100%; width: auto; }
/* 단계 이름 — 지금 보이는 단계만 검정 */
.lk-tabs { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px; }
.lk-stage { position: relative; }
/* 카드 보정 단계 — 카드 아래쪽에 띄우는 작은 보정 막대. 실제 꾸미기의 카드 보정 칸과 같은 모양 */
.lk-adj {
  position: absolute; left: 50%; bottom: 7%; transform: translateX(-50%);
  width: 84%; padding: 10px 12px; border-radius: 10px;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  box-shadow: var(--shadow-2); display: grid; gap: 6px;
  animation: fadeIn 0.3s ease;
}
.lk-adj[hidden] { display: none; }
.lk-adj-row { display: flex; align-items: center; gap: 10px; }
.lk-adj-row span { flex: 0 0 auto; width: 52px; font-size: 11px; font-weight: 600; color: var(--t1); }
.lk-adj-sl { position: relative; flex: 1 1 auto; height: 6px; border-radius: 9999px; background: var(--line); }
.lk-adj-sl.is-light { background: linear-gradient(90deg, #000000, #23b5ec, #ffffff); }
.lk-adj-sl i {
  position: absolute; top: 50%; left: 68%; width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 9999px;
  background: #6bcbf0; border: 2px solid #ffffff; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
}
.lk-adj-sl.is-bright i { left: 41.3%; background: var(--t1); }
.lk-tabs button {
  height: 32px; padding: 0 12px; border-radius: 9999px;
  font-size: 13px; font-weight: 600; color: var(--t3); background: none;
  transition: background 0.18s, color 0.18s;
}
.lk-tabs button:hover { color: var(--t1); }
.lk-tabs button.on { background: var(--ink); color: var(--on-ink); }
.lk-copy { max-width: 400px; }
.lk-copy h2 { font-size: clamp(24px, calc(var(--vw, 100vw) * 0.02), 36px); font-weight: 700; line-height: 1.3; color: var(--t1); }
.lk-copy p { margin-top: 12px; font-size: 15px; line-height: 1.6; color: var(--t2); }
.lk-steps { margin-top: 24px; display: grid; gap: 12px; list-style: none; padding: 0; }
.lk-steps li { display: flex; align-items: center; gap: 12px; font-size: 15px; color: var(--t1); }
.lk-steps b {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 9999px;
  display: grid; place-items: center; background: var(--chip); font-size: 12px; font-weight: 700;
}
.lk-btn {
  margin-top: 32px; height: 52px; padding: 0 28px; border-radius: 12px;
  background: var(--ink); color: var(--on-ink); font-size: 15px; font-weight: 700;
}
.lk-btn:active { opacity: 0.75; }
html[data-fit-narrow] .lk-in { flex-direction: column; text-align: center; gap: 24px; }
html[data-fit-narrow] .lk-case { height: clamp(220px, calc(var(--vh, 100vh) * 0.36), 360px); }
html[data-fit-narrow] .lk-steps { justify-items: center; }
.al-steps { margin-top: 16px; padding-left: 20px; font-size: 15px; color: var(--t1); line-height: 1.7; }
.al-wait { padding: 32px 0 40px; text-align: center; }
.al-err { margin-top: 12px; color: #e5271e; }
.al-spin {
  display: inline-block; width: 28px; height: 28px; margin-bottom: 16px; border-radius: 9999px;
  border: 3px solid var(--line); border-top-color: var(--t1);
  animation: alSpin 0.8s linear infinite;
}
@keyframes alSpin { to { transform: rotate(360deg); } }
.al-folders { margin-top: 20px; display: grid; gap: 20px; }
.al-fh { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 700; color: var(--t1); }
.al-fh i { width: 10px; height: 10px; border-radius: 9999px; }
.al-fh span { margin-left: auto; font-size: 13px; font-weight: 500; color: var(--t3); }
.al-thumbs { margin-top: 8px; display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 8px; }
.al-thumb { position: relative; aspect-ratio: 0.716; border-radius: 4px; overflow: hidden; background: var(--subtle); }
.al-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* 이미 가져온 카드는 옅게 — 연동 뒤 다시 열었을 때 새로 등록한 카드가 눈에 띄게 */
.al-folders:has(.is-new) .al-thumb:not(.is-new) { opacity: 0.4; }
/* 연동 코드 — 시트 안에서 한눈에 읽히게 */
.link-code {
  margin: 18px 0; padding: 18px; border-radius: 10px; background: var(--subtle);
  text-align: center; font-size: 26px; font-weight: 700; color: var(--t1);
  letter-spacing: 0.08em; font-variant-numeric: tabular-nums;
}

.sf-foot { margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line); text-align: center; }
.sf-foot button {
  height: 44px; padding: 0 18px; border-radius: 12px;
  font-size: 13px; font-weight: 600; color: var(--t3);
}
.sf-foot button:hover { background: var(--chip); color: var(--t2); }

/* 담은 카드 썸네일 (왼쪽 세로 레일) */
.dz-rail .side-h span { font-weight: 500; color: var(--t3); }
.mycards { margin-top: 12px; }
/* 담은 카드 — 고른 카드는 검은 테두리 대신 '옅은 받침'으로 표시하고,
   카드 둘레에 여백을 넉넉히 둬서 답답해 보이지 않게 한다 */
.mycard {
  padding: 9px;
  border-radius: 12px;
  background: none;
  opacity: 0.6;
  transition: opacity 0.18s, background 0.18s;
}
.mycard:hover { opacity: 0.9; }
.mycard.on { opacity: 1; background: var(--chip); }
.mycards:empty::after {
  content: '담은 카드가 없어요';
  font-size: 12px; color: var(--t3);
}


/* ── 카드 상세 — 갤러리 ─────────────────────
   카드를 크게 걸어 두고 그 옆에 소장자의 글·좋아요·댓글을 두는 화면 */
.gal {
  position: fixed; z-index: 45;
  inset: 0;
  background: var(--bg);
  overflow-y: auto;
  animation: galIn 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes galIn { from { opacity: 0; } to { opacity: 1; } }

.gal-in {
  min-height: 100%;
  display: grid;
  grid-template-columns: auto minmax(280px, 400px);
  align-items: center;
  justify-content: center;
  gap: clamp(48px, 7vw, 120px);
  padding: clamp(48px, 8vh, 96px) var(--gutter);
}

/* 낮은 창 — 옆의 글이 화면보다 길어지면, 가운데 정렬 때문에 카드가 같이 밀려 내려가
   첫 화면에서 아래가 잘린다. 이때는 위에 붙여 카드가 통째로 보이게 한다. */
@media (max-height: 760px) {
  .gal-in { align-items: start; }
}

.gal-card {
  width: min(calc(var(--vh, 100vh) * 0.46), 360px);
  animation: galCard 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes galCard { from { opacity: 0; transform: translateY(14px) scale(0.97); } to { opacity: 1; transform: none; } }
/* 벽에 걸린 것처럼 — 아주 옅고 길게 */
.gal-card .case {
  filter:
    drop-shadow(0 2px 3px rgba(24, 24, 27, 0.1))
    drop-shadow(10px 16px 24px rgba(24, 24, 27, 0.09));
}

.gal-story { max-width: 340px; animation: galText 0.7s 0.1s cubic-bezier(0.22, 1, 0.36, 1) backwards; }
@keyframes galText { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.gal-meta { font-size: 12px; font-weight: 600; letter-spacing: 0.12em; color: var(--t3); }
.gal-title { margin-top: 14px; font-size: clamp(28px, 3vw, 40px); font-weight: 500; letter-spacing: -0.06em; color: var(--t1); line-height: 1.2; }
.gal-sub { margin-top: 10px; font-size: 13px; font-weight: 500; color: var(--t3); line-height: 1.4; }
.gal-body { margin-top: 36px; }
.gal-body p { font-size: 16px; font-weight: 400; line-height: 1.62; color: var(--t2); }
.gal-body p + p { margin-top: 15px; }
.gal-sign { margin-top: 32px; font-size: 13px; font-weight: 500; color: var(--t3); }

.gal-actions { margin-top: 48px; display: flex; gap: 8px; }
.gal-btn {
  height: 40px; padding: 0 16px; border-radius: 6px;
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 13px; font-weight: 600; color: var(--t2);
  transition: box-shadow 0.15s, color 0.15s;
}
.gal-btn:hover { box-shadow: inset 0 0 0 1px var(--t3); color: var(--t1); }
.gal-btn-p { box-shadow: inset 0 0 0 1.5px var(--t1); color: var(--t1); }

.gal-close {
  position: fixed; top: 28px; right: var(--gutter); z-index: 2;
  width: 40px; height: 40px; border-radius: 9999px;
  display: grid; place-items: center;
  font-size: 15px; color: var(--t2);
  transition: background 0.15s, color 0.15s;
}
.gal-close:hover { background: var(--chip); color: var(--t1); }

@media (max-width: 860px) {
  .gal-in { grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 40px; padding: 72px 24px 56px; }
  .gal-card { width: min(52vw, 260px); }
  .gal-story { max-width: 420px; }
  .gal-actions { margin-top: 32px; }
}

/* 좋아요 · 댓글 — 상자 없이, 여백과 굵기로만 정리한다 */
.gal-bar {
  margin-top: 40px; padding-bottom: 24px;
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 20px;
}
.gal-heart {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 14px; font-weight: 600; color: var(--t2);
  font-variant-numeric: tabular-nums;
  transition: color 0.18s;
}
.gal-heart svg {
  width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linejoin: round;
  transition: transform 0.28s cubic-bezier(0.22, 1.5, 0.36, 1), fill 0.18s;
}
.gal-heart:hover { color: var(--t1); }
.gal-heart.on { color: #f04452; }
.gal-heart.on svg { fill: #f04452; }
.gal-heart.pop svg { transform: scale(1.22); }

.gal-quiet {
  font-size: 13px; font-weight: 600; color: var(--t3);
  padding-bottom: 2px; box-shadow: inset 0 -1px 0 transparent;
  transition: color 0.15s, box-shadow 0.15s;
}
.gal-quiet:hover { color: var(--t1); box-shadow: inset 0 -1px 0 var(--t1); }

.gal-comments { margin-top: 24px; }
.gal-cmt-head { font-size: 12px; font-weight: 600; letter-spacing: 0.1em; color: var(--t3); }
.gal-cmt-head span { font-variant-numeric: tabular-nums; }
.gal-cmt {
  margin-top: 18px;
  display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; align-items: start;
}
.gal-av {
  width: 28px; height: 28px; border-radius: 9999px;
  display: grid; place-items: center;
  background: var(--chip); color: var(--t2);
  font-size: 12px; font-weight: 700;
}
.gal-cmt.me .gal-av { background: var(--ink); color: var(--on-ink); }
.gal-cmt-by { font-size: 12px; font-weight: 600; color: var(--t3); }
.gal-cmt-text { margin-top: 3px; font-size: 14px; line-height: 1.65; color: var(--t2); }
.gal-cmt.me .gal-cmt-text { color: var(--t1); }

.gal-write {
  margin-top: 28px;
  display: flex; align-items: center; gap: 8px;
  border-bottom: 1px solid var(--line);
  transition: border-color 0.18s;
}
.gal-write:focus-within { border-color: var(--t1); }
.gal-input {
  flex: 1; min-width: 0; height: 42px; padding: 0;
  border: none; background: transparent;
  font-family: var(--font); font-size: 14px; color: var(--t1);
}
.gal-input::placeholder { color: var(--t3); }
.gal-input:focus { outline: none; }
.gal-send {
  width: 32px; height: 32px; border-radius: 9999px;
  display: grid; place-items: center; color: var(--t1);
  transition: opacity 0.18s, background 0.18s;
}
.gal-send svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.gal-send:hover { background: var(--chip); }
.gal-send[disabled] { opacity: 0.25; pointer-events: none; }

/* ── 입장 화면 ────────────────────────────
   워드마크 하나와 버튼 하나. 다른 것은 두지 않는다. */
.gate {
  position: fixed; z-index: 60;
  inset: 0;
  background: var(--bg);
  display: grid; place-items: center;
  transition: opacity 0.55s cubic-bezier(0.22, 1, 0.36, 1), transform 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
/* 걷힐 때 — 화면이 앞으로 열리듯 */
.gate.is-gone { opacity: 0; transform: scale(1.06); pointer-events: none; }

.gate-in {
  display: grid; justify-items: center; gap: 56px;
  animation: gateIn 0.8s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes gateIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

.gate-mark { width: clamp(180px, calc(var(--vw, 100vw) * 0.26), 300px); color: var(--logo); }
.gate-mark svg { display: block; width: 100%; height: auto; }

.gate-btn {
  height: 46px; padding: 0 30px;
  border-radius: 9999px;
  box-shadow: inset 0 0 0 1px var(--t3);
  background: none;
  font-size: 14px; font-weight: 600; color: var(--t2);
  transition: box-shadow 0.2s, color 0.2s, background 0.2s;
}
.gate-btn:hover { box-shadow: inset 0 0 0 1px var(--ink); background: var(--ink); color: var(--on-ink); }
.gate-btn:active { transform: scale(0.985); }

/* ── 카드쇼 ────────────────────────────────
   three.js(WebGL)로 그리는 3D 전시장. 여기 CSS 는 캔버스를 화면에 채우고
   그 위에 안내 글씨를 얹는 일만 한다 — 장면은 전부 js/cardshow.js 가 만든다. */
/* 관을 옮길 때 한 번 어두워졌다 밝아진다 — 눈앞이 통째로 바뀌는 게 덜 갑작스럽다 */
.cs-fade {
  position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background: #0f1216; opacity: 0;
}
.cs {
  /* 화면을 헤더 뒤까지 끌어올린다 — 카드쇼는 워드마크 없이 전체 화면으로 본다 */
  position: absolute; inset: 0; top: calc(-1 * var(--nav-h)); overflow: hidden;
  background: #f0e8dc;
  cursor: grab;
  touch-action: none;
  user-select: none;
}
.cs.is-look { cursor: grabbing; }
.cs canvas { display: block; width: 100%; height: 100%; }

/* 카드쇼에서는 헤더를 비운다 — 워드마크는 감추고 햄버거만 남긴다 */
body[data-tab='cardshow']:not(.menu-open) .topnav { background: none; backdrop-filter: none; }
body[data-tab='cardshow']:not(.menu-open) .brand { visibility: hidden; }
/* 취향의 발견(홈)도 워드마크 없이 — 자리는 그대로 둬서 햄버거·커스텀 위치가 움직이지 않는다 */
body[data-tab='discover']:not(.menu-open) .brand { visibility: hidden; }

/* 화면 위 안내 — 3D 밖에 그대로 얹는다 */
.cs-hud {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 0 var(--gutter) clamp(18px, 3vh, 34px);
  pointer-events: none; text-align: center;
}
.cs-here {
  font-size: clamp(15px, 1.4vw, 22px); font-weight: 700; color: #191f28;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.6);
  opacity: 0; transform: translateY(6px); transition: opacity 0.25s ease, transform 0.25s ease;
}
.cs-here.on { opacity: 1; transform: none; }
.cs-help {
  margin-top: 8px; font-size: 12px; font-weight: 500; color: rgba(25, 31, 40, 0.5);
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
}
.cs-help b { color: rgba(25, 31, 40, 0.75); font-weight: 700; }

/* 행사장 지도(하늘 뷰) 토글 — 화면 오른쪽 위. HUD 는 pointer-events 가 없으므로
   이 버튼만 따로 살려 둔다 */
.cs-map {
  /* 오른쪽 '아래'다. 위에 두면 .topnav(z-index 30, 화면 폭 전체)가 덮어서
     보이기는 해도 클릭이 헤더로 먹힌다 — .cs 는 그보다 낮은 층에 있다. */
  position: absolute; z-index: 2;
  bottom: clamp(18px, 3vh, 34px); right: var(--gutter);
  padding: 9px 16px; border: 0; border-radius: 999px;
  background: rgba(25, 31, 40, 0.82); color: #fff;
  font: 600 13px/1 var(--font); letter-spacing: -0.02em;
  cursor: pointer; pointer-events: auto;
  backdrop-filter: saturate(160%) blur(8px);
  box-shadow: 0 4px 14px rgba(25, 31, 40, 0.22);
  transition: background 0.18s ease, transform 0.18s ease;
}
.cs-map:hover { background: rgba(25, 31, 40, 0.95); transform: translateY(-1px); }
/* 오른쪽 아래 버튼 묶음 — 내 캐릭터 · 시점 · 지도. 지도만 진하게, 나머지는 흰 알약 */
.cs-btns {
  position: absolute; z-index: 2;
  bottom: clamp(18px, 3vh, 34px); right: var(--gutter);
  display: flex; gap: 8px; align-items: center;
}
.cs-btns .cs-map { position: static; }
/* 채팅 — 왼쪽 아래. 기록은 위로 쌓이고 몇 초 뒤 옅어진다(칸에 들어가면 다시 보인다) */
.cs-chat {
  position: absolute; z-index: 2;
  left: var(--gutter); bottom: clamp(18px, 3vh, 34px);
  width: min(340px, 32vw);
}
.cs-chat-log {
  display: flex; flex-direction: column; gap: 4px; margin-bottom: 8px;
  pointer-events: none;           /* 옅어진 기록이 장면 클릭을 가로채지 않게 */
}
.cs-chat-line {
  align-self: flex-start; max-width: 100%; margin: 0;
  padding: 5px 11px; border-radius: 12px;
  background: rgba(255, 255, 255, 0.9); color: #191f28;
  font-size: 13px; line-height: 1.4; word-break: keep-all; overflow-wrap: anywhere;
  box-shadow: 0 2px 8px rgba(25, 31, 40, 0.1);
  transition: opacity 0.6s ease;
}
.cs-chat-line b { margin-right: 4px; font-weight: 700; color: #6b7684; }
.cs-chat-line.is-me b { color: #ff7a3d; }
.cs-chat-line.is-old { opacity: 0; }
.cs-chat.is-on .cs-chat-line.is-old { opacity: 0.85; }
.cs-chat-row { display: flex; gap: 6px; }
.cs-chat-in {
  flex: 1; min-width: 0; height: 36px; padding: 0 14px;
  border: 0; border-radius: 999px; outline: none;
  background: rgba(255, 255, 255, 0.9); color: #191f28;
  font: 500 13px/1 var(--font);
  box-shadow: 0 4px 14px rgba(25, 31, 40, 0.12);
  backdrop-filter: saturate(160%) blur(8px);
}
.cs-chat-in::placeholder { color: #8b95a1; }
.cs-chat-in:focus { background: #fff; box-shadow: 0 0 0 2px #191f28, 0 4px 14px rgba(25, 31, 40, 0.12); }
.cs-chat-send {
  height: 36px; padding: 0 14px; border: 0; border-radius: 999px; cursor: pointer;
  background: rgba(25, 31, 40, 0.82); color: #fff; font: 600 13px/1 var(--font);
}
.cs-chat-send:hover { background: rgba(25, 31, 40, 0.95); }
/* 가운데 조작 안내가 채팅 칸과 겹치기 시작하는 폭 — 안내는 숨긴다(키 안내는 넓은 화면용이다) */
@media (max-width: 1300px) {
  .cs-help { display: none; }
}

/* 좁은 화면 — 버튼 셋은 가운데 줄로, 채팅은 그 위에 화면 폭 그대로, 안내는 그 위로 올린다 */
@media (max-width: 620px) {
  .cs-btns { left: 0; right: 0; justify-content: center; }
  .cs-chat { left: 16px; right: 16px; width: auto; bottom: calc(clamp(18px, 3vh, 34px) + 46px); }
  /* 아래는 채팅 기록이 쌓이는 자리라 구역 이름은 위(햄버거 줄 아래)로 올린다 */
  .cs-hud { top: 0; bottom: auto; padding: calc(var(--nav-h) + 4px) 16px 0; }
}
.cs-btns .cs-sub { background: rgba(255, 255, 255, 0.9); color: #191f28; }
.cs-btns .cs-sub:hover { background: #fff; }
/* 내 캐릭터 시트 */
.cs-me-l { display: block; margin: 16px 0 8px; font-size: 13px; font-weight: 700; color: var(--t2); }
.cs-me-name {
  display: block; width: 100%; margin-top: 8px; padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 12px;
  font: 600 15px/1.2 var(--font); color: var(--t1); background: var(--bg, #fff);
}
.cs-sws { display: flex; flex-wrap: wrap; gap: 10px; }
.cs-sw {
  width: 34px; height: 34px; border-radius: 50%; border: 0; cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12);
  transition: transform 0.15s ease;
}
.cs-sw:hover { transform: scale(1.08); }
/* 내 캐릭터 — 미리보기는 시트 맨 위에 붙어 있어서 아래 칸을 내려 보며 골라도 계속 보인다 */
.cs-me-prev {
  position: sticky; top: -28px; z-index: 3;
  margin: -28px -28px 4px; padding: 14px 0 6px;
  display: flex; justify-content: center;
  /* 시트를 내려도 아래 칸이 비쳐 겹치지 않게 바탕을 꽉 채우고, 아래에 옅은 그늘로 경계를 준다 */
  background: var(--surface);
  box-shadow: 0 10px 10px -10px rgba(25, 31, 40, 0.14);
}
.cs-me-prev { flex-direction: column; align-items: center; }
.cs-me-prev canvas {
  width: 220px; height: 200px; display: block;
  cursor: grab; touch-action: none;   /* 끌어 돌리는 동안 시트가 스크롤되지 않게 */
}
.cs-me-prev canvas.is-drag { cursor: grabbing; }
.cs-me-turn { display: flex; align-items: center; gap: 4px; margin-top: 2px; padding-bottom: 6px; }
.cs-me-turn button {
  height: 26px; padding: 0 11px; border-radius: 999px;
  background: var(--chip); color: var(--t2);
  font: 600 12px/1 var(--font); cursor: pointer;
}
.cs-me-turn button:hover { color: var(--t1); }
.cs-me-hint { margin-right: 6px; font-size: 11px; color: var(--t3); }
.cs-opts { display: flex; flex-wrap: wrap; gap: 6px; }
.cs-opt {
  height: 34px; padding: 0 13px; border-radius: 999px; cursor: pointer;
  background: var(--chip); color: var(--t1);
  font: 600 13px/1 var(--font);
  transition: background 0.15s ease, color 0.15s ease;
}
.cs-opt:hover { background: var(--line); }
.cs-opt.on { background: var(--ink); color: var(--on-ink); }
/* 다른 컬렉터의 컬렉션 — 카드 썸네일 격자 */
.cs-col {
  margin-top: 14px; display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  max-height: min(46vh, 420px); overflow-y: auto;
}
.cs-col-card {
  padding: 0; border: 0; cursor: pointer; background: var(--subtle, #f2f0ec);
  aspect-ratio: 0.716; border-radius: 6px; overflow: hidden;
  box-shadow: 0 1px 3px rgba(25, 31, 40, 0.12);
  transition: transform 0.15s ease;
}
.cs-col-card:hover { transform: translateY(-2px); }
.cs-col-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cs-sw.on { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.12), 0 0 0 2px #fff, 0 0 0 4px #191f28; }
/* 하늘 뷰에서는 드래그가 '내 자리 옮기기'다 — 손 모양으로 알려 준다 */
.cs.is-map { cursor: grab; }
.cs.is-map:active { cursor: grabbing; }

.cs-story { margin-top: 12px; font-size: 14px; line-height: 1.65; color: var(--t2); }
/* 카드 크게 보기 — 시트 맨 위에 카드 한 장. 화면이 낮으면 높이에 맞춰 줄인다 */
.cs-card-big {
  display: flex; justify-content: center;
  margin: -4px 0 22px;
}
.cs-card-big img {
  /* 높이 · 폭 상한 안에서 카드 원래 비율 그대로 — 좁은 화면에서 옆이 잘리지 않게 */
  display: block; width: auto; height: auto;
  max-width: 100%; max-height: min(52vh, 460px);
  border-radius: 12px;
  box-shadow: 0 14px 34px rgba(25, 31, 40, 0.22), 0 2px 6px rgba(25, 31, 40, 0.1);
}
.cs-card-bar { margin-top: 24px; padding-bottom: 18px; }
/* 기업부스 이벤트 목록 — 시각 표기가 뒤에 붙으므로 한 줄에 하나씩 */
.cs-events { margin: 14px 0 0; padding: 0; list-style: none; }
.cs-events li {
  position: relative; padding: 9px 0 9px 16px; font-size: 14px; line-height: 1.5;
  color: var(--t1); border-top: 1px solid var(--line);
}
.cs-events li:last-child { border-bottom: 1px solid var(--line); }
/* 시각은 왼쪽에 칸을 고정해 세로로 줄이 맞게 한다 — 내용 길이가 제각각이라
   그냥 앞에 붙이면 시간이 들쭉날쭉해서 훑기가 어렵다 */
.cs-events li { display: flex; gap: 12px; padding-left: 0; }
.cs-ev-t {
  flex: 0 0 auto; min-width: 84px;
  font-variant-numeric: tabular-nums; font-weight: 700; color: #e8467f;
}
/* 할 수 없는 동작 — 눌러도 아무 일 없다는 걸 보이게 */
.sheet-actions .btn[disabled] { opacity: 0.42; pointer-events: none; }

/* 교류 자리 — 상대가 내놓은 카드와 조건 */
.cs-offer { display: flex; gap: 18px; align-items: center; margin-top: 18px; }
.cs-offer-card { flex: 0 0 auto; width: 118px; }
.cs-offer-txt { flex: 1 1 auto; min-width: 0; }
.cs-offer-name { font-size: 16px; font-weight: 700; color: var(--t1); }
.cs-offer-price {
  margin-top: 10px; font-size: 24px; font-weight: 800; color: var(--t1);
  font-variant-numeric: tabular-nums;
}
.cs-offer-price span { font-size: 14px; font-weight: 600; color: var(--t2); margin-left: 4px; }
/* 못 하는 이유 — 비활성 버튼만 두면 내 잘못인지 원래 그런지 알 수가 없다 */
.cs-offer-why {
  margin-top: 14px; padding: 10px 12px; border-radius: 10px;
  background: var(--chip); font-size: 13px; font-weight: 600; color: var(--t2);
}
/* 결제 — 산 카드 · 결제 수단 · 금액 */
.cs-pay-test {
  margin-top: 14px; padding: 8px 12px; border-radius: 10px;
  background: color-mix(in srgb, #3b6fd4 12%, transparent);
  font-size: 13px; font-weight: 700; color: #3b6fd4;
}
.cs-pay-item { display: flex; gap: 14px; align-items: center; margin-top: 16px; }
.cs-pay-card { flex: 0 0 auto; width: 64px; }
.cs-pay-label { margin-top: 22px; font-size: 13px; font-weight: 700; color: var(--t2); }
.cs-pay-methods { display: grid; gap: 8px; margin-top: 10px; }
.cs-pay-m {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 12px 14px; border-radius: 12px; text-align: left;
  box-shadow: inset 0 0 0 1px var(--line);
  transition: box-shadow 0.15s, background 0.15s;
}
.cs-pay-m:hover { background: var(--chip); }
.cs-pay-m[aria-checked="true"] { box-shadow: inset 0 0 0 2px var(--ink); }
.cs-pay-badge {
  flex: 0 0 auto; width: 44px; height: 30px; border-radius: 8px;
  display: grid; place-items: center;
  font-size: 12px; font-weight: 800; letter-spacing: -0.02em;
}
.cs-pay-mt { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.cs-pay-mt b { font-size: 15px; font-weight: 700; color: var(--t1); }
.cs-pay-mt small { font-size: 12px; font-weight: 500; color: var(--t2); }
.cs-pay-dot {
  flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%;
  box-shadow: inset 0 0 0 2px var(--t3);
  transition: box-shadow 0.15s;
}
.cs-pay-m[aria-checked="true"] .cs-pay-dot { box-shadow: inset 0 0 0 6px var(--ink); }
.cs-pay-total {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line);
  font-size: 14px; font-weight: 600; color: var(--t2);
}
.cs-pay-total b { font-size: 22px; font-weight: 800; color: var(--t1); font-variant-numeric: tabular-nums; }
.cs-pay-total b span { font-size: 14px; font-weight: 600; color: var(--t2); margin-left: 6px; }
/* 결제 중 — 눌리지는 않되 흐려지지는 않게 */
.sheet-actions .btn[data-act="pay"][disabled] { opacity: 0.7; }
/* 교환 신청 — 줄 카드 ⇄ 받을 카드 */
.cs-swap {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px;
  margin-top: 20px;
}
.cs-swap-side { margin: 0; display: grid; justify-items: center; gap: 10px; min-width: 0; }
.cs-swap-card { width: min(128px, 100%); }
.cs-swap-side figcaption {
  display: grid; gap: 2px; text-align: center; min-width: 0;
  font-size: 14px; font-weight: 700; color: var(--t1);
}
.cs-swap-side small { font-size: 12px; font-weight: 600; color: var(--t2); }
.cs-swap-arrow { font-size: 24px; color: var(--t3); }
/* 응답을 기다리는 신청 */
.cs-trade-wait {
  display: flex; gap: 12px; align-items: center;
  margin-top: 16px; padding: 12px 14px; border-radius: 12px;
  background: color-mix(in srgb, #8b5cf0 10%, transparent);
}
.cs-trade-wait-t { font-size: 14px; font-weight: 700; color: #7446d8; }
.cs-trade-wait-s { margin-top: 2px; font-size: 13px; font-weight: 500; color: var(--t2); }
.cs-trade-wait-s b { font-weight: 700; color: var(--t1); }
.cs-trade-spin {
  flex: 0 0 auto; width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid color-mix(in srgb, #8b5cf0 25%, transparent); border-top-color: #8b5cf0;
  animation: csSpin 0.9s linear infinite;
}
@keyframes csSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .cs-trade-spin { animation-duration: 2.4s; } }
.cs-trade-test {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 10px; font-size: 12px; font-weight: 600; color: var(--t2);
}
.cs-trade-test span { flex: 1 1 auto; }
.cs-trade-test button {
  height: 28px; padding: 0 12px; border-radius: 8px;
  background: var(--chip); color: var(--t1); font-size: 12px; font-weight: 700;
}
/* 교환 응답 결과 — 흰 창 한가운데 크게. 열려 있는 시트보다 위에 뜬다 */
.modal-scrim.is-top { z-index: 50; }
.modal.tr-res { z-index: 51; width: min(440px, calc(var(--vw, 100vw) - 48px)); padding: 32px 28px 24px; }
.tr-res-icon {
  width: 64px; height: 64px; margin: 0 auto 16px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 30px; font-weight: 800; color: #fff;
  animation: trPop 0.46s cubic-bezier(0.22, 1.5, 0.36, 1) 0.08s both;
}
@keyframes trPop { from { transform: scale(0.4); opacity: 0; } to { transform: none; opacity: 1; } }
.tr-res.is-accepted .tr-res-icon { background: #16a34a; box-shadow: 0 0 0 8px color-mix(in srgb, #16a34a 16%, transparent); }
.tr-res.is-declined .tr-res-icon { background: #e5484d; box-shadow: 0 0 0 8px color-mix(in srgb, #e5484d 16%, transparent); }
.tr-res.is-failed .tr-res-icon { background: #f0a72a; box-shadow: 0 0 0 8px color-mix(in srgb, #f0a72a 18%, transparent); }
.modal.tr-res h3 { font-size: 24px; font-weight: 800; }
.tr-res.is-accepted h3 { color: #16a34a; }
.tr-res.is-declined h3 { color: #e5484d; }
.tr-res.is-failed h3 { color: #c98512; }
.modal.tr-res > p { font-size: 15px; }
.modal.tr-res > p b { color: var(--t1); font-weight: 700; }
/* 모달 공통 p 규칙(.modal p)이 카드 레이블 글줄(<p class="lb-line">)까지 키워 버린다 — 되돌린다 */
.modal .case-label p { margin-top: 0; font-size: 3.6cqw; line-height: 1.25; color: inherit; }
.tr-res-swap {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 10px;
  margin-top: 20px; padding: 16px 12px; border-radius: 14px; background: var(--chip);
}
.tr-res-side { margin: 0; display: grid; justify-items: center; gap: 8px; min-width: 0; }
.tr-res-card { width: min(96px, 100%); }
.tr-res-side figcaption {
  display: grid; gap: 2px; min-width: 0;
  font-size: 13px; font-weight: 700; color: var(--t1); overflow-wrap: anywhere;
}
.tr-res-side small { font-size: 11px; font-weight: 600; color: var(--t2); }
.tr-res-arrow { font-size: 22px; color: var(--t3); }
/* 거절·실패 — 오가지 않았다는 걸 카드를 가라앉혀서도 보인다 */
.tr-res.is-declined .tr-res-card, .tr-res.is-failed .tr-res-card { opacity: 0.55; filter: grayscale(0.4); }
.tr-res-ok { width: 100%; margin-top: 20px; }
/* 교환에 내놓을 카드 고르기 */
.cs-pick {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
  margin-top: 16px; max-height: 46vh; overflow-y: auto;
}
.cs-pick-i { display: block; width: 100%; transition: transform 0.15s; }
.cs-pick-i:hover { transform: translateY(-4px); }

/* 일정마다 붙는 참여 버튼 — 시각·내용 다음, 줄 오른쪽 끝에 붙는다 */
.cs-events li { align-items: center; }
.cs-ev-n { flex: 1 1 auto; }
.cs-ev-join {
  flex: 0 0 auto;
  height: 30px; padding: 0 12px; border-radius: 8px;
  background: var(--ink); color: var(--on-ink);
  font-size: 12px; font-weight: 700; white-space: nowrap;
}
.cs-ev-join:active { opacity: 0.75; }
.cs-ev-join[disabled] { background: var(--chip); color: var(--t3); pointer-events: none; }

/* 처음 기업부스를 눌렀을 때 도는 안내 —
   화면을 덮어 어둡게 하고 말하는 물건 한 군데만 뚫어서 밝게 남긴다.
   구멍은 '아주 큰 그림자'로 판다: 테두리 밖으로 9999px 짜리 그늘을 던지면
   상자 안쪽만 원래 밝기로 남는다. 자리는 js 가 매 프레임 잡아 준다. */
.cs-tour { position: absolute; inset: 0; z-index: 3; }
.cs-tour-hole {
  position: absolute; border-radius: 12px;
  box-shadow: 0 0 0 9999px rgba(24, 20, 16, 0.66);
  outline: 2px solid rgba(255, 255, 255, 0.92);
  outline-offset: -1px;
  transition: left 0.28s cubic-bezier(0.22, 1, 0.36, 1),
              top 0.28s cubic-bezier(0.22, 1, 0.36, 1),
              width 0.28s cubic-bezier(0.22, 1, 0.36, 1),
              height 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.cs-tour-say {
  position: absolute; width: 268px;
  padding: 16px 18px 14px; border-radius: 14px;
  background: var(--bg, #fff); box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
  transition: left 0.28s cubic-bezier(0.22, 1, 0.36, 1),
              top 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.cs-tour-step { font-size: 12px; font-weight: 700; color: #e8467f; }
.cs-tour-text {
  margin: 6px 0 14px; font-size: 15px; font-weight: 600;
  line-height: 1.5; color: var(--t1);
}
.cs-tour-say .btn { width: 100%; }

/* ── 특별전 — 사진째 거는 작품 (js/exhibit.js) ──
   케이스 PNG 없이 사진 한 장이 곧 작품이다. 높이는 케이스와 맞추고 폭은 사진 비율대로(--pw).
   그림자 판(.case::before)은 사진 가장자리에 딱 붙인다 — 케이스 몸통 안쪽으로 들일 테두리가 없다. */
.room-shelves .gitem.is-photo { width: calc(var(--slot, 64px) * var(--pw, 1)); }
.case-photo { border-radius: 1.6cqw; }
.case-photo-img {
  position: relative; z-index: 1;
  display: block; width: 100%; height: 100%;
  object-fit: cover; border-radius: inherit;
}
.room-shelves .gitem .case-photo::before { inset: 0; border-radius: inherit; }
.room-shelves .gitem .case-photo::after { left: 0; right: 0; bottom: 0; z-index: 2; border-radius: 0 0 1.6cqw 1.6cqw; }
/* 이름이 긴 작품이 많다 — 한두 줄로 감싸 화면 폭을 넘지 않게 */
.ri-name-ex { max-width: min(640px, calc(var(--vw, 100vw) - 48px)); line-height: 1.4; }
/* 방 위에서 연 작품 설명은 방보다 앞에 뜬다 */
body:has(.room) .sheet-scrim { z-index: 50; }
body:has(.room) .sheet { z-index: 51; }
.ex-story { margin-top: 18px; display: grid; gap: 10px; }
.ex-story p { font-size: 14px; line-height: 1.65; color: var(--t2); word-break: keep-all; }
/* 작품 설명 안의 원본 사진 — 시트에 실려 있던 슬랩 사진 그대로 */
.ex-photo { display: block; margin: 18px auto 0; max-width: 100%; max-height: min(420px, calc(var(--vh, 100vh) * 0.4)); border-radius: 8px; }

/* 카드쇼 렌더링 측정 모드(?bench=N) 표시판 */
.cs-bench {
  position: fixed; top: calc(var(--nav-h, 64px) + 12px); left: 50%; transform: translateX(-50%); z-index: 50;
  padding: 6px 12px; border-radius: 8px; background: rgba(0, 0, 0, 0.72); color: #fff;
  font: 600 13px/1.4 var(--font); white-space: nowrap; pointer-events: none;
}

/* 카드쇼 함께 보기 상태 — 연결되면 초록 점 */
.cs-live {
  position: fixed; top: calc(var(--nav-h, 64px) + 12px); left: 16px; z-index: 40;
  padding: 6px 12px; border-radius: 9999px; background: rgba(255, 255, 255, 0.86); color: var(--t2);
  font: 600 12px/1.4 var(--font); pointer-events: none;
}
.cs-live.is-on { color: var(--t1); }
.cs-live.is-on::before {
  content: ''; display: inline-block; width: 7px; height: 7px; margin-right: 6px; border-radius: 9999px;
  background: #16a34a; vertical-align: 1px;
}
