/* 공통 스타일. 치지직 느낌을 참고한 다크 + 그린 포인트 컬러 테마.
   (실제 치지직 사이트에 자동으로 접속해서 정확한 색상값을 확인하진 못했고,
   일반적으로 알려진 치지직의 다크 배경 + 네온 그린 포인트 컬러 느낌을 참고해서 만든 것.
   나중에 정확한 색을 알려주시면 --accent 값만 바꾸면 전체에 반영됨.) */
:root {
  --bg: #0c0e11;
  --sidebar-bg: #111418;
  --surface: #15181c;
  --surface-2: #1c2025;
  --border: #23272d;
  --text: #eef1f3;
  --text-dim: #cfd6dc;
  --muted: #8b939b;
  --accent: #00e5a0;
  --accent-strong: #3dffc4;
  --accent-dim: rgba(0, 229, 160, 0.14);
  --accent-text: #04120c;
  --danger: #ff5a5a;
  --danger-dim: rgba(255, 90, 90, 0.15);
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  /* 브랜드 이름("유진 팬보드")에만 쓰는 로고용 폰트 — 본문(system-ui)은 그대로 두고
     사이드바 로고 글자 + 홈 화면 상단 제목, 이 두 군데에만 적용함.
     처음엔 영문 브랜드명이라 Google Fonts의 Orbitron을 썼는데, 한글 브랜드명("유진 팬보드")으로
     바뀌면서 Orbitron엔 한글 글리프가 없어 의미가 없어짐 — 대신 고도체(Godo)로 교체함.
     고도체는 눈누(noonnu.cc)에 등록된 상업용 무료 한글 폰트로, 실제 치지직 채팅 폰트로도
     알려진 서체라 요청하신 "치지직 느낌"에 가장 가깝다고 판단함. @font-face는 아래
     "브랜드 로고 폰트" 섹션 참고. */
  --font-logo: "Godo", system-ui, sans-serif;
}

/* 브랜드 로고 폰트 (고도체/Godo) — 눈누(noonnu.cc)가 제공하는 상업용 무료 한글 폰트 CDN.
   시청자 브라우저가 직접 이 URL에서 woff2를 받아오므로 로그인 여부와 무관하게 항상 로드됨.
   혹시 이 CDN이 막히거나 파일이 404여도 --font-logo의 다음 폰트(system-ui)로 자연스럽게
   대체되니 레이아웃이 깨지진 않음. */
@font-face {
  font-family: "Godo";
  src: url("//cdn.jsdelivr.net/korean-webfonts/1/corps/godo/Godo/GodoM.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "Godo";
  src: url("//cdn.jsdelivr.net/korean-webfonts/1/corps/godo/Godo/GodoB.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

* { box-sizing: border-box; }

/* hidden 속성은 항상 이긴다 — 클래스 선택자로 display:flex/grid 등을 준 요소는 브라우저 기본
   [hidden]{display:none}(우선순위가 제일 낮은 UA 규칙)을 덮어써서, JS로 hidden을 줘도 안
   숨겨지는 버그가 이 프로젝트에서 반복됐음(투표 폼, 공지 팝업의 수정/삭제 버튼 등). 요소마다
   .xxx[hidden] 예외를 다는 대신 여기서 한 번에 막음. */
[hidden] { display: none !important; }

/* 세로 스크롤바가 뜨고 안 뜨고에 따라(칭호 카드처럼 내용이 접혔다 펼쳐지면서 페이지 전체
   높이가 뷰포트를 넘었다 안 넘었다 할 때) 본문 폭이 스크롤바 두께만큼 늘었다 줄었다 하면서
   화면이 좌우로 살짝 튀는 걸 막음 — 스크롤이 실제로 필요 없을 때도 그 자리를 미리 비워둠. */
/* 스크롤바는 전부 숨김(스크롤 자체는 그대로 됨) — 특히 폰 화면에서 오른쪽에 스크롤바가 보이는
   게 거슬린다는 요청. 스크롤바가 아예 공간을 안 차지하니 예전에 쓰던 scrollbar-gutter(스크롤바
   생겼다 없어질 때 화면이 좌우로 튀는 것 방지)도 필요 없어짐. */
html, body, * {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
html::-webkit-scrollbar, body::-webkit-scrollbar, *::-webkit-scrollbar {
  display: none;
  width: 0;
  height: 0;
}

body {
  margin: 0;
  font-family: system-ui, "Noto Sans KR", sans-serif;
  background: var(--bg);
  color: var(--text);
}

h1 {
  font-size: 1.4rem;
  margin: 0 0 20px;
}

a {
  color: var(--accent);
}

/* 레이아웃: 왼쪽 사이드바 + 메인 컨텐츠 */
.app-shell {
  display: flex;
  min-height: 100vh;
  align-items: stretch;
}

.sidebar {
  width: 220px;
  flex-shrink: 0;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  padding: 24px 16px;
  display: flex;
  flex-direction: column;
  gap: 28px;
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;
  transition: width 0.2s ease;
}

.sidebar-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--text);
  text-decoration: none;
  min-width: 0;
  overflow: hidden;
}
.sidebar-brand .mark {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  object-fit: cover;
}
.sidebar-brand .label {
  /* 한글("유진 팬보드")은 영문 워드마크보다 훨씬 짧아서 폭 걱정은 없어졌지만, 혹시 모를
     좁은 화면 대비 말줄임표는 남겨둠. 고도체(Godo)는 한글 글자 자체가 이미 또렷해서
     Orbitron 때처럼 letter-spacing을 크게 줄 필요는 없음. */
  font-family: var(--font-logo);
  font-size: 1.05rem;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* 홈 화면(index.html) 맨 위 제목 — 사이드바 로고와 같은 문구("유진 팬보드")라 같은
   로고 폰트를 씀. */
.brand-heading {
  font-family: var(--font-logo);
  font-size: clamp(1.3rem, 4vw, 1.7rem);
}

.sidebar-toggle-btn {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-dim);
}
.sidebar-toggle-btn:hover { border-color: var(--accent); color: var(--accent); background: transparent; }
.sidebar-toggle-btn svg {
  width: 16px;
  height: 16px;
  transition: transform 0.2s ease;
}

.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.sidebar-nav a {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.95rem;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.sidebar-nav a:hover { background: var(--surface-2); color: var(--text); }
.sidebar-nav a.active {
  background: var(--accent-dim);
  color: var(--accent);
  font-weight: 600;
}
/* 위의 .sidebar-nav a { display: flex; } 가 일반 규칙이라 브라우저 기본 [hidden] 규칙보다
   우선순위가 높아서, hidden 속성을 줘도 안 숨겨지는 문제가 있었음 — 그래서 명시적으로 덮어씀.
   (관리자 링크(#admin-nav-link)를 JS로 hidden 처리해서 숨기는데 이게 없으면 계속 보였음) */
.sidebar-nav a[hidden] {
  display: none;
}
.sidebar-nav .icon,
.sidebar-icon-btn .icon {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative; /* .notice-nav-badge를 아이콘 모서리에 절대위치로 얹기 위한 기준점 */
}
.sidebar-nav .icon svg { width: 20px; height: 20px; }
.sidebar-icon-btn .icon svg { width: 18px; height: 18px; }

/* 공지사항 새 글 알림 점. 사이드바가 접혀서 아이콘만 보일 때도(body.sidebar-collapsed) 눈에
   띄어야 해서 라벨 텍스트가 아니라 .icon(20x20, position: relative) 안에 넣고 그 모서리에
   절대위치로 얹음. 기본은 hidden 속성으로 숨겨져 있다가 initNoticeBadge()/markNoticesSeen()
   (chzzk-auth.js)이 토글함. */
.notice-nav-badge {
  position: absolute;
  top: -2px;
  right: -2px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid var(--sidebar-bg);
}
.notice-nav-badge[hidden] { display: none; }

/* "포인트 상점" 아코디언 그룹 — 기본은 접혀있고 펼치면 하위 링크(일반 상점/칭호 상점)가
   나옴. 토글 버튼은 <button>이라 아래 공통 button {} 규칙을 덮어써야 해서 클래스
   선택자로 배경/보더를 다시 투명하게 잡아줌(클래스 선택자가 태그 선택자보다 우선순위가
   높아서 순서와 무관하게 항상 이김). */
.sidebar-nav-group { display: flex; flex-direction: column; }
.sidebar-nav-toggle {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  color: var(--text-dim);
  background: transparent;
  border: none;
  font-size: 0.95rem;
  font-weight: 400;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
  text-align: left;
}
.sidebar-nav-toggle:hover { background: var(--surface-2); color: var(--text); }
.sidebar-nav-toggle.active {
  background: var(--accent-dim);
  color: var(--accent);
  font-weight: 600;
}
.sidebar-nav-toggle .chevron {
  margin-left: auto;
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.2s ease;
}
.sidebar-nav-toggle .chevron svg { width: 14px; height: 14px; }
/* 그룹(포인트 상점 / 미니게임)마다 따로 펼침 — body 클래스로 기억해서 SPA 페이지 이동에도 유지됨. */
body.shop-nav-expanded #shop-nav-toggle .chevron,
body.game-nav-expanded #game-nav-toggle .chevron { transform: rotate(180deg); }

.sidebar-nav-submenu {
  display: none;
  flex-direction: column;
  gap: 2px;
  padding: 2px 0 4px 44px;
}
body.shop-nav-expanded #shop-nav-submenu,
body.game-nav-expanded #game-nav-submenu { display: flex; }
.sidebar-nav-submenu a {
  display: block;
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.88rem;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  white-space: nowrap;
}
.sidebar-nav-submenu a:hover { background: var(--surface-2); color: var(--text); }
.sidebar-nav-submenu a.active {
  background: var(--accent-dim);
  color: var(--accent);
  font-weight: 600;
}

.sidebar-user {
  margin-top: auto;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  overflow: hidden;
}
.sidebar-user-name {
  margin: 0 0 10px;
  font-size: 0.88rem;
  color: var(--text-dim);
  word-break: break-all;
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 8px;
}
.sidebar-user-name-text { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
/* 사이드바 이름 앞 동그란 프로필(치지직 프사, 없으면 이름 첫 글자). */
.sidebar-avatar {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 0.75rem;
  font-weight: 700;
  overflow: hidden;
}
/* 치지직 프사가 있으면 동그라미 안을 사진으로 꽉 채움(모바일 상단바/더보기 아바타 공용). */
.sidebar-avatar.has-image,
.m-avatar.has-image { background: var(--surface-2); padding: 0; overflow: hidden; }
.sidebar-avatar > img,
.m-avatar > img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
.sidebar-user button { width: 100%; }
.sidebar-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
  overflow: hidden;
}

/* 접힌 상태 (데스크톱 폭에서만 — 모바일은 아래 가로 바 레이아웃으로 이미 컴팩트함) */
@media (min-width: 721px) {
  body.sidebar-collapsed .sidebar { width: 64px; }
  body.sidebar-collapsed .sidebar-top { flex-direction: column; gap: 10px; }
  body.sidebar-collapsed .sidebar-brand { justify-content: center; }
  body.sidebar-collapsed .sidebar-brand .label,
  body.sidebar-collapsed .sidebar-nav .label,
  body.sidebar-collapsed .sidebar-icon-btn .label,
  body.sidebar-collapsed .sidebar-user-name {
    display: none;
  }
  body.sidebar-collapsed .sidebar-nav a { justify-content: center; padding: 10px 0; }
  body.sidebar-collapsed .sidebar-toggle-btn svg { transform: rotate(180deg); }
  /* 접힌 상태에선 아이콘만 보이는 폭(64px)이라 하위 메뉴를 펼쳐봐야 잘려 보이므로,
     펼침 상태였더라도 접힌 사이드바에서는 화살표/하위 링크를 그냥 숨긴다. */
  body.sidebar-collapsed .sidebar-nav-toggle { justify-content: center; padding: 10px 0; }
  body.sidebar-collapsed .sidebar-nav-toggle .chevron { display: none; }
  body.sidebar-collapsed .sidebar-nav-submenu { display: none !important; }
}

.main-content {
  flex: 1;
  min-width: 0;
  max-width: 720px;
  margin: 0 auto;
  padding: 24px 16px 64px;
  transition: opacity 0.15s ease;
}
/* 사이드바는 그대로 두고 본문만 fetch로 교체하는 라우터(assets/js/spa-router.js)가
   페이지 전환 중일 때 붙이는 클래스 — View Transitions API를 지원 안 하는 브라우저에서
   쓰는 대체 트랜지션(살짝 페이드). */
.main-content.page-fade-out {
  opacity: 0;
}

/* 브라우저가 View Transitions API를 지원하면(크롬/엣지 등) 이 값으로 전환 속도를 맞춤. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.18s;
}

/* ============================================================================
   모바일 전용 레이아웃 (720px 이하) — 사이드바를 숨기고 상단바 + 하단 탭바 + 더보기 시트로
   대체함. 마크업은 chzzk-auth.js의 initMobileNav()가 body에 끼워 넣음. PC 폭에선 전부 숨김.
   ============================================================================ */
.m-topbar, .m-tabbar, .m-sheet, .m-sheet-backdrop { display: none; }

@media (max-width: 720px) {
  .app-shell { flex-direction: column; }
  .sidebar { display: none; }
  /* 세로 flex 안에서 margin:0 auto를 받은 자식은 폭이 내용물만큼으로 줄어들어서(가운데로
     좁게 몰리던 버그) 폭을 명시적으로 꽉 채움. 아래쪽은 고정 탭바에 안 가리게 여백. */
  .main-content {
    width: 100%;
    padding: 16px 14px calc(84px + env(safe-area-inset-bottom));
  }

  /* 상단바 */
  .m-topbar {
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 10px;
    height: 54px;
    padding: 0 14px;
    background: var(--sidebar-bg);
    border-bottom: 1px solid var(--border);
  }
  .m-brand {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text);
    text-decoration: none;
    font-family: var(--font-logo);
    font-weight: 700;
    font-size: 1.02rem;
  }
  .m-brand img { width: 30px; height: 30px; border-radius: 50%; }
  .m-topbar-user { margin-left: auto; display: flex; align-items: center; }
  .m-topbar-profile { display: flex; align-items: center; gap: 8px; text-decoration: none; }
  .m-point-pill {
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--accent);
    background: var(--accent-dim);
    padding: 5px 10px;
    border-radius: 999px;
    white-space: nowrap;
  }
  .m-avatar {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 0.85rem;
    font-weight: 700;
  }
  .m-avatar-lg { width: 42px; height: 42px; font-size: 1rem; }
  .m-login-btn { padding: 7px 14px; font-size: 0.85rem; }

  /* 하단 탭바 */
  .m-tabbar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    display: flex;
    background: var(--sidebar-bg);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .m-tab {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    height: 60px;
    padding: 0;
    border-radius: 0;
    background: none;
    color: var(--muted);
    font-size: 0.7rem;
    font-weight: 500;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
  }
  .m-tab:hover { background: none; color: var(--text-dim); }
  .m-tab.active, .m-tab.open { color: var(--accent); }
  .m-tab-icon { position: relative; display: flex; }
  .m-tab-icon svg { width: 23px; height: 23px; }
  .m-tab .notice-nav-badge { top: -2px; right: -4px; }

  /* 더보기 시트 */
  body.m-sheet-open { overflow: hidden; }
  .m-sheet-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 45;
    background: rgba(0, 0, 0, 0.55);
  }
  .m-sheet {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 48;
    max-height: calc(100vh - 80px);
    overflow-y: auto;
    background: var(--surface);
    border-top: 1px solid var(--border);
    border-radius: 18px 18px 0 0;
    padding: 8px 16px calc(76px + env(safe-area-inset-bottom));
    animation: m-sheet-up 0.18s ease-out;
  }
  @keyframes m-sheet-up { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }
  .m-sheet-grabber { width: 40px; height: 4px; border-radius: 4px; background: var(--border); margin: 0 auto 14px; }
  .m-sheet-user {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 2px 2px 14px;
    border-bottom: 1px solid var(--border);
  }
  .m-sheet-user-text { flex: 1; min-width: 0; }
  .m-sheet-user-name { font-weight: 700; font-size: 0.95rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .m-sheet-user-sub { font-size: 0.75rem; color: var(--muted); margin-top: 2px; }
  .m-sheet-user-points { font-weight: 800; font-size: 1.05rem; color: var(--accent); white-space: nowrap; }
  .m-sheet-login-btn { padding: 8px 12px; font-size: 0.82rem; white-space: nowrap; }
  .m-sheet-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    padding: 14px 0;
  }
  .m-sheet-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 7px;
    padding: 14px 4px;
    border-radius: var(--radius-md);
    background: var(--surface-2);
    border: 1px solid transparent;
    color: var(--text-dim);
    font-size: 0.78rem;
    text-decoration: none;
  }
  .m-sheet-item svg { width: 22px; height: 22px; }
  .m-sheet-item.active { color: var(--accent); border-color: var(--accent); background: var(--accent-dim); }
  .m-sheet-footer:empty { display: none; }
  .m-sheet-footer { border-top: 1px solid var(--border); padding-top: 6px; }
  .m-sheet-logout-btn {
    width: 100%;
    background: none;
    color: var(--muted);
    font-weight: 500;
    font-size: 0.85rem;
    padding: 10px;
  }
  .m-sheet-logout-btn:hover { background: none; color: var(--danger); }

  /* 공지 제목 버튼이 글자 높이(약 21px)밖에 안 돼서 손가락으로 누르기 작았음 — 위아래로 누르는
     영역만 넓히고, 그만큼 음수 마진으로 상쇄해서 보이는 간격은 그대로 유지. */
  /* (.notice-item을 앞에 붙여 우선순위를 올림 — 아래쪽의 기본 .notice-title-btn 규칙이 파일상
     더 뒤에 있어서, 같은 우선순위면 그쪽 padding:0이 이겨버림) */
  .notice-item .notice-title-btn { padding: 8px 0; margin: -8px 0 -4px; }
}

button {
  font: inherit;
  cursor: pointer;
  border: none;
  border-radius: var(--radius-sm);
  padding: 10px 16px;
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 600;
  /* 한글 버튼 글자가 좁은 칸에서 "가능"의 "능"만 따로 떨어지는 식으로 끊기지 않게 — 줄바꿈은 띄어쓰기에서만. */
  word-break: keep-all;
}
button:hover { background: var(--accent-strong); }
button:disabled {
  background: var(--surface-2);
  color: var(--muted);
  cursor: not-allowed;
  font-weight: 400;
}
button.secondary {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-weight: 400;
}
button.secondary:hover { border-color: var(--accent); color: var(--accent); background: transparent; }

/* "전체 보기" 같은, 카드 헤더에 붙는 작은 필 모양 링크 버튼 */
.pill-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-dim);
  text-decoration: none;
  font-size: 0.82rem;
  white-space: nowrap;
  flex-shrink: 0;
}
.pill-link:hover { border-color: var(--accent); color: var(--accent); }
.pill-link svg { width: 14px; height: 14px; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 20px;
  margin-bottom: 16px;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}
/* 카드 소제목("공지사항", "랭킹 미리보기" 등)도 브랜드 로고와 같은 치지직 느낌 폰트(고도체)로 —
   사이드바 로고/홈 상단 제목에만 쓰던 --font-logo를 모든 카드 소제목까지 넓힘. */
.card-header h2 { margin: 0; font-size: 1.05rem; font-family: var(--font-logo); }

.muted { color: var(--muted); font-size: 0.88rem; }

.balance {
  /* clamp로 잡아둬서 포인트가 나중에 자릿수가 늘어나도(예: 999999P) 박스 폭을 안 벗어나고
     알아서 살짝 작아짐 — 최소 1.4rem, 기본 2rem, 화면이 아주 좁으면 그 사이로 줄어듦. */
  font-size: clamp(1.4rem, 5vw, 2rem);
  font-weight: 700;
  word-break: break-all;
}
.balance .unit { font-size: 1rem; font-weight: 400; color: var(--muted); margin-left: 4px; }

/* 마이페이지 "현재 포인트" 박스 — 포인트/칭호(구매·장착)/등급(포인트 구간, 자동) 세 칸으로
   나눔. grid로 폭을 1fr/auto/1fr/auto/1fr로 딱 나눠서 세 칸이 항상 정확히 같은 폭이 되게 함
   (flex 기반이면 divider 폭만큼 미세하게 안 맞을 수 있어서 grid로 함). */
.balance-split {
  display: grid;
  grid-template-columns: 1fr auto 1fr auto 1fr;
  align-items: stretch;
}
.balance-half {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4px;
  padding: 4px 10px;
}
.balance-half .muted,
.balance-half .balance { margin: 0; }
.balance-divider { width: 1px; background: var(--border); }
.balance-title-placeholder { color: var(--muted); font-size: 1.1rem; margin: 0; }
/* 세 칸(포인트/칭호/등급)일 때만 포인트 숫자를 칭호·등급 텍스트와 같은 크기로 줄임 —
   원래 .balance 크기(clamp 1.4~2rem)를 그대로 두면 숫자 칸만 세로로 훨씬 높아져서
   세 칸 값 줄이 나란히 안 맞고 어긋나 보임. shop.html처럼 칸 나눔 없이 혼자 쓰는
   .balance-card-centered 쪽은 그대로 큰 글씨 유지(.balance 자체는 안 건드림). */
.balance-split .balance { font-size: 1.1rem; font-weight: 700; word-break: break-all; }
@media (max-width: 560px) {
  /* 세 칸이라 폭이 좁은 화면에선 더 빡빡해짐 — 양옆 여백만 줄여서 칭호/등급 이름이
     잘리지 않게 함 (글자 크기는 그대로 둬도 대부분의 칭호명이 짧아서 괜찮음). */
  .balance-half { padding: 4px 4px; }
  .balance-title-placeholder,
  .balance-split .balance { font-size: 1rem; }
}

/* 포인트 상점의 "현재 포인트" 박스는 (칭호 칸 없이) 통짜라서 그냥 박스 전체를 중앙 정렬. */
.balance-card-centered { text-align: center; }
.balance-card-centered .muted,
.balance-card-centered .balance { margin: 0; }

/* 토글 스위치 (공개 설정용) */
.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.switch {
  position: relative;
  display: inline-block;
  width: 44px;
  height: 24px;
  flex-shrink: 0;
}
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute;
  inset: 0;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  transition: background 0.15s;
}
.switch .slider::before {
  content: "";
  position: absolute;
  width: 16px;
  height: 16px;
  left: 3px;
  top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.15s;
}
.switch input:checked + .slider { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .slider::before { transform: translateX(20px); background: var(--accent-text); }

/* 방송 상태 배지 */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.9rem;
  font-weight: 600;
}
.status-badge .dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.status-badge.live { background: var(--danger-dim); color: #ff8a8a; }
.status-badge.live .dot {
  background: var(--danger);
  animation: status-pulse 1.6s infinite;
}
.status-badge.offline { background: rgba(139, 147, 155, 0.15); color: var(--muted); }
.status-badge.offline .dot { background: var(--muted); }
@keyframes status-pulse {
  0% { box-shadow: 0 0 0 0 rgba(255, 90, 90, 0.5); }
  70% { box-shadow: 0 0 0 6px rgba(255, 90, 90, 0); }
  100% { box-shadow: 0 0 0 0 rgba(255, 90, 90, 0); }
}
.live-title { margin: 10px 0 0; color: var(--text-dim); font-size: 0.92rem; }

/* 공지사항 — 게시판 스타일(제목 목록 + 클릭하면 내용 팝업). */
ul.notice-list, ol.notice-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.notice-item { padding: 12px 0; border-bottom: 1px solid var(--border); }
.notice-item:last-child { border-bottom: none; }
.notice-item-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.notice-item time { color: var(--muted); font-size: 0.8rem; }
.notice-item-actions { display: flex; gap: 10px; flex-shrink: 0; }

/* 글 제목 — 목록 행(버튼, notice.html)과 홈 화면 미리보기(링크, index.html)가 같은 모양을 씀. */
.notice-title-btn {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: 0;
  margin: 0 0 4px;
  font: inherit;
  font-size: 0.98rem;
  font-weight: 600;
  color: var(--text);
  text-decoration: none;
  cursor: pointer;
}
.notice-title-btn:hover { color: var(--accent); background: none; }

/* 제목 앞에 붙는 "NEW" 표시 — 사이드바 알림 점과 같은 기준(마지막으로 확인한 시각)으로 판정함.
   글자 배지라 점(.notice-nav-badge)과 달리 목록에서 어떤 글이 새 글인지 바로 구분됨. */
.notice-new-tag {
  display: inline-block;
  margin-right: 6px;
  padding: 1px 5px;
  border-radius: 4px;
  background: var(--accent);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  vertical-align: middle;
}

/* 상단 고정 공지 — 제목 앞 "고정" 표시만 붙임(줄 배경 하이라이트는 없음, 0042_notice_pin.sql). */
.notice-pin-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-right: 6px;
  padding: 1px 6px 1px 5px;
  border-radius: 4px;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  color: var(--accent);
  font-size: 0.68rem;
  font-weight: 700;
  vertical-align: middle;
  line-height: 1.4;
}
.notice-form-toggles { display: inline-flex; align-items: center; gap: 16px; flex-wrap: wrap; }

/* 텍스트만 있는 작은 버튼 (공지 수정/삭제 등). <button class="secondary">보다 더 가볍게. */
.link-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 400;
  text-decoration: underline;
}
.link-btn:hover { color: var(--accent); background: none; }

/* 공지 글쓰기/수정/내용보기 팝업(notice.html의 <dialog>)과 그 안 textarea 공용 스타일. */
.notice-textarea {
  display: block;
  width: 100%;
  min-height: 44px;
  /* 줄바꿈하면 스크롤 대신 박스 높이 자체가 늘어나게(JS의 autoResizeTextarea가 height를 갱신) —
     그래서 resize는 막고, 늘어난 높이만큼 넘치는 내용도 안 잘리게 overflow는 숨김 처리. */
  resize: none;
  overflow: hidden;
  font: inherit;
  line-height: 1.5;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 10px 12px;
  margin-bottom: 10px;
}
.notice-textarea:focus { outline: none; border-color: var(--accent); }
.notice-title-input {
  display: block;
  width: 100%;
  font: inherit;
  font-weight: 600;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 10px 12px;
  margin-bottom: 10px;
}
.notice-title-input:focus { outline: none; border-color: var(--accent); }
.notice-form-actions { display: flex; gap: 8px; margin-bottom: 10px; }

/* 네이티브 <dialog> — 제목 누르면 뜨는 팝업(보기/수정/글쓰기 공용). */
.notice-modal {
  width: min(520px, calc(100vw - 32px));
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 20px;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
}
.notice-modal::backdrop { background: rgba(0, 0, 0, 0.55); }
.notice-modal h3 { margin: 0 0 6px; font-size: 1.15rem; word-break: break-word; }
.notice-modal-content {
  margin: 14px 0 0;
  white-space: pre-wrap;
  word-break: break-word;
  line-height: 1.6;
}
.notice-modal-content[hidden] { display: none; }

/* 이미지가 들어있는 공지를 볼 때만 팝업을 넓힘(JS가 .has-images를 토글 — 글쓰기/수정 폼이나
   notice-modal을 재사용하는 다른 팝업들은 원래 520px 그대로). */
.notice-modal.has-images { width: min(860px, calc(100vw - 32px)); }

/* ── 공지 팝업(notice.html/index.html의 #notice-modal) — PC에선 넓게, 높이는 화면 안으로 제한하고
   제목(head)·버튼(actions)은 고정한 채 본문(.notice-modal-body)만 스크롤. 글쓰기/수정 폼도 같은 구조
   (입력칸 영역만 스크롤, 등록/취소 버튼은 항상 보임). notice-modal을 같이 쓰는 다른 팝업(상점 등)은 그대로. */
.notice-modal.notice-board-modal {
  width: min(880px, calc(100vw - 32px));
  max-height: calc(100dvh - 48px);
  padding: 0;
  overflow: hidden;
}
/* display는 열렸을 때만 바꿈 — 닫힌 dialog에 display를 주면 브라우저 기본 숨김이 풀려버림. */
.notice-modal.notice-board-modal[open] { display: flex; flex-direction: column; }
.notice-modal-pane { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.notice-modal-pane[hidden] { display: none; }
.notice-modal-head { padding: 20px 22px 4px; flex: 0 0 auto; }
.notice-modal-head p { margin: 0; }
.notice-modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 4px 22px 16px;
}
.notice-modal-body:focus { outline: none; }
.notice-board-modal .notice-modal-actions,
.notice-board-modal .notice-form-actions {
  flex: 0 0 auto;
  margin: 0;
  padding: 12px 22px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface);
}
.notice-form-body { padding-top: 20px; }
@media (max-width: 560px) {
  .notice-modal-head { padding: 16px 16px 4px; }
  .notice-modal-body { padding: 4px 16px 14px; }
  .notice-form-body { padding-top: 16px; }
  .notice-board-modal .notice-modal-actions,
  .notice-board-modal .notice-form-actions { padding: 10px 16px 14px; }
}

/* ── 공지 HTML 모드: 글쓰기 도구 ── */
.notice-html-bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin: 0 0 8px; flex-wrap: wrap; }
.notice-html-toggle { font-size: 0.85rem; }
.notice-preview-btn { padding: 6px 12px; font-size: 0.82rem; }
.notice-html-tools { display: flex; flex-wrap: wrap; gap: 5px; margin: 0 0 8px; }
.notice-html-tools[hidden] { display: none; }
.notice-html-tools button { padding: 5px 9px; font-size: 0.78rem; white-space: nowrap; }
.notice-html-tools select {
  padding: 5px 6px;
  font: inherit;
  font-size: 0.78rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-dim);
}
.notice-textarea.is-code { font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace; font-size: 0.84rem; line-height: 1.55; min-height: 220px; }
/* 미리보기 팝업 제목 아래 "미리보기" 표시 */
.notice-preview-badge { display: inline-block; padding: 1px 8px; margin-right: 4px; border-radius: 999px; font-size: 0.72rem; font-weight: 700; color: #3a2a00; background: #f2c230; vertical-align: 1px; }

/* ── 공지 HTML 모드: 보는 화면(노션 느낌). renderNoticeContent가 .notice-html을 붙임 ── */
.notice-modal-content.notice-html { white-space: normal; line-height: 1.7; }
/* 글 안의 position:fixed 등이 페이지 전체를 덮지 못하게 이 상자 안에 가둠. */
.notice-html { contain: layout paint; overflow-wrap: anywhere; }
.notice-html > :first-child { margin-top: 0; }
.notice-html > :last-child { margin-bottom: 0; }
.notice-html h1 { font-size: 1.55rem; margin: 1.1em 0 0.4em; line-height: 1.3; }
.notice-html h2 { font-size: 1.28rem; margin: 1em 0 0.35em; line-height: 1.35; }
.notice-html h3 { font-size: 1.08rem; margin: 0.9em 0 0.3em; }
.notice-html h4 { font-size: 1rem; margin: 0.8em 0 0.3em; }
.notice-html p { margin: 0.35em 0; }
.notice-html ul, .notice-html ol { margin: 0.35em 0; padding-left: 1.5em; }
.notice-html li { margin: 0.15em 0; }
.notice-html a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.notice-html hr { border: 0; border-top: 1px solid var(--border); margin: 1.1em 0; }
.notice-html blockquote { margin: 0.6em 0; padding: 2px 0 2px 14px; border-left: 3px solid var(--text-dim); color: var(--text-dim); }
.notice-html code { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 0.88em; padding: 1px 5px; border-radius: 4px; background: var(--surface-2); color: #ff9aa2; }
.notice-html pre { background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 10px 12px; overflow-x: auto; }
.notice-html pre code { background: none; padding: 0; color: var(--text); }
.notice-html mark { background: rgba(242, 194, 48, 0.3); color: inherit; padding: 0 2px; border-radius: 3px; }
.notice-html img { max-width: 100%; height: auto; border-radius: var(--radius-sm); }
.notice-html table { border-collapse: collapse; width: 100%; margin: 0.6em 0; font-size: 0.92em; }
.notice-html th, .notice-html td { border: 1px solid var(--border); padding: 7px 10px; text-align: left; vertical-align: top; }
.notice-html th { background: var(--surface-2); font-weight: 700; }
.notice-html details { margin: 0.4em 0; padding: 2px 0 2px 4px; }
.notice-html summary { cursor: pointer; font-weight: 600; list-style: none; display: flex; align-items: center; gap: 6px; }
.notice-html summary::-webkit-details-marker { display: none; }
.notice-html summary::before { content: ""; width: 0; height: 0; border-left: 6px solid currentColor; border-top: 4.5px solid transparent; border-bottom: 4.5px solid transparent; transition: transform 0.15s ease; flex-shrink: 0; }
.notice-html details[open] > summary::before { transform: rotate(90deg); }
.notice-html details > :not(summary) { margin-left: 16px; }
.notice-html .callout { display: flex; gap: 10px; align-items: flex-start; margin: 0.6em 0; padding: 12px 14px; border-radius: var(--radius-sm); background: var(--surface-2); }
.notice-html .callout > div { flex: 1; min-width: 0; }
.notice-html .callout-icon { font-size: 1.15em; line-height: 1.5; flex-shrink: 0; }
.notice-html ul.todo { list-style: none; padding-left: 0.2em; }
.notice-html ul.todo li { display: flex; gap: 8px; align-items: baseline; }
.notice-html ul.todo li::before { content: ""; width: 14px; height: 14px; border: 1.5px solid var(--muted); border-radius: 3px; flex-shrink: 0; transform: translateY(2px); }
.notice-html ul.todo li.done { color: var(--muted); text-decoration: line-through; }
.notice-html ul.todo li.done::before { background: var(--accent); border-color: var(--accent); box-shadow: inset 0 0 0 2px var(--surface); }
.notice-html .columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin: 0.6em 0; }
.notice-html .center { text-align: center; }
.notice-html .small { font-size: 0.85em; }
.notice-html .c-gray { color: #9aa1a8; } .notice-html .c-red { color: #ff6b6b; } .notice-html .c-orange { color: #ff9f5a; }
.notice-html .c-yellow { color: #f2c230; } .notice-html .c-green { color: #3ddc84; } .notice-html .c-blue { color: #5cb6ff; }
.notice-html .c-purple { color: #b18cff; } .notice-html .c-pink { color: #ff7bbf; } .notice-html .c-accent { color: var(--accent); }
.notice-html .bg-gray { background: rgba(154, 161, 168, 0.2); } .notice-html .bg-red { background: rgba(255, 107, 107, 0.2); }
.notice-html .bg-orange { background: rgba(255, 159, 90, 0.2); } .notice-html .bg-yellow { background: rgba(242, 194, 48, 0.22); }
.notice-html .bg-green { background: rgba(61, 220, 132, 0.18); } .notice-html .bg-blue { background: rgba(92, 182, 255, 0.2); }
.notice-html .bg-purple { background: rgba(177, 140, 255, 0.2); } .notice-html .bg-pink { background: rgba(255, 123, 191, 0.2); }
.notice-html span[class^="bg-"] { padding: 1px 4px; border-radius: 4px; }

/* 공지 첨부파일 — 이미지는 네이버카페 본문처럼 한 장씩 세로로 크게, 그 외 문서는 다운로드
   목록으로 따로 보여줌 (renderNoticeAttachmentsHtml, chzzk-auth.js 참고). 보기 전용 팝업
   (notice.html, index.html 둘 다)에서 씀. */
.notice-image-gallery {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
}
/* class 선택자로 display:flex를 주는 규칙이 기본 [hidden]{display:none} UA 규칙을 덮어써서
   안 가려지는 문제 — predict.html에서 이미 여러 번 겪은 것과 같은 패턴이라 처음부터 같이 둠. */
.notice-image-gallery[hidden] { display: none; }
/* 래퍼는 이미지 실제 크기에 딱 맞게(fit-content) — 그래야 다운로드 버튼이 이미지 모서리에 붙음.
   이미지는 원본 크기 그대로 보여주되 팝업 폭을 넘으면 비율 유지한 채 줄임(작은 이미지를
   억지로 늘리진 않음). */
.notice-gallery-thumb {
  position: relative;
  display: block;
  width: fit-content;
  max-width: 100%;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-2);
}
.notice-gallery-thumb img { display: block; max-width: 100%; height: auto; }
.notice-gallery-download-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  border-radius: 6px;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.notice-gallery-download-btn svg { width: 16px; height: 16px; }
.notice-gallery-thumb:hover .notice-gallery-download-btn,
.notice-gallery-download-btn:focus-visible { opacity: 1; }
/* 폰/태블릿처럼 마우스 올리기(hover)가 없는 기기에선 위 규칙이 영영 안 걸려서 다운로드 버튼이
   안 보였음 — 터치 기기에선 항상 보이게. */
@media (hover: none) {
  .notice-gallery-download-btn { opacity: 1; }
}

.notice-file-list { display: flex; flex-direction: column; gap: 6px; margin-top: 14px; }
.notice-file-list[hidden] { display: none; }
.notice-file-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  font-size: 0.86rem;
}
.notice-file-row:hover { border-color: var(--accent); }
.notice-file-icon { flex-shrink: 0; display: flex; color: var(--muted); }
.notice-file-icon svg { width: 16px; height: 16px; }
.notice-file-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notice-file-size { flex-shrink: 0; color: var(--muted); font-size: 0.78rem; }

/* 글쓰기/수정 폼의 첨부파일 선택 영역 — 네이버카페처럼 "사진"과 "파일"을 서로 다른 그룹으로
   나눔(notice-attachment-group 두 개). 실제 <input type=file>은 각 그룹당 하나씩 hidden으로
   숨겨두고, 대신 JS(renderAttachmentPreview)가 그리는 점선 테두리 "추가" 타일/버튼(label
   for=input id)로 엶 — 브라우저 기본 파일선택 버튼 대신 그리드/목록 안에 자연스럽게 들어가게. */
.notice-attachment-field { margin-bottom: 10px; }
.notice-attachment-field-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 10px;
}
.notice-attachment-hint {
  font-size: 0.76rem;
  font-variant-numeric: tabular-nums;
}
.notice-attachment-group { margin-bottom: 14px; }
.notice-attachment-group:last-child { margin-bottom: 0; }
.notice-attachment-group-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-dim);
  margin-bottom: 8px;
}
.notice-attachment-group-title svg { width: 15px; height: 15px; flex-shrink: 0; }
.notice-attachment-group-subtitle { font-size: 0.72rem; font-weight: 400; }

/* 사진 그룹 — 정사각형 썸네일 그리드 + 마지막 칸에 점선 "사진 추가" 타일. */
.notice-photo-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: 8px;
}
.notice-photo-tile {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--surface-2);
}
.notice-photo-tile img { display: block; width: 100%; height: 100%; object-fit: cover; }
.notice-photo-add-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--border);
  color: var(--muted);
  font-size: 0.68rem;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.notice-photo-add-tile:hover { border-color: var(--accent); color: var(--accent); }
.notice-photo-add-tile svg { width: 18px; height: 18px; }

/* 파일 그룹 — 아이콘+이름+용량 행 목록 + 맨 아래 점선 "파일 추가" 버튼(가로 폭 전체). */
.notice-file-picker-list { display: flex; flex-direction: column; gap: 6px; }
.notice-file-picker-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  font-size: 0.85rem;
}
.notice-file-picker-row svg { flex-shrink: 0; width: 16px; height: 16px; color: var(--muted); }
.notice-file-picker-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notice-file-picker-size { flex-shrink: 0; color: var(--muted); font-size: 0.76rem; }
.notice-file-add-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  border: 1.5px dashed var(--border);
  color: var(--muted);
  font-size: 0.82rem;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.notice-file-add-btn:hover { border-color: var(--accent); color: var(--accent); }
.notice-file-add-btn svg { width: 15px; height: 15px; }

/* 삭제(×) 버튼 — 사진 타일 위에서는 우상단 원형 오버레이, 파일 행에서는 오른쪽에 나란히. */
.notice-attachment-remove-btn {
  flex-shrink: 0;
  padding: 0;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: 0.8rem;
  cursor: pointer;
}
.notice-photo-tile .notice-attachment-remove-btn {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 18px;
  height: 18px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
}
.notice-photo-tile .notice-attachment-remove-btn:hover { background: var(--danger); }
.notice-file-picker-row .notice-attachment-remove-btn {
  width: 20px;
  height: 20px;
  background: var(--surface);
  color: var(--muted);
  border: 1px solid var(--border);
}
.notice-file-picker-row .notice-attachment-remove-btn:hover {
  background: var(--danger-dim);
  color: var(--danger);
  border-color: var(--danger);
}

.notice-modal-actions {
  display: flex;
  align-items: center;
  /* 오른쪽 정렬이 기본 — 홈 화면 팝업(notice.html)처럼 버튼이 "닫기" 하나뿐인 경우에도
     자연스럽게 오른쪽에 붙음. 관리자용 수정/삭제가 같이 있을 땐 그쪽에 margin-right:auto를
     줘서 왼쪽으로 밀어내고 닫기는 계속 오른쪽에 남게 함. */
  justify-content: flex-end;
  gap: 8px;
  margin-top: 18px;
}
.notice-modal-admin-actions {
  display: inline-flex;
  gap: 10px;
  margin-right: auto;
}
/* "고정 해제"처럼 두 단어 버튼이 좁은 폰 화면에서 두 줄로 꺾이지 않게. */
.notice-modal-actions button { white-space: nowrap; }
@media (max-width: 420px) {
  .notice-modal-admin-actions { gap: 6px; }
  .notice-modal-actions button { padding-left: 12px; padding-right: 12px; }
}

/* 랭킹 리스트 */
ol.ranking-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
ol.ranking-list li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
ol.ranking-list li:last-child { border-bottom: none; }
ol.ranking-list .rank {
  width: 28px;
  text-align: center;
  color: var(--muted);
  font-weight: 600;
}
ol.ranking-list .name { flex: 1; min-width: 0; word-break: keep-all; overflow-wrap: anywhere; } /* 이름이 길면 글자 중간이 아니라 칭호/이름 단위로 줄바꿈 */
ol.ranking-list .name.is-private { color: var(--muted); }
/* 관리자 화면에서만 — 비공개 유저 이름 앞 "비공개" 표시(일반 유저 화면엔 이름 자체가 "비공개"로 가려짐). */
.rank-private-tag {
  display: inline-block;
  margin-right: 6px;
  padding: 1px 6px;
  border-radius: 4px;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 600;
  vertical-align: middle;
  line-height: 1.4;
}
ol.ranking-list .points { font-weight: 600; }
ol.ranking-list li.me {
  background: var(--accent-dim);
  border-radius: var(--radius-sm);
}
ol.ranking-list li.me .name { color: var(--accent); font-weight: 600; }

/* 포인트 상점 목록 */
.shop-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
.shop-item h3 { margin: 0 0 6px; font-size: 1.05rem; }
.shop-item .cost { color: var(--accent); font-weight: 600; margin-bottom: 10px; }
.shop-item p.desc { color: var(--text-dim); font-size: 0.88rem; min-height: 2.4em; }
/* 이미 구매한 칭호 상품 카드 — 마이페이지 title-card.selected와 같은 강조 패턴. */
.shop-item.owned { border-color: var(--accent); }
.shop-item.owned h3 { color: var(--accent); }
/* 한정 수량(재고)이 걸린 상품의 "N개 남음/품절" 안내 — cost 바로 아래 붙게 간격을 좁힘. */
.shop-item .stock-note { margin: -4px 0 10px; font-size: 0.82rem; }
.shop-item.sold-out { opacity: 0.65; }

/* 상점 상품 관리자용 인라인 수정 UI (shop.html — 관리자로 로그인했을 때만 노출).
   "+ 상품 추가"/"+ 칭호 상품 추가" 버튼은 각자 자기 섹션(일반 상점/칭호 상점) 안에 따로 둠. */
.shop-section-toolbar { margin: -4px 0 14px; display: flex; gap: 8px; flex-wrap: wrap; }
/* .shop-item-field[hidden]와 같은 이유 — display:flex를 주는 author 규칙이 브라우저 기본
   [hidden]{display:none} 규칙보다 우선순위가 높아서, 관리자가 아닐 때 JS로 .hidden=true를
   줘도 안 숨겨지고 "+ 칭호 상품 추가" 버튼이 계속 보이던 버그의 원인이었음. */
.shop-section-toolbar[hidden] { display: none; }
.shop-item.inactive { opacity: 0.55; }
.shop-item-admin-bar {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--border);
}
.shop-item-inactive-badge {
  font-size: 0.78rem;
  color: var(--muted);
}
.shop-item-admin-buttons { display: flex; flex-wrap: wrap; justify-content: center; gap: 5px; }
.shop-item-admin-buttons button { padding: 6px 9px; font-size: 0.8rem; white-space: nowrap; }

/* 상품 추가/수정 모달의 입력칸 — placeholder만으로는 값을 채우고 나면(특히 숫자 입력칸)
   뭘 의미하는지 안 보여서, 각 입력칸 위에 사라지지 않는 작은 라벨을 고정으로 둠. */
.shop-item-field { display: flex; flex-direction: column; gap: 4px; margin-bottom: 10px; }
/* .shop-item-field가 display:flex를 주는 author 규칙이라, 브라우저 기본 [hidden]{display:none}
   (user-agent 규칙)보다 우선순위가 높아서 JS로 .hidden=true를 줘도 안 숨겨지는 문제가 있었음 —
   같은 author 레이어에서 더 구체적인 선택자로 다시 눌러줘야 함(id 필드 숨김 버그의 원인). */
.shop-item-field[hidden] { display: none; }
.shop-item-field .field-label { font-size: 0.8rem; color: var(--muted); }
.shop-item-field .notice-title-input,
.shop-item-field .notice-textarea,
.shop-item-field .admin-amount-input { margin-bottom: 0; width: 100%; }
.admin-bulk-row .shop-item-field { flex: 1 1 120px; align-items: stretch; margin-bottom: 0; }
/* .admin-bulk-row는 margin-bottom이 없어서, 바로 다음에 오는 독립 .shop-item-field(칭호명 등)와
   붙어버려 다른 필드 사이 간격(10px)이랑 안 맞았음 — 그 필드에 margin-top을 직접 줘서 맞춤. */
#shop-item-titlename-row { margin-top: 10px; }

/* 마이페이지 칭호 목록 — 이제 상점 구매 칭호만 보임(포인트 구간 칭호는 자동 배지라 목록에
   안 나옴), 그래서 잠김 상태 없이 장착 상태만 있음. shop-grid/shop-item과 같은 레이아웃 패턴. */
.titles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
.title-card h3 { margin: 0 0 6px; font-size: 1.05rem; }
.title-card p.desc { color: var(--text-dim); font-size: 0.88rem; min-height: 2.4em; }
.title-card.selected { border-color: var(--accent); }
.title-card.selected h3 { color: var(--accent); }

/* 상점/관리자 칭호 배지 — 칭호마다 고른 색으로 배경을 꽉 채운 작은 네모 배지(titleBadgeHtml,
   chzzk-auth.js가 --badge-bg/--badge-fg를 인라인으로 넣어줌). 글자색은 배경 밝기에 맞춰 흰/검 자동.
   포인트 구간 칭호(브론즈~다이아)는 배지가 아니라 이름 글자색으로 보여줌(applyTierColorToName). */
.title-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.12em 0.55em;
  border-radius: 5px;
  background: var(--badge-bg, var(--accent));
  color: var(--badge-fg, var(--accent-text));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16), 0 1px 2px rgba(0, 0, 0, 0.35);
  font-size: 0.78em;
  font-weight: 700;
  line-height: 1.45;
  letter-spacing: 0.01em;
  /* 가운데 정렬 — 예전엔 baseline 기준(0.08em)이었는데, 메탈 반짝처럼 overflow:hidden이 걸린
     배지는 브라우저가 baseline을 배지 맨 아래로 잡아버려서 옆 글자보다 위로 떠 보였음. */
  vertical-align: middle;
  white-space: nowrap;
}

/* 칭호 카드 접기/펴기. 처음엔 <details>/<summary>로 했는데 브라우저 기본 동작이라 열고 닫을
   때 애니메이션 없이 뚝 끊기듯 전환돼서, 버튼 + 클래스 토글 + CSS 트랜지션 방식으로 바꿈.
   grid-template-rows를 0fr↔1fr로 트랜지션시키는 방식이라("auto 높이 애니메이션" 트릭) 내용
   높이를 JS로 재는 코드 없이도 부드럽게 늘었다 줄었다 함 — 자식(.collapse-inner)에
   overflow:hidden + min-height:0을 줘야 진짜 0으로 접힘.
   칭호 목록 자체도 /me 응답 + titles 테이블 조회가 끝나야 채워지는데, 그 사이 빈 칸이 잠깐
   보이는 "딜레이"가 느껴지지 않도록 마크업에 스켈레톤 카드 3개를 기본으로 넣어둠 — 데이터가
   오면 renderTitlesGrid()가 그 자리를 통째로 덮어씀(랭킹 스켈레톤 행과 같은 패턴). */
.collapse-toggle {
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  margin-bottom: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
}
/* 전역 button 스타일(칭호 카드 위 "button { background: var(--accent) }")이 :hover에서
   button:hover로 다시 끼어들어서(가상클래스가 있으면 명시도가 더 높아짐) 마우스만 올려도
   초록 배경이 도로 나타났었음 — hover/focus/active에서도 확실히 배경을 없앰. 키보드로
   포커스했을 땐 배경 채우기 대신 얇은 테두리로만 표시. */
.collapse-toggle:hover,
.collapse-toggle:focus,
.collapse-toggle:active {
  background: none;
}
.collapse-toggle:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.collapse {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.25s ease;
}
.collapse.open { grid-template-rows: 1fr; }
.collapse-inner { overflow: hidden; min-height: 0; }
.collapse-inner > *:first-child { margin-top: 12px; }
.details-arrow {
  width: 18px;
  height: 18px;
  color: var(--muted);
  flex-shrink: 0;
  transition: transform 0.2s ease;
}
.collapse-toggle[aria-expanded="true"] .details-arrow { transform: rotate(180deg); }

.status-msg { margin-top: 10px; font-size: 0.88rem; }
.status-msg.error { color: #ff8a8a; }
.status-msg.ok { color: var(--accent); }

.empty-state {
  color: var(--muted);
  padding: 24px 0;
  text-align: center;
}

/* 스켈레톤(로딩 중 표시). 데이터가 오기 전, 빈 화면 대신 카드/리스트 모양의
   회색 뼈대를 먼저 보여주고 자리를 채워 넣는 식으로 로딩을 표현함. */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--surface-2);
  border-radius: var(--radius-sm);
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.07), transparent);
  transform: translateX(-100%);
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  100% { transform: translateX(100%); }
}
.skeleton-line { height: 14px; }
.skeleton-pill { height: 28px; width: 110px; border-radius: 999px; }
.skeleton-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
}
.skeleton-row:last-child { border-bottom: none; }
.skeleton-row .skeleton-avatar { width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0; }
.skeleton-row .skeleton-line.grow { flex: 1; }

/* 관리자 페이지 */
.admin-search-row { display: flex; gap: 8px; }
.admin-search-row input[type="text"] {
  flex: 1;
  min-width: 0;
  font: inherit;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 10px 12px;
}
.admin-search-row input[type="text"]:focus { outline: none; border-color: var(--accent); }

.admin-user-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 14px 0;
  border-bottom: 1px solid var(--border);
}
.admin-user-row:last-child { border-bottom: none; }
.admin-user-row.is-banned { opacity: 0.6; }
.admin-user-info { flex: 1; min-width: 0; }
.admin-user-info strong { display: block; margin-bottom: 2px; }
.admin-user-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* 일괄 지급/차감 + 체크박스 선택 */
.admin-checkbox-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.9rem;
  color: var(--text-dim);
  cursor: pointer;
}
.admin-checkbox-label input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }
/* .shop-item-field[hidden]와 같은 이유 — display:inline-flex를 주는 author 규칙이 브라우저
   기본 [hidden] 규칙보다 우선순위가 높아서 JS로 .hidden=true를 줘도 안 숨겨짐. */
.admin-checkbox-label[hidden] { display: none; }
.admin-select-all-row { padding-bottom: 10px; margin-bottom: 4px; border-bottom: 1px solid var(--border); }
.admin-row-checkbox { flex-shrink: 0; }
.admin-bulk-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
#admin-bulk-selected-count { margin-top: 10px; margin-bottom: 0; }

/* 관리자 페이지 상단 현황 요약 카드 */
.admin-total-points { margin-bottom: 16px; }
.admin-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 10px;
}
.admin-stat-tile {
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 14px 10px;
  text-align: center;
}
.admin-stat-value {
  display: block;
  /* 전체 발행 포인트처럼 자릿수가 계속 늘어나는 값이 있어서, .balance와 같은 이유로
     clamp + word-break을 씀 — 타일 폭(최소 110px)을 넘기지 않고 알아서 줄어듦. */
  font-size: clamp(1rem, 4vw, 1.4rem);
  font-weight: 700;
  color: var(--accent);
  word-break: break-all;
}
.admin-stat-label {
  display: block;
  margin-top: 4px;
  font-size: 0.78rem;
  color: var(--muted);
}

/* 유저 목록에서 이름을 눌러 상세 모달을 여는 버튼 — <strong>처럼 보이되 클릭 가능함을
   살짝 드러내려고 hover에서만 밑줄. */
.admin-user-name-btn {
  display: block;
  background: none;
  border: none;
  padding: 0;
  margin-bottom: 2px;
  font: inherit;
  font-weight: 700;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.admin-user-name-btn:hover { color: var(--accent); text-decoration: underline; background: none; }

/* 유저 상세 모달 (notice-modal 재사용 + 내용이 길어질 수 있어서 자체 스크롤 추가) */
.admin-user-modal {
  width: min(560px, calc(100vw - 32px));
  max-height: 85vh;
  overflow-y: auto;
}
.admin-user-detail-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 8px;
  margin: 14px 0;
}
.admin-user-detail-stat {
  background: var(--surface-2);
  border-radius: var(--radius-sm);
  padding: 10px;
  text-align: center;
}
.admin-user-detail-stat strong { display: block; font-size: 1.05rem; }
.admin-user-detail-stat span { display: block; margin-top: 2px; font-size: 0.76rem; color: var(--muted); }

/* 관리자 > 상점 내역 행 오른쪽의 처리 영역 — 처리 전엔 강조색 "처리 완료" 버튼(아직 할 일이
   눈에 띄게), 처리 후엔 "✓ 처리됨" + 작은 "되돌리기" 링크. 처리된 행은 내용을 흐리게. */
.spend-process-area { flex: 0 0 auto; display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.spend-process-btn { padding: 6px 14px; font-size: 0.82rem; }
.spend-processed-badge { font-size: 0.82rem; font-weight: 600; color: var(--muted); }
.spend-unprocess-btn { font-size: 0.76rem; text-decoration: underline; text-underline-offset: 2px; }
/* 칭호 상점 구매 — 사는 순간 자동 지급이라 처리 버튼 대신 표시만(0045_title_purchase_flag.sql). */
.spend-auto-badge { font-size: 0.78rem; font-weight: 600; color: var(--muted); }
/* 체크박스 자리 비워두기 — 보이지 않는 체크박스를 그대로 둬서 다른 줄과 이름 시작 위치를 맞춤. */
.spend-select-placeholder { visibility: hidden; }
.points-log-row.is-processed .points-log-who,
.points-log-row.is-processed .points-log-amount,
.points-log-row.is-processed .points-log-time { opacity: 0.5; }
.admin-amount-input {
  width: 90px;
  font: inherit;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 8px 10px;
}
.admin-amount-input:focus { outline: none; border-color: var(--accent); }
.admin-ban-btn.is-banned { border-color: var(--danger); color: #ff8a8a; }
.admin-ban-btn.is-banned:hover { border-color: var(--danger); color: #ff8a8a; }

.admin-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 16px; }
.admin-tab-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  font-size: 0.9rem;
}
.admin-tab-btn:hover { background: var(--surface-2); color: var(--text); }
.admin-tab-btn.active { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }

/* who(가변폭) / amount·time(고정폭)로 나눠서 행마다 글자 길이가 달라도 금액·시간 칸이
   세로로 딱 맞게 정렬되도록 함 (who만 가변이라 나머지 두 칸은 항상 같은 자리에 옴). */
.points-log-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.9rem;
}
.points-log-row:last-child { border-bottom: none; }
.points-log-who { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.points-log-who strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.points-log-reason { color: var(--muted); font-size: 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.points-log-amount { flex: 0 0 84px; width: 84px; text-align: right; font-weight: 700; white-space: nowrap; }
.points-log-amount.positive { color: var(--accent); }
.points-log-amount.negative { color: var(--danger); }
.points-log-time { flex: 0 0 160px; width: 160px; text-align: right; color: var(--muted); font-size: 0.78rem; white-space: nowrap; }
/* 관리자 지급/차감 행에만 실행취소 버튼/"취소됨" 표시가 뜨는 칸 — 다른 종류 행(출석체크,
   상점 사용 등)은 내용이 비어도 이 칸의 너비만큼은 그대로 차지해서 금액·시간 칸처럼 세로
   정렬이 흐트러지지 않게 함. */
.points-log-undo-area { flex: 0 0 72px; width: 72px; text-align: right; white-space: nowrap; }
.points-log-undo-btn { font-size: 0.78rem; padding: 2px 4px; }
.points-log-undone-label { color: var(--muted); font-size: 0.78rem; }

@media (max-width: 560px) {
  .points-log-row { flex-wrap: wrap; }
  .points-log-who { flex-basis: 100%; }
  .points-log-amount { flex: 0 0 auto; width: auto; text-align: left; }
  .points-log-time { flex: 1 1 auto; width: auto; text-align: right; }
  .points-log-undo-area { flex: 0 0 auto; width: auto; text-align: right; }
}

.pagination { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; margin-top: 16px; }
.page-btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-dim);
  border-radius: var(--radius-sm);
  padding: 6px 12px;
  font-size: 0.85rem;
  min-width: 36px;
}
.page-btn:hover:not(:disabled) { background: var(--surface-2); color: var(--text); }
.page-btn.active { background: var(--accent); color: var(--accent-text); border-color: var(--accent); }
.page-btn:disabled { opacity: 0.4; }
.page-ellipsis { color: var(--muted); padding: 6px 2px; font-size: 0.85rem; }

/* 출석체크 — 달력 UI. */
.attendance-header {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-bottom: 14px;
}
.attendance-header strong { min-width: 110px; text-align: center; font-size: 1.05rem; }
.attendance-nav-btn {
  width: 32px;
  height: 32px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.attendance-nav-btn svg { width: 16px; height: 16px; }
.attendance-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  text-align: center;
  color: var(--muted);
  font-size: 0.82rem;
  margin-bottom: 6px;
}
.attendance-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}
.attendance-day {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 0.88rem;
}
.attendance-day.is-empty { background: none; }
.attendance-day.is-today {
  box-shadow: inset 0 0 0 1px var(--accent);
  color: var(--text);
  font-weight: 600;
}
.attendance-day.is-attended {
  background: var(--accent-dim);
  color: var(--accent);
  font-weight: 600;
}
.attendance-day.is-attended.is-today { background: var(--accent); color: var(--accent-text); }
.attendance-checkin-btn { width: 100%; margin-top: 12px; }

/* 투표(승부예측) — 치지직 승부예측 스타일: 항목마다 걸린 포인트 비율만큼 배경이 채워지는
   퍼센트 바 + 배당률 표기. .predict-option은 .card처럼 별도 박스가 아니라 카드 하나 안에서
   항목별로 쌓이는 행이라 padding/border-radius만 갖고 배경은 없음(바 자체가 배경 역할). */
.predict-title { margin: 0 0 4px; font-size: 1.1rem; font-family: var(--font-logo); word-break: break-word; }
.predict-countdown {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 0.85rem;
  margin-bottom: 14px;
}
/* [hidden] 속성이 있어도 .predict-countdown { display: inline-flex } 같은 클래스 선택자
   규칙이 브라우저 기본 [hidden]{display:none} UA 규칙보다 우선 적용돼서 안 가려지는
   문제 — .sidebar-nav a[hidden] 등과 같은 이유로 여기도 override 필요. */
.predict-countdown[hidden] { display: none; }
.predict-countdown.is-urgent { color: #ff8a8a; }
.predict-status-banner {
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-dim);
  font-size: 0.9rem;
  margin-bottom: 14px;
}
.predict-status-banner.win { background: var(--accent-dim); color: var(--accent); font-weight: 600; }
.predict-status-banner.lose { background: var(--danger-dim); color: #ff8a8a; }

.predict-option-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 14px; }
.predict-option {
  position: relative;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  overflow: hidden;
  cursor: pointer;
  background: var(--surface-2);
}
.predict-option:hover { border-color: var(--accent); }
.predict-option.selected { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.predict-option.is-winner { border-color: var(--accent); }
.predict-option.is-loser { opacity: 0.6; }
.predict-option.disabled { cursor: default; }
/* 이미 베팅했거나 투표가 끝나서 선택 불가능한 항목은 마우스를 올려도 강조되면 안 됨
   (클릭 리스너는 JS에서 이미 안 붙이지만, hover 강조는 별도 CSS라 따로 막아야 함).
   단, 내 선택(.selected)이나 당첨 항목(.is-winner)은 원래도 항상 accent 테두리인데
   이 규칙이 class 2개(.predict-option.disabled) + :hover라 specificity가 더 높아서
   hover 시 그 accent 테두리를 var(--border)로 덮어써버리는 문제가 있었음(테두리는
   흐려지는데 .selected의 box-shadow 링은 그대로라 "테두리가 얇아지는" 것처럼 보임) —
   :not()으로 그 두 케이스는 이 규칙에서 아예 제외해서 원래 accent 테두리가 유지되게 함. */
.predict-option.disabled:not(.selected):not(.is-winner):hover { border-color: var(--border); }
/* 걸린 포인트 비율만큼 채워지는 바 — 실제 색은 배경 위에 깔리는 레이어라 텍스트보다 아래(z-index 0),
   내용은 그 위(z-index 1)에 얹음. 폭은 JS가 인라인 style.width로 퍼센트를 직접 넣음. */
.predict-option-bar {
  position: absolute;
  inset: 0;
  width: 0%;
  background: var(--accent-dim);
  transition: width 0.3s ease;
  z-index: 0;
}
.predict-option.is-winner .predict-option-bar { background: rgba(0, 229, 160, 0.28); }
.predict-option-content {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.predict-option-label { font-weight: 600; display: flex; align-items: center; gap: 6px; min-width: 0; }
.predict-option-label .my-pick-badge {
  flex-shrink: 0;
  font-size: 0.7rem;
  font-weight: 700;
  color: var(--accent-text);
  background: var(--accent);
  border-radius: 4px;
  padding: 1px 5px;
}
.predict-option-stats { display: flex; align-items: baseline; gap: 8px; flex-shrink: 0; color: var(--text-dim); font-size: 0.85rem; }
.predict-option-percent { font-weight: 700; color: var(--text); }
.predict-option-multiplier { color: var(--muted); }

.predict-bet-form {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 4px;
}
/* 이미 베팅했거나(내 베팅 노트로 대체) 투표가 끝나면 hidden 처리하는데, 위의 class
   선택자 display:flex 규칙이 기본 [hidden]{display:none} UA 규칙을 덮어써서 안 가려지던
   문제 — .predict-countdown과 같은 이유로 override 추가. */
.predict-bet-form[hidden] { display: none; }
.predict-bet-form input {
  flex: 1 1 140px;
  min-width: 0;
  font: inherit;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 10px 12px;
}
.predict-bet-form input:focus { outline: none; border-color: var(--accent); }
.predict-my-bet-note { margin-top: 10px; font-size: 0.85rem; color: var(--text-dim); }

/* 투표 항목 추가/삭제(생성 모달) — 항목명 입력칸 + 2개 초과일 때만 보이는 삭제 X 버튼. */
.predict-create-option-row { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.predict-create-option-row .notice-title-input { margin-bottom: 0; flex: 1 1 auto; }
.predict-option-remove-btn {
  flex-shrink: 0;
  width: 32px;
  height: 32px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  line-height: 1;
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  border-radius: var(--radius-sm);
}
.predict-option-remove-btn:hover { border-color: var(--danger); color: #ff8a8a; background: transparent; }
.predict-add-option-btn { width: 100%; margin-bottom: 10px; }

.predict-duration-row { display: flex; gap: 8px; margin-bottom: 10px; }
.predict-duration-option {
  flex: 1;
  text-align: center;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text-dim);
  font-size: 0.9rem;
  cursor: pointer;
}
.predict-duration-option input { display: none; }
.predict-duration-option.selected { border-color: var(--accent); background: var(--accent-dim); color: var(--accent); font-weight: 600; }

/* 관리자 투표 현황(admin.html "투표" 탭) — 개별 베팅 내역(비익명) 목록. points-log-row와
   비슷한 who/amount 2단 구성을 재사용하되 who 칸에 선택한 항목명도 같이 보여줌. */
.predict-admin-bet-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.88rem;
}
.predict-admin-bet-row:last-child { border-bottom: none; }
.predict-admin-bet-who { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.predict-admin-bet-option { color: var(--muted); font-size: 0.8rem; margin-left: 6px; }
.predict-admin-bet-amount { flex-shrink: 0; font-weight: 700; white-space: nowrap; }
.predict-admin-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.predict-admin-actions button.danger { border-color: var(--danger); color: #ff8a8a; }
.predict-admin-actions button.danger:hover { border-color: var(--danger); color: #ff8a8a; background: transparent; }

/* ============================================================================
   폰 화면 다듬기 — 파일 맨 끝에 둬서 위쪽의 같은 우선순위 규칙들보다 나중에 적용되게 함.
   ============================================================================ */
@media (max-width: 720px) {
  /* 홈 화면 제목("유진 팬보드")은 폰에선 상단바 로고와 겹쳐서 숨김. */
  .home-heading { display: none; }
}

@media (max-width: 560px) {
  /* 관리자 > 유저 행: 위쪽 줄 [☐ 이름/잔액], 아래 줄 [수량 입력(남는 폭 전부)][지급][차감][밴]. */
  .admin-user-row { gap: 10px 12px; }
  .admin-user-actions { flex: 1 1 100%; flex-wrap: nowrap; min-width: 0; }
  /* 숫자 입력칸은 브라우저 기본 최소 폭(약 200px)이 있어서 그대로 두면 줄이 화면 밖으로 밀려남 —
     기본 폭을 0으로 두고 남는 공간만큼 늘어나게 함. */
  .admin-user-actions .admin-amount-input { flex: 1 1 auto; width: 0; min-width: 0; }
  .admin-user-actions button { flex-shrink: 0; white-space: nowrap; padding: 10px 12px; }

  /* 관리자 > 일괄 지급/차감, 상점 내역 일괄 처리: 버튼들을 2칸 격자로 가지런하게(수량 입력은 한 줄 통째로). */
  .admin-bulk-row { display: grid; grid-template-columns: 1fr 1fr; }
  .admin-bulk-row .admin-amount-input { grid-column: 1 / -1; width: 100%; }
  .admin-bulk-row button { padding: 10px 8px; font-size: 0.88rem; }

  /* 관리자 > 상점 내역 행: 5줄로 흩어지던 걸 2줄로.
       [☐] 이름 / 사용 내역          -100P
       [☐] 날짜·시간        [처리 완료]  */
  #spend-log-list .points-log-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "sel who  amount"
      "sel time done";
    column-gap: 12px;
    row-gap: 6px;
    align-items: center;
  }
  #spend-log-list .admin-row-checkbox { grid-area: sel; }
  #spend-log-list .points-log-who { grid-area: who; }
  #spend-log-list .points-log-amount { grid-area: amount; width: auto; text-align: right; }
  #spend-log-list .points-log-time { grid-area: time; width: auto; text-align: left; }
  #spend-log-list .spend-process-area { grid-area: done; justify-self: end; }

  /* 투표 > 베팅 입력: 입력칸이 좁아 안내 문구가 잘려서, 폰에선 입력칸·버튼을 각각 한 줄씩. */
  .predict-bet-form input,
  .predict-bet-form button { flex: 1 1 100%; }
  /* 투표 > 관리자 버튼들(참여자 보기/정산/취소): 폭이 제각각 들쭉날쭉해서 폰에선 전부 꽉 찬 폭으로. */
  .predict-admin-actions { flex-direction: column; }
  .predict-admin-actions > *,
  #predict-admin-view-bets-btn { width: 100%; }
}

/* ── 칭호 색 고르기 (createTitleColorPicker, chzzk-auth.js) ───────────────── */
.title-color-picker { display: flex; flex-direction: column; gap: 10px; }
.title-color-swatches { display: flex; flex-wrap: wrap; gap: 8px; }
.title-color-swatch {
  position: relative;
  width: 30px;
  height: 30px;
  min-width: 0;
  padding: 0;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.14);
  background: var(--swatch);
  cursor: pointer;
  flex: 0 0 auto;
  transition: transform 0.12s ease, box-shadow 0.12s ease;
}
.title-color-swatch:hover { transform: scale(1.08); background: var(--swatch); }
.title-color-swatch.is-selected {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--text);
}
.title-color-swatch.is-selected::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: var(--swatch-fg, #fff);
}
/* 색상표에서 직접 고르기 — "+" 아이콘 동그라미. 직접 고른 색이 있으면 그 색으로 채워짐. 실제
   input[type=color]는 동그라미 전체를 덮는 투명 버튼 역할. */
.title-color-custom {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: transparent;
  border: 2px dashed rgba(255, 255, 255, 0.28);
  color: var(--muted);
}
.title-color-custom:hover { background: rgba(255, 255, 255, 0.06); }
.title-color-custom.is-selected { background: var(--swatch); border-style: solid; }
.title-color-custom.is-selected:hover { background: var(--swatch); }
.title-color-custom-icon { width: 15px; height: 15px; }
.title-color-custom.is-selected .title-color-custom-icon { display: none; }
/* 무지개(특수 스타일) 동그라미 */
.title-color-swatch--rainbow,
.title-color-swatch--rainbow:hover {
  background: conic-gradient(#ff4d5a, #ff922b, #ffd43b, #94d82d, #00e5a0, #5dc8ff, #9b6bff, #ff6bb5, #ff4d5a);
}
.title-color-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
  border: 0;
  padding: 0;
}
.title-color-preview {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--surface-2, rgba(255, 255, 255, 0.04));
  border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
}
.title-color-preview-label { font-size: 0.78rem; color: var(--muted); margin-right: 2px; }
.title-color-preview-name { font-weight: 600; }
.title-color-hex-field {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.72rem;
  color: var(--muted);
  letter-spacing: 0.04em;
}
.title-color-hex-input {
  width: 92px;
  padding: 5px 8px;
  border-radius: 7px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font: 600 0.85rem ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  text-transform: lowercase;
}
.title-color-hex-input:focus { outline: none; border-color: var(--accent); }
.title-color-hex-input.is-invalid { border-color: var(--danger); }

/* ── 칭호 상점 카드: 상품명 아래에 실제로 받게 될 칭호 배지를 보여줌 ── */
.shop-item-title-preview { margin: 2px 0 8px; font-size: 1rem; }
.shop-item-stock-help { font-size: 0.78rem; margin: 2px 0 0; line-height: 1.5; }

/* ── 관리자 상점: 판매 중지된 상품은 아래 접힌 영역으로 모아둠 ── */
.shop-inactive-group {
  margin-top: 18px;
  border: 1px dashed var(--border, rgba(255, 255, 255, 0.12));
  border-radius: 12px;
  padding: 0 14px;
}
.shop-inactive-group > summary {
  cursor: pointer;
  padding: 12px 0;
  color: var(--muted);
  font-size: 0.9rem;
  list-style: none;
}
.shop-inactive-group > summary::-webkit-details-marker { display: none; }
.shop-inactive-group > summary::before { content: "▸ "; }
.shop-inactive-group[open] > summary::before { content: "▾ "; }
.shop-inactive-group .shop-grid { padding-bottom: 14px; }
.shop-item-owner-note { font-size: 0.8rem; color: var(--muted); margin: 0 0 8px; }

/* ── 관리자 상점: 상품 순서 변경(드래그) — shop.html의 "순서 변경" ── */
.shop-reorder-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; width: 100%; }
.shop-reorder-bar[hidden] { display: none; }
.shop-reorder-hint { flex: 1 1 220px; color: var(--muted); font-size: 0.85rem; line-height: 1.5; }
/* 안내 문구는 마우스(카드 아무 데나)와 터치(손잡이로만)가 달라서 입력 방식에 맞는 것만 보여줌. */
.shop-reorder-hint .hint-coarse { display: none; }
@media (pointer: coarse) {
  .shop-reorder-hint .hint-fine { display: none; }
  .shop-reorder-hint .hint-coarse { display: inline; }
}
@media (max-width: 640px) {
  .shop-reorder-hint { flex-basis: 100%; }
  .shop-reorder-bar button { flex: 1 1 0; }
}
.shop-section-toolbar button[hidden] { display: none; }
/* 순서 바꾸는 동안엔 판매 중지된 상품 접힘 영역은 안 보이게(그쪽은 순서 변경 대상이 아님). */
.shop-reordering .shop-inactive-group { display: none; }
/* 카드 위치 계산(offsetTop/Left)의 기준이 그리드가 되게 함. */
.shop-grid.reordering { position: relative; }
.shop-item.reorder-card {
  position: relative;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  border-style: dashed;
}
.shop-item.reorder-card:hover { border-color: var(--accent); }
.shop-item.reorder-card h3 { padding-right: 40px; }
.shop-item-drag-handle {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 36px;
  height: 36px;
  padding: 0;
  display: grid;
  place-items: center;
  background: var(--surface-2);
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: grab;
  /* 폰에서 손잡이를 잡고 끌 때 화면이 같이 스크롤되지 않게. */
  touch-action: none;
}
.shop-item-drag-handle:hover,
.shop-item-drag-handle:focus-visible { background: var(--surface-2); color: var(--accent); border-color: var(--accent); }
.shop-item-drag-handle svg { width: 18px; height: 18px; pointer-events: none; }
/* 끄는 동안 원래 자리(= 놓으면 들어갈 자리)는 흐린 점선 칸으로. */
.shop-item.drag-placeholder { opacity: 0.35; border-color: var(--accent); }
/* 손가락/마우스를 따라다니는 카드 사본. */
.shop-item.shop-drag-ghost {
  position: fixed;
  z-index: 1000;
  margin: 0;
  pointer-events: none;
  cursor: grabbing;
  border-color: var(--accent);
  border-style: solid;
  box-shadow: 0 14px 36px rgba(0, 0, 0, 0.5);
  opacity: 0.96;
}
body.shop-dragging,
body.shop-dragging * { cursor: grabbing !important; user-select: none; -webkit-user-select: none; }

/* 화면엔 안 보이고 화면 읽기 프로그램만 읽는 글(예: 순서 변경 키보드 안내). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── 출석: 누적 출석/다음 보너스 안내 ── */
.attendance-progress { margin: 10px 0 0; text-align: center; font-size: 0.88rem; color: var(--muted); }
.attendance-progress strong { color: var(--accent); }

/* ── 관리자 유저 상세: 보유 칭호 + 칭호 지급 ── */
/* 유저 상세 모달의 칭호 요약 줄 — 자세한 건 "칭호 관리" 버튼(별도 모달)에서. */
.admin-user-titles-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 6px 0 4px; padding: 10px 12px; border-radius: 10px; background: rgba(255, 255, 255, 0.03); border: 1px solid var(--border, rgba(255, 255, 255, 0.08)); }
.admin-user-titles-row .admin-user-section-heading { margin: 0 0 4px; }
.admin-user-titles-summary p { margin: 0; font-size: 0.85rem; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.admin-user-titles-row > button { flex: 0 0 auto; white-space: nowrap; }
.admin-user-section-heading { margin: 16px 0 8px; font-size: 0.95rem; }
.admin-user-title-list { display: flex; flex-wrap: wrap; gap: 8px; }
.admin-user-title-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 8px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
  font-size: 0.85rem;
}
.admin-user-title-chip .chip-meta { color: var(--muted); font-size: 0.75rem; }
.admin-user-title-chip button { padding: 2px 8px; font-size: 0.75rem; min-height: 0; }
.admin-title-grant-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid var(--border, rgba(255, 255, 255, 0.08));
}
.admin-title-grant-actions { display: flex; gap: 8px; justify-content: flex-end; }
.title-card h3 .title-badge { font-size: 0.95rem; }
.admin-title-grant-form .status-msg:empty { display: none; }

/* 무지개 칭호(특수 스타일 "rainbow") — 무지개 그라데이션이 천천히 흘러감. 흰 글자 + 그림자로
   어느 색 위에서도 읽히게. 움직임 줄이기 설정을 켠 기기에선 멈춰 있음. */
.title-badge--rainbow {
  background: linear-gradient(90deg, #ff4d5a, #ff922b, #ffd43b, #94d82d, #00e5a0, #5dc8ff, #9b6bff, #ff6bb5, #ff4d5a);
  background-size: 200% 100%;
  color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
  animation: title-badge-rainbow 6s linear infinite;
}
@keyframes title-badge-rainbow {
  from { background-position: 0% 50%; }
  to { background-position: 200% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .title-badge--rainbow { animation: none; }
}

/* 칭호 상품 카드의 상품명([네루] 등)은 칭호 색과 상관없이 흰색 고정(이미 산 카드도) — 칭호 색은
   바로 아래 배지 미리보기로만 보여줌. */
.shop-item.title-item h3,
.shop-item.title-item.owned h3 { color: var(--text); }

/* ── 칭호 디자인 옵션 (titleBadgeHtml이 붙이는 클래스) ─────────────────────────────
   색은 --badge-bg(기본색)/--badge-light(밝게)/--badge-dark(어둡게)/--badge-fg(글자)로 들어옴.
   새 디자인을 추가하려면 chzzk-auth.js의 TITLE_DESIGNS에 한 줄 + 여기 .title-badge--<id> 규칙. */
.title-badge { position: relative; }
.title-badge .tb-icon { width: 1.05em; height: 1.05em; margin-right: 0.2em; flex: 0 0 auto; }

/* 메탈 반짝: 칭호 색에서 뽑은 밝은/어두운 색으로 금속 광택 + 몇 초마다 빛줄기가 지나감.
   빛줄기는 배지 안에 깔린 .tb-sweep(배지 크기로 잘라줌) 안에서만 움직임 — 예전처럼 배지 자체에
   overflow:hidden을 걸면 모서리에 튀어나오는 반짝이 별까지 잘려서 따로 뺌. */
.title-badge--shine {
  background: linear-gradient(135deg, var(--badge-light), var(--badge-bg) 42%, var(--badge-dark) 72%, var(--badge-light));
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.35), 0 1px 3px rgba(0, 0, 0, 0.5);
}
.title-badge .tb-sweep {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  pointer-events: none;
}
.title-badge .tb-sweep::after {
  content: "";
  position: absolute;
  top: -50%;
  left: -60%;
  width: 40%;
  height: 200%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.85), transparent);
  transform: rotate(20deg);
  animation: title-badge-sweep 2.8s ease-in-out infinite;
}
@keyframes title-badge-sweep {
  0%, 55% { left: -60%; }
  100% { left: 130%; }
}
.title-badge--shine.title-badge--rainbow {
  background: linear-gradient(90deg, #ff4d5a, #ff922b, #ffd43b, #94d82d, #00e5a0, #5dc8ff, #9b6bff, #ff6bb5, #ff4d5a);
  background-size: 200% 100%;
}

/* 빛나는 테두리: 어두운 배지 + 칭호 색 테두리 빛이 빙글빙글 돌고 글자는 금속 느낌 */
@property --tb-angle { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
.title-badge--glow {
  isolation: isolate;
  background: #121417;
  box-shadow: 0 0 8px color-mix(in srgb, var(--badge-bg, #ffffff) 35%, transparent);
  /* 도는 테두리 색 목록. 각도(--tb-angle)는 아래 ::before에서 직접 써야 돌아감 — 여기서
     conic-gradient(from var(--tb-angle), …)까지 만들어 넘기면 배지 자신의 0도로 계산된 채로
     ::before에 물려줘서 테두리가 멈춰 있었음. */
  --glow-stops: var(--badge-bg), var(--badge-light), var(--badge-bg), var(--badge-dark), var(--badge-bg);
}
.title-badge--glow::before {
  content: "";
  position: absolute;
  inset: -1.5px;
  border-radius: 6.5px;
  z-index: -2;
  background: conic-gradient(from var(--tb-angle), var(--glow-stops));
  animation: title-badge-spin 3s linear infinite;
}
.title-badge--glow::after {
  content: "";
  position: absolute;
  inset: 1px;
  border-radius: 4px;
  z-index: -1;
  background: #121417;
}
.title-badge--glow .tb-text {
  background: linear-gradient(180deg, var(--badge-light), var(--badge-fg) 55%, var(--badge-bg));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.title-badge--glow .tb-icon { color: var(--badge-fg); }
@keyframes title-badge-spin { to { --tb-angle: 360deg; } }
.title-badge--glow.title-badge--rainbow {
  background: #121417;
  animation: none;
  text-shadow: none;
  box-shadow: 0 0 8px rgba(155, 107, 255, 0.35);
  --glow-stops: #ff4d5a, #ff922b, #ffd43b, #94d82d, #00e5a0, #5dc8ff, #9b6bff, #ff6bb5, #ff4d5a;
}
.title-badge--glow.title-badge--rainbow .tb-text {
  background: linear-gradient(90deg, #ff4d5a, #ff922b, #ffd43b, #94d82d, #00e5a0, #5dc8ff, #9b6bff, #ff6bb5, #ff4d5a);
  background-size: 200% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  animation: title-badge-rainbow 6s linear infinite;
}
.title-badge--glow.title-badge--rainbow .tb-icon { color: #ffd43b; }

/* 유리: 반투명 유리 안에 칭호 색이 비치는 느낌(정지). 글자색은 JS가 밝게 뽑아줌. */
.title-badge--glass {
  background: linear-gradient(160deg, color-mix(in srgb, var(--badge-bg) 40%, transparent), color-mix(in srgb, var(--badge-bg) 14%, transparent));
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), inset 0 0 0 1px color-mix(in srgb, var(--badge-bg) 55%, transparent), 0 2px 6px rgba(0, 0, 0, 0.35);
}
.title-badge--glass.title-badge--rainbow {
  background: linear-gradient(90deg, rgba(255, 77, 90, 0.38), rgba(255, 146, 43, 0.34), rgba(255, 212, 59, 0.32), rgba(0, 229, 160, 0.32), rgba(93, 200, 255, 0.34), rgba(155, 107, 255, 0.38), rgba(255, 107, 181, 0.36), rgba(255, 77, 90, 0.38));
  background-size: 200% 100%;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35), inset 0 0 0 1px rgba(255, 255, 255, 0.28), 0 2px 6px rgba(0, 0, 0, 0.35);
}

/* ── 두 가지 색: 그라데이션(--duo) — 디자인마다 두 색을 같이 씀 ── */
.title-badge--duo { background: linear-gradient(90deg, var(--badge-bg), var(--badge-bg2)); }
.title-badge--duo:not(.title-badge--shine):not(.title-badge--glow):not(.title-badge--glass) { text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); }
.title-badge--shine.title-badge--duo {
  background: linear-gradient(135deg, var(--badge-light), var(--badge-bg) 32%, var(--badge-bg2) 68%, var(--badge-light2));
}
.title-badge--glow.title-badge--duo {
  --glow-stops: var(--badge-bg), var(--badge-bg2), var(--badge-bg), var(--badge-bg2), var(--badge-bg);
}
.title-badge--glow.title-badge--duo .tb-text,
.title-badge--glass.title-badge--duo .tb-text {
  background: linear-gradient(90deg, var(--badge-light), var(--badge-light2));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.title-badge--glow.title-badge--duo .tb-icon,
.title-badge--glass.title-badge--duo .tb-icon { color: var(--badge-light); }
.title-badge--glass.title-badge--duo {
  background: linear-gradient(90deg, color-mix(in srgb, var(--badge-bg) 40%, transparent), color-mix(in srgb, var(--badge-bg2) 40%, transparent));
}

/* ── 두 가지 색: 배경색 + 글자색(--ink) — 글자색(--badge-fg)은 JS가 두 번째 색으로 넣어줌 ── */
.title-badge--glow.title-badge--ink .tb-text {
  background: none;
  color: var(--badge-fg);
}

/* ── 반짝이 별: 배지 모서리에서 작은 별이 번갈아 반짝(어느 디자인에나 같이 붙음) ── */
.title-badge .tb-stars { position: absolute; inset: 0; pointer-events: none; }
.title-badge .tb-star {
  position: absolute;
  width: 0.55em;
  height: 0.55em;
  color: #fff;
  opacity: 0;
  filter: drop-shadow(0 0 2px var(--badge-bg2, var(--badge-bg, #ffd43b)));
  animation: title-badge-twinkle 2.2s ease-in-out infinite;
}
.title-badge .tb-star--1 { right: -0.28em; top: -0.3em; }
.title-badge .tb-star--2 { left: -0.22em; bottom: -0.22em; width: 0.45em; height: 0.45em; animation-delay: 0.8s; }
.title-badge .tb-star--3 { right: 32%; top: -0.34em; width: 0.38em; height: 0.38em; animation-delay: 1.5s; }
.title-badge--rainbow .tb-star { filter: drop-shadow(0 0 2px #ff6bb5); }
@keyframes title-badge-twinkle {
  0%, 100% { opacity: 0; transform: scale(0.3) rotate(0deg); }
  50% { opacity: 1; transform: scale(1) rotate(45deg); }
}

@media (prefers-reduced-motion: reduce) {
  .title-badge .tb-sweep { display: none; }
  .title-badge--glow::before, .title-badge--glow .tb-text { animation: none; }
  .title-badge .tb-star { animation: none; opacity: 1; transform: scale(0.85) rotate(45deg); }
}

/* ── 칭호 꾸미기 UI: 디자인 선택 줄 ── */
.title-design-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
.title-design-label { font-size: 0.78rem; color: var(--muted); }
.title-design-options { display: flex; flex-wrap: wrap; gap: 6px; }
.title-design-option,
.title-design-option:hover {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 10px;
  border-radius: 9px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-weight: 500;
  font-size: 0.82rem;
}
.title-design-option:hover { border-color: var(--muted); }
.title-design-option.is-selected { border-color: var(--accent); color: var(--text); box-shadow: 0 0 0 1px var(--accent); }
.title-design-sample { font-size: 0.95rem; display: inline-flex; }
.title-extra-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
/* 아이콘 고르기: "아이콘 붙이기 ›" 버튼 → 작은 창(모달)에 아이콘 격자. 고르면 바로 닫힘. */
.title-icon-toggle,
.title-icon-toggle:hover {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 10px;
  border-radius: 9px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text-dim);
  font-size: 0.82rem;
  font-weight: 500;
}
.title-icon-toggle:hover { border-color: var(--muted); }
.title-icon-toggle.has-icon { border-color: var(--accent); color: var(--text); }
.title-icon-current { display: inline-flex; align-items: center; gap: 6px; }
.title-icon-toggle .title-icon-glyph { width: 16px; height: 16px; }
.title-icon-chevron { width: 14px; height: 14px; }
.title-icon-dialog {
  width: min(420px, calc(100vw - 32px));
  max-height: min(560px, 80vh);
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6);
  overflow: hidden;
}
.title-icon-dialog[open] { display: flex; flex-direction: column; }
.title-icon-dialog::backdrop { background: rgba(0, 0, 0, 0.55); }
.title-icon-dialog-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 12px 10px 16px;
  border-bottom: 1px solid var(--border);
  flex: 0 0 auto;
}
.title-icon-dialog-head strong { font-size: 0.95rem; }
.title-icon-dialog-preview { font-size: 0.95rem; display: inline-flex; }
.title-icon-dialog-close,
.title-icon-dialog-close:hover {
  margin-left: auto;
  width: 32px;
  height: 32px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
}
.title-icon-dialog-close:hover { background: var(--surface-2); color: var(--text); }
.title-icon-dialog-close svg { width: 18px; height: 18px; }
.title-icon-dialog .title-icon-grid { padding: 12px 14px 16px; overflow-y: auto; }
.title-icon-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(36px, 1fr)); gap: 6px; }
.title-icon-option,
.title-icon-option:hover {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 36px;
  min-width: 0;
  padding: 0;
  border-radius: 8px;
  border: 1px solid transparent;
  background: var(--surface-2, rgba(255, 255, 255, 0.04));
  color: var(--text-dim);
}
@media (hover: hover) { .title-icon-option:hover { border-color: var(--muted); color: var(--text); } }
.title-icon-option.is-selected { border-color: var(--accent); color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.title-icon-option .title-icon-glyph { width: 20px; height: 20px; }
.title-icon-option--none { grid-column: span 2; font-size: 0.78rem; font-weight: 600; }
.title-icon-group-label { grid-column: 1 / -1; font-size: 0.72rem; color: var(--muted); font-weight: 600; letter-spacing: 0.04em; margin: 6px 0 -2px; }
.title-option-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; color: var(--text-dim); cursor: pointer; }
.title-option-toggle input { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; }

/* ── 칭호 꾸미기 UI: 색 줄(첫 번째/두 번째) + 두 가지 색 섞기 ── */
.title-color-group { display: flex; flex-direction: column; gap: 8px; }
.title-color-group[hidden] { display: none; }
.title-color-group-head { display: flex; align-items: center; gap: 8px; min-height: 28px; }
.title-color-group-label { font-size: 0.78rem; color: var(--muted); }
.title-duo-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; padding-top: 2px; }
.title-duo-bar .title-mix-options,
.title-duo-bar .title-duo-swap { display: none; }
.title-duo-bar.is-on .title-mix-options { display: flex; }
.title-duo-bar.is-on .title-duo-swap { display: inline-flex; }
.title-duo-note { display: none; font-size: 0.78rem; color: var(--muted); }
.title-duo-bar.is-rainbow .title-duo-note { display: inline; }
.title-duo-bar.is-rainbow .title-duo-toggle { opacity: 0.5; cursor: not-allowed; }
.title-mix-options { gap: 4px; padding: 3px; border-radius: 9px; background: var(--bg); border: 1px solid var(--border); }
.title-mix-option,
.title-mix-option:hover {
  padding: 4px 10px;
  border-radius: 7px;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 0.8rem;
  font-weight: 600;
}
.title-mix-option.is-selected { background: var(--surface-2, rgba(255, 255, 255, 0.08)); color: var(--accent); }
.title-duo-swap,
.title-duo-swap:hover {
  align-items: center;
  padding: 4px 10px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  font-size: 0.8rem;
  font-weight: 500;
}
.title-duo-swap:hover { border-color: var(--muted); }

/* ── 관리자 칭호 지급: 새로 만들기 / 기존 칭호 탭 ── */
.admin-grant-tabs { display: flex; gap: 4px; padding: 3px; border-radius: 10px; background: var(--bg); border: 1px solid var(--border); }
.admin-grant-tab,
.admin-grant-tab:hover {
  flex: 1 1 0;
  padding: 7px 10px;
  border-radius: 7px;
  background: transparent;
  color: var(--muted);
  font-weight: 500;
  font-size: 0.85rem;
}
.admin-grant-tab.is-active,
.admin-grant-tab.is-active:hover { background: var(--surface-2); color: var(--text); font-weight: 600; }
.admin-grant-existing-help { font-size: 0.82rem; margin: 10px 0; line-height: 1.5; }
/* 기존 칭호 주기 안의 상점 칭호 / 커스텀 칭호 탭 — 위 탭보다 한 단계 작은 밑줄형 */
.admin-grant-subtabs { display: flex; gap: 14px; border-bottom: 1px solid var(--border); }
.admin-grant-subtab,
.admin-grant-subtab:hover {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 2px;
  margin-bottom: -1px;
  border-radius: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 500;
}
.admin-grant-subtab:hover { color: var(--text); }
.admin-grant-subtab.is-active,
.admin-grant-subtab.is-active:hover { color: var(--text); font-weight: 600; border-bottom-color: var(--accent); }
.admin-grant-count { font-size: 0.72rem; color: var(--muted); background: var(--surface-2); border-radius: 999px; padding: 1px 7px; font-weight: 600; }
.admin-grant-count:empty { display: none; }
.admin-grant-subtab.is-active .admin-grant-count { color: var(--accent); }
.admin-grant-existing-list { display: flex; flex-wrap: wrap; gap: 8px; max-height: 220px; overflow-y: auto; }
.admin-grant-existing-option,
.admin-grant-existing-option:hover {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 9px;
  border-radius: 9px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  font-weight: 500;
  font-size: 0.85rem;
}
.admin-grant-existing-option:hover { border-color: var(--muted); }
.admin-grant-existing-option.is-selected { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.admin-grant-existing-option .chip-meta { color: var(--muted); font-size: 0.75rem; }

/* ── 룰렛 (roulette.html) ─────────────────────────────────────────────────────
   가로 릴: 배율 카드들이 옆으로 지나가다 가운데 선에서 멈춤. 카드엔 배율만 크게. */
.roulette-card { display: flex; flex-direction: column; gap: 18px; }
.roulette-view {
  position: relative;
  height: 150px;
  overflow: hidden;
  border-radius: 14px;
  background: #0f1215;
  box-shadow: inset 0 0 0 1px var(--border);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.roulette-strip { position: absolute; top: 15px; left: 0; display: flex; gap: 8px; will-change: transform; }
.roulette-tile {
  width: 88px;
  height: 120px;
  flex: 0 0 auto;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(180deg, color-mix(in srgb, var(--c) 32%, #1a1d22), #16191d 72%);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--c) 70%, transparent), inset 0 -4px 0 var(--c);
}
.roulette-tile b { font-size: 1.45rem; font-weight: 800; color: #fff; letter-spacing: 0.01em; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.5); }
.roulette-tile.is-jackpot {
  background: linear-gradient(160deg, #fff3b0, #f2c230 35%, #b8860b 70%, #ffe27a);
  box-shadow: inset 0 0 0 1.5px rgba(255, 255, 255, 0.6), inset 0 -4px 0 #8a6508, 0 0 14px rgba(242, 194, 48, 0.35);
}
.roulette-tile.is-jackpot b { color: #3a2a00; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); }
.roulette-tile.is-hit { animation: roulette-hit 0.9s ease 2; }
@keyframes roulette-hit {
  50% { box-shadow: inset 0 0 0 2px #fff, 0 0 20px var(--c), inset 0 -4px 0 var(--c); transform: scale(1.05); }
}
.roulette-marker {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 3px;
  margin-left: -1.5px;
  background: #fff;
  border-radius: 2px;
  box-shadow: 0 0 10px rgba(255, 255, 255, 0.8);
  z-index: 2;
  pointer-events: none;
}
.roulette-marker::before,
.roulette-marker::after { content: ""; position: absolute; left: 50%; transform: translateX(-50%); border: 8px solid transparent; }
.roulette-marker::before { top: 0; border-top-color: #fff; }
.roulette-marker::after { bottom: 0; border-bottom-color: #fff; }

.game-panel { display: flex; flex-direction: column; gap: 10px; }
.game-balance { display: flex; justify-content: space-between; align-items: baseline; }
.game-balance strong { font-size: 1.3rem; font-variant-numeric: tabular-nums; }
.game-bet-field { display: flex; flex-direction: column; gap: 6px; font-size: 0.82rem; }
.game-bet-field input {
  width: 100%;
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
  color: var(--text);
  font: 700 1.15rem system-ui, sans-serif;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.game-bet-field input:focus { outline: none; border-color: var(--accent); }
.game-bet-field input.is-bad { border-color: var(--danger); }
.game-chips { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; }
@media (max-width: 560px) { .game-chips { grid-template-columns: repeat(3, 1fr); } }
.game-chips .game-chip { padding: 8px 0; font-size: 0.82rem; font-weight: 600; min-width: 0; }
.game-hint { margin: 0; font-size: 0.8rem; color: var(--muted); min-height: 1.2em; }
.game-hint.is-bad { color: #ff8a8a; }
.roulette-spin-btn { padding: 14px; font-size: 1.05rem; font-weight: 800; border-radius: 12px; }
.game-result {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 12px;
  border-radius: 12px;
  background: var(--bg);
  border: 1px solid var(--c, var(--border));
  text-align: center;
}
.game-result strong { font-size: 1.2rem; font-variant-numeric: tabular-nums; }
.game-result .muted { font-size: 0.8rem; }
.game-result.is-plus strong { color: var(--accent); }
.game-result.is-minus strong { color: #ff8a8a; }
.game-result.is-even strong { color: var(--text); }
.game-result.is-error { color: #ff8a8a; font-size: 0.9rem; }
.game-result.is-jackpot { box-shadow: 0 0 18px rgba(242, 194, 48, 0.35); }
.game-result.is-jackpot strong { color: #f2c230; }

.game-recent-title { margin: 0 0 10px; font-size: 1rem; }
.game-recent { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.game-recent li { display: grid; grid-template-columns: 52px 1fr auto auto; align-items: center; gap: 10px; padding: 9px 2px; border-bottom: 1px solid var(--border); font-size: 0.88rem; }
.game-recent li:last-child { border-bottom: 0; }
.game-recent .game-recent-empty { display: block; text-align: center; padding: 18px 0; }
.game-recent-mult {
  justify-self: start;
  padding: 2px 8px;
  border-radius: 6px;
  font-weight: 800;
  font-size: 0.8rem;
  color: #fff;
  background: color-mix(in srgb, var(--c) 45%, #1a1d22);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 75%, transparent);
}
.game-recent-bet { font-variant-numeric: tabular-nums; }
.game-recent-time { font-size: 0.78rem; }
.game-recent-net { font-weight: 700; font-variant-numeric: tabular-nums; min-width: 72px; text-align: right; }
.game-recent-net.is-plus { color: var(--accent); }
.game-recent-net.is-minus { color: #ff8a8a; }
.game-recent-net.is-even { color: var(--muted); }
/* 폰 폭에선 한 줄에 다 안 들어가서 시간을 아래 줄로 내림(결과 배지 · 내용 · 포인트 / 시간). */
@media (max-width: 560px) {
  .game-recent li { grid-template-columns: auto 1fr auto; row-gap: 2px; }
  .game-recent-time { grid-column: 2; grid-row: 2; }
  .game-recent-net { min-width: 0; }
}

.game-lock { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 8px; }
.game-lock[hidden] { display: none; }
.game-lock svg { width: 36px; height: 36px; color: #cd7f32; }
.game-lock p { margin: 0; font-size: 0.88rem; }
.game-lock-progress { width: min(320px, 100%); height: 8px; border-radius: 999px; background: var(--bg); overflow: hidden; }
.game-lock-progress div { height: 100%; background: linear-gradient(90deg, #8a5a2b, #cd7f32); }

/* ── 가위바위보 (rps.html) — 나 vs 상대 카드 + 손 고르는 버튼(누르면 바로 한 판).
   베팅 칸/결과/최근 기록/잠금 안내는 룰렛과 같은 .game-* 스타일을 같이 씀. */
.rps-card { display: flex; flex-direction: column; gap: 18px; }
.rps-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 18px 12px 14px;
  border-radius: 14px;
  background: #0f1215;
  box-shadow: inset 0 0 0 1px var(--border);
}
.rps-vs { display: flex; align-items: center; justify-content: center; gap: clamp(14px, 6vw, 48px); }
.rps-side { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.rps-who { font-size: 0.8rem; color: var(--muted); font-weight: 600; }
.rps-hand {
  width: clamp(96px, 26vw, 128px);
  height: clamp(96px, 26vw, 128px);
  border-radius: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  box-shadow: inset 0 0 0 2px var(--border);
  color: var(--text-dim);
  transition: box-shadow 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
}
.rps-hand svg { width: 58%; height: 58%; }
.rps-hand.is-me { color: var(--accent); }
.rps-hand.is-shaking { animation: rps-shake 0.18s ease-in-out infinite alternate; }
@keyframes rps-shake {
  from { transform: translateY(-4px) rotate(-6deg); }
  to { transform: translateY(4px) rotate(6deg); }
}
.rps-hand.is-win { box-shadow: inset 0 0 0 2px var(--accent), 0 0 22px rgba(0, 229, 160, 0.35); transform: scale(1.05); }
.rps-hand.is-lose { box-shadow: inset 0 0 0 2px #e03141; opacity: 0.65; }
.rps-vs-label { font-weight: 900; color: var(--muted); font-size: 1.05rem; }
.rps-rule { margin: 0; font-size: 0.8rem; }
.rps-picks { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.rps-pick,
.rps-pick:hover {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 12px 0 10px;
  border-radius: 12px;
  background: var(--surface-2);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--border);
  font-weight: 700;
  font-size: 0.95rem;
}
.rps-pick svg { width: 34px; height: 34px; color: var(--accent); }
.rps-pick:hover:not(:disabled) { box-shadow: inset 0 0 0 1.5px var(--accent); }
.rps-pick:disabled { opacity: 0.45; }
.rps-pick:disabled svg { color: var(--muted); }
/* ── 홀짝 (oddeven.html) — 카드 한 장이 섞였다가 뒤집힘 + 홀/짝 버튼(누르면 바로 한 판).
   홀은 분홍, 짝은 파랑으로 색을 고정해서 결과가 색으로 바로 읽히게 함.
   베팅 칸/결과/최근 기록/잠금 안내는 룰렛·가위바위보와 같은 .game-* 스타일을 같이 씀. */
.oe-card { display: flex; flex-direction: column; gap: 18px; --oe-odd: #ff7b8f; --oe-even: #5cb6ff; }
.oe-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 22px 12px 14px;
  border-radius: 14px;
  background: #0f1215;
  box-shadow: inset 0 0 0 1px var(--border);
  overflow: hidden;
}
.oe-deck { position: relative; width: 128px; height: 180px; perspective: 900px; }
.oe-ghost { position: absolute; inset: 0; border-radius: 14px; background: #1f2a33; box-shadow: inset 0 0 0 1px #2e3b46; }
.oe-deck.is-shuffling .oe-ghost-l { animation: oe-fan-l 0.9s ease-in-out infinite; }
.oe-deck.is-shuffling .oe-ghost-r { animation: oe-fan-r 0.9s ease-in-out infinite; }
@keyframes oe-fan-l { 0%, 100% { transform: none; } 30%, 60% { transform: translateX(-66px) rotate(-14deg); } }
@keyframes oe-fan-r { 0%, 100% { transform: none; } 30%, 60% { transform: translateX(66px) rotate(14deg); } }
.oe-flip { position: absolute; inset: 0; transform-style: preserve-3d; transition: transform 0.7s cubic-bezier(0.3, 0.8, 0.3, 1.15); }
.oe-flip.is-open { transform: rotateY(180deg); }
.oe-flip.is-quick { transition-duration: 0.25s; }
.oe-side { position: absolute; inset: 0; border-radius: 14px; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.oe-back {
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(45deg, #102a22 0 8px, #0c1f19 8px 16px);
  box-shadow: inset 0 0 0 5px #0c0e11, inset 0 0 0 6px var(--accent), 0 10px 26px rgba(0, 0, 0, 0.5);
}
.oe-back b {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #0c0e11;
  box-shadow: 0 0 0 2px var(--accent);
  color: var(--accent);
  font-size: 1.2rem;
}
.oe-front {
  transform: rotateY(180deg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: linear-gradient(160deg, #fdfdfd, #e7e9ec);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5);
  color: #1d2126;
}
.oe-front.is-red { color: #e2334a; }
.oe-num { font-size: 3.8rem; font-weight: 900; line-height: 1; }
.oe-front > svg { width: 26px; height: 26px; margin-top: 6px; }
.oe-corner { position: absolute; display: flex; flex-direction: column; align-items: center; gap: 2px; font-weight: 800; font-size: 0.95rem; line-height: 1; }
.oe-corner svg { width: 12px; height: 12px; }
.oe-corner.is-tl { top: 9px; left: 10px; }
.oe-corner.is-br { bottom: 9px; right: 10px; transform: rotate(180deg); }
.oe-reveal { margin: 4px 0 0; min-height: 1.5em; font-weight: 800; font-size: 1.1rem; font-variant-numeric: tabular-nums; }
.oe-reveal .is-odd { color: var(--oe-odd); }
.oe-reveal .is-even { color: var(--oe-even); }
.oe-rule { margin: 0; font-size: 0.8rem; }
.oe-picks { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.oe-pick,
.oe-pick:hover {
  position: relative;
  padding: 14px 0;
  border-radius: 14px;
  background: var(--surface-2);
  color: var(--text);
  font-weight: 900;
  font-size: 1.5rem;
  line-height: 1.1;
  transition: box-shadow 0.15s ease, background 0.15s ease, opacity 0.15s ease;
}
.oe-pick.is-odd { color: var(--oe-odd); box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--oe-odd) 45%, transparent); }
.oe-pick.is-even { color: var(--oe-even); box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--oe-even) 45%, transparent); }
.oe-pick.is-odd:hover:not(:disabled),
.oe-pick.is-odd.is-chosen { background: color-mix(in srgb, var(--oe-odd) 12%, var(--surface-2)); box-shadow: inset 0 0 0 2px var(--oe-odd); }
.oe-pick.is-even:hover:not(:disabled),
.oe-pick.is-even.is-chosen { background: color-mix(in srgb, var(--oe-even) 12%, var(--surface-2)); box-shadow: inset 0 0 0 2px var(--oe-even); }
.oe-pick.is-odd.is-hit { background: color-mix(in srgb, var(--oe-odd) 22%, var(--surface-2)); box-shadow: inset 0 0 0 2px var(--oe-odd), 0 0 22px color-mix(in srgb, var(--oe-odd) 40%, transparent); }
.oe-pick.is-even.is-hit { background: color-mix(in srgb, var(--oe-even) 22%, var(--surface-2)); box-shadow: inset 0 0 0 2px var(--oe-even), 0 0 22px color-mix(in srgb, var(--oe-even) 40%, transparent); }
/* 전역 button:disabled(회색 배경/글자)를 덮어서 색은 유지하고 흐리게만 — 고른 쪽·맞은 쪽은 또렷하게. */
.oe-pick:disabled { cursor: not-allowed; font-weight: 900; }
.oe-pick.is-odd:disabled { color: var(--oe-odd); }
.oe-pick.is-even:disabled { color: var(--oe-even); }
.oe-pick:disabled:not(.is-chosen):not(.is-hit) { opacity: 0.45; background: var(--surface-2); }
.oe-pick-mine {
  display: none;
  position: absolute;
  top: 6px;
  right: 8px;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  color: var(--text);
  font-size: 0.66rem;
  font-weight: 700;
  line-height: 1.5;
}
.oe-pick.is-chosen .oe-pick-mine { display: inline; }

@media (prefers-reduced-motion: reduce) {
  .rps-hand.is-shaking { animation: none; }
  .oe-deck.is-shuffling .oe-ghost { animation: none; }
  .oe-flip { transition-duration: 0.01s; }
  .roulette-tile.is-hit { animation: none; box-shadow: inset 0 0 0 2px #fff, 0 0 20px var(--c), inset 0 -4px 0 var(--c); }
}

/* 관리자 "후원 적립" 탭 — 탭 이름 옆 확인 대기 숫자, 익명 후원 한 건씩 유저를 골라 적립하는 행. */
.admin-tab-count {
  display: inline-block;
  min-width: 18px;
  margin-left: 6px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--danger);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}
.admin-tab-count[hidden] { display: none; }
.donation-row { padding: 14px 0; border-bottom: 1px solid var(--border); }
.donation-row:last-child { border-bottom: none; }
.donation-row-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; }
.donation-row-head strong { color: var(--accent); }
.donation-row-head .muted { font-size: 0.8rem; }
.donation-message {
  margin: 8px 0 0;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: 0.88rem;
  white-space: pre-wrap;
  word-break: break-word;
}
.donation-assign { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
.donation-assign .donation-user-input { flex: 1 1 180px; min-width: 0; }
.donation-assign button { white-space: nowrap; }
.donation-user-results { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; font-size: 0.85rem; color: var(--muted); }
.donation-user-results:empty { display: none; }
.donation-assign .donation-user-input {
  font: inherit;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 8px 12px;
}
.donation-assign .donation-user-input:focus { outline: none; border-color: var(--accent); }
#donation-recent-list .points-log-time { flex: 0 0 auto; width: auto; }

/* 방송 코드 — 출석체크 페이지 입력 카드(0047_stream_codes.sql). 코드는 대문자로 보이게(서버도 대문자로 맞춰서 비교). */
.code-card-head h2 { margin: 0; font-size: 1.05rem; font-family: var(--font-logo); }
.code-card-desc { margin: 6px 0 0; color: var(--muted); font-size: 0.86rem; word-break: keep-all; }
.code-redeem-row { display: flex; gap: 8px; margin-top: 14px; }
.code-redeem-input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-family: var(--font-logo);
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-align: center;
  text-transform: uppercase;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 12px;
}
.code-redeem-input::placeholder { letter-spacing: normal; font-weight: 500; font-size: 0.95rem; color: var(--muted); text-transform: none; }
.code-redeem-input:focus { outline: none; border-color: var(--accent); }
.code-redeem-row button { white-space: nowrap; padding-left: 20px; padding-right: 20px; }
.code-result { margin-top: 12px; padding: 12px 14px; border-radius: var(--radius-sm); font-size: 0.9rem; display: flex; align-items: center; gap: 10px; word-break: keep-all; }
.code-result:empty { display: none; }
.code-result.ok { background: var(--accent-dim); color: var(--accent); }
.code-result.ok strong { font-size: 1.15rem; white-space: nowrap; }
.code-result.error { background: var(--danger-dim); color: #ff8a8a; }

/* 관리자 "방송 코드" 탭 — 만들기 폼 / 진행 중인 코드 / 지난 코드(5개씩 페이지). */
.code-form { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr) auto; gap: 8px; align-items: end; margin-top: 12px; }
.code-form label { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; color: var(--muted); }
.code-form input { font: inherit; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius-sm); color: var(--text); padding: 10px 12px; min-width: 0; }
.code-form input:focus { outline: none; border-color: var(--accent); }
.code-form button { white-space: nowrap; }
.code-overlay-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border); font-size: 0.82rem; color: var(--muted); }
.code-overlay-row button { font-size: 0.8rem; padding: 4px 10px; }
.code-active { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; padding: 16px; border-radius: var(--radius-sm); background: var(--accent-dim); border: 1px solid rgba(0, 229, 160, 0.35); }
.code-active-code { font-family: var(--font-logo); font-size: 2rem; font-weight: 700; letter-spacing: 0.08em; color: var(--accent); word-break: break-all; }
.code-active-meta { flex: 1; min-width: 160px; display: flex; flex-direction: column; gap: 4px; font-size: 0.88rem; }
.code-active-meta .time { font-size: 1.1rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.code-active-actions { display: flex; gap: 8px; }
.code-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
.code-row:last-child { border-bottom: none; }
.code-row .c { font-family: var(--font-logo); font-weight: 700; letter-spacing: 0.04em; min-width: 110px; }
.code-row .m { flex: 1; color: var(--muted); font-size: 0.82rem; }
.code-row .t { color: var(--muted); font-size: 0.78rem; white-space: nowrap; }
@media (max-width: 560px) {
  .code-form { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .code-form label:first-child, .code-form button { grid-column: 1 / -1; }
  .code-active { display: grid; grid-template-columns: 1fr auto; gap: 6px 12px; padding: 14px; }
  .code-active-code { font-size: 1.6rem; }
  .code-active-meta { display: contents; }
  .code-active-meta .time { grid-column: 2; grid-row: 1; align-self: center; font-size: 1rem; }
  .code-active-meta span:not(.time) { grid-column: 1 / -1; font-size: 0.85rem; }
  .code-active-actions { grid-column: 1 / -1; }
  .code-active-actions button { width: 100%; }
  .code-row { flex-wrap: wrap; gap: 4px 12px; }
  .code-row .c { flex: 1; }
  .code-row .m { order: 3; flex-basis: 100%; }
}
