/* ============================================================
   socialradar 360 — v8 앱 셸 확장 (v8.css 정본 위에 얹는 앱 전용 계층)
   ------------------------------------------------------------
   v8.css(와이어 정본)는 수정하지 않는다 — 앱 런타임에만 필요한
   로딩/토스트/프로그레스/모바일 드로어를 여기서 확장한다.
   페이지 한정 스타일은 페이지별 파일 (v8-login.css 등).
   ============================================================ */

/* ---- Alpine x-cloak (평가 전 깜빡임 방지) ---- */
[x-cloak] { display: none !important; }

/* ---- Livewire navigate 진행바 (topbar 상단 1선) ---- */
#nav-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 200;
  pointer-events: none;
}
#nav-progress .bar {
  height: 100%; width: 0; background: var(--brand);
  transition: width .25s ease, opacity .25s ease; opacity: 0;
}
#nav-progress.loading .bar { width: 70%; opacity: 1; transition: width 6s cubic-bezier(.1,.6,.2,1), opacity .1s; }
#nav-progress.done .bar { width: 100%; opacity: 0; }

/* Livewire 내장 NProgress 바 억제 — config 로 끄지 말 것 (config/livewire.php 주석 참고).
   `navigate.show_progress_bar = false` 는 v3.7.15 번들의 모듈 최상위 `Alpine.navigate.
   disableProgressBar()` 참조를 깨워 window.Alpine 정의 전에 ReferenceError 로 부트 전체가
   죽는다 (전 화면 wire:click 무반응 전면 장애). 그래서 부트는 켠 채 시각만 숨긴다 —
   위 #nav-progress 브랜드 바가 유일한 진행 표시다. */
#nprogress { display: none !important; }

/* ---- navigate 스왑 창 — 전환 깜빡임 억제 (레이아웃 스크립트가 클래스를 관리) ----
   body 교체 직후 페이지 CSS 가 적용되기 전 한두 프레임 동안 무스타일 기본값이 그려지고,
   페이지 CSS 가 뒤늦게 적용되는 순간 transition 이 그 보정을 애니메이션으로 재생해
   깜빡임이 된다 (실측: /projects 의 hover 전용 [대시보드 →] opacity 1→0 페이드).
   스왑 창 동안 transition 을 전면 차단해 보정을 즉시 반영한다.
   #nav-progress 는 제외 — 진행바 자체가 transition 으로 움직인다. */
html.sr-nav-swap body *:not(#nav-progress):not(#nav-progress *) { transition: none !important; }

/* ---- navigate 스왑 홀드 — "보였다가 자리잡는" 정착 현상 근절 ----
   새 body 는 페이지 CSS(link) 로드가 끝나기 전에 그려질 수 있다 (Livewire mergeNewHead 는
   stylesheet 를 await 하지 않는다 — 실측: 캐시 미스 시 v8-feed 미적용 화면이 수 초 노출).
   스왑 직전부터 모든 stylesheet 가 준비될 때까지 새 화면을 숨겨, 완성된 화면이 한 프레임에
   뜨게 한다. visibility 를 쓰는 이유: 레이아웃은 유지되어야 스크롤 복원이 정확하다.
   · 셸 화면: 콘텐츠 영역만 숨긴다 (사이드바·탑바는 전역 CSS 만 쓰므로 항상 완성 상태).
   · bare 화면(온보딩/프로젝트 홈 등): 컴포넌트 루트째 숨긴다.
   · #nav-progress(진행바)·#sr-toast 는 제외 — 홀드 동안에도 계속 보여야 한다. */
html.sr-nav-hold main.content { visibility: hidden !important; }
html.sr-nav-hold body > div:not(.shell):not(#nav-progress):not(#sr-toast):not(#nprogress) { visibility: hidden !important; }

/* ---- 페이지 래퍼 중앙 정렬 — 와이어 <main class="content xx-wrap"> 대응 ----
   와이어는 .content 와 래퍼가 한 요소라 .content 의 margin:0 auto 로 중앙 정렬되지만,
   앱은 레이아웃의 .content 안에 컴포넌트 루트(래퍼)가 따로 들어와 max-width 만 걸리고
   중앙 정렬이 빠진다 → 좌측 쏠림 (실측: rp-wrap 우측 224px / st-wrap 우측 264px 공백).
   페이지 CSS(와이어 원문)는 불변으로 두고 여기서만 보강한다.
   fd-wrap 은 피드 blade 가 같은 값을 인라인으로 이미 갖고 있다 — 동일 값 중복이라 무해. */
.content > .rp-wrap, .content > .st-wrap, .content > .fd-wrap { width: 100%; margin-inline: auto; }

/* ---- 스피너 (버튼/인라인 공용) ---- */
.sr-spin {
  display: inline-block; width: 14px; height: 14px; flex-shrink: 0;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%;
  animation: sr-rotate .7s linear infinite;
}
.sr-spin.lg { width: 20px; height: 20px; border-width: 2.5px; }
@keyframes sr-rotate { to { transform: rotate(360deg); } }

/* ---- 스켈레톤 (목록/카드 최초 로드) ---- */
.sr-skel {
  border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--surface-hover) 25%, var(--border-soft) 50%, var(--surface-hover) 75%);
  background-size: 200% 100%;
  animation: sr-shimmer 1.4s ease infinite;
}
@keyframes sr-shimmer { to { background-position: -200% 0; } }

/* ---- 재조회 디밍 (wire:loading 델리게이트) ----
   목록 재조회는 콘텐츠를 유지한 채 살짝 가라앉힌다 (레이아웃 점프 방지). */
.sr-dim { opacity: .45; pointer-events: none; transition: opacity .15s; }

/* ---- 토스트 (하단 중앙 단일 채널) ---- */
.sr-toast {
  position: fixed; left: 50%; bottom: 28px; transform: translateX(-50%) translateY(8px);
  z-index: 160; pointer-events: none;
  background: var(--ink); color: #fff;
  font-size: var(--fs-sm); font-weight: 500; line-height: 1.5;
  padding: 10px 16px; border-radius: var(--r-md);
  box-shadow: var(--shadow-pop);
  opacity: 0; transition: opacity .18s ease, transform .18s ease;
  max-width: min(92vw, 480px); text-align: center;
}
.sr-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .sr-spin, .sr-skel { animation-duration: 1.5s; }
  #nav-progress .bar { transition: none; }
  .sr-toast { transition: none; }
}

/* ---- 모바일 사이드바 드로어 (≤1024px) ---- */
@media (max-width: 1024px) {
  .sidebar.is-open {
    display: flex;
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 150;
    box-shadow: var(--shadow-pop);
  }
  .sidebar-backdrop {
    position: fixed; inset: 0; z-index: 140;
    background: rgba(11, 18, 32, .35);
  }
}

/* ============================================================
   채널 배지 — 전 화면 공용 (<x-channel-badge> / App\Support\ChannelPresenter)
   ------------------------------------------------------------
   피드·설정·온보딩·어드민이 같은 부품을 쓰므로 페이지 CSS 가 아니라 여기 있어야 한다.
   두 형태뿐이고 마크업은 전부 컴포넌트가 만든다:
     · pill (.fd-ch-badge) — 목록/상세의 [아이콘] 채널명 · 세부출처
     · tile (.ob-ch-ic)    — 설정/온보딩/어드민 카드의 브랜드색 정사각 아이콘

   ⚠️ 아래 두 base 블록은 와이어 원문(v8-feed.css / v8-dashboard.css 의 .fd-ch-badge,
   v8-settings.css / v8-onboarding.css 의 .ob-ch-ic)과 **같은 값의 자립 사본** 이다.
   와이어가 없는 화면(어드민 등)에서도 배지가 성립하도록 두었고, 해당 페이지에서는
   나중에 로드되는 와이어 쪽이 이기지만 값이 같아 결과가 달라지지 않는다.
   와이어 정본이 값을 바꾸면 이 사본도 같이 맞출 것.
   ============================================================ */

/* ---- pill — 와이어 .fd-ch-badge 자립 사본 (와이어 없는 화면용) ---- */
.fd-ch-badge {
  font-size: 11px; font-weight: 700; color: var(--ink-2);
  padding: 3px 10px; border-radius: var(--r-pill);
  background: var(--surface-2); border: 1px solid var(--border-soft);
  max-width: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex-shrink: 0;
}
/* 아이콘·채널명·세부출처 3슬롯 — 와이어엔 없는 앱 보강 (display 는 와이어가 지정하지 않아 안전) */
.fd-ch-badge { display: inline-flex; align-items: center; gap: 5px; }
/* 채널명은 줄이지 않는다 — 말줄임은 언제나 세부 출처 쪽이 흡수한다 */
.fd-ch-badge .fd-ch-nm { flex-shrink: 0; }
.fd-ch-badge .fd-ch-src { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-3); font-weight: 600; }
.fd-ch-badge .fd-ch-src::before { content: "·"; margin-right: 4px; color: var(--ink-4); }
/* 세부 출처가 붙는 배지만 넓힌다 (채널명만이면 와이어의 150px 그대로).
   `.has-src` 는 특이도 0,2,0 이라 뒤에 로드되는 페이지 CSS 의 `.fd-ch-badge` 를 이긴다. */
.fd-ch-badge.has-src { max-width: 240px; }
@media (max-width: 640px) { .fd-ch-badge.has-src { max-width: 130px; } }

/* 인라인 SVG 아이콘 — 배지 안에서도, 필터 드롭다운(.filter-opt) 안에서도 줄어들지 않는다 */
.fd-ch-ico { flex-shrink: 0; }

/* ---- tile — 와이어 .ob-ch-ic 자립 사본 + 글자 대신 아이콘 ---- */
.ob-ch-ic {
  width: 30px; height: 30px; flex-shrink: 0; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-sm); font-weight: 800; color: #fff;
}
/* 아이콘 흰 선은 ChannelPresenter::icon() 이 인라인 color 로 준다 (배경이 브랜드 색이므로).
   여기선 baseline 여백이 남지 않도록 블록화만 — flex 자식이라 이미 블록화되지만 명시해 둔다. */
.ob-ch-ic .fd-ch-ico { display: block; }

/* ---- 알림 배너 (로그인 안내 등 공용) ---- */
.sr-notice {
  display: flex; align-items: flex-start; gap: 9px;
  font-size: var(--fs-sm); line-height: 1.55;
  padding: 11px 14px; border-radius: var(--r-md);
  background: var(--warn-soft); color: var(--warn-text);
  border: 1px solid rgba(217, 126, 26, .22);
}
.sr-notice svg, .sr-notice i { width: 15px; height: 15px; flex-shrink: 0; margin-top: 1px; }
.sr-notice.is-info { background: var(--brand-soft); color: var(--brand-deep); border-color: rgba(79, 70, 229, .2); }
.sr-notice.is-good { background: var(--good-soft); color: var(--good-text); border-color: rgba(31, 157, 85, .22); }
.sr-notice.is-bad  { background: var(--bad-soft);  color: var(--bad-text);  border-color: rgba(221, 68, 68, .22); }

/* ============================================================
   탑바 — 좁은 폭 보강 (모바일 375px 급 실측 깨짐 대응)
   ------------------------------------------------------------
   와이어 정본은 .ws(프로젝트명)에만 말줄임을 주고 크럼 꼬리(페이지명)는
   생 텍스트라, 긴 실데이터 프로젝트명 + 페이지명 + 우측 액션·사용자 칩이
   한 줄을 넘치면 꼬리가 낱글자 세로 낙하하고 사용자 칩이 내부 줄바꿈된다
   (와이어는 짧은 예시 데이터라 드러나지 않던 문제).
   꼬리는 한 줄 고정하고 프로젝트명이 먼저 줄어들게 shrink 가중치를 준다.
   ⚠ 와이어 v8.css 의 topbar @media(1024: padding / 640: .topbar-note 숨김)와
   겹치는 선언 없음 — 와이어가 지정하지 않은 속성만 추가한다.
   ============================================================ */
.topbar-title { flex-wrap: nowrap; }
.topbar-title .ws { flex-shrink: 30; min-width: 36px; }   /* 프로젝트명이 우선 양보 (와이어가 이미 말줄임 지정) */
.topbar-title .sep { flex-shrink: 0; }
/* 꼬리(페이지명)는 사실상 안 줄어든다(0.01) — 프로젝트명이 min-width 바닥까지 먼저 양보하고,
   그래도 모자라는 극단 폭에서만 꼬리가 말줄임된다 (shrink 를 0 으로 두면 그 극단에서 가로 넘침). */
.topbar-title > span:last-child { flex-shrink: 0.01; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.topbar-right, .topbar-user { flex-shrink: 0; }
.topbar-user .nm { white-space: nowrap; }
@media (max-width: 640px) {
  /* 와이어 .topbar-note 숨김(640)과 같은 축 — 모바일에선 아바타만 남긴다 */
  .topbar-user .nm { display: none; }
}

/* ── 워크스페이스 스위처 — 긴 프로젝트명 대응 (2026-08-06 사용자 보고:
      이름이 아바타~캐럿 사이를 꽉 채워 부자연스러움). 10자 초과면 한 단계 작은
      폰트 + 자간 미세 축소로 여백을 만든다. 와이어 .ws-name ellipsis 는 그대로. ── */
.ws-name.is-long { font-size: var(--fs-sm); letter-spacing: -.01em; }
