/* giirin 공용 컴포넌트 — contrace-ds 시맨틱 토큰 위에 얹는 클래스.
   토큰 출처: contrace/fig-tokens.css(시맨틱) + contrace/contrace-theme.css(테라코타·차트).
   레이아웃은 Tailwind 유틸로, 색·모양은 여기서. 다크모드는 [data-theme] 토큰이 알아서 뒤집는다.

   2026-08-01 업그레이드 — Apify 콘솔 실측 반영 (docs/DS_MEASUREMENT_APIFY.md).
   요지: ① radius를 조인다(카드16→12, 버튼10→8) ② 그림자는 "띄우는 것"에만, 카드는 선으로만
        ③ 모션 .12s 토큰화 ④ 없던 컴포넌트(메뉴·모달·토스트·폼·아코디언·탭·페이저·빈상태) 신설.
   폰트는 기존 Pretendard/Wanted Sans 유지 — Apify의 Inter는 가져오지 않는다. */

:root {
  /* 파생 별칭 — DS 토큰을 화면 어휘로 축약 (여기서만 정의, 다른 곳에서 하드코딩 금지) */
  --g-ground: var(--background-normal-alternative, #F7F7F8);
  --g-surface: var(--background-normal-normal, #FFFFFF);
  --g-elevated: var(--background-elevated-normal, #FFFFFF);
  --g-label: var(--label-normal, #171719);
  /* ★보조 라벨 두 종은 fig-tokens 원본(.61 / .28)을 그대로 쓰면 흰 배경 대비가
     3.64:1 · 1.69:1 로 WCAG AA(본문 4.5:1, 부가 3:1)에 한참 못 미친다.
     실제로 상세 페이지의 근거 문장이 "안 보인다"는 지적을 받았다(2026-08-01).
     참고로 Apify의 보조색 #6D7178 은 4.90:1 이다. 여기서 알파를 올려 덮는다.
       .61 → .69  = 4.55:1   (본문으로 읽히는 보조 텍스트)
       .28 → .57  = 3.28:1   (메타·캡션. 여전히 흐리지만 읽을 수는 있다) */
  /* ★2026-08-03: 원본 DS 값(.61/.28)은 물론이고 1차 보정(.69/.57)도 여전히 흐렸다.
     "메뉴부터 다 연하고 흐리멍텅하다"는 지적을 받고 한 번 더 올렸다.
       alt   .86 → 흰 배경 대비 7.3:1 (본문에 가까운 보조 문장)
       faint .72 → 4.9:1 (메타. 예전 3.28:1 은 사실상 안 읽혔다)
     위계는 색 차이가 아니라 굵기·크기로 만든다 — 흐리게 해서 만드는 위계는 위계가 아니라 손실이다. */
  --g-label-alt: rgba(55,56,60,.86);
  --g-label-faint: rgba(55,56,60,.72);
  --g-line: var(--line-normal-normal, rgba(112,115,124,.22));
  --g-line-soft: var(--line-normal-alternative, rgba(112,115,124,.08));
  --g-hairline: rgba(112,115,124,0.16); /* DS 킷 카드/셸 보더 (kitTokens.hairline) */
  --g-positive: var(--status-positive, rgb(0,150,80));
  --g-caution: var(--status-cautionary, rgb(255,150,0));
  --g-negative: var(--status-negative, rgb(255,66,66));

  /* ── radius 스케일 (실측: 6px 46회 · 4px 22회 · 8px · 12px) ── */
  --r-1: 4px;    /* 체크박스·초소형 */
  --r-2: 6px;    /* 작은 컨트롤·태그 */
  --r-3: 8px;    /* 버튼·인풋·메뉴 항목 */
  --r-4: 12px;   /* 카드·패널·팝오버 */
  --r-5: 16px;   /* 큰 모달 */
  --r-full: 999px;

  /* ── 그림자 (실측: 전체 3종뿐. 카드에는 쓰지 않는다) ──
     색이 순수 검정이 아니라 파란끼(63,71,93)라 회색 위에서 탁해지지 않는다. */
  --sh-line: inset 0 0 0 1px var(--g-hairline);           /* 레이아웃 안 밀고 테두리 */
  --sh-pop:
    0 4px 10px -2.5px rgba(63,71,93,.12),
    0 2px 4px -1.7px rgba(63,71,93,.13),
    0 1px 1.5px -.8px rgba(63,71,93,.14);                 /* 드롭다운·팝오버 */
  --sh-modal: 0 1px 6px rgba(0,0,0,.06), 0 2px 32px rgba(0,0,0,.16);
  --sh-toast: 0 4px 12px rgba(63,71,93,.14), 0 12px 32px rgba(63,71,93,.12);

  /* ── 모션 (실측: .12s ease-out 이 지배적) ── */
  --dur-1: .12s;  /* 상태 변화 — hover/focus/색 */
  --dur-2: .2s;   /* 레이아웃 — 높이/폭 */
  --dur-3: .3s;   /* 패널 진입 */
  --ease-out: cubic-bezier(.2,.8,.2,1);
  --ease-io: cubic-bezier(.4,0,.2,1);

  /* ── 타입 스텝 ──
     실측 결과 우리 화면에 서로 다른 크기가 12종(10·10.5·11·11.5·12·12.5·13·13.5·15·16·17·24)이나
     있었다. 3.5px 안에 8단계가 몰려 있으니 "디자인 시스템이 안 맞는 느낌"이 날 수밖에 없다.
     Apify 콘솔은 사실상 12/13/14/20 네 종으로 끝낸다. 아래 6단계로 좁힌다. */
  --fs-1: 11px;  /* 그룹 라벨·초소형 태그 */
  --fs-2: 12px;  /* 메타·칩·표 헤더 */
  --fs-3: 13px;  /* 기본 본문·표 셀·사이드바 */
  --fs-4: 14px;  /* 강조 라벨·버튼 */
  --fs-5: 16px;  /* 섹션 제목 */
  --fs-6: 20px;  /* 페이지 제목 */
  --fs-kpi: 24px;

  /* ══ 타이포·색 사용 규칙 (2026-08-03 확정 — "체계가 잡혀 있긴 하냐"는 지적의 답) ══
     크기는 아래 6단 + KPI 만 쓴다. 새 값을 만들지 말 것.
       11px … 숫자 뒤 단위(건/명/개), 정렬 화살표, 키캡 같은 **비문장 요소 전용**.
              ★사람이 읽는 문장·라벨에 11px 를 쓰지 않는다. 최소 12px.
       12px … 메타(날짜·개수), 칩, 표 헤더, 보조 라벨
       13px … 기본 본문, 표 셀, 사이드바
       14px … 강조 라벨, 버튼, 카드 소제목
       16px … 섹션 제목
       20px … 페이지 제목

     색은 세 단계뿐이다. 쓰임을 섞지 말 것.
       --g-label       본문·제목            (대비 15:1)
       --g-label-alt   보조 문장·설명       (4.55:1 — 문장에 쓸 수 있는 하한)
       --g-label-faint 메타 전용            (3.28:1 — **문장에 쓰지 않는다.** 날짜·개수·단위만)
     즉 "읽어야 하는 문장"에 faint 를 쓰면 안 된다. 실제로 그렇게 쓴 자리가
     "배경이랑 구분이 안 돼 안 읽힌다"는 지적을 받았다. */

  /* ── z 레이어 ── */
  --z-sticky: 20; --z-pop: 40; --z-backdrop: 55; --z-modal: 60; --z-toast: 80; --z-tip: 9999;

  /* ── 레이아웃 폭 (2026-08-03) ──
     "중구난방의 레이아웃 너비"라는 지적을 받았다. 화면마다 1080·1200·960·760이 섞여 있었다.
     이제 아래 셋만 쓴다. 새 값을 임의로 만들지 말 것. */
  --w-app: 1200px;    /* 앱 화면(대시보드·분석·목록) 본문 컬럼 */
  --w-mkt: 1120px;    /* 마케팅(랜딩) 컬럼 */
  --w-read: 68ch;     /* 읽기용 텍스트 한 줄 — 한글 기준 약 40자 */
  --pad-x: 24px;      /* 컬럼 좌우 여백(데스크탑) */
  --pad-x-sm: 16px;   /* 〃 (모바일) */
}

:root[data-theme="dark"] {
  /* 라이트에서 알파를 올려 덮었으므로 다크도 같이 올려야 한다.
     다크 원본은 rgba(174,176,182,…) 이라 라이트 값을 그대로 두면 어두운 글씨가 어두운 배경에
     깔려 아예 안 보인다. 다크 표면 rgb(27,28,30) 기준 실측:
       .61 → 3.84:1 (부족)   .69 → 4.59:1 ✓
       .28 → 1.78:1 (심각)   .53 → 3.22:1 ✓ */
  --g-label-alt: rgba(174,176,182,.88);   /* 6.1:1 */
  --g-label-faint: rgba(174,176,182,.74);  /* 4.7:1 */

  /* 다크에선 그림자가 안 보인다 → 테두리를 조금 더 세워 깊이를 만든다 */
  --sh-pop: 0 4px 12px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.6);
  --sh-modal: 0 2px 8px rgba(0,0,0,.5), 0 8px 40px rgba(0,0,0,.6);
  --sh-toast: 0 6px 20px rgba(0,0,0,.55);
}

/* 접근성 — 모션 줄이기를 켠 사용자에겐 전환을 끈다 */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-1: .01ms; --dur-2: .01ms; --dur-3: .01ms; }
}

/* ★ .hidden 보증 —
   Tailwind 4의 유틸리티는 `@layer utilities` 안에 있고 이 파일은 레이어 밖이다.
   캐스케이드에서 un-layered 가 layered 를 이기므로 `display:flex` 를 가진 컴포넌트에
   `hidden` 을 붙여도 안 숨겨진다. (실측: 필터 결과 0건용 빈 상태가 행이 3개 보이는데도
   같이 떠 있었다.) display 를 지정하는 컴포넌트는 전부 여기서 명시적으로 막는다. */
.c-menu.hidden, .c-menu-item.hidden, .c-field.hidden, .c-input-icon.hidden,
.c-check.hidden, .c-radio.hidden, .c-check-row.hidden, .c-switch.hidden,
.c-modal.hidden, .c-modal-head.hidden, .c-modal-foot.hidden, .c-backdrop.hidden,
.c-toast-wrap.hidden, .c-toast.hidden,
.c-tabs.hidden, .c-tab.hidden, .c-seg.hidden, .c-seg > label.hidden,
.scale-row.hidden, .scale-main.hidden,
.c-filterbar.hidden, .c-filter-btn.hidden, .c-pager.hidden,
.c-empty.hidden, .c-empty-acts.hidden, .c-empty-card.hidden, .c-more.hidden,
.c-kbd.hidden, .c-meter.hidden, .cell-id.hidden, .c-alert.hidden,
.pill.hidden, .chip.hidden, .tag.hidden, .step.hidden, .c-ava.hidden,
.side-nav-i.hidden, .og-row.hidden, .spot-row.hidden, .fmt-badge.hidden,
.ev-ref.hidden, .pitch-idea.hidden, .qscore.hidden, .radar-legend.hidden {
  display: none !important;
}

/* ── 카드 ──
   실측 근거: Apify는 카드에 그림자를 쓰지 않고 1px 선으로만 나눈다(border 73회 vs 그림자 3종). */
.c-card {
  background: var(--g-surface);
  border: 1px solid var(--g-hairline);
  border-radius: var(--r-4);
}
.c-card--pad { padding: 16px; }
.c-card--hover { transition: border-color var(--dur-1), background var(--dur-1); }
.c-card--hover:hover { border-color: var(--g-line); background: var(--g-line-soft); }

/* ── 버튼 ── */
.c-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  font-size: 14px; font-weight: 600; letter-spacing: .014em;
  border-radius: var(--r-3); padding: 9px 16px; cursor: pointer;
  border: 1px solid var(--g-line); background: var(--g-surface); color: var(--g-label);
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out),
              border-color var(--dur-1) var(--ease-out), opacity var(--dur-1);
}
.c-btn:hover { color: var(--g-label); border-color: var(--g-line); background: var(--g-line-soft); }
.c-btn--pri, a.c-btn--pri, a.c-btn--pri:visited { background: var(--primary-normal); border-color: var(--primary-normal); color: #fff; }
.c-btn--pri:hover:enabled, a.c-btn--pri:hover { background: var(--primary-strong); border-color: var(--primary-strong); color: #fff; }
/* 다크에선 primary가 밝은 살몬(contrace-60)이라 흰 글씨 대비가 무너진다 → 어두운 글씨로 반전 */
:root[data-theme="dark"] .c-btn--pri, :root[data-theme="dark"] a.c-btn--pri,
:root[data-theme="dark"] a.c-btn--pri:visited, :root[data-theme="dark"] .c-btn--pri:hover:enabled,
:root[data-theme="dark"] a.c-btn--pri:hover { color: rgb(23,23,25); }
/* 조용한 버튼 — 테두리 없이 hover 때만 배경 (툴바·아이콘 버튼용) */
.c-btn--ghost { border-color: transparent; background: transparent; }
.c-btn--ghost:hover { background: var(--g-line-soft); border-color: transparent; }
.c-btn--danger { color: var(--g-negative); border-color: color-mix(in srgb, var(--g-negative) 40%, transparent); }
.c-btn--danger:hover { background: color-mix(in srgb, var(--g-negative) 8%, transparent); color: var(--g-negative); }
.c-btn--sm { font-size: 13px; padding: 6px 12px; border-radius: var(--r-2); }
.c-btn--xs { font-size: 12px; padding: 4px 9px; border-radius: var(--r-2); gap: 4px; }
.c-btn--icon { padding: 0; width: 28px; height: 28px; border-radius: var(--r-2); }
.c-btn--block { display: flex; width: 100%; }
.c-btn:disabled { opacity: .4; cursor: not-allowed; }
/* tailwind 4 유틸리티는 @layer라 un-layered .c-btn의 display에 진다 → 명시적으로 숨김 보장 */
.c-btn.hidden { display: none !important; }
/* ★반응형 변형도 같은 함정에 걸린다 — `md:hidden` 은 @layer utilities 안이라
   un-layered .c-btn{display:inline-flex} 에 진다. 실제로 데스크탑에서 안 숨겨졌다(2026-08-02). */
@media (min-width: 768px) { .c-btn.md\:hidden, .pill.md\:hidden, .chip.md\:hidden { display: none !important; } }
@media (min-width: 640px) { .c-btn.sm\:hidden, .pill.sm\:hidden, .chip.sm\:hidden { display: none !important; } }

/* ── 상태 pill ── */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; border-radius: var(--r-full); padding: 3px 9px; white-space: nowrap;
}
.pill--run  { background: var(--primary-background); color: var(--primary-foreground); }
.pill--ok   { background: color-mix(in srgb, var(--g-positive) 10%, transparent); color: var(--g-positive); }
.pill--warn { background: color-mix(in srgb, var(--g-caution) 12%, transparent); color: color-mix(in srgb, var(--g-caution) 78%, var(--g-label)); }
.pill--bad  { background: color-mix(in srgb, var(--g-negative) 10%, transparent); color: var(--g-negative); }
.pill--mute { background: var(--g-line-soft); color: var(--g-label-alt); }
/* 진행중 표시 — 점이 숨쉰다 (Apify 의 Running 칩과 같은 사고) */
.pill--run .pill-dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; animation: pulse-dot 1.4s ease-in-out infinite; }
@keyframes pulse-dot { 0%,100% { opacity: 1 } 50% { opacity: .35 } }

/* ── 칩 (필터·매칭기준) ── */
.chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; font-weight: 500; border: 1px solid var(--g-line);
  border-radius: var(--r-full); padding: 4px 11px; color: var(--g-label); background: var(--g-surface);
  transition: background var(--dur-1), border-color var(--dur-1), color var(--dur-1);
}
button.chip, a.chip { cursor: pointer; }
button.chip:hover, a.chip:hover { background: var(--g-line-soft); color: var(--g-label); }
.chip--on  { background: var(--primary-background); border-color: transparent; color: var(--primary-foreground); font-weight: 600; }
/* 제외 기준 칩 — ✕ 아이콘을 떼고 그룹 소제목("이런 채널은 제외합니다")이 뜻을 맡는다.
   칩 자체는 색으로만 구분한다. 아이콘으로 문장을 대신하려 들면 늘 오해가 생긴다. */
.chip--neg {
  color: var(--g-negative);
  border-color: color-mix(in srgb, var(--g-negative) 40%, transparent);
  background: color-mix(in srgb, var(--g-negative) 5%, var(--g-surface));
}
.crit-grp { margin-top: 14px; }
.crit-k { font-size: 12.5px; font-weight: 700; color: var(--g-label-alt); margin-bottom: 7px; }
.crit-k--neg { color: var(--g-negative); }
.crit-chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* ── 작은 태그 (경고·매칭 불명·구매 인증) ── */
.tag {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px; font-weight: 600; border-radius: var(--r-2); padding: 2px 7px; white-space: nowrap;
}
.tag--ok   { background: color-mix(in srgb, var(--g-positive) 9%, transparent); color: var(--g-positive); }
.tag--warn { background: color-mix(in srgb, var(--g-caution) 13%, transparent); color: color-mix(in srgb, var(--g-caution) 78%, var(--g-label)); }
.tag--unk  { background: color-mix(in srgb, var(--g-negative) 9%, transparent); color: var(--g-negative); }

/* ── 키캡 (단축키 표시 — Apify ⌘K 팔레트 패턴) ── */
.c-kbd {
  display: inline-flex; align-items: center; justify-content: center; min-width: 18px;
  height: 18px; padding: 0 5px; border-radius: var(--r-1);
  border: 1px solid var(--g-line); background: var(--g-line-soft);
  font-size: 11px; font-weight: 600; color: var(--g-label-alt); font-variant-numeric: tabular-nums;
}

/* ── 알림 배너 ── */
.c-alert {
  display: flex; gap: 10px; align-items: flex-start;
  border-radius: var(--r-3); padding: 11px 14px; font-size: 13px; color: var(--g-label-alt);
}
.c-alert--caution { background: color-mix(in srgb, var(--g-caution) 9%, transparent); }
.c-alert--caution b, .c-alert--caution .c-alert-i { color: color-mix(in srgb, var(--g-caution) 80%, var(--g-label)); }
.c-alert--negative { background: color-mix(in srgb, var(--g-negative) 8%, transparent); }
.c-alert--negative b, .c-alert--negative .c-alert-i { color: var(--g-negative); }
.c-alert--info { background: var(--primary-background); }
.c-alert--info b, .c-alert--info .c-alert-i { color: var(--primary-foreground); }

/* ── KPI ──
   28px → 24px, 라벨 12 → 11.5. 실측상 데이터 화면의 주력은 12~13px이고 숫자만 크게 띄우면
   여백이 비어 보인다(대시보드 KPI 5장이 각 90px로 텅 비었던 문제). */
.kpi-t { font-size: 12.5px; font-weight: 600; color: var(--g-label-alt); letter-spacing: .01em; }
.kpi-v { font-size: 24px; font-weight: 700; letter-spacing: -.022em; font-variant-numeric: tabular-nums;
  color: var(--g-label); line-height: 1.25; margin-top: 2px; }
.kpi-v small { font-size: 12px; font-weight: 500; color: var(--g-label-faint); margin-left: 2px; }

/* ── 테이블 ── */
/* 밀도: 실측상 조밀한 데이터 표는 12~13px. 13.5 → 13, 셀 패딩 11 → 9. */
.c-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
/* ★머리글 (2026-08-03 재작업) — 예전엔 알파 .08 회색 배경 + 흐린 글자라 바닥과 구분이 안 됐다.
   ①브랜드색을 아주 옅게 깔아 "여기가 머리글"임을 면으로 알리고
   ②글자를 본문색·600 으로 세우고
   ③아래 경계를 브랜드색 2px 로 그어 본문 첫 행과 확실히 끊는다. */
.c-tbl th {
  text-align: left; font-size: 12px; font-weight: 600; letter-spacing: .01em;
  color: var(--g-label); white-space: nowrap;
  padding: 10px 14px;
  background: color-mix(in srgb, var(--primary-normal) 6%, var(--g-surface));
  border-bottom: 2px solid color-mix(in srgb, var(--primary-normal) 28%, transparent);
}
:root[data-theme="dark"] .c-tbl th {
  background: color-mix(in srgb, var(--primary-normal) 12%, var(--g-surface));
}
.c-tbl td { padding: 10px 14px; border-bottom: 1px solid var(--g-line-soft); }
.c-tbl tbody tr:last-child td { border-bottom: 0; }
/* ★행 클릭 규약 (2026-08-03) — "어떤 표는 행이 눌리고 어떤 표는 버튼을 눌러야 한다"는
   일관성 지적. 이제 규칙은 하나다: **클릭 가능한 행은 행 전체가 눌린다.**
   마지막 칸에는 텍스트 링크("결과 보기 →")를 두지 않고 chevron 어포던스만 둔다 —
   글자 링크가 있으면 "저기를 눌러야 하나?" 하고 한 번 더 판단하게 만든다. */
.c-tbl tbody tr.is-link { cursor: pointer; }
.c-tbl tbody tr.is-link:hover { background: color-mix(in srgb, var(--primary-normal) 4%, transparent); }
.c-tbl tbody tr.is-link:hover .cell-go { color: var(--primary-normal); }
.c-tbl tbody tr.is-link:hover .cell-go svg { transform: translateX(2px); }
.cell-go { color: var(--g-label-faint); display: flex; justify-content: flex-end; transition: color var(--dur-1); }
.cell-go svg { transition: transform var(--dur-1) var(--ease-out); }
.c-tbl th.go, .c-tbl td.go { width: 36px; padding-left: 0; padding-right: 12px; }
.c-tbl .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.c-tbl th.num { text-align: right; }
.c-tbl .hero-col { color: var(--primary-normal); font-weight: 700; }
/* 정렬 가능 헤더 — 기본은 흐린 ⇅, 활성은 방향 하나만 진하게 (Apify 패턴) */
.c-tbl th.sortable { cursor: pointer; user-select: none; transition: color var(--dur-1); }
.c-tbl th.sortable:hover { color: var(--g-label); }
.c-tbl th.sortable .sort-i { opacity: .35; margin-left: 3px; font-size: 11px; }
.c-tbl th.is-sorted { color: var(--g-label); font-weight: 600; }
.c-tbl th.is-sorted .sort-i { opacity: 1; color: var(--primary-normal); }
/* 아바타 + 이름 + 회색 서브텍스트 2줄 셀 */
.cell-id { display: flex; align-items: center; gap: 10px; min-width: 0; }
.cell-id-t { font-weight: 600; color: var(--g-label); line-height: 1.3; }
.cell-id-s { font-size: 12.5px; color: var(--g-label-alt); line-height: 1.35; }
/* ── 가로로 넘치는 표 (2026-08-03 사용자 질문에 대한 답) ──
   "표 오른쪽에 마진 없이 전체 너비로 두는 게 맞나, 스크롤을 다 하면 마진이 생기는 게 나은가?"
   결론 두 가지로 나눠 처리한다.
   ① 진짜 문제는 마진이 아니라 "더 있는지 모른다"는 것 → 양끝 그림자로 알린다.
      Lea Verou 의 background-attachment 기법: local 그라디언트(표면색)가 내용과 함께 밀려나며
      끝에 닿으면 scroll 그림자를 정확히 덮는다. JS·스크롤 이벤트가 필요 없다.
   ② 좁은 화면에서는 옆 마진이 보여줄 수 있는 열을 깎아먹기만 한다 → 표를 담은 카드를
      화면 끝까지 붙인다(full-bleed). 대신 표 안쪽 첫/마지막 셀 패딩은 그대로 두어
      글자가 화면 모서리에 붙지 않게 한다. */
.c-tbl-wrap {
  overflow-x: auto; overscroll-behavior-x: contain;
  background:
    linear-gradient(to right, var(--g-surface) 30%, transparent) left center / 36px 100% no-repeat local,
    linear-gradient(to left,  var(--g-surface) 30%, transparent) right center / 36px 100% no-repeat local,
    radial-gradient(farthest-side at 0% 50%, rgba(63,71,93,.22), transparent) left center / 13px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(63,71,93,.22), transparent) right center / 13px 100% no-repeat scroll;
}
@media (max-width: 640px) {
  .c-card:has(> .c-tbl-wrap), .c-card:has(> * > .c-tbl-wrap) {
    margin-inline: calc(-1 * var(--pad-x-sm));
    border-inline: 0; border-radius: 0;
  }
}

/* ── 진행 스텝 ── */
.step { display: flex; gap: 10px; align-items: flex-start; padding: 7px 0; font-size: 14px; color: var(--g-label); }
.step .step-m {
  width: 19px; height: 19px; border-radius: 50%; flex-shrink: 0; margin-top: 1px;
  display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700;
}
.step--done .step-m { background: var(--primary-normal); color: #fff; }
.step--now  .step-m { border: 2px solid var(--primary-normal); color: var(--primary-normal); }
.step--now  { font-weight: 600; }
.step--fail .step-m { background: color-mix(in srgb, var(--g-negative) 12%, transparent); color: var(--g-negative); }
.step--wait { color: var(--g-label-faint); }
.step--wait .step-m { border: 1.5px solid var(--g-line); color: var(--g-label-faint); }
.step small { display: block; font-size: 12px; font-weight: 400; color: var(--g-label-faint); }

/* ── 진행 표시 (2026-08-03: "실제로 뭔가 하고 있는 것처럼" 보이게) ──
   분석은 40~60분 걸린다. 그동안 화면이 정지해 있으면 멈춘 건지 도는 건지 알 수 없다.
   ①막대에 흐르는 빛 ②지금 단계 점의 파동 ③완료 체크의 등장 ④수집 숫자의 미세 맥박. */
.c-bar { height: 6px; border-radius: var(--r-2); background: var(--g-line-soft); overflow: hidden; position: relative; }
.c-bar > i {
  display: block; height: 100%; border-radius: var(--r-2);
  background: var(--primary-normal);
  transition: width .5s var(--ease-out);
  position: relative; overflow: hidden;
}
/* 진행 중인 막대 위로 빛이 한 번씩 지나간다 */
.c-bar > i::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  transform: translateX(-100%);
  animation: bar-sheen 1.9s ease-in-out infinite;
}
@keyframes bar-sheen { 0% { transform: translateX(-100%) } 60%, 100% { transform: translateX(100%) } }
/* 막대 끝단이 숨 쉰다 — 진행이 살아 있다는 신호 */
.c-bar--live > i { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary-normal) 60%, transparent); animation: bar-pulse 2.2s ease-in-out infinite; }
@keyframes bar-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--primary-normal) 45%, transparent) }
  50% { box-shadow: 0 0 0 4px color-mix(in srgb, var(--primary-normal) 0%, transparent) }
}

/* 지금 단계 — 마커가 파동을 내보낸다 */
.step--now .step-m { position: relative; }
.step--now .step-m::after {
  content: ""; position: absolute; inset: -3px; border-radius: 50%;
  border: 2px solid var(--primary-normal);
  animation: step-ping 1.8s cubic-bezier(0, 0, .2, 1) infinite;
}
@keyframes step-ping {
  0% { transform: scale(.85); opacity: .8 }
  75%, 100% { transform: scale(1.9); opacity: 0 }
}
/* 지금 단계 라벨이 아주 미세하게 밝아졌다 어두워진다 */
.step--now > div { animation: step-breathe 2.4s ease-in-out infinite; }
@keyframes step-breathe { 0%, 100% { opacity: 1 } 50% { opacity: .72 } }
/* 방금 끝난 단계의 체크는 톡 하고 나타난다 */
.step--done .step-m { animation: step-pop .38s var(--ease-out) both; }
@keyframes step-pop { 0% { transform: scale(.4); opacity: 0 } 60% { transform: scale(1.12) } 100% { transform: scale(1); opacity: 1 } }

/* 수집 중 카운트 — 숫자가 갱신될 때마다 살짝 튄다(턴 단위 폴링이라 값이 바뀌는 순간이 보인다) */
.live-n { display: inline-block; animation: rise-in .4s var(--ease-out) both; font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .c-bar > i::after, .c-bar--live > i, .step--now .step-m::after,
  .step--now > div, .step--done .step-m, .live-n { animation: none !important; }
}

/* 미터 (사이드바 RAM/Usage 같은 소형 게이지 — Apify 사이드바 푸터 패턴) */
.c-meter { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12px; }
.c-meter .k { color: var(--g-label-alt); }
.c-meter .v { color: var(--g-label); font-weight: 600; font-variant-numeric: tabular-nums; }
.c-meter .v small { color: var(--g-label-faint); font-weight: 500; }

/* ── 아바타(이니셜) ── */
.c-ava {
  display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0;
  border-radius: 50%; overflow: hidden; position: relative;
  background: var(--primary-background); color: var(--primary-foreground); font-weight: 700;
}

/* ── 사이드바 ──
   실측(§7): 항목 h28 · radius 6 · 13/20 w500 · 아이콘16 + gap 9.
   ★활성 상태를 브랜드색 블록으로 칠하지 않는다. Apify는 옅은 중립 회색만 쓴다 —
   사이드바가 데이터보다 튀면 안 되기 때문. contrace는 브랜드 정체성을 버리지 않되
   면(面)이 아니라 좌측 인디케이터 선(線)으로만 표현한다. */
.side-nav-i {
  position: relative;
  display: flex; align-items: center; gap: 9px;
  /* 메뉴는 "읽는 글"이 아니라 "누르는 것"이다 — 보조색으로 흐려 두면 안 된다 */
  min-height: 30px; font-size: 13px; font-weight: 500; color: var(--g-label);
  border-radius: var(--r-2); padding: 5px 9px;
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.side-nav-i:hover { background: var(--g-line-soft); color: var(--g-label); }
.side-nav-i.is-on { background: var(--g-line-soft); color: var(--g-label); font-weight: 600; }
.side-nav-i.is-on::before {
  content: ""; position: absolute; left: -2.5px; top: 50%; transform: translateY(-50%);
  width: 2.5px; height: 15px; border-radius: 0 2px 2px 0; background: var(--primary-normal);
}
.side-nav-i.is-on svg { color: var(--primary-normal); }
/* 사이드바 우측 개수 배지 — "지금 몇 개 담겨 있는지"를 메뉴에서 바로 알린다 */
.side-nav-i .side-n {
  margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-full); background: var(--primary-background); color: var(--primary-foreground);
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
}
.side-nav-i .side-star { width: 16px; text-align: center; font-size: 14px; line-height: 1; font-style: normal; color: var(--g-caution); }

.side-grp {
  font-size: 11.5px; font-weight: 700; letter-spacing: .06em;
  color: var(--g-label-faint); padding: 14px 9px 5px;
}

/* ── 페이지 헤더 밴드 ──
   실측: 콘텐츠가 회색 바닥 위에 떠 있는 카드 컬럼이 아니라, 흰 헤더 밴드(선으로 마감) →
   회색 본문 순으로 층이 나뉜다. 이 층 구조가 "앱"처럼 보이게 하는 가장 큰 요소다. */
.c-head {
  background: var(--g-surface); border-bottom: 1px solid var(--g-hairline);
  padding: 14px 0;   /* 좌우 패딩은 안쪽 max-w 래퍼가 갖는다 — 본문과 시작점을 맞추기 위해 */
}
/* ★sticky (2026-08-03 사용자 지시) — 목록을 한참 내려가도 페이지 제목과 주요 액션(새 분석)이
   손에 남아야 한다. 데스크탑에서만: 모바일은 이미 상단 앱바가 sticky라 두 겹이 되면 화면을 먹는다.
   스크롤로 내려가면 그림자를 얹어 본문과 층을 분리한다(스크롤 여부는 CSS만으로는 못 잡으므로
   scroll-timeline 대신 항상 옅은 선 + 반투명 배경으로 처리). */
@media (min-width: 768px) {
  .c-head {
    position: sticky; top: 0; z-index: var(--z-sticky);
    background: color-mix(in srgb, var(--g-surface) 88%, transparent);
    backdrop-filter: blur(12px) saturate(180%);
  }
}
/* 컬럼 폭 — 앱/마케팅/읽기 세 종류만 (--w-app / --w-mkt / --w-read) */
.c-col { width: 100%; margin-inline: auto; max-width: var(--w-app); padding-inline: var(--pad-x); }
.c-col--mkt { max-width: var(--w-mkt); }
.c-read { max-width: var(--w-read); }
@media (max-width: 640px) { .c-col { padding-inline: var(--pad-x-sm); } }
.c-head-row { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.c-head-t { font-size: 20px; font-weight: 700; letter-spacing: -.022em; color: var(--g-label); line-height: 1.25; }
.c-head-d { font-size: 13px; color: var(--g-label-alt); margin-top: 4px; line-height: 1.55; }
.c-head-m { font-size: 12px; color: var(--g-label-faint); margin-top: 4px; }
/* 상위로 돌아가기 — 제목 위 왼쪽. 화살표가 hover 때 살짝 왼쪽으로 밀려 방향을 감각으로 알린다 */
.c-back {
  display: inline-flex; align-items: center; gap: 3px; margin-bottom: 6px;
  font-size: 12px; font-weight: 600; color: var(--g-label-faint);
  transition: color var(--dur-1) var(--ease-out);
}
.c-back:hover { color: var(--g-label); }
.c-back svg { transition: transform var(--dur-1) var(--ease-out); }
.c-back:hover svg { transform: translateX(-2px); }
.c-head-acts { margin-left: auto; display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.c-head-tabs { display: flex; gap: 2px; margin-top: 12px; margin-bottom: -14px; }
.c-head-tabs .c-tab { border-radius: var(--r-2) var(--r-2) 0 0; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.c-head-tabs .c-tab.is-on { background: none; border-color: transparent; border-bottom-color: var(--primary-normal); color: var(--g-label); }
.c-head + * { padding-top: 32px; }   /* c-body 가 아닌 형제용 폴백 */
/* 좌우 여백은 .c-col 이 갖는다(둘 다 주면 두 배가 된다) — 여기선 위아래만 */
.c-body { padding-block: 32px 40px; }
/* ★모바일(<768px)에서는 제목·뒤로가기를 상단 앱바가 맡는다 (2026-08-03).
   둘 다 그리면 "분석 목록 / 제목"이 위아래로 두 번 나와 화면 위쪽을 통째로 낭비한다(실측).
   헤더 밴드에는 실행일 같은 메타와 액션 버튼만 남긴다. */
@media (max-width: 767px) {
  .c-head { padding: 8px 0; }
  .c-head .c-back, .c-head .c-head-t { display: none; }
  .c-head-row { align-items: center; gap: 8px; }
  .c-head-d, .c-head-m { margin-top: 0; }
  /* 제목이 빠져 헤더가 텅 비면 밴드 자체를 없앤다(메타·액션이 하나도 없을 때) */
  .c-head:not(:has(.c-head-d)):not(:has(.c-head-m)):not(:has(.c-head-acts > *)):not(:has(.c-head-tabs)) {
    display: none;
  }
}
@media (max-width: 640px) {
  .c-body { padding-block: 20px 28px; }
  .c-head-t { font-size: 16px; }
}

/* ── 상세 패널 섹션 계층 ── */
.panel-sec-t {
  display: flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 700; color: var(--g-label); letter-spacing: -.01em;
  margin: 26px 0 12px;
}
.panel-sec-t::before { content: ""; width: 3.5px; height: 15px; border-radius: 2px; background: var(--primary-normal); }
.panel-sec-t small { font-weight: 500; font-size: 12px; color: var(--g-label-faint); }
.panel-blk-t {
  font-size: 12.5px; font-weight: 700; color: var(--primary-foreground);
  letter-spacing: .01em; margin-bottom: 4px;
}
/* ── 라벨/값 정의 목록 (2026-08-03) ──
   "AI가 이해한 제품"의 가격대·누가 사나·언제 쓰나가 **라벨과 값이 같은 굵기로 세로로 쌓여**
   여섯 줄이 구분 없이 읽혔다(사용자 지적). 원인 두 겹:
     ① 임의값 유틸(`grid-cols-[auto_1fr]`)을 썼는데 **빌드에 그 클래스가 없어서**
        그리드가 아예 안 걸리고 dt/dd 가 블록으로 쌓였다.
     ② 걸렸어도 라벨과 값의 위계·정렬이 없었다.
   그래서 유틸 조합 대신 컴포넌트로 고정한다. 라벨은 왼쪽 고정폭 메타, 값은 읽는 문장,
   행 사이는 헤어라인으로 끊는다(카드 그림자 없음 · DS 규칙).
   ★색 규칙: 라벨은 메타라 faint 를 쓸 수 있지만 **값은 문장이라 alt 이상**이어야 한다. */
.c-deflist {
  display: grid; grid-template-columns: 96px minmax(0, 1fr);
  column-gap: 0; margin-top: 14px;   /* ★간격은 dt 의 padding-right 로 — gap 을 주면 구분선이 끊겨 보인다 */
}
.c-deflist > dt {
  font-size: 12px; font-weight: 600; color: var(--g-label-faint);
  padding: 8px 14px 8px 0; white-space: nowrap;
}
.c-deflist > dd {
  font-size: 13px; color: var(--g-label-alt); line-height: 1.6; padding: 8px 0;
}
.c-deflist > dt:not(:first-of-type),
.c-deflist > dt:not(:first-of-type) + dd { border-top: 1px solid var(--g-hairline); }
/* 좁은 화면에서는 라벨을 값 위로 올린다 — 82px 열이 값을 세로로 눌러 읽기 어려워진다 */
@media (max-width: 420px) {
  .c-deflist { grid-template-columns: minmax(0, 1fr); }
  .c-deflist > dt { padding: 8px 0 0; }
  .c-deflist > dd { padding: 2px 0 8px; }
  .c-deflist > dt:not(:first-of-type) + dd { border-top: 0; }
}

.panel-stat { border: 1px solid var(--g-hairline); border-radius: var(--r-3); padding: 9px 13px; }
.panel-stat .t { font-size: 11px; color: var(--g-label-alt); }
.panel-stat .v { font-size: 16px; font-weight: 700; font-variant-numeric: tabular-nums; }
.radar-legend { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 16px; flex: 1; min-width: 200px; }
.radar-legend .k { font-size: 12px; color: var(--g-label-alt); display: block; }
.radar-legend .v { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* ── 툴팁 (기존 시스템 유지, 색만 토큰화) ── */
#giirin-tip {
  position: fixed; z-index: var(--z-tip); max-width: 260px; pointer-events: none;
  opacity: 0; transition: opacity var(--dur-1); border-radius: var(--r-3);
  padding: 6px 10px; font-size: 12px; line-height: 1.4;
  box-shadow: var(--sh-pop);
  background: var(--inverse-background, #1B1C1E); color: var(--inverse-label, #F1F1F2);
}

/* 포커스 링 — 키보드 접근성 */
.c-btn:focus-visible, .side-nav-i:focus-visible, a:focus-visible,
.c-input:focus-visible, .c-menu-item:focus-visible, .c-tab:focus-visible {
  outline: 2px solid var(--primary-normal); outline-offset: 2px;
}

/* ══════════════════════════════════════════════════════════════════════════
   신설 컴포넌트 — Apify 콘솔 실측 기반 (docs/DS_MEASUREMENT_APIFY.md §7)
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 드롭다운 / 메뉴 ──
   실측: 목록형(listbox) radius 8 · 선택형(menu) radius 12 로 구분해 쓴다.
   항목 h28 · pad 6/8 · radius 8 · gap 8 · hover 는 브랜드색이 아니라 중립 회색. */
.c-menu {
  position: absolute; z-index: var(--z-pop); min-width: 160px;
  display: flex; flex-direction: column; padding: 4px;
  background: var(--g-elevated); border: 1px solid var(--g-hairline);
  border-radius: var(--r-4); box-shadow: var(--sh-pop);
  max-height: min(60vh, 420px); overflow-y: auto; overscroll-behavior: contain;
}
.c-menu--list { border-radius: var(--r-3); }         /* 목록형(다중선택 필터) */
.c-menu-label {
  font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--g-label-faint); padding: 8px 8px 4px;
}
.c-menu-item {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  min-height: 28px; padding: 6px 8px; border: 0; background: none; border-radius: var(--r-3);
  font-size: 13px; font-weight: 500; color: var(--g-label); cursor: pointer;
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.c-menu-item:hover { background: var(--g-line-soft); }
.c-menu-item.is-on { background: var(--primary-background); color: var(--primary-foreground); font-weight: 600; }
.c-menu-item[disabled] { opacity: .4; cursor: not-allowed; }
.c-menu-item .mi-pre { color: var(--g-label-faint); font-weight: 400; }  /* "이동" 같은 흐린 접두어 */
.c-menu-item .mi-end { margin-left: auto; display: flex; align-items: center; gap: 3px; }
.c-menu-item--danger { color: var(--g-negative); }
.c-menu-item--danger:hover { background: color-mix(in srgb, var(--g-negative) 8%, transparent); }
.c-menu-sep { height: 1px; margin: 4px -4px; background: var(--g-line-soft); }

/* ── 폼 ── */
.c-field { display: flex; flex-direction: column; gap: 6px; }
.c-label { font-size: 13px; font-weight: 600; color: var(--g-label); }
.c-label .req { color: var(--g-negative); margin-left: 2px; }
.c-help { font-size: 12px; color: var(--g-label-alt); line-height: 1.45; }
.c-err  { font-size: 12px; color: var(--g-negative); }
.c-input, .c-select, .c-textarea {
  width: 100%; font: inherit; font-size: 14px; color: var(--g-label);
  background: var(--g-surface); border: 1px solid var(--g-line);
  border-radius: var(--r-3); padding: 8px 11px;
  transition: border-color var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
.c-input--sm { font-size: 13px; padding: 6px 10px; border-radius: var(--r-2); }
.c-textarea { min-height: 88px; resize: vertical; line-height: 1.55; }
.c-input::placeholder, .c-textarea::placeholder { color: var(--g-label-faint); }
.c-input:hover, .c-select:hover, .c-textarea:hover { border-color: var(--g-label-faint); }
.c-input:focus, .c-select:focus, .c-textarea:focus {
  outline: none; border-color: var(--primary-normal);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-normal) 16%, transparent);
}
.c-input[aria-invalid="true"], .c-input.is-err { border-color: var(--g-negative); }
.c-input:disabled, .c-select:disabled, .c-textarea:disabled { opacity: .55; cursor: not-allowed; background: var(--g-line-soft); }
.c-select { appearance: none; padding-right: 30px; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 13px center, right 8px center; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
/* 앞에 아이콘이 들어가는 검색 인풋 */
.c-input-icon { position: relative; display: flex; align-items: center; }
.c-input-icon > .ii { position: absolute; left: 10px; color: var(--g-label-faint); font-size: 13px; pointer-events: none; }
.c-input-icon > .c-input { padding-left: 30px; }

/* 체크박스·라디오 — 실측 16x16 · radius 4 · border 1px · transition .12s ease-out */
.c-check, .c-radio {
  appearance: none; width: 16px; height: 16px; flex-shrink: 0; margin: 0; cursor: pointer;
  border: 1px solid var(--g-line); background: var(--g-surface); border-radius: var(--r-1);
  display: inline-grid; place-content: center;
  transition: background var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.c-radio { border-radius: 50%; }
.c-check:checked, .c-radio:checked { background: var(--primary-normal); border-color: var(--primary-normal); }
.c-check:checked::after { content: ""; width: 9px; height: 5px; border: 2px solid #fff; border-top: 0; border-right: 0;
  transform: rotate(-45deg) translate(1px,-1px); }
.c-radio:checked::after { content: ""; width: 6px; height: 6px; border-radius: 50%; background: #fff; }
:root[data-theme="dark"] .c-check:checked::after { border-color: rgb(23,23,25); }
:root[data-theme="dark"] .c-radio:checked::after { background: rgb(23,23,25); }
.c-check:disabled, .c-radio:disabled { opacity: .45; cursor: not-allowed; }
.c-check-row { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--g-label); cursor: pointer;
  padding: 6px 8px; border-radius: var(--r-3); transition: background var(--dur-1); }
.c-check-row:hover { background: var(--g-line-soft); }

/* 스위치 */
.c-switch { appearance: none; width: 34px; height: 20px; border-radius: var(--r-full); background: var(--g-line);
  position: relative; cursor: pointer; transition: background var(--dur-1) var(--ease-out); flex-shrink: 0; }
.c-switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%;
  background: #fff; transition: transform var(--dur-1) var(--ease-out); }
.c-switch:checked { background: var(--primary-normal); }
.c-switch:checked::after { transform: translateX(14px); }

/* 파일 첨부 입력 (인테이크: 기획서·제품 소개서)
   ★네이티브 인풋은 버튼 글자를 브라우저가 정한다("Choose Files" / "파일 선택" — OS 언어에 좌우).
   한국어 상용 화면에 영어가 새는 걸 막으려면 인풋을 감추고 label 을 버튼으로 쓰는 수밖에 없다. */
.c-filepick { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.c-file-input { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.c-filepick label { cursor: pointer; }
/* 키보드 포커스가 감춰진 인풋에 갔을 때 라벨에 링을 보여준다(안 그러면 포커스가 사라진 것처럼 보인다) */
.c-file-input:focus-visible + label { outline: 2px solid var(--primary-normal); outline-offset: 2px; }
.c-file-name { font-size: 13px; color: var(--g-label-alt); min-width: 0; word-break: break-all; }

/* ── 모달 (중앙) ── 실측: 상단 정렬 · 백드롭은 어둡게가 아니라 살짝 흐리게 */
.c-backdrop {
  position: fixed; inset: 0; z-index: var(--z-backdrop);
  background: rgba(23,23,25,.28); backdrop-filter: blur(2px);
  animation: fade-in var(--dur-2) var(--ease-out);
}
.c-modal {
  position: fixed; z-index: var(--z-modal); left: 50%; top: 6vh; transform: translateX(-50%);
  width: min(560px, calc(100vw - 32px)); max-height: 84vh; display: flex; flex-direction: column;
  background: var(--g-elevated); border: 1px solid var(--g-hairline);
  border-radius: var(--r-5); box-shadow: var(--sh-modal); overflow: hidden;
  animation: modal-in var(--dur-2) var(--ease-out);
}
.c-modal--wide { width: min(880px, calc(100vw - 32px)); }
/* 목록 하단의 "전체보기 →" — 버튼이지만 링크처럼 보이게 해서 스크롤 흐름을 끊지 않는다 */
.c-more {
  display: flex; align-items: center; justify-content: center; gap: 5px; width: 100%;
  padding: 11px 12px; border: 0; border-top: 1px solid var(--g-line-soft); background: none;
  font-size: 13px; font-weight: 600; color: var(--primary-normal); cursor: pointer;
  transition: background var(--dur-1) var(--ease-out);
}
.c-more:hover { background: var(--g-line-soft); }
.c-more .n { color: var(--g-label-faint); font-weight: 500; }
.c-modal-head { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--g-line-soft); }
.c-modal-t { font-size: 16px; font-weight: 700; color: var(--g-label); }
.c-modal-x { margin-left: auto; border: 0; background: none; cursor: pointer; color: var(--g-label-faint);
  width: 28px; height: 28px; border-radius: var(--r-2); transition: background var(--dur-1), color var(--dur-1); }
.c-modal-x:hover { background: var(--g-line-soft); color: var(--g-label); }
.c-modal-body { padding: 16px; overflow-y: auto; overscroll-behavior: contain; }
.c-modal-foot { display: flex; gap: 8px; justify-content: flex-end; padding: 12px 16px; border-top: 1px solid var(--g-line-soft); }
@keyframes fade-in { from { opacity: 0 } to { opacity: 1 } }
@keyframes modal-in { from { opacity: 0; transform: translateX(-50%) translateY(-8px) } to { opacity: 1; transform: translateX(-50%) translateY(0) } }

/* ── 토스트 ── */
.c-toast-wrap { position: fixed; z-index: var(--z-toast); right: 16px; bottom: 16px;
  display: flex; flex-direction: column; gap: 8px; pointer-events: none; max-width: min(380px, calc(100vw - 32px)); }
.c-toast {
  pointer-events: auto; display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 13px; border-radius: var(--r-3);
  background: var(--g-elevated); border: 1px solid var(--g-hairline); box-shadow: var(--sh-toast);
  font-size: 13px; color: var(--g-label); animation: toast-in var(--dur-3) var(--ease-out);
}
.c-toast .t-i { flex-shrink: 0; margin-top: 1px; }
.c-toast--ok  .t-i { color: var(--g-positive); }
.c-toast--bad .t-i { color: var(--g-negative); }
.c-toast--warn .t-i { color: var(--g-caution); }
.c-toast-x { margin-left: auto; border: 0; background: none; color: var(--g-label-faint); cursor: pointer; padding: 0 2px; }
.c-toast.is-out { animation: toast-out var(--dur-2) var(--ease-io) forwards; }
@keyframes toast-in { from { opacity: 0; transform: translateY(8px) } to { opacity: 1; transform: translateY(0) } }
@keyframes toast-out { to { opacity: 0; transform: translateY(6px) } }

/* ── 탭 (pill 형) ── 실측: 활성만 흰 배경 + 테두리, 비활성은 완전 평면 */
.c-tabs { display: flex; align-items: center; gap: 4px; }
.c-tab {
  display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px;
  border: 1px solid transparent; border-radius: var(--r-3); background: none;
  font-size: 13px; font-weight: 600; color: var(--g-label-alt); cursor: pointer; white-space: nowrap;
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out), border-color var(--dur-1);
}
.c-tab:hover { background: var(--g-line-soft); color: var(--g-label); }
.c-tab.is-on { background: var(--g-surface); border-color: var(--g-hairline); color: var(--g-label); font-weight: 600; }
.c-tab .t-n { font-size: 11px; color: var(--g-label-faint); font-variant-numeric: tabular-nums; }
/* 밑줄형 탭 (상세 페이지 섹션 전환용) */
.c-tabs--line { gap: 0; border-bottom: 1px solid var(--g-hairline); }
.c-tabs--line .c-tab { border-radius: 0; border: 0; border-bottom: 2px solid transparent; padding: 9px 14px; }
.c-tabs--line .c-tab.is-on { background: none; border-bottom-color: var(--primary-normal); color: var(--primary-normal); }

/* ── 세그먼티드 컨트롤 ── */
.c-seg { display: inline-flex; padding: 2px; gap: 2px; background: var(--g-line-soft); border-radius: var(--r-3); }
/* a 도 받는다 — 서버 왕복으로 거르는 화면(디렉터리)은 링크가 맞다(뒤로가기·북마크가 산다) */
.c-seg > button, .c-seg > a {
  display: inline-flex; align-items: center; justify-content: center; white-space: nowrap;
  border: 0; background: none; cursor: pointer; padding: 5px 11px; border-radius: var(--r-2);
  font-size: 12.5px; font-weight: 600; color: var(--g-label-alt); transition: background var(--dur-1), color var(--dur-1);
}
.c-seg > button:hover, .c-seg > a:hover { color: var(--g-label); }
.c-seg > a.is-on { background: var(--g-surface); color: var(--g-label); box-shadow: 0 1px 2px rgba(63,71,93,.12); }
.c-seg > button.is-on { background: var(--g-surface); color: var(--g-label); box-shadow: 0 1px 2px rgba(63,71,93,.12); }
/* 세그먼트 옆 건수 — 누르기 전에 결과 개수를 알 수 있어야 헛클릭이 없다 */
.c-seg .seg-n { margin-left: 5px; font-weight: 600; color: var(--g-label-faint); font-variant-numeric: tabular-nums; }
.c-seg > button.is-on .seg-n { color: var(--primary-normal); }

/* 폼 안의 세그먼트 — label 로 감싼 라디오. 값이 폼과 함께 전송돼야 하는 곳(분석 규모)에 쓴다.
   버튼형과 생김새를 맞추되 상태는 :has(input:checked) 로 잡는다(JS 없이 동작). */
.c-seg > label {
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  white-space: nowrap; cursor: pointer; padding: 5px 13px; border-radius: var(--r-2);
  font-size: 12.5px; font-weight: 600; color: var(--g-label-alt);
  transition: background var(--dur-1), color var(--dur-1);
}
.c-seg > label:hover { color: var(--g-label); }
.c-seg > label:has(input:checked) {
  background: var(--g-surface); color: var(--g-label); box-shadow: 0 1px 2px rgba(63,71,93,.12);
}
.c-seg > label > input { position: absolute; opacity: 0; pointer-events: none; }
/* 옵션 아래 보조 문구(「최대 15명」) — 「분석 규모」 라벨과 같은 서식으로 맞췄다(2026-08-13).
   예전 11px/500/faint 는 한 톤 더 흐려서 옵션의 조건이 안 읽혔다. */
.c-seg > label .seg-sub { font-size: 12px; font-weight: 600; color: var(--g-label-alt); margin-top: 1px; }
/* 미선택 상태로 제출했을 때 — `.c-input.is-err` 는 border-color 를 쓰지만 `.c-seg` 는 테두리가
   없는 채움 트랙이다. 그래서 같은 negative 색을 1px 링으로 준다. */
.c-seg.is-err { box-shadow: inset 0 0 0 1px var(--g-negative); }
@media (max-width: 640px) {
  .c-seg { width: 100%; }
  .c-seg > button { flex: 1; padding-inline: 6px; }
  /* ★라디오형 label 도 폭을 나눠 갖게 — 이게 없으면 여러 줄 문구가 카드를 삐져나간다 */
  .c-seg > label { flex: 1; min-width: 0; }
}

/* ── 분석 규모 줄 (새 분석 화면) ──────────────────────────────────────────────
   「분석 규모 · 토글 · 취소/시작 · 소요시간 안내 · 각주」를 한 묶음으로 앉힌다.
   넓은 화면에서는 2열 그리드(라벨 | 나머지)라 **안내 문구가 토글 열에 정렬된다**.
   라벨 폭을 px 로 박지 않으므로 폰트가 대체돼도 어긋나지 않는다.
   좁은 화면에서는 그리드를 끄고 위에서 아래로 흐른다(라벨 → 토글 → 버튼 → 문구). */
.scale-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.scale-row > .scale-main { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; width: 100%; }
@media (min-width: 641px) {
  .scale-row { display: grid; grid-template-columns: auto 1fr; column-gap: 14px; row-gap: 8px; }
  .scale-row > .scale-lbl   { align-self: center; }
  .scale-row > .scale-main  { flex-wrap: nowrap; width: auto; }
  .scale-row > .scale-notes { grid-column: 2; }
}
/* 안내 3줄은 토글보다 8px 안쪽에서 시작한다 — 토글에 딸린 값이라는 게 위치로 보인다 */
.scale-notes { padding-left: 8px; }
.scale-note { font-size: 12px; font-weight: 600; color: var(--g-label-alt); line-height: 1.55; }
/* 머리줄(「분석 규모 표준」) — `.panel-blk-t` 와 같은 결: 작고 굵은 브랜드색 소제목.
   색은 `--primary-foreground`(글자용 브랜드색 토큰) 다. `--primary-normal` 은 버튼 배경용이라
   12px 글자로 쓰면 흰 배경 대비가 4.35:1 로 모자란다(foreground 는 4.98:1). */
.scale-head { font-size: 12.5px; font-weight: 700; color: var(--primary-foreground); letter-spacing: .01em; }
/* 항목명(콘텐츠 분석·판매수치 분석)은 700 — `.scale-note` 기본값이 600 이라 600 으로 두면
   "값만 얇아진" 것이 되고 항목명은 전혀 굵어 보이지 않는다(2026-08-13 실측 지적). */
.scale-k { font-weight: 700; }
.scale-v { font-weight: 500; }   /* 값(30분 이상 …) — 12px 의 디자인시스템 굵기 */
/* 각주 두 줄 — `*` 로 시작한다. 줄이 넘칠 때 둘째 줄이 `*` 아래로 들어가지 않게 내어쓰기. */
.scale-foot { margin-top: 14px; }
.scale-foot .scale-note { font-weight: 400; padding-left: 10px; text-indent: -10px; }
.scale-foot .scale-note + .scale-note { margin-top: 2px; }

/* ── 아코디언 ── */
.c-acc { border: 1px solid var(--g-hairline); border-radius: var(--r-4); overflow: hidden; background: var(--g-surface); }
.c-acc + .c-acc { margin-top: 8px; }
.c-acc > summary {
  display: flex; align-items: center; gap: 10px; cursor: pointer; list-style: none;
  padding: 12px 14px; font-size: 14px; font-weight: 600; color: var(--g-label);
  transition: background var(--dur-1) var(--ease-out);
}
.c-acc > summary::-webkit-details-marker { display: none; }
.c-acc > summary:hover { background: var(--g-line-soft); }
.c-acc > summary::after {
  content: "⌄"; margin-left: auto; color: var(--g-label-faint); font-size: 14px; line-height: 1;
  transition: transform var(--dur-2) var(--ease-out);
}
.c-acc[open] > summary::after { transform: rotate(180deg); }
.c-acc[open] > summary { border-bottom: 1px solid var(--g-line-soft); }
.c-acc-body { padding: 14px; font-size: 13px; color: var(--g-label); line-height: 1.7; }

/* ── 필터 바 ── 실측: [검색][필터▾][필터▾] ... [결과 n건] */
.c-filterbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.c-filterbar .fb-count { margin-left: auto; font-size: 13px; font-weight: 600; color: var(--g-label-alt); white-space: nowrap; }
.c-filter-btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px;
  border: 1px solid var(--g-line); border-radius: var(--r-3); background: var(--g-surface);
  font-size: 13px; font-weight: 600; color: var(--g-label); cursor: pointer; white-space: nowrap;
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1), border-color var(--dur-1);
}
.c-filter-btn:hover { background: var(--g-line-soft); color: var(--g-label); }
.c-filter-btn.is-on { border-color: var(--primary-normal); color: var(--primary-foreground); background: var(--primary-background); font-weight: 600; }
.c-filter-btn .fb-n { display: inline-flex; align-items: center; justify-content: center; min-width: 16px; height: 16px;
  padding: 0 4px; border-radius: var(--r-full); background: var(--primary-normal); color: #fff; font-size: 11px; font-weight: 700; }
:root[data-theme="dark"] .c-filter-btn .fb-n { color: rgb(23,23,25); }

/* ── 페이지네이션 ── 실측: 좌측 per-page · 우측 이동 */
.c-pager { display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-top: 1px solid var(--g-line-soft); font-size: 13px; color: var(--g-label); flex-wrap: wrap; }
.c-pager .pg-right { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.c-pager .pg-b {
  min-width: 28px; height: 28px; padding: 0 8px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: var(--r-2); background: none; cursor: pointer;
  font-size: 13px; color: var(--g-label-alt); font-variant-numeric: tabular-nums;
  transition: background var(--dur-1), color var(--dur-1), border-color var(--dur-1);
}
.c-pager .pg-b:hover:not(:disabled) { background: var(--g-line-soft); color: var(--g-label); }
.c-pager .pg-b.is-on { border-color: var(--g-line); background: var(--g-surface); color: var(--g-label); font-weight: 600; }
.c-pager .pg-b:disabled { opacity: .35; cursor: not-allowed; }

/* ── 누를 수 있는 카드 행 (.link-row) ──
   ★2026-08-03: 이런 행마다 "그 분석에서 보기 →" 같은 버튼을 달아 뒀는데 무슨 말인지 안 읽혔다.
   표에 세운 규약과 같이 간다: **행 전체가 눌리고, 끝에는 chevron 만.**
   문구를 고민할 일이 없어지고, 표·카드·목록의 조작법이 하나로 통일된다. */
.link-row {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  border: 1px solid var(--g-hairline); border-radius: var(--r-3);
  background: var(--g-ground); padding: 13px 14px; cursor: pointer;
  transition: border-color var(--dur-1) var(--ease-out), background var(--dur-1), transform var(--dur-1);
}
.link-row:hover { border-color: var(--g-line); background: var(--g-surface); }
.link-row:hover .cell-go { color: var(--primary-normal); }
.link-row:hover .cell-go svg { transform: translateX(2px); }
.link-row > .cell-go { flex-shrink: 0; }

/* ── 숫자형 페이지네이션 (2026-08-03) ──
   "← 이전  1 / 6  다음 →" 은 총 몇 장인지, 3장으로 바로 가는 법이 없었다. 숫자를 직접 누른다. */
.c-pages { display: flex; align-items: center; justify-content: center; gap: 4px; flex-wrap: wrap; }
.c-pages .pg-b {
  min-width: 34px; height: 34px; padding: 0 10px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid transparent; border-radius: var(--r-2);
  font-size: 13px; font-weight: 600; color: var(--g-label); font-variant-numeric: tabular-nums;
  transition: background var(--dur-1) var(--ease-out), border-color var(--dur-1), color var(--dur-1);
}
.c-pages a.pg-b:hover { background: var(--g-line-soft); border-color: var(--g-line); }
.c-pages .pg-b.is-on {
  background: var(--primary-normal); border-color: var(--primary-normal); color: #fff;
}
:root[data-theme="dark"] .c-pages .pg-b.is-on { color: rgb(23,23,25); }
.c-pages .pg-arrow { color: var(--g-label-alt); }
.c-pages .pg-arrow.is-off { opacity: .3; pointer-events: none; }
.c-pages .pg-gap { padding: 0 2px; color: var(--g-label-faint); font-size: 13px; }

/* ── 빈 상태 ──
   실측(Runs 페이지): "없음"으로 끝내지 않고 다음 행동 카드를 제시한다. */
.c-empty { display: flex; flex-direction: column; align-items: center; text-align: center; padding: 56px 20px; }
.c-empty-t { font-size: 20px; font-weight: 700; letter-spacing: -.02em; color: var(--g-label); }
.c-empty-d { margin-top: 10px; max-width: 560px; font-size: 14px; line-height: 1.7; color: var(--g-label-alt); }
.c-empty-acts { display: flex; gap: 16px; margin-top: 28px; flex-wrap: wrap; justify-content: center; }
.c-empty-card {
  width: 260px; padding: 24px 20px; text-align: center;
  border: 1px solid var(--g-hairline); border-radius: var(--r-4); background: var(--g-surface);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  transition: border-color var(--dur-1) var(--ease-out);
}
.c-empty-card:hover { border-color: var(--g-line); }
.c-empty-card .ec-ico { width: 56px; height: 56px; display: grid; place-content: center; margin-bottom: 6px;
  border-radius: var(--r-4); background: var(--g-line-soft); font-size: 24px; }
.c-empty-card .ec-t { font-size: 14px; font-weight: 700; color: var(--g-label); }
.c-empty-card .ec-d { font-size: 13px; line-height: 1.6; color: var(--g-label-alt); }
.c-empty-card .c-btn { margin-top: 8px; }
/* 표 안의 작은 빈 상태 */
.c-empty--inline { padding: 32px 16px; }
.c-empty--inline .c-empty-t { font-size: 14px; }
.c-empty--inline .c-empty-d { font-size: 13px; }

/* ── 등장 애니메이션 (reveal_controller.js) ──
   스크롤로 들어오면 8px 아래에서 올라오며 나타난다. 딱 한 겹만 — 회전·확대는 쓰지 않는다.
   데이터 화면에서 요소가 튀면 "읽는 흐름"이 끊긴다. 지연은 --rv-d 로 목록에 계단을 준다. */
.rv { opacity: 0; transform: translateY(8px);
  transition: opacity .5s var(--ease-out) var(--rv-d, 0s), transform .5s var(--ease-out) var(--rv-d, 0s); }
.rv-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .rv { opacity: 1; transform: none; transition: none; } }

/* 숫자·강조 카운트업 대신 쓰는 은은한 상승 강조 (KPI 진입) */
@keyframes rise-in { from { opacity: 0; transform: translateY(6px) } to { opacity: 1; transform: none } }

/* ══════════════════════════════════════════════════════════════════════════
   기하학적 배경 — 앱 화면용 (2026-08-03 사용자 지시: 랜딩만이 아니라 대시보드·여러
   페이지·컴포넌트에도 적절한 곳에 배치). 랜딩용(.ld-bg-*)과 무늬는 같은 계열이되
   **훨씬 옅다** — 데이터 화면에서 배경이 눈에 띄면 숫자를 읽는 데 방해가 된다.
   규칙: ①본문 뒤에만 ②알파 ≤ .06 ③transform/opacity 만 애니메이션 ④reduced-motion 정지
   ══════════════════════════════════════════════════════════════════════════ */
.g-bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.g-bg + * { position: relative; z-index: 1; }

/* 헤더 밴드용 — 아주 옅은 격자가 오른쪽 위로 천천히 흐른다 */
.g-bg-grid {
  position: absolute; inset: 0;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--g-label) 4%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--g-label) 4%, transparent) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: linear-gradient(100deg, #000 0%, transparent 62%);
  animation: g-drift 50s linear infinite;
}
@keyframes g-drift { to { background-position: 44px 44px; } }

/* 빈 상태·CTA 용 — 옅은 광원 하나 */
.g-bg-glow {
  position: absolute; width: 460px; height: 460px; border-radius: 50%;
  top: -55%; left: 50%; filter: blur(70px); opacity: .5;
  background: radial-gradient(circle, color-mix(in srgb, var(--primary-normal) 16%, transparent), transparent 70%);
  animation: g-float 26s ease-in-out infinite alternate;
}
@keyframes g-float { from { transform: translate(-56%, 0) } to { transform: translate(-44%, 5%) } }

@media (prefers-reduced-motion: reduce) { .g-bg-grid, .g-bg-glow { animation: none !important; } }

/* 페이지 헤더 밴드에 기본 적용 — 층 구조를 유지하면서 표면에 결을 준다 */
.c-head { position: relative; overflow: hidden; }
.c-head > * { position: relative; z-index: 1; }
.c-head::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, color-mix(in srgb, var(--g-label) 4%, transparent) 1px, transparent 1px),
    linear-gradient(to bottom, color-mix(in srgb, var(--g-label) 4%, transparent) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: linear-gradient(100deg, transparent 30%, #000 100%);
  animation: g-drift 50s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .c-head::before { animation: none; } }

/* 빈 상태 — 다음 행동을 권하는 자리라 조금 더 살아 있어도 된다 */
.c-empty { position: relative; overflow: hidden; }
.c-empty > * { position: relative; z-index: 1; }
.c-empty::before {
  content: ""; position: absolute; z-index: 0; pointer-events: none;
  width: 420px; height: 420px; border-radius: 50%; top: -60%; left: 50%;
  filter: blur(70px);
  background: radial-gradient(circle, color-mix(in srgb, var(--primary-normal) 14%, transparent), transparent 70%);
  animation: g-float 26s ease-in-out infinite alternate;
}
@media (prefers-reduced-motion: reduce) { .c-empty::before { animation: none; transform: translateX(-50%); } }

/* ── 카드 호버 미세 반응 ── 데이터 화면에서 "누를 수 있다"를 색이 아니라 깊이로 알린다 */
.c-card--hover:hover, .c-tbl tbody tr.is-link:hover { transition: all var(--dur-1) var(--ease-out); }
.pitch-idea.is-link { transition: border-color var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out); }
.pitch-idea.is-link:hover { border-color: var(--g-line); transform: translateY(-1px); }

/* KPI 스트립 — 값이 바뀔 때가 아니라 화면에 들어올 때 한 번만 올라온다 */
.kpi-v { animation: rise-in .45s var(--ease-out) both; }
@media (prefers-reduced-motion: reduce) { .kpi-v { animation: none; } }

/* ── 스켈레톤 (로딩) ── */
.c-skel { background: var(--g-line-soft); border-radius: var(--r-2); position: relative; overflow: hidden; }
.c-skel::after {
  content: ""; position: absolute; inset: 0; transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--g-surface) 60%, transparent), transparent);
  animation: skel 1.3s infinite;
}
@keyframes skel { to { transform: translateX(100%) } }
.c-skel--line { height: 12px; }
.c-skel--title { height: 18px; width: 40%; }

/* ══════════════════════════════════════════════════════════════════════════
   동결 컴포넌트 — 구조·형태 변경 금지 (UI_UX_MASTER_SPEC §2.5).
   색·반경·모션 토큰만 갈아끼운다.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 온톨로지 그래프 (좌측 상세 패널 + 범례) ──
   ★배경 (2026-08-03): 예전엔 --g-ground 라 랜딩·대시보드 바닥과 같은 색이었다 —
   "그래프가 배경이랑 구분이 안 된다"는 지적. 표면색 위에 미세 격자 + 중앙 광원을 깔아
   "지도가 놓인 판"으로 읽히게 한다. 격자는 캔버스가 아니라 CSS라 그리기 비용이 0이다. */
.og-wrap {
  position: relative; border-radius: var(--r-4); overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in srgb, var(--primary-normal) 5%, transparent), transparent 62%),
    linear-gradient(to right, var(--g-line-soft) 1px, transparent 1px) 0 0 / 40px 40px,
    linear-gradient(to bottom, var(--g-line-soft) 1px, transparent 1px) 0 0 / 40px 40px,
    var(--g-surface);
  border: 1px solid var(--g-hairline);
}
/* 랜딩용 — 조작 없는 배경 애니메이션. 커서·조작 힌트를 일절 주지 않는다. */
.og-wrap--ambient { cursor: default; }
.og-wrap--ambient canvas { pointer-events: none; }

/* 지도 조작 버튼 (우상단) */
.og-ctl {
  position: absolute; top: 10px; right: 10px; z-index: 4;
  display: flex; flex-direction: column; gap: 4px;
}
.og-ctl button {
  width: 28px; height: 28px; display: grid; place-items: center; cursor: pointer;
  border: 1px solid var(--g-hairline); border-radius: var(--r-2);
  background: color-mix(in srgb, var(--g-surface) 92%, transparent);
  backdrop-filter: blur(6px);
  color: var(--g-label-alt); font-size: 14px; font-weight: 600; line-height: 1;
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1), border-color var(--dur-1);
}
.og-ctl button:hover { background: var(--g-surface); color: var(--g-label); border-color: var(--g-line); }

/* ── 패널 안 겹침 층위 (2026-08-03 정리) ──
   .ms-head(sticky 헤더) 12  >  그래프/차트 툴팁 6  >  본문 0
   툴팁이 헤더보다 위면 채널 이름 위로 올라타서 "무엇을 보고 있는지"를 가린다. */
.chart-tip {
  position: absolute; z-index: 6; width: 210px; left: 0; top: 0;
  border-radius: var(--r-4); padding: 10px 12px;
  background: var(--g-elevated); color: var(--g-label);
  border: 1px solid var(--g-hairline); box-shadow: var(--sh-pop);
  opacity: 0; transition: opacity var(--dur-1) var(--ease-out); pointer-events: none;
  font-size: 12px;
}

/* 호버 툴팁 — 인라인 스타일로 흩어져 있던 것을 컴포넌트로 회수 */
.og-tip {
  position: absolute; z-index: 6; width: 240px; pointer-events: none;
  font-size: 12px; line-height: 1.55; border-radius: var(--r-4); padding: 10px 12px;
  background: var(--g-elevated); color: var(--g-label);
  border: 1px solid var(--g-hairline); box-shadow: var(--sh-pop);
  opacity: 0; transition: opacity var(--dur-1) var(--ease-out);
}
.og-panel {
  position: absolute; inset: 0 auto 0 0; width: min(300px, 82%); z-index: 5;
  background: color-mix(in srgb, var(--g-surface) 92%, transparent);
  backdrop-filter: blur(6px);
  border-right: 1px solid var(--g-hairline);
  transform: translateX(-102%); transition: transform var(--dur-3) var(--ease-out);
  overflow-y: auto; padding: 14px; font-size: 13px;
}
.og-panel--on { transform: translateX(0); }
.og-panel-head { display: flex; align-items: center; gap: 10px; }
.og-ava { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.og-ava--init { display: inline-flex; align-items: center; justify-content: center; font-weight: 700; font-size: 16px; }
.og-panel-name { font-weight: 700; font-size: 14px; color: var(--g-label); line-height: 1.25; }
.og-panel-sub { font-size: 12px; color: var(--g-label-alt); margin-top: 2px; }
.og-x { margin-left: auto; border: 0; background: none; color: var(--g-label-faint); cursor: pointer; font-size: 13px; padding: 4px; }
.og-x:hover { color: var(--g-label); }
.og-facts { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 10px; }
.og-facts span { font-size: 12px; font-weight: 600; padding: 3px 9px; border-radius: var(--r-2); background: var(--g-line-soft); color: var(--g-label); }
.og-sum { margin-top: 10px; color: var(--g-label); line-height: 1.55; }
.og-quote { margin-top: 8px; padding-left: 9px; border-left: 3px solid var(--primary-normal); color: var(--g-label-alt); line-height: 1.5; }
.og-open { display: block; width: 100%; margin-top: 12px; padding: 8px 0; border: 0; border-radius: var(--r-3);
  background: var(--primary-normal); color: #fff; font-weight: 600; font-size: 12px; cursor: pointer; }
:root[data-theme="dark"] .og-open { color: rgb(23,23,25); }
.og-link { display: inline-block; margin-top: 8px; font-size: 12px; font-weight: 600; color: var(--primary-normal); }
.og-grp { font-size: 11px; font-weight: 700; letter-spacing: .05em; color: var(--g-label-faint); margin: 14px 0 4px; text-transform: uppercase; }
.og-row { display: flex; align-items: center; gap: 7px; width: 100%; text-align: left; border: 0; background: none;
  padding: 6px 8px; border-radius: var(--r-2); font-size: 12.5px; color: var(--g-label); cursor: pointer; }
.og-row:hover { background: var(--g-line-soft); }
.og-row--hl { background: color-mix(in srgb, var(--primary-normal) 12%, transparent); }
.og-row .og-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.og-row-d { margin-left: auto; font-size: 11px; color: var(--g-label-faint); white-space: nowrap; }
.og-legend {
  position: absolute; right: 12px; bottom: 10px; z-index: 3; pointer-events: none;
  display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px 12px;
  max-width: min(520px, 70%);
  font-size: 12px; font-weight: 500; color: var(--g-label-alt);
}
.og-legend span { display: inline-flex; align-items: center; white-space: nowrap; }
.og-legend i { width: 7px; height: 7px; border-radius: 50%; display: inline-block; margin-right: 4px; }

/* ── 모달 스택 (우측 슬라이드 — UI_UX_MASTER_SPEC §1 모달 스택 규칙) ── */
.ms-backdrop {
  position: fixed; inset: 0; z-index: var(--z-backdrop);
  background: rgba(23,23,25,.42); backdrop-filter: blur(2px);
  opacity: 0; transition: opacity var(--dur-2) var(--ease-out);
}
.ms-backdrop.is-in { opacity: 1; }
.ms-panel {
  position: fixed; top: 0; bottom: 0; right: 0; width: min(1080px, 94vw);
  background: var(--g-surface); border-left: 1px solid var(--g-line);
  box-shadow: var(--sh-modal);
  transform: translateX(100%);
  transition: transform var(--dur-3) var(--ease-out), filter var(--dur-2);
  overflow-y: auto; overscroll-behavior: contain;
}
/* 프레임 로딩 자리표시 — "불러오는 중…" 텍스트보다 실제 레이아웃을 예고하는 편이 덜 튄다 */
.ms-loading { display: flex; flex-direction: column; gap: 10px; padding: 22px 20px; }
/* ★모바일에서는 화면을 통째로 넘겨받는다 (2026-08-03).
   94vw 로 두면 왼쪽에 6vw 짜리 띠로 뒤 페이지와 상단바가 비쳐서, 모달이 "덮은" 건지
   "옆에 뜬" 건지 모호해진다. 좁은 화면에서 6vw 는 되돌아갈 단서로도 너무 좁다.
   대신 헤더에 닫기(✕)가 sticky 로 항상 있고, 백드롭·ESC·뒤로가기 모두 살아 있다. */
@media (max-width: 640px) {
  .ms-panel { width: 100vw; border-left: 0; }
  /* 모달이 열려 있는 동안 모바일 앱바를 감춘다 — 100vw 라 어차피 가려지지만
     backdrop-filter 를 가진 sticky 요소가 밑에 남아 있으면 스크롤 성능이 떨어진다 */
  .has-modal .app-bar { display: none; }
}
/* 목록 전체보기 패널 — 표가 넓어 기본 1080px 로는 가로 스크롤이 생긴다 (2026-08-02) */
.ms-panel--list { width: min(1440px, 96vw); transition: transform var(--dur-3) var(--ease-out), filter var(--dur-2), width var(--dur-3) var(--ease-out); }
@media (max-width: 640px) { .ms-panel--list { width: 100vw; } }
/* ★아래로 밀릴 때는 표준 폭으로 줄인다 — 96vw 그대로면 좌측 끝이 화면 밖(x=-6)이라
   "어떤 모달이었는지" 세로 라벨(.ms-edge)이 잘려 돌아갈 단서가 사라진다(실측). */
.ms-panel--list.ms-panel--under { width: min(1080px, 94vw); }
.ms-panel--under { filter: brightness(.94); cursor: pointer; }
.ms-panel--under > turbo-frame { pointer-events: none; }
/* 패널 안 sticky 헤더 — 스크롤이 긴 상세 패널에서 닫기·주요 액션이 늘 손에 남게 (2026-08-03).
   패널 자체가 스크롤 컨테이너라 top:0 이 곧 패널 상단이다. 좌우 패딩만큼 음수 마진으로 넓혀
   배경이 모서리까지 닿게 한다(그러지 않으면 글자가 헤더 옆으로 비껴 지나간다). */
.ms-head {
  position: sticky; top: 0; z-index: 12;   /* 툴팁(6)보다 위 — 헤더가 가려지면 안 된다 */
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin: -20px -20px 0; padding: 14px 20px;
  background: color-mix(in srgb, var(--g-surface) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--g-line-soft);
}
@media (min-width: 640px) { .ms-head { margin: -28px -28px 0; padding: 16px 28px; } }
/* 이 화면에서 할 일들 — 한 덩어리로 묶어야 "창 제어"인 ✕ 와 구분된다 */
.ms-head-acts { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
/* ✕ = 창 제어. 액션 그룹에서 구분선으로 떼어 놓는다(붙여 두면 오작동을 부른다) */
.ms-close {
  flex-shrink: 0; display: grid; place-items: center;
  width: 32px; height: 32px; border: 0; background: none; cursor: pointer;
  border-radius: var(--r-2); color: var(--g-label-faint);
  margin-left: 6px; padding-left: 12px; border-left: 1px solid var(--g-line-soft);
  transition: color var(--dur-1), background var(--dur-1);
}
.ms-close:hover { color: var(--g-label); background: var(--g-line-soft); }
/* 좁은 화면: 정체성 줄 아래로 액션이 통째로 내려간다(제목이 눌려 잘리는 것보다 낫다) */
@media (max-width: 560px) {
  .ms-head { gap: 10px; }
  .ms-head-acts { order: 3; width: 100%; }
  .ms-close { order: 2; margin-left: auto; }
}

.ms-edge {
  position: absolute; inset: 0 auto 0 0; width: 30px; z-index: 3; display: none;
  border-right: 1px solid var(--g-line-soft); background: var(--g-surface);
}
/* ★세로 라벨 (2026-08-03 두 번 고침).
   ① `rotate(180deg)` 금지 — `writing-mode: vertical-rl` 만으로 한글이 위→아래로 바르게
      흐르는데 180° 회전이 겹쳐 글자가 거꾸로 서고 아래에서 위로 읽혔다.
   ② 절대 위치(`top`/`left`/`transform`) 금지 — 머리글자가 잘려 "전체 인플루언서 목록"이
      "플루언서 목록"으로 보였다. flex 로 위쪽 정렬하면 시작점이 패딩 안쪽에 고정돼
      **앞글자가 잘릴 수 없다**. 넘칠 때는 꼬리를 자르고 말줄임을 붙인다(title 속성에 전문). */
.ms-panel--under .ms-edge {
  display: flex; align-items: flex-start; justify-content: center;
  padding: 18px 0; box-sizing: border-box;
}
.ms-edge span {
  writing-mode: vertical-rl; text-orientation: mixed;
  font-size: 11px; font-weight: 600; color: var(--g-label-alt); white-space: nowrap;
  max-height: 100%; overflow: hidden; text-overflow: ellipsis;
}

/* ── 광고분석 컴포넌트 행 ──
   ⚠ 클래스명에 "ad"를 쓰지 말 것 — .ad-row 같은 이름은 광고차단 확장(EasyList 제네릭 규칙)이
   무조건 display:none 처리해서 리스트가 통째로 사라진다 (2026-07-30 실제 발생). */
/* ── 광고 분석 + 판매 흐름 2단 배치 ──
   ★2026-08-03: 왼쪽 그래프와 오른쪽 리스트의 높이가 서로 놀아서 아래가 들쭉날쭉했다.
   한 덩어리로 보이게 높이를 같이 잡는다. 그래프는 자기 비율을 지키며 세로 중앙,
   리스트는 남는 높이 안에서 스크롤한다. 모바일에서는 위아래로 쌓는다. */
.spot-cols { --spot-h: 420px; display: flex; flex-direction: column; gap: 16px; }
.spot-col { min-width: 0; display: flex; flex-direction: column; }
.spot-list { display: flex; flex-direction: column; gap: 8px; overflow-y: auto; overscroll-behavior: contain; padding-right: 4px; }
@media (min-width: 640px) {
  .spot-cols { flex-direction: row; align-items: stretch; }
  .spot-col--chart { width: 55%; flex: 0 0 55%; }
  .spot-col--list { flex: 1 1 auto; }
  /* 두 칸 모두 같은 높이. 헤더 줄(30px + 여백 6px)을 뺀 나머지가 본문 높이가 된다. */
  .spot-col { height: calc(var(--spot-h) + 36px); }
  .spot-col--chart > div:last-child { flex: 1; display: flex; flex-direction: column; justify-content: center; }
  .spot-list { flex: 1; min-height: 0; }
}
@media (max-width: 639px) { .spot-list { max-height: var(--spot-h); } }

.spot-row { display: flex; gap: 12px; align-items: flex-start; padding: 12px; border: 1px solid var(--g-hairline);
  border-radius: var(--r-3); cursor: pointer; transition: border-color var(--dur-1), background var(--dur-1); }
.spot-row:hover { background: var(--g-line-soft); }
.spot-row--on { border-color: var(--primary-normal); background: color-mix(in srgb, var(--primary-normal) 5%, transparent); }
.spot-row--flash { animation: spotflash 1.2s; }
@keyframes spotflash { 0%, 60% { background: color-mix(in srgb, var(--primary-normal) 14%, transparent); } 100% { background: transparent; } }
.empty-flash { animation: spotflash 1s; }

/* 광고 방식 배지 — 전용 광고인지 / 중간 소개인지가 한눈에 띄어야 한다 (2026-07-30 지시) */
.fmt-badge {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%;
  font-size: 11px; font-weight: 700; border-radius: var(--r-2); padding: 3px 8px; line-height: 1.35;
  background: var(--primary-background); color: var(--primary-foreground);
}
/* 이모지로 뜻을 만들지 않는다 — 라벨이 이미 서술형이라 확성기 아이콘은 장식일 뿐이었다(2026-08-03) */

/* ── pitch (콘텐츠 기획 제안) ── */
.ev-ref {
  display: inline-flex; align-items: center; vertical-align: baseline;
  font-size: 9.5px; font-weight: 700; line-height: 1;
  padding: 2px 5px; margin: 0 1px; border-radius: var(--r-1); cursor: help;
  background: var(--primary-background); color: var(--primary-foreground);
}
.pitch-card {
  border: 1px solid color-mix(in srgb, var(--primary-normal) 30%, transparent);
  background: color-mix(in srgb, var(--primary-normal) 4%, var(--g-surface));
  border-radius: var(--r-4); padding: 16px;
}
.pitch-headline { font-size: 14px; font-weight: 700; line-height: 1.45; color: var(--g-label); }
/* 콘텐츠 제안 한 줄 — 형식 칩 + 기획 문장.
   ★모바일에서는 세로로 쌓는다 (2026-08-03 지적, 스크린샷 첨부):
   가로 flex 로 두면 "극한 테스트형 생활가전 사용기" 같은 긴 칩이 폭의 절반 이상을 먹고
   본문이 오른쪽 좁은 골짜기에서 여러 줄로 흘러내린다. 칩은 라벨이지 문단의 첫 단어가 아니다. */
.pitch-idea {
  display: flex; flex-direction: column; gap: 7px; align-items: flex-start;
  padding: 10px 12px; border: 1px solid var(--g-line-soft); border-radius: var(--r-3);
  background: var(--g-surface);
}
/* ★데스크탑에서도 가로로 되돌리지 않는다 (2026-08-03 2차 지적).
   모바일만 세로로 했더니 데스크탑에서 "칩 왼쪽 / 설명 오른쪽"이 됐고, 그것도 어색하다는
   지적을 받았다. 칩은 이 제안이 "어떤 형식인지" 알려주는 머리표다 — 항상 제 줄에 둔다. */
/* 칩이 제 줄을 쓸 때는 줄바꿈을 허용해야 한다(nowrap 이면 좁은 화면에서 넘친다) */
.pitch-idea > .tag, .pitch-idea > .chip { white-space: normal; text-align: left; }

/* ── 한눈 요약 스트립 ──
   ★2026-08-03: 여기 있던 `.verdict`(라벨 + 큰 한 줄 요약)를 걷어냈다.
   그 자리엔 LLM 이 쓴 압축 문장이 들어갔는데, ①바로 아래 콘셉트 카드와 내용이 겹치고
   ②압축된 쪽이 훨씬 읽기 어려워서 "화면에서 제일 크게 띄울 것"이 아니었다.
   대신 서버가 데이터로 조립한 숫자만 둔다 — 문장 품질에 좌우되지 않고 항상 말이 된다. */
.sum-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  border: 1px solid var(--g-hairline); border-radius: var(--r-4); overflow: hidden;
  background: var(--g-surface);
}
.sum-strip > div {
  display: flex; flex-direction: column; gap: 3px;
  padding: 12px 14px; border-right: 1px solid var(--g-line-soft);
}
.sum-strip > div:last-child { border-right: 0; }
.sum-strip .k { font-size: 12.5px; font-weight: 600; color: var(--g-label-alt); }
.sum-strip .v {
  font-size: 22px; font-weight: 700; letter-spacing: -.022em; color: var(--g-label);
  font-variant-numeric: tabular-nums; line-height: 1.2;
}
.sum-strip .v small { font-size: 12px; font-weight: 600; color: var(--g-label-faint); margin-left: 2px; }
@media (max-width: 640px) {
  .sum-strip { grid-template-columns: 1fr 1fr; }
  .sum-strip > div { border-bottom: 1px solid var(--g-line-soft); }
  .sum-strip > div:nth-child(2n) { border-right: 0; }
}

/* ── 예시 블록 ── 라벨 + 본문. 회색 줄글로 흘려 두면 바닥색과 구분이 안 된다. */
.ex-block {
  display: flex; gap: 8px; align-items: flex-start;
  border-radius: var(--r-3); padding: 9px 11px; background: var(--g-surface);
  border: 1px solid var(--g-line-soft);
}
.ex-k {
  flex-shrink: 0; font-size: 12px; font-weight: 700; letter-spacing: .02em;
  color: var(--g-label-faint); padding-top: 1px;
}
.ex-v { font-size: 13px; line-height: 1.6; color: var(--g-label); }

/* 버튼 안 개수 뱃지 — "제안서 만들기 [2]" 처럼 대상 규모를 붙인다 */
.c-btn-n {
  display: inline-flex; align-items: center; justify-content: center; min-width: 17px; height: 17px;
  padding: 0 5px; border-radius: var(--r-full); font-size: 11px; font-weight: 700;
  background: var(--g-line-soft); color: var(--g-label-alt); font-variant-numeric: tabular-nums;
}
.c-btn--pri .c-btn-n { background: rgba(255,255,255,.22); color: #fff; }

/* ── 섭외 목록 담기 버튼 + 시청자 정체성 칩 ── */
.sl-btn {
  display: inline-flex; align-items: center; gap: 5px;
  border: 0; background: none; line-height: 1; padding: 3px 5px;
  color: var(--g-label-faint); cursor: pointer;
  transition: color var(--dur-1), transform var(--dur-1), background var(--dur-1);
}
.sl-btn .sl-i {
  font-size: 16px; line-height: 1; font-style: normal;   /* 어떤 태그로 감싸도 눕지 않게 */
  font-family: "Apple SD Gothic Neo", "Segoe UI Symbol", "Noto Sans Symbols 2", sans-serif;
}
.sl-btn:hover { color: var(--g-caution); }
.sl-btn:hover .sl-i { transform: scale(1.15); }
.sl-btn .sl-i { transition: transform var(--dur-1) var(--ease-out); display: inline-block; }
.sl-btn.sl-on { color: var(--g-caution); }
.sl-btn:disabled { opacity: .5; cursor: wait; }
/* 글자 라벨형 — 처음 만나는 자리(모달 헤더)에는 아이콘만 두지 않는다.
   "★이 뭔데?"라는 지적(2026-08-03)의 직접적 대응이다. */
.sl-btn--label {
  padding: 6px 12px; border-radius: var(--r-3);
  border: 1px solid var(--g-line); font-size: 13px; font-weight: 600;
  color: var(--g-label-alt); background: var(--g-surface);
}
.sl-btn--label:hover { background: var(--g-line-soft); color: var(--g-label); }
.sl-btn--label.sl-on {
  border-color: color-mix(in srgb, var(--g-caution) 45%, transparent);
  background: color-mix(in srgb, var(--g-caution) 10%, transparent);
  color: color-mix(in srgb, var(--g-caution) 82%, var(--g-label));
}
/* 담은 게 0건일 때 제안서 버튼 잠금 — 빈 문서로 가는 길을 막는다 */
.is-locked { opacity: .45; pointer-events: none; }
.chip--persona { background: color-mix(in srgb, #7A63C9 12%, transparent); border-color: transparent;
  color: #7A63C9; font-weight: 600; }

/* ── 적합도 근거 매트릭스 ──
   ★2026-08-03 버그: 체크 아이콘이 한 줄을 통째로 먹고 라벨이 다음 줄로 떨어졌다(스크린샷).
   원인은 Tailwind preflight 의 `svg { display: block }` — td 안에 아이콘을 그냥 두면
   블록이라 줄이 바뀐다. 셀 안을 flex 로 감싸고 아이콘을 shrink-0 으로 고정한다.
   폭이 좁은 패널에서도 라벨이 먼저 읽히도록 글자도 12→13px 로 올렸다. */
.micro-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
.micro-tbl td { padding: 8px; border-bottom: 1px solid var(--g-line-soft); vertical-align: middle; }
.micro-tbl tr:last-child td { border-bottom: 0; }
.micro-tbl tr.is-neg td { color: var(--g-negative); }
.micro-tbl .pts { text-align: right; font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
.micro-tbl th {
  text-align: left; font-size: 12px; font-weight: 600; color: var(--g-label-alt);
  padding: 6px 8px; border-bottom: 1px solid var(--g-line-soft); white-space: nowrap;
}
.micro-tbl th.pts { text-align: right; }
.micro-tbl .mk { display: flex; align-items: center; gap: 7px; font-weight: 500; }
.micro-tbl .mk svg { flex-shrink: 0; }
/* 좁은 패널(모바일 모달)에서는 태그·횟수 칸을 접고 라벨+점수만 남긴다 */
@media (max-width: 560px) { .micro-tbl .mhide { display: none; } }

/* ── 정성 점수 배지 ── */
.qscore { display: inline-flex; align-items: baseline; gap: 3px; font-weight: 700; font-variant-numeric: tabular-nums; }
.qscore small { font-weight: 500; font-size: 11px; color: var(--g-label-faint); }

/* ── 근거 지도 (크리에이터 → 인용 → 매칭 기준) ──
   giirin-result-mockup.html 의 3단 SVG 복원. 힘기반 온톨로지 그래프(동결)와 별개다.
   색·크기는 전부 DS 토큰을 따른다(목업의 원시 hex 는 가져오지 않았다). */
.eg-wrap { overflow-x: auto; overscroll-behavior-x: contain; }
.eg-svg { display: block; min-width: 720px; }
.eg-col { font-size: 10px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  fill: var(--g-label-faint); }
.eg-name  { font-size: 12px; font-weight: 700; fill: var(--g-label); }
.eg-quote { font-size: 11px; fill: var(--g-label); }
.eg-sub   { font-size: 10px; fill: var(--g-label-faint); }
.eg-link {
  fill: none; stroke: var(--g-line); stroke-width: 1.2;
  transition: opacity var(--dur-1) var(--ease-out), stroke var(--dur-1), stroke-width var(--dur-1);
}
.eg-node { fill: var(--g-label-faint); transition: fill var(--dur-1), opacity var(--dur-1); }
.eg-node--c { fill: var(--primary-normal); }
.eg-node--l { fill: color-mix(in srgb, var(--primary-normal) 55%, var(--g-label-faint)); }
.eg-hit { cursor: pointer; }
.eg-hit:focus { outline: none; }
.eg-hit:focus-visible rect { fill: color-mix(in srgb, var(--primary-normal) 10%, transparent); }
.eg-hit.is-neg .eg-node--l { fill: var(--g-negative); }
.eg-hit.is-neg .eg-name { fill: var(--g-negative); }

/* 강조: 관련 없는 것만 흐려진다 — 지우지 않고 남겨야 전체 맥락이 유지된다 */
.eg-svg.is-dim .eg-link { opacity: .10; }
.eg-svg.is-dim .eg-link.hi { opacity: 1; stroke: var(--primary-normal); stroke-width: 2; }
.eg-svg.is-dim .eg-node { opacity: .22; }
.eg-svg.is-dim .eg-name, .eg-svg.is-dim .eg-sub, .eg-svg.is-dim .eg-quote { opacity: .25; }
.eg-svg.is-dim .hi .eg-node,
.eg-svg.is-dim .hi .eg-name, .eg-svg.is-dim .hi .eg-sub, .eg-svg.is-dim .hi .eg-quote { opacity: 1; }


/* ── 사이드바 레일(접기) ──
   데스크탑에서 접기 버튼(‹)이 아무 동작도 안 했다(2026-08-02 지적). mobile 전용 close 였는데
   md:hidden 이 안 먹어 데스크탑에도 보이던 것. 이제 데스크탑에선 아이콘만 남는 레일로 접는다. */
@media (min-width: 768px) {
  #app-sidebar.is-rail { width: 60px; padding-left: 8px; padding-right: 8px; }
  #app-sidebar.is-rail .rail-hide { display: none !important; }
  #app-sidebar.is-rail .rail-only { display: inline !important; }
  #app-sidebar.is-rail .side-nav-i,
  #app-sidebar.is-rail .side-brand,
  #app-sidebar.is-rail .c-btn { justify-content: center; padding-left: 0; padding-right: 0; }
  /* 접힌 상태에서 c. 마크가 좌측에 붙어 있었다(2026-08-02 지적) — 링크·인풋 모두 중앙으로 */
  #app-sidebar.is-rail .c-input { justify-content: center; }
  #app-sidebar.is-rail .side-nav-i.is-on::before { left: -8px; }
  #app-sidebar.is-rail .side-grp { text-align: center; padding-left: 0; padding-right: 0;
    font-size: 0; }                                  /* 그룹 라벨은 레일에서 구분선 역할만 */
  #app-sidebar.is-rail .side-grp::after { content: "···"; font-size: 10px; }
  #app-sidebar.is-rail [data-rail-toggle] svg { transform: rotate(180deg); }
  #app-sidebar.is-rail .rail-row { flex-direction: column; gap: 4px; }
}
.rail-only { display: none; }

/* ── 스크롤스파이 목차(dot navigation) — 분석상세 우측 레일 (2026-08-02) ──
   항목은 toc_controller.js 가 data-toc-label 섹션들을 읽어 생성한다.
   평소엔 점만 보이고, 레일 hover 시 라벨이 나타난다. 현재 섹션 항목은 .is-on.
   라벨 "모양"은 .chip 그대로(단일 원천) — 여기서는 부유 동작(--sh-pop·--dur-1)만 얹는다. */
.toc {
  position: fixed; right: 12px; top: 50%; transform: translateY(-50%);
  z-index: var(--z-sticky);
  display: none; flex-direction: column; align-items: flex-end;
}
@media (min-width: 1280px) { .toc { display: flex; } }
@media print { .toc { display: none !important; } }
.toc-i { display: flex; align-items: center; justify-content: flex-end; gap: 8px; padding: 10px 0; cursor: pointer; }
/* 항목 간 세로 간격 = 20px (4px→10px 패딩, 2026-08-02 사용자: 기존의 2.5배) — 점이 붙어 있으면
   어느 점이 어느 섹션인지 시선으로 매칭이 안 된다 */
.toc-lab {
  opacity: 0; pointer-events: none; white-space: nowrap;
  padding: 2px 9px;                              /* 레일용 저밀도 chip */
  box-shadow: var(--sh-pop);                     /* 부유 요소 규약 */
  transition: opacity var(--dur-1);
}
.toc:hover .toc-lab, .toc-i:focus-visible .toc-lab { opacity: 1; }
.toc-dot {
  width: 8px; height: 8px; border-radius: var(--r-full); flex-shrink: 0;
  border: 1px solid var(--g-line); background: var(--g-surface);
  transition: background var(--dur-1), border-color var(--dur-1);
}
.toc-i.is-on .toc-dot { background: var(--primary-normal); border-color: var(--primary-normal); }
