/* ============================================================
   Clipper Studio — SFC Vision 디자인 시스템 (다크 전용 컨트롤룸)
   소스: 성남 클리퍼/tokens/* · readme.md. 인디고 #5B5EF0 액센트,
   Rajdhani(수치·라벨) + Pretendard(한글·본문) + 모노(타임코드).
   라이트 모드 폐기 — 컨트롤룸 소프트웨어는 영구 다크.
   ============================================================ */

/* ---- Rajdhani (Latin display / numerics / labels) ---- */
@font-face { font-family: "Rajdhani"; font-style: normal; font-weight: 400; font-display: swap; src: url("./assets/fonts/Rajdhani-400.woff2") format("woff2"); }
@font-face { font-family: "Rajdhani"; font-style: normal; font-weight: 500; font-display: swap; src: url("./assets/fonts/Rajdhani-500.woff2") format("woff2"); }
@font-face { font-family: "Rajdhani"; font-style: normal; font-weight: 600; font-display: swap; src: url("./assets/fonts/Rajdhani-600.woff2") format("woff2"); }
@font-face { font-family: "Rajdhani"; font-style: normal; font-weight: 700; font-display: swap; src: url("./assets/fonts/Rajdhani-700.woff2") format("woff2"); }
/* ---- Pretendard (Korean + Latin body) ---- */
@font-face { font-family: "Pretendard"; font-style: normal; font-weight: 400; font-display: swap; src: url("./assets/fonts/Pretendard-400.woff2") format("woff2"); }
@font-face { font-family: "Pretendard"; font-style: normal; font-weight: 500; font-display: swap; src: url("./assets/fonts/Pretendard-500.woff2") format("woff2"); }
@font-face { font-family: "Pretendard"; font-style: normal; font-weight: 600; font-display: swap; src: url("./assets/fonts/Pretendard-600.woff2") format("woff2"); }
@font-face { font-family: "Pretendard"; font-style: normal; font-weight: 700; font-display: swap; src: url("./assets/fonts/Pretendard-700.woff2") format("woff2"); }
/* ---- 자막/템플릿 번들 폰트(@font-face) — /fonts 마운트(app/assets/fonts) 서빙.
   번인(render_encode)이 쓰는 실제 폰트 파일과 동일 패밀리라 미리보기≈결과. 굵게/기울임은
   브라우저 합성 — 번인은 폰트 파일 변형(config.subtitle_font_file)이라 근사 일치.
   편집 자막 + 템플릿 배치 모달 + 원스톱 미리보기 칩이 공유(edit.css 에서 이동). ---- */
@font-face { font-family: 'NanumGothic'; src: url('/fonts/NanumGothic-Regular.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'NanumMyeongjo'; src: url('/fonts/NanumMyeongjo-Regular.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'BlackHanSans'; src: url('/fonts/BlackHanSans-Regular.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SUIT'; src: url('/fonts/SUIT-Regular.ttf') format('truetype'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'SUIT'; src: url('/fonts/SUIT-Bold.ttf') format('truetype'); font-weight: 700; font-display: swap; }
@font-face { font-family: 'SUIT Heavy'; src: url('/fonts/SUIT-Heavy.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SUIT Thin'; src: url('/fonts/SUIT-Thin.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SUIT ExtraLight'; src: url('/fonts/SUIT-ExtraLight.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SUIT Light'; src: url('/fonts/SUIT-Light.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SUIT Medium'; src: url('/fonts/SUIT-Medium.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SUIT SemiBold'; src: url('/fonts/SUIT-SemiBold.ttf') format('truetype'); font-display: swap; }
@font-face { font-family: 'SUIT ExtraBold'; src: url('/fonts/SUIT-ExtraBold.ttf') format('truetype'); font-display: swap; }

:root,
:root[data-theme="dark"],
:root[data-theme="light"] {  /* light 셀렉터도 다크로 폴백(과거 토글 잔재 무해화) */
  /* ---- Fonts ---- */
  --font-display: "Rajdhani", "Pretendard", system-ui, sans-serif;
  --font-body:    "Pretendard", "Noto Sans KR", "Malgun Gothic", system-ui, sans-serif;
  --font-mono:    "Cascadia Code", "JetBrains Mono", Consolas, monospace;

  /* ---- Brand raw ---- */
  --sfc-indigo:        #5b5ef0;
  --sfc-indigo-bright: #8487ff;
  --sfc-gold:          #ffca00;   /* 골/우승 */
  --sfc-red:           #f6676e;   /* alert */

  /* ---- Neutral ramp (cool charcoal) ---- */
  --neutral-0: #0a0b0c; --neutral-50: #0e0f11; --neutral-150: #16181b;
  --neutral-250: #1f2123; --neutral-400: #282b30; --neutral-500: #3c424c;
  --neutral-700: #6d6d6d; --neutral-800: #a8a8a8; --neutral-900: #d8d8d8;

  /* ---- Surfaces (SFC Vision) ---- */
  --surface-app:    #0e0f11;
  --surface-sunken: #0a0b0c;
  --surface-1:      #16181b;   /* panels, sidebar */
  --surface-2:      #1f2123;   /* cards */
  --surface-3:      #282b30;   /* raised / hover */
  --surface-4:      #3c424c;   /* inputs, controls */

  /* ---- Text (SFC Vision) ---- */
  --text-strong:  #ffffff;
  --text-default: #d8d8d8;
  --text-muted:   #a8a8a8;
  --text-faint:   #6d6d6d;
  --text-on-accent: #ffffff;

  /* ---- Borders ---- */
  --border-subtle:  #232629;
  --border-default: #2e3338;
  --border-strong:  #3c424c;

  /* ---- Accent (indigo) + semantic ---- */
  --accent-bright:  #8487ff;
  --accent-hover:   #6f72f4;
  --accent-active:  #4548d6;
  --accent-soft:    rgba(91, 94, 240, 0.16);
  --accent-soft-bright: rgba(132, 135, 255, 0.14);
  --accent-ring:    rgba(132, 135, 255, 0.45);
  --rec:            #ff3b3b;   /* 녹화/라이브 */
  --rec-soft:       rgba(255, 59, 59, 0.14);
  --success:        #3bd17a;
  --gold:           #ffca00;

  /* ---- Glows / scrims / veils ---- */
  --glow-accent: 0 0 0 1px rgba(132, 135, 255, 0.35), 0 0 18px rgba(132, 135, 255, 0.28);
  --glow-rec:    0 0 0 1px rgba(255, 59, 59, 0.45), 0 0 16px rgba(255, 59, 59, 0.4);
  --inset-hairline: inset 0 1px 0 rgba(255, 255, 255, 0.04);
  --scrim:      rgba(0, 0, 0, 0.62);
  --scrim-soft: rgba(0, 0, 0, 0.35);
  --glass-bg:   rgba(18, 20, 22, 0.72);
  --hover-veil: rgba(255, 255, 255, 0.05);

  /* ---- App shell frame ---- */
  --topbar-h:        64px;
  --sidebar-w:       224px;   /* expanded: icon + label + group caption */
  --sidebar-w-min:   56px;    /* collapsed: icon only */
  --sidebar-current: var(--sidebar-w);  /* shell-nav.js toggles to -min */

  /* ---- Radius / motion / z ---- */
  --radius-xs: 3px; --radius-pill: 999px;
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-1: 90ms; --dur-2: 150ms; --dur-3: 220ms;
  --z-sticky: 100; --z-overlay: 600; --z-modal: 800; --z-toast: 900; --z-tooltip: 1000;

  /* ============================================================
     레거시 시맨틱 별칭 — 기존 화면 CSS(수백 줄)가 이 이름들을 참조한다.
     SFC Vision 값으로 재매핑 → 화면 대부분이 자동으로 새 룩으로 전환.
     ============================================================ */
  --bg:        var(--surface-app);
  --surface:   var(--surface-1);
  --text:      var(--text-default);
  --muted:     var(--text-muted);
  --dim:       var(--text-faint);
  --border:    var(--border-default);
  --accent:    var(--sfc-indigo);
  --accent-2:  var(--accent-hover);
  --on-accent: var(--text-on-accent);
  --danger:    var(--sfc-red);
  --on-danger: #ffffff;
  --ok:        var(--success);
  --work:      var(--gold);
  --info:      var(--accent-bright);
  --manual:    var(--accent-bright);
  --score:     #8b7df0;
  --audio:     #ff8c42;
  --shadow:    0 8px 24px rgba(0, 0, 0, 0.5);
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px;
  --radius-sm: 5px; --radius-md: 8px; --radius-lg: 12px;
  --stage-bg: var(--surface-sunken);
  /* 새 IA 페이지가 쓰는 별칭 */
  --fg:        var(--text-default);
  --card:      var(--surface-2);
  --fg-muted:  var(--text-muted);
  --bg-hover:  var(--surface-3);
}

* {
  box-sizing: border-box;
}

/* 스크롤바는 필요할 때만(팬텀 스크롤바 제거). 콘솔 레이아웃에서 페이지 자체는 스크롤 안 함. */
html {
  scrollbar-gutter: auto;
}

/* 전역 스크롤바 — 얇게 + 회색 계열 + 상시 노출(트랙·썸 항상 보임). 전 페이지·전 스크롤 영역 공통. */
* { scrollbar-width: thin; scrollbar-color: rgba(148, 163, 184, 0.55) rgba(148, 163, 184, 0.12); }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: rgba(148, 163, 184, 0.12); border-radius: 999px; }
::-webkit-scrollbar-thumb { background: rgba(148, 163, 184, 0.55); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: rgba(148, 163, 184, 0.82); background-clip: padding-box; }
::-webkit-scrollbar-corner { background: transparent; }

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

button,
input,
select {
  font: inherit;
}

/* Rajdhani(컨트롤룸 디스플레이) — 헤딩·버튼·nav·eyebrow·수치. 한글은 Pretendard 폴백. */
h1, h2, h3, .brand strong, .btn, .topnav a, .eyebrow {
  font-family: var(--font-display);
  letter-spacing: 0.005em;
}
.eyebrow {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
}
/* 큰 수치 — 표 정렬용 tabular */
.stat-num, .metric strong, .mono {
  font-variant-numeric: tabular-nums;
}

.topbar {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 16px;
  min-height: var(--topbar-h);
  padding: 12px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.brand {
  display: flex;
  align-items: baseline;
  gap: 12px;
  min-width: 220px;
}

.brand strong {
  font-size: 20px;
}

.brand span,
.toolbar span,
.metric span {
  color: var(--muted);
  font-size: 12px;
}

.topbar-actions,
.toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

/* 액션(유저·계정·WS·시계)을 오른쪽 끝에 고정 — 액션 폭이 변해도 왼쪽 nav 가 안 밀린다(헤더 흔들림 원인 제거). */
.topbar-actions {
  margin-left: auto;
}

/* range(슬라이더/재생바)는 박스 스타일 제외 — 테두리·배경·min-height·padding 없이 슬라이더로만
   렌더(전 화면 재생바 통일). 텍스트/셀렉트만 박스. range 공통 색은 아래 input[type=range]에서. */
input:not([type="range"]),
select {
  min-height: 36px;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0 10px;
}

/* 모든 슬라이더(재생바·볼륨·줌·게인 등) 공통 — 박스 없는 native 슬라이더, 테마 강조색. 시크바
   (.cp-seek/.ed-seek/.media-preview-seek/.clipcfg-seek)는 아래에서 트랙·핸들을 따로 커스텀한다. */
input[type="range"] {
  border: none;
  background: transparent;
  min-height: 0;
  padding: 0;
  accent-color: var(--accent);
}

input:focus,
select:focus,
button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* 버튼 톤 통일(2026-07-07 dykim): accent 채움(보라) 버튼 폐기 — 전 화면 .btn/.icon-btn 을
   마크 '← 소스 변경'(.src-change)과 같은 중립 아웃라인(surface 배경+테두리, hover=accent 테두리)
   으로 통일한다. primary/secondary 는 하위호환 클래스로만 남고 모양 차이는 없다. */
.btn,
.icon-btn {
  min-height: 36px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, filter 0.15s ease, opacity 0.15s ease;
}

.btn {
  /* inline-flex 중앙정렬 — <a> 로 만든 버튼(다운로드)도 <button> 처럼 글자가 가운데 오고
     min-height 가 먹게(인라인 <a> 는 text-align/min-height 가 안 먹어 글자가 좌측에 붙었음). */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 14px;
  text-decoration: none;   /* <a> 로 만든 버튼(다운로드 등)에 밑줄이 생기지 않게 */
}

.icon-btn {
  width: 36px;
}

.btn.primary,
.btn.secondary {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
}

.btn:hover:not(:disabled),
.icon-btn:hover:not(:disabled) {
  background: var(--surface-3);
  border-color: var(--accent);
}

.btn:active:not(:disabled),
.icon-btn:active:not(:disabled) {
  filter: brightness(0.94);
}

.btn:disabled,
.icon-btn:disabled {
  opacity: 0.48;
  cursor: not-allowed;
}

.btn.danger,
.btn.primary.danger,
.btn.secondary.danger,
.btn[data-delete],
.btn[data-remove] {
  color: var(--danger) !important;
  background: color-mix(in srgb, var(--danger) 14%, transparent) !important;
  border-color: color-mix(in srgb, var(--danger) 48%, transparent) !important;
}

.btn.danger:hover:not(:disabled),
.btn.primary.danger:hover:not(:disabled),
.btn.secondary.danger:hover:not(:disabled),
.btn[data-delete]:hover:not(:disabled),
.btn[data-remove]:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger) 22%, transparent) !important;
  border-color: color-mix(in srgb, var(--danger) 62%, transparent) !important;
}

.conn,
.badge,
.user-badge,
.admin-link {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  border-radius: var(--radius-sm);
  padding: 0 9px;
  font-size: 12px;
  font-weight: 700;
}

/* WS 상태 뱃지: 글자(연결중↔연결됨↔재연결 대기) 길이가 달라도 헤더가 안 흔들리게 고정 폭. */
.conn {
  min-width: 96px;
  justify-content: center;
}

.conn.on,
.badge.up,
.badge.done {
  color: var(--ok);
  background: color-mix(in srgb, var(--ok) 16%, transparent);
}

.conn.wait,
.badge.extracting,
.badge.queued,
.badge.restarting {
  color: var(--work);
  background: color-mix(in srgb, var(--work) 16%, transparent);
}

.conn.off,
.badge.down,
.badge.failed {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 16%, transparent);
}

.badge.manual { color: var(--manual); }
.badge.score_api { color: var(--score); }
.badge.audio { color: var(--audio); }

/* 헤더 간소화: WS 상태 = 작은 점(색이 상태: 녹색 연결·주황 대기·빨강 끊김), 시계 숨김. */
#wsState.conn {
  min-width: 0; padding: 0; border: none; background: none !important; font-size: 0;
}
#wsState.conn::before { content: "\25CF"; font-size: 11px; line-height: 1; }
#clock { display: none; }

.user-badge,
.admin-link {
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--border);
  text-decoration: none;
}

.mono {
  color: var(--muted);
  font-family: "Cascadia Code", Consolas, monospace;
  font-size: 12px;
}

.shell {
  max-width: none;
  margin: 0;
  padding: 0;
  min-height: 0;
}

/* ============================================================
   App shell — 좌측 접이식 사이드바 + 얇은 헤더 (shell-nav.js)
   ============================================================ */
body:has(.app-shell) {
  display: flex;
  flex-direction: column;
  height: 100vh;
  overflow: hidden;
}
.app-shell {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface-app);
}
.shell-body { flex: 1; min-height: 0; display: flex; }
.shell-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* 본문 슬롯에 전 페이지 공통 10px 여백(헤더·사이드바·창 가장자리와 간격).
   세로 스크롤바 상시 노출(내용이 안 넘쳐도 트랙이 늘 보이게). */
.app-content { flex: 1; min-height: 0; overflow-x: hidden; overflow-y: scroll; position: relative; margin: 10px; }

/* 슬롯 안으로 이동된 기존 본문은 슬롯을 꽉 채운다(자체 고정높이/플렉스 해제). */
.app-content > #view { height: 100%; min-height: 0; overflow: visible; }
.app-content > #view > .shell { height: auto; overflow: visible; }
.app-content > main.page,
.app-content > main { min-height: 100%; }

/* ---- Sidebar ---- */
.app-sidebar {
  width: var(--sidebar-current);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  background: var(--surface-1);
  border-right: 1px solid var(--border-subtle);
  overflow: hidden;
  transition: width var(--dur-2) var(--ease-out);
}
.nav-collapsed .app-sidebar { width: var(--sidebar-w-min); }

.app-brand {
  display: flex; align-items: center; gap: 10px;
  height: var(--topbar-h); flex-shrink: 0;
  padding: 0 12px; border-bottom: 1px solid var(--border-subtle);
}
.nav-collapsed .app-brand { padding: 0 0 0 8px; }
.app-burger {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; flex-shrink: 0;
  border: none; background: transparent; color: var(--text-muted);
  border-radius: var(--radius-sm); cursor: pointer;
}
.app-burger:hover { background: var(--hover-veil); color: var(--text-strong); }
.app-brand-mark { display: flex; align-items: center; gap: 9px; min-width: 0; text-decoration: none; }
.app-brand-mark img { width: 36px; height: 36px; object-fit: contain; flex-shrink: 0; }
.app-brand-text { display: flex; flex-direction: column; line-height: 1; min-width: 0; }
.app-brand-text strong { font-family: var(--font-display); font-weight: 700; font-size: 15px; letter-spacing: 0.02em; color: #fff; white-space: nowrap; }
.app-brand-text em { font-family: var(--font-display); font-weight: 600; font-size: 8.5px; font-style: normal; letter-spacing: 0.22em; color: var(--accent-bright); margin-top: 3px; }
.nav-collapsed .app-brand-mark { display: none; }

/* overflow-y:auto 단독이면 overflow-x 가 visible→auto 로 승격돼, 접힘 모드 hover 툴팁(.tip,
   left:calc(100%+8px))의 가로 오버플로가 nav 하단에 가로 스크롤바로 뜬다. x 를 명시적으로 잘라 제거. */
.app-nav { display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; flex: 1; overflow-x: hidden; overflow-y: auto; }
.nav-collapsed .app-nav { padding: 10px 8px; align-items: center; }
.app-group-cap {
  font-family: var(--font-display); font-size: 9.5px; font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-faint);
  padding: 14px 14px 6px;
}
.nav-collapsed .app-group-cap { height: 1px; padding: 0; margin: 10px 12px; background: var(--border-subtle); overflow: hidden; color: transparent; }

/* 외부 뷰어(read-only) — 쓰기 메뉴/빈 그룹 캡션 숨김. body.viewer-mode 는 auth.loadMe 가 토글. */
body.viewer-mode [data-viewer-hidden="1"] { display: none !important; }

.app-nav-item {
  position: relative; display: flex; align-items: center; gap: 12px;
  height: 40px; padding: 0 14px; text-decoration: none; cursor: pointer;
  border-radius: var(--radius-md); color: var(--text-muted);
  font-family: var(--font-body); font-size: 14px; font-weight: 500;
  transition: background var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out);
}
.app-nav-item .ico { display: inline-flex; flex-shrink: 0; }
.app-nav-item .tip { display: none; }
.app-nav-item:hover { background: var(--hover-veil); color: var(--text-strong); }
.app-nav-item.active { background: var(--accent-soft); color: var(--accent-bright); font-weight: 600; }
.app-nav-item.active::before {
  content: ""; position: absolute; left: 0; top: 9px; bottom: 9px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--accent-bright); box-shadow: 0 0 8px var(--accent-bright);
}
.nav-collapsed .app-nav-item { width: 40px; padding: 0; justify-content: center; }
.nav-collapsed .app-nav-item .lbl { display: none; }
.nav-collapsed .app-nav-item .tip {
  display: block; position: absolute; left: calc(100% + 8px); top: 50%; transform: translateY(-50%);
  z-index: var(--z-tooltip); padding: 5px 10px; border-radius: var(--radius-sm);
  background: var(--surface-4); color: var(--text-strong); font-size: 12.5px; font-weight: 600;
  white-space: nowrap; box-shadow: var(--shadow); pointer-events: none; opacity: 0; transition: opacity var(--dur-1);
}
.nav-collapsed .app-nav-item:hover .tip { opacity: 1; }

.app-sidebar-foot { padding: 10px 16px 14px; border-top: 1px solid var(--border-subtle); }
.nav-collapsed .app-sidebar-foot { display: none; }

/* admin 그룹은 권한 있을 때만(body.is-admin) — 기본 숨김 */
.app-group-cap[data-admin="1"], .app-nav-item[data-admin="1"] { display: none; }
body.is-admin .app-group-cap[data-admin="1"] { display: block; }
body.is-admin .app-nav-item[data-admin="1"] { display: flex; }
body.is-admin.nav-collapsed .app-group-cap[data-admin="1"] { display: block; }

/* 코드 관리 = 로그인한 모든 사용자(admin·operator) 노출(body.is-codeadmin 은 shell-nav 가 항상 설정, 2026-07-12).
   '관리' 그룹 캡션은 기본 admin 전용이라, 코드 관리만 보는 operator 에게도 캡션을 보여 항목이 붕 뜨지 않게 한다.
   (계정 관리 항목은 data-admin 이라 operator 에겐 계속 숨김.) */
.app-nav-item[data-codeadmin="1"] { display: none; }
body.is-codeadmin .app-nav-item[data-codeadmin="1"] { display: flex; }
body.is-codeadmin .app-group-cap[data-admin="1"] { display: block; }
body.is-codeadmin.nav-collapsed .app-group-cap[data-admin="1"] { display: block; }

/* 템플릿 관리 = 'admin' + 운영 계정(seongnamfc) 노출(body.is-tpladmin) — 제작 그룹 소속. */
.app-nav-item[data-tpladmin="1"] { display: none; }
body.is-tpladmin .app-nav-item[data-tpladmin="1"] { display: flex; }

/* ---- Header ---- */
.app-header {
  height: var(--topbar-h); flex-shrink: 0; display: flex; align-items: center; gap: 14px;
  padding: 0 18px; background: var(--surface-1); border-bottom: 1px solid var(--border-subtle);
}
.app-head-left { flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; }
.app-titleblock { display: flex; flex-direction: column; justify-content: center; gap: 1px; min-width: 0; }
.app-title { margin: 0; font-family: var(--font-display); font-size: 17px; font-weight: 700; letter-spacing: -0.01em; color: var(--text-strong); white-space: nowrap; line-height: 1.15; }
.app-subtitle { margin: 0; font-size: 11.5px; font-weight: 500; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.2; }
@media (max-width: 760px) { .app-subtitle { display: none; } }
.app-head-right { display: flex; align-items: center; gap: 12px; }
.app-head-sep { width: 1px; height: 22px; background: var(--border-default); }
.app-clock { font-family: var(--font-mono); font-size: 12.5px; color: var(--text-muted); letter-spacing: 0.02em; }

/* 헤더 녹화 클러스터: '녹화 시작' 단축 버튼 + '녹화중 · N CAM' pill(전 페이지 공통) */
.app-rec-cluster { display: flex; align-items: center; gap: 10px; }
.app-rec-start {
  display: inline-flex; align-items: center; gap: 7px; height: 34px; padding: 0 14px;
  border-radius: 99px; background: var(--rec); color: #fff; border: 0;
  font-family: var(--font-display); font-size: 13px; font-weight: 700; text-decoration: none;
  cursor: pointer; box-shadow: 0 1px 8px rgba(255, 60, 60, 0.25); white-space: nowrap;
}
.app-rec-start:hover { filter: brightness(1.08); }
.app-rec-start.is-recording { background: var(--surface-3); color: var(--text-muted); box-shadow: none; }
.app-rec-pill {
  display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 11px;
  border-radius: 99px; background: var(--rec-soft); color: #ff8a8a;
  font-family: var(--font-display); font-size: 12px; font-weight: 700; letter-spacing: 0.02em; white-space: nowrap;
  text-decoration: none; cursor: pointer; /* 링크(녹화 화면 바로가기)로 동작 */
}
.app-rec-pill:hover { background: color-mix(in srgb, var(--rec, #e5484d) 26%, transparent); color: #ffb3b3; }
.app-rec-pill[hidden] { display: none; }
/* mp4 생성중 pill — 녹화중(빨강)과 구분되게 주황(진행중). 클릭 → 원본 화면. */
.app-mp4-pill { background: color-mix(in srgb, #f59e0b 18%, transparent); color: #ffce7a; }
.app-mp4-pill:hover { background: color-mix(in srgb, #f59e0b 28%, transparent); color: #ffe0a8; }
.app-rec-pill svg { animation: rec-blink 1.4s ease-in-out infinite; }
@keyframes rec-blink { 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) { .app-rec-pill svg { animation: none; } }
@media (max-width: 700px) { .app-rec-start span { display: none; } }

/* WS pill: 작은 점 + 라벨 */
#wsState.conn {
  display: inline-flex; align-items: center; gap: 6px; min-width: 0;
  padding: 0 4px; border: none; background: none; font-size: 11.5px; font-weight: 600; color: var(--text-muted);
}
#wsState.conn::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--text-faint); }
#wsState.conn.on::before { background: var(--success); box-shadow: 0 0 6px var(--success); }
#wsState.conn.wait::before { background: var(--gold); }
#wsState.conn.off::before { background: var(--rec); }
/* WS 표시등은 실제 연결(on/연결중)일 때만 노출 — 연결 안 된(off) idle 화면(경기준비·대시보드
   ·설정 등)에선 숨겨 헤더를 깔끔하게. 헤더 기본 class 가 'conn off' 라 평소엔 보이지 않는다. */
#wsState.conn.off { display: none; }

/* 계정 드롭다운 */
.app-account { position: relative; }
.app-account-btn {
  display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 8px 0 6px;
  border-radius: 99px; background: transparent; border: 1px solid var(--border-subtle);
  cursor: pointer; color: var(--text-default);
}
.app-account-btn:hover { background: var(--surface-3); }
.app-avatar {
  display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px;
  border-radius: 50%; background: var(--accent-soft); color: var(--accent-bright);
  font-family: var(--font-display); font-weight: 700; font-size: 12px;
}
.app-account-name { font-size: 13px; font-weight: 600; }
.app-account-menu {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: var(--z-overlay);
  width: 220px; padding: 6px; background: var(--surface-2); border: 1px solid var(--border-default);
  border-radius: var(--radius-lg); box-shadow: var(--shadow);
}
.app-account-menu[hidden] { display: none; }
.app-menu-row {
  display: flex; align-items: center; gap: 10px; width: 100%; height: 36px; padding: 0 10px;
  border: none; background: transparent; border-radius: var(--radius-sm); cursor: pointer;
  color: var(--text-default); font-size: 13px; font-weight: 500; font-family: var(--font-body);
  text-align: left; text-decoration: none;
}
.app-menu-row:hover { background: var(--hover-veil); }
.app-menu-row.danger { color: var(--rec); }
.app-menu-div { height: 1px; background: var(--border-subtle); margin: 4px 0; }

/* ---- 편집기 전체화면(크롬 숨김) ---- */
.app-shell.chrome-hidden .app-sidebar,
.app-shell.chrome-hidden .app-header { display: none; }

/* ---- 반응형: <768px 드로어 ---- */
.nav-drawer .app-sidebar {
  position: fixed; left: 0; top: 0; bottom: 0; z-index: var(--z-modal);
  width: var(--sidebar-w); box-shadow: var(--shadow); transform: translateX(-100%);
}
.nav-drawer:not(.nav-collapsed) .app-sidebar { transform: translateX(0); }

/* ---- 하단 시스템 리소스 바 (statusbar.js — 실 /api/system 데이터, SFC Vision 룩) ----
   우측 정렬 + 메트릭별 고정 폭 → 값이 갱신돼도(3초 폴링) 텍스트가 흔들리지 않는다. */
#statusbar {
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: flex-end; gap: 12px;
  height: 26px; padding: 0 20px;
  background: var(--surface-1); border-top: 1px solid var(--border-subtle);
  font-family: var(--font-mono); font-size: 10.5px; color: var(--text-muted);
  white-space: nowrap; overflow: hidden;
}
#statusbar .sb-item { display: inline-flex; align-items: center; gap: 5px; flex-shrink: 0; }
/* 메트릭별 고정 슬롯(흔한 렌더 worst-case 폭). 값이 좌측 정렬로 슬롯 안에서만 자라 이웃을 밀지
   않는다. 과거엔 드물게만 나오는 폭(GPU VRAM 폴백 등)까지 상시 예약해 여백이 컸다 → 흔한 케이스
   기준으로 좁히고, 드문 폭은 슬롯을 잠깐 넘겨 좌측 이웃만 미세 이동(허용). */
#statusbar .sb-item:nth-child(1) { min-width: 68px; }    /* CPU */
#statusbar .sb-item:nth-child(2) { min-width: 162px; }   /* RAM + GB */
#statusbar .sb-item:nth-child(3) { min-width: 80px; }    /* GPU(util만; VRAM 폴백은 슬롯 초과 허용) */
#statusbar .sb-item:nth-child(4) { min-width: 290px; }   /* 네트워크(↓↑ 처리율이 매 폴링 변동 → 넉넉히) */
#statusbar .sb-item:nth-child(5) { min-width: 196px; }   /* 디스크 */
/* 퍼센트 값은 우측정렬 고정 폭(9.2% ↔ 100.0% 자릿수 변화에도 라벨/이웃 불변). */
#statusbar .num { display: inline-block; text-align: right; min-width: 3.6em; }
#statusbar .sb-label {
  font-family: var(--font-display); font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; color: var(--text-faint);
}
#statusbar .num { color: var(--text-default); font-weight: 600; font-variant-numeric: tabular-nums; }
#statusbar .num.ok { color: var(--success); }
#statusbar .num.warn { color: var(--gold); }
#statusbar .num.hot { color: var(--rec); }
#statusbar .sb-dim { color: var(--text-faint); }

/* ============================================================
   SFC Vision 컴포넌트 폴리시 (추가형 — 기존 레이아웃 비파괴)
   ============================================================ */
/* 카드/패널 — 전 화면 통일 카드(surface-2 · 가시 보더 · radius-lg · 인셋 헤어라인).
   화면별 CSS(settings .card / 전역 .panel / recordings·admin .panel)가 제각각이던 것을
   하나의 룩으로 수렴시킨다. */
.surface-card, .panel, .metric, .toolbar, .card {
  background: var(--surface-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--inset-hairline);
}
.panel, .card { padding: 18px; }
/* 패널/카드 헤더 — 제목(Rajdhani) + 우측 액션, 통일된 간격. */
.panel-head, .card-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 14px;
}
.panel-head h1, .panel-head h2, .card-head h1, .card-head h2,
.panel > h1:first-child, .card > h2:first-child {
  margin: 0; font-family: var(--font-display); font-weight: 700;
  font-size: 16px; letter-spacing: 0.01em; color: var(--text-strong);
}
/* 버튼 — 대문자 Rajdhani(라틴), 누름 = 기계식 키감(translateY 1px). 한글 라벨은 그대로. */
.btn { letter-spacing: 0.02em; }
.btn:active:not(:disabled), .icon-btn:active:not(:disabled) { transform: translateY(1px); }
/* 배지/뱃지 — pill. */
.badge, .conn, .session-badge, .tag { border-radius: var(--radius-pill); }
/* 입력/셀렉트 — 컨트롤 표면 + 인디고 포커스 헤일로. */
input, select, textarea { background: var(--surface-4); border-color: var(--border-strong); color: var(--text-default); }
input:focus, select:focus, textarea:focus, button:focus-visible {
  outline: none; border-color: var(--accent-bright);
  box-shadow: 0 0 0 2px var(--surface-app), 0 0 0 4px var(--accent-ring);
}
/* 토스트 — 인디고 강조 바. */
.toast { background: var(--surface-2); border-color: var(--border-default); border-left-color: var(--accent); }

.surface-card,
.metric,
.panel,
.toolbar {
  background: var(--surface-2);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--inset-hairline);
}

.video-16x9 {
  position: relative;
  display: grid;
  place-items: center;
  width: min(100%, calc((100dvh - var(--topbar-h) - 96px) * 16 / 9));
  max-width: 100%;
  aspect-ratio: 16 / 9;
  margin-inline: auto;
  overflow: hidden;
  color: var(--dim);
  background: var(--stage-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.video-16x9 > video,
.video-16x9 > iframe,
.video-16x9 > img,
.video-16x9 > .live-embed {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

.video-16x9 > video,
.video-16x9 > img {
  object-fit: cover;
}

.dashboard-view {
  display: grid;
  gap: 16px;
  align-items: start;
}

.summary-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(140px, 1fr));
  gap: 12px;
}

.metric {
  padding: 16px;
}

.metric strong {
  display: block;
  margin-top: 6px;
  font-size: 26px;
}

.toolbar {
  margin: 16px 0;
  padding: 12px;
}

.dashboard-view .toolbar,
.dashboard-view .clips-panel {
  margin: 0;
}

.toolbar label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.workspace {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(320px, 0.8fr);
  gap: 16px;
}

.dashboard-view .workspace {
  align-items: start;
}

.dashboard-view .workspace > .panel {
  min-height: 0;
}

.panel {
  min-width: 0;
  padding: 16px;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

h1 {
  margin: 0;
  font-size: 18px;
}

.camera-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 12px;
}

.camera-card,
.clip-card,
.event-item {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.camera-card,
.clip-card {
  padding: 14px;
}

.preview {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  margin-bottom: 12px;
  color: var(--dim);
  background:
    linear-gradient(135deg, rgba(91, 200, 255, 0.16), transparent),
    var(--stage-bg);
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  overflow: hidden;
}

/* 유튜브 라이브 임베드 — 검은 박스 자리를 영상이 채운다(순수 iframe, 외부 JS 0). */
.preview iframe.live-embed,
.preview-box iframe.live-embed {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  border-radius: var(--radius-sm);
}

.row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.progress {
  height: 8px;
  overflow: hidden;
  margin: 10px 0;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 99px;
}

.progress div {
  height: 100%;
  background: var(--accent);
}

.event-feed {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 560px;
  overflow: auto;
}

.dashboard-view .event-feed {
  max-height: min(560px, calc(100vh - 260px));
}

.event-item {
  padding: 10px;
  border-left: 4px solid var(--info);
}

.event-item.clip { border-left-color: var(--ok); }
.event-item.recorder { border-left-color: var(--work); }
.event-item.ok { border-left-color: var(--ok); }
.event-item.work { border-left-color: var(--work); }
.event-item.info { border-left-color: var(--info); }
.event-item.error { border-left-color: var(--danger); }
.event-detail { margin-top: 4px; font-size: 13px; color: var(--dim); line-height: 1.4; }

.clips-panel {
  margin-top: 16px;
}

.clip-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 12px;
}

/* 카드가 grid 트랙을 넘기지 않게(min-width:auto 해제) + 긴 파일경로/제목(clips/xxxx_cam-….mp4
   처럼 공백 없는 토큰)이 카드 밖으로 새지 않고 줄바꿈되게. */
.clip-card {
  min-width: 0;
  overflow-wrap: anywhere;
}

.clip-card h2 {
  margin: 10px 0 8px;
  font-size: 17px;
}

.clip-meta,
.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.clip-actions {
  /* 2열 균등 그리드 — 버튼 4개가 2×2 로 같은 폭(좁은 카드도 카드 안 수용·정렬 일치).
     버튼 수가 2개뿐인 카드는 1행으로 자연 배치(빈 셀 무해). */
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  margin-top: 12px;
}

.clip-actions .btn {
  min-width: 0;        /* 그리드 셀이 트랙을 넘기지 않게(기본 min-width:auto 넘침 차단) */
  white-space: nowrap; /* 라벨("재생·정밀컷" 등)은 한 줄로 — 절반 폭 확보로 안 잘림 */
}

.inline-error {
  color: var(--danger);
  font-size: 12px;
}

.empty {
  color: var(--muted);
  padding: 24px;
  text-align: center;
}

.toast-host {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  display: grid;
  justify-items: center;
  gap: 8px;
  z-index: 1100;   /* cp-modal 오버레이(1000) 위에도 보이게 — 저장 토스트가 모달 뒤로 가던 문제 */
}

/* 공용 중앙 토스트(ClipperStudioToast) — '완료' 류 알림을 화면 가운데 위쪽에 팝업으로 통일.
   전 페이지 공용(styles.css 전역 로드). 디자인 토큰만 사용. */
.cs-toast-host {
  position: fixed; top: 16%; left: 50%; transform: translateX(-50%);
  display: grid; justify-items: center; gap: 8px;
  z-index: var(--z-toast, 900); pointer-events: none;
}
.cs-toast {
  min-width: 200px; max-width: min(440px, calc(100vw - 32px));
  padding: 13px 20px; border-radius: 10px; text-align: center;
  background: var(--surface-2); border: 1px solid var(--border-default);
  border-left: 4px solid var(--accent); box-shadow: var(--shadow);
  color: var(--text-strong); font-size: 14px; font-weight: 600; line-height: 1.4;
  animation: cs-toast-in .18s ease-out;
}
.cs-toast.ok { border-left-color: var(--success); }
.cs-toast.error { border-left-color: var(--rec); }
@keyframes cs-toast-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }

.toast {
  width: min(360px, calc(100vw - 32px));
  padding: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 8px;
  box-shadow: var(--shadow);
}

@media (max-width: 900px) {
  .topbar,
  .workspace {
    display: block;
  }

  .topbar-actions {
    margin-top: 10px;
  }

  .summary-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .panel + .panel {
    margin-top: 16px;
  }
}

/* === ui-complete 추가(추가만, 기존 규칙 불변): 네비·미디어·렌디션·프리뷰 === */
.topnav {
  display: flex;
  gap: 4px;
}

.topnav a {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0 14px;
  color: var(--muted);
  text-decoration: none;
  border: 1px solid transparent;
  border-radius: 6px;
  font-weight: 700;
}

.topnav a:hover {
  color: var(--text);
  background: var(--surface-2);
}

.topnav a.active {
  color: var(--accent);
  border-color: var(--border);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}

.import-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 12px;
  margin-bottom: 12px;
}

.import-grid .row {
  display: flex;
  gap: 8px;
}

.import-grid .row input {
  flex: 1;
}

.upload-panel {
  display: grid;
  gap: 6px;
  margin-top: 10px;
  padding: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.upload-panel[hidden] {
  display: none;
}

.upload-summary strong {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.upload-progress {
  margin: 4px 0;
}

.upload-progress div {
  transition: width 0.18s ease;
}

.upload-detail {
  color: var(--muted);
  font-size: 12px;
}

.media-shell {
  display: grid;
  gap: 16px;
  align-items: start;
}

.media-shell > .panel {
  min-width: 0;
}

.media-console {
  display: grid;
  gap: 12px;
  align-content: start;
}

.media-console .mark-fields {
  margin-top: 0;
}

.session-badge {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  padding: 0 9px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 700;
}

.session-badge.idle {
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--border);
}

.session-badge.armed {
  color: var(--ok);
  background: color-mix(in srgb, var(--ok) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--ok) 36%, transparent);
}

.mark-btn.instant {
  display: grid;
  justify-items: start;
  gap: 2px;
  min-height: 64px;
  padding: 12px 16px;
}

.mark-btn.instant small {
  color: var(--on-accent);
  opacity: 0.82;
}

.mark-result {
  min-height: 34px;
  padding: 8px 10px;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}

@media (min-width: 1100px) {
  .media-shell {
    grid-template-columns: minmax(0, 1.55fr) minmax(320px, 0.85fr);
  }

  .media-shell > .panel:first-child {
    grid-column: 1 / -1;
  }

  .media-shell > .panel:nth-child(2) {
    grid-column: 1;
    grid-row: 2 / span 2;
  }

  .media-shell > .media-console {
    grid-column: 2;
    grid-row: 2;
  }

  .media-shell > .panel:nth-child(4) {
    grid-column: 2;
    grid-row: 3;
  }
}

.media-card {
  cursor: pointer;
}

.media-card.selected {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.rendition-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--border);
}

.preview-box {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 9;
  margin-bottom: 10px;
  color: var(--dim);
  background: var(--stage-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.replay-list {
  display: flex;
  flex-direction: column;
  gap: 4px;
  max-height: 240px;
  overflow: auto;
}

/* 카메라 관리(admin) — 추가 폼 + 목록 */
.toolbar label.grow { flex: 1 1 280px; }
.toolbar label.grow input { width: 100%; }
.camera-admin-list { display: grid; gap: 8px; margin-top: 12px; }
.camera-admin-row {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 12px; border: 1px solid var(--border, #2a2f3a); border-radius: 8px;
}
.camera-admin-row .url { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; opacity: .8; }

/* ClipperStudioPlayer — 커스텀 프레임 플레이어 모달 */
.cp-overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(0,0,0,.72);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.cp-overlay[hidden] { display: none; }
.cp-modal {
  width: min(960px, 96vw, calc((100dvh - 220px) * 16 / 9)); max-height: 94vh; overflow: auto;
  background: var(--surface, #0e131c); border: 1px solid var(--border); border-radius: 12px;
  padding: 16px; display: grid; gap: 10px;
}
.cp-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.cp-x { background: none; border: 0; color: var(--muted); font-size: 18px; cursor: pointer; }
/* 제목 + 이름변경 입력/펜슬 — 좌측에서 한 그룹으로 묶어 길어져도 actions 와 겹치지 않게. */
.cp-title-wrap { display: inline-flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 auto; }
.cp-title-wrap #cpTitle { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cp-title-input { flex: 1 1 auto; min-width: 0; max-width: 360px; background: var(--surface-2); color: var(--text);
  border: 1px solid var(--accent); border-radius: 6px; padding: 4px 8px; font-size: 14px; }
.cp-rename { background: none; border: 1px solid var(--border); color: var(--muted); border-radius: 6px;
  cursor: pointer; padding: 2px 7px; font-size: 13px; line-height: 1.4; flex: 0 0 auto; }
.cp-rename:hover { color: var(--text); border-color: var(--accent); }
.cp-stage {
  position: relative;
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: var(--stage-bg);
  border-radius: var(--radius-md);
}
.cp-stage video {
  display: block;
  width: 100%;
  height: 100%;
  /* contain — 세로(9:16) 클립도 잘리지 않고 전체가 보이게(stage 안에서 레터박스).
     이전 cover 는 9:16 영상을 16:9 로 잘라 확대해 엉뚱한 윗부분만 보였다(편집 미리보기와 불일치). */
  object-fit: contain;
}
/* 영상 좌하단 카메라명 라벨 — 제목에서 분리(멀티캠 타일 라벨과 동일 톤). */
.cp-cam-label {
  position: absolute; left: 10px; bottom: 10px; z-index: 2; pointer-events: none;
  padding: 3px 10px; border-radius: 6px; font-size: 12.5px; font-weight: 600;
  color: #fff; background: rgba(0, 0, 0, .55);
}
/* 세로(9:16) 클립: stage 종횡비를 영상에 맞춰 전환(player.js loadedmetadata 토글). 16:9 고정이면
   세로 영상이 작은 strip 으로만 보임 → 9:16 stage(높이 기준·중앙)로 키워 편집 미리보기처럼 표시. */
.cp-stage.video-9x16 {
  width: auto;
  height: min(70vh, 560px);
  aspect-ratio: 9 / 16;
  max-width: 100%;
  margin-inline: auto;
}

/* 태그 편집 전용 모달(mark.js 최근클립 "재생·정밀컷"): 영상은 순수 확인용(축소·오버레이 0),
   편집용 컨트롤(정밀컷·IN/OUT·"이 구간으로 자르기"·프레임/이동)은 전부 숨기고
   태그 편집 패널(이벤트/선수/위치)만 영상 아래 블록으로. :has(.cp-edit-panel) 스코프로만 —
   편집 패널 없는 일반 재생 모달(아카이브·대시보드)은 정밀컷·IN/OUT 그대로(무영향). */
/* 2열 배치(dykim 최종): 왼쪽=영상+시크바+재생+위치(피치) / 오른쪽=이벤트+선수+저장.
   .cp-edit-panel·.cp-edit-grid 는 display:contents(mark.css)라 내부 필드가 .cp-modal 그리드
   아이템이 된다. 제목(.cp-head)은 상단 전체, 각 항목은 아래 grid-column 으로 좌/우 분배. */
.cp-modal:has(.cp-edit-panel) {
  width: min(1080px, 96vw); /* 16:9 영상 전용 폭 계산 해제 — 2열 폭 */
  grid-template-columns: minmax(0, 1.4fr) minmax(300px, 1fr);
  column-gap: 16px;
  align-content: start;
}
/* 제목은 상단 전체 폭. 좌/우 항목은 grid-column·grid-row 를 명시 배치(혼합 자동배치 비결정성
   회피). 숨김 항목(.cp-time·.cp-marks·#cpStatus)은 display:none 이라 레이아웃에서 빠진다. */
.cp-modal:has(.cp-edit-panel) > .cp-head { grid-column: 1 / -1; grid-row: 1; }
/* 왼쪽 컬럼(col 1): 영상 → 시크바 → 재생 컨트롤 → 위치(피치). */
.cp-modal:has(.cp-edit-panel) > .cp-stage { grid-column: 1; grid-row: 2; }
.cp-modal:has(.cp-edit-panel) > .cp-seek-wrap { grid-column: 1; grid-row: 3; }
.cp-modal:has(.cp-edit-panel) > .cp-controls { grid-column: 1; grid-row: 4; }
.cp-modal:has(.cp-edit-panel) .cp-edit-location { grid-column: 1; grid-row: 5; }
/* 오른쪽 컬럼(col 2): 이벤트 → 선수 → 저장(제목 아래 2행째부터). */
.cp-modal:has(.cp-edit-panel) .cp-edit-events { grid-column: 2; grid-row: 2; }
.cp-modal:has(.cp-edit-panel) .cp-edit-players { grid-column: 2; grid-row: 3 / 5; }
.cp-modal:has(.cp-edit-panel) .cp-edit-actions { grid-column: 2; grid-row: 5; }
/* 뒤 라이브뷰가 비치지 않게 — 편집 모달일 때 오버레이 불투명. */
.cp-overlay:has(.cp-edit-panel) {
  background: rgba(2, 6, 12, .97);
}
/* 영상 16:9 비율 절대 유지 — 왼쪽 컬럼 폭 기준(30vh cap 제거: 왜곡 0). */
.cp-modal:has(.cp-edit-panel) .cp-stage {
  width: 100%;
  aspect-ratio: 16 / 9;
}
/* 영상 컨테이너 내부 오버레이 0 — video 외 절대배치 자식(자르기 버튼 등) 방어 숨김. */
.cp-modal:has(.cp-edit-panel) .cp-stage > *:not(video) {
  display: none;
}
/* 편집용 컨트롤 전체 숨김(정밀컷·IN/OUT·"이 구간으로 자르기"·⚡지금·IN/OUT으로). */
.cp-modal:has(.cp-edit-panel) .cp-marks {
  display: none;
}
/* 확인용엔 불필요 — 시간/프레임 표시·상태줄 숨김. */
.cp-modal:has(.cp-edit-panel) .cp-time,
.cp-modal:has(.cp-edit-panel) #cpStatus {
  display: none;
}
/* 재생 컨트롤 중 편집용(프레임 ±1f·±N초·이동 간격)은 숨기고 재생/소리만 남김(최소 재생). */
.cp-modal:has(.cp-edit-panel) #cpBack1s,
.cp-modal:has(.cp-edit-panel) #cpBackF,
.cp-modal:has(.cp-edit-panel) #cpFwdF,
.cp-modal:has(.cp-edit-panel) #cpFwd1s,
.cp-modal:has(.cp-edit-panel) .cp-controls .cp-step {
  display: none;
}
/* 반응형 폴백: 좁은 화면은 1열 세로 스택(영상→이벤트→선수→위치→저장). */
@media (max-width: 860px) {
  .cp-modal:has(.cp-edit-panel) {
    width: min(560px, 96vw);
    grid-template-columns: 1fr;
  }
  .cp-modal:has(.cp-edit-panel) > .cp-head { grid-column: 1; grid-row: auto; }
  .cp-modal:has(.cp-edit-panel) > .cp-stage,
  .cp-modal:has(.cp-edit-panel) > .cp-seek-wrap,
  .cp-modal:has(.cp-edit-panel) > .cp-controls,
  .cp-modal:has(.cp-edit-panel) .cp-edit-events,
  .cp-modal:has(.cp-edit-panel) .cp-edit-players,
  .cp-modal:has(.cp-edit-panel) .cp-edit-location,
  .cp-modal:has(.cp-edit-panel) .cp-edit-actions { grid-column: 1; }
  /* 세로 순서: 영상(2)→시크(3)→재생(4)→이벤트(5)→선수(6)→위치(7)→저장(8). */
  .cp-modal:has(.cp-edit-panel) > .cp-stage { grid-row: 2; }
  .cp-modal:has(.cp-edit-panel) > .cp-seek-wrap { grid-row: 3; }
  .cp-modal:has(.cp-edit-panel) > .cp-controls { grid-row: 4; }
  .cp-modal:has(.cp-edit-panel) .cp-edit-events { grid-row: 5; }
  .cp-modal:has(.cp-edit-panel) .cp-edit-players { grid-row: 6; }
  .cp-modal:has(.cp-edit-panel) .cp-edit-location { grid-row: 7; }
  .cp-modal:has(.cp-edit-panel) .cp-edit-actions { grid-row: 8; }
}
.cp-seek-wrap { position: relative; display: grid; align-items: center; }
/* 통일 재생바 — 얇은 트랙(4px) + I자(세로 막대) 핸들. 왼쪽 흰색 채움(진행률) + 미채움 반투명
   흰 트랙. 재생하는 모든 화면 공통(공용 플레이어·편집 미리보기·타임라인·클립설정). */
.cp-seek {
  -webkit-appearance: none; appearance: none; width: 100%; height: 16px;
  background: transparent; cursor: pointer; margin: 0;
}
.cp-seek::-webkit-slider-runnable-track {
  height: 4px; border-radius: 999px;
  background: linear-gradient(to right,
    #fff 0%, #fff var(--cp-progress, 0%),
    rgba(255, 255, 255, 0.22) var(--cp-progress, 0%),
    rgba(255, 255, 255, 0.22) 100%);
}
.cp-seek::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 4px; height: 16px; margin-top: -6px;
  border-radius: 2px; background: #fff; border: none; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
.cp-seek::-moz-range-track { height: 4px; border-radius: 999px; background: rgba(255, 255, 255, 0.22); }
.cp-seek::-moz-range-progress { height: 4px; border-radius: 999px; background: #fff; }
.cp-seek::-moz-range-thumb {
  width: 4px; height: 16px; border-radius: 2px; background: #fff; border: none;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
/* 편집 화면 재생바(미리보기·타임라인·클립설정)도 동일 — 얇은 트랙 + I자 핸들. */
.media-preview-seek, .ed-seek, .clipcfg-seek {
  -webkit-appearance: none; appearance: none; width: 100%; height: 16px;
  background: transparent; cursor: pointer; accent-color: #fff; margin: 0;
}
.media-preview-seek::-webkit-slider-runnable-track,
.ed-seek::-webkit-slider-runnable-track,
.clipcfg-seek::-webkit-slider-runnable-track {
  height: 4px; border-radius: 999px; background: rgba(255, 255, 255, 0.22);
}
.media-preview-seek::-moz-range-track,
.ed-seek::-moz-range-track,
.clipcfg-seek::-moz-range-track {
  height: 4px; border-radius: 999px; background: rgba(255, 255, 255, 0.22);
}
.media-preview-seek::-moz-range-progress,
.ed-seek::-moz-range-progress,
.clipcfg-seek::-moz-range-progress {
  height: 4px; border-radius: 999px; background: #fff;
}
.media-preview-seek::-webkit-slider-thumb,
.ed-seek::-webkit-slider-thumb,
.clipcfg-seek::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 4px; height: 16px; margin-top: -6px;
  border-radius: 2px; background: #fff; border: none; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
.media-preview-seek::-moz-range-thumb,
.ed-seek::-moz-range-thumb,
.clipcfg-seek::-moz-range-thumb {
  width: 4px; height: 16px; border-radius: 2px; background: #fff; border: none;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
.ed-seek:disabled { opacity: 0.4; cursor: default; }
.cp-seek-marks {
  position: absolute; inset-inline: 0; top: 50%; height: 12px;
  transform: translateY(-50%); pointer-events: none;
}
.cp-seek-mark {
  position: absolute; top: 1px; height: 10px; min-width: 6px;
  border-radius: 999px; background: var(--muted);
  box-shadow: 0 0 0 1px var(--surface);
  opacity: .8;
  /* host(.cp-seek-marks)는 pointer-events:none(빈 영역이 시크 슬라이더 막지 않게)이라
     개별 마커만 auto 로 되살려 hover 툴팁 + 클릭(시작점 이동·재생)이 동작하게 한다.
     min-width 6px·hover 확대로 짧은 클립도 쉽게 클릭. */
  pointer-events: auto;
  cursor: pointer;
  transition: height .08s ease, top .08s ease, opacity .08s ease;
}
.cp-seek-mark:hover {
  top: -1px; height: 14px; opacity: 1;
  box-shadow: 0 0 0 1px var(--surface), 0 0 0 2px var(--accent);
}
.cp-seek-mark.done {
  background: var(--accent);
  opacity: .95;
}
.cp-seek-mark.pending {
  background: var(--border);
  opacity: .62;
}
/* 현재 지정한 IN/OUT 마커 + 구간 하이라이트(시크바 위). */
.cp-mark-range {
  position: absolute; top: 50%; transform: translateY(-50%); height: 7px;
  background: color-mix(in srgb, var(--accent) 38%, transparent);
  border-radius: 3px; pointer-events: none; z-index: 1;
}
.cp-mark-flag {
  position: absolute; top: 50%; transform: translate(-50%, -50%);
  width: 3px; height: 18px; border-radius: 2px; pointer-events: none; z-index: 2;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .35);
}
.cp-mark-flag.in { background: var(--ok); }
.cp-mark-flag.out { background: var(--danger); }
.cp-mark-flag[hidden], .cp-mark-range[hidden] { display: none; }
/* 타임코드(시크바 오른쪽 인라인) — 모노스페이스, 현재(밝게)/전체(뮤트). */
.cp-time { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; white-space: nowrap; font-size: 13px; color: var(--muted); }
.cp-time #cpCur { color: var(--text); }
.cp-time #cpDur { color: var(--muted); }
.cp-time .cp-sep { color: var(--muted); opacity: .55; }
.cp-time #cpFrame, .cp-time #cpFrame[hidden] { display: none; }
/* 시크 행 — [재생/정지] [시크바(가변폭)] [타임코드] [🔴 LIVE]. */
.cp-seekrow { display: flex; align-items: center; gap: 12px; }
.cp-seekrow .cp-seek-wrap { flex: 1; min-width: 0; }
.cp-seekrow .live-btn { flex: 0 0 auto; }
.cp-seekrow .live-btn[hidden] { display: none; }
/* 보기 구간 토글(최근 5분 / 전체) — 시크 행, 컴팩트. */
.cp-zoom-btn {
  flex: 0 0 auto; font-size: 12px; min-height: 30px; padding: 0 9px;
  border: 1px solid var(--border); color: var(--muted); white-space: nowrap;
}
.cp-zoom-btn:hover { background: var(--surface-2); color: var(--text); }
.cp-zoom-btn[hidden] { display: none; }
/* 플랫 아이콘 버튼(트랜스포트) — 테두리 없는 고스트, hover 시 surface. */
.cp-icon-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 2px;
  min-height: 34px; padding: 0 10px; border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: var(--text); font-size: 13px; line-height: 1; cursor: pointer;
}
.cp-icon-btn:hover { background: var(--surface-2); }
.cp-play-icon {
  flex: 0 0 auto; width: 40px; min-height: 40px; padding: 0; font-size: 15px;
  background: var(--surface-2);
}
.cp-play-icon:hover { background: var(--surface-3, var(--border)); }
.cp-controls { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
/* 길게누르기 가속 배지(버튼 위에 툴팁처럼) — 현재 배속 표시(1초씩·×2·×3·×5). */
.cp-hold-badge {
  position: fixed; z-index: 99999; transform: translate(-50%, -100%);
  background: var(--accent); color: #07121f; font-weight: 800; font-size: 13px;
  padding: 3px 9px; border-radius: 7px; pointer-events: none; white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
}
.cp-hold-badge[hidden] { display: none; }
.cp-controls .btn { min-height: 34px; }
.cp-step { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 12px; }
.cp-step-sec { width: 56px; }
.cp-step-n { font-weight: 700; }
/* number 입력 상하 스피너 화살표 제거(이동 간격·지금 N초). */
.cp-step-sec::-webkit-inner-spin-button,
.cp-step-sec::-webkit-outer-spin-button,
.cp-now-sec::-webkit-inner-spin-button,
.cp-now-sec::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.cp-step-sec, .cp-now-sec { -moz-appearance: textfield; appearance: textfield; }
.cp-now { display: inline-flex; align-items: center; gap: 6px; }
/* ⚡지금(DVR 전용)은 hidden 속성으로 숨긴다. 명시적 display 가 UA [hidden](display:none)
   을 덮어써 무력화되므로 [hidden] 조합 셀렉터로 명시 차단 — VOD/클립 모달 모드 누수 방지. */
.cp-now[hidden] { display: none; }
.cp-now-sec { width: 52px; }
.cp-now-unit { color: var(--muted); font-size: 12px; }
.cp-marks { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; border-top: 1px solid var(--border); padding-top: 10px; }
.cp-seekrow .live-btn,
.cp-marks .live-btn,
.cp-marks .mark-out-btn {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 14%, transparent);
  border-color: color-mix(in srgb, var(--danger) 48%, transparent);
  font-weight: 800;
}
.cp-seekrow .live-btn:hover:not(:disabled),
.cp-marks .live-btn:hover:not(:disabled),
.cp-marks .mark-out-btn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger) 22%, transparent);
  border-color: color-mix(in srgb, var(--danger) 62%, transparent);
}
/* 유튜브식 LIVE — 라이브 엣지+재생 중일 때만 빨강(.at-live). 뒤로 스크럽/정지면 회색(눌러서 엣지로). */
.cp-seekrow .live-btn:not(.at-live) {
  color: var(--muted);
  background: var(--surface-2);
  border-color: var(--border);
  font-weight: 600;
}
.cp-seekrow .live-btn:not(.at-live):hover:not(:disabled) {
  background: var(--hover-veil, rgba(255, 255, 255, 0.08));
  border-color: var(--border);
}
.mark-in-btn {
  color: var(--ok);
  background: color-mix(in srgb, var(--ok) 14%, transparent);
  border-color: color-mix(in srgb, var(--ok) 48%, transparent);
  font-weight: 800;
}
.mark-in-btn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--ok) 22%, transparent);
  border-color: color-mix(in srgb, var(--ok) 62%, transparent);
}
/* OUT 상태(누른 뒤) — 빨강. cp-controls 로 옮긴 토글 버튼이라 전역 선택자로 지정
   (예전 '.cp-marks .mark-out-btn' 스코프는 더 이상 안 닿음). */
.mark-out-btn {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 14%, transparent);
  border-color: color-mix(in srgb, var(--danger) 48%, transparent);
  font-weight: 800;
}
.mark-out-btn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--danger) 22%, transparent);
  border-color: color-mix(in srgb, var(--danger) 62%, transparent);
}
/* IN 토글부터 우측 정렬 — margin-left:auto 가 이동 컨트롤과 'IN·구간표시·클립 버튼' 묶음을
   갈라 오른쪽으로 민다. */
#cpSetMark { margin-left: auto; }
/* 구간 표시(IN·OUT·길이) — 라벨·구분점은 고정, 값만 아래 고정폭 슬롯에 들어간다. */
#cpRange { margin: 0 10px; white-space: nowrap; }
/* 값 슬롯 — 시간(예: 05:38)이 채워져도 폭이 안 변해 좌우 라벨·버튼이 안 밀린다. */
#cpRange .cp-rg-v {
  display: inline-block; min-width: 60px; text-align: right;
  color: var(--text); font-weight: 700;
}
#cpRange #cpRgLen { min-width: 52px; }
/* 추출(인라인) 화면에선 cp-marks(길이 입력 전용)가 비어 빈 줄만 남으므로 숨긴다.
   상세보기 모달(인라인 아님)에선 ✏️ 구간 수정 때 길이 입력을 위해 그대로 노출. */
.cp-inline .cp-marks { display: none; }

/* 단순 재생 모드(cp-simple) — 편집본 보관함처럼 '그냥 플레이어'. 자르기·구간·프레임이동·이름변경·
   묶음 타일·상태줄을 모두 숨기고 재생/시크/시간 + 음소거만 남긴다(음소거는 시크줄 우측 상주). */
.cp-modal.cp-simple .cp-controls,
.cp-modal.cp-simple .cp-marks,
.cp-modal.cp-simple #cpTrimToggle,
.cp-modal.cp-simple #cpRename,
.cp-modal.cp-simple .cp-tiles,
.cp-modal.cp-simple #cpStatus { display: none !important; }
/* view-only 모드(cp-viewonly) — 추출본 아카이브: 편집(자르기·구간·프레임이동·이름변경·구간수정)만
   숨기고 4캠 타일(카메라 전환 리뷰)은 유지. cp-simple 에서 .cp-tiles 제외만 다르다. */
.cp-modal.cp-viewonly .cp-controls,
.cp-modal.cp-viewonly .cp-marks,
.cp-modal.cp-viewonly #cpTrimToggle,
.cp-modal.cp-viewonly #cpRename,
.cp-modal.cp-viewonly #cpStatus { display: none !important; }
.cp-status { color: var(--muted); min-height: 18px; }

/* '클립 만들기' 버튼 옆 추출 상태 배지 — 추출중(앰버)→완료(초록)/실패(빨강). 좌측 전체폭 배너 대체. */
.cp-cut-status {
  font-size: 12px; font-weight: 700; padding: 3px 10px; border-radius: 999px;
  white-space: nowrap; align-self: center;
}
.cp-cut-status[hidden] { display: none; }
.cp-cut-status.working {
  color: #e0a32e;
  background: color-mix(in srgb, #e0a32e 16%, transparent);
  border: 1px solid color-mix(in srgb, #e0a32e 48%, transparent);
}
.cp-cut-status.done {
  color: var(--ok);
  background: color-mix(in srgb, var(--ok) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--ok) 48%, transparent);
}
.cp-cut-status.error {
  color: #e5484d;
  background: color-mix(in srgb, #e5484d 14%, transparent);
  border: 1px solid color-mix(in srgb, #e5484d 48%, transparent);
}

/* 상세보기 모달의 클립 태그(정보) 입력 패널 — 영상 아래. 비어 있으면(다른 모드) 숨김. */
.cp-edit-mount:empty { display: none; }
/* 상세보기 우측 정보 폼 — 영상과 나란한 한 컬럼 수직 스택. 컴팩트 간격으로 무스크롤 수용. */
.cp-cliptags {
  border-top: 1px solid var(--border);
  margin-top: 2px; padding-top: 10px;
  display: flex; flex-direction: column; gap: 9px;
}
.cp-cliptags .field { display: flex; flex-direction: column; gap: 4px; }
.cp-cliptags .field > span { color: var(--muted); font-size: 12px; }
.cp-cliptags select,
.cp-cliptags input { width: 100%; box-sizing: border-box; }
/* 장면설명(서술형) textarea — select/input 폭 규칙이 textarea 를 안 잡아 별도 지정. */
.cp-cliptags textarea { width: 100%; box-sizing: border-box; resize: vertical; min-height: 42px; font: inherit; }
.cp-cliptags textarea.cp-ct-desc { line-height: 1.35; }
/* SNS 게시 체크박스 — 저장 액션 줄 좌측. */
.cp-ct-sns { display: flex; align-items: center; gap: 6px; color: var(--muted); font-size: 12px; cursor: pointer; }
.cp-ct-sns input { width: auto; }
/* 부위 셀렉트와 경기시간을 한 줄(2열)에 둘 때 세로 정렬 맞춤. */
.cp-ct-2col .cp-ct-time { align-self: start; }
/* 종목 고정 표시(축구). */
.cp-ct-top { color: var(--muted); font-size: 12px; }
.cp-ct-top strong { color: var(--text); margin-left: 4px; }
/* 팀·선수 2열. */
.cp-ct-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 10px; }
/* 우측 하단 정렬: 상태 텍스트는 왼쪽, '정보 저장' 버튼은 오른쪽 끝으로. */
.cp-cliptags-actions { display: flex; align-items: center; gap: 10px; margin-top: 6px; justify-content: flex-end; }
.cp-cliptags-actions .btn { flex: 0 0 auto; }
.cp-cliptags-status { color: var(--muted); font-size: 12px; margin-right: auto; }
/* 버튼 스타일 = 편집 화면(.ed .btn)과 동일한 톤(surface-2 + 보더, 밝은 accent 대신). */
.cp-cliptags-actions .btn[data-act="save"] {
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.cp-cliptags-actions .btn[data-act="save"]:hover:not(:disabled) {
  background: var(--hover-veil, rgba(255, 255, 255, 0.08));
  border-color: var(--border);
  filter: none;
}
/* 경기시간(전후반 + 분 + 초) — 좁은 인라인 입력. */
.cp-ct-time > span { color: var(--muted); font-size: 12px; }
.cp-ct-time-row { display: flex; align-items: center; gap: 6px; margin-top: 4px; }
.cp-ct-time-row select { flex: 0 0 auto; width: auto; }
.cp-ct-time-row input { width: 52px; flex: 0 0 auto; text-align: center; }
.cp-ct-time-row .u { color: var(--muted); font-size: 12px; }
.cp-ct-time-row input::-webkit-inner-spin-button,
.cp-ct-time-row input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.cp-ct-time-row input { -moz-appearance: textfield; appearance: textfield; }
/* 위치 — 헤더(라벨 + 선택값 인라인) + 경기장 그래픽. */
.cp-ct-loc { display: flex; flex-direction: column; gap: 6px; }
.cp-ct-loc-head { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 12px; white-space: nowrap; }
.cp-ct-loc-val { margin-left: auto; color: var(--text); font-size: 12px; font-weight: 700; }
/* 세로 하프피치(SVG) — 9분할 존 클릭 선택. xy 는 내부 저장(표시는 L1~L9). */
.cp-pitch {
  width: 100%; max-width: 210px; aspect-ratio: 260 / 200;  /* 가로형 하프코트(폭>길이, 실제 비율) */
  background: linear-gradient(0deg, #1f6b34, #19592b);
  border-radius: 6px; cursor: crosshair; overflow: hidden;
}
.cp-pitch-svg { width: 100%; height: 100%; display: block; }
.cp-pl { fill: none; stroke: rgba(255, 255, 255, .5); stroke-width: 2; }
.cp-pl-goal { stroke: #fff; stroke-width: 3; }
.cp-zone { fill: transparent; stroke: rgba(255, 255, 255, .22); stroke-width: 1; stroke-dasharray: 3 3; cursor: pointer; }
.cp-zone:hover { fill: rgba(255, 255, 255, .08); }
.cp-zone.on { fill: color-mix(in srgb, var(--accent) 22%, transparent); stroke: var(--accent); stroke-dasharray: none; }
.cp-zone-label { fill: rgba(255, 255, 255, .85); font-size: 16px; font-weight: 700; text-anchor: middle; dominant-baseline: middle; pointer-events: none; }
/* 클릭 지점 정밀 점(xy) — 구역(L1~L9)과 함께 실제 찍은 위치를 표시. 밝은 점 + 외곽선 대비. */
.cp-loc-dot { fill: #ffd400; stroke: #1a1a1a; stroke-width: 1.5; pointer-events: none; }

/* 위치·부위 다이어그램 나란히 — 왼쪽 위치(하프피치), 오른쪽 부위(사람 도형 클릭). */
.cp-ct-diagrams { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: 8px 12px; align-items: stretch; }
.cp-ct-diagrams .cp-pitch { max-width: none; }
.cp-ct-body { display: flex; flex-direction: column; gap: 6px; }
.cp-ct-body-val { margin-left: auto; color: var(--text); font-size: 12px; font-weight: 700; }
/* 사람 도형(SVG) — 머리·어깨·몸통·양발 영역 클릭 + 기타(버튼). 왼쪽 피치와 같은 높이로 꽉 채운다.
   .cp-bodymap = 세로 flex(도형 박스 flex:1 + 기타 버튼). 기타 버튼이 잘리지 않게 overflow clip 은
   도형 박스(SVG)에만 두고 컨테이너는 clip 안 함. */
.cp-bodymap {
  flex: 1; display: flex; flex-direction: column; gap: 6px;
  width: 100%; max-width: none; margin: 0; min-height: 150px;
}
.cp-bodymap-svg {
  flex: 1; width: 84%; min-height: 0; display: block;
  background: linear-gradient(0deg, #1f6b34, #19592b); border-radius: 6px;  /* 왼쪽 피치와 같은 초록 필드 */
}
/* 초록 필드 위 선수 실루엣(어두운 회색 채움) + 공 — 장식(클릭 불가). 그 위에 부위 클릭 영역
   = 경기장 존처럼 흰 점선 구분선(선택 시 accent). '경기장 땅바닥처럼' 부위를 구분한다. */
.cp-body-sil { fill: rgba(24, 30, 26, .5); pointer-events: none; }
.cp-body-ball { fill: rgba(255, 255, 255, .9); stroke: rgba(20, 40, 24, .6); stroke-width: 2; pointer-events: none; }
.cp-bpart { fill: transparent; stroke: rgba(255, 255, 255, .32); stroke-width: 1.5; stroke-dasharray: 4 3; cursor: pointer; }
.cp-bpart:hover:not(.disabled) { fill: rgba(255, 255, 255, .12); stroke-dasharray: none; }
.cp-bpart.on { fill: color-mix(in srgb, var(--accent) 40%, transparent); stroke: var(--accent); stroke-width: 3; stroke-dasharray: none; }
.cp-bpart.disabled { fill: transparent; stroke: rgba(255, 255, 255, .1); cursor: default; }
.cp-bpart-label { fill: rgba(255, 255, 255, .96); font-size: 15px; font-weight: 700; text-anchor: middle; dominant-baseline: middle; pointer-events: none; paint-order: stroke; stroke: rgba(0, 0, 0, .45); stroke-width: 3.5; }
.cp-bpart-extra { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; justify-content: center; }
.cp-bpart-btn { font-size: 12px; padding: 3px 10px; border-radius: 999px; border: 1px solid var(--border); background: transparent; color: var(--muted); cursor: pointer; }
.cp-bpart-btn:hover { color: var(--text); border-color: var(--accent); }
.cp-bpart-btn.on { color: var(--text); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 22%, transparent); }
/* 기타(도형 밖 부위) — SVG 필드 안 우측상단 필 버튼(부위 클릭 영역과 같은 점선 스타일). */
.cp-bpart-extra-svg rect { fill: transparent; stroke: rgba(255, 255, 255, .32); stroke-width: 1.5; stroke-dasharray: 4 3; cursor: pointer; }
.cp-bpart-extra-svg:hover rect { fill: rgba(255, 255, 255, .12); stroke-dasharray: none; }
.cp-bpart-extra-svg.on rect { fill: color-mix(in srgb, var(--accent) 40%, transparent); stroke: var(--accent); stroke-width: 3; stroke-dasharray: none; }
.cp-bpart-extra-svg text {
  fill: rgba(255, 255, 255, .96); font-size: 17px; font-weight: 700;
  text-anchor: middle; dominant-baseline: middle; pointer-events: none;
  paint-order: stroke; stroke: rgba(0, 0, 0, .45); stroke-width: 3.5;
}
/* 인스타식 해시태그 칩 입력 — 칩 목록 + 인라인 입력(엔터/콤마로 추가, ×로 삭제). */
.cp-tagchips {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; min-height: 38px;
  padding: 5px 8px; background: var(--surface-4); border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm); box-sizing: border-box;
}
.cp-tagchips:focus-within { border-color: var(--accent-bright); }
.cp-tagchips-list { display: contents; }
.cp-tagchips input { flex: 1 1 90px; min-width: 70px; min-height: 0; padding: 2px; border: none; background: transparent; color: var(--text); outline: none; font: inherit; }
.cp-tagchip {
  display: inline-flex; align-items: center; gap: 3px; padding: 2px 4px 2px 9px; white-space: nowrap;
  border-radius: 999px; background: color-mix(in srgb, var(--accent) 22%, transparent);
  color: var(--text-strong); font-size: 12.5px; font-weight: 600;
}
.cp-tagchip-x {
  display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; padding: 0;
  border: none; border-radius: 50%; background: transparent; color: var(--muted); cursor: pointer; font-size: 14px; line-height: 1;
}
.cp-tagchip-x:hover { color: var(--text-strong); background: rgba(255, 255, 255, .14); }
/* 상세보기(cp-cliptags 태그 패널) — 2열: 왼쪽=영상+타일+시크+재생/자르기, 오른쪽=이벤트/팀/선수/경기시간/위치/저장.
   왼쪽 항목은 col1 에 순서대로 자동배치, 오른쪽 #cpEditMount 는 col2 에 위에서부터 고정(영상과 나란히). */
/* 3열: [큰 영상 | 카메라 타일 세로 | 태그 폼]. 타일을 영상 아래가 아니라 옆 세로열로 빼서
   세로 높이를 줄이고(스크롤 제거) 영상을 키운다. 모달 폭도 넓혀 한 화면에 다 들어오게. */
.cp-modal:has(#cpEditMount .cp-cliptags) {
  width: min(1560px, 97vw);
  grid-template-columns: minmax(0, 2.7fr) 140px minmax(300px, 1fr);
  column-gap: 14px;
  align-content: start;
}
.cp-modal:has(#cpEditMount .cp-cliptags) > .cp-head { grid-column: 1 / -1; }
/* col1 — 큰 영상 + 시크/컨트롤/상태 */
.cp-modal:has(#cpEditMount .cp-cliptags) > .cp-stage,
.cp-modal:has(#cpEditMount .cp-cliptags) > .cp-seekrow,
.cp-modal:has(#cpEditMount .cp-cliptags) > .cp-controls,
.cp-modal:has(#cpEditMount .cp-cliptags) > .cp-marks,
.cp-modal:has(#cpEditMount .cp-cliptags) > #cpStatus { grid-column: 1; }
/* 영상 높이 상한을 올려 폼(오른쪽) 높이에 맞춰 영상이 아래까지 채우게 — 재생바 아래 빈 여백 축소. */
.cp-modal:has(#cpEditMount .cp-cliptags) > .cp-stage { width: 100%; aspect-ratio: 16 / 9; max-height: 62vh; }
/* col2 — 카메라 타일 세로 스택(영상 오른쪽). 스팬을 실제 행 수(2~6)로 제한 — 2/100 은 ~99개
   행을 만들고 행 gap 이 누적돼 모달이 과도하게 높아진다(스크롤 원인). */
.cp-modal:has(#cpEditMount .cp-cliptags) > .cp-tiles {
  grid-column: 2; grid-row: 2 / 5; align-self: start;
  flex-direction: column; flex-wrap: nowrap; gap: 8px; min-width: 0;
}
.cp-modal:has(#cpEditMount .cp-cliptags) .cp-tiles .cp-tile { width: 100%; }
/* col3 — 태그 폼 */
.cp-modal:has(#cpEditMount .cp-cliptags) > #cpEditMount {
  grid-column: 3; grid-row: 2 / 5; align-self: stretch; min-width: 0;
  display: flex; flex-direction: column;
}
/* 상세 모달은 한 화면에 — 영상 옆 세로 타일 + 컴팩트 폼으로 일반 높이에서 모달 내부 스크롤이 안 생긴다. */
.cp-modal:has(#cpEditMount .cp-cliptags) { max-height: 94vh; }
/* 폼이 영상 컬럼 높이만큼 늘어나고(flex:1), '정보 저장'은 margin-top:auto 로 우측 하단 끝에 붙는다. */
.cp-modal:has(#cpEditMount .cp-cliptags) .cp-cliptags { gap: 7px; flex: 1 1 auto; min-height: 0; }
.cp-modal:has(#cpEditMount .cp-cliptags) .cp-cliptags-actions { margin-top: auto; }
/* 상세보기 모달: IN/OUT·자르기(cp-marks)는 ✏️ 구간 수정 때만 노출. 평소엔 영상·시크바·재생만 깔끔하게. */
.cp-modal:has(#cpEditMount .cp-cliptags) .cp-marks { display: none; }
.cp-modal.trim-edit:has(#cpEditMount .cp-cliptags) .cp-marks { display: flex; }
/* 이동 컨트롤(프레임/초 스텝)은 상세 트림에서 제거 — '길이 조절'로 대체. 단, 이동 줄로
   올린 IN 지정·구간표시(cpSetMark·cpRange)는 트림 때 노출해야 하므로 cp-controls 자체는
   보이되 그 안의 이동/프레임 버튼만 숨긴다. */
.cp-modal:has(#cpEditMount .cp-cliptags) .cp-controls { display: none; }
.cp-modal.trim-edit:has(#cpEditMount .cp-cliptags) .cp-controls { display: flex; }
.cp-modal.trim-edit:has(#cpEditMount .cp-cliptags) .cp-controls > .cp-icon-btn,
.cp-modal.trim-edit:has(#cpEditMount .cp-cliptags) .cp-controls > .cp-step { display: none; }
/* 길이 조절(cpLenWrap)은 ✏️ 구간 수정 때 노출 — IN 기준 OUT=IN+길이. */
.cp-modal.trim-edit:has(#cpEditMount .cp-cliptags) #cpLenWrap { display: inline-flex; }
.cp-len { display: inline-flex; align-items: center; gap: 6px; }
.cp-len label { color: var(--muted); font-size: 12px; }
.cp-len .cp-len-sec { width: 64px; }
.cp-len .cp-len-unit { color: var(--muted); font-size: 12px; }
/* 펜슬(구간 수정) 토글 버튼 — 상세보기(cp-cliptags) 모달에서만 노출. */
.cp-head-actions { display: inline-flex; align-items: center; gap: 8px; }
.cp-edit-toggle { display: none; background: none; border: 1px solid var(--border); color: var(--muted);
  border-radius: 6px; padding: 3px 8px; font-size: 12px; cursor: pointer; }
.cp-modal:has(#cpEditMount .cp-cliptags) .cp-head-actions .cp-edit-toggle { display: inline-flex; }
.cp-edit-toggle.on { color: var(--text); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 18%, transparent); }
/* 좁은 화면: 1열 세로 스택(영상→타일(가로)→시크→재생→자르기→태그). */
@media (max-width: 980px) {
  .cp-modal:has(#cpEditMount .cp-cliptags) {
    width: min(560px, 96vw);
    grid-template-columns: 1fr;
  }
  .cp-modal:has(#cpEditMount .cp-cliptags) > .cp-tiles,
  .cp-modal:has(#cpEditMount .cp-cliptags) > #cpEditMount { grid-column: 1; grid-row: auto; }
  .cp-modal:has(#cpEditMount .cp-cliptags) > .cp-tiles { flex-direction: row; flex-wrap: wrap; }
  .cp-modal:has(#cpEditMount .cp-cliptags) .cp-tiles .cp-tile { width: 104px; }
}

/* 보관함 묶음 재생(태그폼 없는 기본 모달) — 영상 좌 + 카메라 타일 세로 우(가로 스트립 대신). */
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) {
  grid-template-columns: minmax(0, 1fr) 150px;
  column-gap: 14px;
  align-content: start;
}
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > .cp-head { grid-column: 1 / -1; }
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > .cp-stage,
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > .cp-seekrow,
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > .cp-controls,
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > .cp-marks,
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > #cpStatus,
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > #cpEditMount { grid-column: 1; }
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) > .cp-tiles {
  grid-column: 2; grid-row: 2 / 6; align-self: start;
  flex-direction: column; flex-wrap: nowrap; gap: 8px; min-width: 0;
}
.cp-modal:has(.cp-tiles:not([hidden])):not(:has(#cpEditMount .cp-cliptags)) .cp-tiles .cp-tile { width: 100%; }

/* 묶음(5캠 등) 상세보기 — 메인 영상 아래 가로 타일 스트립(메인 제외 카메라). 클릭하면 메인 스왑. */
.cp-tiles { display: flex; flex-wrap: wrap; gap: 8px; }
.cp-tiles[hidden] { display: none; }
.cp-tile {
  position: relative; padding: 0; border: 1px solid var(--border); border-radius: 6px;
  overflow: hidden; cursor: pointer; background: var(--stage-bg);
  width: 132px; aspect-ratio: 16 / 9; flex: 0 0 auto;
}
.cp-tile:hover { border-color: var(--accent); }
.cp-tile video { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.cp-tile-label {
  position: absolute; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,.55); color: #fff; font-size: 11px; padding: 2px 6px; text-align: left;
}

/* ClipperStudioPlayer 인라인 모드(마크 화면 미리보기 자리) */
.review-mount:empty { display: none; }
.cp-modal.cp-inline {
  width: 100%; max-height: none; border: 0; padding: 0; box-shadow: none; background: transparent;
}
.cp-modal.cp-inline .cp-head { display: none; }

/* 녹화중 — 빨강 강조(맥동). 종료(초록)·대기와 한눈에 구분. (archive 원본 목록 등) */
.badge.rec {
  color: #fff;
  background: var(--danger, #d3455b);
  animation: badge-rec-pulse 1.6s ease-in-out infinite;
}
@keyframes badge-rec-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--danger, #d3455b) 55%, transparent); }
  50% { box-shadow: 0 0 0 5px color-mix(in srgb, var(--danger, #d3455b) 0%, transparent); }
}

/* ═══════════ 화면 사용법(?) — 전 페이지 공용 ═══════════ */
/* 상단바 ? 버튼 */
.app-help-btn {
  flex: 0 0 auto;
  width: 28px; height: 28px; border-radius: 50%;
  border: 1px solid var(--border, #2a3240);
  background: var(--surface-2, #141922);
  color: var(--muted, #9aa4b2);
  font-weight: 800; font-size: 15px; line-height: 1; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.app-help-btn:hover { color: #fff; border-color: var(--accent, #3b82f6); background: var(--accent, #3b82f6); }

/* 안내 오버레이 — 한 번에 전부: 어두운 배경 + 강조 링 + 화살표 말풍선. */
.tour-all {
  position: fixed; inset: 0; z-index: 4000;
  background: rgba(0, 0, 0, 0.5);
  cursor: pointer;
  animation: tour-fade .12s ease-out;
}
@keyframes tour-fade { from { opacity: 0; } to { opacity: 1; } }
.tour-banner {
  position: fixed; top: 14px; left: 50%; transform: translateX(-50%); z-index: 4003;
  display: inline-flex; align-items: center; gap: 12px;
  background: var(--surface, #0e131c); color: var(--text, #e6e9ef);
  border: 1px solid var(--accent, #3b82f6); border-radius: 999px;
  padding: 8px 8px 8px 16px; font-size: 13px; font-weight: 600;
  box-shadow: 0 8px 30px rgba(0, 0, 0, 0.5);
}
.tour-close-btn {
  border: 0; border-radius: 999px; cursor: pointer;
  background: var(--accent, #3b82f6); color: #fff; font-weight: 700;
  padding: 5px 12px; font-size: 12.5px;
}
.tour-empty {
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 4002;
  background: var(--surface, #0e131c); color: var(--text, #e6e9ef);
  border: 1px solid var(--border, #2a3240); border-radius: 10px;
  padding: 14px 18px; font-size: 14px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
}
/* 강조 링 — 버튼 위치를 어두운 배경 위에서 또렷하게. */
.tour-ring {
  position: fixed; z-index: 4001; pointer-events: none;
  border-radius: 8px;
  border: 2px solid var(--accent, #3b82f6);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25), 0 0 14px rgba(59, 130, 246, 0.55);
  background: rgba(59, 130, 246, 0.06);
}
/* 화살표 말풍선 */
.tour-tip {
  position: fixed; z-index: 4002; pointer-events: none; max-width: 230px;
  background: var(--surface, #0e131c); color: var(--text, #e6e9ef);
  border: 1px solid var(--accent, #3b82f6); border-radius: 9px;
  padding: 8px 11px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.55);
  font-size: 12.5px; line-height: 1.5; font-weight: 500;
}
.tour-tip b { color: var(--accent, #6ea8fe); }
.tour-tip::after { content: ""; position: absolute; width: 0; height: 0; border: 7px solid transparent; }
.tour-tip.place-top::after { bottom: -14px; left: 50%; transform: translateX(-50%); border-top-color: var(--accent, #3b82f6); }
.tour-tip.place-bottom::after { top: -14px; left: 50%; transform: translateX(-50%); border-bottom-color: var(--accent, #3b82f6); }
.tour-tip.place-left::after { right: -14px; top: 50%; transform: translateY(-50%); border-left-color: var(--accent, #3b82f6); }
.tour-tip.place-right::after { left: -14px; top: 50%; transform: translateY(-50%); border-right-color: var(--accent, #3b82f6); }
/* 겹침 해소로 위치가 밀린 말풍선은 화살표 숨김(엉뚱한 방향 가리킴 방지). */
.tour-tip.tour-tip-shifted::after { display: none; }

/* ── 원스톱 편집 모달(onestop.js) — 보관함 이벤트 묶음에서 선택·순서·문구 → 9:16 렌더 ── */
.os-overlay { position: fixed; inset: 0; z-index: 10000; display: flex; align-items: center; justify-content: center; }
.os-overlay[hidden] { display: none; }
.os-backdrop { position: absolute; inset: 0; background: rgba(0, 0, 0, .6); }
/* 모달 크기 고정(가로·세로) — 템플릿(9:16)↔일반(16:9) 전환 등 내용 변화로 늘었다 줄었다 하지 않게. */
.os-modal {
  position: relative; width: min(1360px, 97vw); height: 94vh; display: flex; flex-direction: column;
  background: var(--panel, #12161c); border: 1px solid var(--border, #2a2f3a); border-radius: 12px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, .5); overflow: hidden;
}
.os-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--border, #2a2f3a); }
.os-head strong { font-size: 15px; }
.os-head .os-sub { color: var(--muted, #8b93a1); font-size: 12px; font-weight: 500; margin-left: 6px; }
.os-x { background: none; border: none; color: var(--muted, #8b93a1); font-size: 18px; cursor: pointer; line-height: 1; }
.os-x:hover { color: var(--text, #e6e9ef); }
/* 2열: 좌=큰 미리보기 플레이어(소재/완성본 공용) / 우=클립 선택·순서+문구. 좁으면 1열 스택. */
.os-body {
  padding: 14px 16px; overflow: auto; display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(320px, 1fr);
  gap: 14px; align-items: start;
  flex: 1 1 auto; min-height: 0; /* 모달 고정 높이에서 푸터를 하단에 고정 + 내용만 스크롤 */
}
.os-main { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
/* 플레이어 = 두 모드 공통 고정 높이 스테이지 — 일반(16:9)은 안에서 레터박스(contain),
   템플릿 모드는 같은 높이의 9:16 캔버스. 전환해도 좌열/모달 높이가 변하지 않는다. */
.os-player {
  position: relative; width: 100%; height: min(72vh, 900px); background: #000;
  border: 1px solid var(--border, #2a2f3a); border-radius: 8px; overflow: hidden;
}
/* 영상 클립 박스 — 기본은 플레이어 전체, 템플릿 모드는 JS 인라인(x/y/w/h)로 배치.
   overflow:hidden 이라 줌(transform scale) 시 넘치는 부분이 잘려 렌더의 가운데 크롭과 일치. */
.os-vid-box { position: absolute; inset: 0; overflow: hidden; z-index: 1; }
.os-player video { width: 100%; height: 100%; object-fit: contain; display: block; background: #000; transform-origin: center center; }
.os-player-empty {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--muted, #8b93a1); font-size: 13px;
}
.os-player-empty[hidden] { display: none; }
.os-player-cap { color: var(--muted, #8b93a1); font-size: 12px; min-height: 16px; }
/* 하단 단일 컨트롤 — 재생/일시정지 + 시크바(선택 N개 전체 구간) + 시간 + 음소거 */
.os-ctrl { display: flex; align-items: center; gap: 10px; }
.os-ctrl-play, .os-ctrl-mute {
  flex: 0 0 auto; width: 34px; height: 30px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--border, #2a2f3a); background: var(--panel-2, #171c24); color: var(--text, #e6e9ef);
  display: inline-flex; align-items: center; justify-content: center; font-size: 13px;
}
.os-ctrl-play:hover, .os-ctrl-mute:hover { border-color: var(--accent, #3b82f6); }
.os-ctrl-seek { flex: 1 1 auto; min-width: 0; accent-color: var(--accent, #3b82f6); cursor: pointer; }
.os-ctrl-time { flex: 0 0 auto; color: var(--muted, #8b93a1); font-size: 12px; }
/* 템플릿 모드 — 9:16 합성 미리보기: 영상은 렌더와 동일 밴드(y=656/1920, h=608/1920) 위치,
   그 위에 PNG 프레임(풀캔버스) + 텍스트 칩(슬롯 위치·크기 근사). 렌더 산식과 동일 비율.
   배경=초록 격자(투명 PNG 영역이 비어 보이게 — 검정 PNG 와 구분). */
.os-player.tpl-mode {
  width: auto; aspect-ratio: 9 / 16; height: min(72vh, 900px); margin: 0 auto;
  background: conic-gradient(#1c5c31 0 25%, #123c20 0 50%, #1c5c31 0 75%, #123c20 0);
  background-size: 28px 28px;
}
/* 가로형(16:9) 프레임 — 캔버스도 가로로(폭 기준, 모달 크기는 고정 그대로). */
.os-player.tpl-mode.tpl-wide { width: 100%; height: auto; aspect-ratio: 16 / 9; max-height: min(72vh, 900px); }
.os-player.tpl-mode .os-vid-box { background: #000; }
.os-tpl-frame { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill; pointer-events: none; z-index: 2; }
.os-tpl-frame[hidden] { display: none; }
/* 팬 가능(줌>1/채움) 상태 — 영상 드래그로 보이는 부분 이동 */
.os-vid-box.pannable { cursor: grab; touch-action: none; }
.os-vid-box.pannable:active { cursor: grabbing; }
.os-tpl-hint { grid-column: 1 / -1; color: var(--muted, #8b93a1); font-size: 12px; }
.os-tpl-textlayer { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
.os-tpl-textlayer[hidden] { display: none; }
.os-tpl-text {
  /* pre-line: 문구의 엔터(줄바꿈)를 미리보기에도 그대로 반영(WYSIWYG) — 번인 drawtext 와 동일하게
     블록은 위치(가운데/좌표) 기준, 줄은 좌측 정렬로 세로로 쌓인다. */
  position: absolute; white-space: pre-line; line-height: 1.1; font-weight: 700;
  text-shadow: 0 0 3px rgba(0, 0, 0, .8);
  /* 칩만 포인터 잡기(레이어는 pointer-events:none 통과) — 드래그로 위치 이동. */
  pointer-events: auto; cursor: move; touch-action: none;
  outline: 1px dashed transparent; outline-offset: 3px; border-radius: 2px;
}
.os-tpl-text:hover { outline-color: rgba(96, 165, 250, .85); }
.os-tpl-text.dragging { outline-color: var(--accent, #3b82f6); outline-style: solid; }
/* 템플릿 모드에선 PNG 프레임이 캔버스를 채우므로 빈 안내문 숨김. */
.os-player.tpl-mode .os-player-empty { display: none; }
.os-side { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
@media (max-width: 860px) { .os-body { grid-template-columns: 1fr; } }
.os-clips-head { color: var(--muted, #8b93a1); font-size: 12px; }
.os-clips-head em { font-style: normal; opacity: .8; }
/* 카드 = 가로 2개 그리드(카메라 4대 기준 2×2). 순서 = 체크(클릭)한 순서(번호 배지). */
.os-clips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.os-clip {
  position: relative; border: 1px solid var(--border, #2a2f3a); border-radius: 8px;
  padding: 5px; background: var(--panel-2, #171c24); cursor: pointer; display: flex; flex-direction: column;
}
.os-clip.on { border-color: var(--accent, #3b82f6); background: color-mix(in srgb, var(--accent, #3b82f6) 12%, transparent); }
.os-check { position: absolute; top: 8px; left: 8px; z-index: 5; }
.os-check input { width: 17px; height: 17px; cursor: pointer; }
/* 썸네일이 카드 본문 — 카메라명(상단)·IN/OUT 바(하단)를 오버레이로 얹어 카드 높이를 줄인다. */
.os-thumb-wrap { position: relative; border-radius: 5px; overflow: hidden; }
.os-thumb { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 5px; display: block; background: #000; }
.os-thumb-empty { display: flex; align-items: center; justify-content: center; color: var(--muted, #8b93a1); font-size: 11px; }
/* ▶ 소재 미리보기 — 썸네일 우하단(선택 토글과 별개, 좌측 큰 플레이어에서 재생). */
.os-play {
  position: absolute; right: 4px; bottom: 4px; width: 24px; height: 24px; border-radius: 999px; z-index: 3;
  border: none; background: rgba(0, 0, 0, .62); color: #fff; font-size: 11px; line-height: 1;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.os-play:hover { background: var(--accent, #3b82f6); }
.os-order {
  position: absolute; top: 4px; right: 4px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 999px; z-index: 3;
  background: var(--accent, #3b82f6); color: #fff; font-size: 12px; font-weight: 800;
  display: flex; align-items: center; justify-content: center;
}
/* 메타(카메라명+길이) = 썸네일 상단 오버레이. 클릭은 카드 토글로 통과(pointer-events:none). */
.os-clip-meta {
  position: absolute; top: 0; left: 0; right: 0; z-index: 2; pointer-events: none;
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  padding: 3px 30px 12px 28px;
  background: linear-gradient(to bottom, rgba(0,0,0,.72), rgba(0,0,0,0));
}
.os-cam { font-size: 12px; font-weight: 600; color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,.9); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.os-dur { color: rgba(255,255,255,.85); font-size: 11px; text-shadow: 0 1px 2px rgba(0,0,0,.9); }
/* 클립 적용 구간(IN/OUT) 듀얼 슬라이더 = 썸네일 하단 오버레이. 오른쪽은 ▶ 버튼 자리 비움(34px). */
.os-trim {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;  /* 크롭 박스(z2) 위 — 핸들 드래그 우선 */
  margin: 0; padding: 8px 34px 2px 6px;
  background: linear-gradient(to top, rgba(0,0,0,.72), rgba(0,0,0,0));
}
.os-trim-track { position: relative; height: 6px; border-radius: 3px; background: rgba(255,255,255,.28); margin: 6px 6px; }
.os-trim-fill { position: absolute; top: 0; height: 100%; border-radius: 3px; background: var(--accent, #3b82f6); }
.os-trim-h {
  position: absolute; top: 50%; width: 13px; height: 13px; transform: translate(-50%, -50%);
  background: #fff; border: 2px solid var(--accent, #3b82f6); border-radius: 50%;
  cursor: ew-resize; touch-action: none; box-shadow: 0 1px 3px rgba(0,0,0,.5); z-index: 1;
}
.os-trim-h:hover, .os-trim-h:active { background: var(--accent, #3b82f6); }
.os-trim-lab { text-align: center; color: rgba(255,255,255,.9); font-size: 10px; margin-top: 1px; text-shadow: 0 1px 2px rgba(0,0,0,.9); }
/* 세로 크롭 프레임 — 확대(전역)되면 선택 클립마다 '표시될 부분'을 파란 실선(+바깥 어둡게)으로 표시,
   드래그해 이동. 확대 없으면 숨김. 크기(확대)는 미리보기 휠에서. */
.os-crop-box { position: absolute; z-index: 2; box-sizing: border-box; }
.os-crop-box:not(.cropped) { display: none; }  /* 확대(크롭) 없으면 프레임 숨김(전체 사용) */
.os-crop-box.cropped {
  border: 2px solid var(--accent, #3b82f6); border-radius: 2px; pointer-events: auto; cursor: move; touch-action: none;
  box-shadow: 0 0 0 9999px rgba(0,0,0,.42);  /* thumb-wrap overflow:hidden 이 바깥 그림자를 썸네일로 클립(표시 영역만 밝게) */
}
.os-crop-tag {
  position: absolute; top: 1px; left: 2px; padding: 0 3px; border-radius: 3px; pointer-events: none;
  background: var(--accent, #3b82f6); color: #fff; font-size: 9px; line-height: 1.35; font-weight: 800;
}
.os-texts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.os-field { display: flex; flex-direction: column; gap: 4px; }
.os-field > span { color: var(--muted, #8b93a1); font-size: 12px; }
.os-field input { width: 100%; box-sizing: border-box; }
/* 문구 입력 textarea — 엔터로 여러 줄. 입력칸 모양은 input 과 맞추고 세로 리사이즈만 허용. */
.os-field textarea.os-textin {
  width: 100%; box-sizing: border-box; resize: vertical; min-height: 2.4em;
  font: inherit; line-height: 1.35;
}
/* SNS 슬롯 문구 옆 글자 크기·색상 조절(이번 내보내기만) — 라벨·입력칸·크기/가로/색상을 한 줄로. */
.os-tpl-texts { grid-template-columns: 1fr; }
.os-tpl-slot { display: flex; flex-direction: row; align-items: center; flex-wrap: wrap; gap: 10px; }
.os-tpl-slot > span { flex: 0 0 auto; white-space: nowrap; }
.os-tpl-slot textarea.os-textin { flex: 1 1 160px; width: auto; min-width: 110px; min-height: 2.2em; }
.os-tpl-style { display: flex; gap: 8px; align-items: center; margin-top: 0; flex: 0 0 auto; flex-wrap: wrap; }
.os-tpl-style > label { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; color: var(--muted, #8b93a1); margin: 0; }
.os-tpl-style input[type="number"] { width: 58px; box-sizing: border-box; }
.os-tpl-style .os-pct { font-size: 11px; color: var(--muted, #8b93a1); margin-left: -2px; }
.os-tpl-style input[type="color"] { width: 34px; height: 24px; padding: 0; border: 1px solid var(--border, #2a2f3a); border-radius: 4px; background: none; cursor: pointer; }
/* 텍스트 칩 우측하단 리사이즈 그립 — 드래그로 크기(세로)·가로(가로) 조절. 칩 scaleX 를 상쇄해 정사각 유지. */
.os-tpl-text .os-tpl-grip {
  position: absolute; right: -3px; bottom: -3px; width: 11px; height: 11px;
  background: var(--accent, #3b82f6); border: 1.5px solid #fff; border-radius: 2px;
  cursor: nwse-resize; pointer-events: auto; box-shadow: 0 0 3px rgba(0,0,0,.6);
  opacity: 0; transition: opacity .1s;
}
.os-tpl-text:hover .os-tpl-grip, .os-tpl-text.dragging .os-tpl-grip,
.os-tpl-textlayer.os-resizing .os-tpl-grip { opacity: 1; }
.os-foot { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-top: 1px solid var(--border, #2a2f3a); }
.os-status { font-size: 12px; margin-right: auto; }
.os-status.working { color: #e0a32e; }
.os-status.done { color: var(--ok, #3fb950); }
.os-status.error { color: #e5484d; }
@media (max-width: 560px) { .os-texts { grid-template-columns: 1fr; } }
