/* tokens.css — 디자인 토큰 단일 출처. 여기 값을 바꾸면 전체 화면에 반영된다. */
:root {
  color-scheme: light;

  /* ── core palette (§0 confirmed values) ─────────────────────── */
  --bg: #f5f6f8;
  --surface: #ffffff;
  --surface-alt: #f5f5f5;
  --line: #dde1e8;
  --text: #1c222e;
  --muted: #5b6472;
  --brand: #d8432a;
  --brand-soft: #fbe7e2;
  /* --brand를 흰 배경 위 글자색으로 쓰면 대비 4.42:1로 AA 4.5:1에 살짝
     못 미친다. 이 잉크색(5.39:1)은 작은 글자에 쓸 때만 쓴다. */
  --brand-ink: #c13a22;
  --hl: #d8ff3d;
  /* --hl 위에 놓일 글자색은 고정값으로 둔다 — --text를 그대로 쓰면
     다크모드에서 --text 색이 반전될 때 밝은 배경에 밝은 글자가 겹쳐
     안 보이게 된다. */
  --hl-ink: #1c222e;
  --focus: #8a94a6;

  /* 상태 색상 쌍(배경/잉크): mint=진행중, amber=종료임박, pink=찜·관심,
     rose=에러, up=예정. */
  --pink-soft: #fce7ee;
  --pink-ink: #b01e52;
  --mint-soft: #dff3e6;
  --mint-ink: #1f7a44;
  --amber-soft: #fbebd2;
  --amber-ink: #9a5b12;
  --rose-soft: #ffe4e6;
  --rose-ink: #be123c;
  --up-soft: #e4eafb;
  --up-ink: #33488f;
  /* teal = 내 활동(archive) 전용 액센트. 라이트/다크 값이 위 --up-ink와
     같아 별도 색상 체계 없이 그대로 맞춰 정의했다. */
  --teal: #0e7490;
  --teal-soft: #d3edf2;
  --teal-ink: #0e7490;
  /* end = 종료 상태(찾아온 기록의 4번째 상태). 잉크색은 대비 4.28:1로
     AA 기준에 못 미쳐 4.75:1로 살짝 어둡게 보정했다. */
  --end-soft: #ececef;
  --end-ink: #64686e;
  /* muted-soft = 중립·"비공식" 마커 배경, 잉크는 --muted. */
  --muted-soft: #eef0f3;

  /* 활동 달력 날짜/범례용 얇은 테두리 색. 각 -soft 배경보다 살짝 어둡게
     둬 --bg-card 위에서도 테두리가 구분되게 했다. */
  --rose-border: #f8b7c3;
  /* 찜 버튼 테두리 전용 색. 팔레트에 딱 맞는 기존 값이 없어 별도로 뒀다. */
  --pink-border: #f8bfd8;

  --shadow: 0 18px 38px rgba(17, 31, 55, 0.08);

  /* ── translucent chrome ─────────────────────────────────────── */
  /* 반투명 크롬 색상들. 다크모드 값은 각각 아래 :root[data-theme="dark"]
     블록에 짝으로 정의돼 있다. */
  /* 상단 고정 헤더(site-chrome.css .site-header)용. */
  --chrome-glass: rgba(255, 255, 255, 0.9);
  /* 모바일 고정 CTA 바(.mobile-cta)용. --chrome-glass보다 불투명도가 조금 높다. */
  --chrome-glass-cta: rgba(255, 255, 255, 0.96);
  --shadow-cta: 0 -8px 24px rgba(17, 31, 55, 0.1);
  /* 드롭다운 패널(.account-menu-panel, .region-select-menu 등)용. 값이
     같아 토큰 하나로 공유한다. */
  --shadow-dropdown: 0 8px 24px rgba(17, 31, 55, 0.14);
  /* 모달·확인창 배경 오버레이용. 값이 같아 토큰 하나로 공유한다. */
  --backdrop: rgba(17, 31, 55, 0.45);

  --radius-card: 10px;
  --radius-control: 8px;
  /* 칩·배지·필 형태 라운드 값. 예전의 "티켓 스텁" 모양(한쪽만 둥근 형태)은
     폐기하고 완전한 캡슐형으로 통일했다(사용자 확정 사안). */
  --radius-chip: 999px;

  /* 6단계 글자 크기 체계. --fs-xl은 페이지당 가장 강조되는 제목 한 곳에만
     쓴다(현재는 홈 히어로 h1뿐) — 그래야 기존 제목 위계가 흐트러지지
     않는다. */
  --fs-xs: 0.75rem;
  --fs-sm: 0.8rem;
  --fs-md: 0.875rem;
  --fs-base: 0.95rem;
  --fs-lg: 1.125rem;
  --fs-xl: 1.75rem;
  /* --fs-xl의 모바일용 크기. */
  --fs-xl-mobile: 1.375rem;

  /* 중성 배경 톤. border-soft는 --line보다 살짝 밝고, bg-soft/bg-card는
     --bg와 --surface 사이 중간 톤이다. */
  --border-soft: #e6e9ef;
  --bg-soft: #f7f8fa;
  --bg-card: #fbfbfc;

  /* 카테고리 배색 — 상태 색상(핑크/브랜드/민트/회색)과 겹치지 않게 채도를
     낮췄다. -ink는 템플릿에서 카테고리 slug로 직접 참조한다. -soft는
     지금 당장 참조하는 곳이 없어 보여도 지우지 마라 — 카테고리마다
     soft/ink 쌍 구조를 유지하려고 남겨둔 것이다. */
  --cat-popup_store-soft: #f3e8ff;
  --cat-popup_store-ink: #7e22ce;
  --cat-collaboration_cafe-soft: #f5ecdf;
  --cat-collaboration_cafe-ink: #92633a;
  --cat-theater_bonus-soft: #e0e7ff;
  --cat-theater_bonus-ink: #3730a3;
  --cat-goods_reservation-soft: #d8f3ee;
  --cat-goods_reservation-ink: #0f766e;
  --cat-exhibition-soft: #e2e8f0;
  --cat-exhibition-ink: #475569;
  --cat-fan_meeting-soft: #fce7f3;
  --cat-fan_meeting-ink: #9d174d;

  /* work_title(시리즈)별 배색 — 카테고리(--cat-*)와는 별개 축이다
     (core/views.py의 _series_ink_classes 참고, 둘을 섞지 말 것).
     OKLCH 30도 간격으로 12색을 만들고 홀짝 명도를 다르게 둬 라이트/다크
     모두 대비 AA를 지킨다(72개 배경 조합 실측, 최저 4.91:1). 홀짝을
     나눈 이유는 색약자도 인접 색을 명도 차이로 구분하게 하려는 것이다.
     배경 채우기용 -soft 짝은 의도적으로 두지 않았다 — 필요해지면 그때
     추가한다. */
  --series-1-ink: #a6373f;
  --series-2-ink: #743200;
  --series-3-ink: #825b00;
  --series-4-ink: #4b4b00;
  --series-5-ink: #2c7619;
  --series-6-ink: #005541;
  --series-7-ink: #007276;
  --series-8-ink: #004f6b;
  --series-9-ink: #2d60b4;
  --series-10-ink: #4a328e;
  --series-11-ink: #864296;
  --series-12-ink: #7c1852;
}

/* ── dark mode token overrides ────────────────────────────────── */
/* 다크모드 확정 팔레트를 그대로 반영했다. 다크/라이트 오버라이드는 이
 * 블록 하나로 모아 뒀고, static/js/shared/theme.js가 <html>에
 * data-theme를 설정한다.
 */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #13151b;
  --surface: #1f232d;
  --surface-alt: #272b35;
  --bg-soft: #292d38;
  --bg-card: #2e323e;
  --border-soft: #373e4e;
  --line: #3d465c;
  --text: #e3e4e8;
  --muted: #a2a9b9;
  --focus: #969fb0;

  --brand: #c63d24;
  /* 원안 색이 --bg-card 다크 배경 위에서 대비 4.4985:1로 AA 기준에
     근소하게 못 미쳐 값을 미세 조정했다(4.588:1로 통과, 다른 배경
     페어링도 함께 개선됨). */
  --brand-ink: #da8474;
  --brand-soft: #422824;
  --hl: #c1e52e;

  --cat-popup_store-soft: #342442;
  --cat-popup_store-ink: #b17edc;
  --cat-collaboration_cafe-soft: #3d3024;
  --cat-collaboration_cafe-ink: #bf9f82;
  --cat-theater_bonus-soft: #272541;
  --cat-theater_bonus-ink: #8f8bcf;
  --cat-goods_reservation-soft: #20413f;
  --cat-goods_reservation-ink: #64d8cf;
  --cat-exhibition-soft: #23354e;
  --cat-exhibition-ink: #839ec3;
  --cat-fan_meeting-soft: #412530;
  --cat-fan_meeting-ink: #da769e;

  /* 시리즈 색 12개는 전부 다크값을 채워야 한다 — 하나라도 빠지면 아무
     오류 없이 조용히 회색으로 대체된다(이 프로젝트에서 실제로 두 번
     발생한 실패 유형). */
  --series-1-ink: #da8282;
  --series-2-ink: #f7a97c;
  --series-3-ink: #c29647;
  --series-4-ink: #c2c46e;
  --series-5-ink: #79af6d;
  --series-6-ink: #6cd5b3;
  --series-7-ink: #2bb3b9;
  --series-8-ink: #6bcbf7;
  --series-9-ink: #769fe3;
  --series-10-ink: #bcb2ff;
  --series-11-ink: #bd88c9;
  --series-12-ink: #f4a0c8;

  --pink-soft: #42242e;
  --pink-ink: #d87497;
  --mint-soft: #243d2e;
  --mint-ink: #72cb95;
  --amber-soft: #403221;
  --amber-ink: #dba466;
  --rose-soft: #43232b;
  --rose-ink: #e0718c;
  /* 라이트 모드는 테두리를 배경보다 어둡게 잡지만, 다크에서는 반대로
     배경보다 밝아야 눈에 띈다. 다크값이 없어 라이트 값이 그대로 새어
     나와 삭제 버튼·오류 배너가 지나치게 밝게 보이던 결함을 고쳤다
     (--surface 대비 4.01:1, --rose-soft 대비 3.54:1로 확인). */
  --rose-border: #c46278;
  --up-soft: #242a3d;
  --up-ink: #8897c8;
  /* 원안 색은 흰 글자 대비 3.27:1로 AA 4.5:1에 못 미쳐 5.74:1로
     보정했다(사용자 확정). --teal-ink는 원안 값을 그대로 유지했다. */
  --teal: #17707f;
  --teal-soft: #173b42;
  --teal-ink: #5ac9d4;
  --end-soft: #2d3239;
  --end-ink: #a5acb6;
  /* --muted-soft에 다크값이 없어 "비공식" 마커 칩이 다크모드에서도 밝은
     배경 위에 어두운 글자가 얹혀 대비 2.06:1로 렌더되던 결함을 고쳤다.
     --surface-alt 다크값을 그대로 재사용했다(대비 6.01:1). */
  --muted-soft: #272b35;

  --shadow: 0 18px 38px rgba(255, 255, 255, 0.04);

  --chrome-glass: rgba(31, 35, 45, 0.88);
  --chrome-glass-cta: rgba(31, 35, 45, 0.94);
  --shadow-cta: 0 -8px 24px rgba(255, 255, 255, 0.05);
  --shadow-dropdown: 0 8px 24px rgba(255, 255, 255, 0.05);
  --backdrop: rgba(0, 0, 0, 0.6);
}

/* ── --page-pad-x: 페이지 좌우 여백 토큰 ───────────────────────── */
/* 모바일(45rem 이하) 16px / 태블릿(45~64rem) 24px / 데스크톱(64rem 초과)
 * 32px 3단계로 통일했다(사용자 확정). 각 소비 파일은 자기 상하 여백과
 * 다른 브레이크포인트는 그대로 두고, 좌우 값만 이 토큰을 따른다.
 */
:root {
  --page-pad-x: 2rem; /* 32px, 데스크톱 기본값(>64rem) */
}

@media (max-width: 64rem) {
  :root {
    --page-pad-x: 1.5rem; /* 24px, 태블릿 */
  }
}

@media (max-width: 45rem) {
  :root {
    --page-pad-x: 1rem; /* 16px, 모바일 */
  }
}

/*
 * base.css — 전역 기본 레이어: 리셋, 문서 기본값, 페이지 래퍼, 포커스
 * 아웃라인. 컴포넌트·오브젝트는 별도 파일로 분리돼 있다.
 *
 * 단위 규칙: 간격류(font-size/padding/margin/gap/sticky top/@media
 * 브레이크포인트)는 전부 rem을 쓴다 — 사용자가 브라우저 글자 크기를
 * 키우면 간격도 함께 커지게 하려는 것이다. 고정값(테두리 두께, 그림자,
 * 모서리 반경, 44px 탭 타깃, 999px 필 반경, 절대위치 코너 오프셋,
 * safe-area calc(), 사진 업로드 인풋 -1px 클립, 팬 덱 카드 중앙 정렬
 * 여백)만 px를 쓴다.
 *
 * html에 font-size 재정의가 없어 rem 기준은 브라우저 기본값(16px)이고,
 * 기존 px 값은 /16으로 변환해 기본 배율에서는 픽셀 단위로 동일하다.
 * @media 브레이크포인트(rem, CSS 변수를 @media 조건에 못 써서 리터럴
 * 값 사용): 38.75(620px) 45(720px) 47.5(760px) 53.75(860px) 56.25(900px)
 * 57.5(920px) 60(960px)rem. 64rem(1024px)만 예외로 --page-pad-x
 * 토큰(tokens.css) 전용이며, 위 목록의 900px이 아니라 사용자가 명시적으로
 * 확정한 1024px 값을 쓴다.
 */

/* ── reset ─────────────────────────────────────────────────── */
* {
  box-sizing: border-box;
}

/* 링크에 밑줄을 넣지 않는다 — 색과 문맥만으로 링크임을 알 수 있게 한다. */
a {
  text-decoration: none;
}

/* ── body ───────────────────────────────────────────────────── */
body {
  margin: 0;
  font-family: "Pretendard", -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Noto Sans KR", sans-serif;
  line-height: 1.6;
  color: var(--text);
  background:
    radial-gradient(160% 90% at 100% -10%, var(--surface) 0%, transparent 45%),
    radial-gradient(120% 70% at -10% -20%, var(--surface) 0%, transparent 40%),
    var(--bg);
}

/* ── page wrapper ───────────────────────────────────────────── */
.page {
  max-width: 1120px;
  margin: 0 auto;
  padding: 1.625rem var(--page-pad-x) 5rem;
}

/* ── site-wide messages (django.contrib.messages) ──────────── */
.site-messages {
  max-width: 1120px;
  margin: 0.75rem auto 0;
  padding: 0 var(--page-pad-x);
  list-style: none;
}

.site-message {
  margin: 0 0 0.5rem;
  padding: 0.625rem 0.75rem;
  border-radius: 8px;
  font-size: 0.88rem;
}

.site-message-error {
  background: var(--rose-soft);
  color: var(--rose-ink);
}

.site-message-info {
  border: 1px dashed var(--line);
  background: var(--bg-soft);
  color: #46617f;
}

/* 잉크 리터럴 개별 다크 오버라이드 — 처음엔 다른 7곳과 동일하게 --muted
   다크값(#A2A9B9)으로 대응했으나, .site-message-info는 error(rose)/
   success(mint)와 함께 상태 트리오를 이루는 형제 규칙이라 무채색 muted를
   쓰면 정체성이 끊긴다는 게이트 지적(UX MED)으로 --up-ink로 교체 —
   원래 라이트 잉크(#46617f)와 같은 블루 계열인 up 카테고리 토큰을
   재사용해 "info=파랑" 형제 관계를 다크에서도 유지한다. */
:root[data-theme="dark"] .site-message-info {
  color: var(--up-ink);
}

.site-message-success {
  background: var(--mint-soft);
  color: var(--mint-ink);
}

/* ── focus outline (global) ─────────────────────────────────── */
a:focus,
button:focus,
input:focus,
textarea:focus,
select:focus {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* ── interaction feedback: hover lift + loading spinner ──────── */
/* .is-loading은 요청이 진행 중일 때 TakuAPI.setLoading이 붙였다 떼는 클래스로,
   버튼을 비활성 스피너로 바꾼다. */
.hover-lift {
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.hover-lift:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  border-color: var(--border-soft);
}

.hover-lift:active {
  transform: translateY(0);
}

.chip,
.status-btn,
.status,
.nav-links a,
.top-action {
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.chip:not(.active):hover {
  background: var(--brand-soft);
  border-color: var(--brand);
}

.status-btn:hover {
  border-color: var(--border-soft);
}

.nav-links a:not(.active):hover {
  background: var(--brand-soft);
  border-color: var(--brand);
}

.top-action:hover {
  filter: brightness(0.98);
  border-color: var(--brand);
}

/* ── glint (카드 호버/포커스 시 반짝이는 ✦ 표시) ──────────────────── */
/* `<span class="glint">✦</span>`를 .hover-lift가 붙은 요소 안에 두면
   호버·포커스 시에만 나타난다. */
.glint {
  position: absolute;
  opacity: 0;
  transform: scale(0.7);
  color: #fff;
  text-shadow: 0 0 7px rgba(28, 34, 46, 0.55);
  transition: opacity 0.15s ease, transform 0.15s ease;
  pointer-events: none;
}

.hover-lift:hover .glint,
.hover-lift:focus-within .glint {
  opacity: 1;
  transform: scale(1);
}

.is-loading {
  position: relative;
  pointer-events: none;
  opacity: 0.85;
}

.is-loading::after {
  content: "";
  display: inline-block;
  width: 0.85em;
  height: 0.85em;
  margin-left: 0.375rem;
  vertical-align: -0.15em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
}

@keyframes btn-spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hover-lift {
    transition: none;
  }
  .hover-lift:hover,
  .hover-lift:active {
    transform: none;
  }
  .glint {
    transition: none;
  }
}

/* ── status-row (찜/예정 등 카드 액션 버튼 줄) ───────────────────
   여러 페이지(비공식·찜목록·예정목록·이벤트목록·이벤트상세)가 공유하는
   단일 정의. 예전엔 4개 페이지 CSS에 중복돼 있던 것을 여기로 통합했다. */
.status-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4375rem;
  margin-top: 0.5625rem;
}

/* ── layout (two-column grid shared by list/archive pages) ──── */
.layout {
  display: grid;
  gap: 0.75rem;
}

/* 여러 아카이브·드래프트 페이지가 공유하는 사이드 패널이다 */
.side-stack {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.75rem;
  align-self: start;
  position: sticky;
  top: calc(var(--site-header-h) + 0.75rem);
}
.rule-list {
  margin: 0.75rem 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.5625rem;
}
.rule-list li {
  display: flex;
  gap: 0.5625rem;
  align-items: flex-start;
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.5;
}
.rule-list li::before {
  content: "·";
  flex: none;
  color: var(--brand-ink);
  font-weight: 700;
  line-height: 1.5;
}
.side-list {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}
.side-list li {
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--bg-card);
  padding: 0.5625rem 0.625rem;
}
/* .back-link와 같은 규칙: brand-ink, 평소엔 밑줄 없음, 호버 시 밑줄.
   글자 크기는 변형(--row 등)과 무관하게 같은 컴포넌트는 같은 크기여야
   한다는 판단으로 통일했다. 터치 타깃 높이는 .side-list li의 패딩이 담당한다. */
.side-list a {
  color: var(--brand-ink);
  text-decoration: none;
  font-size: var(--fs-xs);
  font-weight: 600;
}
.side-list a:hover {
  text-decoration: underline;
}

/* 칩 그룹을 감싸는 컨테이너다 */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 0.75rem;
}

/* 스킵 링크. 포커스 전엔 화면 밖에 숨어 있다가 포커스되면 좌상단에
   나타난다. z-index 100은 아래 .site-header의 50보다 위다. */
.skip-link {
  position: absolute;
  left: -999px;
  top: 0;
  z-index: 100;
  padding: 0.5rem 0.875rem;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.skip-link:focus {
  left: 0.75rem;
  top: 0.75rem;
}

/* ── global site header ─────────────────────────────────────── */
/* base.html에서 한 번만 렌더되는 상단 고정 바 — 브랜드/메인 내비/로그인
 * 상태를 담는다.
 */
:root {
  /* .site-header의 데스크톱 실제 높이값. 다른 곳(사이드바 등)에서
     헤더 아래에 딱 붙게 고정 배치할 때 쓴다 — 이 값을 바꾼다고 헤더
     자체 높이가 바뀌지는 않는다. */
  --site-header-h: 4.3125rem;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--chrome-glass);
  backdrop-filter: saturate(180%) blur(8px);
  border-bottom: 1px solid var(--line);
}

.site-header-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0.75rem var(--page-pad-x);
  display: flex;
  align-items: center;
  gap: 1.125rem;
}

.site-nav {
  display: flex;
  gap: 0.25rem;
  flex-wrap: wrap;
}

.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.375rem 0.75rem;
  border-radius: 8px;
  text-decoration: none;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--muted);
  position: relative;
}

.site-nav a:hover {
  background: var(--brand-soft);
  color: var(--brand-ink);
}

/* 현재 페이지는 채워진 필이 아니라 빨간 밑줄로 표시한다 — 그래야 페이지
   안 다른 칩·배지와 시각적으로 겹치지 않는다. */
.site-nav a.active {
  background: transparent;
  color: var(--text);
  font-weight: 700;
}

.site-nav a.active::after {
  content: "";
  position: absolute;
  left: 0.75rem;
  right: 0.75rem;
  bottom: 0.25rem;
  height: 2px;
  border-radius: 2px;
  background: var(--brand);
}

.site-nav a.active:hover {
  background: var(--brand-soft);
  color: var(--brand-ink);
}

.site-header .topbar-auth {
  margin-left: auto;
  /* 모바일에서 .site-nav가 헤더 아래로 줄바꿈될 때 계정 메뉴 드롭다운
     패널을 덮어 그리지 않도록 그리기 순서를 올린다. */
  z-index: 1;
}

@media (max-width: 45rem) {
  .site-header-inner {
    flex-wrap: wrap;
    gap: 0.625rem;
    padding: 0.625rem var(--page-pad-x);
  }
  .site-nav {
    order: 3;
    width: 100%;
  }
  .site-header .topbar-auth {
    flex-wrap: wrap;
  }
  /* 모바일(45rem 이하)에서는 아이디 표시 자체를 숨긴다(사용자 결정) —
     전체 주소는 계정 메뉴 패널을 열면 확인할 수 있다.
     셀렉터는 반드시 `.site-header .topbar-username`으로 스코프해야 한다.
     modal.css가 미디어쿼리 없이 `.topbar-username{max-width:15rem}`을
     이 파일보다 뒤에 불러오는데, 특이도가 같으면 나중에 로드된 규칙이
     이겨 이 규칙이 조용히 무시된다 — .site-header 조상을 붙여 특이도를
     올려서 이긴다. */
  .site-header .topbar-username {
    display: none;
  }
}

/* ── mobile nav toggle (hamburger) ─────────────────────────────
   계정 메뉴와 같은 인터랙션 관례(aria-expanded/aria-controls/Escape/
   포커스 복귀)를 재사용한다. 45rem 초과에서는 .site-nav가 항상 보이므로
   이 버튼 자체를 숨긴다(모바일 전용 컨트롤). */
.nav-menu-toggle {
  display: none;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  color: var(--text);
}

.nav-menu-toggle:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.nav-menu-icon {
  font-size: 1.5rem;
  line-height: 1;
}

@media (max-width: 45rem) {
  .nav-menu-toggle {
    display: flex;
    width: 32px;
    height: 32px;
  }
  .nav-menu-icon {
    font-size: 1.5rem; /* 32px 히트박스 안에 24px 아이콘 */
  }
  /* 45rem 초과에서는 이 규칙 자체가 매치되지 않아 항상 보이는 상태를
     유지한다. */
  .site-nav[data-expanded="false"] {
    display: none;
  }
}

/* ── notice banner (marquee) ───────────────────────────────────
   보이는 정지 버튼 없이 순수 CSS 무한 루프로만 구현했다(사용자 승인
   예외) — 대신 prefers-reduced-motion에서는 애니메이션을 완전히 끈다. */
.site-banner {
  background: var(--brand-soft);
  overflow: hidden;
}

.site-banner-inner {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee 24s linear infinite;
}

.marquee-set {
  display: flex;
  flex-shrink: 0;
}

.marquee-item {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.5rem 1.5rem;
  white-space: nowrap;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--brand-ink);
}

@keyframes marquee {
  to {
    transform: translateX(-50%);
  }
}

@media (max-width: 45rem) {
  .marquee-track {
    animation-duration: 18s;
  }
}

@media (prefers-reduced-motion: reduce) {
  .marquee-track {
    animation: none !important;
  }
}

/* ── secondary in-page nav (archive / drafts sub-sections) ──── */
.sub-nav {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 0.625rem 0.875rem;
  margin-bottom: 0.875rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.625rem;
  flex-wrap: wrap;
}

/* ── global site footer ─────────────────────────────────────── */
.site-footer {
  margin-top: 2.5rem;
  border-top: 1px solid var(--line);
  background: var(--surface);
}

.site-footer-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 2rem var(--page-pad-x) 1.5rem;
  display: grid;
  grid-template-columns: 1.3fr 2fr;
  gap: 1.75rem;
}

.footer-logo {
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--text);
  display: block;
}

.footer-tagline {
  margin: 0.5rem 0 0;
  font-size: 0.8rem;
  color: var(--muted);
  line-height: 1.6;
}

.footer-cols {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
}

.footer-col h2 {
  margin: 0 0 0.625rem;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.footer-col a,
.footer-col p {
  display: block;
  margin: 0 0 0.375rem;
  font-size: 0.86rem;
  color: var(--muted);
  text-decoration: none;
}

.footer-col a:hover {
  color: var(--brand-ink);
}

/* 안내 문구는 4개 메뉴 컬럼(이벤트/컬렉션/내 활동/계정)에 속하지 않는
   별도 행이다. */
.site-footer-notice {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 var(--page-pad-x) 1.5rem;
}

.site-footer-notice p {
  margin: 0 0 0.375rem;
  font-size: 0.86rem;
  color: var(--muted);
}

.site-footer-notice p:last-child {
  margin-bottom: 0;
}

.site-footer-base {
  border-top: 1px solid var(--line);
}

.site-footer-base-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 1rem var(--page-pad-x);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
}

.site-footer-base p {
  margin: 0;
  font-size: 0.8rem;
  color: var(--muted);
}

.footer-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
}

.footer-legal a {
  font-size: 0.8rem;
  color: var(--muted);
  text-decoration: none;
  padding: 0.375rem 0; /* WCAG 2.5.8: 인라인 링크 세로 히트영역 확보 */
}

.footer-legal a:hover {
  color: var(--brand-ink); /* --brand는 흰 배경 AA 미달 — brand-ink 사용 */
}

/* 좁은 화면에서도 푸터는 2x2로 접지 않고 4컬럼 한 줄을 유지한다(사용자
   확정) — 대신 이 구간에서는 gap/폰트/여백만 줄인다. 320px에서도 가장
   긴 라벨이 줄바꿈 없이 들어가는 여유폭이 있는 것을 산식으로 확인했다. */
@media (max-width: 47.5rem) {
  .site-footer-inner {
    grid-template-columns: 1fr;
    gap: 1.25rem;
  }
  .footer-cols {
    gap: 0.5rem;
  }
  .footer-col h2 {
    font-size: 0.7rem;
    margin-bottom: 0.375rem;
  }
  .footer-col a,
  .footer-col p {
    font-size: 0.72rem;
    margin-bottom: 0.25rem;
  }
  .site-footer-base-inner {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ── brand ──────────────────────────────────────────────────── */
.brand {
  font-size: 1.3rem;
  font-weight: 700;
  color: var(--text);
  text-decoration: none;
}

/* ── theme toggle (light/dark) ─────────────────────────────────
   .account-menu-toggle 패턴 재사용(44px 히트박스/30px 원) — hover는
   계정 메뉴 아바타와 달리 중립(--bg-soft/--line, 브랜드 레드는
   상태·CTA 전용이라 배제, 다크모드 팔레트 문서 §9). 글리프 2종을 겹쳐
   두고 [data-theme]로 하나만 보이게 하는 순수 CSS 전환 — FOUC 방지
   인라인 스크립트가 첫 페인트 전에 data-theme을 이미 확정하므로 JS의
   아이콘 교체 타이밍에 기댈 필요가 없다. */
.theme-toggle {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
}

.theme-toggle:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.theme-toggle-mark {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-soft);
  border-radius: 50%;
  background: transparent;
  color: var(--text);
  font-size: 0.95rem;
  line-height: 1;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}

.theme-toggle:hover .theme-toggle-mark,
.theme-toggle:focus-visible .theme-toggle-mark {
  border-color: var(--line);
  background: var(--bg-soft);
}

.theme-toggle-icon-dark {
  display: none;
}

:root[data-theme="dark"] .theme-toggle-icon-light {
  display: none;
}

:root[data-theme="dark"] .theme-toggle-icon-dark {
  display: inline;
}

@media (max-width: 45rem) {
  .theme-toggle {
    width: 32px;
    height: 32px;
  }
  .theme-toggle-mark {
    width: 24px;
    height: 24px;
    font-size: 0.75rem;
  }
}

/* ── account menu (header disclosure dropdown) ────────────────
   event_list.js의 지역 선택 드롭다운과 같은 방식: 클릭으로 열고, 바깥
   클릭이나 Escape로 닫히며 포커스가 트리거로 돌아간다.
   static/js/shared/account_menu.js 참고. */
[data-account-menu] {
  position: relative;
}

/* 눈에 보이는 30px 원 바깥에 44px 탭 타깃을 둔다. .hscroll-btn의
   ::before 기법과 같은 비율이지만, 원 안에 이니셜 글자를 넣어야 해서
   가상 요소 대신 실제 자식 요소를 쓴다. */
.account-menu-toggle {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
}

.account-menu-toggle:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

.account-mark {
  width: 30px;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border-soft);
  border-radius: 50%;
  background: var(--bg-soft);
  color: var(--text);
  font-size: 0.85rem;
  font-weight: 700;
  transition: border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}

.account-menu-toggle:hover .account-mark,
.account-menu-toggle:focus-visible .account-mark,
.account-menu-toggle[data-expanded="true"] .account-mark {
  border-color: var(--brand);
  background: var(--brand-soft);
  color: var(--brand-ink); /* --brand는 흰 배경 글자로 쓰기엔 대비가 부족하다 */
}

.account-menu-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 30;
  min-width: 11rem;
  /* 최대 너비를 안 두면 안 끊기는 이메일 주소 때문에 패널이 한없이
     넓어진다 — right:0 기준이라 왼쪽으로 커지면서 좁은 화면에서 뷰포트
     밖으로 나갈 수 있다. */
  max-width: min(18rem, calc(100vw - 1.5rem));
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-dropdown);
  padding: 0.5rem;
}

.account-menu-panel[hidden] {
  display: none;
}

.account-menu-email {
  margin: 0.25rem 0.75rem 0.5rem;
  color: var(--muted);
  font-size: 0.82rem;
  overflow-wrap: break-word;
}

.account-menu-divider {
  margin: 0.375rem 0;
  border: none;
  border-top: 1px solid var(--line);
}

.account-menu-item {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;
  padding: 0.5rem 0.75rem;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.account-menu-item:hover {
  background: var(--brand-soft);
  color: var(--brand-ink);
}

/* ── category color system (archive list chip) ─────────────── */
/* 카테고리 색은 상태색 4종과 구분되도록 채도를 낮췄다. */
/* ── archive list chip (.event-category) ──────────────────────── */
/* .unofficial은 비공식(개인) 기록 표시용이다. */
.event-category {
  border-radius: var(--radius-chip);
  padding: 0.25rem 0.5625rem;
  font-size: var(--fs-xs);
  font-weight: 700;
  overflow-wrap: anywhere;
  background: var(--brand-soft);
  color: var(--brand-ink);
}
/* --brand-soft 배경엔 --brand-ink를 써야 명암비 AA(4.5:1)를 만족한다. */
.event-category.unofficial {
  display: inline-flex;
  align-items: center;
  background: var(--muted-soft);
  color: var(--muted);
}

/* ── archive user-status classes (canonical slug keys) ──────── */
/* 표준 슬러그: interested / planned / visited / missed. 예전 wish/plan/done/miss는 쓰지 않는다. */
.status-btn,
.status {
  border: 1px solid var(--line);
  border-radius: var(--radius-chip);
  padding: 0.3125rem 0.625rem;
  font-size: var(--fs-sm);
  color: var(--text);
  background: var(--surface);
  cursor: pointer;
}

.status-btn.interested,
.status.interested {
  background: var(--pink-soft);
  border-color: currentColor;
  color: var(--pink-ink);
}

/* planned(예정)는 `archive.css`·`archive_statuses.css`의 `.user-status.planned`와
   같은 up(파랑) 계열로 맞춰야 `/archive/*` 형제 페이지끼리 색이 갈리지 않는다. */
.status-btn.planned,
.status.planned {
  background: var(--up-soft);
  border-color: currentColor;
  color: var(--up-ink);
}

.status-btn.visited,
.status.visited {
  background: var(--mint-soft);
  border-color: currentColor;
  color: var(--mint-ink);
}

.status-btn.missed,
.status.missed {
  background: var(--end-soft);
  border-color: currentColor;
  color: var(--end-ink);
}

/* `.active`는 status.js가 토글하는 클래스로, 서버 렌더링과 클라이언트 상태를 일치시킨다. */
.status-btn.active {
  font-weight: 700;
  box-shadow: inset 0 0 0 2px currentColor;
}

.status-btn.active::before {
  content: "✓ ";
}

/* 다른 status-btn 요청이 진행 중이거나(status.js) 서버가 선택 불가로 내려준
   경우에 흐리게 처리한다. .active("이미 추가됨")는 제외 — 확정된 완료 상태를
   "로딩 중"처럼 보이게 하면 안 되기 때문이다. */
.status-btn:disabled:not(.active) {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ── interest button (찜 toggle — independent from .status-btn) ─ */
/* .status-btn을 상속하지 않는다 — 상속하면 .status-btn.active::before의
   체크 글자가 여기에도 붙는다. 상태 표시는 ♡/♥ 하트 글자로만 한다. */
/* 찜 버튼은 옆 상태 버튼(.status-btn — 예정/방문 등)과 같은 알약 모양·높이로 통일한다. */
.interest-btn {
  border: 1px solid var(--pink-border);
  border-radius: var(--radius-chip);
  padding: 0.3125rem 0.625rem;
  font-size: var(--fs-sm);
  color: var(--pink-ink);
  background: var(--surface);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.interest-btn:hover {
  border-color: var(--pink-ink);
  background: var(--pink-soft);
}

.interest-btn.active {
  background: var(--pink-soft);
  border-color: var(--pink-border);
  color: var(--pink-ink);
  font-weight: 700;
}

@media (prefers-reduced-motion: reduce) {
  .interest-btn {
    transition: none;
  }
}

/* ── chip (filter / quick-chip) ─────────────────────────────── */
.chip {
  border-radius: var(--radius-chip);
  border: 1px solid var(--border-soft);
  background: var(--bg-soft);
  color: var(--text);
  font-size: 0.82rem;
  padding: 0.4375rem 0.75rem;
  cursor: pointer;
}

.chip.active {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-weight: 600;
}

/* ── search bar (shared: home + event_list) ─────────────────── */
/* home.css는 `.hero .search { max-width: 540px }`로 별도 오버라이드를 둔다. */
.search {
  display: flex;
  gap: 0.5rem;
  min-width: 0;
  margin: 0 0 0.75rem;
}
.search input {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.625rem 0.75rem;
  font-size: 0.95rem;
  color: var(--text);
  background: var(--surface);
}
/* 검색 버튼은 브랜드레드가 기본이다(내 활동 페이지의
   `.archive-search-row button[type="submit"]`만 예외로 teal 유지).
   컬렉션 페이지의 .collection-add-btn과는 색이 아닌 크기(34px vs 44px)로
   구분하므로 이 버튼 높이를 키우지 마라. */
.search button {
  border: 1px solid var(--brand);
  background: var(--brand);
  color: #fff;
  border-radius: 8px;
  padding: 0.625rem 0.875rem;
  font-weight: 700;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.search button:hover {
  filter: brightness(0.95);
}

/* ── form fields (shared) ─────────────────────────────────── */

.form-group {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  margin-bottom: 0.875rem;
}

.form-group label {
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--muted);
}

.form-group input {
  padding: 0.625rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  font-size: 0.95rem;
  background: var(--surface);
  color: var(--text);
}

/* ── .btn — canonical generic button component ──────────────────── */
/* 포커스 아웃라인은 base.css의 전역 a:focus/button:focus 규칙을 그대로
   물려받으므로 여기서 다시 선언하지 않는다. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 0.6875rem 0.75rem;
  /* §5.4 44px 터치 타깃: padding+line-height+border만으로는 ~42.24px
     (실측)였음. .btn-sm은 min-height를 재정의하지 않아(패딩·폰트만
     축소) 이 44px을 그대로 물려받음 — 축소는 시각 크기만이고 터치
     타깃은 모든 변형이 동일하게 44px. */
  min-height: 44px;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease,
    color 0.15s ease, filter 0.15s ease;
}

.btn-primary {
  border-color: var(--brand);
  background: var(--brand);
  color: #fff;
  font-weight: 700;
}

.btn-primary:hover {
  filter: brightness(1.05);
}

.btn-secondary {
  border-color: var(--line);
  background: var(--surface);
  color: var(--muted);
  font-weight: 400;
}

.btn-secondary:hover {
  background: var(--brand-soft);
  border-color: var(--brand);
}

/* 탈퇴 등 파괴적 동작용 배색. staff console의 .action-button.danger와 톤을 맞췄다. */
.btn-danger {
  border-color: var(--rose-ink);
  background: var(--rose-soft);
  color: var(--rose-ink);
}

.btn-danger:hover {
  filter: brightness(0.97);
}

.btn-sm {
  padding: 0.5rem 0.625rem;
  font-size: 0.82rem;
  font-weight: 600;
}

.btn-block {
  width: 100%;
}

/* ── panel ──────────────────────────────────────────────────── */
.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 0.875rem;
}

.panel-divider {
  border: none;
  border-top: 1px solid var(--line);
  margin: 0.875rem 0;
}

/* ── summary cards (shared across archive + drafts pages) ───── */
/* 요약 바의 공통 스타일. 각 페이지는 `--summary-cols`(카드 수, 최대 5)만
   지정하면 되고 카드 수만큼 균등한 열로 채워진다 — 페이지마다 다시
   정의하지 않아 모든 보관함 페이지의 요약 바가 항상 같은 모양이다. */
.summary-grid {
  display: grid;
  grid-template-columns: repeat(var(--summary-cols, 4), minmax(0, 1fr));
  gap: 0.625rem;
  margin-top: 0.875rem;
}

.summary-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--bg-card);
  padding: 0.75rem;
}

.summary-label {
  margin: 0 0 0.375rem;
  color: var(--muted);
  font-size: 0.82rem;
}

.summary-value {
  margin: 0;
  font-size: 1.28rem;
  font-weight: 700;
  line-height: 1.2;
}

/* 요약 카드가 클릭 가능한 링크(article → a)로 쓰일 때만 붙는 스타일이다.
   기본 .summary-card 자체는 건드리지 않는다. */
.summary-card-link {
  display: block;
  text-decoration: none;
  color: inherit;
}

.summary-card-link:hover {
  border-color: var(--brand);
}

/* ── hero block ─────────────────────────────────────────────── */
.hero {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-shadow: var(--shadow);
  padding: 1.125rem;
  margin-bottom: 0.875rem;
}

.hero h1 {
  margin: 0 0 0.5rem;
  font-size: 1.5rem;
  line-height: 1.3;
}

.hero p {
  margin: 0;
  color: var(--muted);
}

/* ── responsive typography: scale large text down on phones ──── */
@media (max-width: 38.75rem) {
  .hero h1 {
    font-size: 1.3rem;
  }
  .hero > p {
    font-size: 0.92rem;
  }
  .summary-value {
    font-size: 1.1rem;
  }
}

/* ── notice / empty-note ─────────────────────────────────────── */
.notice {
  border: 1px dashed var(--line);
  border-radius: 10px;
  background: var(--bg-soft);
  color: #46617f;
  padding: 0.75rem;
  font-size: 0.88rem;
}

/* 잉크 리터럴 개별 다크 오버라이드 — 신규 토큰 통합 없이 --muted 다크값과
   동일한 #A2A9B9로 직접 대응(다크모드 팔레트 문서 "크롬·그림자·잉크 리터럴",
   계획상 Deferred). */
:root[data-theme="dark"] .notice {
  color: #a2a9b9;
}

/* ── applied filter chips (event_list) ───────────────────────── */
.applied-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem;
  margin: 0 0 0.75rem;
}

.applied-chip {
  display: inline-block;
  border-radius: var(--radius-chip);
  padding: 0.25rem 0.625rem;
  font-size: 0.78rem;
  font-weight: 600;
  background: var(--brand-soft);
  color: var(--brand-ink);
  border: 1px solid var(--brand);
}

.applied-clear {
  font-size: 0.78rem;
  color: var(--muted);
  margin-left: 0.125rem;
}

/* ── empty state (shared) ────────────────────────────────────── */
.empty-state {
  text-align: center;
  padding: 2.25rem 1rem;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: #fafcff;
}

/* 유사-중복 surface 리터럴 개별 다크 오버라이드 — #fafcff는 인접
   토큰(--bg-card) 다크값을 그대로 준용해 #2E323E로 대응. */
:root[data-theme="dark"] .empty-state {
  background: #2e323e;
}

.empty-icon {
  font-size: 1.8rem;
  margin: 0 0 0.5rem;
}

.empty-title {
  margin: 0 0 0.25rem;
  font-weight: 700;
  color: var(--text);
}

.empty-note {
  margin: 0 0 0.75rem;
  font-size: 0.88rem;
  color: var(--muted);
}
/* 본문 안에 섞인 링크("지우기" 등). .empty-note가 여러 페이지에서
   재사용되므로 페이지별 스타일시트가 아니라 여기 공용 컴포넌트에 둔다. */
.empty-note a {
  color: var(--brand-ink);
  text-decoration: underline;
}

/* 컬렉션이 완전히 비었을 때 버튼 두 개를 나란히 보여주는 행 — 좁은
   화면에서는 줄바꿈된다. */
.empty-actions {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  justify-content: center;
}

/* min-height: 44px — 원래 계산 높이가 약 37~38px로 다른 인터랙티브
   요소가 지키는 44px 탭 타깃 기준에 못 미쳐 맞춰 넣었다. */
.empty-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  padding: 0.5rem 0.875rem;
  min-height: 44px;
  background: var(--brand);
  color: #fff;
  font-size: 0.85rem;
  font-weight: 700;
  text-decoration: none;
}

/* ── panel heading shared styles ─────────────────────────────── */
.panel h2 {
  margin: 0;
  font-size: 1rem;
}

.panel-note {
  margin: 0.125rem 0 0;
  color: var(--muted);
  font-size: 0.84rem;
}

/* 보관함 여러 페이지가 함께 쓰는 사이드 액션 링크 */
.side-action-link {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  border: 1px solid var(--border-soft);
  border-radius: 8px;
  background: var(--surface);
  color: #25508a;
  font-size: 0.82rem;
  font-weight: 700;
  padding: 0.5rem 0.625rem;
  text-decoration: none;
  white-space: nowrap;
  min-height: 44px;
}

/* 잉크 리터럴 개별 다크 오버라이드 — #A2A9B9(=--muted 다크값). */
:root[data-theme="dark"] .side-action-link {
  color: #a2a9b9;
}

/* 검토 상태 칩 색상만 공용으로 뺐다 — 모양(.draft-chip / .status-chip)은
   각 페이지 스타일시트가 그대로 담당한다. */
.review-status-pending {
  background: var(--amber-soft);
  color: var(--amber-ink);
}
.review-status-approved {
  background: var(--mint-soft);
  color: var(--mint-ink);
}
.review-status-rejected {
  background: var(--rose-soft);
  color: var(--rose-ink);
}

/* ── event compact row (홈 레일 3개 + 로그인 홈 다가오는 일정 공용) ──
   _event_compact_row.html이 렌더한다. 포스터 카드를 대신하는 텍스트 전용
   세로 목록 행 — 이미지·뱃지·카드 테두리 없이 여백과 헤어라인만으로
   행을 구분한다. */
.event-compact-list {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}
.event-compact-row {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr) auto;
  align-items: start;
  gap: 1rem;
  padding: 0.875rem 0;
  border-top: 1px solid var(--line);
}
.event-compact-list > .event-compact-row:first-child {
  border-top: none;
}
.event-compact-date {
  padding-top: 0.125rem;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--muted);
}
.event-compact-date time {
  font-variant-numeric: tabular-nums;
}
.event-compact-main {
  min-width: 0;
}
.event-compact-work {
  margin: 0 0 0.1875rem;
  font-size: var(--fs-xs);
  font-weight: 600;
  color: var(--muted);
  word-break: keep-all;
}
.event-compact-title {
  margin: 0 0 0.1875rem;
  font-size: var(--fs-base);
  font-weight: 700;
  line-height: 1.35;
  word-break: keep-all;
}
.event-compact-title a {
  color: inherit;
  text-decoration: none;
}
.event-compact-title a:hover {
  text-decoration: underline;
}
.event-compact-title a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 2px;
}
.event-compact-place {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--muted);
}
.event-compact-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.5rem;
}
.event-compact-status {
  font-size: var(--fs-xs);
  font-weight: 700;
  color: var(--muted);
  white-space: nowrap;
}
/* 24px 이상 + 주변 여백 확보(WCAG 2.5.8 예외 기준)로 34px 원을 유지한다
   — event_list.css의 .event-row-interest와 같은 크기다. */
.event-compact-interest {
  width: 34px;
  height: 34px;
  min-height: 0;
  padding: 0;
  gap: 0;
  border-radius: 50%;
  border: 1px solid var(--border-soft);
  background: var(--surface);
  color: var(--muted);
  font-size: 0.875rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.event-compact-interest:hover {
  border-color: var(--pink-ink);
  background: var(--pink-soft);
  color: var(--pink-ink);
}
.event-compact-interest.active {
  border-color: var(--pink-border);
  background: var(--pink-soft);
  color: var(--pink-ink);
  font-weight: 700;
}
/* 공용 .is-loading 스피너(objects/interaction.css)는 앞에 텍스트가 있는
   버튼을 전제로 여백을 둔다. 아이콘 전용 버튼마다 이 오버라이드를
   다시 넣어야 한다 — 상속되지 않는다(event_list.css:502-509와 같은
   패턴, 이 저장소가 두 번 겪은 결함). */
.event-compact-interest.is-loading [data-interest-glyph] {
  display: none;
}
.event-compact-interest.is-loading::after {
  margin-left: 0;
}

/* 모바일: 날짜/본문/행동이 DOM 순서 그대로 세로로 쌓인다(order 미사용).
   date가 항상 title보다 앞이라 자연히 제목 위 eyebrow처럼 보인다. */
@media (max-width: 45rem) {
  .event-compact-row {
    grid-template-columns: 1fr;
    gap: 0.375rem;
  }
  .event-compact-date {
    padding-top: 0;
    font-size: var(--fs-xs);
  }
  .event-compact-actions {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

/* 모든 페이지가 같은 방식으로 페이지를 넘기도록 공용 컴포넌트로 뒀다.
   마크업은 templates/core/partials/_pager.html. */
.pager {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.375rem;
  margin-top: 1.75rem;
  font-size: 0.8125rem;
}

/* 화살표·숫자·생략 칸을 모두 32px 고정 박스로 통일해 페이지 창이 움직여도 행이 흔들리지 않는다. */
.pager-arrow,
.pager-page,
.pager-gap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 0.25rem;
  border-radius: 8px;
  text-decoration: none;
  font-variant-numeric: tabular-nums;
}

.pager-arrow {
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1;
}
.pager-page {
  color: var(--text);
}
.pager-gap {
  color: var(--muted);
  min-width: 1.25rem;
}

a.pager-arrow,
a.pager-page {
  transition: background-color 0.15s ease, color 0.15s ease;
}
a.pager-arrow:hover,
a.pager-page:hover {
  background: var(--bg-soft);
  color: var(--brand-ink);
}

/* 현재 페이지는 이동할 곳이 없어 <span>이지 링크가 아니다. */
.pager-page.is-current {
  background: var(--brand);
  color: #fff;
  font-weight: 700;
}

@media (prefers-reduced-motion: reduce) {
  a.pager-arrow,
  a.pager-page {
    transition: none;
  }
}

/* ── archive-search (GET search form, archive list pages) ──────────── */
/* /archive/, /archive/statuses/, /archive/visits/, /archive/items/에서 쓴다.
   마크업: templates/core/partials/_archive_search.html */

.archive-search {
  margin-bottom: 0.75rem;
}

.archive-search-row {
  display: flex;
  align-items: center;
  gap: 0.375rem;
}

/* ⌕ 글자는 별도 요소가 아니라 input의 placeholder 첫 글자로 들어간다
   (_archive_search.html). 왼쪽 패딩을 0.875rem으로 넉넉히 둬 그 글자가
   테두리에 붙어 보이지 않게 한다. */
.archive-search-row input[type="search"] {
  flex: 1;
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.5rem 0.75rem 0.5rem 0.875rem;
  font-size: 0.9rem;
  color: var(--text);
  background: var(--surface);
  font-family: inherit;
}

.archive-search-row button[type="submit"] {
  /* --teal + 흰 텍스트 조합은 명암비 AA(라이트 5.36:1 / 다크 5.74:1)를 충족한다. */
  border: 1px solid var(--teal);
  background: var(--teal);
  color: #fff;
  border-radius: 8px;
  min-height: 34px;
  padding: 0.5rem 0.875rem;
  font-size: 0.9rem;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
  white-space: nowrap;
}

.archive-search-row button[type="submit"]:hover {
  filter: brightness(0.95);
}

.archive-search-clear {
  display: inline-block;
  margin-top: 0.375rem;
  font-size: 0.8rem;
  color: var(--muted);
}

.archive-search-clear[hidden] {
  display: none;
}

.archive-search-clear:hover {
  color: var(--text);
  text-decoration: underline;
}

/* ── live-search swap target ───────────────────────────────────────── */
/* archive_search.js가 innerHTML을 통째로 교체하는 대상이라 border/padding/margin을
   따로 두지 않는다 — 감싸기 전과 레이아웃이 달라지지 않게 하기 위해서다. */
#archive-results.is-loading {
  /* 검색 요청이 진행 중일 때만 흐리게 표시한다(archive_search.js가 토글). JS 없으면 이 클래스도 안 붙는다. */
  opacity: 0.55;
  transition: opacity 0.12s ease;
}

/* 이벤트/아카이브 목록·카드가 공유하는 텍스트 스타일 모음이다. */
.meta {
  margin: 0;
  color: var(--muted);
  font-size: 0.84rem;
}
.period {
  margin: 0.25rem 0 0;
  color: var(--text);
  font-size: var(--fs-md);
}

/* ── monospace numerals ──────────────────────────────────────────── */
/* 숫자가 가변폭 글꼴에서 흔들리지 않도록 모노스페이스 + tabular-nums를 쓴다. */
.mono-num {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* ── highlighter ("형광펜") ──────────────────────────────────────── */
/* 홈 히어로의 "한눈에" 문구 전용이다. 카드·버튼 배경으로는 확장하지 않는다.
   box-decoration-break는 줄바꿈이 생겨도 형광펜 표시가 자연스럽게 이어지게 한다. */
.hl {
  background: var(--hl);
  /* var(--text) 대신 --hl-ink를 쓴다: --text는 다크모드에서 밝은색으로
     뒤집혀 밝은 형광펜 배경과 겹치면 거의 안 보이게 된다. --hl-ink는
     테마와 무관하게 고정된 값이라 이 조합에서만 쓴다. */
  color: var(--hl-ink);
  padding: 0 0.22em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

/* ── shared inline error line ────────────────────────────────────── */
/* 컨트롤 아래 오류 한 줄을 표시하는 공용 스타일이다. auth.css의 .field-error와 같은 토큰을 쓴다. */
.inline-error {
  color: var(--rose-ink);
  font-size: var(--fs-xs);
  margin: 0.25rem 0 0;
}

/* ── live search result summary (screen-reader only) ─────────────── */
/* 검색 결과 개수는 화면에는 안 보이고 스크린리더에만 알린다(archive_search.js).
   숨김 기법은 photo-upload.css의 .photo-upload-native-input과 같다. */
.archive-search-status {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ── sub-nav (shared staff console chrome) ───────────────────── */
.sub-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
}

/* ── nav-links (archive + draft topbars) ────────────────────── */
.nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  justify-content: center;
}

.nav-links a {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  border: 1px solid var(--border-soft);
  background: var(--bg-soft);
  color: var(--text);
  padding: 0.4375rem 0.75rem;
  border-radius: 999px;
  font-size: 0.84rem;
  font-weight: 600;
  min-height: 44px;
}

.nav-links a.active {
  background: var(--brand);
  color: #fff;
  border-color: var(--brand);
}

/* ── archive tab bar (always-visible sub-nav, shared by 5 archive pages) ── */
/* 예전엔 아코디언(<details>)이었지만 지금은 항상 펼쳐진 탭 줄이고, 현재
   탭은 밑줄로 표시한다(site-nav의 `.active::after` 방식을 재사용). */
.archive-nav-wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.625rem;
  width: 100%;
  border-bottom: 1px solid var(--line);
}

.archive-nav-tabs {
  display: flex;
  flex-wrap: wrap;                /* 320px 전 탭 도달 보장 — overflow:hidden 금지 */
  gap: 0.125rem 0.5rem;
}

.archive-nav-tabs a {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.5rem 0.625rem;
  text-decoration: none;
  color: var(--muted);
  font-size: 0.88rem;
  font-weight: 600;
  transition: color 0.15s ease;
}

.archive-nav-tabs a:hover {
  color: var(--brand-ink);
}

.archive-nav-tabs a.active {
  color: var(--text);
  font-weight: 700;
}

.archive-nav-tabs a.active::after {
  content: "";
  position: absolute;
  left: 0.625rem;
  right: 0.625rem;
  bottom: -1px;                   /* 부모 밑줄과 딱 맞춘다 */
  height: 2px;
  border-radius: 2px;
  background: var(--teal);
}

/* 서브탭 짧은 라벨 — 각 탭 앵커가 `.tab-label-full`/`.tab-label-short` 두
   span을 함께 렌더하고 브레이크포인트별로 CSS만으로 하나를 고른다(JS 없음).
   `_archive_nav.html`을 로드하지 않는 페이지도 있어 이 규칙은 페이지별
   스타일시트가 아니라 전역 로드되는 이 컴포넌트 파일에 둔다. a11y 트리에
   라벨이 하나만 남아야 해서 `display:none`을 쓴다 — opacity/clip을 쓰면
   스크린리더가 라벨을 두 번 읽는다. */
.tab-label-short {
  display: none;
}

@media (max-width: 53.75rem) {
  .tab-label-full {
    display: none;
  }
  .tab-label-short {
    display: inline;
  }
}

/* 찜 목록 — 독립된 핑크 필 모양, 오른쪽 정렬 */
.archive-nav-wrap .nav-interest {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  border: 1px solid var(--pink-border);
  background: var(--surface);
  color: var(--pink-ink);
  padding: 0.4375rem 0.75rem;
  border-radius: 999px;
  font-size: 0.84rem;
  font-weight: 600;
  min-height: 44px;
  transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.archive-nav-wrap .nav-interest:hover {
  background: var(--pink-soft);
  border-color: var(--pink-ink);
  transform: translateY(-1px);
  box-shadow: 0 2px 8px rgba(214, 81, 138, 0.18);
}

.archive-nav-wrap .nav-interest.active {
  background: var(--pink-soft);
  border-color: var(--pink-border);
}

/* 모바일에서는 archive/draft 상단 탭바를 왼쪽 정렬한다. */
@media (max-width: 45rem) {
  .nav-links {
    justify-content: start;
  }
}

/* ── activity view toggle: 목록 | 달력 ─────────────────────────── */
/* `/archive/`와 `/archive/calendar/`가 서로 다른 페이지 스타일시트만
   불러오는데 이 토글은 두 페이지 모두에 있어, 전역 로드되는 이 컴포넌트
   파일에 모양을 둔다(페이지 CSS에 두면 한쪽이 무스타일로 렌더된다).
   컬렉션의 `.collection-view-toggle`과 같은 시각 어휘를 쓰되 활성색만
   청록으로 다르다. 그리드 안 위치(justify-self)는 `/archive/`에만
   해당하는 레이아웃 문제라 archive.css의 `.hero-activity
   .activity-view-toggle`에 남겨 뒀다. */
.activity-view-toggle {
  display: flex;
  gap: 1rem;
}

.activity-view-btn {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-bottom: 0.1875rem;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.15s ease;
}

.activity-view-btn:hover {
  color: var(--teal-ink);
}

.activity-view-btn.is-active {
  color: var(--teal-ink);
  font-weight: 700;
  border-bottom-color: var(--teal);
}

@media (prefers-reduced-motion: reduce) {
  .activity-view-btn {
    transition: none;
  }
}

/* ── activity-series teal accent ───────────────────────────────── */
/* 내 활동 계열 페이지들은 각자 자기 페이지 CSS만 불러와, 예전에는 일부
   페이지만 청록으로 바뀌고 나머지는 기본 브랜드 레드로 남는 결함이
   있었다. `.activity-page`로 스코프해 특이도로 `controls.css`/
   `pager.css`의 무스코프 기본 규칙을 로드 순서와 무관하게 이긴다.
   `/collection/`은 `.activity-page` 클래스가 없어 브랜드 레드를
   그대로 쓴다. */
.activity-page .chip.active {
  background: var(--teal);
  border-color: var(--teal);
}

.activity-page .pager-page.is-current {
  background: var(--teal);
}

/* ── top-action button (archive + draft topbars) ────────────── */
.top-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  border: 1px solid var(--brand);
  background: var(--brand-soft);
  color: var(--brand-ink);
  font-weight: 700;
  padding: 0.5rem 0.75rem;
  border-radius: 8px;
  min-height: 44px;
}

/* ── topbar auth nav (shared _topbar.html partial) ──────────── */
.topbar-auth {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: nowrap;
}

.topbar-username {
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  /* 이메일이 길면 .topbar-auth가 늘어나 .site-nav 링크가 줄바꿈되고
     sticky .site-header가 2줄로 커진다(site-chrome.css --site-header-h가
     그 높이에 맞춰져 있음). max-width로 상한을 둬 헤더 한 줄을 지킨다.
     단, 관리자 링크까지 4개가 붙는 슈퍼유저는 이 상한으로도 못 막아
     2줄이 되는 잔여 한계가 있다. */
  max-width: 15rem;
  overflow: hidden;
  text-overflow: ellipsis;
  display: inline-block;
}

/* 같은 줄의 주 메뉴(.site-nav a, site-chrome.css)와 동일한 글자 크기·
   패딩·터치 타깃(44px)으로 맞췄다. */
.topbar-link {
  display: inline-flex;
  align-items: center;
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--brand-ink);
  text-decoration: none;
  border: 1px solid var(--border-soft);
  background: var(--bg-soft);
  border-radius: 8px;
  padding: 0.375rem 0.75rem;
  white-space: nowrap;
  min-height: 44px;
}

.topbar-link:hover {
  background: var(--brand-soft);
}

/* 로그아웃 폼의 기본 form 스타일을 지워 버튼이 링크처럼 보이게 한다 */
.topbar-logout-form {
  display: inline-flex;
  margin: 0;
  padding: 0;
}

.topbar-logout-btn {
  cursor: pointer;
  font-family: inherit;
  line-height: 1;
}

/* ── login prompt modal (shown when a guest tries to save) ──── */
.auth-modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  background: var(--backdrop);
}

.auth-modal {
  position: relative;
  width: 100%;
  max-width: 360px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 1.75rem 1.5rem 1.5rem;
  text-align: center;
}

.auth-modal h2 {
  margin: 0 0 0.5rem;
  font-size: 1.2rem;
}

.auth-modal p {
  margin: 0 0 1.25rem;
  color: var(--muted);
  font-size: 0.92rem;
}

.auth-modal-actions {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}

.auth-modal-primary {
  display: block;
  padding: 0.6875rem 0.75rem;
  border-radius: 8px;
  background: var(--brand);
  color: #fff;
  font-weight: 700;
  text-decoration: none;
}

.auth-modal-primary:hover {
  filter: brightness(1.05);
}

.auth-modal-secondary {
  display: block;
  padding: 0.6875rem 0.75rem;
  border-radius: 8px;
  border: 1px solid var(--line);
  color: var(--brand-ink);
  font-weight: 600;
  text-decoration: none;
}

.auth-modal-secondary:hover {
  background: var(--brand-soft);
}

.auth-modal-close {
  position: absolute;
  top: 10px;
  right: 12px;
  border: none;
  background: none;
  cursor: pointer;
  font-size: 1.3rem;
  line-height: 1;
  color: var(--muted);
}

/* confirm-modal.js와 짝을 이룬다: [hidden] 속성으로 숨기고, 열 때 [hidden]을
   제거하며 .is-open을 붙여 전환 애니메이션을 튼다. */

.confirm-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--backdrop);
  z-index: 1000;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.confirm-overlay[hidden] {
  display: none;
}

/* 모달이 열려 있는 동안 confirm-modal.js가 <html>에 붙인다. 스크롤바 폭
   보정은 하지 않아 데스크톱에서 1px 내외 밀림은 감수한다. */
.confirm-scroll-lock {
  overflow: hidden;
}

/* 안전장치: [hidden]이 복구되지 않는 오류가 나도 닫힌 오버레이가 클릭을 가로채면 안 된다. */
.confirm-overlay:not(.is-open) {
  pointer-events: none;
}

.confirm-overlay.is-open {
  opacity: 1;
}

.confirm-dialog {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--shadow);
  padding: 1.25rem;
  max-width: 360px;
  width: calc(100% - 32px);
  transform: translateY(6px);
  transition: transform 0.15s ease;
}

.confirm-overlay.is-open .confirm-dialog {
  transform: translateY(0);
}

.confirm-message {
  font-size: 0.95rem;
  color: var(--text);
  margin: 0 0 1.125rem;
  line-height: 1.5;
}

.confirm-actions {
  display: flex;
  gap: 0.625rem;
  justify-content: flex-end;
}

.confirm-no,
.confirm-yes {
  border-radius: 8px;
  padding: 0.5rem 1rem;
  min-height: 44px;
  font-weight: 600;
  cursor: pointer;
  font-size: 0.9rem;
}

.confirm-no {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--line);
}

.confirm-yes {
  background: var(--brand);
  color: #fff;
  border: 1px solid var(--brand);
}

.confirm-no:hover {
  background: var(--surface-alt);
}

.confirm-yes:hover {
  filter: brightness(0.93);
}

@media (prefers-reduced-motion: reduce) {
  .confirm-overlay,
  .confirm-dialog {
    transition: none;
  }
}

/* position:fixed로 둬 문서 흐름에 끼지 않게 한다(좁은 화면 가로 스크롤 방지).
   z-index는 event_detail.css의 .mobile-cta(20)보다 위, confirm-modal.css의
   .confirm-overlay(1000)보다 아래로 둔다. */

.taku-toast {
  position: fixed;
  left: 50%;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  transform: translate(-50%, 8px);
  z-index: 40;
  max-width: calc(100% - 2rem);
  padding: 0.625rem 1rem;
  border-radius: 999px;
  background: var(--text);
  /* 흰색 리터럴 대신 var(--bg)를 쓴다: --text/--bg는 테마별로 짝을 이루는
     고대비 쌍이라, 배경을 --text로 채운 이 토스트가 다크모드에서도
     별도 오버라이드 없이 자동으로 뒤집힌다. */
  color: var(--bg);
  font-size: var(--fs-md);
  font-weight: 600;
  text-align: center;
  box-shadow: var(--shadow);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.taku-toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

@media (prefers-reduced-motion: reduce) {
  .taku-toast {
    transition: none;
  }
}
