/*
 * neotrip 모바일 셸 스타일 — 뉴모피즘(Soft UI) 라이트 테마
 *
 * 앱형 셸: 좌측 아이콘 레일 + 콘텐츠 페이지 + 하단 플레이 바.
 * 토큰과 규칙의 근거는 저장소 루트 DESIGN.md와 docs/design/references/에 있다.
 * 한 재질(#ECF0F3) 위에서 왼쪽 위 광원의 그림자 쌍으로만 형태를 만들고, 테마색은 #61b3e4 하나다.
 */

:root {
  /* 색 (DESIGN.md §2) */
  --bg: #ECF0F3;
  --surface: #ECF0F3;
  --surface-bright: #F6F8FA;
  --surface-sunken: #E4E9EE;
  --shade-dark: #D1D9E6;
  --shade-light: #FFFFFF;
  --shade-ink: rgba(13, 39, 80, 0.16);
  --text: #31394A;
  --muted: #5A6577;
  --faint: #8A94A3;
  --accent: #61b3e4;
  --accent-ink: #1A6494;
  --on-accent: #0B2538;
  --accent-soft: rgba(97, 179, 228, 0.16);
  --accent-border: rgba(97, 179, 228, 0.45);
  --accent-glow: rgba(97, 179, 228, 0.35);
  --accent-stroke: rgba(97, 179, 228, 0.55);
  --accent-fill: rgba(97, 179, 228, 0.10);
  /* 재생 중 재생바 버튼의 회색 바탕(디자이너 사운드바 메모). 아이콘은 --text로 올려 대비를 지킨다. */
  --neutral-fill: #BFC7D1;
  /* 네온빛: 디자이너 오로라 참조 이미지에서 추출한 깊은 파랑→밝은 청록. 단일색이 아니라 --neon-aurora 그라디언트로 쓴다.
     이 선언은 씬 레인만 두고, 다른 파일은 var(--neon-3, #0093fe)처럼 대체값과 함께 참조한다. */
  --neon-1: #0049ff;
  --neon-2: #0074ff;
  --neon-3: #0093fe;
  --neon-4: #00aafe;
  --neon-5: #00c6fc;
  --neon-6: #00eff7;
  --neon-aurora: linear-gradient(110deg, var(--neon-1), var(--neon-3), var(--neon-5), var(--neon-6), var(--neon-3), var(--neon-1));
  --warning: #E6B451;
  --warning-ink: #8A5A00;
  --warning-soft: rgba(230, 180, 81, 0.16);
  --danger: #E0485F;
  --danger-ink: #B4233F;
  --danger-soft: rgba(224, 72, 95, 0.12);
  --scrim: rgba(49, 57, 74, 0.28);
  --oral-ink: #6B4E9B;
  --oral-soft: rgba(107, 78, 155, 0.12);
  --oral-border: rgba(107, 78, 155, 0.35);
  --on-oral: #FFFFFF;
  --viewer-bg: rgba(20, 26, 36, 0.94);
  --map-void: #E6ECF1;
  --label-halo: rgba(255, 255, 255, 0.92);

  /* 그림자 (DESIGN.md §3, button1·button2 수치를 축소) */
  --shadow-raised: 12px 12px 24px var(--shade-dark), -12px -12px 24px var(--shade-light);
  --shadow-raised-sm: 5px 5px 10px var(--shade-dark), -5px -5px 10px var(--shade-light);
  --shadow-micro: 2px 2px 4px var(--shade-dark), -2px -2px 4px var(--shade-light);
  --shadow-inset: inset 5px 5px 10px var(--shade-dark), inset -5px -5px 10px var(--shade-light);
  --shadow-inset-sm: inset 2px 2px 4px var(--shade-dark), inset -2px -2px 4px var(--shade-light);
  --shadow-inset-deep: inset 10px 10px 18px var(--shade-ink), inset -10px -10px 16px rgba(255, 255, 255, 0.64);
  --shadow-round: 10px 10px 18px var(--shade-ink), -8px -8px 16px var(--shade-light);
  --shadow-float: 0 12px 32px rgba(13, 39, 80, 0.14), -6px -6px 16px var(--shade-light);

  /* 라운드 (DESIGN.md §4) */
  --radius-xs: 8px;
  --radius-sm: 14px;
  --radius: 20px;
  --radius-lg: 28px;
  --radius-full: 999px;

  /* 타이포 (DESIGN.md §5) */
  --font-mono: ui-monospace, 'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', monospace;
  --font-sans: -apple-system, BlinkMacSystemFont, 'Apple SD Gothic Neo', 'Pretendard', 'Noto Sans KR', 'Malgun Gothic', 'Segoe UI', Roboto, sans-serif;

  --rail-w: 64px;
  --playbar-h: 68px;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --workspace-max: 90rem;
  --workspace-panel: 22rem;
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

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

[hidden] { display: none !important; }

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: pointer;
  touch-action: manipulation;
}

:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

/* ── 앱 셸 레이아웃 ─────────────────────────────── */

.app {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100vh;
  height: 100dvh;
  max-width: 520px;
  width: 100%;
  margin: 0 auto;
  background: var(--bg);
}

@media (min-width: 560px) {
  .app {
    box-shadow: 0 0 40px var(--shade-dark);
  }
}

@media (min-width: 960px) {
  .app {
    max-width: none;
  }

  .app.admin-active .pages {
    padding-inline: 0;
  }
}

.app.admin-active {
  max-width: none;
}

.app.admin-active .pages {
  overflow: hidden;
  padding: 0;
}

.app-body {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
}

/* ── 좌측 아이콘 레일 ────────────────────────────── */

.rail {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 30;
  width: calc(var(--rail-w) + var(--safe-left));
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 24px;
  padding: var(--space-4) var(--space-2) var(--space-4) calc(var(--space-2) + var(--safe-left));
  /* 디자이너 메뉴바 메모: 메뉴바와 내용 영역 사이 그림자를 뺀다. 경계는 평평하게 둔다. */
  background: var(--surface);
  box-shadow: none;
  /* 아이콘 홈의 그림자와 길게 누르기 말풍선이 레일 오른쪽 끝에서 잘리지 않도록 자르지 않는다. */
  overflow: visible;
  /* 길게 누르는 동안 글자 선택·iOS 문맥 메뉴가 뜨지 않게 한다. */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}

.rail-nav {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.rail-chat {
  margin-top: auto;
}

.rail-item {
  display: flex;
  align-items: center;
  height: 48px;
  flex: none;
}

.rail-icon {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--surface);
  color: var(--muted);
  box-shadow: var(--shadow-raised-sm);
  transition: background 0.2s ease, box-shadow 0.15s ease-out, color 0.2s ease, transform 0.1s ease;
}

.rail-icon svg {
  display: block;
  width: 22px;
  height: 22px;
}

@media (hover: hover) and (pointer: fine) {
  .rail-item:hover .rail-icon {
    color: var(--accent-ink);
  }
}

/* 현재 페이지: 눌린 홈 + 청록 아이콘 + 옅은 청록 바탕 (그림자만으로 구분하지 않는다) */
.rail-item[aria-current="true"] .rail-icon {
  background: var(--accent-soft);
  box-shadow: var(--shadow-inset);
  color: var(--accent-ink);
}

.rail-item:active .rail-icon {
  box-shadow: var(--shadow-inset);
  transform: scale(0.97);
}

/* 길게 누르기 말풍선: 누른 아이콘 오른쪽에 메뉴 이름을 한 줄로 띄운다. 위치(top·left)는 mobile.js가 정한다. */
.rail-tip {
  position: absolute;
  z-index: 1;
  transform: translateY(-50%);
  padding: 6px 12px;
  border-radius: var(--radius-full);
  background: var(--surface-bright);
  box-shadow: var(--shadow-float);
  color: var(--text);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap;
  pointer-events: none;
  animation: rail-tip-in 0.12s ease-out both;
}

/* 말풍선 꼬리: 아이콘 쪽을 가리킨다. */
.rail-tip::before {
  content: '';
  position: absolute;
  top: 50%;
  left: -4px;
  width: 8px;
  height: 8px;
  background: inherit;
  transform: translateY(-50%) rotate(45deg);
}

.rail-tip[hidden] {
  display: none;
}

@keyframes rail-tip-in {
  from { opacity: 0; transform: translate(-4px, -50%); }
  to { opacity: 1; transform: translateY(-50%); }
}

/* ── 페이지 영역 ────────────────────────────────── */

.pages {
  flex: 1;
  min-width: 0;
  margin-left: calc(var(--rail-w) + var(--safe-left));
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: var(--space-6) calc(20px + var(--safe-right)) var(--space-6) 20px;
  scrollbar-width: thin;
  scrollbar-color: var(--shade-dark) transparent;
}

.pages::-webkit-scrollbar {
  width: 8px;
}

.pages::-webkit-scrollbar-track {
  background: transparent;
}

.pages::-webkit-scrollbar-thumb {
  border-radius: var(--radius-full);
  background: var(--shade-dark);
}

.pages::-webkit-scrollbar-thumb:hover,
.pages::-webkit-scrollbar-thumb:active {
  background: var(--accent);
}

.page {
  display: none;
  min-height: 100%;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  text-align: center;
}

.page.active {
  display: flex;
  animation: page-in 0.22s ease both;
}

.live-info-column,
.live-map-column {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

/* 운영자·기획자 페이지: 셸 안에 임베드된 별도 문서가 클라이언트 영역을 가득 채운다 */
#page-admin,
#page-planner {
  min-height: 0;
  height: 100%;
  padding: 0;
  gap: 0;
  align-items: stretch;
  justify-content: stretch;
}

#adminFrame,
#plannerFrame {
  flex: 1;
  width: 100%;
  min-height: 0;
  height: 100%;
  border: 0;
  display: block;
  background: var(--bg);
}

@keyframes page-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.page-head h2 {
  color: var(--text);
  font-size: 1.5rem;
  font-weight: 300;
  line-height: 1.3;
  letter-spacing: -0.01em;
  word-break: keep-all;
}

.page-head p {
  margin-top: 6px;
  color: var(--accent-ink);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.28em;
  text-transform: uppercase;
}

.page-body {
  max-width: 30ch;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.7;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.nowrap {
  white-space: nowrap;
}

.page-note {
  padding: 8px 14px;
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-micro);
  color: var(--muted);
  font-size: 0.75rem;
}

/* ── 레코더: 위 안내 카드, 아래 물결 원형 마이크(recording-page.png), 녹음본 칸 1개와 업로드 ── */

#page-recorder {
  --recorder-pad-size: calc(var(--space-8) * 6);
  --recorder-mic-size: calc(var(--space-8) * 3);
  --recorder-wave-duration: 3.6s;
  --recorder-aurora-duration: 8s;
  --recorder-neon: var(--neon-aurora, linear-gradient(110deg, var(--neon-1, #0049ff), var(--neon-2, #0074ff), var(--neon-3, #0093fe), var(--neon-4, #00aafe), var(--neon-5, #00c6fc), var(--neon-6, #00eff7), var(--neon-3, #0093fe), var(--neon-1, #0049ff)));
  justify-content: flex-start;
  align-items: stretch;
  gap: var(--space-3);
  text-align: left;
}

#page-recorder .page-head,
#page-live .page-head {
  width: 100%;
  text-align: left;
  background: none;
  box-shadow: none;
}

#page-recorder .page-head h2,
#page-live .page-head h2 {
  font-weight: 700;
}

.recorder-card,
.recorder-take {
  width: 100%;
  max-width: 420px;
  align-self: center;
}

.recorder-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius);
  border: 1px solid var(--shade-dark);
  background: var(--surface);
  box-shadow: none;
}

.recorder-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
}

.recorder-intro {
  color: var(--text);
  font-size: 0.875rem;
  line-height: 1.5;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.recorder-count {
  flex: none;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  box-shadow: var(--shadow-inset-sm);
  color: var(--accent-ink);
  font-size: 0.75rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.recorder-count[hidden] {
  display: none;
}

.recorder-items {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.recorder-items:empty {
  display: none;
}

/* 번호 항목 = 업로드 칸. 완료는 체크 + 문구, 다음 항목은 청록 면 + "지금 채집"으로 함께 표시한다. */
.recorder-item {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  column-gap: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-inset-sm);
}

.recorder-item-marker {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-micro);
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
}

.recorder-item-body {
  min-width: 0;
}

.recorder-item-text {
  color: var(--text);
  font-size: 0.875rem;
  line-height: 1.5;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.recorder-item-example {
  margin-top: 2px;
  color: var(--muted);
  font-size: 0.75rem;
  line-height: 1.45;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.recorder-item-state {
  grid-column: 2;
  margin-top: 4px;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 500;
}

.recorder-item[data-state='pending'] .recorder-item-state {
  display: none;
}

.recorder-item[data-state='current'] {
  background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent-border);
}

.recorder-item[data-state='current'] .recorder-item-marker {
  color: var(--accent-ink);
}

.recorder-item[data-state='current'] .recorder-item-state,
.recorder-item[data-state='done'] .recorder-item-state {
  color: var(--accent-ink);
}

.recorder-item[data-state='done'] .recorder-item-marker {
  background: var(--accent);
  box-shadow: none;
  color: var(--on-accent);
}

.recorder-item[data-state='done'] .recorder-item-text {
  color: var(--muted);
}

.recorder-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

#page-recorder .rec-pad {
  position: relative;
  width: var(--recorder-pad-size);
  height: var(--recorder-pad-size);
  display: grid;
  place-items: center;
}

#page-recorder .rec-pad::before,
#page-recorder .rec-ripple-2::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: var(--radius-full);
  background: var(--recorder-neon);
  filter: blur(var(--space-3));
  transform: scale(1.15);
  opacity: 0.32;
  pointer-events: none;
}

#page-recorder .rec-pad::before {
  mask-image: radial-gradient(circle, transparent 24%, var(--text) 44%, var(--text) 60%, transparent 75%);
}

#page-recorder .rec-ripple-2::before {
  filter: blur(var(--space-2));
  opacity: 0.22;
}

.rec-ripple,
.rec-wave {
  position: absolute;
  top: 50%;
  left: 50%;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
}

#page-recorder .rec-ripple {
  background: linear-gradient(145deg, var(--surface-bright), var(--surface), var(--surface-sunken));
}

/* 공용 네온 토큰은 씬 lane이 선언한다. 밝은 능선과 홈 사이로 파랑·청록 오로라가 새어 나온다. */
#page-recorder .rec-ripple-1 {
  width: 100%;
  height: 100%;
  box-shadow: var(--shadow-round), inset 0 0 var(--space-4) var(--shade-light);
}

#page-recorder .rec-ripple-2 {
  width: 78%;
  height: 78%;
  box-shadow: var(--shadow-round);
}

#page-recorder .rec-ripple-3 {
  width: 62%;
  height: 62%;
  box-shadow: var(--shadow-inset);
}

/* 녹음 중에만 마이크에서 바깥으로 퍼지는 물결. */
#page-recorder .rec-wave {
  width: var(--recorder-mic-size);
  height: var(--recorder-mic-size);
  background: var(--recorder-neon);
  mask-image: radial-gradient(circle, transparent 58%, var(--text) 68%, transparent 76%);
  filter: blur(var(--space-1));
  opacity: 0;
}

#page-recorder[data-status='recording'] .rec-wave {
  animation: rec-wave var(--recorder-wave-duration) ease-out infinite;
}

#page-recorder[data-status='recording'] .rec-wave-late {
  animation-delay: calc(var(--recorder-wave-duration) / -2);
}

#page-recorder[data-status='recording'] .rec-pad::before,
#page-recorder[data-status='recording'] .rec-ripple-2::before {
  animation: recorder-aurora var(--recorder-aurora-duration) linear infinite;
}

#page-recorder[data-status='recording'] .rec-pad::before {
  opacity: 0.65;
}

#page-recorder[data-status='recording'] .rec-ripple-2::before {
  opacity: 0.5;
}

@keyframes recorder-aurora {
  from { transform: scale(1.15) rotate(0deg); }
  to { transform: scale(1.15) rotate(360deg); }
}

@keyframes rec-wave {
  from {
    opacity: 0.6;
    transform: translate(-50%, -50%) scale(1);
  }
  to {
    opacity: 0;
    transform: translate(-50%, -50%) scale(1.9);
  }
}

#page-recorder .rec-mic {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: var(--recorder-mic-size);
  height: var(--recorder-mic-size);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--surface-bright);
  box-shadow: var(--shadow-round);
  color: var(--muted);
  font: inherit;
  cursor: pointer;
  transition: box-shadow 0.15s ease-out, color 0.12s ease-out, transform 0.1s ease;
}

#page-recorder .rec-mic:active:not(:disabled) {
  box-shadow: var(--shadow-inset);
  transform: scale(0.97);
}

.rec-mic:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

#page-recorder .rec-mic:disabled {
  background: var(--surface-sunken);
  box-shadow: var(--shadow-inset-sm);
  cursor: default;
}

.rec-icon {
  display: none;
  width: 30px;
  height: 30px;
}

.rec-mic[data-icon='mic'] .rec-icon-mic,
.rec-mic[data-icon='stop'] .rec-icon-stop,
.rec-mic[data-icon='redo'] .rec-icon-redo,
.rec-mic[data-icon='check'] .rec-icon-check,
.rec-mic[data-icon='lock'] .rec-icon-lock {
  display: block;
}

.rec-mic-label {
  font-size: 0.72rem;
  font-weight: 500;
  line-height: 1.2;
}

/* 녹음 중: 정지 아이콘 + 위험 색 + "정지" 문구. 녹음본 있음: 다시 녹음 아이콘 + 청록 문구. */
#page-recorder .rec-mic[data-icon='stop'] {
  color: var(--danger-ink);
  box-shadow: var(--shadow-round);
}

.rec-mic[data-icon='stop'] .rec-icon-stop {
  color: var(--danger);
}

.rec-mic[data-icon='redo'],
.rec-mic[data-icon='check'] {
  color: var(--accent-ink);
}

.recorder-hint {
  min-height: 1.5em;
  max-width: 30ch;
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
  text-align: center;
  word-break: keep-all;
  font-variant-numeric: tabular-nums;
}

#page-recorder[data-status='recording'] .recorder-hint {
  color: var(--danger-ink);
}

#page-recorder[data-status='insecure'] .recorder-hint,
#page-recorder[data-status='unsupported'] .recorder-hint {
  padding: 8px 12px 8px 14px;
  border-left: 3px solid var(--danger);
  border-radius: var(--radius-sm);
  background: var(--danger-soft);
  color: var(--text);
  text-align: left;
}

.recorder-take {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.recorder-take-row {
  display: flex;
  align-items: stretch;
  gap: var(--space-3);
}

.take-slot {
  flex: 1;
  min-width: 0;
  min-height: 48px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 6px 14px;
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-inset);
}

.take-label {
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 500;
}

.take-info {
  color: var(--muted);
  font-size: 0.875rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

#page-recorder[data-status='ready'] .take-info,
#page-recorder[data-status='uploading'] .take-info {
  color: var(--text);
}

#page-recorder[data-status='recording'] .take-info {
  color: var(--danger-ink);
}

.recorder-upload {
  flex: none;
  min-width: 116px;
  min-height: 48px;
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
  color: var(--accent-ink);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: box-shadow 0.15s ease-out, transform 0.1s ease;
}

.recorder-upload:active:not(:disabled) {
  box-shadow: var(--shadow-inset);
  transform: scale(0.98);
}

.recorder-upload:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

.recorder-upload:disabled {
  background: var(--surface-sunken);
  box-shadow: none;
  color: var(--muted);
  cursor: default;
}

.upload-progress {
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--surface-sunken);
  box-shadow: var(--shadow-inset-sm);
  overflow: hidden;
}

.upload-progress[hidden] {
  display: none;
}

.upload-progress span {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  transform: scaleX(var(--upload-progress, 0));
  transform-origin: left center;
  transition: transform 0.2s ease-out;
}

.recorder-message {
  min-height: 1.45em;
  color: var(--muted);
  font-size: 0.8125rem;
  line-height: 1.45;
  word-break: keep-all;
}

.recorder-message[data-kind='error'] {
  color: var(--danger-ink);
}

.recorder-message[data-kind='done'] {
  color: var(--accent-ink);
  font-weight: 500;
}

.recorder-message[data-kind='done']::before {
  content: '✓ ';
}

/* 소리 채집 시간이 아니면 레코더 레일 항목이 꺼진 면 + 흐린 아이콘으로 바뀐다(탭은 그대로 동작). */
.rail-item.rail-item-disabled .rail-icon {
  background: var(--surface-sunken);
  box-shadow: var(--shadow-inset-sm);
  color: var(--faint);
}

/* ── 하단 플레이 바 ─────────────────────────────── */

.playbar {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: calc(var(--playbar-h) + env(safe-area-inset-bottom, 0px));
  padding: var(--space-3) calc(var(--space-4) + var(--safe-right)) calc(var(--space-3) + env(safe-area-inset-bottom, 0px)) calc(var(--space-4) + var(--safe-left));
  background: var(--surface);
  box-shadow: 0 -6px 16px var(--shade-dark);
  /* 경계선 위 seek 포인트가 레일(30)·카드 창 스크림(31)에 가리지 않도록 그 위, 채팅 말풍선(35) 아래에 둔다. */
  z-index: 33;
}

/* 트랙 썸네일 자리 */

.playbar-thumb {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: var(--shadow-inset-sm);
  color: var(--accent-ink);
}

.playbar-thumb svg {
  display: block;
  width: 22px;
  height: 22px;
}

.playbar-info {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
}

.playbar-title {
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.playbar-artist {
  font-size: 0.75rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.playbar-context {
  color: var(--accent-ink);
  font-size: 0.75rem;
  line-height: 1.4;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.playbar-context[hidden] {
  display: none;
}

.playbar-btn {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  /* 디자이너 사운드바 메모: 누르기 전에는 하늘색, 누른 뒤(재생 중)에는 회색. 아이콘 모양은 그대로다.
     모든 재생바 소유자(라이브·설명·녹음본)가 같은 .playing 규칙을 쓴다. */
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: var(--shadow-raised-sm), 0 0 18px var(--accent-glow);
  transition: background-color 0.12s ease-out, color 0.12s ease-out, box-shadow 0.15s ease-out, transform 0.1s ease;
  /* seek 터치 영역(z 1)과 겹치는 자리에서는 재생 버튼이 이긴다. */
  position: relative;
  z-index: 2;
}

/* 재생 중: 회색 채움 + 일시정지 아이콘, 빛 없음 */
.playbar-btn.playing {
  background: var(--neutral-fill);
  color: var(--text);
  box-shadow: var(--shadow-raised-sm);
}

/* 눌러도 아무 일도 없는 때(카드를 열기 전 설명, 녹음 대기·녹음 중, 라이브 시간 아님)는 연한 하늘색으로 낮춘다. */
.playbar-btn:disabled {
  background: var(--accent-border);
  color: var(--accent-ink);
  box-shadow: none;
  cursor: default;
}

.playbar-btn:active {
  box-shadow: var(--shadow-inset);
  transform: scale(0.96);
}

.playbar-btn svg {
  display: block;
  width: 22px;
  height: 22px;
}

.playbar-btn .icon-pause {
  display: none;
}

.playbar-btn.playing .icon-pause {
  display: block;
}

.playbar-btn.playing .icon-play {
  display: none;
}

/* ── 라이브 페이지: GPS 배너 + 사이버 지도 ──────── */

#page-live {
  height: 100%;
  min-height: 0;
  justify-content: flex-start;
  align-items: stretch;
  padding-bottom: var(--live-bottom-clearance, calc(var(--space-8) * 2));
  overflow: hidden;
}

#page-live .page-head,
#page-live .live-guide,
#page-live .live-info-column {
  flex: none;
}

.live-map-column {
  flex: 1;
  min-height: 0;
  align-items: stretch;
  gap: 0;
}

.live-signal-board {
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
  text-align: left;
}

/* 보이는 상태가 하나도 없으면 보드와 정보 열을 레이아웃에서 뺀다(디버깅 요소는 DOM에 남는다). */
.live-signal-board:not(:has(> :not([hidden]))),
.live-info-column:not(:has(> :not([hidden]):not(.live-signal-board), > .live-signal-board > :not([hidden]))) {
  display: none;
}

.live-transport-status {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}

/* ── 라이브 안내(시퀀스 live 모드) ──────────────── */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.live-guide {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-4);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
  text-align: center;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.live-guide-text {
  color: var(--text);
  font-size: 1.05rem;
  font-weight: 400;
  line-height: 1.6;
}

.live-guide-sub {
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1.5;
}

.live-guide-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--text);
  font-size: 1rem;
  line-height: 1.7;
}

/* 글리치: 원문 위에 청록·위험색 사본 두 장을 가로로 어긋나게 잘라 짧게 겹친다. 글자는 그대로 읽힌다. */
.glitch-text {
  position: relative;
  display: inline-block;
}

.glitch-text::before,
.glitch-text::after {
  content: attr(data-text);
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}

.glitch-text.glitching::before {
  opacity: 0.75;
  color: var(--accent);
  clip-path: inset(10% 0 55% 0);
  transform: translateX(-3px);
  animation: glitch-slice 0.18s steps(2, end) both;
}

.glitch-text.glitching::after {
  opacity: 0.6;
  color: var(--danger);
  clip-path: inset(60% 0 8% 0);
  transform: translateX(3px);
  animation: glitch-slice 0.18s steps(2, end) reverse both;
}

.glitch-text.glitching {
  text-shadow: -1px 0 var(--accent-glow);
}

@keyframes glitch-slice {
  0% { clip-path: inset(10% 0 55% 0); }
  50% { clip-path: inset(45% 0 20% 0); }
  100% { clip-path: inset(70% 0 5% 0); }
}

/* off 모드: 라이브 페이지는 짧은 안내만 남긴다. */
#page-live[data-mode="off"] .live-info-column,
#page-live[data-mode="off"] .live-map-column {
  display: none;
}

#page-live[data-mode="off"] .live-guide {
  background: var(--surface-sunken);
  box-shadow: var(--shadow-inset);
}

/* ── 크레딧 ─────────────────────────────────────────── */

/* 레일 하단 작은 링크(지금은 숨김). 레일 아이콘 항목이 아니라 멜로디 해금에 끼지 않는다. */
.rail-credits {
  display: none;
  flex: none;
  align-self: flex-start;
  min-height: 44px;
  margin-top: calc(var(--space-4) * -1);
  padding: 0 var(--space-3);
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.rail-credits[aria-current="page"] {
  color: var(--accent-ink);
}

.rail-credits:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}

#page-credits {
  justify-content: flex-start;
}

.credits {
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  text-align: left;
}

.credits-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-raised);
}

.credits-card h3 {
  color: var(--accent-ink);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.28em;
}

.credits-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
}

.credits-list div {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-inset-sm);
}

.credits-list dt {
  color: var(--text);
  font-size: 0.875rem;
  font-weight: 500;
}

.credits-list dd {
  margin: 0;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.55;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.credits-list a {
  color: var(--accent-ink);
  overflow-wrap: anywhere;
}

.signal-status {
  min-width: 0;
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--muted);
  font-size: 0.75rem;
  line-height: 1.4;
  word-break: keep-all;
}

.signal-dot {
  flex: none;
  width: var(--space-2);
  height: var(--space-2);
  border: 1px solid currentColor;
  border-radius: var(--radius-full);
  background: transparent;
}

.signal-status[data-kind="connected"],
.signal-status[data-kind="playing"] {
  color: var(--accent-ink);
}

.signal-status[data-kind="connected"] .signal-dot,
.signal-status[data-kind="playing"] .signal-dot {
  background: var(--accent);
}

.signal-status[data-kind="connecting"],
.signal-status[data-kind="reconnecting"],
.signal-status[data-kind="degraded"] {
  color: var(--warning-ink);
}

.signal-status[data-kind="connecting"] .signal-dot,
.signal-status[data-kind="reconnecting"] .signal-dot,
.signal-status[data-kind="degraded"] .signal-dot {
  background: var(--warning);
}

.signal-status[data-kind="error"] {
  color: var(--danger-ink);
}

.signal-status[data-kind="error"] .signal-dot {
  background: var(--danger);
}

/* 지도 stage 안 상단에 뜨는 알림 더미(#live-map-notice, #gps-banner). 지도 조작을 막지 않고 서로 세로로 쌓는다. */
.live-map-alerts {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  right: var(--space-3);
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  pointer-events: none;
}

.gps-banner {
  width: max-content;
  max-width: min(100%, 480px);
  min-height: 44px;
  display: flex;
  align-items: center;
  padding: 10px 16px;
  border-left: 3px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--surface-bright);
  box-shadow: var(--shadow-float);
  color: var(--text);
  font-size: 0.875rem;
  line-height: 1.5;
  text-align: left;
  word-break: keep-all;
}

/* 대기·요청·정상 추적은 알릴 것이 없으므로 보이지 않는다. */
.gps-banner[data-kind="idle"],
.gps-banner[data-kind="requesting"],
.gps-banner[data-kind="tracking"] {
  display: none;
}

/* 의미 색은 반투명 soft 변수를 불투명 표면 위에 겹쳐 지도 위에서도 글을 읽게 한다. */
.gps-banner[data-kind="degraded"],
.gps-banner[data-kind="stale"] {
  border-color: var(--warning);
  background: linear-gradient(var(--warning-soft), var(--warning-soft)), var(--surface-bright);
}

.gps-banner[data-kind="denied"],
.gps-banner[data-kind="unavailable"] {
  border-color: var(--danger);
  background: linear-gradient(var(--danger-soft), var(--danger-soft)), var(--surface-bright);
}

.live-stage {
  width: 100%;
  min-height: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
}

.live-view {
  width: 100%;
  min-height: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
}

.live-view[hidden] {
  display: none;
}

.live-map-frame {
  min-height: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: var(--space-3);
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-inset-deep);
}

.live-map-stage {
  position: relative;
  min-height: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
}

.live-map-canvas {
  width: 100%;
  min-height: 0;
  flex: 1;
  border-radius: var(--radius-xs);
  overflow: hidden;
  background: var(--map-void);
  box-shadow: var(--shadow-inset-sm);
  touch-action: none;
}

.live-map-canvas:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
}

/* 셀의 img max-width 규칙이 NAVER 타일과 옛 지도 타일을 줄이지 않게 한다. */
.live-map-canvas img,
.live-map-canvas .old-map-overlay img {
  max-width: none;
}

.live-locate {
  position: absolute;
  right: var(--space-3);
  bottom: var(--space-3);
  z-index: 10;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-round);
  color: var(--accent-ink);
  transition: box-shadow 0.12s ease-out, background 0.12s ease-out;
}

.live-locate svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
}

.live-locate svg circle:first-child {
  fill: currentColor;
  stroke: none;
}

.live-locate:active {
  background: var(--surface-sunken);
  box-shadow: var(--shadow-inset);
}

.live-locate:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

.live-map-notice {
  width: max-content;
  max-width: 100%;
  margin: 0;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-full);
  background: var(--surface-bright);
  box-shadow: var(--shadow-float);
  color: var(--text);
  font-size: 0.8rem;
  line-height: 1.45;
  text-align: center;
  word-break: keep-all;
}

.live-map-notice[hidden] {
  display: none;
}

/* 내 위치: 흰 핵 + 테마 잉크 테두리 + 옅은 빛(DESIGN §8 지도 프레임). 정확도 원은 SDK Circle로 은은하게 그린다. */
.live-me {
  position: relative;
  display: block;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-full);
  background: var(--accent-glow);
}

.live-me-dot {
  position: absolute;
  inset: 4px;
  border: 3px solid var(--accent-ink);
  border-radius: var(--radius-full);
  background: var(--shade-light);
  box-shadow: var(--shadow-micro);
}

.live-map-fallback {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: var(--map-void);
  container-type: size;
}

.live-map-fallback-sheet {
  position: relative;
  width: min(100cqw, 100cqh);
}

.live-map-fallback-sheet img {
  display: block;
  width: 100%;
  height: 100%;
}

.live-map-fallback .live-me-fallback {
  position: absolute;
  transform: translate(-50%, -50%);
}

.live-map-fallback .live-me-fallback[hidden] {
  display: none;
}

/* 개요도 venue 점: divIcon의 자식들을 앵커(좌표점) 중심으로 겹쳐 놓는다. */

.live-venue-dot,
.live-node {
  position: relative;
}

.live-venue-dot .venue-dot-halo {
  position: absolute;
  top: 0;
  left: 0;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--accent-soft);
  border: 1px solid var(--accent-stroke);
  transform: translate(-50%, -50%);
}

.live-venue-dot .venue-dot-core {
  position: absolute;
  top: 0;
  left: 0;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--accent);
  transform: translate(-50%, -50%);
}

.live-venue-dot .venue-dot-label {
  position: absolute;
  top: 10px;
  left: 0;
  transform: translateX(-50%);
  color: var(--text);
  font-size: 0.8rem;
  font-weight: 500;
  white-space: nowrap;
  text-shadow: 0 0 3px var(--label-halo), 0 0 6px var(--label-halo);
}

.live-venue-dot.current .venue-dot-core {
  background: var(--shade-light);
  border: 2px solid var(--accent-ink);
}

.live-venue-dot.current .venue-dot-halo {
  background: var(--accent-glow);
}

/* venue 탭/뒤로가기/재시도: 44px 터치 타겟 */

.live-venue-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.live-venue-tab {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 16px;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
  color: var(--text);
  font-size: 0.9rem;
  font-weight: 500;
  transition: box-shadow 0.15s ease-out, background 0.2s ease, color 0.2s ease;
}

.live-venue-tab:hover {
  color: var(--accent-ink);
}

.live-venue-tab[aria-pressed="true"] {
  background: var(--accent-soft);
  box-shadow: var(--shadow-inset);
  color: var(--accent-ink);
}

.live-local-head {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
}

.live-back {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
  font-size: 0.875rem;
  font-weight: 500;
}

.live-back svg {
  display: block;
  width: 18px;
  height: 18px;
}

.live-venue-name {
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: -0.01em;
}

.live-map-status {
  width: 100%;
  max-width: 480px;
  min-height: 20px;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.5;
  text-align: left;
  word-break: keep-all;
}

.live-map-status:empty {
  display: none;
}

.live-map-status.error {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  color: var(--danger-ink);
}

.live-retry {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 16px;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
  color: var(--text);
  font-size: 0.875rem;
  font-weight: 500;
}

.live-retry:hover {
  color: var(--accent-ink);
}

.live-retry:active {
  box-shadow: var(--shadow-inset);
}

@media (min-width: 960px) {
  .app:not(.admin-active) .pages {
    padding-inline: var(--space-6);
  }

  .app:not(.admin-active) .page {
    width: 100%;
    max-width: var(--workspace-max);
    margin-inline: auto;
  }

  /* 데스크톱에서는 씬 페이지 폭을 읽기 좋은 너비로 묶는다(관객은 모바일 전용). */
  .app:not(.admin-active) #page-intro .scene > * {
    width: 100%;
    max-width: 44rem;
  }

  /* 레코더: 제목은 두 열에 걸치고, 왼쪽은 채집 안내 카드, 오른쪽은 마이크와 녹음본·업로드다. */
  .app:not(.admin-active) #page-recorder.active {
    display: grid;
    grid-template-columns: minmax(var(--workspace-panel), 1fr) minmax(var(--workspace-panel), 0.8fr);
    grid-template-areas:
      "head head"
      "card stage"
      "card take";
    column-gap: var(--space-8);
    row-gap: var(--space-4);
    align-content: center;
    align-items: start;
  }

  .app:not(.admin-active) #page-recorder .page-head { grid-area: head; width: 100%; }
  .app:not(.admin-active) #page-recorder .recorder-card { grid-area: card; max-width: none; }
  .app:not(.admin-active) #page-recorder .recorder-stage { grid-area: stage; }
  .app:not(.admin-active) #page-recorder .recorder-take { grid-area: take; max-width: none; }

}

/* ── 좁은 화면 ─────────────────────────────────── */

@media (max-width: 360px) {
  .playbar-seek {
    left: calc(var(--space-3) + var(--safe-left));
    right: calc(var(--space-3) + var(--safe-right));
  }

  .pages {
    padding: var(--space-4) calc(var(--space-3) + var(--safe-right)) var(--space-4) var(--space-3);
  }

  .page {
    gap: var(--space-3);
  }

  .live-transport-status {
    align-items: flex-start;
    flex-direction: column;
  }

  .playbar {
    gap: var(--space-2);
    padding-inline-start: calc(var(--space-3) + var(--safe-left));
    padding-inline-end: calc(var(--space-3) + var(--safe-right));
  }
}

@media (max-height: 430px) and (orientation: landscape) {
  .pages {
    padding-top: var(--space-3);
    padding-bottom: var(--space-3);
  }

  #page-live {
    gap: var(--space-2);
  }

}

@media (prefers-reduced-motion: reduce) {
  .page.active,
  .rail-tip {
    animation: none;
  }

  .rail,
  .rail-icon,
  .playbar-btn,
  .live-venue-tab,
  .live-retry,
  .scene-step,
  .scene-card,
  .sheet-audio,
  .scene-dot,
  #page-recorder .rec-mic,
  .recorder-upload,
  .upload-progress span {
    transition: none;
  }

  #page-recorder[data-status='recording'] .rec-wave,
  #page-recorder[data-status='recording'] .rec-pad::before,
  #page-recorder[data-status='recording'] .rec-ripple-2::before {
    animation: none;
  }

  .glitch-text::before,
  .glitch-text::after {
    display: none;
  }
}

/* 고대비 선호: 그림자만으로 보이던 형태에 실선 경계를 더한다. */
@media (prefers-contrast: more) {
  .rail-icon,
  .scene-step,
  .scene-card,
  .scene-sheet,
  .sheet-guide,
  .sheet-audio,
  .sheet-close,
  .playbar-btn,
  .live-signal-board,
  .gps-banner,
  .live-map-frame,
  .live-venue-tab,
  .live-retry,
  .live-back,
  .recorder-card,
  .take-slot,
  .recorder-upload,
  .rec-mic,
  .live-guide,
  .credits-card {
    border: 1px solid var(--faint);
  }
}

/* .rail-item의 display:flex가 UA hidden 규칙을 덮어쓴다. */
.rail-item[hidden] {
  display: none;
}

/* 설명은 본문마다 세로 스크롤, 이동 버튼과 플레이 바는 고정한다. */
.app.explanation-active .pages {
  overflow: hidden;
}

.app.explanation-active {
  --playbar-h: 68px;
}

.app:not(.admin-active) #page-intro.active {
  display: flex;
  height: 100%;
  min-height: 0;
  gap: var(--space-2);
  align-items: stretch;
}

.scene-deck {
  flex: 1;
  min-height: 0;
  overflow: hidden;
  position: relative;
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
}

.scene-track {
  display: flex;
  height: 100%;
  min-height: 0;
  will-change: transform;
}

.scene-track {
  gap: 28px;
}

.scene-track > .scene {
  flex: 0 0 100%;
  width: 100%;
  min-width: 100%;
}

/* 씬 페이지: 굵은 시퀀스 제목은 위에 고정되고(이전 페이지 스와이프 영역), 그 아래 본문만 세로로 스크롤한다. */
.scene {
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 100%;
  min-height: 0;
  word-break: keep-all;
}

.scene-head,
.scene-body {
  width: 100%;
}

.scene-head {
  flex: none;
  padding: var(--space-5) var(--space-5) var(--space-3);
}

.scene-title {
  color: var(--text);
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.01em;
  overflow-wrap: break-word;
}

.scene-body {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  overflow-y: auto;
  overscroll-behavior-y: contain;
  scrollbar-width: none;
  padding: var(--space-2) var(--space-5) calc(var(--space-6) + var(--space-3));
}

.scene-body::-webkit-scrollbar {
  width: 0;
  height: 0;
}

.scene-body > * {
  flex-shrink: 0;
}

/* ── 씬 페이지: 시퀀스 제목, 번호 붙은 가로형 소제목 카드, 내용 창, 안내 창(DESIGN.md §8) ── */

#page-intro {
  position: relative;
  text-align: left;
  /* 씬 전용 토큰: 데이터(namso·mia) 카드의 회색 바탕, 하늘색 안쪽 테두리 선과 그 안쪽 간격. */
  --scene-card-gray: color-mix(in srgb, var(--surface-sunken) 55%, var(--shade-dark));
  --scene-card-line: var(--accent);
  --scene-card-inset: 5px;
}

/* INTRO(#1): 제목 'INTRO' 아래 로고를 여백 상자 없이 꽉 차게, 그 아래 한 줄 소개. */
.scene-intro-logo {
  display: block;
  width: min(100%, 240px);
  height: auto;
}

.scene-intro-line {
  color: var(--text);
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.5;
}

.scene--intro .scene-cards {
  margin-top: var(--space-4);
}

.scene-cards {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.scene-cards-item {
  display: flex;
  min-width: 0;
}

/* 소제목 카드: 화면 폭의 가로로 긴 둥근 직사각형, 하늘색 실선 안쪽 테두리.
   ::before가 테두리 선, .scene-card-neon이 읽지 않은 동안 그 선을 따라 번지는 오로라 네온이다. */
.scene-card {
  position: relative;
  width: 100%;
  min-height: 64px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
  color: var(--text);
  text-align: left;
  transition: box-shadow 0.15s ease-out, color 0.12s ease-out;
}

.scene-card::before {
  content: '';
  position: absolute;
  inset: var(--scene-card-inset);
  border: 1.5px solid var(--scene-card-line);
  border-radius: calc(var(--radius-lg) - var(--scene-card-inset));
  pointer-events: none;
}

/* 오로라 네온: 테두리 선 자리에 --neon-aurora 고리(두 겹)를 두고 번지게 흐린다.
   흐림(filter)은 마스크보다 먼저 적용되므로, 마스크한 고리는 자식 가상 요소에 두고 흐림은 이 요소에 건다.
   그라디언트는 천천히 옆으로 흘러 색이 테두리를 따라 돈다. */
.scene-card-neon {
  position: absolute;
  inset: calc(var(--scene-card-inset) - 2px);
  border-radius: calc(var(--radius-lg) - var(--scene-card-inset) + 2px);
  pointer-events: none;
  filter: blur(3px);
}

.scene-card-neon::before,
.scene-card-neon::after {
  content: '';
  position: absolute;
  border-radius: inherit;
  background: var(--neon-aurora);
  background-size: 300% 100%;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: scene-aurora 9s ease-in-out infinite alternate;
}

/* 안쪽 고리: 선 위에 진하게 */
.scene-card-neon::before {
  inset: 0;
  padding: 4px;
}

/* 바깥 고리: 넓고 옛게 퍼지는 빛 */
.scene-card-neon::after {
  inset: -4px;
  padding: 6px;
  border-radius: calc(var(--radius-lg) - var(--scene-card-inset) + 6px);
  opacity: 0.45;
}

.scene-card--read .scene-card-neon {
  display: none;
}

/* namso·mia 데이터 카드: 회색 바탕. 읽기 전에는 같은 네온, 읽으면 빛만 사라진 회색. */
.scene-card--data {
  background: var(--scene-card-gray);
}

@keyframes scene-aurora {
  from { background-position: 0% 50%; }
  to { background-position: 100% 50%; }
}

@media (hover: hover) and (pointer: fine) {
  .scene-card:hover {
    color: var(--accent-ink);
  }
}

.scene-card:active {
  box-shadow: var(--shadow-inset);
  color: var(--accent-ink);
}

/* 둘째 줄: '번호. 소제목'(길면 셋째 줄까지)과 오른쪽 매체 아이콘. */
.scene-card-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  width: 100%;
}

.scene-card-title {
  flex: 1;
  min-width: 0;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.45;
  word-break: keep-all;
  overflow-wrap: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.scene-card-number {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.scene-card-media {
  flex: none;
  display: flex;
  gap: 6px;
  padding-top: 2px;
  color: var(--muted);
}

.scene-card-icon {
  width: 16px;
  height: 16px;
}

.scene-card-source,
.sheet-source {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px 3px 7px;
  border-radius: var(--radius-full);
  background: var(--surface-sunken);
  box-shadow: var(--shadow-inset-sm);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.02em;
  white-space: nowrap;
  max-width: 100%;
}

.scene-card-source-icon,
.sheet-source-icon {
  width: 12px;
  height: 12px;
  color: var(--muted);
}

.sheet-source {
  align-self: flex-start;
}

.scene-error {
  padding: var(--space-6) var(--space-5);
  color: var(--danger-ink);
  font-size: 0.875rem;
}

/* 내용 창 닫기: 옅은 회색으로 시선을 끌지 않는다. 누르는 영역은 44px 그대로다. */
.sheet-close {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--faint);
  transition: background-color 0.15s ease-out, color 0.12s ease-out;
}

.sheet-close svg {
  width: 20px;
  height: 20px;
}

.sheet-close:active {
  background: var(--surface-sunken);
  color: var(--muted);
}

/* 내용 창: 레일까지 덮는 화면 폭 창. 위는 시퀀스 제목 바로 아래, 아래는 레일 채팅 버튼·재생바 바로 위까지다
   (scene-pages.js가 열 때 재서 --sheet-top/--sheet-bottom으로 넘긴다). 스크림은 페이지 여백·레일까지 화면 전체를 덮고(레일 30 위), 재생바(33)는 음성 조작을 위해 그 위에 남는다. */
.scene-sheet-scrim {
  position: fixed;
  inset: 0;
  z-index: 31;
  background: rgba(31, 38, 52, 0.46);
  animation: sheet-scrim-in 0.16s ease-out both;
}

.scene-sheet-scrim[hidden] {
  display: none;
}

/* page-in의 끝 transform이 fill로 남으면 설명 페이지가 fixed 스크림의 기준·쌓임 맥락이 되므로 들어올 때만 적용한다. */
#page-intro.active {
  animation-fill-mode: backwards;
}

.scene-sheet {
  position: fixed;
  top: var(--sheet-top, calc(env(safe-area-inset-top, 0px) + 88px));
  bottom: var(--sheet-bottom, calc(var(--playbar-h) + 72px));
  left: calc(var(--space-3) + var(--safe-left));
  right: calc(var(--space-3) + var(--safe-right));
  z-index: 32;
  max-width: 44rem;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--bg);
  box-shadow: var(--shadow-float);
  animation: sheet-in 0.18s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}

.scene-sheet[hidden] {
  display: none;
}

@keyframes sheet-in {
  from {
    opacity: 0;
    transform: translateY(12px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes sheet-scrim-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.sheet-head {
  flex: none;
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-3) var(--space-2) var(--space-5);
}

.sheet-title {
  flex: 1;
  min-width: 0;
  padding-top: 9px;
  color: var(--text);
  font-size: 1.125rem;
  font-weight: 700;
  line-height: 1.45;
  word-break: keep-all;
  overflow-wrap: break-word;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.sheet-body {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
}

/* 창 안 장 넘김: 가로는 scenes.js 제스처가, 세로는 각 장의 스크롤이 맡는다. */
.sheet-viewport {
  height: 100%;
  overflow: hidden;
  touch-action: pan-y;
  -webkit-user-select: none;
  user-select: none;
}

.sheet-track {
  display: flex;
  gap: var(--space-4);
  height: 100%;
  will-change: transform;
}

.sheet-page {
  flex: 0 0 100%;
  width: 100%;
  min-width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-3) var(--space-5) var(--space-6);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}

.sheet-page::-webkit-scrollbar {
  display: none;
}

.sheet-page > * {
  flex-shrink: 0;
}

/* 얇은 스크롤 표시: 브라우저 기본 막대를 숨기고, 스크롤하는 동안만 잠깐 보인다. */
.sheet-scrollbar {
  position: absolute;
  top: var(--space-2);
  right: 4px;
  bottom: var(--space-2);
  width: 3px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease-out;
}

.sheet-scrollbar.is-visible {
  opacity: 1;
  transition-duration: 0.1s;
}

.sheet-scrollbar-thumb {
  display: block;
  width: 100%;
  border-radius: var(--radius-full);
  background: var(--muted);
  opacity: 0.55;
}

/* 창 안 장 수: 작은 점. 한 장이면 숨긴다. */
.sheet-dots {
  flex: none;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 6px;
  padding: var(--space-1) 0 var(--space-4);
}

.sheet-dots[hidden] {
  display: none;
}

.sheet-dot {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-full);
  background: var(--surface-sunken);
  box-shadow: var(--shadow-inset-sm);
  transition: width 0.2s ease, background-color 0.2s ease;
}

.sheet-dot[aria-current='true'] {
  width: 16px;
  background: var(--accent);
  box-shadow: none;
}

.sheet-text {
  max-width: 34em;
  color: var(--text);
  font-size: 1rem;
  line-height: 1.8;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.sheet-text p + p {
  margin-top: 1em;
}

.sheet-audio-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* 오디오 버튼: 음성 안내(헤드폰, 알약, 청록)와 구술 채록(목소리 마이크, 둥근 사각, 보라 + 태그)을 모양·색·문구로 나눈다. */
.sheet-audio {
  width: 100%;
  min-height: 56px;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4) var(--space-2) var(--space-2);
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
  color: var(--text);
  text-align: left;
  transition: box-shadow 0.15s ease-out, background-color 0.15s ease-out, color 0.12s ease-out;
}

.sheet-audio-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-inset-sm);
  color: var(--accent-ink);
}

.sheet-audio-icon svg {
  grid-area: 1 / 1;
  width: 20px;
  height: 20px;
}

.sheet-audio-active,
.sheet-audio.is-playing .sheet-audio-idle {
  display: none;
}

.sheet-audio.is-playing .sheet-audio-active {
  display: block;
}

.sheet-audio-text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

.sheet-audio-label {
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.4;
}

.sheet-audio-time {
  flex: none;
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.sheet-audio:active {
  box-shadow: var(--shadow-inset);
}

.sheet-audio.is-current:not(.is-playing) {
  border-color: var(--accent-border);
}

.sheet-audio--narration.is-playing {
  background: var(--accent);
  box-shadow: var(--shadow-raised-sm), 0 0 0 4px var(--accent-glow);
  color: var(--on-accent);
}

.sheet-audio--narration.is-playing .sheet-audio-icon {
  background: rgba(255, 255, 255, 0.35);
  box-shadow: none;
  color: var(--on-accent);
}

.sheet-audio--narration.is-playing .sheet-audio-time {
  color: var(--on-accent);
}

.sheet-audio--oral {
  border-radius: var(--radius);
}

.sheet-audio--oral .sheet-audio-icon {
  border-radius: var(--radius-sm);
  background: var(--oral-soft);
  color: var(--oral-ink);
}

.sheet-audio--oral.is-current:not(.is-playing) {
  border-color: var(--oral-border);
}

.sheet-audio-tag {
  padding: 1px 8px;
  border-radius: var(--radius-full);
  background: var(--oral-soft);
  color: var(--oral-ink);
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.04em;
}

.sheet-audio--oral.is-playing {
  background: var(--oral-ink);
  box-shadow: var(--shadow-raised-sm), 0 0 0 4px var(--oral-border);
  color: var(--on-oral);
}

.sheet-audio--oral.is-playing .sheet-audio-icon {
  background: rgba(255, 255, 255, 0.18);
  box-shadow: none;
  color: var(--on-oral);
}

/* 작은 태그 글자는 반투명 면 위에서 AA에 못 미치므로 바탕 없이 외곽선만 둔다(흰 글자 6.6:1). */
.sheet-audio--oral.is-playing .sheet-audio-tag {
  background: transparent;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.6);
  color: var(--on-oral);
}

.sheet-audio--oral.is-playing .sheet-audio-time {
  color: var(--on-oral);
}

.sheet-image {
  position: relative;
  display: block;
  width: 100%;
  padding: var(--space-2);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
}

.sheet-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

.sheet-image-zoom {
  position: absolute;
  right: var(--space-4);
  bottom: var(--space-4);
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: var(--surface-bright);
  box-shadow: var(--shadow-micro);
  color: var(--text);
}

.sheet-image-zoom svg {
  width: 18px;
  height: 18px;
}

.image-viewer {
  width: 100vw;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--viewer-bg);
}

.image-viewer::backdrop {
  background: var(--viewer-bg);
}

.image-viewer img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  touch-action: pinch-zoom;
}

.image-viewer-close {
  position: absolute;
  top: calc(var(--space-3) + env(safe-area-inset-top, 0px));
  right: var(--space-3);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-full);
  background: var(--surface-bright);
  box-shadow: var(--shadow-micro);
  color: var(--text);
}

.image-viewer-close svg {
  width: 20px;
  height: 20px;
}

@media (max-width: 360px) {
  .scene-cards {
    gap: var(--space-3);
  }

  .scene-card {
    padding: var(--space-3) var(--space-4);
  }

  .sheet-page {
    padding-inline: var(--space-4);
  }

  .sheet-head {
    padding-left: var(--space-4);
  }
}

@media (prefers-reduced-motion: reduce) {
  .scene-sheet,
  .scene-sheet-scrim {
    animation: none;
  }

  /* 오로라는 흐르지 않고 고정된 그라디언트로 남는다. */
  .scene-card-neon::before,
  .scene-card-neon::after {
    animation: none;
  }

  .sheet-dot,
  .sheet-scrollbar {
    transition: none;
  }
}

/* 재생 섹션의 상단 경계 자체가 탐색 바다. 선은 경계처럼, 손잡이는 선 위에 얹는다. */
.playbar-seek {
  position: absolute;
  /* 터치 높이는 44px 그대로 두되, 위로는 13px만 내밀어 레일 채팅 버튼(경계 16px 위)을 가로채지 않는다.
     아래 패딩 16px로 트랙(2px)을 위에서 13~15px에 두어 재생 섹션 맨 윗경계에 정확히 앉힌다. */
  top: -13px;
  left: calc(var(--space-4) + var(--safe-left));
  right: calc(var(--space-4) + var(--safe-right));
  width: auto;
  height: 44px;
  box-sizing: border-box;
  margin: 0;
  padding: 0 0 16px;
  border: 0;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  touch-action: none;
  z-index: 1;
}

/* 트랙은 재생 섹션의 맨 윗경계에 정확히 놓는다. */
.playbar-seek::-webkit-slider-runnable-track {
  height: 2px;
  border-radius: 0;
  background: var(--shade-dark);
}

.playbar-seek::-moz-range-track {
  height: 2px;
  border-radius: 0;
  background: var(--shade-dark);
}

.playbar-seek::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 14px;
  height: 14px;
  margin-top: -6px;
  border: 2px solid var(--accent);
  border-radius: var(--radius-full);
  background: var(--surface-bright);
  box-shadow: var(--shadow-micro);
  opacity: 0;
  transition: opacity 0.18s ease;
}

.playbar-seek::-moz-range-thumb {
  width: 10px;
  height: 10px;
  border: 2px solid var(--accent);
  border-radius: var(--radius-full);
  background: var(--surface-bright);
  opacity: 0;
  transition: opacity 0.18s ease;
}

/* 비활성 시크바는 아래 재생 버튼의 터치를 가로채지 않는다. */
.playbar-seek:disabled {
  cursor: default;
  pointer-events: none;
}

/* 재생 중에는 경계선이 채워지고 손잡이가 선 위에 나타난다. */
.playbar[data-owner='tts'] .playbar-seek:not(:disabled)::-webkit-slider-runnable-track,
.playbar[data-owner='recorder'] .playbar-seek:not(:disabled)::-webkit-slider-runnable-track {
  background: linear-gradient(to right, var(--accent) var(--seek-fill, 0%), var(--shade-dark) var(--seek-fill, 0%));
}

.playbar[data-owner='tts'] .playbar-seek:not(:disabled)::-moz-range-track,
.playbar[data-owner='recorder'] .playbar-seek:not(:disabled)::-moz-range-track {
  background: linear-gradient(to right, var(--accent) var(--seek-fill, 0%), var(--shade-dark) var(--seek-fill, 0%));
}

/* 벤더 의사 요소를 한 규칙에 묶으면 브라우저가 규칙 전체를 버리므로 따로 쓴다. */
.playbar[data-owner='tts'] .playbar-seek:not(:disabled)::-webkit-slider-thumb,
.playbar[data-owner='recorder'] .playbar-seek:not(:disabled)::-webkit-slider-thumb {
  opacity: 1;
}

.playbar[data-owner='tts'] .playbar-seek:not(:disabled)::-moz-range-thumb,
.playbar[data-owner='recorder'] .playbar-seek:not(:disabled)::-moz-range-thumb {
  opacity: 1;
}

/* 녹음 중에는 경계선이 최대 60초 대비 경과를 위험 색으로 채운다(손잡이 없음, 조작 불가). */
.playbar.recording .playbar-seek::-webkit-slider-runnable-track {
  background: linear-gradient(to right, var(--danger) var(--seek-fill, 0%), var(--shade-dark) var(--seek-fill, 0%));
}

.playbar.recording .playbar-seek::-moz-range-track {
  background: linear-gradient(to right, var(--danger) var(--seek-fill, 0%), var(--shade-dark) var(--seek-fill, 0%));
}

/* ── 운영 큐 강제 이동 · 시퀀스 제목 강조 · 참여자 이동 버튼 ───────────── */

/* 큐가 관객을 옮길 때의 빠른 전환. transform을 쓰면 페이지 안 고정 요소(카드 창)의 기준이 바뀌므로 opacity만 쓴다. */
.pages.cue-arrive {
  animation: cue-arrive 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

@keyframes cue-arrive {
  from { opacity: 0.15; }
  to { opacity: 1; }
}

.scene-action {
  align-self: stretch;
  min-height: 56px;
  padding: 0 var(--space-5);
  border: 0;
  border-radius: var(--radius-full);
  background: var(--surface);
  box-shadow: var(--shadow-raised-sm);
  color: var(--accent-ink);
  font: inherit;
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
  transition: box-shadow 0.15s ease-out, transform 0.1s ease;
}

.scene-action:active {
  box-shadow: var(--shadow-inset);
  transform: scale(0.98);
}

.scene-action:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 3px;
}

@media (prefers-contrast: more) {
  .scene-action {
    border: 1px solid var(--faint);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pages.cue-arrive {
    animation: none;
  }

  .scene-action {
    transition: none;
  }
}
