:root {
  /* Dark theme is the default — applied unless data-theme="light" is set on
     the html element. The light overrides below swap only the variables
     that change; everything else (radii, sizes, shadows) stays the same. */
  /* 미디엄 다크 — 이전 팔레트는 테두리(#1f232c)가 배경과 거의 같아 카드·표
     경계가 안 보였다. 배경을 한 단계 올리고 테두리 대비를 확실히 키운 값. */
  --bg: #1c2029;
  --surface: #252a35;
  --surface-2: #313846;
  --border: #3d4658;
  --text: #f0f3f8;
  --muted: #a3aebf;
  --accent: #74a3f7;
  --accent-2: #5b8def;
  --danger: #f4707f;
  --success: #52d189;
}

:root[data-theme="light"] {
  --bg: #f4f6fa;
  --surface: #ffffff;
  --surface-2: #eef1f6;
  --border: #d8dde6;
  --text: #1e2230;
  --muted: #6b7280;
  --accent: #3960c2;
  --accent-2: #2d4ea0;
  --danger: #d8394a;
  --success: #28a05e;
}

* { box-sizing: border-box; }

/* Frameless desktop window: html and body must fully cover the window,
   otherwise the WebView2 default canvas (white/black) leaks through at the
   edges. overflow-x: hidden lives on html only — putting it on body turns
   body into its own scroll container, which would trap position:sticky
   inside body instead of letting it stick to the viewport. */
html {
  margin: 0;
  width: 100%;
  height: 100%;
  background: var(--bg);
  overflow: hidden;   /* 스크롤은 main 이 담당한다 (아래 참조) */
}

/* 창 = 헤더(고정) + 본문(스크롤). 페이지 전체를 스크롤하면 스크롤바가 헤더까지
   덮어 창 가장자리에 붙고, 스크롤바가 생길 때마다 헤더 폭이 줄어 제목이 접혔다.
   본문만 스크롤하도록 바꿔 스크롤바를 헤더 아래 영역 안쪽에 둔다. */
body {
  margin: 0;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
  font-family: -apple-system, "Segoe UI", Roboto, "Malgun Gothic", sans-serif;
  color: var(--text);
  line-height: 1.5;
}

/* 본문 스크롤바 — 창 가장자리가 아니라 헤더 아래 콘텐츠 영역 안에 그려진다. */
.tab-pane, .result-info, #format-list {
  /* thin 으로 두면 Chromium 이 ::-webkit-scrollbar 의 width 를 무시하고
     자체 얇은 스크롤바를 그린다. 폭을 직접 정하기 위해 auto 로 둔다. */
  scrollbar-width: auto;
  scrollbar-color: var(--border) transparent;
}
/* 프레임리스 창이라 오른쪽 가장자리 6px 가 리사이즈 영역으로 덮여 있다.
   스크롤바가 얇으면 그 아래 깔려 잡기 어려우므로 넉넉히 준다.
   (막대 자체는 투명 테두리로 얇아 보이게 하되, 잡히는 폭은 14px) */
.tab-pane::-webkit-scrollbar,
.result-info::-webkit-scrollbar,
#format-list::-webkit-scrollbar { width: 14px; }
.tab-pane::-webkit-scrollbar-track,
.result-info::-webkit-scrollbar-track,
#format-list::-webkit-scrollbar-track { background: transparent; }
.tab-pane::-webkit-scrollbar-thumb,
.result-info::-webkit-scrollbar-thumb,
#format-list::-webkit-scrollbar-thumb {
  background: var(--border);
  background-clip: padding-box;
  border: 4px solid transparent;
  border-radius: 7px;
  min-height: 40px;
}
.tab-pane::-webkit-scrollbar-thumb:hover,
.result-info::-webkit-scrollbar-thumb:hover,
#format-list::-webkit-scrollbar-thumb:hover {
  background: var(--muted);
  background-clip: padding-box;
}

header {
  min-height: 52px;   /* 내용에 상관없이 높이를 일정하게 */
  flex-wrap: nowrap;
  padding: 0.6rem 1rem 0.6rem 1.5rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 1rem;
  flex: 0 0 auto;   /* body flex 컬럼의 고정 행 — 스크롤되지 않는다 */
  position: relative;
  z-index: 50;  /* sit above page content but below resize-zone overlays (99999) */
  -webkit-app-region: drag;  /* Frameless window: header acts as the title bar drag region */
  app-region: drag;
  user-select: none;
}

/* Anything interactive inside the header must opt out of dragging. */
header nav,
header .menu-toggle,
header .window-controls,
header button,
header input {
  -webkit-app-region: no-drag;
  app-region: no-drag;
}

.window-controls {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  margin-left: 0.25rem;
}

.win-btn {
  width: 32px;
  height: 28px;
  border: none;
  background: transparent;
  color: var(--text, #ddd);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-radius: 0.3rem;
  padding: 0;
  transition: background 0.12s ease;
}

.win-btn:hover {
  background: var(--surface-2, rgba(255, 255, 255, 0.08));
}

.win-btn.win-close:hover {
  background: #e81123;
  color: #fff;
}

/* Theme toggle — shows the icon for the OPPOSITE mode (the one you'll
   switch to on click). Dark active → sun visible; light active → moon. */
.theme-toggle .theme-icon-sun,
.theme-toggle .theme-icon-moon { display: none; }
:root[data-theme="light"] .theme-toggle .theme-icon-moon { display: inline-block; }
:root:not([data-theme="light"]) .theme-toggle .theme-icon-sun { display: inline-block; }

/* Frameless-window resize zones — overlaid on the edges of the viewport.
   The zones themselves are invisible; only their cursor and mousedown
   handler matter. Kept above content so corners don't get blocked by
   tall scrollable panes. */
.resize-zone {
  position: fixed;
  z-index: 99999;
  background: transparent;
}

header h1 {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0;
  flex-shrink: 0;
  font-size: 1.2rem;
  font-weight: 600;
  flex: 1;  /* push nav to the far right */
  /* 폭이 좁아져도 두 줄로 접히지 않게 — 접히면 헤더 높이가 통째로 커진다.
     넘칠 때는 줄바꿈 대신 말줄임으로 잘라낸다. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* Version label inside the nav. On wide screens nav is inline, so we keep
   it small and muted. In dropdown mode (narrow window) we move it under
   the tabs with a divider — see media query below. */
.nav-version {
  font-size: 0.7rem;
  color: var(--muted);
  padding: 0.12rem 0.55rem;
  align-self: center;
  user-select: none;
  font-family: inherit;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.nav-version:hover {
  color: var(--text);
  border-color: var(--accent);
  background: rgba(127, 127, 127, 0.12);
}

/* On wide screens 매뉴얼/버전 wrapper dissolves into the nav row.
   Narrow widths re-activate it as a flex row with a divider. */
.nav-footer { display: contents; }

nav {
  display: flex;
  gap: 0.5rem;
}

/* Hamburger menu toggle — hidden on desktop, revealed at narrow widths. */
.menu-toggle {
  display: none;
  background: transparent;
  border: 1px solid var(--border);
  padding: 0.4rem 0.55rem;
  border-radius: 6px;
  color: var(--text);
  cursor: pointer;
  align-items: center;
  justify-content: center;
}
.menu-toggle:hover { border-color: var(--accent); }

.tab, .ftab {
  background: transparent;
  color: var(--muted);
  border: 1px solid transparent;
  padding: 0.4rem 0.9rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.tab .tab-icon { flex-shrink: 0; }

.tab:hover, .ftab:hover { color: var(--text); }
.tab.active, .ftab.active {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--border);
}

main {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;   /* 스크롤은 각 탭(.tab-pane)이 담당 */
  /* 창 가장자리는 리사이즈 손잡이 몫으로 비워둔다. 스크롤바가 테두리에 딱
     붙어 있으면 창을 늘리려고 가장자리를 잡을 때 스크롤바가 먼저 잡힌다. */
  margin-right: 8px;
  /* 스크롤 유무와 관계없이 같은 폭을 유지해 내용이 좌우로 흔들리지 않게 */
  scrollbar-gutter: stable;
  padding: 1.25rem 1rem;
  width: 100%;
}

/* 본문 폭 제한은 main 자체가 아니라 내부 래퍼가 맡는다. main 에 margin:auto 를
   주면 스크롤 컨테이너가 좁아져 스크롤바까지 안쪽으로 끌려들어온다. */
main > .tab-pane {
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
}

.tab-pane { display: none; }
/* 기본 탭들은 통째로 스크롤한다 (라이브러리 · 다운로드 현황). */
.tab-pane.active {
  display: block;
  height: 100%;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-gutter: stable;
}
/* 검색 탭만은 페이지를 통으로 굴리지 않는다 — URL 입력은 위에 고정하고
   영상 정보 / 다운로드 설정 두 열이 각각 자기 안에서 스크롤한다. */
#tab-download.active {
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow: hidden;
}
#tab-download > .card:first-child { flex: 0 0 auto; }
#tab-download > #info-card {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  overflow: hidden;
}

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;   /* 각진 느낌 */
  padding: 1.25rem;
  margin-bottom: 1rem;
}

.card h2 {
  margin-top: 0;
  margin-bottom: 1rem;
  font-size: 1.05rem;
}
/* Visual divider between "영상 정보" and "다운로드 설정" sections. */
.info-grid + h2 {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--border);
}

.card h3 {
  font-size: 0.95rem;
  margin: 1.2rem 0 0.6rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.row {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  flex-wrap: wrap;
}

.row.between { justify-content: space-between; }

input[type="text"], select {
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.55rem 0.7rem;
  font-size: 0.95rem;
  flex: 1;
  min-width: 0;
}

select { flex: 0; }

button {
  font-family: inherit;
  font-size: 0.9rem;
  padding: 0.55rem 1rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  cursor: pointer;
  background: var(--surface-2);
  color: var(--text);
}

button.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}
.btn-icon {
  display: inline-block;
  vertical-align: middle;
  flex-shrink: 0;
}
/* Stabilise probe-btn width so it doesn't jump between "검색" and "검색 중" */
#probe-btn { min-width: 110px; }
button.primary:hover { background: var(--accent-2); border-color: var(--accent-2); }
button.ghost { background: transparent; }
button.danger { background: transparent; border-color: var(--danger); color: var(--danger); }
button:disabled { opacity: 0.5; cursor: not-allowed; }

label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  color: var(--muted);
}

.muted { color: var(--muted); }
.small { font-size: 0.85rem; }
.hidden { display: none !important; }

.info-grid {
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 1rem;
  align-items: start;
}
.info-grid img {
  width: 100%;
  border-radius: 6px;
  background: var(--surface-2);
}
#info-desc {
  margin: 0;
  white-space: pre-wrap;
  word-break: break-word;
}
#info-desc.clamp {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Expanded ("더 보기"): cap height and scroll inside instead of pushing the page.
   Subtle tinted background so the scroll boundary is visible against the card. */
#info-desc:not(.clamp) {
  max-height: 240px;
  overflow-y: auto;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.7rem 0.85rem;
}

/* Thin scrollbars for in-app scroll containers (Chromium + Firefox) */
#info-desc, .format-options {
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
#info-desc::-webkit-scrollbar,
.format-options::-webkit-scrollbar { width: 6px; height: 6px; }
#info-desc::-webkit-scrollbar-track,
.format-options::-webkit-scrollbar-track { background: transparent; }
#info-desc::-webkit-scrollbar-thumb,
.format-options::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 3px;
}
#info-desc::-webkit-scrollbar-thumb:hover,
.format-options::-webkit-scrollbar-thumb:hover { background: var(--muted); }
.link-btn {
  background: none;
  border: none;
  padding: 0;
  margin-top: 0.35rem;
  color: var(--accent);
  font-size: 0.82rem;
  font-weight: 500;
  cursor: pointer;
}
.link-btn:hover { text-decoration: underline; }

.format-tabs {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.6rem;
}

/* Compact horizontal video/audio toggle (always left-aligned) */
.kind-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1rem;
  flex-wrap: wrap;
  justify-content: flex-start;
}
.kind-tabs .ftab {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 1rem;
  font-size: 0.92rem;
  border: 1px solid var(--border);
  background: var(--surface-2);
  transition: all 0.1s;
}
.kind-tabs .ftab:hover {
  border-color: var(--accent);
  color: var(--text);
}
.kind-tabs .ftab.active {
  background: rgba(91, 141, 239, 0.15);
  border-color: var(--accent);
  color: var(--text);
}
.kind-tabs .ftab-icon {
  color: var(--accent);
  font-size: 0.85rem;
}
.kind-tabs .ftab-label {
  font-weight: 500;
}

.format-list {
  border: 1px solid var(--border);
  border-radius: 6px;
  overflow: hidden;  /* clip rounded corners; no nested scrolling */
}

/* Format groups (accordion: click ext header to expand options) */
.format-group {
  border-bottom: 1px solid var(--border);
}
.format-group:last-child { border-bottom: none; }

.format-group-header {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.7rem 0.95rem;
  cursor: pointer;
  user-select: none;
  transition: background 0.1s;
}
.format-group-header:hover { background: var(--surface-2); }
.format-group.expanded .format-group-header {
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.format-group-header .caret {
  color: var(--muted);
  font-size: 0.7rem;
  width: 12px;
  text-align: center;
}
.format-group-header .group-ext {
  font-weight: 600;
  font-size: 0.95rem;
  text-transform: uppercase;
  color: var(--text);
  letter-spacing: 0.5px;
}
.format-group-header .group-meta {
  margin-left: auto;
  color: var(--muted);
  font-size: 0.78rem;
}

.format-options {
  background: rgba(0, 0, 0, 0.18);
}
/* When a group has more than 10 options, cap the height and scroll inside. */
.format-options.scrollable {
  max-height: 400px;
  overflow-y: auto;
}

/* Column-label header — sticky, visually distinct from the group header. */
.format-row-header {
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--muted);
  cursor: default;
  position: sticky;
  top: 0;
  z-index: 1;
}
.format-row-header:hover { background: var(--bg); }
.format-row-header > span { text-align: center; }
.format-row.format-row-header .col-size { text-align: center; }

/* Custom radio: rounded square, centered within its column. */
.format-row input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  margin: 0;
  border: 1.5px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
  cursor: pointer;
  position: relative;
  transition: background 0.12s, border-color 0.12s;
  justify-self: center;
}
.format-row input[type="radio"]:hover { border-color: var(--accent); }
.format-row input[type="radio"]:checked {
  background: var(--accent);
  border-color: var(--accent);
}
.format-row input[type="radio"]:checked::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 6px;
  height: 6px;
  background: #fff;
  border-radius: 1px;
  transform: translate(-50%, -50%);
}

/* Audio mode panel: 상/중/하 quality choices + output format picker */
.audio-quality {
  background: rgba(0, 0, 0, 0.18);
  border-bottom: 1px solid var(--border);
}
/* Audio tier rows reuse .format-row layout but without the deep left indent. */
.audio-tier-row { padding-left: 0.95rem; }
.audio-tier-row .tier-label {
  text-align: center;
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--text);
}
.audio-tier-row.selected .tier-label { color: var(--accent); }

/* (legacy single-best display, kept for safety if referenced elsewhere) */
.audio-best {
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--border);
}
.audio-format-picker {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.85rem 1rem;
  flex-wrap: wrap;
}
.audio-fmt-buttons {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.audio-fmt-btn {
  padding: 0.35rem 0.85rem;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--muted);
}
.audio-fmt-btn:hover {
  border-color: var(--accent);
  color: var(--text);
}
.audio-fmt-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.format-row {
  display: grid;
  grid-template-columns: 30px 130px 1fr 100px;
  gap: 0.5rem;
  padding: 0.5rem 0.95rem 0.5rem 2.4rem;
  border-bottom: 1px solid var(--border);
  font-size: 0.88rem;
  align-items: center;
  cursor: pointer;
  transition: background 0.1s;
}
.format-options .format-row:last-child { border-bottom: none; }
.format-row:hover { background: var(--surface-2); }
.format-row.selected { background: rgba(91, 141, 239, 0.22); }
.format-row .col-codec { color: var(--muted); font-size: 0.82rem; }
.format-row .col-size { text-align: center; color: var(--muted); }
/* Center-align the resolution column (2nd cell) to match the size column. */
.format-row > span:nth-child(2) { text-align: center; }

/* Library: split view — list on the left, detail on the right (desktop). */
.library-layout {
  display: grid;
  grid-template-columns: 320px 1fr;
  gap: 1.25rem;
  align-items: start;
}
.library-list-col { min-width: 0; }
.library-list-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.85rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--border);
}
.library-list-head h2 { margin: 0; }
.lib-refresh-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.lib-refresh-btn:hover {
  color: var(--text);
  border-color: var(--accent);
  background: rgba(127, 127, 127, 0.12);
}
.lib-refresh-btn:disabled { opacity: 0.5; cursor: default; }
.lib-refresh-btn.spinning svg { animation: lib-spin 0.8s linear infinite; }
@keyframes lib-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}
.library-search {
  width: 100%;
  margin-bottom: 0.7rem;
}
.library-list {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  max-height: 70vh;
  overflow-y: auto;
  padding-right: 0.3rem;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.library-list::-webkit-scrollbar { width: 6px; }
.library-list::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }

/* Compact list-style card (replaces old grid tile). */
.lib-card {
  display: grid;
  grid-template-columns: 110px 1fr auto;
  gap: 0.7rem;
  align-items: center;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.55rem;
  cursor: pointer;
  transition: background 0.1s, border-color 0.1s;
}
.lib-card:hover { border-color: var(--accent); }
.lib-card.active {
  background: rgba(91, 141, 239, 0.18);
  border-color: var(--accent);
}
.lib-card .thumb {
  width: 110px;
  height: 62px;
  aspect-ratio: 16/9;
  border-radius: 4px;
  background: #000;
  object-fit: cover;
}
.lib-card .thumb-placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: #6b7280;
  font-size: 1.25rem;
}
.lib-card .body { min-width: 0; }
.lib-card .body h4 {
  margin: 0;
  font-size: 0.86rem;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text);
}
.lib-card .body p {
  margin: 0.2rem 0 0;
  font-size: 0.72rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Per-row quick actions — save / delete icons on the right side of every
   library card so the user can manage items without opening the detail. */
.lib-card-actions {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  align-items: center;
  justify-content: center;
  padding-right: 0.15rem;
}
.lib-action {
  width: 30px;
  height: 30px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--muted);
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.1s, color 0.1s, border-color 0.1s;
  padding: 0;
}
.lib-action:hover {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text);
}
.lib-action.lib-action-danger:hover {
  border-color: var(--danger);
  color: var(--danger);
}
.lib-action svg { display: block; }

.library-detail-col { min-width: 0; }
.library-detail-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
}
.library-detail-head h3 {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.detail-empty {
  text-align: center;
  padding: 3rem 1rem;
  color: var(--muted);
  font-size: 0.9rem;
}
.mobile-only { display: none; }

/* Mobile accordion detail — inserted directly under the clicked list card.
   Animates open/close via max-height + opacity + spacing transitions. */
.lib-inline-detail {
  display: none;  /* hidden on desktop; revealed via media query */
}
.inline-detail-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-bottom: 0.6rem;
}
.inline-title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.inline-close {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: 0.82rem;
  font-weight: 500;
  padding: 0.35rem 0.7rem;
  line-height: 1;
  flex-shrink: 0;
}
.inline-close svg { flex-shrink: 0; }

/* Two-up grid for the detail action buttons (영상 구간 추출 / 프레임 추출).
   Each button takes exactly half the width regardless of label length so
   the row reads as a clean 2-column toolbar. */
.detail-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  margin: 1rem 0;
}
.detail-actions > button,
.detail-actions > a {
  width: 100%;
  padding: 0.7rem 0.85rem;
  font-size: 0.92rem;
}

/* URL search input wrapper + recent-history dropdown */
.search-input-wrap {
  position: relative;
  flex: 1;
  min-width: 0;
}
.search-input-wrap input[type="text"] {
  width: 100%;
  display: block;
}
.recent-searches {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  max-height: 320px;
  overflow-y: auto;
  z-index: 60;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5);
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.recent-searches.hidden { display: none; }
.recent-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.7rem;
  cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.recent-item:last-of-type { border-bottom: none; }
.recent-item:hover { background: var(--surface-2); }
.recent-thumb {
  width: 64px;
  height: 36px;
  border-radius: 3px;
  background: #000;
  object-fit: cover;
  flex-shrink: 0;
}
.recent-info { min-width: 0; flex: 1; }
.recent-title {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.recent-url {
  font-size: 0.72rem;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-top: 0.15rem;
}
.recent-remove {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 1.1rem;
  line-height: 1;
  padding: 0.2rem 0.45rem;
  cursor: pointer;
  flex-shrink: 0;
}
.recent-remove:hover { color: var(--danger); }
.recent-empty {
  padding: 0.85rem;
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
}
.recent-clear {
  display: block;
  width: 100%;
  text-align: center;
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 0.78rem;
  padding: 0.55rem;
  cursor: pointer;
  border-top: 1px solid var(--border);
}
.recent-clear:hover { color: var(--text); background: var(--surface-2); }

/* Subtle divider between sections — matches the .info-grid + h2 divider. */
.section-divider {
  border: none;
  border-top: 1px solid var(--border);
  margin: 1.5rem 0;
  height: 0;
}

/* Frames section: head + horizontally-scrolling thumbnail row with arrows */
.frames-section { margin-top: 0.6rem; }

.frame-strip {
  display: flex;
  align-items: stretch;
  gap: 0.5rem;
  margin-top: 0.4rem;
}
.frame-strip .frame-grid {
  flex: 1;
  min-width: 0;
  margin-top: 0;
}
.frame-strip-nav {
  flex: 0 0 36px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--muted);
  cursor: pointer;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  transition: all 0.1s;
}
.frame-strip-nav:hover {
  border-color: var(--accent);
  color: var(--text);
  background: var(--surface);
}
.frame-strip-nav:disabled {
  opacity: 0.3;
  cursor: not-allowed;
}
.frame-strip-nav.hidden { display: none; }
/* Frames result card — title + count + ZIP button must stay on one row even
   on narrow screens. The detail-section-head's flex-wrap default would otherwise
   push the [전체 ZIP] button onto a second line. */
.frames-section > .detail-section-head {
  flex-wrap: nowrap;
  gap: 0.5rem;
}
.frames-section > .detail-section-head h3 {
  flex: 1 1 auto;
  min-width: 0;
  /* Title is short and fixed — clip if it ever grows. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.frames-section > .detail-section-head .frames-zip-btn {
  flex-shrink: 0;
}

.frames-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.6rem 0 0.4rem;
}
.frames-head h3 { margin: 0; }
.frames-zip-btn { font-size: 0.82rem; padding: 0.4rem 0.85rem; }

.frame-grid {
  display: flex;
  gap: 0.6rem;
  margin-top: 0.4rem;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 0.55rem;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.frame-grid::-webkit-scrollbar { height: 6px; }
.frame-grid::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
.frame-grid::-webkit-scrollbar-thumb:hover { background: var(--muted); }
.frame-grid figure {
  margin: 0;
  flex: 0 0 160px;  /* fixed width per item — single row, scroll horizontally */
}
.frame-grid img {
  width: 100%;
  aspect-ratio: 16/9;
  object-fit: cover;
  border-radius: 4px;
  background: #000;
  cursor: pointer;
  border: 1px solid var(--border);
  transition: border-color 0.1s;
}
.frame-thumb {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: block;
  width: 100%;
}
.frame-thumb:hover img { border-color: var(--accent); }

/* Slideshow viewer for frame thumbnails — image stage + bottom bar. */
.slideshow-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 2000;
  padding: 1rem;
  gap: 0.85rem;
  animation: fade-in 0.12s ease-out;
}
.slideshow-backdrop.hidden { display: none; }

/* Stage holds the image + close + nav arrows so close-button sits on the
   image's top-right corner, not the viewport corner. */
.slideshow-stage {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  max-width: 92vw;
  max-height: 76vh;
}
#slideshow-img {
  display: block;
  max-width: 92vw;
  max-height: 76vh;
  object-fit: contain;
  border-radius: 4px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.7);
}

/* Unified circular control buttons (close + nav) */
.slideshow-close,
.slideshow-nav {
  position: absolute;
  background: rgba(20, 22, 30, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #fff;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  width: 38px;
  height: 38px;
  transition: background 0.1s, border-color 0.1s, opacity 0.1s;
}
.slideshow-close:hover,
.slideshow-nav:hover {
  background: rgba(20, 22, 30, 0.95);
  border-color: var(--accent);
}
.slideshow-close svg { width: 18px; height: 18px; }
.slideshow-nav svg { width: 22px; height: 22px; }
.slideshow-close { top: 0.5rem; right: 0.5rem; z-index: 6; }
.slideshow-nav { top: 50%; transform: translateY(-50%); width: 44px; height: 44px; }
.slideshow-prev { left: 0.5rem; }
.slideshow-next { right: 0.5rem; }
.slideshow-nav:disabled { opacity: 0.3; cursor: not-allowed; }

/* Bottom bar: caption left | save center | delete right. Buttons share a
   unified pill style for visual consistency. */
.slideshow-bar {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 1rem;
  background: rgba(20, 22, 30, 0.85);
  border: 1px solid var(--border);
  border-radius: 8px;
  max-width: 92vw;
  width: max-content;
}
.slideshow-bar #slideshow-caption { justify-self: start; white-space: nowrap; }
.slideshow-bar #slideshow-save { justify-self: center; }
.slideshow-bar #slideshow-delete { justify-self: end; }
.slideshow-bar button {
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
  font-weight: 600;
  min-width: 88px;
}
@media (max-width: 480px) {
  .slideshow-nav { width: 38px; height: 38px; }
  .slideshow-nav svg { width: 18px; height: 18px; }
  .slideshow-prev { left: 0.35rem; }
  .slideshow-next { right: 0.35rem; }
  .slideshow-close { width: 32px; height: 32px; top: 0.4rem; right: 0.4rem; }
  .slideshow-close svg { width: 14px; height: 14px; }
  .slideshow-bar {
    grid-template-columns: 1fr 1fr;
    padding: 0.5rem 0.7rem;
    gap: 0.4rem;
    width: 100%;
    max-width: 100%;
  }
  .slideshow-bar #slideshow-caption {
    grid-column: 1 / -1;
    justify-self: center;
    margin-bottom: 0.25rem;
  }
  .slideshow-bar #slideshow-save { justify-self: stretch; grid-column: 1; }
  .slideshow-bar #slideshow-delete { justify-self: stretch; grid-column: 2; }
  .slideshow-bar button { min-width: 0; padding: 0.5rem 0.6rem; }
}
.frame-grid figcaption {
  text-align: center;
  font-size: 0.75rem;
  color: var(--muted);
  margin-top: 0.2rem;
}

video {
  width: 100%;
  max-height: 420px;
  background: #000;
  border-radius: 6px;
}
audio { width: 100%; }

.task-row {
  display: grid;
  grid-template-columns: 70px 80px 1fr 90px;
  gap: 0.7rem;
  padding: 0.7rem 0.85rem;
  border-bottom: 1px solid var(--border);
  align-items: center;
  font-size: 0.85rem;
  min-height: 64px;  /* keep row height stable as messages change length */
}
.task-row:last-child { border-bottom: none; }

.task-row .task-msg {
  min-width: 0;  /* required for child ellipsis to work inside grid 1fr */
}
.task-row .task-msg-text {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0.35rem;
}
.task-row .task-pct,
.task-row .recheck-btn {
  text-align: center;
  justify-self: end;
}

/* Rich task row — used by the new tasks list with thumbnail + title + time. */
.task-row.task-row-rich {
  grid-template-columns: 96px 1fr 80px;
}
.task-thumb {
  width: 96px;
  height: 54px;
  aspect-ratio: 16/9;
  border-radius: 4px;
  background: #000;
  object-fit: cover;
}
.task-thumb.task-thumb-placeholder {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--surface);
  color: var(--muted);
  font-size: 1.1rem;
  border: 1px solid var(--border);
}
.task-main { min-width: 0; display: flex; flex-direction: column; gap: 0.32rem; }
.task-line-1 {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  min-width: 0;
}
.task-kind-chip {
  display: inline-block;
  padding: 0.16rem 0.55rem;
  border-radius: 4px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 500;
}

/* Merged status+kind chip — replaces the [완료][다운로드] two-chip layout
   with a single status-colored pill that carries both pieces of info.
   Cleaner on mobile, single visual element instead of two competing ones. */
.task-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}
.task-chip svg { flex-shrink: 0; }

/* Per-row trash button — shown under the percentage / recheck control
   so the user can dismiss a single record without using the global
   "전체 삭제". */
.task-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.4rem;
  justify-self: end;
}
.task-delete {
  width: 28px;
  height: 28px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--muted);
  border-radius: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  padding: 0;
  transition: border-color 0.1s, color 0.1s, background 0.1s;
}
.task-delete:hover {
  border-color: var(--danger);
  color: var(--danger);
  background: rgba(239, 91, 107, 0.06);
}
.task-title {
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
  flex: 1 1 auto;
  max-width: 100%;
}
.task-time {
  flex-shrink: 0;
  margin-left: auto;
}
/* Bare timestamp line — no box, no label, just the compact date string. */
.task-stamp {
  font-variant-numeric: tabular-nums;
}

/* Error tasks — surface t.error in a tinted red box so the reason stands
   out from ordinary progress messages. */
.task-error {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  background: rgba(239, 91, 107, 0.1);
  border: 1px solid rgba(239, 91, 107, 0.4);
  border-left-width: 3px;
  border-radius: 4px;
  padding: 0.4rem 0.6rem;
  color: var(--danger);
  font-size: 0.82rem;
  width: fit-content;
  max-width: 100%;
}
.task-error svg { flex-shrink: 0; }
.task-error span {
  white-space: normal;
  word-break: break-word;
}
.task-row-error .task-pct { color: var(--danger); }
.task-row .recheck-btn {
  padding: 0.35rem 0.65rem;
  font-size: 0.78rem;
  white-space: nowrap;
}

/* Status pill — rounded rectangle chip that matches the .task-kind-chip
   visual weight on the right of it, so 완료 doesn't dominate the row. */
.pill {
  display: inline-block;
  padding: 0.16rem 0.55rem;
  border-radius: 4px;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.3px;
  text-align: center;
  border: 1px solid transparent;
}
.pill.pending { background: rgba(138, 147, 163, 0.15); color: var(--muted); border-color: rgba(138, 147, 163, 0.4); }
.pill.running { background: rgba(247, 168, 92, 0.15); color: #f7a85c;       border-color: rgba(247, 168, 92, 0.45); }
.pill.done    { background: rgba(91, 141, 239, 0.15); color: var(--accent); border-color: rgba(91, 141, 239, 0.45); }
.pill.error   { background: rgba(239, 91, 107, 0.15); color: var(--danger); border-color: rgba(239, 91, 107, 0.45); }

.progress {
  height: 6px;
  background: var(--surface-2);
  border-radius: 999px;
  overflow: hidden;
}
.progress > div {
  height: 100%;
  background: var(--accent);
  transition: width 0.2s ease;
}

/* Modal dialog (used for blocking confirmations like "select an item first"). */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(8, 10, 14, 0.78);
  backdrop-filter: blur(6px) saturate(60%);
  -webkit-backdrop-filter: blur(6px) saturate(60%);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  z-index: 1000;
  animation: fade-in 0.12s ease-out;
}
.modal-backdrop.hidden { display: none; }

/* The shared alert/choice/options modal must always sit above any other
   overlay (action modals at 1000, slideshow viewer at 2000). Without this
   bump it paints behind whatever's currently on screen — making confirm
   dialogs invisible from inside the slideshow's "삭제" flow, etc. */
#modal-root { z-index: 2100; }

/* Scroll-lock the page while any blocking overlay (alert/clip modal/slideshow)
   is visible. Uses :has() so we don't have to edit every open/close path —
   modern Chromium/Firefox/Safari all support it. */
body:has(.modal-backdrop:not(.hidden)) main,
body:has(.slideshow-backdrop:not(.hidden)) main {
  overflow: hidden;
}

/* Clip modal needs a noticeably stronger frosted look since the page
   underneath is full of thumbnails — heavier blur reads as "modal mode".
   Frame modal shares the same vibe. */
.clip-modal-backdrop,
.frame-modal-backdrop {
  background: rgba(8, 10, 14, 0.82);
  backdrop-filter: blur(10px) saturate(60%);
  -webkit-backdrop-filter: blur(10px) saturate(60%);
}
.modal {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1.4rem 1.5rem 1.2rem;
  width: 100%;
  max-width: 380px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
  /* 본문이 긴 정보/이력 모달은 더 넓게 (좁은 창에서는 화면 폭을 따른다) */
  
  animation: slide-up 0.16s ease-out;
  /* 내용이 길어도(예: 버전 정보의 변경 이력) 창 밖으로 넘쳐 닫기 버튼이
     사라지지 않도록. 넘치는 부분은 .modal-body 안에서만 스크롤한다. */
  max-height: calc(100vh - 2rem);
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.modal > .modal-title,
.modal > .modal-actions { flex: 0 0 auto; }
.modal > .modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}
.modal-title {
  margin: 0 0 0.6rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
}
.modal-body {
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.5;
  margin-bottom: 1.1rem;
  word-break: keep-all;
}
/* Alert step-hint block — concise "추출 방식 선택 → [선택 추가] 버튼 실행"
   line below the main message, with a soft separator above it for breathing
   room. Used inside showAlert's html body. */
.alert-step-hint {
  margin-top: 0.85rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.82rem;
  line-height: 1.5;
}
.alert-step-hint strong {
  color: var(--text);
  font-weight: 600;
}
.alert-arrow {
  color: var(--accent);
  margin: 0 0.2rem;
  font-weight: 600;
}

/* Long entity name shown above a confirm dialog body — single-line ellipsis
   so a 60+ char video title doesn't blow up the modal. */
.modal-target-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 0.55rem;
  color: var(--text);
  font-weight: 500;
  font-size: 0.95rem;
}
/* Bulleted list of orphaned items inside the "없는 항목 발견" confirm
   dialog — capped height so a long list scrolls instead of overflowing. */
.modal-missing-list {
  margin: 0.6rem 0;
  padding: 0.5rem 0.5rem 0.5rem 1.5rem;
  max-height: 180px;
  overflow-y: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: rgba(127, 127, 127, 0.08);
  color: var(--text);
  font-size: 0.85rem;
  line-height: 1.45;
}
.modal-missing-list li { margin: 0.15rem 0; word-break: break-all; }

/* "정보 / 변경 이력" 팝업 (헤더의 v1.0.0 버튼 클릭 시) */
.about-box { text-align: left; }
.about-head { font-size: 1rem; color: var(--text); margin-bottom: 0.3rem; }
.about-head b { color: var(--accent); }
.about-desc { margin: 0 0 0.7rem; }
.about-box h4 {
  margin: 0.9rem 0 0.35rem;
  color: var(--text);
  font-size: 0.88rem;
}
.about-ver { margin-bottom: 0.3rem; color: var(--text); font-size: 0.85rem; }
.about-ver .muted { color: var(--muted); font-weight: 400; }
.about-list { margin: 0.2rem 0 0.3rem; padding-left: 1.2rem; }
.about-list li { margin: 0.16rem 0; }
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}
.modal-actions button { min-width: 80px; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes slide-up {
  from { transform: translateY(8px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

.toast {
  position: fixed;
  bottom: 2rem;
  right: 2rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  padding: 0.7rem 1.1rem;
  border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.4);
  font-size: 0.88rem;
  max-width: 380px;
}
.toast.error { border-left-color: var(--danger); }
.toast.success { border-left-color: var(--success); }

.timestamp-input {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.4rem 0;
}
.timestamp-input input {
  width: 90px;
  flex: 0;
}

/* Interval mode controls — pill-style fields with inline label/unit */
.iv-controls {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin: 0.5rem 0 0.2rem;
}
.iv-controls.hidden { display: none; }

/* Frame extraction tool — three add-actions feeding a shared timestamp set.
   The 현재 위치 추가 row reads as a single big tappable button, the 간격
   block sits in a tinted card with inline +/- inputs, and 직접 입력 hides
   inside a <details> drawer for power users only. */
.frame-tool-hint { margin: 0 0 0.7rem; }
.frame-add-btn {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  width: 100%;
  text-align: left;
  padding: 0.7rem 0.9rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--text);
  cursor: pointer;
  transition: border-color 0.1s, background 0.1s;
  margin-bottom: 0.6rem;
}
.frame-add-btn:hover {
  border-color: var(--accent);
  background: rgba(91, 141, 239, 0.06);
}
.frame-add-icon {
  flex: 0 0 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(91, 141, 239, 0.15);
  color: var(--accent);
  border-radius: 6px;
  font-size: 0.85rem;
}
.frame-add-label {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
}
.frame-add-label strong { font-size: 0.92rem; font-weight: 600; }

.frame-add-block {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.75rem 0.9rem;
  margin-bottom: 0.6rem;
}
.frame-add-block-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 0.55rem;
  font-size: 0.92rem;
}
.frame-add-block-row {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
  color: var(--muted);
  font-size: 0.85rem;
}
/* One-row variant — used inside the frame modal so
   매 [n]초마다 / 최대 [n]개 / [간격으로 추가] sit on the same line on
   wide screens. Each label+field is wrapped in .frame-add-pair so they
   wrap as a unit (label and value never split across rows on narrow
   viewports). */
.frame-add-block-row.frame-add-block-row-flex {
  flex-wrap: nowrap;
  gap: 0.5rem;
}
.frame-add-pair {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  flex-shrink: 0;
  white-space: nowrap;
}
.frame-add-block-row.frame-add-block-row-flex .frame-add-block-label {
  flex-shrink: 0;
  white-space: nowrap;
}
.frame-add-block-row.frame-add-block-row-flex .iv-field-inline {
  flex-shrink: 0;
}
.frame-add-block-row.frame-add-block-row-flex .frame-add-go {
  flex-shrink: 0;
}
.iv-field-inline {
  padding: 0.2rem 0.55rem;
}
.iv-field-inline input[type="number"] { width: 38px; }
.frame-add-go {
  margin-left: auto;
  font-size: 0.85rem;
  padding: 0.4rem 0.85rem;
}

/* Chip-count header above the chips list inside the frame modal — count
   on the left, [전체 삭제] button on the right (hidden when no chips). */
.frame-chips-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.6rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
}
.fm-chips-clear {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--muted);
  border-radius: 4px;
  padding: 0.2rem 0.55rem;
  font-size: 0.75rem;
  cursor: pointer;
  transition: border-color 0.1s, color 0.1s;
}
.fm-chips-clear:hover {
  border-color: var(--danger);
  color: var(--danger);
}

/* Frame-modal radio-based method list — single select. Every row gets the
   same min-height so the cards line up uniformly even though their content
   (one short label vs. inline number inputs) varies. */
.frame-method-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.frame-method {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  transition: border-color 0.1s, background 0.1s;
}
.frame-method:has(input[type="radio"]:checked) {
  border-color: var(--accent);
  background: rgba(91, 141, 239, 0.06);
}
.frame-method-check {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.45rem 0.7rem;
  cursor: pointer;
  width: 100%;
  min-height: 40px;
  font-size: 0.9rem;
  color: var(--text);
}
.frame-method-check input[type="radio"] {
  width: 18px;
  height: 18px;
  margin: 0;
  flex-shrink: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.frame-method-label {
  display: flex;
  align-items: center;
  min-width: 0;
  flex: 1;
}
.frame-method-label strong { color: var(--text); font-weight: 500; }
.frame-method-row {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: nowrap;
  min-width: 0;
  white-space: nowrap;
}
.frame-method-row > * { flex-shrink: 0; }

/* Plain number inputs inside the method rows — no custom +/- chrome, just
   a clean box with placeholder hint. Native spinners are hidden so the
   look stays consistent across browsers. */
.fm-num-input {
  width: 46px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 5px;
  padding: 0.3rem 0.5rem;
  font-size: 0.9rem;
  font-weight: 500;
  text-align: center;
  font-variant-numeric: tabular-nums;
  outline: none;
  transition: border-color 0.1s;
}
.fm-num-input:focus { border-color: var(--accent); }
.fm-num-input::-webkit-outer-spin-button,
.fm-num-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.fm-num-input { -moz-appearance: textfield; appearance: textfield; }
.fm-unit { color: var(--muted); font-size: 0.85rem; }

/* "선택 추가" — secondary CTA that still needs to read clearly. Tinted
   accent fill + dashed border signal "this is the add action" without
   competing with the final filled 프레임 추출 button. */
.fm-apply-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.7rem 1rem;
  margin: 0.4rem auto 0.2rem;
  background: rgba(91, 141, 239, 0.14);
  border: 1.5px dashed var(--accent);
  border-radius: 8px;
  color: var(--accent);
  font-weight: 600;
  font-size: 0.95rem;
  cursor: pointer;
  text-align: center;
  transition: border-style 0.12s, background 0.12s, transform 0.08s;
}
.fm-apply-btn:hover {
  background: rgba(91, 141, 239, 0.22);
  border-style: solid;
}
.fm-apply-btn:active { transform: translateY(1px); }
.fm-apply-btn svg { flex-shrink: 0; stroke: var(--accent); }

/* Hint text above the method list — single compact line. [선택 추가] is
   bolded + brighter so it pops out of the muted body text. */
.frame-modal-hint {
  margin: 0 0 0.6rem;
  font-size: 0.72rem;
  line-height: 1.4;
}
.frame-modal-hint strong {
  color: var(--text);
  font-weight: 600;
}

/* Final-CTA filled accent button — for "프레임 추출" so it dominates the
   secondary "선택 추가" outline button visually. Override the .btn-icon
   muted color so the download arrow inherits the accent-button white. */
button.primary.primary-cta {
  padding: 0.6rem 1.1rem;
}
button.primary.primary-cta .btn-icon {
  color: #fff;
}

.frame-add-manual {
  margin: 0.4rem 0 0.6rem;
  font-size: 0.85rem;
  color: var(--muted);
}
.frame-add-manual summary {
  cursor: pointer;
  padding: 0.35rem 0;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.frame-add-manual summary::-webkit-details-marker { display: none; }
.frame-add-manual summary::before {
  content: '+';
  display: inline-block;
  width: 16px;
  text-align: center;
  font-weight: 600;
  transition: transform 0.15s;
}
.frame-add-manual[open] summary::before { content: '−'; }
.frame-add-manual[open] summary { color: var(--text); }

.frame-chips {
  margin: 0.5rem 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  /* Modal body itself is scrollable now (.modal--wide), so chips can grow
     freely instead of needing their own nested scroll. */
}
.frame-chips:empty { display: none; }

/* Inline progress shown inside the frame modal while extraction is running.
   Lives between the chips list and the action row so the modal stays open
   and the user sees progress without leaving for the tasks tab. */
.fm-progress {
  margin: 0.85rem 0 0.25rem;
  padding: 0.7rem 0.85rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.fm-progress.hidden { display: none; }
.fm-progress-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.4rem;
}
.fm-progress-label {
  font-size: 0.85rem;
  font-weight: 600;
}
.fm-progress-pct {
  font-size: 0.8rem;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.fm-progress-msg {
  margin-top: 0.35rem;
  min-height: 1em;
}
.frame-extract-row {
  margin-top: 0.7rem;
  justify-content: flex-end;
}
.iv-field {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.35rem 0.7rem;
  color: var(--muted);
  font-size: 0.85rem;
}
.iv-field:focus-within { border-color: var(--accent); }
.iv-field .iv-label { color: var(--muted); }
.iv-field .iv-unit { color: var(--muted); font-size: 0.78rem; }
.iv-field input[type="number"] {
  width: 50px;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 600;
  outline: none;
  padding: 0.1rem 0;
  text-align: right;
}
.iv-field input[type="number"]::-webkit-outer-spin-button,
.iv-field input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Custom stacked up/down stepper buttons inside .iv-field */
.iv-stepper {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  margin-left: 0.1rem;
}
.iv-step {
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--muted);
  padding: 0;
  width: 22px;
  height: 13px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  line-height: 1;
}
.iv-step:hover {
  color: var(--text);
  border-color: var(--accent);
  background: var(--surface-2);
}
.iv-step:active {
  background: var(--accent);
  color: #fff;
  border-color: var(--accent);
}
.iv-step svg { display: block; flex-shrink: 0; }

/* "구간 추출" — start/end pickers reuse iv-controls; quick-pick row below */
.clip-quick-row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}
.clip-quick-row button {
  font-size: 0.82rem;
  padding: 0.4rem 0.85rem;
}
.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 0.8rem;
}
.chip button {
  background: transparent;
  border: none;
  color: var(--muted);
  padding: 0;
  font-size: 1rem;
  line-height: 1;
}

/* =========================================================
   Library detail — section cards
   Each tool/result block lives in its own subtly tinted card
   so the eye can separate "도구" vs. "결과물".
   ========================================================= */
.detail-section {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.95rem 1.05rem;
  margin-top: 0.9rem;
}
.detail-section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  margin-bottom: 0.7rem;
  flex-wrap: wrap;
}
.detail-section-head h3 {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}
.detail-section-icon {
  width: 26px;
  height: 26px;
  border-radius: 6px;
  background: rgba(91, 141, 239, 0.14);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.detail-section-icon svg { display: block; }
.detail-section-count {
  display: inline-block;
  background: rgba(91, 141, 239, 0.18);
  color: var(--accent);
  border-radius: 999px;
  padding: 0.05rem 0.55rem;
  font-size: 0.75rem;
  font-weight: 600;
  margin-left: 0.3rem;
}
.detail-section-empty {
  color: var(--muted);
  font-size: 0.85rem;
  text-align: center;
  padding: 1.4rem 0.5rem;
  border: 1px dashed var(--border);
  border-radius: 6px;
}

/* Collapsible variant — header is a button that toggles the body. The
   chevron rotates 180° in the collapsed state so the affordance is obvious
   even when the body is hidden. */
.detail-section-collapsible > .detail-section-head {
  width: 100%;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  color: inherit;
  text-align: left;
  /* Inherit the existing .detail-section-head margin-bottom so expanded
     state keeps the head/body gap; collapsed override below zeroes it. */
}
.detail-section-collapsible > .detail-section-head:hover .detail-section-chevron {
  color: var(--accent);
}
.detail-section-chevron {
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.18s ease, color 0.12s;
  flex-shrink: 0;
}
.detail-section-collapsible.collapsed > .detail-section-head { margin-bottom: 0; }
.detail-section-collapsible.collapsed > .detail-section-head .detail-section-chevron {
  transform: rotate(-90deg);
}
.detail-section-body {
  overflow: hidden;
  transition: max-height 0.22s ease, opacity 0.18s ease, margin-top 0.18s ease;
  max-height: 1200px;
  opacity: 1;
}
.detail-section-collapsible.collapsed > .detail-section-body {
  max-height: 0;
  opacity: 0;
  margin-top: 0;
  pointer-events: none;
}

/* The "파일 저장" anchor wraps a styled button — drop the underline so the
   pair reads as a single button. */
.detail-save-link { text-decoration: none; display: inline-flex; }

/* Soft outline button — used for download/extract actions so the
   shouty filled-primary tone is reserved for top-level CTAs. */
button.btn-soft {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  transition: border-color 0.1s, color 0.1s, background 0.1s;
}
button.btn-soft:hover {
  border-color: var(--accent);
  color: var(--accent);
  background: rgba(91, 141, 239, 0.06);
}
button.btn-soft .btn-icon { color: var(--muted); transition: color 0.1s; }
button.btn-soft:hover .btn-icon { color: var(--accent); }
button.btn-soft-accent {
  border-color: rgba(91, 141, 239, 0.55);
  color: var(--accent);
}
button.btn-soft-accent:hover {
  border-color: var(--accent);
  background: rgba(91, 141, 239, 0.12);
}

/* Clip extraction modal — wider, centered, with timeline.
   Cap height at viewport so a long chips list never pushes the action
   buttons (취소 / 추출) off screen. The middle body scrolls; the head
   and footer stay anchored. */
.modal--wide {
  max-width: 640px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  /* Override base .modal's static padding so the head/body/footer can
     manage their own spacing without the body's scrollbar gutter cutting
     into the title/footer area. */
  padding: 0;
  overflow: hidden;
}
.modal--wide > .clip-modal-head {
  flex: 0 0 auto;
  padding: 1rem 1rem 0.5rem;
  margin-bottom: 0;
}
.modal--wide > .clip-modal-body {
  /* flex-grow 0 → never expand beyond content height. Body only shrinks
     and scrolls when total content exceeds the modal's 90vh cap. With
     flex-grow 1 (the previous setting), an empty modal stretched all the
     way down to 90vh and left a big void above the action buttons. */
  flex: 0 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 0.3rem 1rem;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.modal--wide > .clip-modal-body::-webkit-scrollbar { width: 6px; }
.modal--wide > .clip-modal-body::-webkit-scrollbar-thumb {
  background: var(--border);
  border-radius: 3px;
}
.modal--wide > .clip-modal-body::-webkit-scrollbar-thumb:hover {
  background: var(--muted);
}
.modal--wide > .modal-actions {
  flex: 0 0 auto;
  padding: 0.7rem 1rem 0.85rem;
  margin-top: 0;
  border-top: 1px solid var(--border);
}
.clip-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.9rem;
}
.clip-modal-head .modal-title { margin: 0; }
.clip-modal-close {
  background: transparent;
  border: none;
  color: var(--muted);
  width: 28px;
  height: 28px;
  padding: 0;
  border-radius: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.clip-modal-close:hover { color: var(--text); background: var(--surface-2); }

.clip-modal-body { display: flex; flex-direction: column; gap: 0.55rem; }
#clip-video,
#frame-video {
  width: 100%;
  max-height: 240px;
  background: #000;
  border-radius: 6px;
  outline: none;
}

/* Meta bar between the clip-modal video and timeline. Surfaces resolution,
   detected fps, and duration in a quiet pill row so the user knows what
   frame rate the mm:ss:ff timecodes refer to. Stays on one line — items
   shrink/clip rather than wrap so the layout doesn't grow taller. */
.clip-meta-bar {
  display: flex;
  flex-wrap: nowrap;
  gap: 0.75rem;
  padding: 0.45rem 0.7rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 0.78rem;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
}
.clip-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.clip-meta-key {
  color: var(--muted);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

/* Compact one-line range summary: [In] ~ [Out] | 총 N분 N초.
   Replaces the labeled In/Out rows + separate length line — values stay
   editable but readable as a single sentence. */
.clip-range-bar {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.55rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-variant-numeric: tabular-nums;
  flex-wrap: nowrap;
}
.clip-range-bar input[type="text"] {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  color: var(--text);
  font-weight: 600;
  padding: 0.3rem 0.55rem;
  width: 92px;
  text-align: center;
  font-size: 0.9rem;
  outline: none;
  font-variant-numeric: tabular-nums;
  flex: 0 0 auto;
}
.clip-range-bar input[type="text"]:focus { border-color: var(--accent); }
.clip-range-sep { color: var(--muted); flex-shrink: 0; }
.clip-range-divider {
  color: var(--border);
  margin: 0 0.15rem;
  flex-shrink: 0;
}
.clip-range-total-key {
  color: var(--muted);
  font-size: 0.78rem;
  flex-shrink: 0;
}
.clip-range-bar strong {
  color: var(--accent);
  font-weight: 600;
  font-size: 0.95rem;
  flex-shrink: 0;
}

/* Timeline track with In/Out markers + scrubber overlay.
   Uses absolute positioning anchored by left:% for the markers and a
   filled span between them for the selection range. */
.clip-timeline {
  user-select: none;
}
.clip-track {
  position: relative;
  height: 26px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 4px;
  margin: 0.2rem 0 0.4rem;
}
.clip-track-fill {
  position: absolute;
  top: 0; bottom: 0;
  background: rgba(91, 141, 239, 0.22);
  border-left: 1px solid var(--accent);
  border-right: 1px solid var(--accent);
  pointer-events: none;
}
.clip-track-progress {
  position: absolute;
  top: 0; bottom: 0;
  width: 2px;
  background: rgba(231, 234, 240, 0.65);
  pointer-events: none;
}
.clip-marker {
  position: absolute;
  top: -4px;
  bottom: -4px;
  width: 12px;
  margin-left: -6px;
  background: var(--accent);
  border-radius: 3px;
  cursor: ew-resize;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  touch-action: none;
}
.clip-marker:focus { outline: 2px solid #fff3; outline-offset: 1px; }
.clip-marker.dragging { background: var(--accent-2); }
.clip-marker-flag {
  position: absolute;
  top: -18px;
  background: var(--accent);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 600;
  padding: 0.05rem 0.4rem;
  border-radius: 3px;
  letter-spacing: 0.3px;
  pointer-events: none;
}
.clip-marker-out .clip-marker-flag { background: var(--accent-2); }
.clip-marker-out { background: var(--accent-2); }
.clip-track-time {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.72rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* Center playhead group = ▼ icon + "현재" label + time, accent-colored
   so it reads as live data distinct from the static start/total ends. */
.clip-track-cur-wrap {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--accent);
  font-weight: 600;
}
.clip-track-cur-label {
  color: var(--muted);
  font-weight: 500;
  font-size: 0.7rem;
}
.clip-track-cur-time {
  color: var(--accent);
  font-weight: 600;
}

.clip-fields {
  display: flex;
  flex-direction: row;
  gap: 0.6rem;
}
.clip-fields .iv-field {
  flex: 1 1 0;
  min-width: 0;
}
.clip-fields .iv-field input[type="text"] {
  min-width: 0;
  flex: 1 1 auto;
}

/* Transport bar — Premiere-style icon buttons (back / play-pause / fwd)
   plus In/Out marker buttons, sitting between the timeline and the In/Out
   numeric fields so the user has a single hub for playback + marking. */
.clip-transport {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 0.4rem 0.55rem;
  flex-wrap: wrap;
}
.clip-transport-group {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
}
.clip-transport-divider {
  width: 1px;
  align-self: stretch;
  background: var(--border);
  margin: 0 0.25rem;
}
.clip-tbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.35rem;
  min-width: 34px;
  height: 30px;
  padding: 0 0.55rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text);
  font-size: 0.8rem;
  cursor: pointer;
  transition: border-color 0.1s, background 0.1s, color 0.1s;
}
.clip-tbtn:hover {
  border-color: var(--accent);
  color: var(--accent);
}
.clip-tbtn-play.is-playing {
  background: rgba(91, 141, 239, 0.15);
  border-color: var(--accent);
  color: var(--accent);
}
.clip-tbtn-mark .kbd {
  display: inline-block;
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: 0.68rem;
  font-weight: 600;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 3px;
  padding: 0 0.3rem;
  color: var(--muted);
}
.clip-tbtn-mark:hover .kbd {
  border-color: var(--accent);
  color: var(--accent);
}
.clip-summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 0.55rem 0.75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
}
.clip-summary strong {
  font-size: 1.05rem;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* Breathing room between the controls block and the cancel/download row. */
.clip-modal-actions {
  margin-top: 1.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}

/* Time-format inputs read more naturally with mono digits */
#clip-modal-in,
#clip-modal-out {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.5px;
}

/* =========================================================
   Responsive — tablet (≤768px) and phone (≤480px)
   ========================================================= */

@media (max-width: 768px) {
  /* Header collapses to title + hamburger; nav becomes a dropdown overlay. */
  header {
    padding: 0.7rem 1rem;
    gap: 0.5rem;
    flex-wrap: nowrap;
  }
  header h1 { font-size: 1rem; }

  .menu-toggle { display: inline-flex; }

  nav {
    display: none;
    position: absolute;
    top: calc(100% + 4px);
    left: 0.7rem;  /* aligns with the now-leftmost .menu-toggle */
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.4rem;
    gap: 0.2rem;
    min-width: 150px;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.5);
    z-index: 50;
  }
  nav.open { display: flex; }
  nav .tab {
    width: 100%;
    text-align: left;
    padding: 0.55rem 0.85rem;
    font-size: 0.9rem;
    border-radius: 4px;
  }
  /* Footer row: 매뉴얼 + 버전을 한 줄에 좌/우로 배치 + 위쪽 분리선 한 번만. */
  .nav-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.25rem;
    padding-top: 0.35rem;
    border-top: 1px solid var(--border);
  }
  .nav-footer .nav-version {
    padding: 0.18rem 0.6rem;
  }

  /* Card spacing */
  main { padding: 1rem; }
  .card {
    padding: 1rem;
    margin-bottom: 1rem;
  }
  .card h2 { font-size: 1rem; }

  /* Stack thumbnail above title/meta */
  .info-grid {
    grid-template-columns: 1fr;
    gap: 0.7rem;
  }
  .info-grid img {
    max-width: 320px;
    margin: 0 auto;
  }

  /* Format rows: tighter columns on tablet */
  .format-row {
    grid-template-columns: 24px 100px 1fr 80px;
    gap: 0.4rem;
    padding: 0.45rem 0.7rem 0.45rem 1rem;
    font-size: 0.83rem;
  }
  .format-row .col-codec { font-size: 0.76rem; }
  .format-group-header {
    padding: 0.6rem 0.8rem;
  }

  /* Audio panel: stack label above buttons when cramped */
  .audio-format-picker {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
  }

  /* Library: full-width list, accordion-style inline detail under each card.
     Right-column detail is hidden — we reveal .lib-inline-detail instead. */
  .library-layout {
    grid-template-columns: 1fr;
    gap: 1rem;
  }
  .library-list { max-height: none; }  /* let page scroll handle long lists */
  .library-detail-col { display: none; }
  .mobile-only { display: inline-flex; }

  /* Animated accordion: collapsed default, .open expands smoothly. */
  .lib-inline-detail {
    display: block;
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--accent);
    border-radius: 6px;
    /* Collapsed state */
    max-height: 0;
    opacity: 0;
    margin: 0;
    padding-top: 0;
    padding-bottom: 0;
    padding-left: 1rem;
    padding-right: 1rem;
    border-width: 0;
    transition:
      max-height 0.2s ease-out,
      opacity 0.14s ease-out,
      margin 0.2s ease-out,
      padding-top 0.2s ease-out,
      padding-bottom 0.2s ease-out,
      border-width 0.14s ease-out;
  }
  .lib-inline-detail.open {
    max-height: 4000px;
    opacity: 1;
    margin: 0.4rem 0 0.6rem;
    padding-top: 0.95rem;
    padding-bottom: 0.95rem;
    border-width: 1px;
  }
  /* Tighter horizontal padding on small phones */
  .lib-inline-detail.open { padding-left: 0.85rem; padding-right: 0.85rem; }

  /* Bigger thumbnail tiles now that the rows have full width to spread out. */
  .lib-card { grid-template-columns: 130px 1fr auto; padding: 0.65rem; gap: 0.85rem; }
  .lib-card .thumb { width: 130px; height: 73px; }
  .lib-card .body h4 { font-size: 0.92rem; }
  .lib-card .body p { font-size: 0.76rem; }

  /* Frame thumbnails fit more per row on tablets, smaller targets */
  .frame-grid {
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 0.5rem;
  }

  /* Video player respects viewport height instead of fixed 420px */
  video { max-height: 50vh; }

  /* Task rows: drop the "kind" column when space is tight (legacy layout
     only — rich layout keeps thumbnail + main + status). */
  .task-row {
    grid-template-columns: 80px 1fr 50px;
    gap: 0.4rem;
    padding: 0.5rem;
    font-size: 0.8rem;
  }
  .task-row:not(.task-row-rich) > :nth-child(2) { display: none; }
  .task-row.task-row-rich {
    grid-template-columns: 80px 1fr 50px;
  }
  .task-row.task-row-rich .task-thumb { width: 80px; height: 45px; }

  /* Toast spans most of the width, anchored to bottom */
  .toast {
    left: 1rem;
    right: 1rem;
    bottom: 1rem;
    max-width: none;
  }

  /* Modal: tighter on mobile */
  .modal-backdrop { padding: 0.7rem; align-items: center; }
  .modal { padding: 1.1rem 0.2rem; max-width: 100%; }
  /* Simple alert/choice/options modal needs proper breathing room — the
     0.2rem horizontal above is for the action modals (영상/프레임 추출)
     which manage their own inner padding. */
  #modal-root .modal { padding: 1.4rem 1.3rem; }
  .modal-title { font-size: 0.95rem; }
  .modal-body { font-size: 0.85rem; }
  .modal-actions button {
    min-width: 0;
    padding: 0.5rem 1rem;
    font-size: 0.88rem;
    flex: 1;  /* full-width buttons on phone for easier tapping */
  }
}

@media (max-width: 480px) {
  /* Phone: tighter still, single-column flows */
  main { padding: 0.7rem; }
  .card { padding: 0.85rem; }

  header { padding: 0.6rem 0.8rem; }
  header h1 { font-size: 0.95rem; }

  /* Format rows: narrowest viable layout */
  .format-row {
    grid-template-columns: 22px 80px 1fr 65px;
    gap: 0.3rem;
    padding: 0.45rem 0.55rem 0.45rem 0.8rem;
    font-size: 0.78rem;
  }
  .format-row .col-codec { font-size: 0.72rem; }
  .format-row-header { font-size: 0.68rem; }

  .format-group-header {
    padding: 0.55rem 0.7rem;
    gap: 0.5rem;
  }
  .format-group-header .group-ext { font-size: 0.88rem; }

  /* Library list: still prominent thumbs on phones, just slightly smaller. */
  .lib-card { grid-template-columns: 110px 1fr auto; padding: 0.55rem; gap: 0.5rem; }
  .lib-card-actions { gap: 0.2rem; }
  .lib-action { width: 28px; height: 28px; }
  .lib-card .thumb { width: 110px; height: 62px; }
  .lib-card .body h4 { font-size: 0.86rem; }
  .lib-card .body p { font-size: 0.72rem; }
  .lib-inline-detail { padding: 0.8rem; }

  /* Frame thumbs: 3-column flow */
  .frame-grid {
    grid-template-columns: repeat(auto-fill, minmax(95px, 1fr));
    gap: 0.4rem;
  }

  /* Search button stays compact, doesn't need 110px on phone */
  #probe-btn { min-width: 90px; }

  /* Kind tabs stay content-fit on phones too — left-aligned, not full width */
  .kind-tabs .ftab { padding: 0.5rem 1rem; }

  /* Detail action buttons wrap to fit (already flex-wrap; tighten spacing) */
  .detail-actions { gap: 0.4rem; }
  .detail-actions button { padding: 0.45rem 0.75rem; font-size: 0.83rem; }

  /* Clip modal: full-bleed inputs on phone, smaller player */
  .detail-section { padding: 0.75rem 0.85rem; }
  #clip-video { max-height: 220px; }
  #frame-video { max-height: 220px; }
  .clip-set-btn { margin-left: 0; }
  .modal--wide { max-width: 100%; }
  /* Tighter horizontal padding so the modal contents don't lose precious
     screen width to the modal frame on phones. */
  .modal--wide > .clip-modal-head { padding: 0.7rem 0.55rem 0.4rem; }
  .modal--wide > .clip-modal-body { padding: 0.25rem 0.55rem; }
  .modal--wide > .modal-actions { padding: 0.55rem 0.55rem 0.7rem; }

  /* Transport bar on phones: keep all 7 buttons on one row by tightening
     gaps/padding and dropping the "인점"/"아웃점" text labels — the I/O
     kbd badge alone is enough to identify those marker buttons. */
  .clip-transport {
    flex-wrap: nowrap;
    gap: 0.3rem;
    padding: 0.3rem 0.4rem;
  }
  .clip-transport-group { gap: 0.2rem; }
  .clip-transport-divider { margin: 0 0.1rem; }
  .clip-tbtn {
    min-width: 28px;
    height: 28px;
    padding: 0 0.4rem;
    font-size: 0.72rem;
  }
  .clip-tbtn-mark { padding: 0 0.35rem; }
  .clip-tbtn-mark > span:not(.kbd) { display: none; }
  .clip-tbtn-mark .kbd {
    margin: 0;
    padding: 0 0.25rem;
    font-size: 0.65rem;
  }

  /* Meta bar: keep all 3 items on one line by shrinking font + gap and
     letting the duration label clip with ellipsis if a really long video
     overflows. */
  .clip-meta-bar {
    gap: 0.5rem;
    padding: 0.4rem 0.55rem;
    font-size: 0.7rem;
  }
  .clip-meta-key { font-size: 0.62rem; }
  .clip-meta-item {
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Range bar: narrower input boxes, allow the [In] [Out] [총] line to
     stay on one row by shrinking input width / font. */
  .clip-range-bar {
    gap: 0.35rem;
    padding: 0.45rem 0.55rem;
    font-size: 0.78rem;
  }
  .clip-range-bar input[type="text"] {
    width: 76px;
    padding: 0.25rem 0.35rem;
    font-size: 0.78rem;
  }
  .clip-range-divider { margin: 0; }
  /* Frame modal: allow the interval row to wrap when there's no horizontal
     room (phone screens) instead of overflowing. The .frame-add-pair groups
     keep label+value glued together so "최대" never gets stranded above
     "[30]개" on the next line. */
  .frame-add-block-row.frame-add-block-row-flex {
    flex-wrap: wrap;
    row-gap: 0.5rem;
  }
  /* Push the action button onto its own row, full-width — feels more like a
     real button than a tail-end orphan. */
  .frame-add-block-row.frame-add-block-row-flex .frame-add-go {
    margin-left: auto;
  }

  /* Stack each task block on its own row when space is very tight */
  .task-row {
    grid-template-columns: 70px 1fr 45px;
    font-size: 0.76rem;
  }
  .task-row.task-row-rich {
    grid-template-columns: 70px 1fr 45px;
  }
  .task-row.task-row-rich .task-thumb { width: 70px; height: 39px; }
  .task-row.task-row-rich .task-time { font-size: 0.66rem; }
}

/* ---------------------------------------------------------------
   헤더 메뉴 — 폭에 따라 아이콘만 / 아이콘+텍스트
   좁은 창에서 글자가 두 줄로 접혀 깨져 보이던 문제 때문에, 기본은
   아이콘만 두고 가로가 넉넉할 때만 라벨을 편다. 라벨을 감춰도 title
   속성이 남아 마우스를 올리면 이름이 뜬다.
   --------------------------------------------------------------- */
header nav .tab,
header nav .nav-version {
  white-space: nowrap;
}
header nav .tab > span,
header nav .nav-version > span {
  display: none;
}
header nav .tab {
  padding: 0.4rem 0.55rem;
  gap: 0;
}
header nav .nav-version {
  padding: 0.28rem 0.4rem;
  display: inline-flex;
  align-items: center;
  gap: 0;
}
header nav .nav-version .tab-icon { flex-shrink: 0; }

/* 햄버거로 접힌 상태(세로 드롭다운)에서는 폭 제약이 없으므로 라벨을 편다.
   이 규칙이 없으면 메뉴를 열어도 아이콘만 보여 뭐가 뭔지 알 수 없다. */
header nav.open .tab > span,
header nav.open .nav-version > span {
  display: inline;
}
header nav.open .tab {
  padding: 0.55rem 0.85rem;
  gap: 0.6rem;
}

@media (min-width: 769px) {
  header nav .tab > span,
  header nav .nav-version > span {
    display: inline;
  }
  header nav .tab {
    padding: 0.4rem 0.9rem;
    gap: 0.5rem;
  }
  header nav .nav-version {
    padding: 0.12rem 0.55rem;
    gap: 0.32rem;
  }
}

/* 워드마크 — 앱 이름을 두 줄로. 클릭 대상이 아니므로 커서도 기본값으로 두고
   포인터 이벤트를 막아 "눌러야 하나" 싶은 인상을 지운다. */
.app-wordmark {
  flex-shrink: 0;
  display: block;
  color: var(--text);
  pointer-events: none;
  user-select: none;
}
/* 제목은 로고로 대체한다. 좁은 창에서 "Vide..." 처럼 잘려 보이는 게 보기
   싫어서 글자를 빼되, 스크린리더용으로 DOM 에는 남긴다. */
.app-title-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------
   검색 결과 — 영상 정보(2) : 다운로드 설정(1) 좌우 분할.
   창이 좁으면 좌우로 나눌 폭이 안 나오므로 세로로 쌓는다.
   URL 입력 카드는 위에 그대로 둔다.
   --------------------------------------------------------------- */
.result-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}
.result-info,
.result-settings {
  min-width: 0;
  min-height: 0;
}
/* 왼쪽(영상 정보)은 통째로 스크롤 */
.result-info {
  overflow-y: auto;
  scrollbar-gutter: stable;
}
/* 오른쪽(다운로드 설정)은 목록만 스크롤하고 버튼은 바닥에 붙인다 */
.result-settings {
  display: flex;
  flex-direction: column;
}
.result-settings > .format-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  scrollbar-gutter: stable;
}
/* 다운로드 시작 — 결과 카드 밖, 창 하단 가운데 고정.
   창 높이가 작아져도 버튼이 화면 밖으로 밀려나지 않는다. */
.download-bar {
  flex: 0 0 auto;
  display: flex;
  justify-content: center;
  padding: 0.85rem 0 0.15rem;
  border-top: 1px solid var(--border);
  background: var(--bg);
}
.download-bar.hidden { display: none; }
.download-bar #download-btn {
  min-width: 200px;
  padding-top: 0.6rem;
  padding-bottom: 0.6rem;
}
.result-info > h2:first-child,
.result-settings > h2:first-child { margin-top: 0; }

@media (min-width: 820px) {
  .result-split {
    /* 오른쪽(포맷 목록·구간)이 좁으면 표가 답답해 6:4 로 둔다 */
    grid-template-columns: 6fr 4fr;
    /* gap 을 0 으로 두고 양쪽에 같은 여백을 줘야 가운데 선이 정확히
       두 열 사이 한가운데에 온다. gap + 한쪽 border 조합은 선이 한쪽으로
       치우쳐 보인다. */
    gap: 0;
    /* start 로 두면 두 열이 부모 높이를 채우지 않아 각 열의 스크롤이
       생기지 않고 내용이 그냥 잘린다. stretch 여야 한다. */
    align-items: stretch;
  }
  .result-info {
    padding-right: 1.25rem;
  }
  .result-settings {
    border-left: 1px solid var(--border);
    padding-left: 1.25rem;
  }
}

/* 분할된 열 안에서는 창 폭이 아니라 "그 열의 폭"에 맞춰 표가 접혀야 한다.
   미디어 쿼리는 창 폭만 보므로 컨테이너 쿼리를 쓴다. */
.result-info,
.result-settings {
  container-type: inline-size;
}

/* 열이 좁아지면 코덱/fps 같은 부가 정보를 먼저 접고, 더 좁아지면
   용량까지 접어 해상도와 선택 체크박스는 끝까지 남긴다. */
@container (max-width: 400px) {
  .format-row {
    grid-template-columns: 24px 1fr 78px;
    gap: 0.4rem;
    padding: 0.45rem 0.6rem 0.45rem 0.9rem;
    font-size: 0.83rem;
  }
  .format-row .col-codec { display: none; }
  .format-group-header { padding: 0.55rem 0.7rem; }
}
@container (max-width: 300px) {
  .format-row {
    grid-template-columns: 22px 1fr;
  }
  .format-row .col-size { display: none; }
}

/* 좌우로 나뉘면 썸네일 옆 텍스트가 눌리므로, 열이 좁을 때는 세로로 쌓는다. */
@container (max-width: 460px) {
  .info-grid {
    grid-template-columns: 1fr;
    gap: 0.7rem;
  }
  .info-grid img {
    max-width: 320px;
    margin: 0 auto;
  }
}

/* 정보(버전·변경 이력) 모달은 글이 길어 좁으면 읽기 불편하다. */
.modal:has(.about-box) {
  max-width: min(560px, calc(100vw - 2rem));
}

/* ---------------------------------------------------------------
   스크롤바 — 앱 전체에서 같은 모양으로 통일.
   기본 브라우저 스크롤바(밝은 회색 두꺼운 막대)가 다크 UI 위에서 튀어
   보이던 것을 테마 색을 쓰는 얇은 막대로 바꾼다.
   --------------------------------------------------------------- */
*::-webkit-scrollbar {
  width: 12px;
  height: 12px;
}
/* 트랙을 살짝 보이게 해서 "여기 스크롤이 있다"를 알린다 */
*::-webkit-scrollbar-track {
  background: color-mix(in srgb, var(--border) 35%, transparent);
  border-radius: 999px;
}
*::-webkit-scrollbar-thumb {
  background: var(--muted);
  background-clip: padding-box;
  border: 3px solid transparent;
  border-radius: 999px;
  min-height: 36px;
}
*::-webkit-scrollbar-thumb:hover {
  background: var(--text);
  background-clip: padding-box;
}
*::-webkit-scrollbar-corner { background: transparent; }

/* ---------------------------------------------------------------
   검색 중 로딩 — 결과가 들어올 자리에 골격을 깔고(체감 대기 단축)
   그 위 중앙에 스피너를 얹는다.
   --------------------------------------------------------------- */
.search-loading {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}
.search-loading.hidden { display: none; }

.skel-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  opacity: 0.5;   /* 중앙 스피너가 주인공 — 골격은 뒤로 물린다 */
}
@media (min-width: 820px) {
  .skel-layout { grid-template-columns: 1fr 1fr; gap: 1.5rem; }
}
.skel-col { min-width: 0; }

.sk {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--border) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: sk-shimmer 1.3s ease-in-out infinite;
  border-radius: 6px;
}
@keyframes sk-shimmer {
  0%   { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}
.sk-thumb { height: 150px; margin-bottom: 1rem; }
.sk-line { height: 12px; margin-bottom: 0.6rem; }
.sk-line.w80 { width: 80%; }
.sk-line.w55 { width: 55%; }
.sk-line.w40 { width: 40%; }
.sk-chip { height: 34px; width: 160px; border-radius: 8px; margin-bottom: 1rem; }
.sk-row { height: 38px; margin-bottom: 0.5rem; }

/* 중앙 스피너 — 골격 위에 겹쳐 놓는다 */
.search-loading-center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.15rem;
  text-align: center;
  pointer-events: none;
}
.loading-spinner {
  width: 44px;
  height: 44px;
  margin-bottom: 0.9rem;
  border-radius: 50%;
  border: 3px solid var(--surface-2);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
.search-loading .loading-text {
  font-size: 0.95rem;
  color: var(--text);
  font-weight: 500;
}
.search-loading .loading-sub {
  font-size: 0.8rem;
  color: var(--muted);
}

/* 애니메이션을 줄이도록 설정한 사용자에게는 움직임을 죽인다. */
@media (prefers-reduced-motion: reduce) {
  .sk { animation: none; }
  .loading-spinner { animation-duration: 2.4s; }
}

/* ---------------------------------------------------------------
   구간만 받기 — 시작/끝 시간을 지정해 그 부분만 내려받는다.
   --------------------------------------------------------------- */
.clip-range {
  flex: 0 0 auto;
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--border);
}
.clip-range-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.86rem;
  color: var(--text);
  cursor: pointer;
  user-select: none;
}
.clip-range-toggle input { accent-color: var(--accent); cursor: pointer; }
.clip-range-fields {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.6rem;
}
.clip-range-fields.hidden { display: none; }
.clip-range-fields input {
  flex: 1 1 0;
  min-width: 0;
  padding: 0.42rem 0.6rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text);
  font-family: inherit;
  font-size: 0.86rem;
  text-align: center;
}
.clip-range-fields input:focus {
  outline: none;
  border-color: var(--accent);
}
.clip-range-sep { color: var(--muted); flex: 0 0 auto; }
.clip-range-hint {
  margin: 0.45rem 0 0;
  font-size: 0.76rem;
  color: var(--muted);
}
.clip-range-hint.hidden { display: none; }

/* ---------------------------------------------------------------
   설정(톱니바퀴) 드롭다운 — 테마 · 매뉴얼 · 도움말을 한곳에.
   --------------------------------------------------------------- */
.settings-wrap {
  position: relative;
  flex: 0 0 auto;
  -webkit-app-region: no-drag;
  app-region: no-drag;
}
.settings-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  min-width: 190px;
  padding: 0.35rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 6px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.settings-menu.hidden { display: none; }

.settings-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.5rem 0.6rem;
  background: transparent;
  border: none;
  border-radius: 5px;
  color: var(--text);
  font-family: inherit;
  font-size: 0.86rem;
  text-align: left;
  cursor: pointer;
}
.settings-item:hover { background: var(--surface-2); }
.settings-item svg { flex-shrink: 0; }
.settings-item-label { white-space: nowrap; }

/* 테마 아이콘은 현재 테마에 따라 하나만 보인다 (기존 규칙 유지) */
.settings-item.theme-toggle { justify-content: flex-start; }

/* ---------------------------------------------------------------
   구간 선택 팝업 — 영상을 보면서 시작/끝 지점을 잡는다.
   --------------------------------------------------------------- */
.range-modal {
  max-width: min(720px, calc(100vw - 2rem));
  padding: 1rem 1.1rem 0.9rem;
}
.range-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.7rem;
}
.range-modal-head .modal-title { margin: 0; }
.range-modal-close {
  background: transparent;
  border: none;
  color: var(--muted);
  cursor: pointer;
  padding: 0.2rem;
  border-radius: 4px;
  display: flex;
}
.range-modal-close:hover { color: var(--text); background: var(--surface-2); }

.range-player-wrap {
  position: relative;
  background: #000;
  border: 1px solid var(--border);
  border-radius: 5px;
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
/* 유튜브 플레이어가 들어가는 자리. 재생 준비 전에는 감춰 둔다 —
   검은 화면이 멈춘 것처럼 보이지 않게. */
.range-yt {
  width: 100%;
  height: 100%;
  visibility: hidden;
}
.range-yt.ready { visibility: visible; }
.range-yt iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
.range-loading {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  background: rgba(0, 0, 0, 0.65);
  color: #fff;
}
.range-loading.hidden { display: none; }
.range-loading .range-retry {
  margin-top: 0.7rem;
  padding: 0.45rem 1rem;
  font-size: 0.85rem;
}
.range-loading .loading-sub { color: rgba(255, 255, 255, 0.72); }

/* 타임라인 — 선택 구간을 색으로, 현재 위치를 막대로 */
.range-track {
  position: relative;
  height: 10px;
  margin: 0.75rem 0 0.6rem;
  background: var(--surface-2);
  border-radius: 999px;
  cursor: pointer;
  overflow: hidden;
}
.range-track-sel {
  position: absolute;
  top: 0; bottom: 0;
  background: color-mix(in srgb, var(--accent) 55%, transparent);
}
.range-track-head {
  position: absolute;
  top: -2px; bottom: -2px;
  width: 2px;
  background: var(--text);
}

.range-controls {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin-bottom: 0.8rem;
}
.range-btn {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 5px;
  padding: 0.35rem 0.6rem;
  font-size: 0.78rem;
  cursor: pointer;
  min-width: 38px;
}
.range-btn:hover { border-color: var(--accent); }
.range-btn-play { min-width: 46px; font-size: 0.85rem; }
.range-time { margin-left: auto; color: var(--muted); font-size: 0.82rem; }
.range-time b { color: var(--text); font-variant-numeric: tabular-nums; }

.range-marks {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  flex-wrap: wrap;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--border);
}
.range-mark { display: flex; align-items: center; gap: 0.4rem; }
.range-mark input {
  width: 108px;
  padding: 0.35rem 0.5rem;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text);
  font-family: inherit;
  font-size: 0.82rem;
  text-align: center;
}
.range-mark input:focus { outline: none; border-color: var(--accent); }
.range-len { margin-left: auto; color: var(--muted); font-size: 0.82rem; }
.range-len b { color: var(--text); }

/* 구간 입력 옆 "영상 보며 고르기" 버튼 */
.clip-pick-btn {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.4rem 0.5rem;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text);
  cursor: pointer;
}
.clip-pick-btn:hover { border-color: var(--accent); color: var(--accent); }

/* 구간 팝업의 현재 위치 표시 — 라이브러리 트랙 스타일 위에 얹는다. */
#range-track { position: relative; }
#range-track .range-track-head {
  position: absolute;
  top: -3px;
  bottom: -3px;
  width: 2px;
  background: var(--text);
  pointer-events: none;
  z-index: 3;
}
.range-modal .clip-timeline { margin: 0.9rem 0 0.2rem; }
.range-modal .clip-transport { margin-bottom: 0.6rem; }

/* 구간 입력 — 체크 전에는 잠긴 상태로 자리만 지킨다 */
.clip-range-fields.disabled { opacity: 0.45; }
.clip-range-fields input:disabled,
.clip-pick-btn:disabled {
  cursor: not-allowed;
  background: var(--bg);
  color: var(--muted);
}
.clip-pick-btn:disabled:hover {
  border-color: var(--border);
  color: var(--muted);
}
.clip-range-hint { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* 작업 카드의 동작 버튼들 — 다시 받기 · 기록 삭제 */
.task-actions {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}
.task-save {
  background: transparent;
  border: none;
  color: var(--muted);
  cursor: pointer;
  padding: 0.3rem;
  border-radius: 4px;
  display: flex;
}
.task-save:hover { color: var(--accent); background: var(--surface-2); }

/* ===============================================================
   웹(브라우저) 대응 — 데스크톱 앱 전제를 덜어낸다.
   앱은 847x874 세로형 창에 맞춰 있지만, 브라우저는 폰부터 와이드
   모니터까지 폭이 제각각이다.
   =============================================================== */

/* 넓은 화면에서 가운데 좁게 몰리지 않도록 본문 폭을 키운다. */
@media (min-width: 1200px) {
  main > .tab-pane { max-width: 1320px; }
  main { padding: 1.5rem 2rem; }
}

/* --- 모바일 (세로형 폰) --------------------------------------- */
@media (max-width: 768px) {
  /* 좌우 분할은 폭이 안 나온다 — 세로로 쌓고 각자 스크롤 대신
     페이지 전체가 흐르게 둔다(폰에서는 그 편이 자연스럽다). */
  #tab-download.active {
    display: block;
    overflow-y: auto;
  }
  #tab-download > #info-card {
    display: block;
    overflow: visible;
  }
  .result-split {
    display: block;
  }
  .result-info,
  .result-settings {
    overflow: visible;
    padding: 0;
    border-left: none;
  }
  .result-settings {
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--border);
  }
  .result-settings > .format-list {
    overflow: visible;
    max-height: none;
  }

  /* 손가락으로 누르기 좋게 — 최소 44px 높이 */
  .format-row {
    padding-top: 0.7rem;
    padding-bottom: 0.7rem;
    font-size: 0.9rem;
  }
  .ftab, .tab, .primary, .ghost {
    min-height: 42px;
  }
  #download-btn { min-height: 48px; font-size: 1rem; }
  .download-bar { padding: 0.7rem 0 0.5rem; }

  /* 입력창이 작으면 iOS 가 화면을 확대해버린다(16px 이상 유지) */
  #url-input,
  .clip-range-fields input,
  .range-mark input { font-size: 16px; }

  main { padding: 0.9rem 0.7rem; }
  .card { padding: 0.9rem; }
  header { padding: 0.5rem 0.7rem; }

  /* 구간 선택 팝업도 화면을 꽉 채우게 */
  .range-modal { max-width: 100%; padding: 0.8rem; }
  .range-marks { gap: 0.5rem; }
  .range-mark input { width: 92px; }
}

/* --- 터치 기기 공통 --------------------------------------------- */
@media (hover: none) {
  /* 프레임 없는 창을 위한 장치들은 브라우저에서 쓸모가 없다. */
  .resize-zone { display: none !important; }
  header {
    -webkit-app-region: none;
    app-region: none;
  }
  /* 마우스 올림 효과 대신 눌림 효과를 준다. */
  .format-row:active { background: var(--surface-2); }
}

/* ===============================================================
   모바일 — 탭이 둘뿐이라 햄버거로 감출 이유가 없다.
   화면 아래 고정 탭바로 두면 한 손으로 오갈 수 있다.
   =============================================================== */
@media (max-width: 768px) {
  /* 햄버거는 쓰지 않는다 */
  .menu-toggle { display: none !important; }

  /* nav 를 드롭다운이 아니라 하단 고정 탭바로 */
  header nav,
  header nav.open {
    display: flex !important;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    flex-direction: row;
    justify-content: space-around;
    align-items: stretch;
    gap: 0;
    min-width: 0;
    padding: 0.3rem 0.4rem;
    /* 아이폰 홈 인디케이터 영역을 피한다 */
    padding-bottom: calc(0.3rem + env(safe-area-inset-bottom, 0px));
    background: var(--surface);
    border: none;
    border-top: 1px solid var(--border);
    border-radius: 0;
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.35);
    z-index: 120;
  }
  header nav .tab {
    flex: 1 1 0;
    flex-direction: column;
    justify-content: center;
    gap: 0.15rem;
    width: auto;
    padding: 0.45rem 0.2rem;
    font-size: 0.72rem;
    text-align: center;
    border: none;
    background: transparent;
  }
  header nav .tab > span { display: inline; }
  header nav .tab.active {
    background: transparent;
    color: var(--accent);
  }
  header nav .tab .tab-icon { width: 20px; height: 20px; }

  /* 본문이 탭바에 가리지 않게 아래 여백을 준다 */
  #tab-download.active,
  .tab-pane.active { padding-bottom: 64px; }
  /* 다운로드 버튼도 탭바 위로 올린다 */
  .download-bar { margin-bottom: 58px; }
}

/* ===============================================================
   메뉴는 두 가지 형태만 쓴다 — 넓으면 상단(로고 옆), 좁으면 하단 탭바.
   중간에 끼어 있던 햄버거 드롭다운은 쓰지 않는다(항목이 둘뿐이라
   감출 이유가 없다).
   =============================================================== */
.menu-toggle { display: none !important; }

/* 로고 바로 오른쪽에 탭을 붙이고, 남는 공간은 그 뒤로 민다.
   (기존에는 제목이 남은 공간을 다 먹어 탭이 오른쪽 끝으로 밀렸다) */
header h1 { flex: 0 0 auto; }
header nav { margin-right: auto; }


/* 톱니바퀴는 항상 헤더 오른쪽 끝에. 모바일에서는 nav 가 하단 고정이라
   흐름에서 빠지므로, 밀어줄 요소가 없어 로고 옆에 붙어 보였다. */
.settings-wrap { margin-left: auto; }
