/* 오행의 정원 — 디자인 시스템 v1 (docs/design-system.md).
   토큰(§2~4) → 컴포넌트(§5) → 모션(§6). 기존 클래스명은 전부 유지(§9 이행 경로).
   모바일 퍼스트 390px 기준. 색 단일 소스: src/lib/theme.ts와 값 동기(§9 Phase 0-4). */

/* ---- 폰트 (§3.1) ---- */
@font-face {
  font-family: 'Pretendard';
  src: url('/fonts/Pretendard-Regular.otf') format('opentype');
  font-weight: 400;
  font-display: swap;
}

@font-face {
  font-family: 'Pretendard';
  src: url('/fonts/Pretendard-Bold.otf') format('opentype');
  font-weight: 700;
  font-display: swap;
}

@font-face {
  font-family: 'Gowun Batang';
  src: url('/fonts/GowunBatang-Bold.subset.woff2') format('woff2');
  font-weight: 700;
  font-display: swap; /* 폴백 = Apple SD Gothic Neo, FOUT 허용 */
}

:root {
  /* 지반 (§2.1) */
  --bg-deep: #131318;
  --bg: #1b1b23; /* 변경 금지 — 픽셀 에셋 제작 기준색 */
  --bg-raised: #24242f;
  --bg-overlay: #2d2d3a;
  --scrim: rgba(9, 9, 13, 0.6);
  --border: #34343f;
  --border-strong: #454553;
  --edge-light: rgba(255, 255, 255, 0.06);

  /* 잉크 (§2.2) */
  --ink: #f2f2f7;
  --ink-body: #d6d6e0;
  --ink-muted: #9c9cb0;
  --ink-faint: #6f6f82;

  /* 오행 기능색 (§2.3) — 데이터 지시 전용, 장식 금지(§7-8) */
  --el-wood: #4c9a5b;
  --el-wood-text: #7fc488;
  --el-wood-dim: #232f2c;
  --el-fire: #e0553f;
  --el-fire-text: #f0876f;
  --el-fire-dim: #3b2427;
  --el-earth: #c79a45;
  --el-earth-text: #d9ae5f;
  --el-earth-dim: #372f28;
  --el-metal: #cfc3a0;
  --el-metal-text: #e3d7b4;
  --el-metal-dim: #35322a;
  --el-water: #4a8ccb;
  --el-water-text: #7fb2e5;
  --el-water-dim: #232d3e;

  /* 액센트 — 단일 브랜드 액센트 "새싹 라임" (§2.4) */
  --accent: #9bd457;
  --accent-ink: #17210d;
  --accent-hover: #a7d96b;
  --accent-active: #88bb4d;
  --accent-dim: #2f392b;

  /* 시맨틱 (§2.5) */
  --ok: #6fbf73;
  --warn: #d9a83c;
  --danger: #e5484d;
  --danger-text: #f2b8b8;
  --danger-surface: #3a2323;

  /* 타이포 (§3) */
  --font-body: -apple-system, BlinkMacSystemFont, 'Apple SD Gothic Neo',
    'Pretendard Variable', 'Pretendard', 'Malgun Gothic', sans-serif;
  --font-display: 'Gowun Batang', 'Apple SD Gothic Neo', serif;
  --fs-display: 26px;
  --fs-title: 20px;
  --fs-heading: 16px;
  --fs-body: 15px;
  --fs-caption: 13px;
  --fs-label: 12px;

  /* 간격 (§4.1) */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-12: 48px;

  /* 반경 4단 (§4.2) */
  --r-sheet: 20px;
  --r-card: 14px;
  --r-control: 10px;
  --r-sm: 6px;
  --r-pill: 999px;

  /* 모션 (§6) */
  --dur-fast: 150ms;
  --dur-base: 240ms;
  --dur-slow: 600ms;
  --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);

  /* 구 토큰 별칭 (§9 Phase 0-2 — 기존 규칙 호환) */
  --bg-elevated: var(--bg-raised);
  --text: var(--ink);
  --text-muted: var(--ink-muted);
  --radius: var(--r-card);
  --danger-bg: var(--danger-surface);

  font-size: 16px;
}

/* 오행 데이터 색 배선 — data-el 슬러그(wood/fire/earth/metal/water)로 지정.
   (비멤버 화면 마스킹 규칙상 DOM엔 한자 오행을 싣지 않는다 — lib/theme.ts ELEMENT_KEY) */
[data-el='wood'] { --el: var(--el-wood); --el-text: var(--el-wood-text); --el-dim: var(--el-wood-dim); }
[data-el='fire'] { --el: var(--el-fire); --el-text: var(--el-fire-text); --el-dim: var(--el-fire-dim); }
[data-el='earth'] { --el: var(--el-earth); --el-text: var(--el-earth-text); --el-dim: var(--el-earth-dim); }
[data-el='metal'] { --el: var(--el-metal); --el-text: var(--el-metal-text); --el-dim: var(--el-metal-dim); }
[data-el='water'] { --el: var(--el-water); --el-text: var(--el-water-text); --el-dim: var(--el-water-dim); }

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink-body);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.6;
  word-break: keep-all; /* §3.4 — 어절 중간 개행 금지 */
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
}

/* 브라우저 디폴트 유출 차단 (§7-3) */
a {
  color: var(--accent);
}

input[type='checkbox'],
input[type='radio'] {
  accent-color: var(--accent);
  width: 20px;
  height: 20px;
}

:is(a, button, input, select, summary):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.app-shell {
  max-width: 480px;
  margin: 0 auto;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.app-main {
  flex: 1;
  padding: 20px 20px 32px;
}

.app-main.has-tabbar {
  padding-bottom: 88px;
}

/* ---- 하단 고정 탐색 4탭 ---- */
.tabbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  max-width: 480px;
  margin: 0 auto;
  display: flex;
  background: var(--bg-raised);
  border-top: 1px solid var(--border);
  box-shadow: inset 0 1px 0 var(--edge-light);
  padding: 8px 0 calc(8px + env(safe-area-inset-bottom));
}

.tabbar-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  text-decoration: none;
  color: var(--ink-muted);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 4px 0;
}

.tabbar-item.is-active {
  color: var(--ink);
}

/* 이모지 → 보유 픽셀 에셋 아이콘 (§7-4 / §9 Phase 3) */
.tabbar-icon-img {
  width: 24px;
  height: 24px;
  object-fit: contain;
  image-rendering: pixelated;
  filter: grayscale(1) brightness(1.45);
  opacity: 0.65;
}

.tabbar-item.is-active .tabbar-icon-img {
  filter: none;
  opacity: 1;
}

/* ---- 공통 타이포 ---- */
.screen-title {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.4;
  color: var(--ink);
  margin: 4px 0 20px;
}

h1,
h2,
h3,
strong,
b {
  color: var(--ink);
}

.disclaimer {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  text-align: center;
  margin-top: var(--sp-6);
}

/* 섹션 헤더 (§5.5) — heading 16px + 픽셀 divider(화면당 1회).
   .section-title은 §5.5가 예고한 통합 클래스. 개인 결과 화면처럼 한 화면에 섹션이 2개 이상이면
   divider는 붙이지 않는다(§5.5 "화면당 1회" — 설정 구역 제목이 이미 쓰는 방식과 동일). */
.section-title,
.member-roles h2,
.settings-choice-card h2,
.garden-list-preview h2,
.legal-section h2,
.faq-section-title {
  font-size: var(--fs-heading);
  font-weight: 700;
  color: var(--ink);
  margin: var(--sp-8) 0 var(--sp-3);
}

.member-roles h2 .member-count,
.garden-list-preview h2 .member-count {
  color: var(--ink-muted);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.member-roles h2::after,
.garden-list-preview h2::after {
  content: '';
  display: block;
  height: 16px;
  margin-top: var(--sp-2);
  background: url('/assets/ui/divider.png') center center / auto 64px no-repeat; /* 2026-08-16 오너 피드백 — 좌측 치우침 → 중앙 정렬 */
  image-rendering: pixelated;
  opacity: 0.7;
}

/* ---- 버튼 (§5.1) ---- */
.cta-primary {
  display: block;
  width: 100%;
  text-align: center;
  background: var(--accent);
  color: var(--accent-ink);
  border: none;
  border-radius: var(--r-control);
  padding: 14px 16px;
  min-height: 52px;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast) ease, transform 80ms ease;
}

.cta-primary:hover {
  background: var(--accent-hover);
}

.cta-primary:active {
  background: var(--accent-active);
  transform: scale(0.985);
}

.cta-primary:disabled {
  background: var(--bg-raised);
  color: var(--ink-faint);
  cursor: default;
}

.cta-secondary {
  display: block;
  width: 100%;
  text-align: center;
  background: transparent;
  color: var(--ink-body);
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  padding: 11px 14px;
  min-height: 44px;
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  margin-top: 10px;
  transition: background var(--dur-fast) ease, border-color var(--dur-fast) ease;
}

.cta-secondary:hover {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--border-strong);
}

.cta-secondary:active {
  background: rgba(255, 255, 255, 0.07);
}

.cta-ghost {
  display: inline-block;
  background: none;
  border: none;
  padding: 10px 0;
  color: var(--accent);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.cta-ghost:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}

.cta-danger {
  display: block;
  width: 100%;
  text-align: center;
  background: transparent;
  color: var(--danger-text);
  border: 1px solid color-mix(in srgb, var(--danger) 60%, transparent);
  border-radius: var(--r-control);
  padding: 11px 14px;
  min-height: 44px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.cta-danger:hover {
  background: var(--danger-surface);
}

.cta-stack {
  margin-top: var(--sp-8);
}

/* ---- S01 랜딩 + 입력 ---- */

/* 상시 로그인 진입점(2026-08-17) — 「이미 정원이 있나요? [로그인]」 한 줄.
   🔴 이 줄의 목적은 **주 입구를 이기지 않는 것**이다. 주 입구는 아래 「내 사주 보기」(.cta-primary
   유일 1개)이고, 여기는 부차 진입점이다. 그래서 표면(배경·보더·반경)을 주지 않았다 — 카드로
   감싸면 revisit-card와 같은 위계로 올라가 첫 화면에 "선택지 두 개"가 생긴다. 안내는 muted 캡션,
   버튼은 내용 폭(아래 .landing-login-cta)이라 노란 면적 자체가 작다.
   wrap: 긴 문구·큰 글씨 설정에서 겹치는 대신 버튼이 다음 줄로 내려간다. */
.landing-login {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}

.landing-login-line {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  margin: 0;
  word-break: keep-all;
}

.revisit-card {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  background: var(--accent-dim);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: var(--r-card);
  padding: var(--sp-4);
  margin-bottom: var(--sp-5);
  text-decoration: none;
  color: var(--ink);
}

.revisit-card-icon {
  width: 32px;
  height: 32px;
  object-fit: contain;
  image-rendering: pixelated;
  flex-shrink: 0;
}

.revisit-card-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.revisit-card-title {
  display: block;
  font-weight: 700;
}

.revisit-card-sub {
  display: block;
  font-size: var(--fs-caption);
  color: var(--ink-muted);
}

/* 픽셀 히어로 — 대표 스프라이트 1점 + 디스플레이 타이틀 조판 */
.hero {
  text-align: center;
  margin-bottom: var(--sp-8);
}

.hero-visual {
  position: relative;
  width: 150px;
  margin: var(--sp-4) auto 0;
}

.hero-visual img {
  position: relative;
  z-index: 1;
  width: 100%;
  image-rendering: pixelated;
}

.hero-title {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.35;
  color: var(--ink);
  margin: var(--sp-4) 0 0;
}

/* §2.5 규칙 이행 — "danger는 반드시 아이콘 또는 명시 문구와 동반". 규칙만 있고 구현이 없었다.
   §4.5 파생 규칙상 "채운 틴트 배경 + 좌측 보더"는 이제 시맨틱 전용 문법이지만, 색에만 의존하면
   색약 사용자에게 정보 카드와 구분되지 않으므로 아이콘으로 이중 부호화한다. */
.age-gate-warning,
.form-error {
  background: var(--danger-surface);
  color: var(--danger-text);
  border-left: 3px solid var(--danger);
  border-radius: var(--r-sm) var(--r-card) var(--r-card) var(--r-sm);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  font-size: 14px;
  display: flex;
  gap: var(--sp-2);
}

.age-gate-warning::before,
.form-error::before {
  content: '!';
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  margin-top: 2px;
  border-radius: 50%;
  background: var(--danger);
  color: var(--ink);
  font-weight: 700;
  font-size: 13px;
  line-height: 18px;
  text-align: center;
}

.field-group {
  border: none;
  padding: 0;
  margin: 0 0 18px;
}

.field-group legend {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
  margin-bottom: var(--sp-2);
  padding: 0;
}

.date-row {
  display: flex;
  gap: var(--sp-2);
}

select,
input[type='text'] {
  background: var(--bg-raised);
  color: var(--ink);
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  padding: 12px 14px;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  min-height: 48px;
  flex: 1;
  min-width: 0;
  font-variant-numeric: tabular-nums;
}

input[type='text']::placeholder {
  color: var(--ink-faint);
}

select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%239c9cb0' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  padding-right: 34px;
}

select:focus,
input[type='text']:focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent);
}

.radio-inline,
.checkbox-inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-right: var(--sp-4);
  font-size: 14px;
}

.checkbox-inline.consent {
  display: flex;
  align-items: flex-start;
  margin: var(--sp-2) 0 var(--sp-5);
  font-size: var(--fs-caption);
  line-height: 1.5;
  color: var(--ink-muted);
}

.checkbox-inline.consent input {
  flex-shrink: 0;
  margin-top: 1px;
}

.about {
  margin-top: var(--sp-8);
  font-size: 14px;
  color: var(--ink-muted);
  line-height: 1.6;
}

/* ---- S02 로딩 ---- */
.screen-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 70vh;
  text-align: center;
  background: radial-gradient(80% 60% at 50% 45%, transparent 0%, var(--bg-deep) 100%);
}

/* 씨앗→새싹 픽셀 연출(스피너 대체) — 보유 obj 스프라이트 3프레임 크로스컷 */
.loading-sprite {
  position: relative;
  width: 88px;
  height: 88px;
  margin-bottom: var(--sp-5);
}

.loading-sprite img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
  opacity: 0;
  animation: seed-frame 1.8s infinite;
}

.loading-sprite img:nth-child(1) {
  opacity: 1; /* 모션 비활성(reduce) 시 정적 폴백 프레임 */
  animation-delay: 0s;
}

.loading-sprite img:nth-child(2) {
  animation-delay: 0.6s;
}

.loading-sprite img:nth-child(3) {
  animation-delay: 1.2s;
}

@keyframes seed-frame {
  0%, 33% {
    opacity: 1;
  }
  33.4%, 100% {
    opacity: 0;
  }
}

.spinner {
  width: 40px;
  height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
  margin-bottom: 20px;
}

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

.loading-text {
  font-size: var(--fs-body);
  color: var(--ink);
  margin: 0 0 4px;
}

.loading-sub {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  margin: 0;
}

/* ---- 정원 디오라마 (v2 개편, 2026-08-15) ----
   원형 마스크(clip-path/border-radius)에 갇힌 "정원 사진"이 아니라, 배경 위에 떠 있는 섬(디오라마)
   오브제로 보이게 한다: 카드 프레임/테두리로 다시 가두지 않고, 넉넉한 여백 + 바닥 그림자로
   "떠 있음"을 표현한다. 오브젝트가 섬 실루엣 위로 튀어나와도 잘리지 않도록 overflow는 항상
   visible. 개인 결과(plant)/그룹·씨앗 정원(bg+terrain+obj+center) 양쪽이 공유한다. */
.diorama-stage {
  position: relative;
  padding: 36px 12px 28px;
  display: flex;
  flex-direction: column;
  align-items: center;
  background: transparent; /* 페이지 다크 톤(body background) 그대로 노출 */
  animation: diorama-in 400ms ease-out; /* §6 허용 목록 — 등장 1회 */
}

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

/* 무대 글로우(§4.4) — 정원 대표 오행 dim색을 인라인 --stage-glow로 주입받아 라디얼로 깐다.
   오행이 UI로 스며드는 공인 통로(원칙 2 — 액센트/데이터 분리 유지). */
.diorama-stage::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(60% 45% at 50% 42%, var(--stage-glow, transparent) 0%, transparent 70%);
  pointer-events: none;
}

.diorama-frame {
  position: relative;
  width: min(300px, 78vw);
  aspect-ratio: 1 / 1;
  overflow: visible; /* 핵심 — 더 이상 잘라내지 않는다 */
}

.diorama-frame-empty {
  display: flex;
  align-items: center;
  justify-content: center;
}

.diorama-frame-single img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain; /* 이미 투명 배경의 스프라이트라 cover로 잘라낼 필요가 없다 */
  image-rendering: pixelated;
}

/* 바닥 타원 그림자 — "화면 속 오브제"로 읽히게 하는 핵심 장치. bg 이미지(불투명이든 섬형 투명
   코너든)에 가려지지 않도록 프레임 "바깥"(bottom이 음수)에 걸쳐서 페이지 배경 위에 앉힌다.
   (2026-08-16 UX 감사 — 과중하던 농도 0.95/0.55를 0.55/0.30으로 완화. 오브제별 접지 그림자
   .grid-obj-shadow는 정합 수정 완료 영역이라 건드리지 않는다.) */
.diorama-shadow {
  position: absolute;
  left: 50%;
  bottom: -12px;
  width: 66%;
  height: 30px;
  transform: translateX(-50%);
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.3) 40%, rgba(0, 0, 0, 0) 78%);
  z-index: 0;
  pointer-events: none;
}

.diorama-caption {
  margin-top: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  text-align: center;
}

.plant-name {
  font-family: var(--font-display);
  font-size: var(--fs-title);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.nickname-tag {
  font-size: var(--fs-label);
  color: var(--ink-muted);
  background: rgba(0, 0, 0, 0.4);
  padding: 2px 8px;
  border-radius: var(--r-pill);
}

/* ---- 오행 게이지 바 (§5.6) ---- */
/* 헤딩이 없는 섹션이라 개편 전엔 간격을 통째로 잃었다(§4.1.1). 래퍼가 직접 소유한다.
   margin-bottom은 두지 않는다 — 다음 섹션이 자기 margin-top을 갖는다(부모·자식 양쪽 margin 금지). */
.element-bars {
  margin-top: var(--sp-8);
}

.interpretation {
  margin-top: var(--sp-8);
}

/* 그룹 정원의 사실 카드는 개인 결과와 달리 <section> 래퍼 없이 <ol>만 놓인다 —
   그래서 섹션 간격을 잃고 오행 바에 붙어 있었다(실측 14px). 목록 자신이 간격을 소유한다(§4.1.1).
   뒤에 오는 .interpretation-sentences{margin:0}를 이기려면 클래스 2개로 특정도를 올려야 한다. */
.interpretation-sentences.garden-facts {
  margin-top: var(--sp-8);
}

.element-bar {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: var(--sp-2);
}

.element-bar-label {
  width: 20px;
  font-weight: 700;
  color: var(--el-text, var(--ink-body)); /* 색·글자 이중 부호화(색약 대응) */
}

.element-bar.is-primary .element-bar-label {
  color: var(--ink);
}

.element-bar-track {
  flex: 1;
  height: 10px;
  background: rgba(255, 255, 255, 0.07); /* 카드 위에서도 소실되지 않는 흰색 알파 트랙 */
  border-radius: var(--r-pill);
  overflow: hidden;
}

.element-bar-fill {
  height: 100%;
  min-width: 10px; /* 1%도 점으로 보이게 */
  border-radius: var(--r-pill);
  background: var(--el, var(--ink-muted));
}

.element-bar-value {
  width: 44px;
  text-align: right;
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* 결핍 오행 표시 — 밑줄 장식 폐지(링크 오독), 값 옆 캡션으로 대체 */
.element-bar-tag {
  position: absolute;
  right: 58px;
  font-size: 11px;
  color: var(--ink-faint);
  background: var(--bg);
  border-radius: var(--r-pill);
  padding: 0 6px;
  pointer-events: none;
}

.element-summary-text {
  margin-top: var(--sp-3);
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-muted);
}

.element-summary-text strong {
  color: var(--ink-body);
}

/* 해석 문장 — "전부 같은 회색 카드" 탈출 지점(§5.2): 왼쪽 2px 오행 보더 + dim 배경 */
.interpretation-sentences {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* §4.5 면적 규칙 — 대면적(화면 폭 카드)에는 오행 dim 배경을 채우지 않는다.
   개편 전: background: var(--el-dim) + 2px 보더. 火 사용자에겐 --el-fire-dim(#3b2427)이
   --danger-surface(#3a2323)와 ΔE 2.14(식별 임계 미만)라 해석 카드가 에러 박스와 같은 물건이었고,
   土 사용자에겐 warn으로 읽혔다(§2.5.1 실측). 표면을 중립으로 되돌리고 오행색은 좌측 보더로 후퇴.
   보더를 2→3px로 굵히고 좌측 패딩을 --sp-5로 늘려 배경이 빠진 만큼의 오행 신호를 되찾는다. */
.interpretation-sentences li {
  background: var(--bg-raised);
  border-left: 3px solid var(--el, var(--border-strong));
  border-radius: var(--r-sm) var(--r-card) var(--r-card) var(--r-sm);
  padding: var(--sp-4);
  padding-left: var(--sp-5);
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--ink-body);
}

/* 문장 라벨(§5.5 라벨 타이포) — 무엇을 말하는 문장인지 앞에 세운다. 오행색이 이미 왼쪽 보더로
   쓰이고 있으므로 라벨은 --ink-muted로 두어 문장 본문과 위계를 만든다(색을 하나 더 발명하지 않음). */
.interpretation-label {
  display: block;
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
  margin-bottom: var(--sp-1);
}

.interpretation-text {
  display: block;
}

/* ---- S2 함께 두면 잘 자라는 화분 (개인 결과, primary CTA 바로 위) ----
   내 화분(대형 디오라마)과 혼동되지 않도록 소형 카드 격자로 낮춘다. 카드 안에 버튼을 두지
   않는다(§5.1 화면당 primary 1개). 점수·순위 표기는 존재하지 않는다(안전 4원칙 ①). */
.match-section {
  margin-top: var(--sp-8);
}

/* 래퍼가 섹션 간격을 소유하므로 안쪽 헤딩의 기본 margin-top(--sp-8)은 상쇄한다(양쪽 margin 금지) */
.match-section .section-title {
  margin-top: 0;
}

.match-card-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-2);
}

.match-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  background: var(--bg-raised);
  border: 1px solid transparent;
  border-radius: var(--r-card);
  padding: var(--sp-3);
  text-align: center;
}

/* 1순위(결핍 보완) 카드 — 한 줄 전체를 쓰고 가로 배치로 이유 문장까지 담는다.
   카드가 2장뿐일 때(일간 없음 → R3 생략)도 반쪽 칸이 비어 보이지 않게 나머지 한 장이 행을 다 쓴다. */
.match-card.is-lead,
.match-card:nth-child(2):last-child {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: var(--sp-3);
  text-align: left;
  padding: var(--sp-3) var(--sp-4);
}

/* 픽셀 스프라이트 자리 — 멤버 카드의 40px 오행 심볼 자리와 같은 문법(§5.2), 크기만 키운다.
   배경은 카드 data-el이 배선한 해당 화분 대표 오행의 --el-dim이라 오행이 이중 부호화된다.
   🔴 크기는 레이아웃(가로형 lead / 격자형)과 무관하게 항상 같다 — 카드마다 화분 크기가 달라지면
   "더 큰 화분이 더 좋은 추천"이라는 없는 위계가 읽힌다(2026-08-16 실사용 버그 ①). 위계는
   카드 폭·이유 문장이 만들고, 이미지는 비교 가능한 상수로 둔다. */
.match-card-thumb {
  flex-shrink: 0;
  width: var(--match-thumb, 72px);
  height: var(--match-thumb, 72px);
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--el-dim, var(--bg-overlay));
  border-radius: var(--r-sm);
}

.match-card-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}

.match-card-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.match-card-name {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-body);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.match-card-line {
  margin: 0;
  font-size: var(--fs-label);
  line-height: 1.5;
  color: var(--ink-muted);
}

.match-card-reason {
  margin: var(--sp-1) 0 0;
  font-size: var(--fs-caption);
  line-height: 1.6;
  color: var(--ink-body);
}

.match-section-note {
  margin: var(--sp-3) 0 0;
  font-size: var(--fs-caption);
  line-height: 1.6;
  color: var(--ink-muted);
  text-align: center;
}

/* ---- S1 강점 칩 섹션 ---- */
/* §4.1.1 섹션 경계 규칙 — 섹션 사이는 항상 --sp-8(32px), 섹션 내부(헤딩→내용)는 --sp-3(12px).
   간격은 섹션 래퍼가 소유한다(헤딩의 margin-top이 아니라). 개편 전엔 .element-bars에 margin-top이
   없어 "이런 특징이 있어요"(내부 12px)와 오행 바 사이가 0px이었고, 근접성 원리상 오행 바가
   강점 섹션에 딸린 것처럼 보였다 — 오너 지적 지점. */
.strength-chips {
  margin-top: var(--sp-8);
}

.strength-chips .section-title {
  margin-top: 0;
}

/* ---- S04 홈 (구) ----
   @deprecated 2026-08-16 홈 재설계. .summary-card* / .garden-list-preview / .home-new-group-cta는
   구 홈("사주 요약 + 정원 목록 + 생성 CTA")의 규칙이다. 새 홈은 파일 하단 "S04 홈 v2" 절을 쓴다.
   .group-list*는 /garden(GardenList)이 계속 쓰므로 살아 있는 규칙이다 — 지우지 말 것. */
.summary-card {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  background: var(--bg-raised);
  border: 1px solid transparent;
  border-radius: var(--r-card);
  padding: var(--sp-4) var(--sp-5);
  text-decoration: none;
  color: var(--ink);
  margin-bottom: var(--sp-6);
}

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

.summary-card-sprite {
  width: 64px;
  height: 64px;
  object-fit: contain;
  image-rendering: pixelated;
  flex-shrink: 0;
}

.summary-card-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.summary-card-plant {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 700;
}

.summary-card-elements {
  font-size: var(--fs-caption);
  color: var(--ink-muted);
}

.summary-card-cta {
  margin-top: 4px;
  font-size: var(--fs-caption);
  color: var(--accent);
}

.summary-card-empty {
  justify-content: center;
  text-align: center;
  color: var(--ink-muted);
}

.empty-note {
  color: var(--ink-muted);
  font-size: 14px;
}

/* ---- 스텁(정원/계정) ---- */
.guest-banner {
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: var(--sp-3) 14px;
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  margin-bottom: var(--sp-4);
}

.stub-message {
  color: var(--ink-muted);
  line-height: 1.6;
}

/* ---- M2-lite/M3 그룹·정원 공통 ---- */
.badge-owner,
.badge-member {
  display: inline-block;
  font-style: normal;
  font-size: 11px;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  margin-left: 6px;
  background: var(--bg-raised);
  color: var(--ink-muted);
}

.badge-owner {
  color: var(--accent);
  border: 1px solid color-mix(in srgb, var(--accent) 60%, transparent);
  background: transparent;
}

.group-list {
  list-style: none;
  margin: 0 0 var(--sp-5);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.group-list-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  background: var(--bg-raised);
  border: 1px solid transparent;
  border-radius: var(--r-card);
  padding: var(--sp-3) var(--sp-4);
  text-decoration: none;
  color: var(--ink);
}

.group-list-item:hover {
  border-color: var(--border-strong);
}

.group-list-icon {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--accent-dim);
  border-radius: var(--r-sm);
  flex-shrink: 0;
}

.group-list-icon img {
  width: 30px;
  height: 30px;
  object-fit: contain;
  image-rendering: pixelated;
}

.group-list-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.group-list-name {
  font-weight: 700;
}

.group-list-sub {
  font-size: var(--fs-label);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

.create-group-form {
  margin-top: var(--sp-2);
}

.quota-note {
  margin-top: 14px;
  font-size: var(--fs-label);
  color: var(--ink-muted);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* ---- 정원 목록 섹션 구분(내가 만든 / 초대받은) — 2026-08-17 ----
   🔴 두 섹션의 **항목 스타일은 완전히 같다.** 구분은 제목으로만 준다 —
   초대받은 정원을 흐리거나 줄이면 친구 정원이 2등 시민처럼 보인다. */
.garden-group + .garden-group {
  margin-top: var(--sp-6);
}

.garden-group-title {
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--ink-muted);
  margin-bottom: var(--sp-2);
}

.garden-group-note {
  font-size: var(--fs-label);
  color: var(--ink-faint);
  margin-bottom: var(--sp-2);
}

.home-new-group-cta {
  margin-top: 14px;
}

/* ---- S06 씨앗 정원 ---- */
.deficient-hook {
  margin-top: var(--sp-3);
  font-size: 14px;
  color: var(--ink-muted);
}

/* 열린 자리 표시 — 점선 원의 "개수"가 정원 정원(定員)으로 읽히면 안 된다(2026-08-16 실사용 버그 ②).
   원은 하나만 두고, 뒤의 말줄임이 "계속 이어진다"를 맡는다. */
.empty-slots {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: var(--sp-5);
}

.empty-slot {
  width: 44px;
  height: 44px;
  border: 1px dashed var(--border-strong);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-faint);
  font-size: 18px;
}

.empty-slot-more {
  color: var(--ink-faint);
  font-size: 18px;
  letter-spacing: 0.1em;
}

.empty-slot:hover,
.empty-slot:focus {
  border-color: var(--accent);
}

.empty-slots-note {
  margin-top: var(--sp-2);
  font-size: var(--fs-label);
  color: var(--ink-muted);
}

.invite-box {
  margin-top: var(--sp-6);
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: var(--sp-4) var(--sp-5);
}

.invite-box-label {
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  margin: 0 0 var(--sp-2);
}

/* /i/{token} 착지 화면 — 사람은 스크립트로 즉시 넘어가므로 보이는 시간이 100ms 남짓이다.
   그래도 JS가 죽은 환경에서는 이게 최종 화면이 되므로 폴백 링크가 화면 가운데에 서게 둔다.
   (왜 리다이렉트가 아니라 화면인지: components/InviteForward.tsx) */
.screen-invite-forward {
  text-align: center;
  padding-top: var(--sp-8, 32px);
}

.invite-forward-note {
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  margin: var(--sp-2) 0 var(--sp-5);
}

/* 초대 링크 공유(SeedGarden / GroupGarden invite-box) — raw URL 텍스트는 렌더하지 않는다.
   (구 .invite-link 규칙 삭제, 2026-08-16 실사용 버그 ③) 링크는 버튼의 data-share-url에만 있다. */
.share-sheet-invite {
  margin-top: 0;
}

/* 초대 링크 만료 한 줄(2026-08-16 오너 요청 "초대링크의 만료 시간을 알려줘").
   평소엔 캡션 톤으로 조용히 있다가, 하루 이내(.is-urgent)에만 색을 올려 재발급을 유도한다 —
   7일 내내 경고색이면 만료가 진짜 임박했을 때 아무도 못 알아본다. */
.invite-expiry {
  font-size: var(--fs-caption);
  color: var(--ink-faint);
  margin: 0 0 var(--sp-3);
}

.invite-expiry.is-urgent {
  color: var(--el-fire-text);
}

/* 재발급은 예외 동작 — 공유 버튼과 시각적 위계를 벌린다(ghost + 오른쪽 정렬) */
.invite-box .cta-ghost {
  margin-top: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--ink-muted);
}

.invite-box .cta-ghost:hover {
  color: var(--ink-body);
}

/* ---- S07 초대 랜딩 ---- */
.invite-teaser .diorama-frame {
  width: min(340px, 92%);
}

.invite-teaser {
  padding-top: var(--sp-5);
  padding-bottom: var(--sp-3);
}

.invite-title {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.35;
  color: var(--ink);
  margin: 4px 0 var(--sp-3);
}

.invite-sub {
  color: var(--ink-muted);
  font-size: 14px;
  margin-top: 0;
}

/* ---- 초대 게이트(초대 없이 /g/{slug}에 닿은 비멤버, 2026-08-16 보안 수정) ----
   조인 폼 자리를 대체하는 블록이라 폼과 같은 무게로 보이면 안 된다 — 경고가 아니라
   "여기서 뭘 하면 되는지" 알려주는 안내 카드로 둔다. */
.invite-gate-notice {
  background: var(--bg-raised);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--r-sm) var(--r-card) var(--r-card) var(--r-sm);
  padding: var(--sp-4);
  margin: var(--sp-5) 0 var(--sp-4);
}

.invite-gate-title {
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 var(--sp-2);
}

.invite-gate-body {
  font-size: 14px;
  color: var(--ink-body);
  margin: 0;
  line-height: 1.6;
}

.invite-gate-hint {
  font-size: var(--fs-caption);
  color: var(--ink-faint);
  margin: var(--sp-2) 0 0;
}

/* ---- 로그인 게이트(LoginGate.tsx — 조인 · 초대 발급, 2026-08-17) ----
   초대 게이트(.invite-gate-notice)와 같은 안내 카드 문법이되 **좌측 보더는 accent**다:
   저쪽은 "여기서 할 수 있는 게 없다"는 상태 고지이고, 이쪽은 그 자리에서 바로 할 수 있는
   행동(로그인)을 담고 있다 — 카드 안에 실제 컨트롤이 있으므로 위계를 한 단계 올린다. */
.login-gate {
  background: var(--bg-raised);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-sm) var(--r-card) var(--r-card) var(--r-sm);
  padding: var(--sp-4);
  margin: var(--sp-5) 0 var(--sp-4);
}

.login-gate-title {
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 var(--sp-2);
}

.login-gate-body {
  font-size: 14px;
  color: var(--ink-body);
  margin: 0 0 var(--sp-4);
  line-height: 1.6;
  word-break: keep-all;
}

/* 카카오 버튼은 규정색으로 격리된 컨트롤이라 카드 안에서 가로 전체를 쓴다(심볼 픽셀 크기는
   KakaoLoginButton의 규정대로 고정 — 늘어나지 않는다). */
.login-gate .login-gate-button {
  width: 100%;
}

.login-gate-hint {
  font-size: var(--fs-caption);
  color: var(--ink-faint);
  margin: var(--sp-3) 0 0;
  word-break: keep-all;
}

/* 게이트로 대체된 초대 박스 — 원래 박스가 갖던 상하 여백만 유지한다(카드가 자기 배경을 갖는다). */
.invite-box-gated {
  background: none;
  border: 0;
  padding: 0;
}

.masked-members {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: var(--sp-4) 0;
}

/* 마스킹 멤버 — 이모지 대신 오행 칩(§5.4 .chip-element) */
.chip-element {
  display: inline-flex;
  align-items: center;
  background: var(--el-dim, var(--bg-raised));
  color: var(--el-text, var(--ink-body));
  border: 1px solid color-mix(in srgb, var(--el, var(--border)) 35%, transparent);
  border-radius: var(--r-pill);
  padding: 3px 10px;
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
}

/* "네 자리" — 대시드 빈 슬롯 문법 재사용 + 액센트 보더 */
.masked-member-you {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  height: 28px;
  padding: 0 10px;
  border: 1px dashed var(--accent);
  border-radius: var(--r-pill);
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--accent);
}

.invite-question {
  font-weight: 700;
  font-size: var(--fs-heading);
  color: var(--ink);
  margin-bottom: var(--sp-5);
}

.join-form-title {
  font-weight: 700;
  color: var(--ink);
  margin-bottom: var(--sp-3);
}

.group-consent-box {
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: 14px 16px;
  margin: var(--sp-4) 0;
}

.group-consent-title {
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 var(--sp-2);
}

.group-consent-line {
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  margin: 4px 0;
  padding-left: 14px;
  position: relative;
}

.group-consent-line::before {
  content: '';
  position: absolute;
  left: 0;
  top: 7px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-faint);
}

.group-consent-line--open::before {
  background: var(--ok);
}

.group-consent-detail {
  margin-top: var(--sp-2);
  font-size: var(--fs-label);
  color: var(--ink-muted);
}

.group-consent-detail summary {
  cursor: pointer;
  color: var(--accent);
}

/* ---- 초대 랜딩 원클릭 참여(기존 화분 보유자) ---- */
.join-form-oneclick .join-form-title {
  margin-bottom: var(--sp-2);
}

.join-pot-card {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: 12px 14px;
}

.join-pot-name {
  font-weight: 700;
  color: var(--ink);
}

.join-pot-hint {
  margin-top: var(--sp-2);
  font-size: var(--fs-caption);
  color: var(--ink-muted);
}

/* ---- 안내 배너(§7.1 기존 화분 유지 등 결과 화면 상단 1줄 고지) ---- */
.notice-banner {
  background: var(--bg-raised);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-sm) var(--r-card) var(--r-card) var(--r-sm);
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
  font-size: 14px;
  color: var(--ink-body);
}

/* ---- S08 그룹 정원 ---- */
.garden-fallback-sprite {
  width: 120px;
  height: 120px;
  object-fit: contain;
  image-rendering: pixelated;
}

/* §7.9 정원 레이어 합성 — bg(투명 코너 아일랜드 PNG)를 그대로 보여준다(마스크 없음). */
.garden-visual-layer {
  position: absolute;
  display: block;
}

.garden-visual-bg {
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  z-index: 1;
}

/* v3(배치 마스크, 2026-08-15) — xPct/yPct는 이제 스프라이트 "밑변 중심(bottom-center)" 앵커다.
   translate(-50%,-100%)로 그 점에 스프라이트의 아래-가운데를 붙이면, 밑동이 항상 마스크로 검증된
   섬 표면 위에 있고 키 큰 스프라이트는 위로만 자연히 넘친다(translate(-50%,-50%) 시절엔 스프라이트
   절반이 앵커 아래로 내려가 섬 밖 허공에 걸치는 게 버그였다). */
.garden-visual-sprite {
  transform: translate(-50%, -100%);
  image-rendering: pixelated;
}

.garden-visual-center {
  transform: translate(-50%, -100%);
  image-rendering: pixelated;
}

/* v4(모듈러 타일 격자, 2026-08-15) — 타일은 오브젝트/센터와 반대로 "상판 중심 top" 앵커다(밑변이
   아니라 상판 기준 배치 — 승인된 데모 수식). translate(-50%, 0)로 이미지의 위-가운데를 격자점에
   붙인다. 폭만 지정하고 높이는 자연 비율(타일 PNG가 128×64 다이아 + 밑동이라 정사각이 아니다). */
.tile-grid-tile {
  position: absolute;
  transform: translate(-50%, 0);
  image-rendering: pixelated;
  display: block;
}

/* P3(2026-08-15) — 오브젝트별 접지 그림자. 스프라이트 밑변 앵커(bottom-center, garden-visual-sprite/
   -center와 같은 xPct/yPct)에 2:1 타원을 깐다. width는 %(부모 격자 박스 폭 대비)로 지정하고
   aspect-ratio:2/1로 높이를 자동 계산해, 격자 박스가 정사각이 아니어도(N×N 섬 블롭) 타원 비율이
   왜곡되지 않는다. 무발판 스프라이트(대부분의 v4 O 오브젝트)가 공중에 뜬 것처럼 보이는 문제의 핵심
   장치 — 화면(GardenVisual.tsx)과 OG(lib/og/cards.ts objShadowNode) 양쪽에 같은 0.7배 폭 규칙을 쓴다. */
.grid-obj-shadow {
  position: absolute;
  aspect-ratio: 2 / 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.55) 0%, rgba(0, 0, 0, 0.25) 55%, rgba(0, 0, 0, 0) 80%);
  pointer-events: none;
}

/* 타일 격자 프레임은 N(격자 크기)에 따라 폭:높이 비율이 달라진다(GardenVisual.tsx가 인라인
   aspect-ratio로 꽂는다) — 더 이상 .diorama-frame의 1:1 고정 정사각을 쓰지 않는다.
   폭(2026-08-15 피드백 #2 "정원 표시 크기 1.5배") — .diorama-frame의 min(300px,78vw)를
   min(450px,100%)로 키운다: 목표/상한은 300px×1.5=450px, 단 실제 폭은 부모(.diorama-stage,
   .app-main 20px 패딩까지 반영된 콘텐츠 폭)를 절대 넘지 않는다 — 390px 모바일 기준선에서도
   컨테이너 폭 안으로 자동 축소되는 fit-to-width. .remix-card-grid .diorama-frame(더 높은 특이도의
   width:100%)은 그대로 이 프레임을 덮어써 미니 비교 카드 크기는 영향받지 않는다. */
.tile-grid-frame {
  aspect-ratio: unset;
  width: min(450px, 100%);
}

.keyword-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin: 0;
}

.keyword-chip {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
  padding: 4px 10px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.05);
  color: var(--ink-body);
}

/* 규정 층 L1 — 정원 이름 바로 아래 "어떤 사람들이 모인 모임인지"를 규정하는 한 줄.
   아래 L2(.garden-name-desc, 분위기 묘사)보다 한 단 위여야 규정→묘사의 위계가 읽히므로
   fs-heading·700·--ink(가장 밝은 잉크)로 올린다. 이 화면의 신규 클래스는 이 하나뿐 —
   L3는 .element-summary-text, L4는 .interpretation-sentences를 그대로 재사용한다. */
.garden-tagline {
  font-size: var(--fs-heading);
  font-weight: 700;
  color: var(--ink);
  margin: var(--sp-3) 0 0;
  line-height: 1.5;
}

.garden-name-desc {
  font-size: var(--fs-body);
  color: var(--ink-body);
  margin: var(--sp-1) 0 0;
  line-height: 1.6;
}

.remix-compare {
  margin-bottom: var(--sp-5);
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: var(--sp-4);
}

.remix-compare-title {
  margin: 0 0 var(--sp-3);
  font-weight: 700;
  color: var(--ink);
}

.remix-cards {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* 카드 안 카드(§5.2) — 미니카드는 --bg-overlay로 "도로 --bg로 꺼지지 않게" + 반경 축소 */
.remix-card {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--bg-overlay);
  border-radius: var(--r-sm);
  padding: 10px;
  font-size: var(--fs-label);
}

.remix-card-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
}

/* v4(모듈러 타일 격자) — 리믹스 카드 안의 미니 정원. .diorama-frame의 width:min(300px,78vw)는
   이 좁은 카드 안에서 너무 크므로 폭을 강제로 눌러준다(높이는 grid의 aspect-ratio가 따라온다).
   래퍼에 고정 폭(width:130px)을 직접 줘야 한다 — align-self:center(shrink-to-fit)인 래퍼 안에서
   자식에 width:100%만 주면 기준이 될 정의된 폭이 없어 0에 가깝게 찌그러진다(실측 — 스크린샷에서
   섬이 아예 안 보이던 버그의 원인). */
.remix-card-grid {
  align-self: center;
  margin-bottom: 6px;
  width: 130px;
}

.remix-card-grid .diorama-frame {
  width: 100%;
}

.remix-card-name {
  font-weight: 700;
  font-size: var(--fs-caption);
  color: var(--ink);
  margin-bottom: 4px;
}

.remix-arrow {
  font-size: 18px;
  color: var(--ink-muted);
}

.member-roles {
  margin-top: var(--sp-6);
}

.member-role-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.member-role-card {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: var(--sp-3) var(--sp-4);
}

/* 40px 오행 심볼 자리(§5.2) — dim 배경 + 픽셀 아이콘(이모지 대체) */
.member-symbol {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--el-dim, var(--bg-overlay));
  border-radius: var(--r-sm);
  flex-shrink: 0;
}

.member-symbol img {
  width: 32px;
  height: 32px;
  object-fit: contain;
  image-rendering: pixelated;
}

.member-role-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.member-role-nickname {
  font-weight: 700;
  font-size: 14px;
  color: var(--ink);
}

/* 역할 라벨 — 전원 초록(액센트) 금지, 해당 오행의 text색으로(§5.2) */
.member-role-label {
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--el-text, var(--accent));
}

.member-role-desc {
  font-size: 11px;
  color: var(--ink-muted);
}

.member-overflow-badge {
  margin-top: var(--sp-2);
  font-size: var(--fs-label);
  color: var(--ink-muted);
  text-align: center;
}

/* `.former-members-note`(「떠난 사람 n명」)는 2026-08-17 화면에서 제거돼 규칙도 함께 지웠다.
   숫자는 누가 나갔는지 알려주지 못하면서 정원에 흉터만 남겼다(오너 결정). */

/* ---- 정원 슬롯 페이월 (§5.4-B 2카드 선택) ----
   🔴 조바심 UI 금지: 카운트다운·"인기"·"가장 많이 선택"·NEW 점·남은 수량은 여기 스타일에도 없다.
   위계는 딱 두 단계 — 채워진 버튼(primary) 1개 + 나머지는 외곽선. */
.screen-paywall {
  text-align: center;
  padding-top: var(--sp-10);
}

.paywall-intro {
  margin-bottom: var(--sp-6);
}

/* "친구가 초대한 정원은 계속 무료" — 안심시키는 줄이라 경고색을 쓰지 않는다. */
.paywall-invite-free {
  color: var(--ink-muted);
  line-height: 1.7;
  font-size: var(--fs-label);
  margin-bottom: var(--sp-3);
}

.paywall-body {
  color: var(--ink-muted);
  line-height: 1.7;
  margin-bottom: var(--sp-6);
}

/* 「정원 슬롯 = …한도예요」 — 이 한 줄이 선불수단 오인 방어의 본체라 시각적으로도 붙박이다. */
.paywall-definition {
  color: var(--ink-muted);
  line-height: 1.7;
  font-size: var(--fs-label);
  background: rgba(255, 255, 255, 0.04);
  border-radius: 12px;
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-6);
}

/* 결제 상한·하드캡·동시 결제 — 에러가 아니라 상태 안내다. 경고색을 쓰지 않는다. */
.paywall-blocked {
  color: var(--ink-muted);
  line-height: 1.7;
  margin-bottom: var(--sp-5);
}

.slot-card-list {
  display: flex;
  flex-direction: column; /* 모바일 세로: 위=SL1, 아래=SL5 — 가격 오름차순 고정 */
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
  list-style: none;
  padding: 0;
}

.slot-card {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 16px;
  padding: var(--sp-5);
  text-align: left;
}

.slot-card-primary {
  border-color: var(--accent, rgba(255, 255, 255, 0.4));
}

.slot-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
}

.slot-card-title {
  font-weight: 700;
}

.slot-card-badge {
  font-size: var(--fs-label);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 999px;
  padding: 2px 10px;
  white-space: nowrap;
}

.slot-card-sub {
  color: var(--ink-muted);
  font-size: var(--fs-label);
  margin-top: var(--sp-1);
}

.slot-card-price {
  font-size: var(--fs-h2, 1.5rem);
  font-weight: 700;
  margin-top: var(--sp-3);
  font-variant-numeric: tabular-nums;
}

.slot-card-unit,
.slot-card-limit {
  color: var(--ink-muted);
  font-size: var(--fs-label);
  font-variant-numeric: tabular-nums;
}

.slot-card form {
  margin-top: var(--sp-4);
}

/* 환불·제공개시 고지. 🔴 접기(details)로 숨기지 않는다 — 표시 자체가 제한 주장의 전제다. */
.paywall-notice {
  color: var(--ink-faint);
  font-size: var(--fs-label);
  line-height: 1.7;
  text-align: left;
  margin-bottom: var(--sp-6);
}

.paywall-exit {
  margin-top: var(--sp-4);
}

.paywall-notified {
  color: var(--ok);
  font-weight: 600;
  margin-bottom: var(--sp-4);
}

/* ---- 결제 확인 화면 (§6.4-A ② · 법적 검토 §8.9 ③) ---- */
.screen-purchase-confirm {
  padding-top: var(--sp-8);
}

.purchase-summary {
  text-align: center;
  margin-bottom: var(--sp-5);
}

.purchase-amount {
  font-size: var(--fs-h1, 2rem);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.purchase-limit,
.purchase-definition {
  color: var(--ink-muted);
  line-height: 1.7;
  font-size: var(--fs-label);
}

.purchase-definition {
  margin-bottom: var(--sp-5);
}

.purchase-notice,
.purchase-always-refundable ul {
  color: var(--ink-muted);
  font-size: var(--fs-label);
  line-height: 1.8;
  padding-left: 1.2em;
  margin-bottom: var(--sp-4);
}

.purchase-notice-head {
  font-weight: 600;
  font-size: var(--fs-label);
  margin-bottom: var(--sp-1);
}

.purchase-notice-line,
.purchase-disclaimer {
  color: var(--ink-faint);
  font-size: var(--fs-label);
  line-height: 1.7;
  margin-bottom: var(--sp-4);
}

.check-line {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-size: var(--fs-label);
  line-height: 1.6;
  margin-bottom: var(--sp-3);
  text-align: left;
}

.purchase-form {
  margin-bottom: var(--sp-4);
}

.purchase-stub-warning {
  color: var(--warn, var(--ink-faint));
  font-size: var(--fs-label);
  margin-bottom: var(--sp-4);
}

/* ---- 결제 내역 · 앱 내 환불 (공정위 고시 2025-8호 14.나 — 앱에서 샀으면 앱에서 취소) ----
   🔴 환불 버튼을 회색 작은 텍스트로 숨기지 않는다(13.나(3) 다크패턴). 여기서는 primary다. */
.screen-purchase-history {
  padding-top: var(--sp-8);
}

.refund-list {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-bottom: var(--sp-6);
}

.refund-item {
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 16px;
  padding: var(--sp-4);
}

.refund-item-head {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  font-size: var(--fs-label);
}

.refund-item-title {
  font-weight: 600;
}

.refund-item-date {
  color: var(--ink-faint);
  white-space: nowrap;
}

.refund-item-state,
.refund-item-note,
.refund-channel {
  color: var(--ink-muted);
  font-size: var(--fs-label);
  line-height: 1.7;
  margin-top: var(--sp-2);
}

.refund-item form {
  margin-top: var(--sp-3);
}

/* ---- 미성년자 고지·동의 (2026-08-17) ----
   🔴 §13③ 취소 가능 고지는 **모든 사용자에게** 보인다. 눈에 띄되 겁주지 않는 톤이라
   경고색(--danger)을 쓰지 않는다 — 이건 위험 경고가 아니라 권리 안내다. */
.purchase-minor-notice {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  line-height: 1.7;
  margin: var(--sp-4) 0;
  word-break: keep-all;
}

/* 미성년 판정일 때만 나오는 확인 단계. 차단이 아니라 확인이므로 막다른 골목처럼 보이면 안 된다 —
   표면을 한 단 올려 "여기를 먼저 보라"까지만 말하고, 그 아래 결제 버튼은 그대로 살아 있다. */
.purchase-guardian {
  background: var(--bg-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-card);
  padding: var(--sp-4);
  margin-bottom: var(--sp-4);
}

.purchase-guardian h2 {
  font-size: var(--fs-heading);
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 var(--sp-2);
}

.purchase-guardian p {
  color: var(--ink-body);
  font-size: 14px;
  line-height: 1.7;
  margin: 0 0 var(--sp-2);
  word-break: keep-all;
}

/* "무료로 계속 쓸 수 있다"는 줄 — 이 문장이 없으면 쫓겨난 것처럼 읽힌다. */
.purchase-guardian-free {
  color: var(--ink-muted) !important;
  font-size: var(--fs-caption) !important;
}

/* ---- 결제 내역(PurchaseHistory.tsx) — 2026-08-17 ---- */
.purchase-history-intro {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  line-height: 1.7;
  margin-bottom: var(--sp-5);
  word-break: keep-all;
}

/* 결제 상태 배지. 상태를 색으로만 말하지 않는다(§접근성) — 글자가 항상 함께 있다. */
.refund-item-status-badge {
  display: inline-block;
  margin-top: var(--sp-2);
  padding: 2px 8px;
  border-radius: var(--r-pill);
  background: var(--bg-overlay);
  color: var(--ink-muted);
  font-size: var(--fs-label);
}

/* 🔴 환불 요청의 현재 처리 상태 — 콘텐츠이용자 보호지침이 요구하는 표시.
   접수된 신청이 "있다"는 사실이 눈에 띄어야 하므로 좌측 액센트 보더로 분리한다. */
.refund-request-state {
  margin-top: var(--sp-3);
  padding: var(--sp-3);
  border-left: 3px solid var(--accent);
  background: var(--bg-overlay);
  border-radius: 0 var(--r-control) var(--r-control) 0;
}

.refund-request-status {
  font-size: var(--fs-caption);
  font-weight: 700;
  color: var(--ink);
  margin: 0;
}

.refund-request-due {
  font-size: var(--fs-label);
  color: var(--ink-muted);
  margin: var(--sp-1) 0 0;
}

.refund-item .cta-secondary {
  margin-top: var(--sp-3);
}

/* ============================================================
   FAQ(Faq.tsx) — 접힌 목록. JS 없이 동작하고 Ctrl+F에도 잡힌다.
   ============================================================ */
.screen-faq {
  max-width: 720px;
}

.faq-toc {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  margin-bottom: var(--sp-6);
}

.faq-toc-link {
  padding: 6px 12px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  color: var(--ink-body);
  font-size: var(--fs-caption);
  text-decoration: none;
}

.faq-toc-link:hover {
  border-color: var(--border-strong);
  color: var(--ink);
}

.faq-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
}

.faq-item + .faq-item {
  border-top: 1px solid var(--border);
}

.faq-question {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 52px;
  padding: var(--sp-3) var(--sp-4);
  color: var(--ink);
  font-size: var(--fs-body);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  word-break: keep-all;
}

.faq-question::-webkit-details-marker {
  display: none;
}

/* 시그니처는 설정 행의 ›를 90도 돌린 것 — 같은 언어를 쓴다(펼침/이동 모두 "여기서 더 간다"). */
.faq-question::after {
  content: '';
  flex: none;
  width: 7px;
  height: 7px;
  border-right: 1.5px solid var(--ink-faint);
  border-bottom: 1.5px solid var(--ink-faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--dur-fast) var(--ease-out);
}

details[open] > .faq-question::after {
  transform: rotate(225deg) translate(-2px, -2px);
}

.faq-question:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.faq-answer {
  padding: 0 var(--sp-4) var(--sp-4);
}

.faq-answer p {
  color: var(--ink-body);
  font-size: 14px;
  line-height: 1.8;
  margin: 0 0 var(--sp-2);
  word-break: keep-all;
  white-space: pre-line; /* 문안이 '· ' 목록을 줄바꿈으로 갖는다 */
}

.faq-answer a {
  color: var(--accent);
  text-decoration: underline;
}

.faq-contact-line {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  margin-top: var(--sp-6);
}

/* ============================================================
   문의하기(Contact.tsx)
   ============================================================ */
.contact-intro {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  line-height: 1.7;
  margin-bottom: var(--sp-5);
  word-break: keep-all;
}

/* 어떤 결제에 대한 문의인지 **선택된 상태**를 눈에 보이게 고정한다 —
   보이지 않으면 사용자가 다시 결제 번호를 찾아 적게 되고, 그 왕복이 3영업일을 잡아먹는다. */
.contact-selected {
  background: var(--bg-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-card);
  padding: var(--sp-4);
  margin-bottom: var(--sp-5);
}

.contact-selected-head {
  font-size: var(--fs-label);
  color: var(--ink-muted);
  margin: 0 0 var(--sp-2);
}

.contact-selected-body {
  font-size: var(--fs-body);
  color: var(--ink);
  margin: 0;
}

.contact-selected-id {
  font-size: var(--fs-label);
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  margin: var(--sp-1) 0 var(--sp-3);
}

.contact-clear {
  font-size: var(--fs-caption);
  color: var(--accent);
}

.contact-picker {
  margin-bottom: var(--sp-5);
}

.contact-picker-head {
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  margin: 0 0 var(--sp-2);
}

.contact-picker-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
}

.contact-picker-list > li + li .settings-row {
  border-top: 1px solid var(--border);
}

.contact-email-line {
  text-align: center;
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  margin: var(--sp-3) 0 0;
}

.contact-privacy-note,
.contact-faq-line {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  line-height: 1.7;
  margin-top: var(--sp-3);
  word-break: keep-all;
}

/* ---- 만 14세 미만 차단 화면(components/AgeGate.tsx) ----
   되돌아가기 링크를 일부러 강조하지 않는다 — 재시도 유도로 읽히면 게이트가 무의미해진다. */
.screen-age-gate {
  text-align: center;
  padding-top: var(--sp-10);
}

.age-gate-body {
  color: var(--ink-muted);
  line-height: 1.8;
  margin-bottom: var(--sp-6);
}

/* ---- M4: 리믹스 Before→After 간단 CSS 애니메이션(§7.11 — 과하지 않게) ---- */
.remix-card-row {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-variant-numeric: tabular-nums;
}

.remix-card-bar-track {
  flex: 1;
  height: 6px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 3px;
  overflow: hidden;
}

.remix-card-bar-fill {
  display: block;
  height: 100%;
  border-radius: 3px;
  width: var(--remix-from, 0%);
  animation: remix-grow 900ms ease-out 150ms forwards;
}

@keyframes remix-grow {
  from {
    width: var(--remix-from, 0%);
  }
  to {
    width: var(--remix-to, 0%);
  }
}

.remix-name-crossfade {
  animation: remix-fade-in 600ms ease-out 200ms both;
}

@keyframes remix-fade-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ---- M4: 공유 시트(ShareSheet.tsx) — 목적 분기 단일 흐름(화면당 primary 1개, §5.1) ---- */
.share-sheet {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-4);
}

.share-btn-primary {
  width: 100%;
}

/* primary 강등 변형 — 같은 화면에 목적상 더 중요한 CTA가 따로 있을 때(§5.1 화면당 1개) */
.share-sheet.share-sheet-demoted .share-btn-primary {
  background: transparent;
  color: var(--ink-body);
  border: 1px solid var(--border);
  min-height: 44px;
  padding: 11px 14px;
  font-size: 14px;
  font-weight: 600;
}

.share-sheet.share-sheet-demoted .share-btn-primary:hover {
  background: rgba(255, 255, 255, 0.04);
  border-color: var(--border-strong);
}

/* compact 변형 — 보조 행(링크 복사/이미지 저장) 없이 메인 버튼만 */
.share-sheet.share-sheet-compact .share-sheet-secondary {
  display: none;
}

.share-sheet-secondary {
  display: flex;
  gap: var(--sp-2);
}

.share-sheet-secondary .cta-secondary {
  flex: 1;
  margin-top: 0;
  text-align: center;
  text-decoration: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 이 시트가 나르는 링크가 **누구에게 열리는지** 말하는 한 줄(2026-08-17 오너 지적).
   상태 문구(.share-sheet-status)와 달리 항상 보이므로 위계를 한 단계 낮춰 버튼을 누르기 전
   읽히기만 하면 되게 한다 — 가운데 정렬하지 않는 이유는 읽는 문장이라서다(버튼 피드백이 아니다). */
.share-sheet-note {
  font-size: var(--fs-label);
  line-height: 1.5;
  color: var(--ink-muted);
  word-break: keep-all;
  margin: 0;
}

.share-sheet-status {
  font-size: var(--fs-label);
  color: var(--ok);
  text-align: center;
  margin: 0;
}

.share-sheet-seat {
  margin-top: var(--sp-3);
}

.member-role-share {
  margin-top: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}

.member-role-share:hover {
  text-decoration: underline;
}

/* ---- 구성원 내보내기 · 정원에서 나가기(2026-08-16 탈퇴·추방) ----
   §5.1: 파괴적 행위는 절대 primary로 올리지 않는다. 오너 화면의 단일 primary는 "정원에 초대하기"이므로
   여기는 카드 오른쪽 끝의 작은 링크 하나로 둔다. danger 색을 쓰되 보더·배경 없이 글자에만 얹어
   면적을 갖지 않게 한다(§2.5.1 — danger 대면적은 火 데이터색과 혼동된다). */
.member-role-remove {
  margin-left: auto;
  padding-left: var(--sp-3);
  flex-shrink: 0;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-faint);
  text-decoration: none;
}

.member-role-remove:hover {
  color: var(--danger-text);
  text-decoration: underline;
}

/* 되돌리기 유예 박스 — 정보 카드(§5.2) 문법. 경고가 아니라 "아직 되돌릴 수 있다"는 안내다. */
.ban-undo-box {
  margin-top: var(--sp-4);
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: var(--sp-3) var(--sp-4);
}

.ban-undo-title {
  font-size: var(--fs-label);
  font-weight: 700;
  color: var(--ink-body);
  margin: 0 0 var(--sp-2);
}

.ban-undo-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

.ban-undo-item {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.ban-undo-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

.ban-undo-window {
  flex: 1;
  min-width: 0;
  font-size: 11px;
  color: var(--ink-faint);
}

.ban-undo-item.is-urgent .ban-undo-window {
  color: var(--danger-text);
}

/* 화면 맨 아래 이탈 링크 — 초대 만료 안내(.invite-expiry)와 같은 무게의 조용한 줄. */
.member-leave-line {
  margin-top: var(--sp-6);
  text-align: center;
}

.member-leave-link {
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

.member-leave-link:hover {
  color: var(--danger-text);
}

/* ---- 이탈 확인 화면(MemberExitConfirm.tsx) ---- */
.exit-confirm-card {
  background: var(--bg-raised);
  border-radius: var(--r-card);
  padding: var(--sp-4) var(--sp-5);
  margin-top: var(--sp-4);
}

.exit-confirm-lead {
  font-size: 15px;
  color: var(--ink);
  margin: 0 0 var(--sp-3);
  word-break: keep-all;
}

.exit-confirm-points {
  list-style: none;
  margin: 0 0 var(--sp-5);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-body);
}

.exit-confirm-points li {
  padding-left: 14px;
  position: relative;
  word-break: keep-all;
}

.exit-confirm-points li::before {
  content: '·';
  position: absolute;
  left: 4px;
  color: var(--ink-faint);
}

/* 되돌릴 수 없는 결과(정원이 사라진다)만 danger 글자색으로 올린다 — §2.5 "danger는 명시 문구와 동반". */
.exit-confirm-points .exit-confirm-danger {
  color: var(--danger-text);
}

.exit-confirm-points .exit-confirm-undo {
  color: var(--ink);
}

.exit-confirm-cancel {
  margin-top: var(--sp-3);
}

/* ---- 추방 통보 화면(RemovedNotice.tsx) ---- */
.screen-removed-notice {
  padding-top: var(--sp-8);
}

/* 초대 게이트(.invite-gate-notice)와 같은 안내 카드 문법. 좌측 보더는 accent가 아니라 중립 —
   상태 고지이지 다음 행동을 유도하는 안내가 아니다(할 수 있는 게 없다). */
.removed-notice {
  background: var(--bg-raised);
  border-left: 3px solid var(--border-strong);
  border-radius: var(--r-sm) var(--r-card) var(--r-card) var(--r-sm);
  padding: var(--sp-4);
  margin: var(--sp-5) 0 var(--sp-5);
}

.removed-notice-title {
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 var(--sp-2);
}

.removed-notice-body {
  font-size: 14px;
  color: var(--ink-body);
  margin: 0;
  line-height: 1.6;
  word-break: keep-all;
}

.removed-notice-hint {
  font-size: var(--fs-caption);
  color: var(--ink-faint);
  margin: var(--sp-2) 0 0;
  word-break: keep-all;
}

/* ============================================================
   설정(Settings.tsx) — 2026-08-17 「계정」 탭 개편
   ============================================================
   🔴 이 화면에는 primary 버튼이 없다(§5.1의 "화면당 primary 1개"는 "이 화면에서 할 단 하나의
   일"을 가리키는데, 설정에는 그런 일이 없다 — 목적지 목록이고 이동 수단은 행 자체다).
   위계는 버튼이 아니라 **구역 · 행 · 시그니처(›)** 세 가지로만 만든다.

   표면 규칙(§1-4·§4.2): 목록은 카드 하나(`--bg-raised` + `--r-card`)로 묶고, 행 사이는
   1px 보더로만 나눈다. 행마다 카드를 주면 §7-1 "균일 카드 그리드"가 된다. */
.screen-settings .settings-note {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  margin: var(--sp-2) 0 var(--sp-4);
  word-break: keep-all;
}

.settings-section {
  margin-top: var(--sp-6);
}

.settings-section-title {
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--ink-muted);
  margin: 0 0 var(--sp-2);
}

.settings-list {
  list-style: none;
  margin: 0;
  padding: 0;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
}

.settings-list > li + li .settings-row {
  border-top: 1px solid var(--border);
}

.settings-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 52px; /* 터치 타깃 44px 이상(§5.1) */
  padding: var(--sp-3) var(--sp-4);
  color: var(--ink);
  font-size: var(--fs-body);
  text-decoration: none;
}

.settings-row-label {
  flex: 1;
  word-break: keep-all;
}

.settings-row-value {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  text-align: right;
  max-width: 55%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 이동 시그니처. 이 자리에 있으면 "누르면 어디로 간다", 없으면 "누를 수 없다"를 뜻한다 —
   설정 화면에서 유일한 어포던스 신호이므로 정적 행에는 절대 붙이지 않는다. */
.settings-row-chevron {
  flex: none;
  width: 7px;
  height: 7px;
  border-right: 1.5px solid var(--ink-faint);
  border-top: 1.5px solid var(--ink-faint);
  transform: rotate(45deg);
}

.settings-row-link:hover {
  background: rgba(255, 255, 255, 0.04);
}

.settings-row-link:active {
  background: rgba(255, 255, 255, 0.07);
}

.settings-row-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.settings-row-static {
  cursor: default;
}

.settings-section-note {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  margin: var(--sp-2) 0 0;
  word-break: keep-all;
}

.settings-saved-note {
  color: var(--ok);
  font-size: var(--fs-caption);
  margin-bottom: var(--sp-2);
}

/* ---- 설정 하위 페이지(SettingsForms.tsx) — 폼은 각자의 화면에서 primary 1개를 갖는다 ---- */
.screen-settings-form .settings-form {
  margin-top: var(--sp-4);
}

.screen-settings-form .settings-form input {
  width: 100%;
  margin-bottom: var(--sp-4);
}

.settings-form-note,
.settings-current-saju {
  color: var(--ink-muted);
  font-size: var(--fs-caption);
  line-height: 1.7;
  margin-bottom: var(--sp-3);
  word-break: keep-all;
}

/* ============================================================
   카카오 로그인 버튼 — 공식 디자인 규정 (2026-08-17 재구현)
   ============================================================
   🔴 **이 블록의 색·반경·비율은 우리 것이 아니다.** 카카오가 강제하는 값이라
   디자인 시스템 토큰(§2)에 편입시키지 않는다 — 토큰으로 만들면 팔레트를 손보는 날
   누군가 함께 바꾸고, 그 순간 브랜드 규정 위반이 된다. 그래서 **리터럴로 박아 두고**
   여기 한 곳에 격리한다. 값의 출처는 developers.kakao.com/docs/ko/kakaologin/design-guide.

   구조 근거(components/KakaoLoginButton.tsx 주석 참조): 공식 이미지 버튼을 늘리면 심볼까지
   늘어나 「형태·비율 변경 금지」에 걸린다. 그래서 배경·라운드는 CSS, 심볼은 **고정 픽셀**,
   레이블은 텍스트로 조립한다. 레이아웃은 공식 medium wide(300×45) 실측값 그대로:
     심볼 19×17(높이의 37.8%) · 좌측 여백 14px(높이의 31.1%) · 수직 중앙
     레이블은 **버튼 전체의 중앙 정렬** — 심볼 오른쪽 공간의 중앙이 아니다.
   심볼을 absolute로 왼쪽에 못 박았기 때문에 컨테이너가 320px이든 720px이든
   **심볼 픽셀 크기가 변하지 않는다**(test/kakao-login-button.test.ts가 이걸 단언한다). */
.kakao-login {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center; /* 레이블은 버튼 중앙 (심볼은 아래에서 absolute로 빠진다) */
  width: 100%;
  min-height: 45px;
  padding: 0 44px; /* 심볼(14 + 18)과 대칭 — 긴 레이블이 심볼 위로 겹치지 않게 */
  background: #fee500;
  border: none;
  border-radius: 12px;
  text-decoration: none;
  cursor: pointer;
  box-sizing: border-box;
}

/* 🔴 고정 크기. `width/height`를 %나 em으로 바꾸지 말 것 — 비율 변경 금지 위반이다. */
.kakao-login-symbol {
  position: absolute;
  left: 14px;
  top: 50%;
  width: 18px;
  height: 17px;
  transform: translateY(-50%);
  flex: none;
  image-rendering: auto; /* 픽셀아트 규칙(§4.4) 적용 대상이 아니다 — 제3자 브랜드 에셋 */
}

.kakao-login-label {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  font-weight: 700;
  line-height: 1;
  color: rgba(0, 0, 0, 0.85); /* 규정: #000000 85% */
  word-break: keep-all;
}

/* 상태 표현에 **색을 쓰지 않는다** — "지정 색상 외 색상 적용" 금지에 걸리지 않게
   움직임(transform)과 아웃라인만 쓴다. 아웃라인 색도 규정 색(검정 85%) 안에서 고른다. */
.kakao-login:active {
  transform: scale(0.985);
}

.kakao-login:focus-visible {
  outline: 2px solid rgba(0, 0, 0, 0.85);
  outline-offset: 2px;
}

/* 앱 키가 없을 때. 배경색을 바꾸지 않고 **전체 투명도**로만 눌러 규정 색을 유지한다. */
.kakao-login.is-disabled {
  opacity: 0.45;
  cursor: default;
  pointer-events: none;
}

/* 랜딩의 로그아웃 안내 배너 안 */
.notice-banner .kakao-login.notice-banner-cta {
  margin-top: var(--sp-3);
}

/* 랜딩 상단의 부차 진입점(.landing-login 안) — **폭만** 내용에 맞춘다.
   🔴 높이·심볼·색·반경은 손대지 않는다: 규정값(45px / 18×17 / #FEE500 / 12px)은 이 변형이
   건드릴 수 있는 값이 아니다. 규정이 허용하는 건 "컨테이너의 확장구간을 좌·우로" 조절하는 것뿐이라
   폭을 줄이는 방향도 좌우 패딩(0 44px)을 그대로 둔 채 auto로만 간다 — 그래야 심볼과 레이블의
   관계가 wide 버전 실측 그대로 남는다. 이 한 줄이 랜딩에서 노란 면적을 주 CTA 아래로 낮춘다. */
.kakao-login.landing-login-cta {
  width: auto;
  flex: none;
}

/* 케이스 ⑦ 화분 선택 카드 — "중요한 것일수록 표면이 밝고 반경이 크다"(§1-4).
   설정의 "primary 없음" 원칙에 대한 유일한 예외 — 설정 항목이 아니라 화면 위에 얹힌 결정 요구다. */
.settings-choice-card {
  background: var(--bg-raised);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-card);
  padding: var(--sp-4);
  margin-top: var(--sp-4);
}

.settings-choice-note {
  color: var(--ink-muted);
  font-size: 14px;
  line-height: 1.6;
  margin-bottom: var(--sp-3);
  word-break: keep-all;
}

.settings-choice-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* 위험 구역 — 목록에서 떼어내 맨 아래. 파괴적 행위가 이동 항목과 같은 무게로 읽히면 안 된다. */
.settings-section-danger {
  margin-top: var(--sp-10);
  padding-top: var(--sp-5);
  border-top: 1px solid color-mix(in srgb, var(--danger) 45%, transparent);
}

.settings-section-danger form + .settings-note {
  margin-top: var(--sp-4);
}

.settings-danger-note {
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  line-height: 1.7;
  margin: var(--sp-4) 0 var(--sp-3);
  word-break: keep-all;
}

/* ---- M6: 법무 페이지(Privacy.tsx / Terms.tsx) — 세계관 뺀다(§8): 시스템 폰트 + 잉크 토큰만 ---- */
.screen-legal {
  max-width: 720px;
}

.screen-legal .screen-title {
  font-family: var(--font-body);
  letter-spacing: 0;
}

.legal-meta {
  color: var(--ink-muted);
  font-size: var(--fs-label);
  margin-bottom: var(--sp-4);
}

.legal-intro {
  margin-bottom: var(--sp-5);
  line-height: 1.6;
}

.legal-section {
  margin-top: var(--sp-6);
}

.legal-section h2 {
  margin: var(--sp-6) 0 10px;
}

.legal-section p,
.legal-section li {
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--ink-body);
}

.legal-section ul,
.legal-section ol {
  padding-left: 18px;
}

.legal-callout {
  background: var(--bg-raised);
  border-radius: var(--r-sm);
  padding: var(--sp-3);
}

.legal-table-wrap {
  overflow-x: auto;
  margin: 10px 0;
}

.legal-table {
  border-collapse: collapse;
  width: 100%;
  font-size: var(--fs-caption);
}

.legal-table th,
.legal-table td {
  border: 1px solid var(--border);
  padding: 8px 10px;
  text-align: left;
  vertical-align: top;
}

.legal-table th {
  background: var(--bg-raised);
  color: var(--ink);
}

/* 사업자 정보에서 "아직 값이 없다"를 사실대로 적는 자리(통신판매업 신고 준비 중).
   🔴 값과 **다르게 보여야** 한다 — 같은 무게로 그리면 "신고 준비 중"이 번호처럼 읽힌다.
   숨기지는 않는다(항목 누락으로 보인다). */
.legal-pending {
  color: var(--ink-muted);
  font-style: italic;
}

.legal-note {
  font-size: var(--fs-label);
  color: var(--ink-muted);
  margin-top: var(--sp-2);
}

/* ---- M6: 사이트 전역 푸터 ---- */
.app-footer {
  margin-top: var(--sp-8);
  padding: var(--sp-4) 0 var(--sp-2);
  text-align: center;
  font-size: var(--fs-label);
  color: var(--ink-muted);
}

.app-footer a {
  color: var(--ink-muted);
}

/* ---- 모션 존중 (§6) ---- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---- 정원 생성 시트 (§5.8 바텀시트 · 2026-08-16 "버튼 → 이름 짓기 팝업") ----
   신규 클래스만 추가한다(기존 규칙 무수정). 트리거는 링크라 JS 없이도 /garden/new로 폴백된다. */
.create-garden {
  display: contents;
}

.garden-list-cta {
  margin-top: var(--sp-2);
}

.sheet {
  width: 100%;
  max-width: 480px;
  margin: auto auto 0;
  padding: 0;
  border: none;
  background: var(--bg-overlay);
  color: var(--ink-body);
  border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  box-shadow: inset 0 1px 0 var(--edge-light);
}

/* ::backdrop은 엔진에 따라 커스텀 속성을 상속받지 못한다 — 폴백 값으로 --scrim과 같은 값을 둔다. */
.sheet::backdrop {
  background: var(--scrim, rgba(9, 9, 13, 0.6));
}

.sheet[open] {
  animation: sheet-rise var(--dur-base) var(--ease-out);
}

@keyframes sheet-rise {
  from {
    transform: translateY(16px);
    opacity: 0;
  }
}

.sheet-grabber {
  display: block;
  width: 36px;
  height: 4px;
  margin: 0 auto var(--sp-4);
  border-radius: var(--r-pill);
  background: var(--border-strong);
}

.sheet-title {
  margin: 0;
  font-size: var(--fs-heading);
  font-weight: 700;
  color: var(--ink);
}

.sheet-desc {
  margin: var(--sp-1) 0 var(--sp-4);
  font-size: var(--fs-caption);
  color: var(--ink-muted);
}

.create-garden-form {
  padding: var(--sp-5) var(--sp-5) calc(var(--sp-5) + env(safe-area-inset-bottom));
}

/* 전역 input 규칙은 flex 컨테이너(.date-row) 전제라 flex:1만 갖는다 — 단독 배치인 여기선 폭을 명시. */
.create-garden-form input[type='text'] {
  width: 100%;
}

.screen-garden-new .create-garden-form {
  padding: 0;
}

.screen-garden-new .sheet-desc {
  margin-top: calc(-1 * var(--sp-2));
}

/* ---- 이탈 수단: 뒤로가기 링크 (§5.10) ----
   탭바가 없어야 정당한 화면(법무 문서·초대 랜딩·만료 안내)의 이탈 수단. 이 앱엔 개편 전까지
   뒤로가기가 단 하나도 없어서, 탭바 없는 화면이 전부 막다른 길이었다(§11.1).
   새 색을 발명하지 않는다 — --ink-muted → hover/focus 시 --ink. 터치 타깃 44px 확보(§접근성). */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  margin-bottom: var(--sp-2);
  color: var(--ink-muted);
  font-size: var(--fs-body);
  font-weight: 600;
  text-decoration: none;
}

.back-link:hover,
.back-link:focus-visible {
  color: var(--ink);
}

/* 셰브론 — 아이콘 에셋 없이 보더 2개를 회전시켜 그린다(픽셀 에셋 회전 금지 규칙과 무관한 CSS 도형) */
.back-link-chevron {
  width: 9px;
  height: 9px;
  border-left: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
}

/* ============================================================
   S04 홈 v2 (2026-08-16 재설계 — design-system.md §12)
   "내 것 요약"에서 "오늘 무슨 일이 있나"로. 신규 클래스만 추가한다(기존 규칙 무수정).
   ============================================================ */

/* 탭바가 이미 "홈"을 말하므로 h1은 스크린리더에만 남긴다(§12.1 — 제목 줄은 오늘의 기운이 갖는다) */
.screen-title-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---- A. 오늘의 기운 — 이 화면의 유일한 대면적 요소 ---- */
.today-qi {
  margin-top: var(--sp-2);
  padding: var(--sp-5) var(--sp-4) var(--sp-4);
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
}

.today-qi-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-4);
}

.today-qi-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-title);
  color: var(--ink);
}

.today-qi-date {
  font-size: var(--fs-caption);
  color: var(--ink-muted);
  font-variant-numeric: tabular-nums;
}

/* ============================================================
   오늘의 장면 v2 — 4×4 아이소 타일 격자 (2026-08-17 오너 지시, §12.3 개정)

   구 `.today-scene`(아래 @deprecated 블록)은 타일 1장을 repeat-x로 가로로만 깔았다. 아이소 타일
   상판은 2:1 마름모라 이미지 경계를 맞대면 좌우 꼭짓점만 닿고 사이에 투명 삼각형이 남는다 →
   **톱니**. 오브젝트는 left:50%/bottom:18px로 얹혀 어느 칸에도 접지하지 않았다 → **붕 뜬 오브제**.
   이제 좌표는 전부 lib/visual/today-grid.ts가 계산하고(그룹 정원과 같은 tilegrid.ts 규약),
   CSS는 앵커 transform 두 종류만 갖는다 — 타일은 상판 중심 top, 스프라이트는 밑변 중심.

   폭 256px의 근거: 타일 소스가 256×192이고 4×4 격자에서 타일 1장 = 프레임폭/4이므로,
   256px에서 타일이 정확히 64px = **소스의 1/4 정수 축소**가 된다(픽셀 아트 뭉개짐 방지).
   부모가 그보다 좁으면 min()이 비정수로 내려가므로 image-rendering: pixelated가 2차 방어다.
   높이는 인라인 aspect-ratio(768/432 = 16:9)가 정한다 — 컴포넌트가 격자에서 받아 꽂는다.
   ============================================================ */
/* 판(무대) — 🔴 2026-08-17 2차: "검정 배경이 좀 답답한 것 같아. … 위아래 여백을 늘리고 좌우는
   폭에 가능한 맞추는 게 어떨까"(오너). 전에는 어두운 판이 곧 격자 프레임(폭 256px)이어서
   ① 카드 안에서 좌우로 크게 남고 ② 위아래 여백이 0이라 격자가 상자에 꽉 낀 채 갇혀 보였다.
   이제 판과 격자를 분리한다 — 판은 카드 안쪽 폭을 쓰고 위아래로 숨 쉬며, 격자는 그 안에 가운데.

   🔴 격자 크기는 **그대로 둔다**(오너 정정: "폭을 넓혀달라는 게 타일을 넓혀달라는 건 아니고").
   타일을 키우면 정수 축소(소스 256px → 64px = 1/4)가 깨져 이음새에 틈이 생긴다. 좌우 패딩을
   --sp-2로 얕게 준 것도 같은 이유다 — 320px 기기에서 격자 폭이 232px(타일 58px 정수)로만
   내려가고, 그보다 큰 패딩을 주면 작은 화면에서 격자가 필요 이상으로 쪼그라든다.

   판 색 = --bg(#1b1b23). --bg-deep(#131318)은 카드(--bg-raised #24242f) 대비 너무 떨어져
   "검정 상자"로 읽혔다. --bg는 카드보다 정확히 한 단 어두우면서 **픽셀 에셋의 제작 기준색**이라
   (§2.1 "변경 금지 — 픽셀 에셋 제작 기준색") 타일 가장자리와 판이 같은 지반 위에서 만난다. */
.today-stage {
  margin: 0 0 var(--sp-4);
  padding: var(--sp-5) var(--sp-2);
  border-radius: var(--r-control);
  background: var(--bg);
}

.today-grid {
  position: relative;
  width: min(256px, 100%);
  margin: 0 auto;
  overflow: hidden;
}

/* 타일 — 상판 중심 top 앵커(.tile-grid-tile과 같은 계약). 폭만 주고 높이는 자연 비율. */
.today-grid-tile {
  position: absolute;
  display: block;
  transform: translate(-50%, 0);
  image-rendering: pixelated;
}

/* 오브젝트·fx — 밑변 중심 앵커(.garden-visual-sprite와 같은 계약). 정사각 스프라이트라
   폭만 주면 높이가 따라온다. fx는 1024×256(4:1)이라 같은 규약으로 가로 띠가 된다. */
.today-grid-sprite {
  position: absolute;
  display: block;
  transform: translate(-50%, -100%);
  image-rendering: pixelated;
}

/* 분위기 이펙트 — 오브젝트와 **같은 칸**에 정렬된 채 그 위를 덮는다(옅게). */
.today-grid-fx {
  opacity: 0.4;
  mix-blend-mode: screen;
  pointer-events: none;
}

/* 사주 미입력(§12.6) — 같은 격자에 잠금 상태만 다르게. 씨앗 타일을 가라앉힌다. */
.today-qi-locked .today-grid-tile,
.today-qi-locked .today-grid-sprite {
  opacity: 0.45;
}

/* 🌟 60일에 하루 — 내 일주가 돌아온 날에만 뜬다. 브랜드 액센트를 여기 한 줄에만 쓴다
   (§4.5 면적 규칙 — 희소해야 특별해 보인다). */
.today-qi-myday {
  margin: 0 0 var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-control);
  background: rgba(155, 212, 87, 0.12);
  border: 1px solid rgba(155, 212, 87, 0.35);
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--accent);
}

/* 칩 묶음 라벨(🔴 2026-08-17 2차 → 3차에서 **둘로 쪼갬**) — 같은 클래스를 두 번 쓴다.
   2차에는 라벨이 하나였다("오늘의 O 기운에 딸린 것"). 그런데 칩 넷은 성격이 둘로 갈린다:
   색·숫자는 사용자가 **할 수 있는 것**, 시간·동물은 할 수 있는 것이 아니라 **날짜의 사실**이다.
   한 라벨로 묶어 두니 "그래서 챙기라는 거야 피하라는 거야"(오너)라는 질문이 남았다 —
   묶음을 쪼개고 라벨을 각각 세우면 **라벨만 읽어도** 둘이 갈린다(§12.9).
   위아래 마진이 같은 --sp-5인 이유: 두 묶음이 형제라 어느 쪽도 상대에 딸려 보이면 안 된다. */
.today-facts-title {
  margin: var(--sp-5) 0 var(--sp-2);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-muted);
}

/* 한 줄 설명 — "이게 무엇인지 명확하게 써줘"(오너). 묶음 라벨 바로 아래·칩 **위**에 둔다
   (칩 아래면 다 읽고 나서야 무엇이었는지 알게 된다 — 2차에서 구 .today-qi-foot이 겪은 실패).
   오행색 한 글자는 여기로 옮겨 왔다(2차에는 .today-facts-title strong이었다) — §4.5 면적 규칙상
   오행색은 이 한 글자와 12px 스와치에만 쓴다. */
.today-facts-note {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-caption);
  line-height: 1.5;
  color: var(--ink-muted);
}

.today-facts-note strong {
  color: var(--el-text, var(--ink));
  font-weight: 700;
}

/* 부가 정보(§12.7) — 한 줄에 2칸씩 끊어 "한 눈에 스캔"되게 한다. 나열표가 되지 않는 것이
   목적이라 칩 총수는 4개를 넘기지 않는다(방위·절기를 뺀 이유는 design-system.md §12.7 참조).
   3차에서 dl이 2개(묶음당 하나)로 갈렸을 뿐, 한 행 2칸이라는 격자 규칙은 그대로다. */
.today-facts {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-2);
  margin: 0;
  padding: 0;
}

.today-fact {
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-control);
  background: rgba(255, 255, 255, 0.04);
}

.today-fact-label {
  display: block;
  font-size: var(--fs-label);
  color: var(--ink-muted);
}

.today-fact-value {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 2px 0 0;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* 오늘의 색 스와치 — 오행색 토큰을 그대로 쓴다(색 단일 소스: lib/theme.ts ↔ :root --el-*).
   글자와 색이 어긋나면 안 되므로 이름표(today-lore.ts colorName)도 이 토큰 기준으로 적었다. */
.today-swatch {
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 3px;
  background: var(--el, var(--ink-muted));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.25);
}

/* ---- @deprecated (2026-08-17) 구 띠(band) 장면 ----
   Home.tsx가 아직 이 마크업을 렌더하고 있어 남겨 둔다. 배선이 .today-grid로 넘어가면
   .today-scene* 5종을 통째로 지운다. 새 화면에서 쓰지 말 것. */
/* 오늘의 장면 — /result 디오라마와 갈라 세우는 지점(§12.3):
   ① 높이 96px 고정(소형) ② 타일 바닥이 깔린 띠 ③ 프레임 안쪽(무대 글로우 없음). */
.today-scene {
  position: relative;
  height: 96px;
  margin-bottom: var(--sp-4);
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--bg-deep);
}

/* 바닥: 타일을 가로로만 반복해 "땅"을 만든다. 세로 반복 금지(다이아 타일이 겹쳐 깨진다). */
.today-scene-ground {
  position: absolute;
  inset: auto 0 0 0;
  height: 64px;
  background-repeat: repeat-x;
  background-position: center bottom;
  background-size: auto 64px;
  image-rendering: pixelated;
  opacity: 0.85;
}

.today-scene-obj {
  position: absolute;
  left: 50%;
  bottom: 18px;
  width: 48px;
  height: 48px;
  transform: translateX(-50%);
  image-rendering: pixelated;
}

/* 분위기 이펙트 — 장면 전체를 덮되 옅게. 오브젝트보다 뒤에 깔린다(z-index 없이 문서 순서로). */
.today-scene-fx {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.35;
  image-rendering: pixelated;
  mix-blend-mode: screen;
}

/* 문장 두 층 — 오늘의 결(굵게, 이 카드의 헤드라인) → 내 화분과의 관계(본문) */
.today-qi-weather {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-heading);
  font-weight: 600;
  line-height: 1.5;
  color: var(--ink);
}

.today-qi-bond {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.6;
  color: var(--ink-body);
}

/* 🔴 층 구분 라벨(2026-08-17 2차) — "이게 내 사주와 상관있는 내용이야?"(오너)의 직접 해법.
   문법·값 모두 .interpretation-label(개인 결과 §5.5)에서 그대로 가져왔다: 짧은 명사구를 문장
   위에 블록으로 세우고 --ink-muted로 낮춰 본문과 위계를 만든다. 색을 새로 발명하지 않는다.
   font-size/weight를 명시하는 이유 — 부모(.today-qi-weather)가 헤딩 크기·600이라 상속되면
   라벨이 문장만큼 커진다. */
.today-qi-label {
  display: block;
  margin-bottom: var(--sp-1);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.4;
  color: var(--ink-muted);
}

.today-qi-line {
  display: block;
}

/* D. 사주 미입력 — 오늘의 기운이 성립하지 않는 홈. 같은 틀에 잠금 상태만 다르게. */
.today-scene-locked .today-scene-ground {
  opacity: 0.4;
}

.today-qi-cta {
  display: block;
  margin-top: var(--sp-4);
  text-align: center;
}

/* ---- B. 정원 소식 ---- */
.home-news {
  margin-top: var(--sp-8);
}

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

.news-item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  background: var(--bg-raised);
  border-radius: var(--r-control);
  text-decoration: none;
  color: inherit;
}

.news-item:hover,
.news-item:focus-visible {
  background: var(--bg-overlay);
}

.news-item-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  background: var(--bg-overlay);
  border-radius: var(--r-sm);
}

.news-item-icon img {
  width: 22px;
  height: 22px;
  image-rendering: pixelated;
}

.news-item-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.news-item-line {
  font-size: var(--fs-body);
  color: var(--ink-body);
}

.news-item-date {
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

/* 빈 상태를 1급으로 — 신규·1인이 다수라 이게 예외가 아니라 기본값이다(§12.2) */
.home-news-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-4);
  background: var(--bg-raised);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-card);
  text-align: center;
}

.home-news-empty-icon {
  width: 40px;
  height: 40px;
  image-rendering: pixelated;
  opacity: 0.8;
}

.home-news-empty-line {
  margin: 0;
  font-size: var(--fs-body);
  color: var(--ink-muted);
  line-height: 1.6;
}

.home-news-empty-cta {
  align-self: stretch;
}

/* ---- C. 이동 통로 — 요약이 아니라 링크. 카드보다 한 급 낮게 보여야 한다(§12.1) ---- */
.home-passages {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-2);
  margin-top: var(--sp-8);
}

.passage {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  padding: var(--sp-3);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  text-decoration: none;
}

.passage:hover,
.passage:focus-visible {
  border-color: var(--border-strong);
  background: var(--bg-raised);
}

.passage-icon {
  width: 28px;
  height: 28px;
  margin-bottom: var(--sp-1);
  image-rendering: pixelated;
}

.passage-label {
  font-size: var(--fs-caption);
  font-weight: 600;
  color: var(--ink-body);
}

.passage-sub {
  font-size: var(--fs-label);
  color: var(--ink-faint);
}

/* 통로가 하나뿐인 경우(사주 미입력) 반 칸으로 남지 않게 가로 전체를 쓴다 */
.home-passages .passage:only-child {
  grid-column: 1 / -1;
  flex-direction: row;
  align-items: center;
  gap: var(--sp-3);
}

.home-passages .passage:only-child .passage-icon {
  margin-bottom: 0;
}
