/* ───────── Pretendard font ───────── */
@import url('https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable-dynamic-subset.min.css');

/* ───────── Design tokens ───────── */
:root {
  --bg: #FAFAF9;
  --surface: #FFFFFF;
  --surface-2: #F4F4F2;
  --surface-3: #EDEDEA;
  --line: #E5E5E2;
  --line-strong: #D4D4D1;
  --ink: #0A0A0A;
  --ink-2: #262626;
  --ink-3: #525252;
  --ink-4: #737373;
  --ink-5: #A3A3A3;
  --accent: #6366F1;
  --accent-soft: color-mix(in oklch, var(--accent) 12%, transparent);
  --accent-ink: #fff;
  --danger: #DC2626;
  --warning: #D97706;
  --warn: #D97706;
  --ok: #059669;
  --radius-xs: 6px;
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-xl: 22px;
  --sb-w: 248px;
  --sb-w-compact: 64px;
  --native-titlebar-h: 40px;
  --shadow-sm: 0 1px 2px rgba(15, 15, 15, .04), 0 0 0 .5px rgba(15,15,15,.05);
  --shadow: 0 1px 3px rgba(15, 15, 15, .04), 0 8px 24px -8px rgba(15,15,15,.08), 0 0 0 .5px rgba(15,15,15,.06);
  --shadow-lg: 0 4px 8px rgba(15,15,15,.04), 0 24px 48px -12px rgba(15,15,15,.14), 0 0 0 .5px rgba(15,15,15,.06);
  --font: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
  --font-mono: 'SF Mono', 'JetBrains Mono', 'Cascadia Mono', Consolas, ui-monospace, Menlo, monospace;
  --t: 220ms cubic-bezier(.2,.7,.2,1);
}

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font);
  font-feature-settings: "ss01", "ss03", "cv01";
  background: var(--bg);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  letter-spacing: -0.011em;
  overflow: hidden;
  height: 100vh;
  word-break: keep-all;
  overflow-wrap: break-word;
}

/* ───────── Polls ───────── */
/* Follows the app idiom: 드라이브/국비-style underline tabs, 12px-radius cards
   without shadows, Supply-style modals, dot-grid empty states. Voting rows keep
   the accent border/fill only for selection + live results. */
.poll-list { display: flex; flex-direction: column; gap: 10px; }
.poll-card-real { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 24px; transition: border-color var(--t); }
.poll-card-real:hover { border-color: var(--line-strong); }
.poll-card-real.closed { background: color-mix(in oklab, var(--surface) 88%, var(--surface-2)); }
.poll-card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.poll-card-title-wrap { min-width: 0; }
.poll-badges { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.poll-card-title-wrap h2 { margin: 11px 0 7px; font-size: 17px; font-weight: 600; line-height: 1.4; letter-spacing: -.015em; }
.poll-author-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; color: var(--ink-4); font-size: 11.5px; }
.poll-author-row i { font-style: normal; color: var(--line-strong); }
.poll-participation { display: flex; align-items: baseline; gap: 4px; flex-shrink: 0; color: var(--ink-4); font-size: 11.5px; }
.poll-participation b { color: var(--ink); font-size: 15px; font-weight: 650; }
.poll-participation.private { align-items: center; gap: 5px; padding: 5px 8px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-2); color: var(--ink-4); }
.poll-options-real { display: flex; flex-direction: column; gap: 10px; }
.poll-option-real { position: relative; overflow: hidden; width: 100%; min-height: 52px; display: flex; align-items: flex-start; gap: 11px; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink-2); text-align: left; transition: border-color var(--t), background var(--t); }
.poll-option-real:hover:not(:disabled) { border-color: var(--line-strong); }
.poll-option-real.selected { border-color: var(--accent); background: color-mix(in oklch, var(--accent) 3%, var(--surface)); }
.poll-option-real:disabled { cursor: default; }
.poll-option-fill { position: absolute; inset: 0 auto 0 0; background: color-mix(in oklch, var(--accent) 7%, transparent); pointer-events: none; transition: width .35s ease; }
.poll-choice-mark { position: relative; z-index: 1; width: 18px; height: 18px; margin-top: 1px; border-radius: 50%; border: 1.5px solid var(--line-strong); display: grid; place-items: center; flex-shrink: 0; color: var(--accent-ink); }
.poll-choice-mark.square { border-radius: 5px; }
.poll-option-real.selected .poll-choice-mark { background: var(--accent); border-color: var(--accent); }
.poll-option-main { position: relative; z-index: 1; display: flex; flex: 1; min-width: 0; flex-direction: column; }
.poll-option-line { display: flex; align-items: center; gap: 12px; min-height: 20px; }
.poll-option-label { flex: 1; min-width: 0; font-size: 13.5px; font-weight: 550; line-height: 1.45; }
.poll-option-count { color: var(--ink-4); font-size: 11.5px; flex-shrink: 0; }
.poll-card-foot { display: flex; justify-content: space-between; align-items: center; gap: 16px; padding-top: 12px; color: var(--ink-4); font-size: 11.5px; }
.poll-summary-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-bottom: 18px; }
.poll-summary-grid > div { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; }
.poll-summary-grid span { display: block; color: var(--ink-4); font-size: 11px; margin-bottom: 6px; }
.poll-summary-grid b { font-size: 22px; font-weight: 650; letter-spacing: -.02em; }
.poll-manage-list { display: flex; flex-direction: column; gap: 8px; }
.poll-manage-card { display: grid; grid-template-columns: minmax(260px, 1fr) auto; align-items: center; gap: 20px; padding: 20px 22px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); transition: border-color var(--t); }
.poll-manage-card:hover { border-color: var(--line-strong); }
.poll-manage-main h3 { margin: 9px 0 5px; font-size: 15.5px; font-weight: 600; letter-spacing: -.012em; }
.poll-manage-main p { margin: 0; color: var(--ink-4); font-size: 11.5px; }
.poll-manage-stats { display: flex; gap: 16px; margin-top: 10px; color: var(--ink-3); font-size: 11.5px; }
.poll-manage-stats b { color: var(--ink); }
.poll-manage-stats.private > span { display: inline-flex; align-items: center; gap: 5px; color: var(--ink-4); }
.poll-manage-actions { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.poll-results-title { max-width: 640px; margin: 5px 0 0; font-size: 20px; font-weight: 650; line-height: 1.4; letter-spacing: -.02em; }
.poll-results-body { max-height: calc(100vh - 230px); overflow-y: auto; }
.poll-results-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; color: var(--ink-4); font-size: 11.5px; }
.poll-results-meta > span:last-child { margin-left: auto; }
.poll-results-summary { display: grid; grid-template-columns: 1fr 1fr 1.6fr; gap: 10px; margin: 18px 0 26px; }
.poll-results-summary > div { min-width: 0; padding: 18px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface-2); }
.poll-results-summary span { display: block; margin-bottom: 6px; color: var(--ink-4); font-size: 10.5px; }
.poll-results-summary b { display: inline; font-size: 24px; font-weight: 650; letter-spacing: -.02em; }
.poll-results-summary em { margin-left: 4px; color: var(--ink-4); font-size: 11px; font-style: normal; }
.poll-results-leading b { display: block; overflow: hidden; font-size: 12.5px; line-height: 1.35; text-overflow: ellipsis; white-space: nowrap; }
.poll-results-leading em { display: block; margin: 4px 0 0; }
.poll-results-section-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 10px; }
.poll-results-section-head h4 { margin: 0 0 3px; font-size: 13px; font-weight: 650; }
.poll-results-section-head p { margin: 0; color: var(--ink-4); font-size: 10.5px; }
.poll-results-section-head > span { color: var(--ink-4); font-size: 10.5px; }
.poll-results-list { display: flex; flex-direction: column; gap: 8px; }
.poll-results-locked { display: grid; justify-items: center; margin-top: 18px; padding: 58px 28px; border: 1px dashed var(--line-strong); border-radius: var(--radius); background: var(--surface-2); text-align: center; }
.poll-results-locked > div { width: 48px; height: 48px; display: grid; place-items: center; margin-bottom: 14px; border: 1px solid var(--line); border-radius: 50%; background: var(--surface); color: var(--ink-4); }
.poll-results-locked h4 { margin: 0; font-size: 15px; font-weight: 650; }
.poll-results-locked p { max-width: 440px; margin: 8px 0 0; color: var(--ink-3); font-size: 12px; line-height: 1.65; }
.poll-results-locked > span { margin-top: 12px; color: var(--ink-4); font-size: 11px; }
.poll-result-row { padding: 16px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.poll-result-row.leading { border-color: color-mix(in oklch, var(--accent) 35%, var(--line)); }
.poll-result-row-head { display: flex; align-items: center; gap: 8px; min-width: 0; }
.poll-result-row-head > b { overflow: hidden; flex: 1; min-width: 0; color: var(--ink-2); font-size: 12.5px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.poll-result-rank { width: 16px; flex-shrink: 0; color: var(--ink-5); font-size: 10.5px; text-align: center; }
.poll-result-score { flex-shrink: 0; color: var(--ink-3); font-size: 11px; }
.poll-result-track { height: 8px; margin: 11px 0 1px 24px; overflow: hidden; border-radius: 999px; background: var(--surface-3); }
.poll-result-track > span { display: block; height: 100%; border-radius: inherit; background: var(--line-strong); transition: width .35s ease; }
.poll-result-row.leading .poll-result-track > span { background: var(--accent); }
.poll-voter-list { position: relative; z-index: 1; display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--line); color: var(--ink-4); }
.poll-voter-list.compact { gap: 5px; margin-top: 8px; padding-top: 8px; }
.poll-voter-label { margin-right: 2px; color: var(--ink-4); font-size: 10px; font-weight: 650; letter-spacing: .03em; }
.poll-voter-chip { display: inline-flex; align-items: center; gap: 5px; max-width: 180px; padding: 3px 8px 3px 3px; border: 1px solid var(--line); border-radius: 999px; background: color-mix(in oklab, var(--surface) 90%, var(--surface-2)); color: var(--ink-3); font-size: 11px; font-weight: 550; }
.poll-voter-chip > span:last-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.poll-voter-list.compact .poll-voter-chip { padding: 2px 7px 2px 2px; font-size: 10.5px; }
.poll-voter-none { color: var(--ink-5); font-size: 10.5px; }
.poll-results-empty { display: grid; justify-items: center; padding: 34px 20px; border: 1px dashed var(--line-strong); border-radius: var(--radius-sm); color: var(--ink-4); text-align: center; }
.poll-results-empty svg { margin-bottom: 9px; color: var(--ink-5); }
.poll-results-empty p { margin: 0; color: var(--ink-2); font-size: 13px; font-weight: 600; }
.poll-results-empty span { margin-top: 4px; font-size: 11px; }
.poll-results-note { margin: 12px 0 0; color: var(--ink-4); font-size: 10.5px; line-height: 1.5; }
.poll-section-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 16px; margin-bottom: 14px; }
.poll-section-head h2 { margin: 0 0 4px; font-size: 15.5px; font-weight: 650; letter-spacing: -.015em; }
.poll-section-head p { margin: 0; color: var(--ink-4); font-size: 11.5px; }
.poll-template-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.poll-template-card { display: flex; flex-direction: column; padding: 16px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); transition: border-color var(--t); }
.poll-template-card:hover { border-color: var(--line-strong); }
.poll-template-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.poll-template-icon { width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center; background: var(--surface-2); color: var(--ink-2); }
.poll-template-scope { color: var(--ink-4); font-size: 10.5px; }
.poll-template-card h3 { margin: 12px 0 4px; font-size: 14px; font-weight: 600; letter-spacing: -.012em; }
.poll-template-card > p { margin: 0; color: var(--ink-4); font-size: 11.5px; line-height: 1.55; }
.poll-template-meta { display: flex; align-items: center; gap: 6px; margin-top: 10px; color: var(--ink-4); font-size: 10.5px; }
.poll-template-meta i { color: var(--line-strong); font-style: normal; }
.poll-template-actions { display: flex; gap: 6px; align-items: center; margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line); }
.poll-template-actions .btn:first-child { flex: 1; justify-content: center; }
.poll-empty { padding: 80px 20px; text-align: center; color: var(--ink-4); }
.poll-empty.compact { padding: 48px 20px; }
.poll-empty .dot-grid { width: 100px; height: 100px; margin: 0 auto 16px; border-radius: 18px; }
.poll-empty p { margin: 0; font-size: 14px; }
.poll-empty .btn { margin-top: 14px; }
.poll-loading { padding: 80px 20px; text-align: center; color: var(--ink-4); font-size: 13px; }
.poll-error-card { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 16px; padding: 14px 16px; border: 1px solid color-mix(in oklch, var(--warn) 30%, var(--line)); background: color-mix(in oklch, var(--warn) 7%, var(--surface)); border-radius: var(--radius); }
.poll-error-card > svg { color: var(--warn); flex-shrink: 0; margin-top: 2px; }
.poll-error-card > div { flex: 1; min-width: 0; }
.poll-error-card b { font-size: 12.5px; }
.poll-error-card p { margin: 3px 0 0; color: var(--ink-4); font-size: 11.5px; line-height: 1.5; }

.poll-editor-section { padding: 22px 0; border-bottom: 1px solid var(--line); }
.poll-editor-section:first-child { padding-top: 2px; }
.poll-editor-section:last-child { border-bottom: 0; padding-bottom: 2px; }
.poll-editor-section > h4 { margin: 0 0 16px; font-size: 11.5px; font-weight: 650; color: var(--ink-3); letter-spacing: .06em; text-transform: uppercase; }
.poll-field-label { display: block; margin: 20px 0 8px; color: var(--ink-2); font-size: 13px; font-weight: 600; }
/* Only a label that literally opens its group loses the top gap — the section
   title (h4) counts as the opener. :first-of-type would also catch the first
   DIV-based label (선택 항목) mid-section and glue it to the field above. */
.poll-editor-section > h4 + .poll-field-label, .poll-field-label:first-child { margin-top: 0; }
.poll-field-help { margin: 7px 0 0; color: var(--ink-4); font-size: 11.5px; line-height: 1.45; }
.poll-label-row { display: flex; justify-content: space-between; gap: 12px; }
.poll-label-row em { color: var(--warn); font-style: normal; font-weight: 450; }
.poll-option-inputs { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.poll-option-inputs > div { display: flex; align-items: center; gap: 7px; }
.poll-option-inputs > div > .num { width: 20px; color: var(--ink-4); text-align: center; font-size: 11px; flex-shrink: 0; }
.poll-option-inputs .input { flex: 1; min-width: 0; }
.poll-option-inputs .icon-btn { flex-shrink: 0; }
.poll-setting-list { display: flex; flex-direction: column; gap: 3px; }
/* Date and time boxes split the row evenly and share one 38px height — a lone
   odd-sized box reads as broken. (Equal halves also fit ko-locale "오후 06:00"
   plus the clock icon, which a narrow fixed column used to clip.) */
.poll-deadline-row { display: grid; grid-template-columns: 1fr 1fr auto; align-items: start; gap: 8px; }
.poll-deadline-row > div { min-width: 0; }
.poll-deadline-row .input { height: 38px; padding-top: 0; padding-bottom: 0; }
.poll-deadline-row .btn { height: 38px; min-height: 0; }
/* 마감 없음: the time box empties and greys out exactly like the date box. */
.poll-deadline-row .input:disabled { color: var(--ink-5); -webkit-text-fill-color: var(--ink-5); }
.poll-no-deadline.active { border-color: var(--ink); background: var(--surface-2); font-weight: 600; }
.poll-toggle-row { min-height: 48px; display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.poll-toggle-row.compact { min-height: 40px; padding: 6px 0; }
.poll-toggle-row:last-child { border-bottom: 0; }
.poll-toggle-row b { display: block; font-size: 13.5px; }
.poll-toggle-row span { display: block; margin-top: 3px; color: var(--ink-4); font-size: 11.5px; line-height: 1.4; }
/* Same toggle as ProfileDrawer's 앱 알림 switch (40×23, 19px thumb). */
.poll-switch { width: 40px; height: 23px; flex-shrink: 0; padding: 2px; border: 0; border-radius: 999px; background: var(--line-strong); transition: background var(--t); }
.poll-switch > span { display: block; width: 19px; height: 19px; margin: 0; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: transform var(--t); }
.poll-switch.on { background: var(--accent); }
.poll-switch.on > span { transform: translateX(17px); }
.poll-external-fields { padding: 13px 14px 14px; margin-top: 8px; border-radius: var(--radius-sm); background: var(--surface-2); }
.poll-org-pills { display: flex; flex-wrap: wrap; gap: 6px; }
.poll-org-pills button { display: inline-flex; align-items: center; gap: 5px; padding: 6px 10px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink-3); font-size: 12px; font-family: inherit; }
.poll-org-pills button.active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.poll-warning { display: flex; align-items: flex-start; gap: 8px; padding: 10px 11px; border: 1px solid color-mix(in oklch, var(--warn) 28%, var(--line)); border-radius: var(--radius-sm); background: color-mix(in oklch, var(--warn) 7%, var(--surface)); color: var(--ink-3); font-size: 11.5px; line-height: 1.5; }
.poll-warning svg { color: var(--warn); flex-shrink: 0; margin-top: 1px; }
.poll-helper { margin: 0; color: var(--ink-4); font-size: 12px; }
.poll-inline-note { display: flex; align-items: center; gap: 8px; padding: 0 0 13px; border-bottom: 1px solid var(--line); color: var(--ink-4); font-size: 12px; }
.poll-inline-note svg { flex-shrink: 0; color: var(--ink-3); }
.poll-template-settings { display: flex; flex-direction: column; }

@media (max-width: 900px) {
  .poll-card-real { padding: 16px; }
  .poll-template-grid { grid-template-columns: 1fr 1fr; }
  .poll-manage-card { grid-template-columns: 1fr; }
  .poll-manage-actions { justify-content: flex-start; }
}

@media (max-width: 600px) {
  .poll-card-head { flex-direction: column; gap: 12px; }
  .poll-card-foot { align-items: stretch; flex-direction: column; }
  .poll-card-foot .btn { width: 100%; justify-content: center; }
  .poll-summary-grid, .poll-template-grid { grid-template-columns: 1fr; }
  .poll-results-meta > span:last-child { width: 100%; margin: 4px 0 0; }
  .poll-results-summary { grid-template-columns: 1fr 1fr; }
  .poll-results-leading { grid-column: 1 / -1; }
  .poll-result-row-head { flex-wrap: wrap; }
  .poll-result-row-head > b { flex-basis: calc(100% - 24px); }
  .poll-result-row-head .pill { margin-left: 24px; }
  .poll-result-score { margin-left: auto; }
  .poll-section-head { align-items: flex-start; flex-direction: column; }
  .poll-deadline-row { grid-template-columns: 1fr 1fr; }
  .poll-deadline-row > .btn { grid-column: 1 / -1; justify-content: center; }
}
#root, #__next { height: 100vh; }
.app-viewport {
  width: 100%;
  height: 100vh;
  overflow: hidden;
}
.tauri-app .app-viewport {
  padding-top: var(--native-titlebar-h);
}

/* ───────── Tauri desktop frame ───────── */
.native-titlebar {
  display: none;
  position: fixed;
  inset: 0 0 auto;
  z-index: 1000;
  height: var(--native-titlebar-h);
  align-items: center;
  color: var(--ink-3);
  background: color-mix(in oklab, var(--surface-2) 92%, var(--surface));
  border-bottom: 1px solid var(--line);
  box-shadow: 0 1px 0 rgba(255, 255, 255, .7) inset;
  user-select: none;
  -webkit-user-select: none;
}
.tauri-app .native-titlebar { display: flex; }
.native-titlebar-drag { align-self: stretch; flex: 1; }
.native-window-controls {
  align-self: stretch;
  display: flex;
  margin-left: auto;
}
.native-window-button {
  width: 46px;
  height: 100%;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-left: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--ink-3);
  transition: color 120ms ease, background 120ms ease;
}
.native-window-button:hover {
  background: var(--surface-3);
  color: var(--ink);
}
.native-window-button:active { background: var(--line); }
/* 채점하기(과제 관리) 카드 — 데스크톱 창 조작 버튼(✕·최대화)은 z-index 1000이라
   모달 위에도 떠 있다. 카드가 화면 위까지 차면 카드의 닫기(✕)와 창의 ✕가 같은
   구석에 겹쳐 보여, 카드를 닫으려다 창을 닫게 된다. 타이틀바 아래로 내려 띄운다. */
.tauri-app .tutor-task-bg { padding-top: calc(var(--native-titlebar-h) + 28px); }
.native-window-button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -3px;
  border-radius: 2px;
}
.native-window-button svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.15;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.native-window-close:hover {
  color: var(--accent-ink);
  background: var(--danger);
}
.native-window-close:active { background: color-mix(in oklch, var(--danger) 84%, var(--ink)); }
button { font-family: inherit; cursor: default; }
input, textarea, select { font-family: inherit; color: inherit; }
::selection { background: var(--accent); color: var(--accent-ink); }
*:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }

/* ───────── Layout shell ───────── */
.shell {
  display: grid;
  grid-template-columns: var(--current-sb, var(--sb-w)) 1fr;
  height: 100%;
  background: var(--bg);
  transition: grid-template-columns var(--t);
}
.shell.compact { --current-sb: var(--sb-w-compact); }

/* ───────── Sidebar ───────── */
.sb {
  background: var(--surface-2);
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  padding: 18px 12px 14px;
  gap: 4px;
  overflow: hidden;
  transition: padding var(--t);
}
.shell.compact .sb { padding: 18px 8px 14px; align-items: center; }
.sb-brand {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 10px 18px;
  color: var(--ink);
}
.sb-logo {
  width: 26px; height: 26px; border-radius: 7px;
  background: var(--ink); color: var(--bg);
  display: grid; place-items: center;
  font-weight: 700; font-size: 13px;
  flex-shrink: 0;
  letter-spacing: -.04em;
}
.sb-brand-name { font-weight: 600; font-size: 14px; letter-spacing: -.015em; white-space: nowrap; }
.sb-brand-sub { font-size: 11px; color: var(--ink-4); white-space: nowrap; font-variant-numeric: tabular-nums; }
.shell.compact .sb-brand-text { display: none; }

.sb-search {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 7px 10px;
  margin-bottom: 12px;
  color: var(--ink-4);
  font-size: 12.5px;
  transition: border-color var(--t);
}
.sb-search:hover { border-color: var(--line-strong); }
.sb-search kbd {
  margin-left: auto;
  font-family: var(--font);
  font-size: 10px;
  padding: 2px 5px;
  background: var(--surface-2);
  border-radius: 4px;
  color: var(--ink-4);
  border: 1px solid var(--line);
}
.shell.compact .sb-search { padding: 7px; justify-content: center; }
.shell.compact .sb-search-text, .shell.compact .sb-search kbd { display: none; }

.sb-section {
  font-size: 10.5px; font-weight: 600; color: var(--ink-4);
  text-transform: uppercase; letter-spacing: .08em;
  padding: 14px 10px 6px;
}
.shell.compact .sb-section {
  color: transparent; height: 1px; padding: 8px 0 0; margin: 6px 0;
  border-top: 1px solid var(--line); pointer-events: none;
}

.sb-item {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px;
  border-radius: var(--radius-sm);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 450;
  cursor: default;
  transition: background var(--t), color var(--t);
  position: relative;
  white-space: nowrap;
  border: 0;
  background: transparent;
  text-align: left;
  width: 100%;
  font-family: inherit;
  text-decoration: none;
}
.sb-item:hover { background: var(--surface-3); }
.sb-nav .sb-item.nav-pending { background: var(--accent-soft); color: var(--accent); }
html.ws-navigating::after { content: ''; position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 2000; pointer-events: none; background: linear-gradient(90deg, transparent, var(--accent), transparent); background-size: 50% 100%; background-repeat: no-repeat; animation: navProgress 1s linear infinite; }
@keyframes navProgress { from { background-position: -100% 0; } to { background-position: 200% 0; } }
@media (prefers-reduced-motion: reduce) { html.ws-navigating::after { animation: none; background: var(--accent); } }
[data-nav-reorder] .sb-item { cursor: grab; }
[data-nav-reorder] .sb-item.nav-dragging { opacity: .4; cursor: grabbing; }
.sb-order-status { font-size: 11px; color: var(--danger, #dc2626); padding: 8px 4px; }
.sb-item.active { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-sm); font-weight: 550; }
.sb-item .sb-num {
  font-family: var(--font);
  font-size: 10px;
  color: var(--ink-5);
  margin-left: auto;
  font-variant-numeric: tabular-nums;
}
.sb-item .sb-badge {
  margin-left: auto;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 10px; font-weight: 600;
  padding: 1px 6px;
  border-radius: 8px;
  line-height: 1.4;
  min-width: 16px; text-align: center;
}
.shell.compact .sb-item { justify-content: center; padding: 9px; width: 40px; height: 40px; }
.shell.compact .sb-item-text, .shell.compact .sb-num, .shell.compact .sb-badge { display: none; }
.shell.compact .sb-item.active::after {
  content: "";
  position: absolute; right: -10px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 18px;
  background: var(--ink); border-radius: 2px;
}
.sb-icon { width: 16px; height: 16px; flex-shrink: 0; color: currentColor; }

/* Nav list scrolls on its own so items are never clipped by the sidebar's
   overflow: hidden on short windows; padding/margin offset keeps the active
   item's box-shadow from clipping at the scroll edge. */
.sb-nav {
  display: flex; flex-direction: column; gap: 4px;
  flex: 1; min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent;
  padding: 4px; margin: -4px;
}
.shell.compact .sb-nav { align-items: center; }

.sb-foot { margin-top: auto; padding-top: 8px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 2px; }
.sb-user {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  transition: background var(--t);
}
.sb-user:hover { background: var(--surface-3); }
.sb-user-btn {
  width: 100%;
  border: 0;
  background: transparent;
  color: inherit;
  font-family: inherit;
  text-align: left;
  cursor: default;
}
.sb-avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--ink); color: var(--bg);
  display: grid; place-items: center;
  font-weight: 600; font-size: 11px;
  flex-shrink: 0;
  position: relative;
}
.sb-avatar::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 9px; height: 9px; background: #10B981; border-radius: 50%;
  border: 2px solid var(--surface-2);
}
.sb-user-name { font-size: 12.5px; font-weight: 550; white-space: nowrap; }
.sb-user-role { font-size: 11px; color: var(--ink-4); white-space: nowrap; }
.shell.compact .sb-user-text { display: none; }

/* ───────── Main canvas ───────── */
.main {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  min-width: 0;
  background: var(--bg);
}

.topbar {
  display: flex; align-items: center;
  height: 56px;
  padding: 0 28px;
  border-bottom: 1px solid var(--line);
  background: color-mix(in oklab, var(--bg) 85%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  flex-shrink: 0;
  gap: 16px;
}
.crumbs { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-4); }
.crumbs .crumb-current { color: var(--ink); font-weight: 550; letter-spacing: -.012em; }
.crumbs .crumb-sep { color: var(--ink-5); }
.crumb { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-4); }
.crumb b { color: var(--ink); font-weight: 550; }
.crumb > * { white-space: nowrap; }

/* Generic avatar (admin uses this without the .sb- prefix) */
.avatar {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--ink); color: var(--bg);
  display: grid; place-items: center;
  font-weight: 600; font-size: 11px;
  flex-shrink: 0; letter-spacing: -.02em;
}
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.icon-btn {
  width: 32px; height: 32px;
  display: grid; place-items: center;
  border: 1px solid transparent;
  background: transparent;
  color: var(--ink-3);
  border-radius: var(--radius-sm);
  transition: all var(--t);
  position: relative;
}
.icon-btn:hover { background: var(--surface-2); color: var(--ink); }
.icon-btn .dot {
  position: absolute; top: 7px; right: 8px;
  width: 6px; height: 6px; background: var(--accent); border-radius: 50%;
  border: 1.5px solid var(--bg);
}

.page {
  flex: 1; min-height: 0; overflow: hidden;
  display: flex; flex-direction: column;
}

/* ───────── Buttons & inputs ───────── */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: 13px; font-weight: 500;
  transition: all var(--t);
  cursor: default;
  letter-spacing: -.01em;
  white-space: nowrap;
  flex-shrink: 0;
  font-family: inherit;
}
.pill, .crumbs > *, .sb-section, .sb-item-text, .sb-user-name, .sb-user-role,
.sb-brand-name, .sb-brand-sub, .sb-search-text,
.mono, kbd, .icon-btn { white-space: nowrap; }
button { white-space: nowrap; }
.btn:hover { background: var(--surface-2); border-color: var(--line-strong); }
.btn.primary { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.btn.primary:hover { background: var(--ink-2); }
.btn.accent { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.btn.accent:hover { filter: brightness(.93); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-3); }
.btn.ghost:hover { background: var(--surface-2); color: var(--ink); }
.btn.danger { color: var(--danger); border-color: color-mix(in oklch, var(--danger) 25%, var(--line)); }
.btn.danger:hover { background: color-mix(in oklch, var(--danger) 8%, transparent); }
.btn.sm { padding: 4px 10px; font-size: 12px; }
.btn.lg { padding: 10px 18px; font-size: 14px; border-radius: var(--radius); }
.btn:disabled { opacity: .5; pointer-events: none; }

.input, .textarea, .select {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  font-size: 13px;
  color: var(--ink);
  width: 100%;
  transition: border-color var(--t), box-shadow var(--t);
  outline: none;
}
.input:focus, .textarea:focus, .select:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* Placeholders are hint text — always render in the sans face so a Korean
   placeholder (e.g. "값") looks identical even when the input's value font is
   monospace (password/URL/code fields). */
.input::placeholder, .textarea::placeholder { color: var(--ink-5); font-family: var(--font); }
.textarea { resize: vertical; min-height: 90px; line-height: 1.5; }
.label { font-size: 11px; font-weight: 600; color: var(--ink-3); letter-spacing: .04em; text-transform: uppercase; margin-bottom: 6px; display: block; }

/* ───────── Surfaces ───────── */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Default inset. Stat cards and chart panels rely on this; full-bleed cards
     (with edge-to-edge dividers/lists) opt out with an inline `padding: 0`. */
  padding: 22px;
  transition: border-color var(--t), transform var(--t);
}
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px;
  font-size: 11px; font-weight: 550;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink-3);
  border: 1px solid var(--line);
  letter-spacing: -.005em;
  white-space: nowrap;
}
.pill.accent { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.pill.ok { background: color-mix(in oklch, #059669 12%, transparent); color: #059669; border-color: transparent; }
.pill.warn { background: color-mix(in oklch, #D97706 14%, transparent); color: #D97706; border-color: transparent; }
.pill.danger { background: color-mix(in oklch, #DC2626 12%, transparent); color: #DC2626; border-color: transparent; }

/* ───────── Table (admin) ───────── */
.table { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; overflow: hidden; }
.table-head { display: grid; gap: 16px; padding: 12px 20px; background: var(--surface-2); font-size: 10.5px; color: var(--ink-4); letter-spacing: .08em; text-transform: uppercase; font-weight: 600; }
.table-row { display: grid; gap: 16px; padding: 14px 20px; font-size: 13px; align-items: center; border-top: 1px solid var(--line); transition: background var(--t); }
.table-row:hover { background: var(--surface-2); }

/* ───────── Modal ───────── */
/* Enhanced Navigation이 보이던 div를 닫힌 모달로 재사용해도 opacity 전환 중 노출되지 않게 합니다. */
.modal-bg { position: fixed; inset: 0; background: rgba(10,10,10,.4); backdrop-filter: blur(4px); display: grid; place-items: center; z-index: 100; padding: 24px; visibility: hidden; opacity: 0; pointer-events: none; transition: opacity var(--t); }
.modal-bg.on { visibility: visible; opacity: 1; pointer-events: auto; }
.modal { background: var(--surface); border: 1px solid var(--line); border-radius: 18px; width: 100%; max-width: 480px; box-shadow: var(--shadow-lg); transform: scale(.96) translateY(8px); transition: transform var(--t); overflow: hidden; }
.modal-bg.on .modal { transform: scale(1) translateY(0); }
.modal-head { padding: 22px 24px 4px; display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
/* 모달 제목 기본값. 이 값이 없어서 지금까지는 모달마다 같은 인라인 스타일을
   복붙해 왔다 — <Modal.Head title>은 이 규칙에 기대 아무것도 인라인으로 주지 않는다. */
.modal-head h3 { font-size: 18px; font-weight: 650; letter-spacing: -.02em; margin: 4px 0 0; }
/* 모달 설명문 기본값. 이게 없어서 모달마다 따로 선언해 왔고, 선언을 빠뜨린
   모달만 본문 기본 글자를 물려받아 혼자 크고 진하게 보였다. */
.modal-head p { margin: 6px 0 0; color: var(--ink-4); font-size: 12.5px; line-height: 1.55; }
.modal-body { padding: 16px 24px 24px; }
.modal-foot { padding: 16px 24px; border-top: 1px solid var(--line); display: flex; gap: 8px; justify-content: flex-end; background: var(--surface-2); }
.modal-foot.center { justify-content: center; }
.modal-foot.between { justify-content: space-between; }
/* 본문이 길어 스크롤돼야 하는 모달(<Modal scroll>). 머리와 바닥은 제자리에 붙어
   있고 본문만 구른다. 여러 모달이 이 세 줄을 인라인으로 되풀이하고 있었다. */
.modal.scroll { display: flex; flex-direction: column; max-height: calc(100vh - 64px); }
.modal.scroll > .modal-body { overflow: auto; min-height: 0; }

/* ───────── Tabs · 세그먼트 · 칩 ───────── */
/* 값 하나를 고르는 가로 선택기(<Tabs>). 네 가지 모양은 앱에 이미 있던 것들이다:
   underline = 국비/투표 탭, segmented = 비품/지출 스위치, chip = 상태 필터 알약,
   soft = 내일배움카드 뷰 전환. 바깥 여백은 쓰는 자리에서 준다. */
.tabs { display: flex; align-items: center; flex-wrap: wrap; min-width: 0; }
/* 커서는 앱 전역 규칙(button { cursor: default })을 따른다 — 손가락 커서를 쓰지 않는다. */
.tabs-item { display: inline-flex; align-items: center; gap: 5px; border: 0; background: transparent; font-family: inherit; color: var(--ink-4); transition: color var(--t), background var(--t), border-color var(--t), box-shadow var(--t); }
.tabs-item:disabled { opacity: .45; cursor: not-allowed; }
.tabs-count { font-variant-numeric: tabular-nums; }
.tabs-end { margin-left: auto; padding-left: 12px; color: var(--ink-5); font-size: 11px; }

/* underline — 밑줄 2px. 항목의 -1px 아래 여백이 컨테이너 경계선을 덮는다. */
.tabs.underline { border-bottom: 1px solid var(--line); }
.tabs.underline .tabs-item { padding: 11px 2px; margin: 0 20px -1px 0; border-bottom: 2px solid transparent; font-size: 13.5px; font-weight: 550; letter-spacing: -.01em; }
.tabs.underline .tabs-item:hover:not(.on):not(:disabled) { color: var(--ink-2); }
.tabs.underline .tabs-item.on { color: var(--ink); border-bottom-color: var(--ink); }
.tabs.underline .tabs-count { color: var(--ink-5); font-size: 10.5px; }

/* segmented — 회색 트랙 위의 스위치. */
.tabs.segmented { gap: 4px; width: fit-content; padding: 3px; border-radius: 10px; background: var(--surface-2); }
.tabs.segmented .tabs-item { gap: 4px; padding: 7px 16px; border-radius: 7px; font-size: 12.5px; font-weight: 550; }
.tabs.segmented .tabs-item:hover:not(.on):not(:disabled) { color: var(--ink-2); }
.tabs.segmented .tabs-item.on { color: var(--ink); background: var(--surface); box-shadow: var(--shadow-sm); }
.tabs.segmented .tabs-count { opacity: .6; }

/* chip — 둥근 알약. 개수가 많아 줄바꿈되는 필터에 쓴다. */
.tabs.chip { gap: 6px; }
.tabs.chip .tabs-item { gap: 4px; padding: 6px 12px; border: 1px solid var(--line); border-radius: 999px; color: var(--ink-2); background: var(--surface); font-size: 12px; font-weight: 500; }
.tabs.chip .tabs-item:hover:not(.on):not(:disabled) { border-color: var(--line-strong); }
.tabs.chip .tabs-item.on { color: var(--bg); background: var(--ink); border-color: var(--ink); }
.tabs.chip .tabs-count { opacity: .65; }

/* soft — accent 배경. 가운데 정렬해 쓰는 뷰 전환. */
.tabs.soft { gap: 5px; }
.tabs.soft .tabs-item { min-height: 38px; padding: 8px 15px; border-radius: 9px; font-size: 13px; }
.tabs.soft .tabs-item:hover:not(.on):not(:disabled) { color: var(--ink-2); background: var(--surface-2); }
.tabs.soft .tabs-item.on { color: var(--accent); background: var(--accent-soft); font-weight: 650; }
.tabs.soft .tabs-count { opacity: .7; }

/* sm — 11px 보조 선택기(.lms-fview-seg 급). */
.tabs.sm .tabs-item { font-size: 11px; font-weight: 600; letter-spacing: -.01em; }
.tabs.underline.sm .tabs-item { padding: 8px 2px; margin-right: 16px; }
.tabs.segmented.sm { gap: 2px; padding: 2px; border-radius: 8px; }
.tabs.segmented.sm .tabs-item { padding: 4px 9px; border-radius: 6px; }
/* 부모 폭을 꽉 채우는 세그먼트(팝오버 안의 스위치 등) */
.tabs.segmented.fill { width: auto; }
.tabs.segmented.fill .tabs-item { flex: 1; justify-content: center; }
.tabs.chip.sm .tabs-item { padding: 4px 10px; }
.tabs.soft.sm .tabs-item { min-height: 30px; padding: 6px 11px; border-radius: 7px; }

/* ───────── Desktop app updater ───────── */
.app-update-overlay {
  position: fixed;
  inset: 0;
  z-index: 900;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(15, 15, 18, .48);
  backdrop-filter: blur(9px) saturate(.85);
  animation: app-update-fade .2s ease-out both;
}
.tauri-app .app-update-overlay { top: var(--native-titlebar-h); }
.app-update-dialog {
  width: min(500px, 100%);
  padding: 28px;
  border: 1px solid var(--line);
  border-radius: 22px;
  background: color-mix(in oklab, var(--surface) 96%, transparent);
  box-shadow: 0 28px 90px rgba(0, 0, 0, .28), var(--shadow-lg);
  animation: app-update-rise .24s cubic-bezier(.2, .8, .2, 1) both;
}
.app-update-icon {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  margin-bottom: 20px;
  border-radius: 14px;
  color: var(--accent-ink);
  background: var(--accent);
  box-shadow: 0 10px 24px color-mix(in oklch, var(--accent) 28%, transparent);
}
.app-update-icon svg,
.app-update-reminder svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.app-update-eyebrow {
  margin: 0 0 7px;
  color: var(--accent);
  font-size: 10px;
  font-weight: 750;
  letter-spacing: .12em;
}
.app-update-copy h2 {
  margin: 0;
  color: var(--ink);
  font-size: 21px;
  line-height: 1.35;
  letter-spacing: -.025em;
}
.app-update-version {
  margin: 7px 0 0;
  color: var(--ink-3);
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
.app-update-progress {
  position: relative;
  height: 5px;
  margin-top: 24px;
  overflow: hidden;
  border-radius: 99px;
  background: var(--surface-3);
}
.app-update-progress i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  transition: width .16s linear;
}
.app-update-progress.indeterminate::after {
  content: '';
  position: absolute;
  inset-block: 0;
  width: 42%;
  border-radius: inherit;
  background: var(--accent);
  animation: app-update-sweep 1.1s cubic-bezier(.4, 0, .2, 1) infinite;
}
.app-update-status {
  min-height: 18px;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin-top: 9px;
  color: var(--ink-4);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.app-update-status strong { color: var(--ink-2); font-weight: 650; }
.app-update-notes {
  max-height: 76px;
  margin: 17px 0 0;
  padding: 12px 14px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: 11px;
  color: var(--ink-3);
  background: var(--surface-2);
  font-size: 11.5px;
  line-height: 1.55;
  white-space: pre-wrap;
}
.app-update-error {
  margin: 20px 0 0;
  padding: 12px 14px;
  border-radius: 11px;
  color: var(--danger, #c2413b);
  background: color-mix(in oklch, var(--danger, #c2413b) 9%, transparent);
  font-size: 12px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.app-update-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 24px;
}
.app-update-reminder {
  position: fixed;
  right: 22px;
  bottom: 22px;
  z-index: 850;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 11px 14px;
  border: 1px solid var(--line);
  border-radius: 13px;
  color: var(--ink);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  font-size: 12px;
  font-weight: 600;
}
.app-update-reminder:hover { background: var(--surface-2); }
.app-update-reminder svg { width: 17px; height: 17px; color: var(--accent); }
/* LMS 엔진 설치 필(LmsEngineGate)은 같은 구석을 쓴다 — 앱 업데이트 필과 동시에
   뜨면 정확히 겹치므로 한 칸 위에 세운다. 받아쓰기 준비 필(LmsSetupGate)은 엔진
   설치와 나란히 돌 수 있어(탭 진입 자동 설치 + 생성 시작) 또 한 칸 위다. */
.app-update-reminder.lms-engine { bottom: 74px; }
.app-update-reminder.lms-setup { bottom: 126px; }
@keyframes app-update-fade { from { opacity: 0; } }
@keyframes app-update-rise { from { opacity: 0; transform: translateY(10px) scale(.98); } }
@keyframes app-update-sweep { from { transform: translateX(-110%); } to { transform: translateX(345%); } }

/* ───────── Toast ───────── */
.toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--ink); color: var(--bg); padding: 12px 18px; border-radius: 14px; font-size: 13px; font-weight: 500; box-shadow: var(--shadow-lg); z-index: 200; display: inline-flex; align-items: flex-start; gap: 10px; max-width: min(92vw, 560px); word-break: break-word; line-height: 1.45; opacity: 0; pointer-events: none; transition: opacity .3s, transform .3s; }
.toast.on { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.toast.off { transform: translateX(-50%) translateY(8px); }

/* ───────── Scrollbars ───────── */
.scrolly { overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
.scrolly::-webkit-scrollbar { width: 10px; height: 10px; }
.scrolly::-webkit-scrollbar-track { background: transparent; }
.scrolly::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 999px; border: 3px solid transparent; background-clip: padding-box; }
.scrolly::-webkit-scrollbar-thumb:hover { background: var(--ink-5); background-clip: padding-box; border: 3px solid transparent; }

/* ───────── Animations ───────── */
@keyframes pageIn { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.page-anim { animation: pageIn .35s cubic-bezier(.2,.7,.2,1); }
/* Modern tooltip (components/ui/Tooltip): a quick fade + tiny rise on appear. */
@keyframes tooltipIn { from { opacity: 0; transform: translateY(2px); } to { opacity: 1; transform: none; } }
/* Indeterminate progress: a chunk that sweeps across the track while we don't
   yet have a real percentage (reading a dropped folder, creating its tree). */
@keyframes indetSweep { from { left: -45%; } to { left: 100%; } }
.indet-bar { position: relative; overflow: hidden; }
.indet-bar::after { content: ''; position: absolute; top: 0; bottom: 0; width: 45%; border-radius: 99px; background: var(--accent); animation: indetSweep 1.1s cubic-bezier(.4,0,.2,1) infinite; }
/* A view rendered directly inside .page must be the flex column that fills it,
   so its .page-body.scrolly gets a bounded height and actually scrolls. The app
   shell sets this inline; admin views rely on this rule. (Scoped to direct
   children so nested .page-anim animation wrappers are unaffected.) */
.page > .page-anim { display: flex; flex-direction: column; flex: 1; min-height: 0; }

.dot-grid {
  background-image: radial-gradient(var(--line-strong) 1px, transparent 1px);
  background-size: 16px 16px;
}

/* ───────── 국민내일배움카드 대장 ───────── */
.nb-dashboard { display: flex; flex-direction: column; gap: 20px; width: 100%; padding-bottom: 20px; }
.nb-toolbar { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; padding-top: 2px; }
.nb-toolbar h2 { margin: 5px 0 6px; color: var(--ink); font-size: 22px; line-height: 1.25; font-weight: 680; letter-spacing: -.025em; }
.nb-toolbar p { margin: 0; color: var(--ink-4); font-size: 13px; line-height: 1.6; }
.nb-eyebrow { display: inline-flex; align-items: center; gap: 7px; color: var(--accent); font-size: 11px; font-weight: 700; letter-spacing: .04em; }
.nb-eyebrow.fail { color: #b91c1c; }
.nb-source-dot { width: 7px; height: 7px; border-radius: 50%; background: #16a34a; box-shadow: 0 0 0 4px color-mix(in oklch, #16a34a 12%, transparent); }
.nb-source-dot.fail { background: #dc2626; box-shadow: 0 0 0 4px color-mix(in oklch, #dc2626 12%, transparent); }
.nb-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.nb-spin { animation: nb-spin .8s linear infinite; }
@keyframes nb-spin { to { transform: rotate(360deg); } }

.nb-message { display: flex; align-items: center; gap: 11px; padding: 13px 15px; border: 1px solid var(--line); border-radius: 12px; font-size: 12px; }
.nb-message > svg { flex-shrink: 0; }
.nb-message > div { display: flex; flex: 1; min-width: 0; gap: 8px; align-items: baseline; }
.nb-message strong { font-weight: 650; }
.nb-message span { color: var(--ink-3); overflow-wrap: anywhere; }
.nb-message.warn { color: #b45309; background: color-mix(in oklch, #f59e0b 8%, var(--surface)); border-color: color-mix(in oklch, #f59e0b 24%, var(--line)); }
.nb-message.danger { color: var(--danger); background: color-mix(in oklch, var(--danger) 7%, var(--surface)); border-color: color-mix(in oklch, var(--danger) 22%, var(--line)); }

.nb-kpis { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.nb-kpi { min-height: 154px; padding: 19px 20px 17px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); box-shadow: 0 1px 2px rgba(0,0,0,.015); }
.nb-kpi.accent { border-color: color-mix(in oklch, var(--accent) 24%, var(--line)); background: linear-gradient(145deg, color-mix(in oklch, var(--accent) 6%, var(--surface)), var(--surface) 62%); }
.nb-kpi-top { display: flex; align-items: center; gap: 9px; color: var(--ink-3); font-size: 13px; font-weight: 600; }
.nb-kpi-icon { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 10px; color: var(--accent); background: var(--accent-soft); }
.nb-kpi-value { margin-top: 15px; color: var(--ink); font-size: 32px; line-height: 1; font-weight: 720; letter-spacing: -.035em; }
.nb-kpi-value small { margin-left: 4px; color: var(--ink-3); font-family: var(--font); font-size: 13px; font-weight: 600; letter-spacing: 0; }
.nb-kpi p { margin: 10px 0 0; color: var(--ink-4); font-size: 11.5px; line-height: 1.35; }

.today-card { border: 1px solid var(--line); border-radius: 16px; background: var(--surface); padding: 18px 20px 17px; box-shadow: 0 1px 2px rgba(0,0,0,.015); }
.today-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 15px; }
.today-card-head h3 { margin: 0; color: var(--ink); font-size: 16px; font-weight: 680; letter-spacing: -.02em; }
.today-date { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 999px; background: var(--surface-2); color: var(--ink-3); font-size: 11.5px; font-weight: 600; letter-spacing: .01em; font-variant-numeric: tabular-nums; }
.today-date .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }
.today-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.today-item { display: flex; align-items: center; gap: 13px; padding: 15px 16px; border: 1px solid var(--line); border-radius: 13px; background: var(--surface); transition: background .15s ease; }
.today-item:hover { background: var(--surface-2); }
.today-item .ic { display: grid; place-items: center; width: 40px; height: 40px; flex: 0 0 40px; border-radius: 12px; }
.today-item.up .ic { color: #16805d; background: color-mix(in oklch, #16805d 12%, transparent); }
.today-item.down .ic { color: #c34b46; background: color-mix(in oklch, #c34b46 12%, transparent); }
.today-item .txt { display: flex; flex-direction: column; gap: 5px; }
.today-item .txt > span { color: var(--ink-4); font-size: 12px; font-weight: 550; }
.today-item .txt strong { color: var(--ink); font-size: 24px; line-height: 1; font-weight: 720; letter-spacing: -.03em; }
.today-item.up .txt strong { color: #16805d; }
.today-item.down .txt strong { color: #c34b46; }
.today-item .txt strong small { margin-left: 2px; color: var(--ink-4); font-family: var(--font); font-size: 12px; font-weight: 600; }

.nb-section-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin: 8px 0 12px; }
.nb-section-head h3 { margin: 0 0 5px; color: var(--ink); font-size: 18px; font-weight: 670; letter-spacing: -.02em; }
.nb-section-head p { margin: 0; color: var(--ink-4); font-size: 12px; }
.nb-section-head > span { padding: 5px 9px; border-radius: 999px; color: var(--ink-3); background: var(--surface-2); font-size: 11px; font-weight: 600; }
.nb-course-list { display: flex; flex-direction: column; gap: 13px; }

/* 기간 필터 */
.nb-period-filter { display: flex; gap: 5px; flex-wrap: wrap; }
.nb-period-filter button { padding: 6px 11px; border: 1px solid var(--line); border-radius: 999px; color: var(--ink-4); background: var(--surface); font: inherit; font-size: 11.5px; cursor: pointer; }
.nb-period-filter button:hover { border-color: var(--line-strong); color: var(--ink-2); }
.nb-period-filter button.on { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); color: var(--accent); background: var(--accent-soft); font-weight: 620; }

/* 회차 섹션 — 같은 개강일의 과정을 묶는다 */
.nb-round-section { overflow: hidden; border: 1px solid var(--line); border-radius: 15px; background: var(--surface); box-shadow: 0 2px 7px rgba(0,0,0,.018); }
.nb-round-section-head { width: 100%; display: flex; align-items: center; gap: 15px; min-height: 84px; padding: 16px 20px; border: 0; color: inherit; background: transparent; text-align: left; font: inherit; cursor: pointer; }
.nb-round-section-head:hover { background: var(--surface-2); }
.nb-round-section.open .nb-round-section-head { border-bottom: 1px solid var(--line); }
.nb-round-section-title { flex: 1; min-width: 0; }
.nb-round-section-title h4 { margin: 6px 0 0; color: var(--ink); font-size: 16px; font-weight: 660; letter-spacing: -.015em; }
.nb-round-section-title p { margin: 5px 0 0; color: var(--ink-4); font-size: 11.5px; }
.nb-round-section .nb-course-toggle { transition: transform .18s ease; }
.nb-round-section.open .nb-course-toggle { transform: rotate(180deg); }
/* 지표가 하나뿐이라 nb-course-totals(2칸·252px·구분선)를 쓰면 오른쪽이 비어 보인다.
   면을 채우면 --surface-2(#F4F4F2)의 따뜻한 기가 흰 배경 위에서 베이지로 읽혀
   이 카드에서 혼자 튄다. 배경 없이 타이포만으로 세운다. */
.nb-round-stat { display: inline-flex; align-items: baseline; gap: 8px; flex: 0 0 auto; }
.nb-round-stat > span { color: var(--ink-5); font-size: 11px; font-weight: 550; }
.nb-round-stat > strong { color: var(--accent); font-size: 22px; line-height: 1; font-weight: 720; letter-spacing: -.01em; }
.nb-round-stat small { margin-left: 2px; color: var(--ink-4); font-family: var(--font); font-size: 10.5px; font-weight: 550; }
.nb-round-empty { display: flex; flex-direction: column; align-items: center; gap: 7px; padding: 44px 20px; border: 1px dashed var(--line-strong); border-radius: 14px; color: var(--ink-4); text-align: center; }
.nb-round-empty strong { color: var(--ink-2); font-size: 13.5px; }
.nb-round-empty span { font-size: 11.5px; }
/* 회차 섹션 안에서는 첫 칸이 회차 배지가 아니라 과정명이라 폭이 더 필요하다. */
.nb-round-section .nb-round-row { grid-template-columns: minmax(200px, 1.6fr) minmax(150px, 1fr) 86px 74px 96px 68px; }
.nb-round-section .nb-round-row > strong.truncate { overflow: hidden; color: var(--ink-2); font-size: 12.5px; font-weight: 620; text-overflow: ellipsis; white-space: nowrap; }

.nb-course { overflow: hidden; border: 1px solid var(--line); border-radius: 15px; background: var(--surface); box-shadow: 0 2px 7px rgba(0,0,0,.018); }
.nb-course-head { width: 100%; display: flex; align-items: center; gap: 15px; min-height: 100px; padding: 18px 20px; border: 0; color: inherit; background: transparent; text-align: left; font: inherit; cursor: pointer; }
.nb-course-head:hover { background: var(--surface-2); }
.nb-course.open .nb-course-head { border-bottom: 1px solid var(--line); }
.nb-course-symbol { width: 44px; height: 44px; display: grid; place-items: center; flex: 0 0 44px; border-radius: 12px; color: var(--accent); background: var(--accent-soft); }
.nb-course-title { flex: 1; min-width: 0; }
.nb-course-tags { display: flex; align-items: center; gap: 6px; margin-bottom: 6px; }
.nb-course-tags > span { display: inline-flex; align-items: center; padding: 3px 8px; border-radius: 999px; color: var(--ink-3); background: var(--surface-2); font-size: 10px; font-weight: 620; }
.nb-course-tags > .status.accent { color: var(--accent); background: var(--accent-soft); }
.nb-course-tags > .status.ok { color: #16805d; background: color-mix(in oklch, #16805d 10%, transparent); }
.nb-course-tags > .status.warn { color: #b45309; background: color-mix(in oklch, #f59e0b 11%, transparent); }
.nb-course-title h4 { margin: 0; overflow: hidden; color: var(--ink); font-size: 16px; line-height: 1.35; font-weight: 670; letter-spacing: -.017em; text-overflow: ellipsis; white-space: nowrap; }
.nb-course-title p { margin: 5px 0 0; color: var(--ink-4); font-size: 12px; }
.nb-course-totals { display: grid; grid-template-columns: repeat(2, minmax(104px, 1fr)); min-width: 252px; border-left: 1px solid var(--line); }
.nb-course-totals > div { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; padding: 0 18px; }
.nb-course-totals > div + div { border-left: 1px solid var(--line); }
.nb-course-totals span { color: var(--ink-4); font-size: 10.5px; }
.nb-course-totals strong { color: var(--ink); font-size: 23px; line-height: 1; font-weight: 720; }
.nb-course-totals strong.accent { color: var(--accent); }
.nb-course-totals small { margin-left: 3px; color: var(--ink-4); font-family: var(--font); font-size: 10.5px; font-weight: 550; }
.nb-course-totals .sub { color: var(--ink-5); font-size: 10px; font-style: normal; }
.nb-course-toggle { width: 34px; height: 34px; display: grid; place-items: center; flex: 0 0 34px; border: 1px solid var(--line); border-radius: 10px; color: var(--ink-4); background: var(--surface); transition: transform .2s ease, color .2s ease, border-color .2s ease; }
.nb-course-head:hover .nb-course-toggle { color: var(--ink); border-color: var(--line-strong); }
.nb-course.open .nb-course-toggle { transform: rotate(180deg); }
.nb-course-body { min-height: 0; }
.nb-rounds-wrap { min-width: 0; padding: 20px 22px 22px; }
.nb-rounds-title { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 11px; }
.nb-rounds-title strong { color: var(--ink-2); font-size: 14px; font-weight: 650; }
.nb-rounds-title span { color: var(--ink-5); font-size: 11.5px; }
.nb-round-table { max-height: 284px; overflow: auto; border: 1px solid var(--line); border-radius: 10px; }
.nb-round-row { min-width: 680px; display: grid; grid-template-columns: 82px minmax(190px, 1.35fr) 86px 74px 96px 68px; align-items: center; gap: 12px; min-height: 53px; padding: 10px 15px; border-top: 1px solid var(--line); color: var(--ink-3); text-decoration: none; font-size: 13px; }
.nb-round-row:not(.head):hover { background: var(--surface-2); }
.nb-round-row.head { position: sticky; top: 0; z-index: 1; min-height: 40px; border-top: 0; color: var(--ink-5); background: var(--surface-2); font-size: 10.5px; font-weight: 650; letter-spacing: .03em; }
.nb-round-row > :nth-child(n+4) { text-align: right; }
.nb-round-row strong { color: var(--ink-2); font-weight: 660; }
.nb-round-row .applicant { color: var(--accent); }
.nb-status { display: inline-flex; align-items: center; justify-content: center; padding: 4px 8px; border-radius: 999px; color: var(--ink-4); background: var(--surface-3); font-style: normal; font-size: 10.5px; font-weight: 650; }
.nb-status.accent { color: var(--accent); background: var(--accent-soft); }
.nb-status.ok { color: #16805d; background: color-mix(in oklch, #16805d 10%, transparent); }
.nb-status.warn { color: #b45309; background: color-mix(in oklch, #f59e0b 11%, transparent); }
/* 기한을 넘긴 단계(…지연) — 색이 없으면 가장 급한 행이 가장 안 보인다. */
.nb-status.danger { color: #c34b46; background: color-mix(in oklch, #c34b46 10%, transparent); }

.nb-empty, .nb-loading { min-height: 350px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 20px; border: 1px dashed var(--line-strong); border-radius: 15px; color: var(--ink-4); text-align: center; background: var(--surface); }
.nb-loading { min-height: 240px; gap: 12px; border-style: solid; }
.nb-loading strong { color: var(--ink-3); font-size: 13px; font-weight: 600; }
.nb-spinner { width: 25px; height: 25px; border: 2px solid var(--line-strong); border-top-color: var(--accent); border-radius: 50%; animation: nb-spin .8s linear infinite; }
.nb-empty-icon { width: 58px; height: 58px; display: grid; place-items: center; margin-bottom: 14px; border-radius: 16px; color: var(--accent); background: var(--accent-soft); }
.nb-empty h3 { margin: 0; color: var(--ink-2); font-size: 16px; }
.nb-empty p { max-width: 520px; margin: 9px 0 18px; font-size: 12.5px; line-height: 1.55; }

.nb-settings-modal { max-width: 650px; max-height: calc(100vh - 48px); display: flex; flex-direction: column; }
.nb-settings-modal .modal-head h3 { margin: 0; color: var(--ink); font-size: 21px; font-weight: 680; letter-spacing: -.025em; }
.nb-settings-modal .modal-head p { margin: 6px 0 0; color: var(--ink-4); font-size: 12px; }
.nb-settings-modal .modal-body { min-height: 0; overflow-y: auto; }

.nb-settings-notice { margin-bottom: 14px; padding: 11px 13px; border-radius: 10px; color: #8a5b00; background: color-mix(in oklch, #f59e0b 10%, transparent); font-size: 11.5px; }
.nb-settings-modal fieldset { display: flex; flex-direction: column; gap: 20px; margin: 0; padding: 0; border: 0; }
.nb-settings-modal fieldset:disabled { opacity: .8; }
.nb-setting-section { padding-bottom: 20px; border-bottom: 1px solid var(--line); }
.nb-setting-section:last-child { padding-bottom: 0; border-bottom: 0; }
.nb-setting-label { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; }
.nb-setting-label strong { color: var(--ink-2); font-size: 14px; font-weight: 660; }
.nb-setting-label span { color: var(--ink-4); font-size: 11.5px; line-height: 1.45; }
.nb-switch-row, .nb-select-row, .nb-range-row { min-height: 46px; display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 0 13px; border: 1px solid var(--line); border-radius: 10px; color: var(--ink-3); background: var(--surface-2); font-size: 12.5px; }
.nb-select-row { margin-top: 8px; }
.nb-select-row select { min-width: 120px; padding: 6px 28px 6px 9px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink-2); background: var(--surface); font: inherit; font-size: 12px; }
.nb-switch-row input { position: absolute; opacity: 0; }
.nb-switch-row i { position: relative; width: 38px; height: 22px; flex-shrink: 0; border-radius: 99px; background: var(--line-strong); transition: background .2s; }
.nb-switch-row i::after { content: ''; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: transform .2s; }
.nb-switch-row input:checked + i { background: var(--accent); }
.nb-switch-row input:checked + i::after { transform: translateX(16px); }
.nb-departments { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.nb-departments label { min-width: 88px; display: inline-flex; align-items: center; justify-content: center; min-height: 37px; padding: 7px 13px; border: 1px solid var(--line); border-radius: 9px; color: var(--ink-3); background: var(--surface); font-size: 12px; text-align: center; cursor: pointer; }
.nb-departments label:hover { border-color: var(--line-strong); }
.nb-departments label.selected { border-color: color-mix(in oklch, var(--accent) 35%, var(--line)); color: var(--accent); background: var(--accent-soft); }
.nb-departments label input { position: absolute; opacity: 0; }
.nb-no-dept { color: var(--ink-5); font-size: 12px; }
.nb-check-row { display: flex; align-items: center; gap: 11px; min-height: 54px; padding: 8px 12px; border-top: 1px solid var(--line); cursor: pointer; }
.nb-check-row:first-of-type { border-top: 0; }
.nb-check-row input { width: 17px; height: 17px; flex-shrink: 0; accent-color: var(--accent); }
.nb-check-row span { display: flex; flex-direction: column; gap: 3px; }
.nb-check-row strong { color: var(--ink-2); font-size: 12.5px; }
.nb-check-row small { color: var(--ink-4); font-size: 10.5px; }
.nb-range-row { justify-content: flex-start; margin-top: 8px; }
.nb-range-row span { flex: 1; }
.nb-range-row input { width: 68px; padding: 6px 8px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink); background: var(--surface); text-align: right; font: inherit; font-size: 12px; }
.nb-range-row b { color: var(--ink-4); font-size: 11px; }
.nb-form-error { margin-top: 14px; padding: 10px 12px; border-radius: 9px; color: var(--danger); background: color-mix(in oklch, var(--danger) 8%, transparent); font-size: 11.5px; }

/* ───────── 내일배움카드 등록 관리 ───────── */

.nb-reg-page { display: flex; flex-direction: column; gap: 13px; }
.nb-reg-toolbar { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; padding-top: 2px; }
.nb-reg-toolbar h2 { margin: 7px 0 6px; color: var(--ink); font-size: 22px; line-height: 1.25; font-weight: 680; letter-spacing: -.025em; }
.nb-reg-toolbar p { margin: 0; color: var(--ink-4); font-size: 13px; line-height: 1.55; }
.nb-reg-live { min-height: 38px; display: flex; align-items: center; gap: 8px; padding: 0 11px; border: 1px solid color-mix(in oklch, #16805d 22%, var(--line)); border-radius: 9px; color: #326b55; background: color-mix(in oklch, #16805d 4%, var(--surface)); font-size: 11px; }
.nb-reg-live > span { width: 6px; height: 6px; border-radius: 50%; background: #16805d; box-shadow: 0 0 0 3px color-mix(in oklch, #16805d 10%, transparent); }
.nb-reg-live b { font-weight: 650; }
.nb-reg-live time { padding-left: 8px; border-left: 1px solid color-mix(in oklch, #16805d 18%, var(--line)); color: #719080; font-size: 9.5px; }

.nb-reg-cred-form { display: grid; gap: 8px; margin-top: 9px; }
.nb-reg-cred-form label { display: grid; gap: 4px; font-size: 11px; font-weight: 700; color: var(--ink-4); }
.nb-reg-cred-form input { min-height: 38px; padding: 0 11px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface); font-size: 13px; }
.nb-reg-cred-note { margin-top: 7px; font-size: 11px; color: var(--ink-5); }

.nb-reg-assist { display: flex; align-items: center; gap: 11px; padding: 12px 14px; border: 1px solid color-mix(in oklch, var(--accent) 19%, var(--line)); border-radius: 11px; background: color-mix(in oklch, var(--accent) 3%, var(--surface)); }
.nb-reg-assist-icon { width: 32px; height: 32px; display: grid; place-items: center; flex: 0 0 32px; border-radius: 9px; color: var(--accent); background: var(--accent-soft); }
.nb-reg-assist strong { display: block; color: var(--ink-2); font-size: 12.5px; }
.nb-reg-assist p { margin: 4px 0 0; color: var(--ink-4); font-size: 11.5px; line-height: 1.45; }

/* 요약 — 결제 합계(히어로) + 처리 상태 세그먼트.
   상태 칸은 그 자체가 필터다. 색과 라벨을 표의 상태 배지와 1:1로 맞춰,
   카드에서 고른 색이 아래 표에서 그대로 보이게 한다. */
/* 히어로(금액 타일)는 있을 때도 없을 때도 있다 — 내배카 훈련 현황처럼 금액이
   없는 화면에서는 세그먼트 혼자 남는다. 그리드 고정 2열이면 그 한 칸이 첫
   트랙(≤320px)에 갇혀 칸이 잘리므로, 남는 폭을 흡수하도록 flex로 둔다. */
.gukbi-summary { display: flex; flex-wrap: wrap; gap: 10px; align-items: stretch; }
/* 가장 가까운 개강 회차의 자부담금 합계 — 담당자가 매일 보는 숫자라 앞자리를 준다. */
.gukbi-hero { flex: 0 1 320px; min-width: 250px; display: flex; flex-direction: column; justify-content: center; padding: 16px 18px; border: 1px solid color-mix(in oklch, #16805d 22%, var(--line)); border-radius: 14px; background: linear-gradient(145deg, color-mix(in oklch, #16805d 6%, var(--surface)), var(--surface)); }
.gukbi-hero-head { display: flex; align-items: center; gap: 10px; }
.gukbi-hero-head i { width: 30px; height: 30px; display: grid; place-items: center; flex: 0 0 30px; border-radius: 9px; color: #16805d; background: color-mix(in oklch, #16805d 11%, transparent); font-style: normal; }
.gukbi-hero-head span { display: block; color: var(--ink-5); font-size: 10.5px; font-weight: 620; letter-spacing: .02em; }
.gukbi-hero-head b { display: block; margin-top: 2px; color: var(--ink-2); font-size: 12.5px; font-weight: 640; }
.gukbi-hero > strong { display: block; margin-top: 14px; color: var(--ink); font-size: 26px; line-height: 1; font-weight: 720; letter-spacing: -.02em; }
.gukbi-hero > strong small { margin-left: 4px; color: var(--ink-4); font-size: 12px; font-weight: 550; }
.gukbi-hero p { margin: 9px 0 0; color: var(--ink-5); font-size: 11px; }
.gukbi-hero p b { color: var(--ink-3); font-weight: 650; }
/* 총액 아래 내역 한 줄 — 자부담 / 국비 지원 */
.gukbi-hero-split { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 7px !important; padding-top: 8px; border-top: 1px solid color-mix(in oklch, #16805d 14%, var(--line)); }
.gukbi-hero-split span { display: inline-flex; align-items: baseline; gap: 4px; }

/* 요약 세그먼트 (StatSegments) — 등록 관리·훈련 현황이 함께 쓴다. */
/* 칸 수는 화면마다 다르다(3~4) — auto-flow로 개수를 따라가고, minmax(0,1fr)로
   칸이 내용보다 좁아질 수 있게 한다. 1fr만 쓰면 칸이 안 줄어 마지막 칸이 잘린다. */
.gukbi-stats { flex: 1 1 460px; min-width: 0; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); overflow: hidden; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); }
.gukbi-stat { --tone: var(--ink-4); position: relative; min-width: 0; display: flex; flex-direction: column; gap: 10px; padding: 16px 16px 17px; border: 0; border-left: 1px solid var(--line); background: transparent; font: inherit; text-align: left; cursor: pointer; transition: background .15s; }
.gukbi-stat:first-child { border-left: 0; }
.gukbi-stat:hover { background: var(--surface-2); }
.gukbi-stat.accent { --tone: var(--accent); }
.gukbi-stat.danger { --tone: #c34b46; }
.gukbi-stat.warn { --tone: #b56b0b; }
.gukbi-stat.ok { --tone: #16805d; }
/* 좁아지면 잘리는 대신 줄바꿈한다 — keep-all 로 띄어쓰기에서 먼저 끊고,
   그래도 안 들어가면 anywhere 가 강제로 넘긴다(한 글자까지 줄 수 있어야
   칸이 min-content 밑으로 내려간다). */
.gukbi-stat-label { min-width: 0; display: flex; align-items: center; gap: 6px; color: var(--ink-4); font-size: 11.5px; font-weight: 600; word-break: keep-all; overflow-wrap: anywhere; }
.gukbi-stat-label i { width: 6px; height: 6px; flex: 0 0 6px; border-radius: 50%; background: var(--tone); }
.gukbi-stat > strong { color: var(--ink); font-size: 26px; line-height: 1; font-weight: 720; letter-spacing: -.02em; }
.gukbi-stat > strong small { margin-left: 3px; color: var(--ink-4); font-size: 11px; font-weight: 550; }
.gukbi-stat em { color: var(--ink-5); font-size: 10.5px; font-style: normal; word-break: keep-all; overflow-wrap: anywhere; }
/* 0건은 눈에 덜 걸리게 — 오늘 할 일이 있는 칸이 먼저 보여야 한다. */
.gukbi-stat.zero > strong { color: var(--ink-5); }
.gukbi-stat.zero .gukbi-stat-label i { background: var(--ink-5); opacity: .45; }
/* 선택된 칸 — 아래 2px 선으로 "이 상태만 보는 중"을 알린다 */
.gukbi-stat.on { background: color-mix(in oklch, var(--tone) 7%, transparent); }
.gukbi-stat.on .gukbi-stat-label { color: var(--tone); }
.gukbi-stat.on > strong { color: var(--tone); }
.gukbi-stat.on::after { content: ''; position: absolute; inset-inline: 0; bottom: 0; height: 2px; background: var(--tone); }

.nb-reg-list { min-width: 0; }
.nb-reg-controls { min-height: 56px; display: flex; align-items: center; gap: 8px; padding: 10px 11px; border: 1px solid var(--line); border-bottom: 0; border-radius: 13px 13px 0 0; background: var(--surface); }
.nb-reg-search { width: 250px; height: 35px; display: flex; align-items: center; gap: 8px; padding: 0 10px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink-5); background: var(--surface); }
.nb-reg-search:focus-within { border-color: color-mix(in oklch, var(--accent) 50%, var(--line)); box-shadow: 0 0 0 3px var(--accent-soft); }
.nb-reg-search input { min-width: 0; width: 100%; border: 0; outline: 0; color: var(--ink); background: transparent; font: inherit; font-size: 12px; }
/* 일반카드 포함 토글 — 켜져 있을 때만 강조된다(기본은 숨김). */
.nb-reg-toggle { height: 35px; display: inline-flex; align-items: center; gap: 6px; padding: 0 11px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink-4); background: var(--surface); font: inherit; font-size: 11.5px; cursor: pointer; }
.nb-reg-toggle:hover { border-color: var(--line-strong); color: var(--ink-2); }
.nb-reg-toggle svg { opacity: .25; }
.nb-reg-toggle.on { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); color: var(--accent); background: var(--accent-soft); }
.nb-reg-toggle.on svg { opacity: 1; }
.nb-reg-toggle b { color: inherit; font-weight: 700; }

/* 회차와 개강일을 한 칩으로 합친 필터 — 운영에서 늘 붙어 다니는 값이다. */
.nb-reg-chips { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 11px 11px; border: 1px solid var(--line); border-top: 0; border-bottom: 0; background: var(--surface); }
.nb-reg-chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px; border: 1px solid var(--line); border-radius: 999px; color: var(--ink-3); background: var(--surface); font: inherit; font-size: 11.5px; cursor: pointer; }
.nb-reg-chip:hover { border-color: var(--line-strong); color: var(--ink); }
.nb-reg-chip em { color: var(--ink-5); font-size: 10.5px; font-style: normal; }
.nb-reg-chip b { min-width: 17px; padding: 1px 5px; border-radius: 999px; color: var(--ink-4); background: var(--surface-2); font-size: 10px; font-weight: 700; text-align: center; }
.nb-reg-chip.on { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); color: var(--accent); background: var(--accent-soft); }
.nb-reg-chip.on em { color: color-mix(in oklch, var(--accent) 65%, var(--ink-4)); }
.nb-reg-chip.on b { color: #fff; background: var(--accent); }

.nb-reg-table-wrap { max-width: 100%; overflow-x: auto; }
.nb-reg-table { min-width: 1000px; overflow: hidden; border: 1px solid var(--line); border-radius: 0 0 13px 13px; background: var(--surface); }
.nb-reg-row { min-height: 72px; display: grid; grid-template-columns: 208px minmax(190px, 1.35fr) 68px 92px 148px 104px 104px; align-items: center; gap: 11px; padding: 10px 14px; border-top: 1px solid var(--line); color: var(--ink-3); font-size: 12.5px; }
/* 행 전체가 상세보기 버튼이다 — 끝의 화살표가 그 사실을 알린다. */
.nb-reg-row[role='button'] { cursor: pointer; transition: background .13s; }
.nb-reg-row[role='button']:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.nb-reg-applied { color: var(--ink-3); font-size: 11.5px; }
.nb-reg-row.head { min-height: 42px; border-top: 0; color: var(--ink-5); background: var(--surface-2); font-size: 10.5px; font-weight: 650; letter-spacing: .035em; }
.nb-reg-row:not(.head):hover { background: color-mix(in oklab, var(--surface-2) 42%, var(--surface)); }
.nb-reg-person { display: flex; align-items: center; gap: 9px; min-width: 0; }
.nb-reg-person > span { width: 33px; height: 33px; display: grid; place-items: center; flex: 0 0 33px; border-radius: 50%; color: #5659c6; background: #eeeefe; font-size: 11px; font-weight: 720; }
.nb-reg-person div, .nb-reg-course, .nb-reg-payment { min-width: 0; }
.nb-reg-person b, .nb-reg-course b, .nb-reg-payment b { display: block; overflow: hidden; color: var(--ink-2); font-size: 12.5px; font-weight: 640; text-overflow: ellipsis; white-space: nowrap; }
.nb-reg-person small, .nb-reg-course small, .nb-reg-payment small { display: block; overflow: hidden; margin-top: 4px; color: var(--ink-5); font-size: 10.5px; font-weight: 450; text-overflow: ellipsis; white-space: nowrap; }
.nb-reg-payment b.danger { color: var(--danger); }
.nb-reg-status { display: inline-flex; align-items: center; gap: 5px; width: max-content; max-width: 100%; padding: 5px 8px; border-radius: 999px; color: var(--ink-4); background: var(--surface-2); font-size: 10.5px; font-weight: 650; white-space: nowrap; }
.nb-reg-status i { width: 5px; height: 5px; flex: 0 0 5px; border-radius: 50%; background: currentColor; }
.nb-reg-status.ok { color: #16805d; background: color-mix(in oklch, #16805d 9%, transparent); }
.nb-reg-status.accent { color: var(--accent); background: var(--accent-soft); }
.nb-reg-status.warn { color: #b56b0b; background: color-mix(in oklch, #f59e0b 11%, transparent); }
.nb-reg-status.danger { color: #c34b46; background: color-mix(in oklch, #c34b46 9%, transparent); }
.nb-reg-row-action { display: flex; align-items: center; justify-content: flex-end; gap: 6px; }
.nb-reg-row-go { display: grid; place-items: center; flex: 0 0 auto; color: var(--ink-5); opacity: .5; transition: opacity .13s, color .13s, transform .13s; }
.nb-reg-row:hover .nb-reg-row-go { color: var(--accent); opacity: 1; transform: translateX(2px); }

/* 처리 이력 — 처리 완료를 되돌릴 수 있게 되면서 "누가 언제"가 필요해졌다. */
.nb-reg-history { margin-top: 14px; padding: 14px 15px; border: 1px solid var(--line); border-radius: 11px; background: var(--surface-2); }
.nb-reg-history > strong { display: block; color: var(--ink-2); font-size: 12px; font-weight: 650; }
.nb-reg-history-empty { margin: 8px 0 0; color: var(--ink-5); font-size: 11.5px; }
.nb-reg-history ol { display: flex; flex-direction: column; gap: 7px; margin: 10px 0 0; padding: 0; list-style: none; }
.nb-reg-history li { display: flex; align-items: center; gap: 8px; font-size: 11.5px; }
.nb-reg-history li b { color: var(--ink-2); font-weight: 620; }
.nb-reg-history li span { color: var(--ink-4); }
.nb-reg-history li time { margin-left: auto; color: var(--ink-5); font-size: 10.5px; }
.nb-reg-empty { min-height: 270px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 35px 20px; border: 1px solid var(--line); border-radius: 0 0 13px 13px; color: var(--ink-4); background: var(--surface); text-align: center; }
.nb-reg-empty > div, .nb-reg-no-access > div { width: 50px; height: 50px; display: grid; place-items: center; margin-bottom: 12px; border-radius: 14px; color: var(--accent); background: var(--accent-soft); }
.nb-reg-empty h3, .nb-reg-no-access h3 { margin: 0; color: var(--ink-2); font-size: 15px; }
.nb-reg-empty p, .nb-reg-no-access p { max-width: 520px; margin: 8px 0 15px; color: var(--ink-4); font-size: 12px; line-height: 1.55; }
.nb-reg-no-access { min-height: 390px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 35px; border: 1px dashed var(--line-strong); border-radius: 15px; text-align: center; }

.nb-reg-connection-modal { max-width: 620px; }
.nb-reg-connection-card { display: flex; align-items: center; gap: 12px; padding: 14px; border: 1px solid var(--line); border-radius: 11px; background: var(--surface-2); }
.nb-reg-connection-card > div { width: 40px; height: 40px; display: grid; place-items: center; flex: 0 0 40px; border-radius: 10px; color: var(--ink-4); background: var(--surface); }
.nb-reg-connection-card.ok { border-color: color-mix(in oklch, #16805d 22%, var(--line)); background: color-mix(in oklch, #16805d 4%, var(--surface)); }
.nb-reg-connection-card.ok > div { color: #16805d; background: color-mix(in oklch, #16805d 10%, var(--surface)); }
.nb-reg-connection-card section { flex: 1; min-width: 0; }
.nb-reg-connection-card strong { display: block; color: var(--ink-2); font-size: 13px; }
.nb-reg-connection-card p { margin: 4px 0 0; color: var(--ink-4); font-size: 11px; }
.nb-reg-connection-details { margin-top: 13px; overflow: hidden; border: 1px solid var(--line); border-radius: 10px; }
.nb-reg-connection-details > div { min-height: 44px; display: grid; grid-template-columns: 130px 1fr; align-items: center; padding: 0 13px; border-top: 1px solid var(--line); font-size: 11.5px; }
.nb-reg-connection-details > div:first-child { border-top: 0; }
.nb-reg-connection-details span { color: var(--ink-4); }
.nb-reg-connection-details b { color: var(--ink-2); font-weight: 600; }
.nb-reg-setup { margin-top: 13px; padding: 13px 14px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); }
.nb-reg-setup strong { font-size: 12px; }
.nb-reg-setup ol { margin: 10px 0 0; padding-left: 20px; color: var(--ink-4); font-size: 11px; line-height: 1.85; }
.nb-reg-security { display: flex; align-items: flex-start; gap: 9px; margin-top: 13px; padding: 11px 12px; border-radius: 9px; color: var(--ink-4); background: var(--surface-2); }
.nb-reg-security svg { flex: 0 0 auto; margin-top: 1px; }
.nb-reg-security p { margin: 0; font-size: 10.5px; line-height: 1.55; }

.nb-reg-job-modal { width: min(980px, calc(100vw - 40px)); max-width: 980px; max-height: calc(100vh - 40px); }
.nb-reg-job-modal .modal-head { padding: 26px 28px 22px; }
.nb-reg-job-modal .modal-head h3 { font-size: 23px; }
.nb-reg-job-modal .modal-head p { margin-top: 7px; font-size: 13px; }
.nb-reg-job-modal .modal-body { min-height: 0; padding: 26px 28px; overflow-y: auto; }
.nb-reg-job-modal .modal-foot { padding: 18px 28px; }
.nb-reg-job-layout { display: grid; grid-template-columns: 180px minmax(0, 1fr); gap: 20px; }
.nb-reg-job-rail { padding-right: 18px; border-right: 1px solid var(--line); }
.nb-reg-job-rail > div { position: relative; min-height: 66px; display: flex; gap: 10px; color: var(--ink-5); }
.nb-reg-job-rail > div:not(:last-child)::after { content: ''; position: absolute; left: 12px; top: 29px; bottom: 3px; width: 1px; background: var(--line); }
.nb-reg-job-rail > div > span { position: relative; z-index: 1; width: 25px; height: 25px; display: grid; place-items: center; flex: 0 0 25px; border: 1px solid var(--line); border-radius: 50%; background: var(--surface); font-size: 9px; font-weight: 700; }
.nb-reg-job-rail section b { display: block; margin-top: 3px; font-size: 11px; }
.nb-reg-job-rail section small { display: block; margin-top: 4px; font-size: 9.5px; }
.nb-reg-job-rail > div.done { color: #16805d; }
.nb-reg-job-rail > div.done > span { border-color: color-mix(in oklch, #16805d 35%, var(--line)); background: color-mix(in oklch, #16805d 10%, var(--surface)); }
.nb-reg-job-rail > div.current { color: var(--accent); }
.nb-reg-job-rail > div.current > span { border-color: color-mix(in oklch, var(--accent) 40%, var(--line)); background: var(--accent-soft); }
.nb-reg-job-main { min-width: 0; }
.nb-reg-candidate { display: flex; align-items: flex-start; justify-content: space-between; gap: 18px; margin-bottom: 22px; padding-bottom: 20px; border-bottom: 1px solid var(--line); }
.nb-reg-candidate strong { color: var(--ink-2); font-size: 17px; line-height: 1.45; }
.nb-reg-candidate p { margin: 7px 0 0; color: var(--ink-4); font-size: 13px; }
.nb-reg-compare { display: grid; grid-template-columns: 1fr 40px 1fr; align-items: stretch; margin-bottom: 22px; }
.nb-reg-compare > span { display: grid; place-items: center; color: #16805d; font-size: 20px; font-weight: 700; }
.nb-reg-info-card { min-height: 250px; padding: 24px 25px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); box-shadow: 0 8px 24px color-mix(in oklch, var(--ink) 6%, transparent); }
.nb-reg-info-card > strong { display: block; padding-bottom: 15px; border-bottom: 1px solid var(--line); color: var(--ink-2); font-size: 16px; }
.nb-reg-info-card dl { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 15px 18px; margin: 20px 0 0; font-size: 13.5px; line-height: 1.45; }
.nb-reg-info-card dt { color: var(--ink-5); }
.nb-reg-info-card dd { min-width: 0; margin: 0; color: var(--ink-2); font-size: 14px; font-weight: 650; overflow-wrap: anywhere; }
.nb-reg-auto-fields { padding: 13px; border: 1px solid color-mix(in oklch, var(--accent) 18%, var(--line)); border-radius: 10px; background: color-mix(in oklch, var(--accent) 3%, var(--surface)); }
.nb-reg-auto-fields > div { display: flex; justify-content: space-between; gap: 10px; }
.nb-reg-auto-fields > div strong { font-size: 11.5px; }
.nb-reg-auto-fields > div span { color: var(--accent); font-size: 9.5px; }
.nb-reg-auto-fields section { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin-top: 10px; }
.nb-reg-auto-fields label { padding: 9px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink-5); background: var(--surface); font-size: 9px; }
.nb-reg-auto-fields label b { display: block; overflow: hidden; margin-top: 5px; color: var(--ink-2); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.nb-reg-job-notice { display: flex; align-items: flex-start; gap: 10px; margin-top: 16px; padding: 15px 16px; border-radius: 11px; color: #76501d; background: color-mix(in oklch, #f59e0b 11%, transparent); }
.nb-reg-job-notice svg { flex: 0 0 auto; margin-top: 1px; }
.nb-reg-job-notice p { margin: 0; font-size: 12.5px; line-height: 1.65; }
.nb-reg-progress { padding: 15px 0 4px; text-align: center; }
.nb-reg-progress-icon { width: 44px; height: 44px; display: grid; place-items: center; margin: 0 auto 12px; border-radius: 50%; color: var(--accent); background: var(--accent-soft); }
.nb-reg-progress-icon .nb-spinner { width: 24px; height: 24px; }
.nb-reg-progress.complete .nb-reg-progress-icon { color: #16805d; background: color-mix(in oklch, #16805d 10%, transparent); }
.nb-reg-progress.failed .nb-reg-progress-icon { color: var(--danger); background: color-mix(in oklch, var(--danger) 9%, transparent); }
.nb-reg-progress h4 { margin: 0; color: var(--ink-2); font-size: 14px; }
.nb-reg-progress > p { max-width: 440px; margin: 7px auto 15px; color: var(--ink-4); font-size: 11px; line-height: 1.55; }
.nb-reg-progress-bar { height: 5px; overflow: hidden; border-radius: 99px; background: var(--surface-3); }
.nb-reg-progress-bar i { display: block; height: 100%; border-radius: inherit; background: var(--accent); transition: width .25s; }
.nb-reg-progress-meta { display: grid; grid-template-columns: 90px 1fr; gap: 0; margin-top: 14px; overflow: hidden; border: 1px solid var(--line); border-radius: 9px; text-align: left; font-size: 10.5px; }
.nb-reg-progress-meta span, .nb-reg-progress-meta b { min-height: 38px; display: flex; align-items: center; padding: 0 11px; border-top: 1px solid var(--line); }
.nb-reg-progress-meta > :nth-child(-n+2) { border-top: 0; }
.nb-reg-progress-meta span { color: var(--ink-5); background: var(--surface-2); }
.nb-reg-progress-meta b { color: var(--ink-2); font-weight: 600; }
.nb-reg-review-note { display: flex; align-items: flex-start; gap: 9px; margin-top: 12px; padding: 11px; border-radius: 9px; color: color-mix(in oklch, var(--accent) 80%, var(--ink)); background: var(--accent-soft); text-align: left; }
.nb-reg-review-note svg { flex: 0 0 auto; }
.nb-reg-review-note p { margin: 0; font-size: 10px; line-height: 1.55; }
.nb-reg-guide-modal { max-width: 620px; }
.nb-reg-guide-modal textarea { width: 100%; min-height: 310px; padding: 15px; resize: vertical; border: 1px solid var(--line); border-radius: 10px; outline: 0; color: var(--ink-2); background: var(--surface-2); font: inherit; font-size: 12px; line-height: 1.75; }

@media (max-width: 1180px) {
  .nb-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 히어로와 세그먼트를 위아래로 — 상태 칸은 한 줄을 그대로 유지한다. */
  .gukbi-summary > * { flex-basis: 100%; max-width: none; }
  .nb-reg-live { display: none; }
}

@media (max-width: 760px) {
  .nb-dashboard { gap: 15px; }
  .nb-toolbar { align-items: stretch; flex-direction: column; gap: 14px; }
  .nb-actions { display: grid; grid-template-columns: repeat(3, 1fr); }
  .nb-kpis { grid-template-columns: 1fr 1fr; gap: 8px; }
  .nb-kpi { min-height: 136px; padding: 15px; }
  .nb-kpi-value { font-size: 27px; }
  .today-grid { gap: 8px; }
  .nb-course-head { align-items: flex-start; flex-wrap: wrap; padding: 16px; }
  .nb-course-title { width: calc(100% - 62px); }
  .nb-course-title h4 { white-space: normal; }
  .nb-course-totals { width: 100%; min-width: 0; padding-top: 14px; border-top: 1px solid var(--line); border-left: 0; }
  .nb-course-totals > div { align-items: flex-start; padding-left: 0; }
  .nb-rounds-wrap { padding: 16px; }
}

@media (max-width: 520px) {
  .nb-kpis { grid-template-columns: 1fr; }
  .nb-actions { grid-template-columns: 1fr; }
  .today-grid { grid-template-columns: 1fr; }
  .nb-reg-toolbar { align-items: stretch; flex-direction: column; }
  .gukbi-stats { grid-template-columns: 1fr 1fr; }
  .gukbi-stat:nth-child(3) { border-left: 0; }
  .gukbi-stat:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .nb-reg-controls { align-items: stretch; flex-direction: column; }
  .nb-reg-search { width: 100%; }
  .nb-reg-toggle { width: 100%; justify-content: center; }
  .nb-reg-chips { padding: 0 11px 11px; }
  .nb-reg-history li { align-items: flex-start; flex-wrap: wrap; }
  .nb-reg-history li time { margin-left: 0; width: 100%; }
  .nb-reg-job-layout { grid-template-columns: 1fr; }
  .nb-reg-job-rail { display: none; }
  .nb-reg-auto-fields section { grid-template-columns: 1fr; }
}

@media (max-width: 460px) {
  .nb-reg-compare { grid-template-columns: 1fr; gap: 8px; }
  .nb-reg-compare > span { transform: rotate(90deg); }
  .nb-reg-job-modal { width: calc(100vw - 20px); }
  .nb-reg-job-modal .modal-head, .nb-reg-job-modal .modal-body, .nb-reg-job-modal .modal-foot { padding-left: 18px; padding-right: 18px; }
  .nb-reg-info-card { min-height: 0; padding: 20px; }
  .nb-reg-info-card dl { grid-template-columns: 92px minmax(0, 1fr); gap: 13px; font-size: 12.5px; }
}

/* ───────── Page heading ───────── */
.page-head {
  padding: 28px 36px 18px;
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.page-title { font-size: 26px; font-weight: 650; letter-spacing: -.025em; line-height: 1.1; margin: 0 0 6px; word-break: keep-all; }
.page-sub { color: var(--ink-4); font-size: 13.5px; margin: 0; letter-spacing: -.008em; word-break: keep-all; }
.page-body { flex: 1; min-height: 0; overflow: hidden; }
.page-body.scrolly { overflow-y: auto; padding: 4px 36px 36px; }
.kicker { font-family: var(--font); font-size: 11px; font-weight: 600; color: var(--ink-4); letter-spacing: .08em; margin-bottom: 6px; }

/* ───────── Markdown content ───────── */
/* Rendered by <Markdown>; styled with design tokens. Two size variants:
   .md-post (full post body) and .md-comment (tighter comment layout). */
.md { color: var(--ink-2); word-break: break-word; overflow-wrap: anywhere; }
.md > :first-child { margin-top: 0; }
.md > :last-child { margin-bottom: 0; }
.md p { margin: 0 0 .7em; }
.md h1, .md h2, .md h3, .md h4, .md h5, .md h6 {
  color: var(--ink); font-weight: 650; letter-spacing: -.02em; line-height: 1.3;
  margin: 1.3em 0 .5em;
}
.md h1 { font-size: 1.5em; }
.md h2 { font-size: 1.3em; }
.md h3 { font-size: 1.15em; }
.md h4, .md h5, .md h6 { font-size: 1em; }
.md a { color: var(--accent); text-decoration: none; border-bottom: 1px solid color-mix(in oklch, var(--accent) 35%, transparent); }
.md a:hover { border-bottom-color: var(--accent); }
.md strong { font-weight: 650; color: var(--ink); }
.md em { font-style: italic; }
.md del { color: var(--ink-4); }
.md ul, .md ol { margin: 0 0 .7em; padding-left: 1.5em; }
.md li { margin: .2em 0; }
.md li::marker { color: var(--ink-4); }
.md li > ul, .md li > ol { margin: .2em 0; }
.md blockquote {
  margin: .8em 0; padding: .15em 0 .15em 1em;
  border-left: 3px solid var(--line-strong); color: var(--ink-3);
}
.md code {
  font-family: var(--font-mono); font-size: .88em;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-xs); padding: .08em .35em;
}
.md pre {
  margin: .8em 0; padding: 13px 16px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm); overflow-x: auto;
}
.md pre code { background: none; border: 0; padding: 0; font-size: .85em; line-height: 1.6; }
.md hr { border: 0; border-top: 1px solid var(--line); margin: 1.4em 0; }
.md img { max-width: 100%; height: auto; border-radius: var(--radius-sm); }
/* inline body images in posts get breathing room + a hairline so screenshots
   don't blend into the page */
.md-post img { margin: .35em 0; border: 1px solid var(--line); }
.md table { border-collapse: collapse; margin: .8em 0; font-size: .95em; display: block; overflow-x: auto; }
.md th, .md td { border: 1px solid var(--line); padding: 6px 12px; text-align: left; }
.md th { background: var(--surface-2); font-weight: 600; }
.md ul.contains-task-list { list-style: none; padding-left: .2em; }
.md li.task-list-item { margin: .1em 0; }
.md input[type="checkbox"] { margin-right: .45em; accent-color: var(--accent); }

.md-post { font-size: 15.5px; line-height: 1.8; letter-spacing: -.005em; }
.md-comment { font-size: 13.5px; line-height: 1.6; }
.md-comment p { margin-bottom: .4em; }
.md-chat { font-size: 13.5px; line-height: 1.6; }
.md-chat p { margin-bottom: .3em; }
.md-chat-root { color: var(--ink); font-size: 14px; }

/* chat @mention pill — mirrors the old inline MentionText styling */
.md .mention {
  color: var(--accent); font-weight: 650;
  background: var(--accent-soft);
  border-radius: 5px; padding: 1px 5px;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
/* keep a trailing "(수정됨)" marker on the same line as a single-paragraph message */
.md-chat > p:last-of-type { display: inline; }
.md-trailing { font-size: 10.5px; color: var(--ink-5); margin-left: 6px; }

/* ───────── Responsive stat grids (admin dashboards) ───────── */
/* Inline grid-template can't be overridden by a media query, so these dashboards
   use a class (gap/margins stay inline) and collapse to fewer columns on mobile. */
.rgrid-3 { display: grid; grid-template-columns: repeat(3, 1fr); }
.rgrid-4 { display: grid; grid-template-columns: repeat(4, 1fr); }
.rsplit { display: grid; grid-template-columns: 2fr 1fr; }
.rsplit-3 { display: grid; grid-template-columns: 1.4fr 1fr 1fr; }

/* ───────── Mobile drawer overlay ───────── */
/* Rendered only on mobile (by AppShell); sits below the sidebar drawer. */
.sb-overlay { display: none; }

/* ───────── Responsive: phones & small tablets ───────── */
@media (max-width: 768px) {
  /* Shell collapses to a single column; the sidebar becomes an off-canvas
     drawer that slides over the content instead of holding a grid track. */
  .shell { grid-template-columns: 1fr; }
  .sb {
    position: fixed;
    top: 0; bottom: 0; left: 0;
    width: min(var(--sb-w), 84vw);
    z-index: 120;
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform var(--t);
    box-shadow: var(--shadow-lg);
  }
  .shell.nav-open .sb { transform: translateX(0); }

  .sb-overlay {
    display: block;
    position: fixed; inset: 0;
    background: rgba(10, 10, 10, .4);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
    z-index: 110;
    opacity: 0; pointer-events: none;
    transition: opacity var(--t);
  }
  .sb-overlay.on { opacity: 1; pointer-events: auto; }

  /* Topbar: tighter, hide the long date/time string. */
  .topbar { padding: 0 12px; gap: 10px; }
  .topbar-clock { display: none; }
  /* Admin topbar: drop the "역할 · 이름" meta and the redundant "관리자 /"
     crumb prefix so the burger + current section fit a narrow screen. */
  .admin-topbar-meta { display: none; }
  .admin-crumb-root { display: none; }

  /* Page chrome: reclaim horizontal space. */
  .page-head { padding: 18px 16px 12px; }
  .page-title { font-size: 21px; }
  .page-sub { font-size: 12.5px; }
  .page-body.scrolly { padding: 4px 16px 24px; }
  .card { padding: 16px; }

  /* Modals fill the small viewport with comfortable margins. */
  .modal-bg { padding: 12px; }
  .modal { max-width: 100%; border-radius: 16px; }
  .modal-head { padding: 18px 18px 4px; }
  .modal-body { padding: 14px 18px 18px; }
  .modal-foot { padding: 14px 18px; }
  /* 배경 패딩이 12px로 줄어드는 만큼 스크롤 모달도 더 높이 쓴다. */
  .modal.scroll { max-height: calc(100vh - 24px); }

  /* Grid-based admin tables turn into stacked "label: value" cards on phones —
     no more dragging a wide row sideways to read it. The header row is dropped;
     each row becomes a card whose cells surface their column via data-label.
     The first cell is the card header (identity) and keeps its own layout; an
     unlabeled trailing cell is the actions row. */
  .table {
    overflow: visible;
    background: transparent;
    border: 0;
    border-radius: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  .table-head { display: none; }
  .table-row {
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--surface);
    overflow: hidden;
  }
  .table-row:hover { background: var(--surface); }
  .table-row > *:not(:first-child) {
    display: flex !important;
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 9px 15px;
    border-top: 1px solid var(--line);
    font-size: 12.5px;
    text-align: left;
  }
  .table-row > *:not(:first-child)::before {
    content: attr(data-label);
    flex-shrink: 0;
    min-width: 76px;
    color: var(--ink-4);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .02em;
  }
  /* First cell = card header. Keep its inline layout (avatar+name, or a stacked
     title), just frame it. */
  .table-row > *:first-child {
    padding: 13px 15px 11px;
    background: var(--surface-2);
  }
  /* Trailing unlabeled cell = the actions; right-align its buttons, drop the
     empty label slot. */
  .table-row > *:not([data-label]):not(:first-child) { justify-content: flex-end; }
  .table-row > *:not([data-label]):not(:first-child)::before { content: none; }

  /* Admin dashboard stat grids reflow instead of crushing. */
  .rgrid-3, .rgrid-4 { grid-template-columns: repeat(2, 1fr); }
  .rsplit, .rsplit-3 { grid-template-columns: 1fr; }
}

/* 교육 운영 현황표가 함께 쓰는 패널 상자 — 검색 줄과 표를 한 장으로 감싼다. */
.edu-panel { overflow: hidden; border: 1px solid var(--line); border-radius: 15px; background: var(--surface); box-shadow: 0 2px 7px rgba(0,0,0,.018); }

/* ───────── 교육 운영: 현황표 (사업주 · 내배카 공용) ───────── */
.edu-ledger { display: flex; flex-direction: column; gap: 14px; padding-bottom: 20px; }
.edu-colcount { margin-left: auto; color: var(--ink-5); font-size: 11.5px; }
.edu-colcount b { color: var(--ink-3); }
/* 검색 줄 + 표를 한 장으로 묶는다. .edu-ledger의 gap이 사이에 끼면 이어 붙도록
   설계된 모서리(위만 둥근 검색 줄 / 아래만 둥근 표)가 어긋나 틈으로 배경이 샌다. */
.edu-panel { display: flex; flex-direction: column; min-width: 0; }
.eg-controls { min-height: 56px; display: flex; align-items: center; gap: 8px; padding: 10px 11px; border: 1px solid var(--line); border-bottom: 0; border-radius: 13px 13px 0 0; background: var(--surface); flex-wrap: wrap; }
.eg-search { width: 250px; height: 35px; display: flex; align-items: center; gap: 8px; padding: 0 10px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink-5); background: var(--surface); }
.eg-search:focus-within { border-color: color-mix(in oklch, var(--accent) 50%, var(--line)); box-shadow: 0 0 0 3px var(--accent-soft); }
.eg-search input { min-width: 0; width: 100%; border: 0; outline: 0; color: var(--ink); background: transparent; font: inherit; font-size: 12px; }
.eg-count { color: var(--ink-4); font-size: 11px; }
.eg-count b { color: var(--ink); }
.edu-table-wrap { border: 1px solid var(--line); border-radius: 0 0 13px 13px; background: var(--surface); overflow: hidden; }
.edu-table-scroll { overflow: auto; max-height: min(620px, calc(100vh - 420px)); }
table.edu-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; white-space: nowrap; }
table.edu-table th { position: sticky; top: 0; z-index: 3; background: var(--surface-2); color: var(--ink-5); font-size: 10.5px; font-weight: 650; letter-spacing: .035em; text-align: left; padding: 12px 13px; border-bottom: 1px solid var(--line); }
table.edu-table td { height: 64px; padding: 11px 13px; border-top: 1px solid var(--line); color: var(--ink-3); vertical-align: middle; }
table.edu-table tbody tr:first-child td { border-top: 0; }
table.edu-table tbody tr:hover td { background: color-mix(in oklab, var(--surface-2) 42%, var(--surface)); }
/* 행 아무 데나 누르면 상세가 열린다(수정 칸·체크박스는 자기 동작을 지킨다).
   클래스 이름은 .edu-row(회차 관리의 그리드 행)와 겹치지 않게 둔다. */
table.edu-table tbody tr.edu-tr { cursor: pointer; }
table.edu-table tbody tr.on td { background: color-mix(in oklch, var(--accent) 4%, var(--surface)); }
table.edu-table th.n, table.edu-table td.n { text-align: right; font-variant-numeric: tabular-nums; }
table.edu-table td b { color: var(--ink-2); font-weight: 640; }
table.edu-table td small { display: block; margin-top: 4px; color: var(--ink-5); font-size: 10.5px; font-weight: 450; }
table.edu-table th.chk, table.edu-table td.chk { width: 40px; padding-right: 0; }
table.edu-table input[type="checkbox"] { width: 15px; height: 15px; accent-color: var(--accent); }
table.edu-table th.fix, table.edu-table td.fix { position: sticky; background: var(--surface); z-index: 2; }
table.edu-table th.fix { z-index: 4; background: var(--surface-2); }
table.edu-table tbody tr:hover td.fix { background: color-mix(in oklab, var(--surface-2) 42%, var(--surface)); }
table.edu-table tbody tr.on td.fix { background: color-mix(in oklch, var(--accent) 4%, var(--surface)); }
table.edu-table .edge { box-shadow: 1px 0 0 var(--line); }
/* 접어 둔 건을 펼쳤을 때 왜 접혔는지 — 이름 아래 작은 표식 */
.edu-flag { display: inline-block; margin: 6px 0 0 42px; padding: 2px 7px; border-radius: 999px; color: var(--ink-5); background: var(--surface-3); font-size: 10px; font-weight: 650; }
.edu-flag.warn { color: #b45309; background: color-mix(in oklch, #f59e0b 12%, transparent); }
/* 첫 열(신청자·업체)은 키보드로 상세를 여는 통로다. 안내는 행 툴팁이 하므로
   눈에 띄는 꾸밈은 두지 않는다 — 표 안에 밑줄이 하나 더 생기면 「바로 수정」
   점선과 헷갈린다. */
.edu-open { display: block; width: 100%; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.edu-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 8px; }
/* 수정 가능한 칸만 점선 밑줄 — LMS/자동계산 칸과 눈으로 구분된다. */
.edu-cell-btn { display: block; width: 100%; padding: 2px 0; border: 0; border-bottom: 1px dashed var(--line-strong); background: transparent; color: inherit; font: inherit; text-align: inherit; transition: background var(--t), border-color var(--t); }
.edu-cell-btn:hover { border-bottom-color: var(--accent); background: color-mix(in oklch, var(--accent) 7%, transparent); }
.edu-cell-input { width: 100%; min-width: 92px; padding: 4px 7px; border: 1px solid var(--accent); border-radius: 6px; background: var(--surface); color: var(--ink); font: inherit; font-size: 12.5px; outline: none; box-shadow: 0 0 0 3px var(--accent-soft); }
.edu-person { display: flex; align-items: center; gap: 9px; min-width: 0; }
.edu-person > i { width: 33px; height: 33px; display: grid; place-items: center; flex: 0 0 33px; border-radius: 50%; color: #5659c6; background: #eeeefe; font-size: 11px; font-weight: 720; font-style: normal; }
.edu-person > i.sq { border-radius: 10px; color: var(--ink-3); background: var(--surface-2); }
.edu-person div { min-width: 0; }
.edu-person b { display: block; color: var(--ink-2); font-size: 12.5px; font-weight: 640; }
.edu-empty-v { color: var(--ink-5); }
.edu-danger { color: #c34b46; }
/* 진도율 — 막대와 숫자를 한 줄에. 셀이 오른쪽 정렬이라 전체가 오른쪽에 붙는다. */
.edu-rate { display: inline-flex; align-items: center; gap: 8px; }
.edu-rate b { color: var(--ink-2); font-weight: 640; }
.edu-bar { display: block; height: 5px; width: 52px; flex: 0 0 52px; border-radius: 3px; background: var(--surface-3); overflow: hidden; }
.edu-bar i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
.edu-bar i.low { background: #d97706; }
.edu-table-empty { min-height: 300px; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 20px; color: var(--ink-4); text-align: center; }
.edu-table-empty h3 { margin: 0; color: var(--ink-2); font-size: 16px; font-weight: 670; }
.edu-table-empty p { max-width: 520px; margin: 9px 0 0; font-size: 12.5px; line-height: 1.55; }
/* 카드 맨 아래 띠라 바깥이 곧 페이지 배경(--bg #FAFAF9)이다. --surface-2(#F4F4F2)로
   채우면 둘이 거의 같은 색이라 카드 아래 모서리가 배경에 녹는다. 흰 면을 유지하고
   위쪽 선으로만 본문과 나눈다. */
.edu-table-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 15px; border-top: 1px solid var(--line); background: var(--surface); color: var(--ink-5); font-size: 11px; }
.edu-bulk { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; padding: 12px 15px; border-top: 1px solid color-mix(in oklch, var(--accent) 20%, var(--line)); background: color-mix(in oklch, var(--accent) 5%, var(--surface)); }
.edu-bulk .lead { color: var(--accent); font-size: 12px; font-weight: 700; }
.edu-bulk .hint { margin-left: auto; color: var(--ink-5); font-size: 11px; }
.edu-bulk .select, .edu-bulk .input { min-height: 34px; font-size: 12px; }
.edu-bulk-date { max-width: 150px; }
.edu-src { display: inline-flex; padding: 1px 5px; border-radius: 4px; font-size: 9.5px; font-weight: 700; font-style: normal; }
.edu-src.lms { color: var(--accent); background: var(--accent-soft); }
.edu-src.calc { color: #16805d; background: color-mix(in oklch, #16805d 10%, transparent); }
.edu-src.hrd { color: #b45309; background: color-mix(in oklch, #f59e0b 12%, transparent); }
.edu-src.manual { color: #c34b46; background: color-mix(in oklch, #c34b46 9%, transparent); }
.edu-src.auto { color: var(--ink-4); background: var(--surface-3); }
/* 국비 헤더 — 연동 상태 + 통합 새로고침 (탭마다 흩어져 있던 동기화를 모았다) */
.gukbi-sync { display: flex; align-items: center; gap: 8px; }
.gukbi-sync-status { display: flex; align-items: center; gap: 5px; margin-right: 2px; }
.gukbi-src { display: inline-flex; align-items: center; gap: 5px; padding: 5px 9px; border: 1px solid var(--line); border-radius: 999px; color: var(--ink-4); background: var(--surface); font-size: 11px; font-weight: 600; white-space: nowrap; }
.gukbi-src i { width: 6px; height: 6px; flex: 0 0 6px; border-radius: 50%; background: var(--ink-5); }
/* 마지막 동기화 시각 — 칩 안에서 라벨보다 한 톤 옅게 */
.gukbi-src b { color: var(--ink-5); font-size: 10.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.gukbi-src.ok b { color: var(--ink-3); }
.gukbi-src.fail b { color: inherit; }
.gukbi-src.ok i { background: #16805d; }
.gukbi-src.fail { border-color: color-mix(in oklch, #c34b46 30%, var(--line)); color: #c34b46; }
.gukbi-src.fail i { background: #c34b46; }

.modal.gukbi-sync-modal { width: min(520px, calc(100vw - 48px)); }
.gukbi-sync-steps { display: flex; flex-direction: column; gap: 8px; margin: 0; padding: 0; list-style: none; }
.gukbi-sync-steps li { display: flex; align-items: flex-start; gap: 11px; padding: 13px 14px; border: 1px solid var(--line); border-radius: 11px; background: var(--surface); }
.gukbi-sync-steps li .mark { width: 20px; height: 20px; display: grid; place-items: center; flex: 0 0 20px; margin-top: 1px; border-radius: 50%; color: var(--ink-5); background: var(--surface-2); font-size: 11px; }
.gukbi-sync-steps li b { display: block; color: var(--ink-2); font-size: 12.5px; font-weight: 620; }
.gukbi-sync-steps li small { display: block; margin-top: 4px; color: var(--ink-4); font-size: 11px; line-height: 1.5; }
.gukbi-sync-steps li.running { border-color: color-mix(in oklch, var(--accent) 40%, var(--line)); }
.gukbi-sync-steps li.running .mark { background: transparent; }
.gukbi-sync-steps li.done .mark { color: #fff; background: #16805d; }
.gukbi-sync-steps li.fail { border-color: color-mix(in oklch, #c34b46 28%, var(--line)); }
.gukbi-sync-steps li.fail .mark { color: #fff; background: #c34b46; }
.gukbi-sync-steps li.fail small { color: #c34b46; }
.gukbi-sync-steps li.skip { opacity: .65; }

@media (max-width: 768px) {
  .gukbi-sync { flex-wrap: wrap; justify-content: flex-end; }
  .gukbi-sync-status { order: -1; width: 100%; justify-content: flex-end; }
}

.edu-form { display: grid; gap: 6px; }
.edu-form .label { margin-top: 8px; }

/* 엑셀 이관 마법사 — 업로드 → 열 매핑 → 미리보기 → 확정 */
.modal.edu-import-modal { width: min(860px, calc(100vw - 48px)); display: flex; flex-direction: column; max-height: calc(100vh - 64px); }
.edu-import-steps { display: flex; gap: 6px; margin: 0 0 16px; padding: 0; list-style: none; }
.edu-import-steps li { display: flex; align-items: center; gap: 6px; flex: 1; padding: 8px 10px; border: 1px solid var(--line); border-radius: 9px; color: var(--ink-5); background: var(--surface-2); font-size: 11.5px; }
.edu-import-steps li b { width: 18px; height: 18px; display: grid; place-items: center; border-radius: 50%; color: var(--ink-4); background: var(--surface); font-size: 10px; }
.edu-import-steps li.on { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); color: var(--accent); background: var(--accent-soft); font-weight: 620; }
.edu-import-steps li.on b { color: #fff; background: var(--accent); }

.edu-import-drop { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 42px 20px; border: 1px dashed var(--line-strong); border-radius: 13px; text-align: center; }
.edu-import-drop > div { width: 52px; height: 52px; display: grid; place-items: center; margin-bottom: 13px; border-radius: 14px; color: var(--accent); background: var(--accent-soft); }
.edu-import-drop h4 { margin: 0; color: var(--ink-2); font-size: 15px; font-weight: 640; }
.edu-import-drop p { max-width: 460px; margin: 8px 0 16px; color: var(--ink-4); font-size: 12px; line-height: 1.55; }
.edu-import-drop label.btn { cursor: pointer; }

.edu-import-controls { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.edu-import-controls label { display: flex; flex-direction: column; gap: 5px; }
.edu-import-controls label > span { color: var(--ink-5); font-size: 11px; font-weight: 600; }
.edu-import-controls select { min-width: 200px; height: 34px; padding: 0 26px 0 10px; border: 1px solid var(--line); border-radius: 8px; color: var(--ink-2); background: var(--surface); font: inherit; font-size: 11.5px; }
.edu-import-note { margin: 0; color: var(--ink-5); font-size: 11px; }
.edu-import-controls .edu-import-note { margin-left: auto; padding-bottom: 9px; }

.edu-import-map { display: flex; flex-direction: column; gap: 6px; max-height: 380px; }
.edu-import-map-row { display: grid; grid-template-columns: minmax(0, 1fr) 16px 220px; align-items: center; gap: 10px; padding: 8px 11px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface); }
.edu-import-map-row > div { min-width: 0; }
.edu-import-map-row b { display: block; overflow: hidden; color: var(--ink-2); font-size: 12px; font-weight: 620; text-overflow: ellipsis; white-space: nowrap; }
.edu-import-map-row small { display: block; overflow: hidden; margin-top: 3px; color: var(--ink-5); font-size: 10.5px; text-overflow: ellipsis; white-space: nowrap; }
.edu-import-map-row select { height: 32px; padding: 0 24px 0 9px; border: 1px solid var(--line); border-radius: 7px; color: var(--ink-2); background: var(--surface); font: inherit; font-size: 11.5px; }
.edu-import-map-row svg { color: var(--ink-5); }

.edu-import-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 9px; margin-bottom: 13px; }
.edu-import-summary article { padding: 13px 14px; border: 1px solid var(--line); border-radius: 11px; background: var(--surface); }
.edu-import-summary article > span { color: var(--ink-5); font-size: 11px; }
.edu-import-summary article > strong { display: block; margin-top: 6px; color: var(--ink); font-size: 24px; font-weight: 700; line-height: 1; }
.edu-import-summary article p { margin: 6px 0 0; color: var(--ink-5); font-size: 10.5px; }
.edu-import-summary article.ok { border-color: color-mix(in oklch, #16805d 26%, var(--line)); }
.edu-import-summary article.ok > strong { color: #16805d; }
.edu-import-summary article.bad { border-color: color-mix(in oklch, #c34b46 26%, var(--line)); }
.edu-import-summary article.bad > strong { color: #c34b46; }

.edu-import-check { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 13px; padding: 12px 13px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface-2); cursor: pointer; }
.edu-import-check b { display: block; color: var(--ink-2); font-size: 12px; font-weight: 620; }
.edu-import-check small { display: block; margin-top: 4px; color: var(--ink-5); font-size: 11px; line-height: 1.5; }

.edu-import-preview { display: flex; flex-direction: column; gap: 5px; max-height: 320px; }
.edu-import-preview-row { display: flex; align-items: center; gap: 10px; padding: 8px 11px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface); font-size: 11.5px; }
.edu-import-preview-row > div { flex: 1; min-width: 0; }
.edu-import-preview-row b { display: block; overflow: hidden; color: var(--ink-2); font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.edu-import-preview-row small { display: block; margin-top: 3px; color: #c34b46; font-size: 10.5px; }
.edu-import-preview-row .tag { padding: 3px 7px; border-radius: 999px; font-size: 10px; font-weight: 680; }
.edu-import-preview-row.new .tag { color: #16805d; background: color-mix(in oklch, #16805d 11%, transparent); }
.edu-import-preview-row.duplicate .tag { color: var(--ink-4); background: var(--surface-2); }
.edu-import-preview-row.error { border-color: color-mix(in oklch, #c34b46 24%, var(--line)); }
.edu-import-preview-row.error .tag { color: #c34b46; background: color-mix(in oklch, #c34b46 10%, transparent); }
.edu-import-preview-row > .num { color: var(--ink-5); font-size: 10.5px; }

@media (max-width: 640px) {
  .edu-import-map-row { grid-template-columns: 1fr; }
  .edu-import-map-row svg { display: none; }
  .edu-import-controls select { width: 100%; min-width: 0; }
}

/* 상세 — 카드형 모달 (국비 대장 EntryDetail 과 같은 문법, 항목이 많아 2열) */
/* modal-bg의 24px 패딩만큼만 빼면 화면 높이를 꽉 채워 위아래가 붙어 보인다.
   96px을 빼서 위아래로 48px씩 숨 쉴 공간을 남긴다. */
.modal.edu-detail { width: min(1080px, calc(100vw - 48px)); max-width: 1080px; display: flex; flex-direction: column; max-height: calc(100vh - 96px); }
.edu-detail .modal-head { padding: 24px 28px 6px; }
.edu-detail .modal-head h3 { margin: 4px 0 0; font-size: 20px; font-weight: 650; letter-spacing: -.02em; }
.edu-detail .modal-head p { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 8px 0 0; color: var(--ink-4); font-size: 12.5px; }
.edu-detail .modal-body { flex: 1; min-height: 0; overflow-y: auto; padding: 18px 28px 22px; }
.edu-detail .modal-foot { padding: 16px 28px; justify-content: space-between; align-items: center; }
.edu-sec { border: 1px solid var(--line); border-radius: 14px; margin-bottom: 12px; overflow: hidden; background: var(--surface); }
.edu-sec > button { display: flex; align-items: center; gap: 11px; width: 100%; padding: 16px 18px; border: 0; background: var(--surface); text-align: left; font: inherit; transition: background .15s; }
.edu-sec.open > button { background: var(--surface-2); }
.edu-sec > button:hover { background: var(--surface-2); }
.edu-sec-mark { width: 3px; height: 17px; border-radius: 2px; background: var(--accent); flex-shrink: 0; }
.edu-sec-name { font-size: 15.5px; font-weight: 650; color: var(--ink); }
.edu-sec-cnt { color: var(--ink-5); font-size: 11.5px; font-weight: 500; }
.edu-sec-chev { margin-left: auto; display: flex; align-items: center; color: var(--ink-4); transition: transform .2s; }
.edu-sec.open .edu-sec-chev { transform: rotate(180deg); }
.edu-sec-body { border-top: 1px solid var(--line); padding: 20px 20px 22px; }
.edu-dgrid { display: grid; grid-template-columns: 148px minmax(0, 1fr) 148px minmax(0, 1fr); gap: 15px 28px; align-items: start; }
.edu-dl { font-size: 13px; color: var(--ink-4); font-weight: 550; padding-top: 6px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.edu-dv { min-width: 0; font-size: 14.5px; color: var(--ink-2); padding-top: 5px; }
.edu-dv .input, .edu-dv .select { width: 100%; max-width: 210px; font-size: 13.5px; }
.edu-dl.full { grid-column: 1; }
.edu-dv.full { grid-column: 2 / -1; }
.edu-dv.full .input { max-width: none; }
.edu-dnote { margin-top: 5px; color: var(--ink-5); font-size: 11.5px; font-weight: 450; line-height: 1.5; }
.edu-calc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 9px; }
.edu-calc { padding: 13px 15px; border-radius: 11px; background: var(--surface-2); color: var(--ink-3); font-size: 12.5px; line-height: 1.55; }
.edu-calc b { color: var(--ink); }
@media (max-width: 900px) { .edu-dgrid { grid-template-columns: 140px minmax(0, 1fr); } }

/* ── 회차 관리 (내배카 개설 일정) — 차수 시트 + 좌 과정리스트 / 우 회차관리 ── */
/* 회차별 현황 필터 줄의 접기/펼치기 구분선 */
.nb-filter-sep { width: 1px; height: 18px; margin: 0 3px; background: var(--line); align-self: center; }
.er-sheets { display: flex; gap: 6px; flex-wrap: wrap; }
.er-sheet { display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border: 1px solid var(--line); border-radius: 999px; color: var(--ink-4); background: var(--surface); font: inherit; font-size: 12px; font-weight: 550; cursor: pointer; }
.er-sheet:hover { border-color: var(--line-strong); color: var(--ink-2); }
.er-sheet.on { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); color: var(--accent); background: var(--accent-soft); font-weight: 650; }
.er-sheet.on svg { opacity: .7; }
.er-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: 14px; align-items: start; }
@media (max-width: 1080px) { .er-split { grid-template-columns: minmax(0, 1fr); } }
.er-pane-head { display: flex; align-items: center; gap: 9px; min-height: 54px; padding: 10px 14px; border-bottom: 1px solid var(--line); background: var(--surface-2); flex-wrap: wrap; }
.er-pane-head > strong { color: var(--ink); font-size: 13.5px; font-weight: 670; }
.er-count { color: var(--ink-4); font-size: 11.5px; font-weight: 600; }
.er-spacer { flex: 1; }
.er-filter { display: inline-flex; gap: 3px; padding: 3px; border-radius: 8px; background: var(--surface-3); }
.er-filter button { padding: 4px 10px; border: 0; border-radius: 6px; color: var(--ink-4); background: transparent; font: inherit; font-size: 11px; font-weight: 620; cursor: pointer; white-space: nowrap; }
.er-filter button.on { color: var(--accent); background: var(--surface); box-shadow: 0 1px 2px rgba(0,0,0,.08); }
.er-body { min-height: 240px; max-height: 480px; overflow: auto; }
table.er-tbl { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
table.er-tbl th { position: sticky; top: 0; z-index: 2; padding: 10px 10px; border-bottom: 1px solid var(--line); background: var(--surface); color: var(--ink-5); font-size: 10.5px; font-weight: 650; letter-spacing: .03em; text-align: left; white-space: nowrap; }
table.er-tbl th.c, table.er-tbl td.c { text-align: center; }
table.er-tbl td { padding: 7px 10px; border-bottom: 1px solid var(--line); color: var(--ink-3); vertical-align: middle; white-space: nowrap; }
table.er-tbl tbody tr:last-child td { border-bottom: 0; }
table.er-tbl tr.past td { opacity: .5; }
table.er-tbl tr.next td { background: color-mix(in oklch, var(--accent) 5%, var(--surface)); }
table.er-tbl tr.next td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
.er-next { display: inline-block; margin-left: 5px; padding: 1px 6px; border-radius: 5px; color: var(--accent); background: var(--accent-soft); font-size: 9.5px; font-weight: 750; vertical-align: 1px; }
.er-course-name { display: block; max-width: 380px; overflow: hidden; text-overflow: ellipsis; color: var(--ink-2); font-weight: 600; }
.er-input { width: 100%; min-width: 0; padding: 6px 8px; border: 1px solid transparent; border-radius: 7px; background: transparent; color: var(--ink-2); font: inherit; font-size: 12.5px; font-weight: 550; outline: none; }
.er-input:hover { border-color: var(--line); background: var(--surface); }
.er-input:focus { border-color: var(--accent); background: var(--surface); box-shadow: 0 0 0 3px var(--accent-soft); }
input[type="date"].er-input { font-variant-numeric: tabular-nums; }
.er-date { display: inline-flex; align-items: center; gap: 5px; padding: 4px 2px; border: 0; border-bottom: 1px dashed var(--line-strong); background: transparent; color: inherit; font: inherit; cursor: pointer; }
.er-date:hover { border-bottom-color: var(--accent); color: var(--ink); }
.er-dot { width: 6px; height: 6px; flex: 0 0 6px; border-radius: 50%; background: var(--accent); font-style: normal; }
.er-tbl .nb-status { margin-left: 7px; }
.er-ox { width: 30px; height: 26px; border: 0; border-radius: 7px; background: transparent; color: var(--ink-5); font: inherit; font-size: 13px; font-weight: 750; line-height: 1; cursor: pointer; }
.er-ox.on { color: #16805d; background: color-mix(in oklch, #16805d 10%, transparent); }
.er-ox:not(:disabled):not(.on):hover { color: #c34b46; background: color-mix(in oklch, #c34b46 8%, transparent); }
.er-ox:disabled { cursor: default; }
.er-del { display: inline-grid; place-items: center; width: 24px; height: 24px; border: 0; border-radius: 6px; background: transparent; color: var(--ink-5); cursor: pointer; }
.er-del:hover { color: #c34b46; background: color-mix(in oklch, #c34b46 9%, transparent); }
.er-del.ok:hover { color: #16805d; background: color-mix(in oklch, #16805d 10%, transparent); }
.er-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 200px; padding: 30px 16px; color: var(--ink-5); font-size: 12px; line-height: 1.7; text-align: center; }
.er-adding td { background: color-mix(in oklch, var(--accent) 4%, var(--surface)); }
.er-foot { padding: 10px 14px; border-top: 1px solid var(--line); background: var(--surface); color: var(--ink-5); font-size: 11px; }
.er-foot b { color: var(--accent); }
/* 과정명 제안 팝오버 — Select의 메뉴와 같은 겉모습 (OS datalist 대체) */
.er-suggest { overflow-y: auto; padding: 5px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); box-shadow: var(--shadow-lg); }
.er-suggest button { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; padding: 8px 11px; border: 0; border-radius: 7px; background: transparent; color: var(--ink-2); font: inherit; font-size: 12.5px; text-align: left; cursor: pointer; }
.er-suggest button.on { background: var(--surface-2); }
.er-suggest button .truncate { max-width: 100%; }
.er-suggest button small { color: var(--ink-4); font-size: 10.5px; }

/* ───────── Utility ───────── */
.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Decorative "mono" labels render in the sans face — the monospace fallback
   looks broken on Windows and clashes with Pretendard for Korean text. True
   monospace (codes, secrets) opts in via `font-family: var(--font-mono)`. */
.mono { font-family: var(--font); white-space: nowrap; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.divider { height: 1px; background: var(--line); width: 100%; }
/* The actions column (last child) keeps its size; the title column flexes.
   Guard with :not(:first-child) so a page-head with NO actions — i.e. a single
   title/sub column — stays shrinkable and wraps instead of overflowing and
   getting clipped by .page's overflow:hidden on a narrow screen. */
.page-head > div:first-child { min-width: 0; }
.page-head > div:last-child:not(:first-child) { flex-shrink: 0; }

/* ───────── 오늘의 일과 (tk-) — 멤버 + 어드민 공용 리뉴얼 ───────── */
/* TaskTrek 레퍼런스를 앱 라이트 문법으로 번역: 인디고 히어로 1곳에만 그라데이션,
   주간 스트립 선택은 잉크 필(언더라인 탭과 같은 액티브 문법), 나머지는 12px 카드. */

.tk-hero {
  position: relative; overflow: hidden;
  display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 40px;
  padding: 28px 34px;
  border-radius: 20px;
  background: linear-gradient(135deg, #6366F1 0%, #4F46E5 78%, #4338CA 100%);
  box-shadow: 0 20px 44px -16px color-mix(in oklch, #4F46E5 55%, transparent);
  margin-bottom: 12px;
}
.tk-hero::before, .tk-hero::after {
  content: ''; position: absolute; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255,255,255,.10) 0%, transparent 68%);
}
.tk-hero::before { width: 460px; height: 460px; right: -120px; top: -260px; }
.tk-hero::after  { width: 380px; height: 380px; left: 28%; bottom: -300px; }
.tk-hero-kicker { font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.66); }
.tk-hero-row { display: flex; align-items: baseline; gap: 14px; margin-top: 10px; flex-wrap: wrap; }
.tk-hero-big { font-size: 56px; font-weight: 250; letter-spacing: -.045em; line-height: 1; color: #fff; }
.tk-hero-big .of { color: rgba(255,255,255,.5); }
.tk-hero-mood { font-size: 14px; color: rgba(255,255,255,.82); font-weight: 450; }
.tk-leafbar { display: flex; gap: 3px; margin-top: 20px; position: relative; z-index: 1; }
.tk-leafbar i { flex: 1; height: 6px; border-radius: 3px; background: rgba(255,255,255,.22); transition: background .3s; }
.tk-leafbar i.done { background: #fff; }
.tk-leafbar i.high { background: rgba(255,255,255,.45); }
.tk-hero-meta { display: flex; gap: 18px; margin-top: 14px; font-size: 11.5px; color: rgba(255,255,255,.62); }
.tk-hero-meta b { color: rgba(255,255,255,.92); font-weight: 650; }
.tk-ring { position: relative; width: 116px; height: 116px; z-index: 1; flex-shrink: 0; }
.tk-ring svg { transform: rotate(-90deg); display: block; }
.tk-ring .track { stroke: rgba(255,255,255,.2); }
.tk-ring .fill { stroke: #fff; transition: stroke-dashoffset .5s cubic-bezier(.2,.7,.2,1); }
.tk-ring-pct { position: absolute; inset: 0; display: grid; place-items: center; color: #fff; font-size: 23px; font-weight: 600; letter-spacing: -.03em; }
.tk-ring-pct small { font-size: 11px; font-weight: 500; color: rgba(255,255,255,.7); margin-left: 1px; }

/* 주간 스트립 */
.tk-week-wrap { display: grid; grid-template-columns: auto 1fr auto; gap: 8px; margin-bottom: 30px; }
.tk-week-arrow { border: 1px solid var(--line); background: var(--surface); border-radius: var(--radius); width: 34px; color: var(--ink-4); display: grid; place-items: center; cursor: pointer; transition: border-color var(--t), color var(--t); }
.tk-week-arrow:hover { border-color: var(--line-strong); color: var(--ink); }
.tk-week-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; }
.tk-day {
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: 10px 4px 11px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  cursor: pointer; transition: border-color var(--t), background var(--t);
  user-select: none; font-family: inherit;
}
.tk-day:hover { border-color: var(--line-strong); }
.tk-day-dow { font-size: 10.5px; font-weight: 600; color: var(--ink-4); display: flex; align-items: center; gap: 4px; }
.tk-day-dow em { font-style: normal; font-size: 9.5px; font-weight: 700; color: var(--accent); }
.tk-day-dt { font-size: 17px; font-weight: 650; letter-spacing: -.02em; color: var(--ink); }
.tk-day-marks { display: flex; gap: 3px; height: 4px; }
.tk-day-marks i { width: 4px; height: 4px; border-radius: 50%; background: var(--line-strong); }
.tk-day-marks i.hot { background: var(--accent); }
.tk-day.sel { background: var(--ink); border-color: var(--ink); }
.tk-day.sel .tk-day-dow { color: rgba(255,255,255,.6); }
.tk-day.sel .tk-day-dow em { color: #A5B4FC; }
.tk-day.sel .tk-day-dt { color: #fff; }
.tk-day.sel .tk-day-marks i { background: rgba(255,255,255,.45); }
.tk-day.sel .tk-day-marks i.hot { background: #A5B4FC; }
.tk-day.wknd .tk-day-dow, .tk-day.wknd .tk-day-dt { color: var(--ink-5); }
.tk-day.wknd .tk-day-dt { font-weight: 500; }
.tk-day.wknd.sel .tk-day-dow { color: rgba(255,255,255,.6); }
.tk-day.wknd.sel .tk-day-dt { color: #fff; }

/* 오늘로 이동 (헤더 우측) */
.tk-today-btn { border: 1px solid var(--line); background: var(--surface); font-family: inherit; font-size: 12px; font-weight: 550; color: var(--ink-3); padding: 7px 14px; border-radius: 9px; cursor: pointer; transition: border-color var(--t); }
.tk-today-btn:hover { border-color: var(--line-strong); }

/* 대분류 오버뷰 카드 — 클릭하면 아래 목록이 그 대분류만 보인다 */
.tk-ov-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 30px; }
.tk-ov-card { position: relative; padding: 16px 18px 18px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); transition: border-color var(--t), background var(--t), transform var(--t); cursor: pointer; user-select: none; text-align: left; font-family: inherit; }
.tk-ov-card:hover { border-color: var(--line-strong); }
.tk-ov-card:active { transform: scale(.985); }
.tk-ov-tag { display: inline-flex; align-items: center; gap: 6px; font-size: 10.5px; font-weight: 650; color: var(--ink-4); }
.tk-ov-tag i { width: 7px; height: 7px; border-radius: 2.5px; }
.tk-ov-card h3 { margin: 9px 0 3px; font-size: 14px; font-weight: 650; letter-spacing: -.015em; line-height: 1.35; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); }
.tk-ov-cnt { font-size: 11.5px; color: var(--ink-4); }
.tk-ov-bar { height: 4px; border-radius: 2px; background: var(--surface-3); margin-top: 13px; overflow: hidden; }
.tk-ov-bar i { display: block; height: 100%; border-radius: inherit; background: var(--ink); transition: width .4s cubic-bezier(.2,.7,.2,1); }
.tk-ov-card.sel { border-color: color-mix(in oklch, var(--accent) 55%, var(--line)); background: color-mix(in oklch, var(--accent) 3.5%, var(--surface)); box-shadow: 0 0 0 3px var(--accent-soft); }
.tk-ov-card.sel .tk-ov-tag { color: var(--accent); }
.tk-ov-card.sel .tk-ov-bar { background: color-mix(in oklch, var(--accent) 14%, transparent); }
.tk-ov-card.sel .tk-ov-bar i { background: var(--accent); }
.tk-ov-more { display: grid; place-items: center; gap: 2px; padding: 16px 18px; background: transparent; border: 1px dashed var(--line-strong); border-radius: var(--radius); color: var(--ink-4); font-family: inherit; font-size: 12px; font-weight: 550; cursor: pointer; transition: border-color var(--t), color var(--t); }
.tk-ov-more:hover { border-color: var(--ink-5); color: var(--ink-2); }
.tk-ov-more b { font-size: 17px; font-weight: 650; letter-spacing: -.02em; color: var(--ink-3); }
.tk-ov-hint { grid-column: 1 / -1; margin-top: -2px; font-size: 11px; color: var(--ink-5); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.tk-ov-hint b { color: var(--accent); font-weight: 650; }
.tk-ov-hint button { border: 0; background: none; font-family: inherit; font-size: 11px; color: var(--ink-4); text-decoration: underline; text-underline-offset: 2px; cursor: pointer; padding: 0; }

/* 본문 2컬럼 (탭은 공통 <Tabs variant="underline">) */
.tk-cols { display: grid; grid-template-columns: 1.55fr 1fr; gap: 26px; align-items: start; }

/* 빠른 추가 */
.tk-quick-add { display: flex; align-items: center; gap: 10px; padding: 10px 14px; background: var(--surface); border: 1px dashed var(--line-strong); border-radius: var(--radius); margin-bottom: 14px; transition: border-color var(--t); }
.tk-quick-add:focus-within { border-style: solid; border-color: var(--accent); }
.tk-quick-add input { flex: 1; border: 0; background: transparent; outline: none; font-size: 13.5px; font-family: inherit; color: var(--ink); min-width: 0; }
.tk-quick-add input::placeholder { color: var(--ink-5); }
.tk-quick-add kbd { font-family: inherit; font-size: 10px; color: var(--ink-5); border: 1px solid var(--line); border-radius: 5px; padding: 2px 6px; background: var(--surface-2); }

/* 대분류 그룹 카드 */
.tk-glist { display: flex; flex-direction: column; gap: 9px; }
.tk-group { position: relative; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; transition: border-color var(--t); }
.tk-group:hover { border-color: var(--line-strong); }
.tk-ghead { display: flex; align-items: center; gap: 12px; padding: 13px 14px 13px 19px; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.tk-gtitle { flex: 1; min-width: 0; font-size: 14px; font-weight: 650; letter-spacing: -.015em; line-height: 1.5; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tk-group.all-done .tk-gtitle { color: var(--ink-5); text-decoration: line-through; text-decoration-color: var(--line-strong); font-weight: 550; }
/* 우선순위 배지 — 좌측 줄/노치 대신 소프트 틴트 필 (앱 표준 문법). */
.tk-prio { font-size: 10px; font-weight: 750; padding: 3px 8px; border-radius: 999px; flex-shrink: 0; letter-spacing: .01em; line-height: 1.4; }
.tk-prio.p-high { color: var(--danger); background: color-mix(in oklch, var(--danger) 11%, transparent); }
.tk-prio.p-med { color: color-mix(in oklch, var(--warn) 82%, var(--ink)); background: color-mix(in oklch, var(--warn) 14%, transparent); }
.tk-prio.p-low { color: var(--ok); background: color-mix(in oklch, var(--ok) 12%, transparent); }
.tk-group.all-done .tk-prio { color: var(--ink-5); background: var(--surface-2); }
.tk-gcnt { font-size: 11.5px; color: var(--ink-4); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.tk-gstat { font-size: 11px; font-weight: 650; flex-shrink: 0; min-width: 40px; text-align: right; }
.tk-gstat.doing { color: var(--accent); }
.tk-gstat.done { color: var(--ok); }
.tk-chev { width: 24px; height: 24px; display: grid; place-items: center; color: var(--ink-5); flex-shrink: 0; border: 0; background: transparent; border-radius: 6px; cursor: pointer; transition: transform var(--t), color var(--t); padding: 0; }
.tk-chev:hover { color: var(--ink-2); background: var(--surface-2); }
.tk-chev.closed { transform: rotate(-90deg); }
.tk-chev.ghost { visibility: hidden; }
.tk-row-acts { display: flex; gap: 2px; opacity: 0; transition: opacity .15s; flex-shrink: 0; }
.tk-ghead:hover .tk-row-acts, .tk-sub:hover .tk-row-acts { opacity: 1; }

/* 체크박스 — 라운드 스퀘어, 완료 = 액센트 필, 부분완료 = 대시 */
.tk-cb { width: 19px; height: 19px; border-radius: 6px; border: 1.5px solid var(--line-strong); background: var(--surface); flex-shrink: 0; display: grid; place-items: center; cursor: pointer; transition: all var(--t); color: transparent; padding: 0; }
.tk-cb:hover { border-color: var(--accent); }
.tk-cb.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.tk-cb.half { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.tk-cb.sm { width: 17px; height: 17px; border-radius: 5px; }
.tk-cb-dash { width: 8px; height: 2px; border-radius: 1px; background: currentColor; display: block; }

/* 세부항목 — 트리 커넥터 */
.tk-subs { border-top: 1px solid var(--line); padding: 6px 0 7px; position: relative; }
.tk-subs::before { content: ''; position: absolute; left: 28px; top: 11px; bottom: 13px; width: 1px; background: var(--line); }
.tk-sub { position: relative; display: flex; align-items: center; gap: 12px; padding: 7px 14px 7px 46px; transition: background var(--t); user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.tk-sub:hover { background: color-mix(in oklab, var(--surface) 60%, var(--surface-2)); }
.tk-sub::before { content: ''; position: absolute; left: 28px; top: 50%; width: 11px; height: 1px; background: var(--line); }
/* 우선순위 밴드 라벨 — 정렬된 세부항목에서 밴드가 바뀌는 경계에 한 번만. */
.tk-subband { display: flex; align-items: center; gap: 7px; padding: 9px 14px 3px 46px; font-size: 10.5px; font-weight: 700; color: var(--ink-4); letter-spacing: .04em; user-select: none; -webkit-user-select: none; }
.tk-subband i { width: 3px; height: 9px; border-radius: 2px; flex-shrink: 0; }
.tk-subtxt { flex: 1; min-width: 0; font-size: 13px; color: var(--ink-2); line-height: 1.5; transition: color var(--t); }
.tk-sub.on .tk-subtxt { color: var(--ink-5); text-decoration: line-through; text-decoration-color: var(--line-strong); }
.tk-sub-add { position: relative; display: flex; align-items: center; gap: 12px; padding: 6px 14px 6px 46px; color: var(--ink-5); font-size: 12px; cursor: pointer; transition: color var(--t); border: 0; background: transparent; font-family: inherit; width: 100%; text-align: left; }
.tk-sub-add::before { content: ''; position: absolute; left: 28px; top: 50%; width: 11px; height: 1px; background: var(--line); }
.tk-sub-add:hover { color: var(--accent); }
.tk-sub-add .mini { width: 17px; height: 17px; display: grid; place-items: center; border: 1.5px dashed var(--line-strong); border-radius: 5px; flex-shrink: 0; }
.tk-sub-input { flex: 1; border: 0; background: transparent; outline: none; font-size: 13px; color: var(--ink); font-family: inherit; min-width: 0; }

/* 우측 컬럼 */
.tk-side { display: flex; flex-direction: column; gap: 13px; }
.tk-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 18px 20px; }
.tk-ck { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; color: var(--ink-4); text-transform: uppercase; display: flex; align-items: center; justify-content: space-between; }
.tk-ck em { font-style: normal; font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--ink-5); font-size: 10.5px; }
.tk-stat3 { display: grid; grid-template-columns: 1fr 1fr 1fr; margin-top: 15px; }
.tk-stat3 > div + div { border-left: 1px solid var(--line); padding-left: 18px; }
.tk-stat3 b { display: block; font-size: 23px; font-weight: 650; letter-spacing: -.03em; line-height: 1.1; color: var(--ink); }
.tk-stat3 b.ac { color: var(--accent); }
.tk-stat3 b small { font-size: 13px; font-weight: 500; color: var(--ink-4); }
.tk-stat3 span { display: block; margin-top: 4px; font-size: 10.5px; color: var(--ink-4); }
.tk-rhythm { display: grid; grid-template-columns: repeat(7, 1fr); gap: 8px; margin-top: 16px; align-items: end; }
.tk-rh { display: flex; flex-direction: column; align-items: center; gap: 7px; }
.tk-rh .col { width: 100%; height: 58px; border-radius: 6px; background: var(--surface-2); position: relative; overflow: hidden; }
.tk-rh .col i { position: absolute; left: 0; right: 0; bottom: 0; border-radius: 6px; background: var(--line-strong); transition: height .4s cubic-bezier(.2,.7,.2,1); }
.tk-rh.today .col i { background: var(--accent); }
.tk-rh .lb { font-size: 10px; color: var(--ink-5); font-weight: 550; }
.tk-rh.today .lb { color: var(--accent); font-weight: 700; }
.tk-rh-note { margin-top: 13px; padding-top: 12px; border-top: 1px solid var(--line); font-size: 11px; color: var(--ink-4); line-height: 1.55; }
.tk-rh-note b { color: var(--ink-2); font-weight: 650; }

/* ── 어드민 (일과 모니터링) ── */
.tka-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(400px, 100%), 1fr)); gap: 14px; }
.tka-card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px 22px; display: flex; flex-direction: column; transition: border-color var(--t); }
.tka-card:hover { border-color: var(--line-strong); }
.tka-head { display: flex; align-items: center; gap: 12px; }
.tka-mid { flex: 1; min-width: 0; }
.tka-mid b { display: block; font-size: 14px; font-weight: 650; letter-spacing: -.012em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tka-mid span { display: block; margin-top: 2px; font-size: 11.5px; color: var(--ink-4); }
.tka-mring { position: relative; width: 44px; height: 44px; flex-shrink: 0; }
.tka-mring svg { transform: rotate(-90deg); display: block; }
.tka-mring .track { stroke: var(--surface-3); }
.tka-mring .fill { stroke: var(--accent); transition: stroke-dashoffset .4s cubic-bezier(.2,.7,.2,1); }
.tka-mring.full .fill { stroke: var(--ok); }
.tka-mring-pv { position: absolute; inset: 0; display: grid; place-items: center; font-size: 10.5px; font-weight: 650; letter-spacing: -.02em; }
.tka-leaf { display: flex; gap: 3px; margin-top: 16px; }
.tka-leaf i { flex: 1; height: 5px; border-radius: 3px; background: var(--surface-3); }
.tka-leaf i.done { background: var(--ink); }
.tka-tasks { margin-top: 15px; display: flex; flex-direction: column; }
.tka-g { padding: 6px 0; }
.tka-g-head { display: flex; align-items: center; gap: 10px; }
.tka-okc { width: 17px; height: 17px; border-radius: 50%; flex-shrink: 0; display: grid; place-items: center; border: 1.6px solid var(--line-strong); color: #fff; background: transparent; }
.tka-okc.on { background: var(--ok); border-color: var(--ok); }
.tka-okc.half { border-color: var(--accent); }
.tka-okc.half i { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); display: block; }
.tka-g-head .t { flex: 1; min-width: 0; font-size: 13px; font-weight: 600; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tka-g.done .tka-g-head .t { color: var(--ink-5); text-decoration: line-through; text-decoration-color: var(--line-strong); font-weight: 500; }
.tka-g-head .c { font-size: 11px; color: var(--ink-4); flex-shrink: 0; }
.tka-subs { position: relative; margin-top: 3px; }
.tka-subs::before { content: ''; position: absolute; left: 8px; top: 2px; bottom: 8px; width: 1px; background: var(--line); }
.tka-sub { position: relative; display: flex; align-items: center; gap: 9px; padding: 4px 0 4px 26px; }
.tka-sub::before { content: ''; position: absolute; left: 8px; top: 50%; width: 10px; height: 1px; background: var(--line); }
.tka-sub .tka-okc { width: 14px; height: 14px; border-width: 1.4px; }
.tka-sub .t { flex: 1; min-width: 0; font-size: 12.5px; color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tka-sub.done .t { color: var(--ink-5); text-decoration: line-through; text-decoration-color: var(--line-strong); }
.tka-rest { margin-top: 20px; padding: 15px 20px; background: var(--surface); border: 1px dashed var(--line-strong); border-radius: var(--radius); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tka-rest .lb { font-size: 12px; color: var(--ink-4); }
.tka-rest .lb b { color: var(--ink-2); font-weight: 650; }
.tka-chip { display: inline-flex; align-items: center; gap: 6px; padding: 3px 10px 3px 3px; border: 1px solid var(--line); border-radius: 999px; background: var(--surface-2); font-size: 11.5px; font-weight: 550; color: var(--ink-3); }

@media (max-width: 768px) {
  .tk-hero { grid-template-columns: 1fr; gap: 0; padding: 22px 24px; }
  .tk-ring { display: none; }
  .tk-hero-big { font-size: 46px; }
  .tk-cols { grid-template-columns: 1fr; gap: 20px; }
  .tk-ov-row { grid-template-columns: 1fr; gap: 8px; margin-bottom: 24px; }
  .tk-day { padding: 8px 2px 9px; }
  .tk-day-dt { font-size: 14.5px; }
  .tk-day-dow { font-size: 9.5px; }
  .tk-week-arrow { width: 28px; }
  .tk-week-wrap { gap: 5px; }
  .tk-week-strip { gap: 5px; }
}

/* ───────── 국비: LMS 콘텐츠 (lms-) ───────── */
/* 동작 시안(국비-LMS콘텐츠-동작시안.html)의 계정 카드 · 출력 폴더 줄 규격.
   설정 화면을 따로 두지 않는 구성이다: 화면 맨 위에는 "지금 로그인돼 있나" 한 줄만
   두고, 출력 폴더는 실제로 그 폴더가 생기는 자리(과정 목록 = 기본 폴더,
   과정 상세 = 이 과정 폴더)에 각각 붙인다. */

.lms-acct { display: flex; align-items: center; gap: 13px; padding: 14px 16px; }
/* 긴 이메일·엔진 문구가 들어와도 버튼 폭은 안 줄어든다 — 가운데 칸이 다 떠안는다. */
.lms-acct > .btn { flex-shrink: 0; }
/* 로그인 상태는 이니셜 원, 그 외(확인 중·미로그인)는 사각 아이콘 배지로 구분한다. */
.lms-acct-avatar {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--ink); color: var(--bg);
  font-size: 13px; font-weight: 650; text-transform: uppercase;
}
.lms-acct-badge {
  width: 34px; height: 34px; border-radius: 9px; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--ink-4);
}
.lms-acct-badge.locked { background: color-mix(in oklch, var(--danger) 10%, transparent); color: var(--danger); }
.lms-acct-title { display: flex; align-items: center; gap: 7px; min-width: 0; }
.lms-acct-title .t { font-size: 13px; font-weight: 650; }
.lms-acct-sub { font-size: 11.5px; color: var(--ink-4); margin-top: 3px; line-height: 1.5; }
.lms-acct-sub b { color: var(--ink-2); font-weight: 650; }
/* 진행 문구·폴백 링크 — 로그인 중에만 나타나는 셋째 줄. */
.lms-acct-live { font-size: 11px; color: var(--accent); margin-top: 4px; line-height: 1.5; }
.lms-acct-live a { color: inherit; }
/* 멀티 계정(§7) — 계정 줄이 여러 개 쌓이고 아래에 [계정 추가] 푸터. 각 줄 오른쪽에
   한도 게이지 열(시안 envCard의 210px 미터)과 버튼 묶음. */
.lms-acct-list > .lms-acct-row + .lms-acct-row { border-top: 1px solid var(--line); }
.lms-acct-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.lms-acct-foot {
  display: flex; align-items: center; gap: 12px; padding: 9px 16px;
  border-top: 1px solid var(--line); background: var(--surface-2);
}
.lms-usage { width: 200px; flex-shrink: 0; display: flex; flex-direction: column; gap: 4px; }
.lms-usage-row { display: flex; align-items: center; gap: 7px; font-size: 10.5px; color: var(--ink-4); }
.lms-usage-label { width: 34px; flex-shrink: 0; }
.lms-usage-bar { flex: 1; height: 4px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.lms-usage-bar > i { display: block; height: 100%; border-radius: inherit; }
.lms-usage-pct { width: 32px; text-align: right; font-weight: 600; color: var(--ink-3); flex-shrink: 0; }

/* 전역 스크립트 대기열 줄 — 목록 화면 맨 위(계정 카드 위) 한 줄.
   대기열이 파일시스템(pending/)으로 내려가면서 "지금 뭐가 돌고 있나"가 과정 상세
   안에 갇히면 안 되게 됐다: 앱을 껐다 켜도 폴더에 남은 영상은 그대로고, 과정 A에서
   등록한 것이 과정 B 화면을 보는 동안에도 계속 돈다.
   규격은 그 아래 서 있는 출력 폴더 줄(.lms-outdir)에서 그대로 가져왔다 — 높이·
   라운드·간격이 같아야 "화면 맨 위의 상태 줄" 두 개가 한 짝으로 읽힌다. */
.lms-qbar {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 9px 13px; margin-bottom: 12px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
  font-family: inherit; text-align: left; color: var(--ink);
  transition: background var(--t), border-color var(--t);
}
.lms-qbar > .ic { flex-shrink: 0; display: grid; place-items: center; color: var(--ink-4); }
.lms-qbar > .t { flex: 1; min-width: 0; font-size: 12.5px; color: var(--ink-2); }
.lms-qbar > .t b { font-weight: 650; }
.lms-qbar > .t .dim { color: var(--ink-4); }
.lms-qbar > .acts { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.lms-qbar > .go { flex-shrink: 0; color: var(--ink-5); display: grid; place-items: center; }
/* 상태 1 — 워커가 돌고 있다. 줄 전체가 그 과정으로 가는 버튼이다(따로 버튼을 두지
   않는다): 여기서 할 수 있는 일은 "보러 가기" 하나뿐이라, 줄 안에 작은 과녁을 만들면
   오히려 어디를 눌러야 하는지 헷갈린다. 색은 단계 카드의 .lms-step-card.live와 같은 배합. */
.lms-qbar.live {
  cursor: pointer;
  border-color: color-mix(in oklch, var(--accent) 40%, var(--line));
  background: color-mix(in oklch, var(--accent) 6%, var(--surface));
}
.lms-qbar.live:hover { background: color-mix(in oklch, var(--accent) 12%, var(--surface)); }
.lms-qbar.live > .ic { color: var(--accent); }
.lms-qbar.live:hover > .go { color: var(--accent); }
/* 상태 2 — 워커는 없는데 pending/ 폴더에 영상이 남아 있다(앱 재시작 직후가 전형).
   사람이 손을 대야 다시 도는 자리라 경고색으로 세운다. 여기서만 버튼이 붙는다. */
.lms-qbar.idle {
  border-color: color-mix(in oklch, var(--warn) 40%, var(--line));
  background: color-mix(in oklch, var(--warn) 6%, var(--surface));
}
.lms-qbar.idle > .ic { color: var(--warn); }

/* 출력 폴더 줄 — 과정 목록(기본 폴더)·과정 상세(이 과정 폴더) 공용 */
.lms-outdir {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 13px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px;
}
.lms-outdir > .ic { color: var(--ink-3); display: grid; place-items: center; flex-shrink: 0; }
.lms-outdir-label { font-size: 11px; color: var(--ink-4); flex-shrink: 0; }
/* 경로는 진짜 등폭으로 — 유틸 .mono(본문 서체)와 달리 여긴 ASCII 경로뿐이다. */
.lms-outdir-path { min-width: 0; flex: 1; font-size: 12.5px; font-family: var(--font-mono); color: var(--ink-2); }
.lms-outdir-path .dim { color: var(--ink-5); }
.lms-outdir-path.empty { color: var(--ink-5); font-family: var(--font); }
/* 과정 상세용 — 줄이 좁아지면 부모 폴더부터 줄이고, 이 줄에서 정작 봐야 할
   폴더 이름은 끝까지 남긴다. 한 덩어리로 truncate하면 반대가 된다. */
.lms-outdir-path.split { display: flex; align-items: baseline; }
.lms-outdir-path.split > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 늘어나진 않고(0) 줄어들 때만 부모 폴더가 거의 전부 떠안는다(100 : 1) — 3em까지
   줄고 나서야 폴더 이름 차례다. 늘리기까지 맡기면 짧은 경로에서 폴더 이름이 오른쪽
   끝으로 밀려나 한 경로로 안 읽힌다. */
.lms-outdir-path.split > .dim { flex: 0 100 auto; min-width: 3em; }
.lms-outdir-path.split > .leaf { flex: 0 1 auto; }

/* 파이프라인 단계 카드 — 단계마다 카드 하나(동작 시안 stepCards). 카드 안에서 그
   단계의 상태를 보고, 그 단계를 실행하고, AI를 쓰는 단계면 모델까지 여기서 고른다.
   영상 등록은 단계로 세지 않는다 — 차시 목록이 곧 영상 등록이라 아래 차시 영역에서
   한다. 3칸 격자는 시안 그대로 두고 ① 스크립트부터 채운다(② HTML ③ 내보내기는
   이후 마일스톤에서 같은 자리에 들어온다). */
.lms-step-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-bottom: 16px; }
.lms-step-card {
  display: flex; flex-direction: column; min-height: 208px; padding: 15px 15px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color var(--t);
}
.lms-step-card.live { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); }
.lms-step-head { display: flex; align-items: center; gap: 9px; }
/* ① 스크립트 pill은 '진행 중 42%'처럼 퍼센트를 싣는다 — 자릿수가 바뀔 때마다
   글자 폭이 흔들리지 않게 고정폭 숫자로. */
.lms-step-head > .pill { margin-left: auto; font-variant-numeric: tabular-nums; }
.lms-step-no {
  width: 28px; height: 28px; flex-shrink: 0; border-radius: var(--radius-sm);
  display: grid; place-items: center;
  font-size: 12.5px; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--surface-2); color: var(--ink-5); border: 1px solid var(--line);
}
.lms-step-no.done { background: color-mix(in oklch, var(--ok) 12%, transparent); color: var(--ok); border-color: transparent; }
.lms-step-no.live { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.lms-step-title { font-size: 13.5px; font-weight: 650; letter-spacing: -.014em; min-width: 0; }
.lms-step-sub { font-size: 11px; color: var(--ink-4); line-height: 1.55; margin-top: 10px; }
.lms-step-body { margin-top: 11px; }
.lms-step-stat { font-size: 12.5px; color: var(--ink-2); }
.lms-step-stat b { color: var(--ink); font-weight: 650; }
.lms-step-note { font-size: 11px; color: var(--ink-5); line-height: 1.55; margin-top: 6px; }
.lms-step-foot { margin-top: auto; padding-top: 13px; display: flex; flex-direction: column; gap: 7px; }
.lms-step-btn { width: 100%; justify-content: center; }

/* 카드 3장이 무엇을 대상으로 도는지 알리는 줄 — 과정 전체 / 고른 차시.
   카드 자리는 하나뿐이라(차시마다 펼쳐지지 않는다) 이 줄이 유일한 이정표다. */
.lms-scope { display: flex; align-items: center; gap: 9px; margin-bottom: 10px; min-width: 0; }
.lms-scope-badge {
  width: 24px; height: 24px; flex-shrink: 0; border-radius: 8px; display: grid; place-items: center;
  font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums;
  background: var(--surface-2); color: var(--ink-4); border: 1px solid var(--line);
}
.lms-scope-badge.on { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.lms-scope-title { font-size: 13px; font-weight: 650; letter-spacing: -.014em; flex-shrink: 0; }
.lms-scope-sub { font-size: 11.5px; color: var(--ink-5); min-width: 0; }


/* 모델·강도 고르는 자리 — Claude를 쓰는 단계 카드의 실행 버튼 바로 위 한 줄
   (동작 시안 .ai-pick). 누르면 아래 .lms-pop 팝오버가 열린다. */
.lms-ai-pick {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 6px 9px; text-align: left;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 9px; color: var(--ink);
  font-family: inherit; cursor: pointer;
  transition: background var(--t), border-color var(--t), opacity var(--t);
}
.lms-ai-pick:hover:not(:disabled) { background: var(--surface); border-color: var(--line-strong); }
.lms-ai-pick:disabled { cursor: default; opacity: .6; }
.lms-ai-pick-ic {
  width: 22px; height: 22px; border-radius: 6px; flex-shrink: 0; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent);
}

/* 모델·강도 팝오버 — body 포털 + fixed. 고를 것만 담는다: 모델(+강도 슬라이더) / 계정.
   제목 줄과 적용 범위 푸터는 없앴다(2026-08-19). */
.lms-pop {
  position: fixed; z-index: 301;
  background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: var(--shadow-lg);
  overflow: hidden;
}
/* 고르는 줄(모델·계정) — 라디오 점 대신 고른 줄에만 체크. 버튼 안에 설명문이 들어가므로
   white-space를 풀어야 접힌다(button 기본 nowrap). 이름은 섹션 제목과 같은 선에 맞춘다. */
.lms-opts { margin: 0 -6px; }
.lms-opt {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 7px 6px;
  border: 0; border-radius: 8px; background: transparent; color: inherit;
  font-family: inherit; text-align: left; cursor: pointer; white-space: normal;
  transition: background var(--t);
}
.lms-opt:hover { background: var(--surface-2); }
.lms-opt-name {
  display: flex; align-items: center; gap: 6px; min-width: 0;
  font-size: 12.5px; font-weight: 650; letter-spacing: -.012em;
}
.lms-opt-desc { display: block; font-size: 10.5px; color: var(--ink-5); margin-top: 2px; line-height: 1.45; }
.lms-opt-check { flex-shrink: 0; display: grid; place-items: center; color: var(--ink); opacity: 0; }
.lms-opt.on .lms-opt-check { opacity: 1; }

/* 응답 강도 슬라이더 — 고른 모델 줄 바로 아래. 눈금 다섯 칸(낮음~최대)과 지금 값.
   채운 길이는 thumb 반지름(6.5px)을 셈에 넣어야 눈금·손잡이가 어긋나지 않는다. */
.lms-slider { display: flex; align-items: center; gap: 9px; padding: 0 6px 8px; }
.lms-slider > .t { font-size: 10.5px; color: var(--ink-5); flex-shrink: 0; }
.lms-slider > .v {
  font-size: 11px; font-weight: 650; color: var(--ink-2);
  flex-shrink: 0; min-width: 46px; text-align: right;
}
.lms-range { position: relative; flex: 1; min-width: 0; height: 16px; }
.lms-range > .track {
  position: absolute; left: 0; right: 0; top: 50%; transform: translateY(-50%);
  height: 4px; border-radius: 999px; background: var(--surface-3);
  display: flex; align-items: center; justify-content: space-between; padding: 0 5px;
}
.lms-range > .track::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; z-index: 1;
  width: calc(6.5px + var(--p, 0) * (100% - 13px));
  border-radius: inherit; background: var(--ink);
}
.lms-range > .track > i { width: 3px; height: 3px; border-radius: 50%; background: var(--line-strong); }
.lms-range > input {
  position: relative; width: 100%; height: 16px; margin: 0; padding: 0;
  -webkit-appearance: none; appearance: none; background: transparent; cursor: pointer;
}
.lms-range > input::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 13px; height: 13px; border-radius: 50%;
  background: var(--ink); border: 2px solid var(--surface); box-shadow: var(--shadow-sm); cursor: pointer;
}
.lms-range > input::-moz-range-thumb {
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--ink); border: 2px solid var(--surface); box-shadow: var(--shadow-sm); cursor: pointer;
}
.lms-range > input:focus-visible { outline: none; }
.lms-range > input:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 3px var(--accent-soft); }
.lms-range > input:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 3px var(--accent-soft); }
.lms-pop-sec { padding: 11px 12px 12px; border-top: 1px solid var(--line); }
/* 첫 섹션(모델)은 팝오버 테두리 바로 아래라 선을 겹쳐 긋지 않는다. */
.lms-pop-sec:first-child { border-top: 0; }
.lms-pop-sec-head { display: flex; align-items: baseline; gap: 6px; margin-bottom: 7px; }
.lms-pop-sec-head .t { font-size: 11.5px; font-weight: 650; flex-shrink: 0; }
.lms-pop-sec-head .d { font-size: 10.5px; color: var(--ink-5); }
.lms-pop-hint { font-size: 10.5px; color: var(--ink-5); margin-top: 7px; line-height: 1.5; }

/* 진행 막대 — 단계 카드 안의 차시 진행률(동작 시안 .bar). */
.lms-bar { height: 4px; border-radius: 999px; background: var(--surface-3); overflow: hidden; }
.lms-bar > i { display: block; height: 100%; border-radius: 999px; background: var(--accent); transition: width .18s linear; }
.lms-bar.ok > i { background: var(--ok); }

/* 차시 번호 칩 — 차시 섹션 헤더의 `01`(동작 시안 .lrow의 번호 칸). 평평하던 차시 줄은
   차시 = 영상 여러 편으로 바뀌면서 섹션(.lms-lsec)과 영상 줄(.lms-vrow)로 갈렸다. */
.lms-lno {
  width: 34px; height: 26px; border-radius: 7px; flex-shrink: 0;
  background: var(--surface-2); color: var(--ink-3);
  display: grid; place-items: center;
  font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums;
  transition: background var(--t), color var(--t);
}

/* ── HTML 검수·편집 화면 (lms-studio, M4c) — 3열: 트리 · 산출물 iframe · 편집 패널 ── */
.lms-studio-wrap { display: flex; flex-direction: column; min-height: 0; }
/* 검수 화면이 열려 있는 동안은 바깥(.page-body.scrolly)이 스크롤되지 않는다 —
   같이 스크롤되면 트리 버튼을 누를 때마다 포커스가 페이지를 위아래로 끌고 다닌다
   (2026-08-19 사용자 신고). 남은 높이는 화면이 flex로 채우고, 스크롤은 안쪽 칸에서만. */
.page-body.lms-studio-host { overflow: hidden; display: flex; flex-direction: column; padding-bottom: 14px; }
.page-body.lms-studio-host > * { flex-shrink: 0; }
.page-body.lms-studio-host > .lms-studio-wrap { flex: 1; min-height: 0; }
.lms-studio-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.lms-studio {
  /* 우측이 [선택 요소 폼 + Claude 채팅] 두 칸이라 M4c(316px)보다 조금 넓다. */
  display: grid; grid-template-columns: 248px minmax(0, 1fr) 344px; gap: 12px;
  /* 높이는 부모(.lms-studio-wrap)가 준 만큼 — 창 높이에서 상수를 빼던 계산은
     실제 헤더 높이와 어긋나 바깥 스크롤을 만들었다. */
  flex: 1; min-height: 0;
}
.lms-studio-pane {
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  min-height: 0; display: flex; flex-direction: column; overflow: hidden;
}
/* 중앙은 산출물이 곧 배경 — 프레임 여백 없이 꽉 채운다. */
.lms-studio-pane.center { background: #0a0a1a; }
.lms-studio-frame { flex: 1; width: 100%; border: 0; min-height: 0; }
.lms-studio-pane-head {
  padding: 10px 13px; font-size: 11px; font-weight: 650; color: var(--ink-4);
  letter-spacing: .06em; border-bottom: 1px solid var(--line); flex-shrink: 0;
}

/* 좌측 트리 — 차시 › 페이지 › 문항 */
.lms-tree { flex: 1; overflow-y: auto; padding: 7px; }
.lms-tree-row {
  display: flex; align-items: center; gap: 7px; width: 100%;
  padding: 6px 8px; border: 0; border-radius: 8px; background: transparent;
  font-family: inherit; font-size: 12.5px; color: var(--ink-2); text-align: left;
  cursor: pointer; transition: background var(--t), color var(--t);
}
.lms-tree-row:hover { background: var(--surface-2); }
.lms-tree-row.on { background: color-mix(in oklch, var(--accent) 10%, transparent); color: var(--ink); }
.lms-tree-row .t { min-width: 0; flex: 1; }
.lms-tree-row .num {
  font-size: 10.5px; font-weight: 700; color: var(--ink-4);
  font-variant-numeric: tabular-nums; flex-shrink: 0;
}
.lms-tree-row .cnt { font-size: 10px; color: var(--ink-5); flex-shrink: 0; }
.lms-tree-row.lesson { font-weight: 650; }
/* 수식 클래스 이름은 .page가 아니라 .pg다 — 전역 .page(레이아웃 프리미티브,
   display:flex; flex-direction:column)와 겹치면 줄이 세로로 쌓인다. */
.lms-tree-row.pg { padding-left: 27px; }
.lms-tree-row.q { padding-left: 40px; font-size: 12px; color: var(--ink-3); }
.lms-tree-badge {
  flex-shrink: 0; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  display: grid; place-items: center; font-size: 9.5px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.lms-tree-badge.err { background: color-mix(in oklch, var(--danger) 14%, transparent); color: var(--danger); }
.lms-tree-badge.warn { background: color-mix(in oklch, var(--accent) 14%, transparent); color: var(--accent); }
/* 자료 큐에 줄 서 있는 차시(2026-08-22) — 도는 차시는 회전자가 말하고, 아직 차례가 안
   온 차시는 이 배지가 말한다. 큐가 도는 중에도 다른 차시를 골라 등록할 수 있게 되면서
   (BUG-0008) "이 줄은 왜 체크가 잠겼나"를 줄에서 바로 읽혀야 한다. 검증 배지(오류·확인)와
   달리 사정이지 잘못이 아니라 잿빛이다. */
.lms-tree-badge.wait { padding: 0 5px; background: var(--surface-3); color: var(--ink-4); font-weight: 650; }

/* 우측 편집 패널 */
.lms-inspector { flex: 1; overflow-y: auto; padding: 13px; display: flex; flex-direction: column; gap: 12px; }
.lms-inspector-kicker { display: flex; flex-direction: column; gap: 2px; }
.lms-inspector-kicker .mono { font-size: 10px; color: var(--ink-5); letter-spacing: .05em; }
.lms-inspector-kicker b { font-size: 13.5px; font-weight: 650; letter-spacing: -.014em; }
.lms-field-label {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  font-size: 11px; color: var(--ink-4); font-weight: 600; margin-bottom: 5px;
}
.lms-answer-pick {
  width: 34px; height: 30px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface); color: var(--ink-3); font-family: inherit;
  font-size: 12.5px; font-weight: 650; cursor: pointer;
  transition: background var(--t), color var(--t), border-color var(--t);
}
.lms-answer-pick:hover:not(:disabled) { border-color: var(--line-strong); background: var(--surface-2); }
.lms-answer-pick.on { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.lms-answer-pick:disabled { opacity: .55; cursor: default; }

/* ── 우측 패널 아래 칸: Claude 편집 채팅 (M4d, 그릴링 Q5′) ──
   위(선택 요소 폼)와 같은 대상을 보므로 "무엇을 고치는지"가 늘 보인다. 손잡이를
   끌어 높이를 바꾸고, 인스펙터가 남은 높이를 먹는다(flex). */
.lms-chat-grip {
  flex-shrink: 0; height: 9px; cursor: ns-resize; position: relative;
  border-top: 1px solid var(--line);
}
.lms-chat-grip::after {
  content: ''; position: absolute; left: 50%; top: 3px; width: 34px; height: 3px;
  transform: translateX(-50%); border-radius: 2px; background: var(--line-strong);
  transition: background var(--t);
}
.lms-chat-grip:hover::after { background: var(--accent); }

.lms-chat { flex-shrink: 0; display: flex; flex-direction: column; min-height: 0; }
.lms-chat-head {
  display: flex; align-items: center; gap: 7px; padding: 8px 8px 6px 12px; flex-shrink: 0;
  font-size: 11.5px; font-weight: 650; color: var(--ink-3);
}
.lms-chat-head .t { min-width: 0; flex: 1; color: var(--ink-2); }
.lms-chat-ai { padding: 0 10px 8px; flex-shrink: 0; }

.lms-chat-log {
  flex: 1; min-height: 0; overflow-y: auto; padding: 4px 10px 10px;
  display: flex; flex-direction: column; gap: 8px;
}
.lms-chat-empty { font-size: 11.5px; line-height: 1.65; color: var(--ink-5); padding: 8px 2px; }
.lms-chat-empty b { color: var(--ink-3); }

.lms-chat-msg { display: flex; flex-direction: column; gap: 4px; max-width: 100%; }
.lms-chat-msg .b {
  border-radius: 11px; padding: 8px 11px; font-size: 12px; line-height: 1.6;
  white-space: pre-wrap; word-break: break-word;
}
.lms-chat-msg.user { align-items: flex-end; }
.lms-chat-msg.user .b {
  background: color-mix(in oklch, var(--accent) 13%, transparent); color: var(--ink);
  border-bottom-right-radius: 4px; max-width: 92%;
}
.lms-chat-msg.claude .b {
  background: var(--surface-2); color: var(--ink-2); border-bottom-left-radius: 4px;
}
.lms-chat-msg.claude.err .b {
  background: color-mix(in oklch, var(--danger) 9%, transparent); color: var(--danger);
}
.lms-chat-msg.system .b {
  background: transparent; color: var(--ink-5); font-size: 11px; padding: 2px 2px; text-align: center;
}
.lms-chat-msg .applied {
  display: flex; align-items: center; gap: 4px; font-size: 10.5px; font-weight: 650;
  color: var(--ok); padding-left: 3px;
}
.lms-chat-msg .note { font-size: 10.5px; line-height: 1.5; color: var(--accent); padding-left: 3px; }

/* 진행 표시 — 답이 오기 전까지 점 세 개가 번갈아 밝아진다 */
.lms-chat-msg .b.pending { display: flex; align-items: center; gap: 8px; color: var(--ink-4); }
.lms-chat-dots { display: inline-flex; gap: 3px; }
.lms-chat-dots i {
  width: 4px; height: 4px; border-radius: 50%; background: var(--ink-4);
  animation: lmsChatDot 1.1s ease-in-out infinite;
}
.lms-chat-dots i:nth-child(2) { animation-delay: .15s; }
.lms-chat-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes lmsChatDot { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }

.lms-chat-undo {
  display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin: 0 10px 8px;
  padding: 6px 8px 6px 11px; border-radius: 9px; font-size: 11px; color: var(--ink-4);
  background: var(--surface-2); border: 1px solid var(--line);
}
.lms-chat-undo > span { min-width: 0; flex: 1; }
.lms-chat-undo .btn { padding: 4px 9px; font-size: 11px; flex-shrink: 0; }

.lms-chat-input {
  display: flex; align-items: flex-end; gap: 7px; flex-shrink: 0;
  padding: 9px 10px 10px; border-top: 1px solid var(--line);
}
.lms-chat-input textarea {
  flex: 1; min-width: 0; resize: none; font-size: 12px; line-height: 1.55; padding: 8px 10px;
}
.lms-chat-send { flex-shrink: 0; height: 34px; padding: 0 12px; }

/* 헤더의 검증 요약 칩 + 결과 팝오버 */
.lms-studio-issues {
  border: 1px solid var(--line); border-radius: 999px; padding: 5px 11px;
  background: var(--surface); font-family: inherit; font-size: 11.5px; font-weight: 650;
  cursor: pointer; transition: border-color var(--t), background var(--t);
}
.lms-studio-issues:hover { border-color: var(--line-strong); }
.lms-studio-issues.err { color: var(--danger); border-color: color-mix(in oklch, var(--danger) 35%, var(--line)); }
.lms-studio-issues.warn { color: var(--accent); border-color: color-mix(in oklch, var(--accent) 35%, var(--line)); }
.lms-studio-issues.ok { color: var(--ok); }
.lms-studio-issue-pop {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60; width: 360px;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: 12px;
  box-shadow: var(--shadow-lg); overflow: hidden;
}
.lms-studio-issue-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 8px 8px 14px; font-size: 12px; font-weight: 650;
  border-bottom: 1px solid var(--line);
}
.lms-studio-issue-list { max-height: 320px; overflow-y: auto; padding: 6px; }
.lms-studio-issue {
  display: flex; align-items: flex-start; gap: 8px; width: 100%;
  padding: 7px 9px; border: 0; border-radius: 8px; background: transparent;
  font-family: inherit; font-size: 11.5px; line-height: 1.5; color: var(--ink-2);
  text-align: left; cursor: pointer; transition: background var(--t);
}
.lms-studio-issue:hover { background: var(--surface-2); }
.lms-studio-issue .loc { color: var(--ink-5); font-weight: 650; margin-right: 6px; }
.lms-studio-issue .dot { flex-shrink: 0; width: 7px; height: 7px; border-radius: 50%; margin-top: 4px; }
.lms-studio-issue .dot.error { background: var(--danger); }
.lms-studio-issue .dot.warn { background: var(--accent); }

/* ── 차시 섹션(아코디언, "차시 = 영상 여러 편") — 헤더 줄 + 펼치면 영상 줄들 ──
   .lms-lrow(옛 평평한 차시 줄)의 시각 언어를 두 겹으로 나눴다: 섹션은 바깥 카드,
   영상 줄은 그 안의 작은 카드다. 선택은 영상 줄에 걸리고, 그 차시 영상이 전부
   골라지면 섹션 헤더도 같이 물든다. */
.lms-lsecs {
  display: flex; flex-direction: column; gap: 6px; padding: 6px; margin: -7px;
  border: 1px dashed transparent; border-radius: 14px;
  transition: border-color var(--t), background var(--t);
  /* 훑는 상자(.lms-marquee)의 기준면 — 목록 바깥(아래 빈 자리)까지 뻗을 수 있게
     overflow 는 건드리지 않는다. 목록과 함께 스크롤되므로 좌표 보정도 필요 없다. */
  position: relative;
}
.lms-lsecs.drop { border-color: var(--accent); background: color-mix(in oklch, var(--accent) 5%, transparent); }

/* 과정 상세 본문을 세로 flex로 세워 마지막 칸(차시 목록)에 남은 높이를 다 준다 —
   그래야 목록 끝의 꼬리(.lms-ltail)가 화면 바닥까지 닿아 "목록 아래 빈 자리에
   떨어뜨리면 새 차시"가 성립한다. 클래스는 목록이 붙어 있는 동안만 얹힌다
   (LmsLessonSections). 나머지 칸은 원래 높이 그대로 — flex 칸에서 내용이 눌리지
   않게 shrink를 끊는다(.lms-studio-host와 같은 규칙). */
.page-body.lms-lsecs-host { display: flex; flex-direction: column; }
.page-body.lms-lsecs-host > * { flex: 0 0 auto; }
.page-body.lms-lsecs-host > .lms-lsecs { flex: 1 0 auto; }

/* 목록 꼬리 — 남은 높이를 채우되 한 줄(46px)은 늘 보인다. 파일을 끌고 오면 목록
   둘레(.lms-lsecs.drop)와 함께 물들어 "여기 놓으면 된다"가 한눈에 보인다. */
.lms-ltail {
  flex: 1 1 auto; min-height: 46px;
  display: flex; align-items: center; justify-content: center;
  border: 1px dashed var(--line); border-radius: 10px;
  font-size: 11.5px; color: var(--ink-5); text-align: center; padding: 0 12px;
  transition: border-color var(--t), color var(--t), background var(--t);
}
.lms-lsecs.drop .lms-ltail {
  border-color: var(--accent); color: var(--accent);
  background: color-mix(in oklch, var(--accent) 6%, transparent);
}

/* 목록 머리의 가운데 칸 — 안내 문구와 선택 요약이 번갈아 선다. 둘 다 **한 줄로
   잘려야** 한다: 창이 좁아 문구가 두 줄이 되면 머리 줄이 자라고, 그만큼 목록이 아래로
   밀려 훑는 중이던 상자와 커서 밑 차시가 어긋난다(LmsLessonSections head 주석). */
.lms-lhint, .lms-lsel-count { min-width: 0; font-size: 12px; }
.lms-lhint { color: var(--ink-5); }
.lms-lhint .dim { opacity: .72; }
/* 선택 요약 — 지금 뭔가 골라져 있다는 걸 문구 자리에서 바로 알리는 자리다. */
.lms-lsel-count { color: var(--ink-3); font-size: 12.5px; }
.lms-lsel-count .num { color: var(--accent); font-weight: 700; }

.lms-lempty {
  padding: 52px 20px; text-align: center; color: var(--ink-4);
  border: 1px dashed var(--line-strong); border-radius: 12px;
  transition: border-color var(--t), background var(--t), color var(--t);
}
.lms-lempty.drop { color: var(--accent); border-color: var(--accent); background: color-mix(in oklch, var(--accent) 5%, transparent); }
.lms-lempty-acts { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 14px; }

.lms-lsec {
  background: var(--surface); border: 1px solid var(--line); border-radius: 11px; overflow: hidden;
  transition: background var(--t), border-color var(--t), opacity var(--t);
}
.lms-lsec:hover { border-color: var(--line-strong); }
.lms-lsec.sel { border-color: color-mix(in oklch, var(--accent) 40%, var(--line)); }
.lms-lsec.sel > .lms-lsec-head { background: color-mix(in oklch, var(--accent) 8%, var(--surface)); }
.lms-lsec.sel .lms-lno { background: color-mix(in oklch, var(--accent) 16%, var(--surface)); color: var(--accent); }
.lms-lsec.drop { border-color: var(--accent); background: color-mix(in oklch, var(--accent) 6%, var(--surface)); }
.lms-lsec.dragging { opacity: .45; }
/* 지금 위쪽 카드가 보고 있는 차시 — 왼쪽 강조선으로 카드와 줄을 잇는다. */
.lms-lsec.active { border-color: color-mix(in oklch, var(--accent) 45%, var(--line)); }
.lms-lsec.active > .lms-lsec-head { background: color-mix(in oklch, var(--accent) 7%, var(--surface)); box-shadow: inset 3px 0 0 var(--accent); }
.lms-lsec.active .lms-lno { background: var(--accent); color: var(--accent-ink); }

.lms-lsec-head {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  cursor: pointer; transition: background var(--t);
}
.lms-lsec-head:hover { background: var(--surface-2); }
.lms-lsec-head > .grip { color: var(--ink-5); cursor: grab; display: grid; place-items: center; flex-shrink: 0; }
.lms-lsec-title { flex: 1; min-width: 0; font-size: 12.5px; color: var(--ink-3); }
.lms-lsec-title .pick { color: var(--accent); font-weight: 600; }
.lms-lsec-caret { color: var(--ink-5); display: grid; place-items: center; flex-shrink: 0; }
.lms-lsec-acts { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }
.lms-lsec-acts > .icon-btn { width: 26px; height: 26px; }
.lms-lsec-body {
  border-top: 1px solid var(--line); background: var(--surface-2);
  padding: 6px; display: flex; flex-direction: column; gap: 4px;
}
.lms-lsec-none { padding: 10px 12px; font-size: 11.5px; color: var(--ink-5); }

/* 영상 줄 — 줄 전체를 눌러 고른다(옛 .lms-lrow의 뜻이 여기로 내려왔다). */
.lms-vrow {
  display: grid; grid-template-columns: 18px 46px minmax(0, 1fr) auto auto;
  align-items: center; gap: 10px; padding: 8px 10px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 9px;
  cursor: pointer;
  transition: background var(--t), border-color var(--t), opacity var(--t);
}
.lms-vrow:hover { border-color: var(--line-strong); }
.lms-vrow.sel { background: color-mix(in oklch, var(--accent) 8%, var(--surface));
  border-color: color-mix(in oklch, var(--accent) 40%, var(--line)); }
.lms-vrow.sel:hover { background: color-mix(in oklch, var(--accent) 13%, var(--surface));
  border-color: color-mix(in oklch, var(--accent) 55%, var(--line)); }
.lms-vrow.sel .lms-vno { background: color-mix(in oklch, var(--accent) 16%, var(--surface)); color: var(--accent); }
.lms-vrow.dragging { opacity: .45; }
.lms-vrow > .grip { color: var(--ink-5); cursor: grab; display: grid; place-items: center; }
/* 줄 오른쪽 버튼 묶음 — 평소엔 휴지통 하나, '대기' 칩이 붙은 줄에만 그 앞에 취소가 선다. */
.lms-vacts { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
.lms-vacts > .icon-btn { width: 26px; height: 26px; }
/* 이번 차례에서만 빼는 취소 — 지우는 일(휴지통)과 헷갈리면 안 되니 한 겹 작게, 칩처럼
   테두리를 둘러 "옆 칩에 딸린 것"으로 읽히게 둔다. 색도 대기 칩과 같은 무채색에서 출발. */
.lms-vacts > .lms-vcancel {
  width: 22px; height: 22px;
  background: var(--surface-2); border-color: var(--line); color: var(--ink-4);
}
.lms-vacts > .lms-vcancel:hover { background: var(--surface-3); border-color: var(--line-strong); color: var(--ink); }
/* 지금 도는 영상을 멈추는 X — 대기 X와 같은 자리·같은 몸짓이지만 뜻이 한 단계
   무겁다: 받아쓰던 중간 결과가 버려지고 그 영상은 '중단됨'으로 남는다. 그래서
   ① 색을 위험색으로 올리고 ② 히트 영역을 22px → 18px로 좁혀 칩에 바싹 붙인다.
   확인 모달은 두지 않는다 — 잘못 눌러도 다시 골라 등록하면 그만이라 모달값이 비싸다. */
.lms-vacts > .lms-vcancel.live {
  width: 18px; height: 18px; margin-left: 2px;
  background: color-mix(in oklch, var(--danger) 8%, var(--surface));
  border-color: color-mix(in oklch, var(--danger) 30%, var(--line));
  color: var(--danger);
}
.lms-vacts > .lms-vcancel.live:hover {
  background: color-mix(in oklch, var(--danger) 16%, var(--surface));
  border-color: var(--danger); color: var(--danger);
}
/* 되돌릴 수 없는 건 이쪽뿐이라 위험색은 휴지통만 쓴다. */
.lms-vacts > .lms-vdel:hover { background: color-mix(in oklch, var(--danger) 10%, transparent); color: var(--danger); }
/* 차시 헤더의 자료(HTML) 큐 취소 X — 위 영상 줄 X와 같은 몸짓·같은 규격이다(2026-08-22
   자료 큐). 축만 다르다: 영상 줄은 받아쓰기 대기열, 여기는 HTML 생성 대기열이고 자료
   상태 칩(.lms-chip.sub) 바로 옆에 붙는다. 두 갈래(무채색 = 대기에서 빼기, 위험색 =
   지금 만드는 중인 차시 중단)도 그대로다 — 몸짓이 같으면 뜻도 같아 보여야 한다. */
.lms-lsec-head > .lms-mcancel {
  width: 22px; height: 22px; flex-shrink: 0; margin-left: -2px;
  background: var(--surface-2); border-color: var(--line); color: var(--ink-4);
}
.lms-lsec-head > .lms-mcancel:hover { background: var(--surface-3); border-color: var(--line-strong); color: var(--ink); }
.lms-lsec-head > .lms-mcancel.live {
  width: 18px; height: 18px;
  background: color-mix(in oklch, var(--danger) 8%, var(--surface));
  border-color: color-mix(in oklch, var(--danger) 30%, var(--line));
  color: var(--danger);
}
.lms-lsec-head > .lms-mcancel.live:hover {
  background: color-mix(in oklch, var(--danger) 16%, var(--surface));
  border-color: var(--danger); color: var(--danger);
}
.lms-vno {
  width: 46px; height: 24px; border-radius: 6px;
  background: var(--surface-2); color: var(--ink-3);
  display: grid; place-items: center;
  font-size: 11px; font-weight: 700; font-variant-numeric: tabular-nums;
  transition: background var(--t), color var(--t);
}
/* 파일명 + 배지 한 줄 — 배지는 안 줄고 이름만 줄어든다(긴 파일명이 배지를 밀지 않게). */
.lms-vname { display: flex; align-items: center; gap: 6px; min-width: 0; }
.lms-vname > .pill { flex-shrink: 0; }

/* 드롭으로 끼워 넣을 자리 — 줄 사이에 뜨는 삽입선(차시 이동도 같은 선으로 보인다). */
.lms-vdrop { height: 2px; border-radius: 2px; background: var(--accent); margin: -3px 4px; }

/* 상태 칩 — 색은 라이브 값이라 인라인으로 얹고, 나머지 규격은 여기서. */
.lms-chip { max-width: 240px; font-size: 11px; font-weight: 600; padding: 3px 8px; border-radius: 6px; flex-shrink: 0; }

/* 보조 칩 — 차시 헤더에서 스크립트 집계 칩 옆에 붙는 자료 상태(작게). */
.lms-chip.sub { max-width: 190px; font-size: 10.5px; padding: 2px 7px; }

/* ── 차시 배정 모달 (lms-asg) — 과정 단위로 떨어뜨린 영상을 나눠 담는다 (2026-08-19) ──
   차시 목록(.lms-lsec)의 축소판이다: 번호 배지 + 제목 줄이 헤더고, 그 아래 영상
   줄이 쌓인다. 조작이 손짓뿐이라 "받을 자리"가 눈에 보여야 한다 — 놓을 자리는
   삽입선(.lms-asg-line), 대상 바구니는 강조색, 훑는 범위는 상자(.lms-marquee). */
.modal.lms-asg {
  width: min(680px, calc(100vw - 48px)); max-width: none;
  display: flex; flex-direction: column; max-height: calc(100vh - 64px);
}
/* position:relative 는 훑는 상자의 기준면 — 목록과 같이 스크롤돼야 자리가 안 어긋난다. */
.lms-asg .modal-body { flex: 1; min-height: 0; overflow-y: auto; position: relative; }
.lms-asg-list { display: flex; flex-direction: column; gap: 8px; }
.lms-asg-sum { margin-right: auto; font-size: 11.5px; color: var(--ink-4); }

/* 여러 장 골랐을 때만 뜨는 띠 — 고른 것을 한 번에 어느 차시로 보낸다. */
.lms-asg-selbar {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 8px 10px; margin-bottom: 8px;
  border: 1px solid color-mix(in oklch, var(--accent) 40%, var(--line));
  border-radius: 10px; background: color-mix(in oklch, var(--accent) 8%, var(--surface));
}
.lms-asg-selbar b { font-size: 11.5px; font-weight: 650; color: var(--accent); }
.lms-asg-selbar span { font-size: 11px; color: var(--ink-4); }
.lms-asg-selbar button {
  padding: 3px 9px; border-radius: 6px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-3);
  font-family: inherit; font-size: 11px; font-weight: 650; transition: all var(--t);
}
.lms-asg-selbar button:hover { border-color: var(--accent); color: var(--accent); }
.lms-asg-selbar button.ghost { margin-left: auto; border-color: transparent; background: transparent; color: var(--ink-5); }

.lms-asg-sec {
  border: 1px solid var(--line); border-radius: 11px; background: var(--surface);
  overflow: hidden; transition: border-color var(--t), background var(--t);
}
.lms-asg-sec.drop { border-color: var(--accent); background: color-mix(in oklch, var(--accent) 6%, var(--surface)); }

.lms-asg-head { display: flex; align-items: center; gap: 8px; padding: 8px 10px; }
.lms-asg-no {
  flex-shrink: 0; min-width: 26px; height: 22px; display: grid; place-items: center;
  border-radius: 6px; background: var(--surface-2); color: var(--ink-3);
  font-size: 11px; font-weight: 650; font-variant-numeric: tabular-nums;
}
.lms-asg-sec.drop .lms-asg-no { background: var(--accent); color: var(--accent-ink); }
.lms-asg-title { flex-shrink: 0; font-size: 12.5px; font-weight: 650; }
.lms-asg-note { flex: 1; min-width: 0; font-size: 11px; color: var(--ink-5); }
.lms-asg-count {
  flex-shrink: 0; padding: 2px 7px; border-radius: 6px;
  background: color-mix(in oklch, var(--accent) 12%, transparent); color: var(--accent);
  font-size: 10.5px; font-weight: 650;
}
.lms-asg-head > .icon-btn { width: 24px; height: 24px; }

.lms-asg-drop {
  display: flex; flex-direction: column; gap: 4px;
  padding: 6px 8px 8px; min-height: 44px;
}
.lms-asg-kept { padding: 2px 4px; font-size: 10.5px; color: var(--ink-5); }
.lms-asg-none {
  display: grid; place-items: center; padding: 10px;
  border: 1px dashed var(--line-strong); border-radius: 8px;
  font-size: 11.5px; color: var(--ink-5);
}
.lms-asg-sec.drop .lms-asg-none { border-color: var(--accent); color: var(--accent); }

/* 영상 한 줄 — 손잡이 · 파일명 · 휴지통. 누르면 골라지고, 끌면 옮겨진다. */
.lms-asg-row {
  display: flex; align-items: center; gap: 8px; padding: 7px 9px;
  border: 1px solid var(--line); border-radius: 8px; background: var(--surface);
  cursor: grab; font-size: 12px;
  transition: border-color var(--t), background var(--t), opacity var(--t);
}
.lms-asg-row:hover { border-color: var(--line-strong); }
.lms-asg-row.dragging { opacity: .45; }
.lms-asg-row.sel {
  border-color: color-mix(in oklch, var(--accent) 45%, var(--line));
  background: color-mix(in oklch, var(--accent) 7%, var(--surface));
}
.lms-asg-row > .grip { flex-shrink: 0; color: var(--ink-5); display: grid; place-items: center; }
.lms-asg-row > .name { flex: 1; min-width: 0; }
/* 휴지통은 줄 위에 올렸을 때만 — 줄마다 늘 떠 있으면 목록이 시끄럽다. */
.lms-asg-row > .del {
  flex-shrink: 0; width: 24px; height: 24px; display: grid; place-items: center;
  border: 0; border-radius: 6px; background: transparent; color: var(--ink-5);
  opacity: 0; transition: all var(--t);
}
.lms-asg-row:hover > .del, .lms-asg-row > .del:focus-visible { opacity: 1; }
.lms-asg-row > .del:hover { color: var(--danger); background: color-mix(in oklch, var(--danger) 10%, transparent); }

.lms-asg-line { height: 2px; border-radius: 2px; background: var(--accent); margin: -3px 2px; }

.lms-asg-add {
  display: flex; align-items: center; justify-content: center; gap: 5px;
  padding: 8px; border: 1px dashed var(--line-strong); border-radius: 10px;
  background: transparent; color: var(--ink-4);
  font: inherit; font-size: 11.5px; font-weight: 600; cursor: pointer;
  transition: border-color var(--t), color var(--t);
}
.lms-asg-add:hover { border-color: var(--accent); color: var(--accent); }

/* 빈 곳을 끌어 훑는 선택 상자 — 파일 탐색기와 같은 몸짓. 배정 모달과 과정 상세의
   차시 목록이 같은 상자를 쓴다(둘 다 "빈 곳을 끌어 여러 개 고르기"라 생김새가 같아야 한다). */
.lms-marquee {
  position: absolute; z-index: 3; pointer-events: none;
  border: 1px solid var(--accent); border-radius: 3px;
  background: color-mix(in oklch, var(--accent) 12%, transparent);
}
/* 훑는 동안 글자가 딸려 잡히지 않게. */
body.lms-marquee-on, body.lms-marquee-on * { user-select: none; -webkit-user-select: none; }

/* 인스펙터 하단 — 수동 3종만 뺄 수 있다(규격 필수 페이지엔 이 버튼이 없다). */
.lms-page-del {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 12px; background: var(--surface);
  border: 1px solid color-mix(in oklch, var(--danger) 30%, var(--line)); border-radius: 9px;
  color: var(--danger); font-family: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer; transition: all var(--t);
}
.lms-page-del:hover:not(:disabled) { background: color-mix(in oklch, var(--danger) 8%, var(--surface)); }
.lms-page-del:disabled { opacity: .45; cursor: default; }

/* ── 검수 화면: 과정 정보(로고·과정명·강사명) ──
   트리 맨 위 한 줄 — 차시가 아니라 과정 전체에 걸리는 값이라 목록과 선으로 가른다. */
.lms-tree-row.info { font-weight: 650; }
.lms-tree-row.info > svg { color: var(--ink-4); }
.lms-tree-row.info.on > svg { color: inherit; }
/* 다음 형제 = 첫 차시 블록. 선은 그 위에 그어야 선택 하이라이트(둥근 배경)를 안 자른다. */
.lms-tree-row.info + * { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--line); }

/* 로고 미리보기 — 실제 상단 바가 어두운 배경(#0a0a1a)이라 같은 톤 위에 얹어야
   흰 글자 로고가 보인다. 중앙 iframe 배경과 같은 값이다. */
.lms-logo-box {
  display: grid; place-items: center; height: 64px; padding: 8px;
  background: #0a0a1a; border: 1px solid var(--line); border-radius: 9px; overflow: hidden;
}
.lms-logo-box img { max-height: 100%; max-width: 100%; object-fit: contain; }
.lms-logo-box .empty { font-size: 11px; color: #8a8aa8; }

/* ── 검수 화면: 자막 크기 배율(로고 바로 아래) ──
   슬라이더는 응답 강도 줄(.lms-slider/.lms-range)을 그대로 쓰고, 여기서는 위에 붙는
   숫자 칸과 아래 크기 미리보기만 더한다. */
.lms-cue-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.lms-cue-head > .t {
  display: flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; color: var(--ink-4);
}
.lms-cue-num { display: flex; align-items: center; gap: 4px; font-size: 10.5px; color: var(--ink-5); }
.lms-cue-num > input {
  width: 54px; padding: 4px 7px; border: 1px solid var(--line); border-radius: 7px;
  background: var(--surface); color: var(--ink); font: inherit; font-size: 12px; font-weight: 650;
  text-align: right; font-variant-numeric: tabular-nums;
}
.lms-cue-num > input:focus-visible {
  outline: none; border-color: var(--line-strong); box-shadow: 0 0 0 3px var(--accent-soft);
}
.lms-cue-num > input:disabled { opacity: .55; }
.lms-cue-reset {
  border: 0; background: none; padding: 0 2px; font: inherit; font-size: 10.5px;
  color: var(--ink-5); cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.lms-cue-reset:hover:not(:disabled) { color: var(--ink-2); }
.lms-cue-reset:disabled { opacity: .5; cursor: default; }
/* 팝오버용 여백(0 6px 8px)은 폼 안에선 과하다. */
.lms-cue-slider { padding: 1px 2px 3px; }
.lms-cue-slider .lms-range > input:disabled { cursor: default; }

/* 크기 미리보기 — 실제 산출물과 같은 비율로 그린 16:9 영상 틀. 자막 크기는 영상
   높이에 비례하므로(material.ts subtitleCuePx) 틀 너비만 알면 비율이 그대로
   재현된다: 폰트를 컨테이너 질의 단위(cqw)로 매겨 패널 폭이 달라져도 같은 비율이다.
   글자가 3~10px로 작게 나오는 건 축소한 만큼의 사실이다 — 절대 크기는 아래 px 판독이 맡는다. */
.lms-cue-stage {
  container-type: inline-size;
  position: relative; aspect-ratio: 16 / 9; margin-top: 7px;
  border: 1px solid var(--line); border-radius: 9px; overflow: hidden;
  background: radial-gradient(115% 85% at 50% 12%, #1c2340 0%, #0a0a1a 68%);
}
/* 아주 옅은 재생 표시 — 이 검은 칸이 "영상 틀"이라는 걸 한눈에 알린다.
   자막이 서는 아랫줄을 비켜 살짝 위(46%)에 둔다. */
.lms-cue-stage::after {
  content: ''; position: absolute; left: 50%; top: 46%; transform: translate(-50%, -50%);
  border-style: solid; border-width: 9px 0 9px 15px;
  border-color: transparent transparent transparent rgba(255, 255, 255, .09);
}
.lms-cue-stage > .tag {
  position: absolute; top: 6px; left: 7px; padding: 2px 6px; border-radius: 999px;
  background: rgba(255, 255, 255, .07); color: rgba(255, 255, 255, .5);
  font-size: 9px; letter-spacing: .04em;
}
/* 브라우저가 그리는 ::cue와 같은 모양 — 흰 글자 + 검은 반투명 상자, 영상 맨 아랫줄. */
.lms-cue-stage > .cue {
  position: absolute; left: 50%; bottom: 4.5%; transform: translateX(-50%);
  max-width: 92%; padding: .16em .5em; border-radius: .2em;
  background: rgba(0, 0, 0, .78); color: #fff;
  font-size: calc(var(--cue, 1.15) * 1cqw); line-height: 1.35; text-align: center;
}
.lms-cue-read {
  display: flex; justify-content: space-between; gap: 8px; margin-top: 6px;
  font-size: 10.5px; color: var(--ink-5);
}
.lms-cue-read b { color: var(--ink-3); font-weight: 650; font-variant-numeric: tabular-nums; }

/* ══ 검수 화면 = 생성 화면 (2026-08-19) ══
   왼쪽 트리 줄 앞의 체크 = "이번에 만들 차시·페이지", 트리 아래 = 생성 패널.
   줄 자체가 <button>이라 체크는 안에 못 넣고 .lms-tree-line으로 나란히 세운다.
   (칸 머리의 힌트 글귀는 2026-08-21에 칸 발치 [골라서 생성] 토글로 바뀌었다 — 아래 선택 모드 절.) */
.lms-tree-line { display: flex; align-items: center; gap: 2px; }
.lms-tree-line > .lms-tree-row { flex: 1; min-width: 0; }
/* 체크가 붙으면 그 칸이 들여쓰기를 대신한다 — 27px 규칙과 눈높이를 맞춘다. */
.lms-tree-line > .lms-gen-check + .lms-tree-row.pg { padding-left: 5px; }
.lms-gen-check {
  flex-shrink: 0; width: 15px; height: 15px; margin-left: 11px; padding: 0;
  display: grid; place-items: center; cursor: pointer;
  border: 1.5px solid var(--line-strong); border-radius: 5px;
  background: var(--surface); color: #fff; transition: all var(--t);
}
.lms-gen-check:hover { border-color: var(--accent); }
.lms-gen-check.on { background: var(--accent); border-color: var(--accent); }
/* 아직 없는 페이지 — 자리만 잡아 두는 줄이라 누를 곳이 없다(체크로만 다룬다). */
.lms-tree-row.ghost { color: var(--ink-5); cursor: default; }
.lms-tree-row.ghost:hover { background: transparent; }

/* 문항이 든 페이지(사전진단·복습·퀴즈) 줄 오른쪽의 펼침 손잡이 — 줄 자체가
   <button>이라 안에 못 넣고 옆에 세운다. */
.lms-tree-caret {
  flex-shrink: 0; width: 20px; height: 20px; margin-right: 2px; padding: 0;
  display: grid; place-items: center; border: 0; border-radius: 6px;
  background: transparent; color: var(--ink-5); cursor: pointer;
  transition: background var(--t), color var(--t), transform .12s;
  transform: rotate(-90deg);
}
.lms-tree-caret:hover { background: var(--surface-2); color: var(--ink-3); }
.lms-tree-caret.on { transform: none; color: var(--ink-3); }

.lms-gen-panel {
  flex-shrink: 0; display: flex; flex-direction: column; gap: 8px;
  padding: 10px; border-top: 1px solid var(--line); background: var(--surface);
}
.lms-gen-head { display: flex; align-items: center; gap: 6px; font-size: 11.5px; }
.lms-gen-head .num {
  font-size: 11px; font-weight: 700; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.lms-gen-head .t {
  flex: 1; min-width: 0; color: var(--ink-4);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lms-gen-all {
  flex-shrink: 0; padding: 2px 4px; border: 0; background: transparent;
  font-family: inherit; font-size: 10.5px; font-weight: 600; color: var(--accent); cursor: pointer;
}
.lms-gen-all:disabled { color: var(--ink-5); cursor: default; }
.lms-gen-fields { display: flex; flex-wrap: wrap; gap: 6px 10px; }
.lms-gen-field { display: flex; align-items: center; gap: 5px; font-size: 10.5px; color: var(--ink-4); }
.lms-gen-field input, .lms-gen-field select {
  width: 54px; padding: 4px 6px; border: 1px solid var(--line); border-radius: 7px;
  background: var(--surface-2); color: var(--ink); font-family: inherit; font-size: 11.5px;
}
.lms-gen-field input { font-variant-numeric: tabular-nums; }
.lms-gen-run { width: 100%; justify-content: center; }
.lms-gen-note { font-size: 10.5px; color: var(--ink-5); line-height: 1.6; }
/* 생성이 통째로 잠긴 사유(gen.blocked — 로그인·엔진·모델) — 잿빛 노트로는 지나치기
   쉬워서(2026-08-21 사용자 보고: 왜 잠겼는지 못 찾음) 빨간 글로 세운다. */
.lms-gen-note.danger { color: var(--danger); font-weight: 550; }

/* 중앙 — 아직 만들지 않은 차시를 골랐을 때(빈 iframe 대신 무엇을 하면 되는지) */
.lms-studio-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 40px 28px; text-align: center; color: #8a8aa8;
}
.lms-studio-empty > svg { color: #6b6b8a; }
.lms-studio-empty b { font-size: 13.5px; color: #e8e8f5; }
.lms-studio-empty p { font-size: 12px; line-height: 1.75; max-width: 340px; }
.lms-studio-empty p b { font-size: inherit; }

/* ══ 과정 도우미 — 하단 명령 바 (시안 안 C, 2026-08-20) ══════════════════════
   과정 폴더 하나를 통째로 아는 Claude. 검수 화면처럼 화면을 빼앗지 않고 과정 상세
   아래에 유리 바 한 줄로 떠 있다가, 누르면 3열 유리판(폴더 트리 · 대화 · 검토)이
   바에서 슈웅 올라온다 — 뒤의 과정 상세는 덮이지 않고 유리 너머로 비친다.
   판 뼈대는 늘 붙어 있고 열림만 .open으로 토글한다: 지웠다 그리면 여는 애니메이션이
   끊긴다. 말풍선·점 세 개(.lms-chat-msg/.lms-chat-dots)와 팝오버(.lms-pop)·고르는
   줄(.lms-opt)·강도 슬라이더(.lms-slider)는 이미 있는 것을 그대로 쓴다 —
   여기 있는 건 바·판과 도우미에만 있는 조각(트리·근거 칩·검토 카드)뿐이다. */

/* 바가 사는 자리 — 본문(.page-body.scrolly)이 스크롤되는 칸이라 그 안에 두면 같이
   흘러가고 판이 잘린다. body 포털 + fixed로 띄우고 좌우·아래는 본문 칸을 실측해
   맞춘다(.lms-pop과 같은 방식). z-index는 모달(.modal-bg = 100)보다 아래다. */
/* 층 자체는 클릭을 통과시킨다 — 바 옆 빈자리가 뒤에 있는 과정 상세를 삼키지 않게. */
.lms-cbar { position: fixed; z-index: 40; pointer-events: none; }
.lms-cbar > * { pointer-events: auto; }
/* 마지막 카드가 바에 가리지 않게 — 검수 화면의 host 규칙(.lms-studio-host)과 같은 손짓. */
.page-body.lms-assist-host { padding-bottom: 92px; }

/* ── 3열 유리판 ─────────────────────────────────────────────────────────
   맥의 팝오버·스포트라이트를 따른다: 판은 바에서 태어나고(transform-origin이 아래
   가운데) 살짝 튀는 곡선(오버슈트 1.32)이 "슈웅"의 정체다. 칸 셋은 가운데부터
   차례로 서서 한 덩어리가 아니라 펼쳐지는 것처럼 보인다. 크기는 본문 칸(.page-body)을
   꽉 채운다 — 폭은 층(.lms-cbar)이 이미 본문을 실측해 앉아 있으니 100%면 되고, 높이만
   실측값에서 바가 먹는 만큼 빼 인라인으로 준다(창 높이 계산은 탭 줄 높이와 어긋난다). */
.lms-cpanel {
  /* 양옆 칸 폭은 변수로 둔다 — 왼쪽은 파일 뷰어(.lms-fview)가 그 오른쪽에 겹쳐 서느라
     같은 수를 봐야 하고(두 곳에 따로 적어 두면 폭을 고칠 때 어긋난다), 오른쪽은 여기
     한 줄만 본다. 판이 본문 칸을 통째로 쓰면서 넓은 화면에서는 남는 폭이 전부 가운데
     대화 칸으로 몰린다 — 좌우가 실오라기처럼 보이지 않게 같이 자라게 둔다. 자라기
     시작하는 자리는 판이 옛 상한(1180)을 넘어서는 창 폭 언저리라, 그보다 좁으면
     예전 수(214·300) 그대로다. 기준을 vw로 잡는 까닭: %로 두면 그리드는 판 안쪽
     (패딩 뺀 폭)을, 뷰어는 바깥을 재서 트리 칸과 뷰어 모서리가 몇 px 어긋난다. */
  --side-w: clamp(214px, 14vw, 320px);
  --work-w: clamp(300px, 19vw, 420px);
  position: absolute; left: 0; right: 0; bottom: calc(100% + 12px); margin: 0 auto;
  width: 100%;
  display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr) var(--work-w); gap: 10px; padding: 10px;
  border-radius: 24px;
  background: color-mix(in oklch, var(--surface) 50%, transparent);
  -webkit-backdrop-filter: blur(34px) saturate(1.9);
  backdrop-filter: blur(34px) saturate(1.9);
  border: 1px solid rgba(255, 255, 255, .72);
  box-shadow:
    0 2px 6px rgba(15, 15, 15, .05),
    0 36px 72px -20px rgba(15, 15, 15, .30),
    0 0 0 .5px rgba(15, 15, 15, .06),
    inset 0 1px 0 rgba(255, 255, 255, .6);
  transform-origin: 50% 100%;
  opacity: 0; visibility: hidden;
  transform: translateY(20px) scale(.945);
  transition: opacity .2s ease, visibility .2s, transform .18s cubic-bezier(.4, 0, 1, 1);
}
.lms-cbar.open .lms-cpanel {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity .18s ease, visibility 0s, transform .48s cubic-bezier(.16, 1.32, .28, 1);
}
.lms-ccol {
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
  border-radius: 16px;
  background: color-mix(in oklch, var(--surface) 86%, transparent);
  border: 1px solid color-mix(in oklch, var(--line) 70%, transparent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5);
  opacity: 0; transform: translateY(12px) scale(.985);
  transition: opacity .2s ease, transform .2s ease;
}
.lms-cbar.open .lms-ccol {
  opacity: 1; transform: none;
  transition: opacity .3s ease .04s, transform .5s cubic-bezier(.16, 1.2, .3, 1) .04s;
}
.lms-cbar.open .lms-ccol.side { transition-delay: .09s; }
/* 양옆(폴더·검토)은 한 톤 눌러 둔다 — 가운데 대화 칸이 종이처럼 도드라지게. */
.lms-ccol.side {
  background: color-mix(in oklch, var(--surface-3) 78%, transparent);
  border-color: color-mix(in oklch, var(--line-strong) 62%, transparent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35);
}
.lms-ccol.side .lms-ccol-head {
  background: color-mix(in oklch, var(--ink) 4%, transparent);
  border-bottom-color: color-mix(in oklch, var(--line-strong) 55%, transparent);
  color: var(--ink-2);
}
.lms-ccol-head {
  display: flex; align-items: center; gap: 7px; padding: 9px 11px; flex-shrink: 0;
  border-bottom: 1px solid color-mix(in oklch, var(--line) 60%, transparent);
  font-size: 11px; font-weight: 650; color: var(--ink-3); letter-spacing: .02em;
}
.lms-ccol-head .pill { margin-left: auto; }
.lms-ccol-head .grow { flex: 1; min-width: 0; }
.lms-ccol-head .nm { font-size: 12.5px; font-weight: 650; color: var(--ink); letter-spacing: -.015em; }
/* 판이 넓어지면 남는 폭은 죄다 가운데 칸으로 간다 — 말풍선까지 그대로 늘어나면 한 줄이
   백 글자를 넘어 눈이 다음 줄 첫머리를 잃는다. 칸은 꽉 찬 채로 두고 대화만 읽기 좋은
   폭에서 멈춰 가운데로 모은다. 그보다 좁을 때는 100%라 아무 일도 일어나지 않는다. */
.lms-cpanel .lms-chat-log > * { width: 100%; max-width: 900px; align-self: center; }
/* 유리 위에서는 흰 카드·말풍선이 뜨는 대신 살짝 비쳐야 한다. */
.lms-cpanel .lms-chat-msg.claude .b { background: color-mix(in oklch, var(--surface-2) 78%, transparent); }
.lms-cpanel .lms-asst-seed button { background: color-mix(in oklch, var(--surface) 66%, transparent); }
.lms-cpanel .lms-asst-src-chip { background: color-mix(in oklch, var(--surface) 62%, transparent); }
.lms-cpanel .lms-asst-card { background: color-mix(in oklch, var(--surface) 82%, transparent); }
.lms-cpanel .lms-asst-card-foot { background: color-mix(in oklch, var(--surface-2) 70%, transparent); }
/* 눌린 유리(양옆 칸) 위에서는 한 겹 더 밝게 띄워야 읽힌다. */
.lms-ccol.side .lms-asst-card { background: color-mix(in oklch, var(--surface) 92%, transparent); }
.lms-ccol.side .lms-asst-card-foot { background: color-mix(in oklch, var(--surface-2) 88%, transparent); }
.lms-ccol.side .lms-fxr:hover { background-color: color-mix(in oklch, var(--surface) 70%, transparent); }
.lms-ccol.side .lms-tree-note { border-top-color: color-mix(in oklch, var(--line-strong) 45%, transparent); }
.lms-ccol.side .lms-rstage { border-top-color: color-mix(in oklch, var(--line-strong) 45%, transparent); }

/* ── 바 한 줄 — 판이 열리면 900 → 본문 칸 폭으로 함께 넓어진다(판과 한 몸으로 보이게) ── */
.lms-cbar-shell {
  max-width: 900px; margin: 0 auto; border-radius: 16px;
  background: color-mix(in oklch, var(--surface) 74%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(1.7);
  backdrop-filter: blur(22px) saturate(1.7);
  border: 1px solid rgba(255, 255, 255, .7);
  box-shadow:
    0 1px 2px rgba(15, 15, 15, .05),
    0 20px 44px -16px rgba(15, 15, 15, .24),
    0 0 0 .5px rgba(15, 15, 15, .06),
    inset 0 1px 0 rgba(255, 255, 255, .55);
  /* border-color도 함께 — 파일을 끌고 오면 껍데기가 과녁이 된다(.lms-cbar-shell.drop).
     테두리만 툭 바뀌고 글로우는 스르르 들어오면 두 겹이 따로 노는 게 보인다. */
  transition: max-width .48s cubic-bezier(.16, 1.32, .28, 1), box-shadow var(--t), border-color var(--t);
}
.lms-cbar.open .lms-cbar-shell { max-width: 100%; }
.lms-cbar-line { display: flex; align-items: center; gap: 9px; padding: 9px 10px 9px 14px; }
.lms-cbar-line > .mk { color: var(--accent); display: grid; place-items: center; flex-shrink: 0; }
.lms-cbar-line > input {
  flex: 1; min-width: 0; border: 0; outline: none; background: transparent;
  font-size: 13px; color: var(--ink); padding: 6px 0; font-family: inherit;
}
.lms-cbar-line > input::placeholder { color: var(--ink-5); }
/* 잡이 도는 동안 입력은 잠긴다 — 그때 클릭까지 삼키면(비활성 폼 요소는 click 이벤트가
   아예 나지 않아 껍데기까지 버블되지 않는다) 바 폭 대부분이 먹통이 되어, 접어 둔 판을
   다시 펴려면 맨 왼쪽 표식(.mk)만 눌러야 한다. 짚이지 않게 비켜 세워 클릭이 껍데기
   (.lms-cbar-shell)로 떨어지게 둔다 — 잠긴 입력은 어차피 고르거나 누를 것이 없다. */
.lms-cbar-line > input:disabled { color: var(--ink-4); pointer-events: none; }
/* 판이 닫혀 있는 동안 도는 턴의 진행 문구가 여기 선다(읽는 중: …). */
.lms-cbar-line .sc {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  max-width: 300px; font-size: 10.5px; color: var(--ink-5);
}

/* ── 도구 칩 — 누르면 위로 팝오버가 열린다(앱 .lms-ai-pick과 같은 알맹이, 모양만 칩).
   모드는 둘뿐이라(부분/모두 허용) 늘 내건다. */
.lms-asst-tool {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 8px; border-radius: 8px;
  border: 1px solid transparent; background: transparent; color: var(--ink-3);
  font-family: inherit; font-size: 11.5px; font-weight: 600; letter-spacing: -.01em;
  transition: all var(--t); min-width: 0; cursor: pointer;
}
.lms-asst-tool:hover, .lms-asst-tool.on { background: var(--surface-2); border-color: var(--line); color: var(--ink-2); }
.lms-asst-tool > .ic { color: var(--accent); display: grid; place-items: center; flex-shrink: 0; }
.lms-asst-tool > .cv { color: var(--ink-5); display: grid; place-items: center; flex-shrink: 0; }
.lms-asst-tool .dim { color: var(--ink-5); font-weight: 550; }
.lms-asst-tool .pm { font-weight: 650; flex-shrink: 0; }
.lms-asst-tool.perm-edit .pm { color: var(--warn); }
/* 모두 허용은 기본값이라 색으로 세우지 않는다 — 이름만 굵게 걸어 둔다(사용자 요청). */
.lms-asst-tool.perm-auto .pm { color: var(--ink-2); }
.lms-asst-send { flex-shrink: 0; height: 30px; width: 34px; padding: 0; justify-content: center; }
/* 모델·모드·계정이 한 판에 들어가 길어졌다 — 화면이 낮으면 팝오버 안에서 구른다. */
.lms-pop.scrolly { max-height: min(600px, calc(100vh - 116px)); overflow-y: auto; }

/* 이름표 — 바의 표식과 대화 칸 머리가 같은 것을 쓴다. */
.lms-asst-mark {
  width: 24px; height: 24px; border-radius: 8px; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); flex-shrink: 0;
}

/* 빈 대화 — 무엇을 시킬 수 있는 물건인지 첫 화면에서 알려준다(시안 asst-empty). */
.lms-asst-seed { display: flex; flex-direction: column; gap: 6px; margin-top: 12px; }
.lms-asst-seed button {
  text-align: left; padding: 9px 11px; border-radius: 9px; border: 1px solid var(--line);
  background: var(--surface); color: var(--ink-2); font-family: inherit; font-size: 12px;
  line-height: 1.5; display: flex; align-items: center; gap: 8px; cursor: pointer;
  transition: all var(--t);
}
.lms-asst-seed button:hover {
  border-color: color-mix(in oklch, var(--accent) 40%, var(--line));
  background: color-mix(in oklch, var(--accent) 4%, var(--surface));
}
.lms-asst-seed button > svg { color: var(--ink-5); flex-shrink: 0; }

/* 근거 — 답 하나마다 무슨 파일을 열었는지. 신뢰가 여기서 난다. */
.lms-asst-src { display: flex; flex-wrap: wrap; gap: 4px; padding-left: 3px; }
.lms-asst-src > .t { font-size: 10.5px; color: var(--ink-5); align-self: center; margin-right: 2px; }
.lms-asst-src-chip {
  display: inline-flex; align-items: center; gap: 4px; padding: 2px 7px; border-radius: 6px;
  background: var(--surface); border: 1px solid var(--line); color: var(--ink-4);
  font-family: var(--font-mono); font-size: 10.5px; cursor: pointer; transition: all var(--t);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lms-asst-src-chip:hover { border-color: var(--line-strong); color: var(--ink-2); }
.lms-asst-src-chip > svg { color: var(--ink-5); flex-shrink: 0; }

/* ── 왼쪽 칸 — 과정 폴더 트리.
   AgentCodeGUI(Explorer.tsx)의 파일 탐색기 행 구조를 라이트 톤으로 옮긴 것이다:
   .lms-fxr > .tw(화살표) · .fic(아이콘) · .n(이름) · 오른쪽 표식. 깊이는 --d로 넘기고,
   들여쓰기 가이드선은 행의 배경(repeating-linear-gradient)이 그린다(저쪽 방식 그대로). */
.lms-fxtree { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; padding: 4px 6px 12px; }
.lms-fxr {
  position: relative; display: flex; align-items: center; gap: 5px; width: 100%;
  padding: 3.5px 8px 3.5px calc(9px + var(--d, 0) * 13px); border: 0; border-radius: 7px;
  background: transparent; font-family: inherit; font-size: 11.8px; color: var(--ink-2);
  text-align: left; white-space: nowrap; cursor: pointer;
  background-image: repeating-linear-gradient(90deg, transparent, transparent 12px, rgba(10, 10, 10, .09) 12px, rgba(10, 10, 10, .09) 13px);
  background-repeat: no-repeat; background-position: 14px 0; background-size: calc(var(--d, 0) * 13px) 100%;
}
.lms-fxr:hover { background-color: color-mix(in oklch, var(--ink) 5%, transparent); color: var(--ink); }
.lms-fxr .tw { width: 11px; flex: 0 0 11px; display: grid; place-items: center; color: var(--ink-4); }
.lms-fxr .tw svg { transition: transform .13s ease; }
.lms-fxr.open .tw svg { transform: rotate(90deg); }
.lms-fxr .fic { width: 15px; flex: 0 0 15px; display: grid; place-items: center; color: var(--ink-3); }
.lms-fxr .fic svg { display: block; }
.lms-fxr .n { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.lms-fxr .n.dir { font-weight: 550; }
/* 이번 대화에서 실제로 읽은 파일 — "무엇을 보고 답했나"의 표식. */
.lms-fxr .fx-dot {
  flex: 0 0 auto; margin-left: auto; margin-right: 2px;
  width: 5px; height: 5px; border-radius: 99px;
}
.lms-fxr .fx-dot.read { background: var(--accent); }
/* 되돌리기 1벌(*.이전.*) — 있는 건 맞지만 읽을 것은 아니라 흐리게 둔다. */
.lms-fxr.hid { opacity: .42; }
.lms-fx-empty { padding: 6px 12px 6px calc(29px + var(--d, 0) * 13px); font-size: 11px; color: var(--ink-4); }
.lms-tree-note {
  padding: 9px 11px; font-size: 10.5px; color: var(--ink-5); line-height: 1.6;
  border-top: 1px solid var(--line); flex-shrink: 0;
}

/* ── 오른쪽 칸 — 검토 판. 고친 파일이 없을 땐 파이프라인 현황이 산다. ── */
.lms-review { flex: 1; overflow-y: auto; padding: 11px; display: flex; flex-direction: column; gap: 11px; }
.lms-review-empty { font-size: 11.5px; color: var(--ink-5); line-height: 1.7; }
.lms-rstage { display: flex; align-items: flex-start; gap: 9px; padding: 9px 0; border-top: 1px solid var(--line); }
.lms-rstage:first-of-type { border-top: 0; padding-top: 0; }
.lms-rstage > .n {
  width: 21px; height: 21px; border-radius: 7px; flex-shrink: 0; display: grid; place-items: center;
  font-size: 11px; font-weight: 650; background: var(--surface-2); border: 1px solid var(--line); color: var(--ink-4);
}
.lms-rstage > .n.done { background: color-mix(in oklch, var(--ok) 12%, transparent); color: var(--ok); border-color: transparent; }
.lms-rstage > .n.live { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.lms-rstage > .n.warn { background: color-mix(in oklch, var(--warn) 14%, transparent); color: var(--warn); border-color: transparent; }
.lms-rstage > .c { min-width: 0; flex: 1; font-size: 11.5px; color: var(--ink-3); line-height: 1.55; }
.lms-rstage > .c b { display: block; color: var(--ink-2); font-size: 12px; font-weight: 650; margin-bottom: 2px; }

/* 고친 파일 카드 — 되돌리기 1벌(*.이전.*)이 파일마다 남아 있다는 약속의 자리. */
.lms-asst-card { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
.lms-asst-card-head {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px;
  font-size: 12px; font-weight: 650; color: var(--ink-2);
}
.lms-asst-card-head > .ic { color: var(--accent); display: grid; place-items: center; flex-shrink: 0; }
.lms-asst-card-head > .pill { margin-left: auto; }
.lms-asst-card-body { padding: 0 12px 11px; }
.lms-asst-item {
  display: flex; align-items: flex-start; gap: 8px; padding: 7px 0;
  border-top: 1px solid var(--line); font-size: 11.5px; color: var(--ink-3); line-height: 1.55;
}
.lms-asst-item:first-child { border-top: 0; }
.lms-asst-item > .n {
  width: 18px; height: 18px; border-radius: 6px; flex-shrink: 0; margin-top: 1px;
  display: grid; place-items: center; font-size: 10px; font-weight: 650;
  background: color-mix(in oklch, var(--ok) 12%, transparent); color: var(--ok);
}
.lms-asst-item > .c { min-width: 0; flex: 1; }
.lms-asst-item > .c b { color: var(--ink-2); font-weight: 650; }
.lms-asst-item .sub {
  color: var(--ink-5); font-family: var(--font-mono); font-size: 10px; margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lms-asst-item > .act { flex-shrink: 0; padding: 2px 7px; font-size: 10.5px; }
.lms-asst-card-foot {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px; row-gap: 8px;
  padding: 10px 12px; border-top: 1px solid var(--line); background: var(--surface-2);
}
.lms-asst-card-foot .note {
  font-size: 10.5px; color: var(--ink-5); margin-right: auto; min-width: 0;
  line-height: 1.5; word-break: keep-all;
}
.lms-asst-card-foot .note b { color: var(--ink-4); font-weight: 650; font-family: var(--font-mono); font-size: 10px; }

/* ── 요청한 작업 카드 — 말풍선 아래에 서서 실행 진행을 좇는다(고친 파일 카드와 같은 뼈대).
   상태색은 .n 원과 오른쪽 .st 글자가 든다: 대기(회색) → 진행(점 셋) → 완료/실패/건너뜀. */
.lms-chat-msg .lms-asst-acts { align-self: stretch; margin-top: 2px; }
.lms-asst-act > .n { background: color-mix(in oklch, var(--accent) 10%, transparent); color: var(--accent); }
.lms-asst-act.done > .n { background: color-mix(in oklch, var(--ok) 12%, transparent); color: var(--ok); }
.lms-asst-act.failed > .n { background: color-mix(in oklch, var(--danger) 10%, transparent); color: var(--danger); }
.lms-asst-act.skipped > .n { background: var(--surface-2); color: var(--ink-5); }
.lms-asst-act .sub.note { color: var(--ink-4); font-family: inherit; font-size: 10.5px; white-space: normal; }
.lms-asst-act.failed .sub.note { color: var(--danger); }
.lms-asst-act > .st { flex-shrink: 0; font-size: 10.5px; font-weight: 650; color: var(--ink-5); margin-top: 2px; }
.lms-asst-act > .st.ok { color: var(--ok); }
.lms-asst-act > .st.live { color: var(--accent); }

/* ── 파일 뷰어 — 판의 2·3열(대화·작업)을 덮는 읽기 전용 검은 화면 한 장 ────────────
   왼쪽 트리는 일부러 남긴다: 연 채로 다른 파일을 눌러 내용만 갈아 끼우라고.
   판 안 absolute 레이어다 — grid 칸으로 겹치면(grid-column: 2/-1) 자동 배치가 그 자리를
   피해 대화·작업 칸을 둘째 줄로 밀어낸다. 왼쪽 인셋만 트리 칸 폭(--side-w)에 판 여백
   10 + 칸 사이 10을 더해 따라간다. 여닫는 곡선은 판(.lms-cpanel)의 것을 한 톤 짧게 줄인
   것이다: 판 위에서 한 겹 더 뜨는 것이라 같은 손짓이되 가벼워야 한다.
   유리 어휘를 여기서만 끊는 까닭: 읽는 화면이라 글자 뒤가 비치면 안 된다(사용자 요청).
   대신 안쪽은 전부 아래 로컬 팔레트를 타므로 앱의 라이트 토큰은 건드리지 않는다. */
.lms-fview {
  /* ── 뷰어 전용 팔레트 ──────────────────────────────────────────────────
     앱 토큰(:root)은 라이트 한 벌뿐이라 다크가 없다. 그래서 같은 이름의 변수를 이
     스코프에서만 다시 선언한다: 앱 팔레트는 그대로 두고, 뷰어 안의 .btn·.icon-btn·
     .lms-ccol-head·.md·.scrolly가 손 안 대고 전부 이 값을 타고 다크가 된다.
     (커스텀 속성은 쓰이는 자리에서 풀리므로 --accent-soft 같은 파생값도 따라온다.)
     밝기 순서는 라이트와 반대다 — surface-2가 surface보다 밝아야 hover가 뜬다. */
  --bg: #0B0B0E;
  --surface: #1E1E26;
  --surface-2: #2A2A34;
  --surface-3: #34343F;
  --line: #2E2E38;
  --line-strong: #3E3E4A;
  --ink: #F4F4F8;
  --ink-2: #DEDEE8;
  --ink-3: #B7B7C6;
  --ink-4: #9494A6;
  --ink-5: #74748A;
  --accent: #A6A8FF;
  --accent-soft: color-mix(in oklch, var(--accent) 22%, transparent);
  --warn: #F2B33D;
  --ok: #45D3A0;
  --danger: #FF8A8A;

  position: absolute; z-index: 2;
  top: 10px; right: 10px; bottom: 10px; left: calc(var(--side-w) + 20px);
  display: flex; flex-direction: column; min-height: 0; overflow: hidden;
  border-radius: 16px;
  /* 읽는 자리라 유리를 한 번 끊는다 — 판 위에 놓인 검은 화면 한 장(사용자 요청).
     흐림을 얹지 않는 것도 같은 까닭이다: 글자 뒤로 대화가 비치면 읽기가 흔들린다. */
  background: #101014;
  color: var(--ink-2);
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow:
    0 1px 3px rgba(0, 0, 0, .3),
    0 26px 52px -22px rgba(0, 0, 0, .55),
    inset 0 1px 0 rgba(255, 255, 255, .06);
  opacity: 0; visibility: hidden; transform: translateY(8px) scale(.99);
  transition: opacity .15s ease, visibility .15s, transform .14s cubic-bezier(.4, 0, 1, 1);
}
.lms-fview.open {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity .16s ease, visibility 0s, transform .4s cubic-bezier(.16, 1.24, .3, 1);
}
/* 머리 — 칸 머리(.lms-ccol-head)를 그대로 쓰고 이름·경로·보기 토글·나가는 문만 얹는다.
   높이는 대화 칸 머리와 같다(같은 자리에서 갈아 끼우는 것처럼 보이게). 색은 위의 로컬
   팔레트를 타고 저절로 다크가 되고, 본문과는 옅은 흰 막 한 겹으로만 갈린다. */
.lms-fview-head {
  gap: 8px; padding: 9px 9px 9px 12px;
  background: color-mix(in oklch, var(--ink) 4%, transparent);
}
.lms-fview-head > svg { color: var(--ink-4); flex-shrink: 0; }
/* 이름만 줄어드는 자리다 — 오른쪽에 선 것(점 셋·보기 토글·버튼 둘)이 전부 flex-shrink:0
   이고 경로(.pt)는 flex-basis가 0이라 이미 0까지 줄어든 뒤다. 여기까지 안 줄면 좁은
   창(최소 1024 + 펼친 사이드바)에서 머리가 넘쳐 [닫기]가 오른쪽으로 밀려 잘린다. */
.lms-fview-head .nm { max-width: 44%; min-width: 3em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lms-fview-head .pt {
  flex: 1; min-width: 0; font-family: var(--font-mono); font-size: 10.5px; font-weight: 450;
  color: var(--ink-5); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lms-fview-head .lms-chat-dots { flex-shrink: 0; }
.lms-fview-head .btn { padding: 4px 9px; font-size: 11px; }
/* 닫는 문은 끝까지 제 크기를 지킨다 — .icon-btn은 기본이 flex-shrink:1이라 좁아지면
   32px 과녁이 먼저 깎인다(누르는 자리가 줄면 안 된다). */
.lms-fview-head .icon-btn { flex-shrink: 0; }
/* 보기 ↔ 원문 — 형식대로 그릴 수 있는 파일에만 뜨는 두 칸짜리 스위치. */
.lms-fview-seg {
  display: inline-flex; flex-shrink: 0; gap: 2px; padding: 2px; border-radius: 8px;
  background: color-mix(in oklch, var(--ink) 7%, transparent);
  border: 1px solid var(--line);
}
.lms-fview-seg button {
  padding: 3px 9px; border: 0; border-radius: 6px; background: transparent; color: var(--ink-4);
  font-family: inherit; font-size: 11px; font-weight: 600; letter-spacing: -.01em;
  cursor: pointer; transition: all var(--t);
}
.lms-fview-seg button:hover { color: var(--ink-2); }
.lms-fview-seg button.on { background: var(--surface-3); color: var(--ink); box-shadow: 0 1px 2px rgba(0, 0, 0, .35); }
/* 잘려 온 원문 — 무엇을 못 보고 있는지 본문보다 먼저 말한다.
   dim은 같은 자리의 다른 사연이다: 정리해 보여주려다 물러난 까닭(JSON 폴백). */
.lms-fview-note {
  flex-shrink: 0; padding: 7px 12px; font-size: 10.5px; line-height: 1.5; color: var(--warn);
  background: color-mix(in oklch, var(--warn) 12%, transparent);
  border-bottom: 1px solid color-mix(in oklch, var(--warn) 22%, transparent);
}
.lms-fview-note.dim {
  color: var(--ink-4);
  background: color-mix(in oklch, var(--ink) 6%, transparent);
  border-bottom-color: var(--line);
}
/* 본문 통 — 구르는 것은 늘 이 한 겹이다(원문·JSON·MD가 같은 통을 쓴다). */
.lms-fview-body { flex: 1; min-height: 0; padding: 12px 14px 20px; }
/* 원문·JSON — 읽기만 하는 자리라 고정폭에 줄만 꺾는다(가로 스크롤은 두지 않는다). */
.lms-fview-pre {
  margin: 0; font-family: var(--font-mono); font-size: 11.5px; line-height: 1.8; color: var(--ink-2);
  white-space: pre-wrap; overflow-wrap: anywhere; tab-size: 2;
}
/* JSON 색 — 뼈대(괄호·쉼표)는 흐리게 눕히고 값의 갈래만 세운다. */
.lms-fview-pre.json { color: var(--ink-5); }
.lms-fview-pre.json .k { color: #A8B6FF; }
.lms-fview-pre.json .s { color: #8FD9A8; }
.lms-fview-pre.json .n { color: #F0B37E; }
.lms-fview-pre.json .b { color: #E294D8; }
/* 마크다운 — 앱 공용 .md 규칙을 그대로 쓰고(전부 토큰이라 다크로 따라온다) 이 판에
   맞는 크기·여백만 얹는다. 스크립트 .md는 줄이 곧 발화라 줄 간격을 넉넉히. */
.lms-fview-body.doc { padding: 16px 20px 28px; }
.lms-fview-body.doc .md { font-size: 13px; line-height: 1.85; }
.lms-fview-body.doc .md h1 { font-size: 1.35em; }
.lms-fview-body.doc .md h2 { font-size: 1.2em; }
.lms-fview-body.doc .md h1, .lms-fview-body.doc .md h2 {
  padding-bottom: .3em; border-bottom: 1px solid var(--line);
}
.lms-fview-body.doc .md hr { border-top-color: var(--line-strong); }
/* HTML — 파일 본연의 배경(대개 흰색) 그대로 둔다. 판이 검으니 첫 칠부터 흰 종이로
   세워 두어야 뜨는 순간 번쩍이지 않는다. 모서리는 뷰어의 overflow가 깎아 준다. */
.lms-fview-frame { flex: 1; min-height: 0; width: 100%; border: 0; background: #fff; }
/* 읽는 중 · 미리볼 수 없음 · 빈 파일 — 본문 자리에 서는 안내 한 판. */
.lms-fview-mid {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px;
  padding: 28px 24px; text-align: center; font-size: 11.5px; color: var(--ink-5);
}
.lms-fview-mid > svg { color: var(--ink-5); opacity: .7; }
/* 미리볼 수 없는 파일 — 잘못된 것이 아니라 영상·이미지라서다. 오류 빨강 대신 한 톤만 세운다. */
.lms-fview-mid.fail > svg { color: var(--ink-4); opacity: 1; }
.lms-fview-mid b { font-size: 12.5px; font-weight: 650; color: var(--ink-2); }
.lms-fview-mid p { margin: 0; max-width: 320px; line-height: 1.7; }
.lms-fview-mid .btn { margin-top: 4px; }
/* 지금 뷰어에 올라 있는 파일 — 트리 행과 근거 칩이 같은 신호를 낸다(눌린 채로).
   트리 행은 눌린 상태가 hover보다 세야 해서 hover 선택자와 같은 무게로 한 번 더 적는다. */
.lms-fxr.on, .lms-ccol.side .lms-fxr.on, .lms-ccol.side .lms-fxr.on:hover {
  background-color: var(--accent-soft); color: var(--accent);
}
.lms-fxr.on .fic, .lms-fxr.on .tw { color: var(--accent); }
.lms-fxr.on .n { font-weight: 600; }
.lms-asst-src-chip.on {
  border-color: color-mix(in oklch, var(--accent) 45%, var(--line));
  color: var(--accent);
}
.lms-asst-src-chip.on > svg { color: var(--accent); }

/* ── 첨부 — 과정 폴더 밖 자료를 들여오는 길 ──────────────────────────────────
   자리가 둘로 갈린다: 입력 상자 위 칩 줄(.lms-att-strip)은 **이번 턴에 새로 붙인 것**,
   오른쪽 칸의 목록(.lms-att)은 지금 참고 중인 것 전부(= 과정 폴더 `참고자료\` 그 자체).
   과정 폴더 파일과 아이콘 팩은 같아도 자리를 갈라 둔다 — 밖에서 들여온 것이라서다. */
.lms-att-strip { display: flex; flex-wrap: wrap; gap: 5px; padding: 8px 8px 2px 14px; }
.lms-att-chip {
  display: inline-flex; align-items: center; gap: 5px; max-width: 220px;
  padding: 3px 4px 3px 6px; border-radius: 8px; font-size: 11px; color: var(--ink-2);
  background: color-mix(in oklch, var(--surface-2) 88%, transparent); border: 1px solid var(--line);
}
.lms-att-chip > svg { flex-shrink: 0; }
.lms-att-chip .n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lms-att-chip .x, .lms-att-row .x {
  flex-shrink: 0; width: 18px; height: 18px; display: grid; place-items: center;
  padding: 0; border: 0; border-radius: 5px; background: transparent; color: var(--ink-5);
  cursor: pointer; transition: all var(--t);
}
.lms-att-chip .x:hover, .lms-att-row .x:hover {
  background: color-mix(in oklch, var(--danger) 10%, transparent); color: var(--danger);
}
/* 클립 버튼 — 모델 칩과 같은 껍데기지만 글자가 없어 좁고, 표식도 강조색을 쓰지 않는다
   (붙이기는 고르기가 아니라 손짓이다). */
.lms-asst-tool.att-btn { padding: 4px 6px; }
.lms-asst-tool.att-btn > .ic { color: var(--ink-4); }
.lms-asst-tool.att-btn:hover > .ic { color: var(--ink-2); }

/* 오른쪽 칸 아래 — 지금 무엇을 참고하고 있는지. 트리에서 파생하므로 따로 비울 것이 없다. */
.lms-att { border-top: 1px solid var(--line); margin-top: 2px; padding: 11px 0 2px; }
.lms-att-head {
  display: flex; align-items: center; gap: 6px; margin-bottom: 8px;
  font-size: 11px; font-weight: 650; color: var(--ink-3);
}
.lms-att-head > svg { color: var(--ink-4); flex-shrink: 0; }
.lms-att-head .pill { padding: 1px 7px; font-size: 10px; }
.lms-att-head .lnk {
  margin-left: auto; padding: 2px 6px; border: 0; border-radius: 6px; background: transparent;
  font-family: inherit; font-size: 11px; font-weight: 650; color: var(--accent); cursor: pointer;
  transition: background var(--t);
}
.lms-att-head .lnk:hover { background: var(--accent-soft); }
.lms-att-row {
  display: flex; align-items: center; gap: 7px; padding: 5px 5px 5px 7px; margin-bottom: 5px;
  border: 1px solid var(--line); border-radius: 9px; background: var(--surface); font-size: 11.5px;
}
.lms-att-row .fic { width: 15px; flex: 0 0 15px; display: grid; place-items: center; }
.lms-att-row .fic svg { display: block; }
.lms-att-row .n { min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-2); }
.lms-att-row .sz { flex-shrink: 0; font-size: 10px; color: var(--ink-5); }
/* 이번 대화에서 실제로 읽은 자료 — 트리 행과 같은 표식이되 여긴 오른쪽으로 밀지 않는다
   (이름이 이미 남는 자리를 다 먹어서, 크기 옆에 붙어야 줄이 흔들리지 않는다). */
.lms-att-row .fx-dot { flex: 0 0 auto; width: 5px; height: 5px; border-radius: 99px; }
.lms-att-row .fx-dot.read { background: var(--accent); }
.lms-att-empty { padding: 2px 2px 6px; font-size: 10.5px; color: var(--ink-5); line-height: 1.6; }
.lms-att-hint { margin-top: 6px; font-size: 10px; color: var(--ink-5); line-height: 1.55; }
.lms-att-hint b { color: var(--ink-4); font-weight: 650; font-family: var(--font-mono); font-size: 9.5px; }
/* 눌린 유리(작업 칸) 위에서는 줄이 흰 종이로 떠야 읽힌다 — 카드와 같은 손짓. */
.lms-ccol.side .lms-att-row { background: color-mix(in oklch, var(--surface) 92%, transparent); }

/* ── 자료 JSON 불러오기 · 규격 자동 보정 내역 (2026-08-21) ────────────────────
   불러오기가 조용히 고친 자리를 사람이 확인하는 목록이다. 100줄에서 잘려 오지만
   그래도 길어서 모달이 화면을 넘길 수 있다 — 구르는 것은 이 목록 한 겹뿐이다. */
.lms-fixes {
  max-height: 44vh; overflow-y: auto; margin: 12px 0 0; padding: 8px 12px;
  list-style: none; border: 1px solid var(--line); border-radius: 10px;
  background: var(--surface-2); font-size: 12px; line-height: 1.6; color: var(--ink-2);
}
.lms-fixes > li { position: relative; padding: 3px 0 3px 12px; overflow-wrap: anywhere; }
.lms-fixes > li::before {
  content: ''; position: absolute; left: 2px; top: 11px;
  width: 3px; height: 3px; border-radius: 50%; background: var(--ink-5);
}
/* ② 카드 안내 줄에 붙는 글자 버튼 — 내역을 다시 펼치는 문 하나뿐이라 링크 생김새로. */
.lms-fixes-link {
  padding: 0; border: 0; background: transparent; color: var(--accent);
  font: inherit; font-weight: 650; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.lms-fixes-link:hover { color: var(--ink); }

/* ── 끌어다 놓는 동안 — "여기 놓아도 된다"를 눈에 보이게 (2026-08-21) ───────────
   커서 모양(dropEffect) 하나로는 판이 과녁인지 알 수 없었다. 켜지는 조건은 드롭 가드와
   같다(파일 드래그일 때만) — 트리 행 재정렬 같은 앱 안의 드래그에는 아무 일도 없다.
   판이 펴져 있으면 판 위 덮개 한 장, 접혀 있으면 바 껍데기 자신이 과녁이 된다. */

/* 판 위 덮개 — 마우스를 받지 않는 것이 핵심이다(pointer-events: none). 덮개가 커서를
   가로채면 판 입장에선 커서가 밖으로 나간 셈이라 dragleave가 떠서 제 손으로 저를
   깜빡인다. 뼈대는 늘 붙어 있고 켜짐만 토글한다(판·뷰어와 같은 규칙). */
.lms-att-dropzone {
  position: absolute; z-index: 4; inset: 0; pointer-events: none;
  display: grid; place-items: center;
  /* 판의 패딩 상자를 덮으므로 모서리는 판(24px)에서 테두리 한 겹만큼 작다. */
  border-radius: 23px;
  background: color-mix(in oklch, var(--accent) 7%, transparent);
  border: 1.5px dashed color-mix(in oklch, var(--accent) 45%, transparent);
  opacity: 0; visibility: hidden; transform: scale(.98);
  transition: opacity .15s ease, visibility .15s, transform .15s cubic-bezier(.2, .7, .2, 1);
}
.lms-att-dropzone.on {
  opacity: 1; visibility: visible; transform: none;
  transition: opacity .15s ease, visibility 0s, transform .16s cubic-bezier(.2, .7, .2, 1);
}
/* 가운데 유리 카드 — 판이 이미 흐린 유리라 칸(.lms-ccol)과 같은 86%로 한 겹 더 띄워야
   글자가 읽힌다. 표식만 강조색을 쓰고 글자는 앱 먹색 그대로 — 소리치는 자리가 아니다. */
.lms-att-dropzone .card {
  display: flex; align-items: center; gap: 11px;
  padding: 13px 18px 13px 13px; border-radius: 15px;
  background: color-mix(in oklch, var(--surface) 86%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(1.7);
  backdrop-filter: blur(22px) saturate(1.7);
  border: 1px solid color-mix(in oklch, var(--accent) 30%, var(--line));
  box-shadow: 0 2px 6px rgba(15, 15, 15, .05), 0 22px 48px -22px rgba(15, 15, 15, .38);
}
.lms-att-dropzone .card .ic {
  flex-shrink: 0; width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 11px; background: var(--accent-soft); color: var(--accent);
}
.lms-att-dropzone .card b { display: block; font-size: 12.5px; font-weight: 650; color: var(--ink); }
.lms-att-dropzone .card .d { display: block; margin-top: 2px; font-size: 10.5px; color: var(--ink-5); }
/* 폴더 이름은 아래 안내문(.lms-att-hint)과 같은 손짓 — 화면에 보이는 글자 그대로. */
.lms-att-dropzone .card .d b {
  display: inline; color: var(--ink-4); font-weight: 650;
  font-family: var(--font-mono); font-size: 9.5px;
}

/* 바만 떠 있을 때(판 접힘) — 판이 없으니 껍데기 자신이 과녁이다. 테두리를 강조색으로
   갈아 끼우고 글로우 한 겹만 얹는다: 원래 그림자는 그대로 둬야 떠 있는 높이가 안 변한다.
   (판이 부풀어 오르는 max-width 애니메이션과는 다른 속성이라 서로 밀지 않는다.) */
.lms-cbar-shell.drop {
  border-color: color-mix(in oklch, var(--accent) 55%, rgba(255, 255, 255, .7));
  box-shadow:
    0 1px 2px rgba(15, 15, 15, .05),
    0 20px 44px -16px rgba(15, 15, 15, .24),
    0 0 0 .5px rgba(15, 15, 15, .06),
    inset 0 1px 0 rgba(255, 255, 255, .55),
    0 0 0 4px color-mix(in oklch, var(--accent) 13%, transparent);
}
/* 바 위 작은 칩 — 입력 자리를 침범하지 않게 바 바깥(위)에 뜬다. 자리는 바 묶음
   (.lms-cbar) 기준이다: 껍데기를 positioned로 만들면 판 그림자와 겹치는 차례가 바뀐다.
   `.lms-cbar > *`의 pointer-events: auto를 덮어야 해서 자식 선택자로 못 박는다. */
.lms-cbar > .lms-att-droptip {
  position: absolute; z-index: 3; left: 50%; bottom: calc(100% + 9px); pointer-events: none;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 5px 11px 5px 9px; border-radius: 999px;
  background: color-mix(in oklch, var(--surface) 86%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
  backdrop-filter: blur(18px) saturate(1.6);
  border: 1px solid color-mix(in oklch, var(--accent) 34%, var(--line));
  box-shadow: 0 10px 26px -14px rgba(15, 15, 15, .4);
  font-size: 11px; font-weight: 600; color: var(--ink-2);
  opacity: 0; visibility: hidden; transform: translate(-50%, 5px) scale(.98);
  transition: opacity .15s ease, visibility .15s, transform .15s cubic-bezier(.2, .7, .2, 1);
}
.lms-cbar > .lms-att-droptip.on {
  opacity: 1; visibility: visible; transform: translate(-50%, 0) scale(1);
  transition: opacity .15s ease, visibility 0s, transform .16s cubic-bezier(.2, .7, .2, 1);
}
.lms-cbar > .lms-att-droptip > svg { flex-shrink: 0; color: var(--accent); }
.lms-cbar > .lms-att-droptip b {
  color: var(--ink-4); font-weight: 650; font-family: var(--font-mono); font-size: 9.5px;
}

/* ══ 검수 화면 — 페이지 순서 편집 (2026-08-21) ══════════════════════════════
   순서의 정본은 자료 JSON의 pages 배열이고, 미리보기도 내보내기 HTML(01.html,
   02.html…)도 그 배열을 그대로 따른다. 그래서 손잡이가 트리 줄에 붙는다 —
   여기서 본 순서가 곧 LMS에 올라갈 순서다. */

/* ▲▼ — 줄이 좁아 평소엔 자리만 잡고 숨어 있다가(자리까지 비우면 짚을 때마다 줄이
   출렁인다) 짚은 줄·고른 줄에서만 드러난다. 숨은 동안은 눌리지도 않는다. */
.lms-pmove {
  display: flex; flex-shrink: 0; gap: 1px;
  opacity: 0; pointer-events: none; transition: opacity var(--t);
}
.lms-tree-line:hover > .lms-pmove,
.lms-tree-line.on > .lms-pmove,
.lms-pmove:focus-within { opacity: 1; pointer-events: auto; }
.lms-pmove > button {
  flex-shrink: 0; width: 17px; height: 19px; padding: 0;
  display: grid; place-items: center; border: 0; border-radius: 5px;
  background: transparent; color: var(--ink-5); cursor: pointer;
  transition: background var(--t), color var(--t);
}
.lms-pmove > button:hover:not(:disabled) { background: var(--surface-2); color: var(--ink-2); }
/* 첫 블록의 ▲·마지막 블록의 ▼ — 갈 곳이 없다는 걸 자리로 남겨 보인다. */
.lms-pmove > button:disabled { opacity: .28; cursor: default; }

/* ── 꾹 눌러 끌기 ───────────────────────────────────────────────────────
   줄이 <button>이라 클릭과 가르려고 홀드(260ms)·세로 6px로 드래그에 들어간다.
   드는 동안은 창 전체가 grabbing이고 글자가 잡히지 않는다(.lms-marquee-on과 같은 손짓). */
body.lms-drag-on, body.lms-drag-on * { cursor: grabbing !important; user-select: none; -webkit-user-select: none; }

/* 들린 줄 — 따로 뜨는 유령 줄은 만들지 않는다(좁은 트리에서 겹치면 어디에 놓이는지
   흐려진다). 대신 제자리를 흐리게 눕히고 살짝 들어 올려 "이게 지금 옮기는 것"만 말한다.
   붙은 [사전퀴즈, 본영상]은 두 줄이 함께 들린다. */
.lms-tree-line.dragging > .lms-tree-row {
  opacity: .45;
  background: var(--surface-2);
  box-shadow: 0 6px 14px -8px rgba(0, 0, 0, .45);
}
/* 드는 동안은 손잡이를 모두 내린다 — 지금 봐야 할 건 놓을 자리 한 줄뿐이다.
   (:hover 규칙보다 세야 해서 줄 선택자를 한 번 더 태운다.) */
body.lms-drag-on .lms-tree-line > .lms-pmove { opacity: 0; pointer-events: none; }

/* 아직 만들지 않은 자리도 순서는 옮길 수 있다(2026-08-21) — 누를 것은 없지만 끌 수는
   있으니, 그 줄만 커서로 말해 준다(고를 수 있다는 뜻의 pointer는 쓰지 않는다). */
.lms-tree-row.ghost.movable { cursor: grab; }

/* 놓을 자리 — 자리를 먹지 않는 선이다(위아래 -1px). 표시가 옮겨 다닐 때마다 아래 줄이
   밀리면 그때그때 실측하는 드롭 지점이 흔들려 선이 떨린다. */
.lms-drop-line {
  height: 0; margin: -1px 8px -1px 27px;
  border-top: 2px solid var(--accent); border-radius: 2px;
}

/* ══ 검수 화면 — 선택 모드 · 여러 차시 한 번에 (2026-08-21) ══════════════════
   문은 둘이다: 트리 칸 발치 [골라서 생성] = 보고 있는 데서 차시·페이지까지 골라서,
   화면 머리 [차시 일괄 생성] = 구성 기본값을 한 번 정해 여러 차시를 통째로.
   기존 조각(.lms-tree-row · .lms-gen-check · .lms-gen-fields · .pill)을 그대로 쓰고
   여기 있는 건 "여러 차시"라서 새로 필요한 뼈대뿐이다. */

/* ── 선택 모드 — 체크는 "골라서 만들 때"만 뜬다 ───────────────────────────────
   트리 40줄에 체크가 상시로 떠 있으면 검수하러 들어온 사람에겐 잡음이다. 기본은
   깨끗한 트리(검수·탐색)고, 칸 발치 [골라서 생성]을 누른 동안만 체크가 자리를 얻고
   아래 생성 패널이 선다. 체크는 지우지 않고 **접기만** 한다 — 껐다 켜도 고른 것이
   그대로라, 잘못 눌러도 처음부터 다시 고를 일이 없다. */
.lms-studio-pane:not(.picking) .lms-tree-line > .lms-gen-check {
  width: 0; border-width: 0; opacity: 0; overflow: hidden; pointer-events: none;
  /* 접힌 체크가 먹는 자리는 flex gap 2px뿐 — 그만큼 당겨 위 [과정 정보] 줄과 왼쪽을 맞춘다. */
  margin-left: -2px;
}
/* 체크가 접히면 페이지 줄은 제 들여쓰기로 돌아간다 — 체크 칸이 대신하던 자리다. */
.lms-studio-pane:not(.picking) .lms-tree-line > .lms-gen-check + .lms-tree-row.pg { padding-left: 27px; }
.lms-studio-pane .lms-tree-line > .lms-tree-row.pg { transition: background var(--t), color var(--t), padding var(--t); }
/* 차시 헤더에 붙는 체크는 트리 맨 왼쪽 끝 — 페이지 줄(11px)만큼 들여쓰지 않는다. */
.lms-tree-line.lesson > .lms-gen-check { margin-left: 2px; }

/* 반쯤 고른 차시 — 그 차시 안에서 일부 페이지만 체크했다는 뜻. 켬/끔 사이의 3번째 얼굴. */
.lms-gen-check.part { background: var(--accent-soft); border-color: var(--accent); }
.lms-gen-check > .dash { width: 7px; height: 2px; border-radius: 1px; background: var(--accent); }
.lms-gen-check:disabled { opacity: .38; cursor: default; }
.lms-gen-check:disabled:hover { border-color: var(--line-strong); }

/* 생성 패널이 드나드는 칸 — 키를 몰라도 여닫히게 0fr↔1fr로 접는다. 패널을 바로 넣으면
   안 된다: min-height를 0으로 눌러도 padding이 남아 0fr 트랙이 그만큼에서 멈춘다.
   여백 없는 칸(.lms-gen-clip)을 한 겹 끼워 잘라 낸다 — 패널의 윗선도 그 칸이 같이
   물고 들어가 접히면 자국이 남지 않는다. */
.lms-gen-slot {
  flex-shrink: 0; display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows var(--t);
}
.lms-gen-slot > .lms-gen-clip { min-height: 0; overflow: hidden; }
.lms-studio-pane.picking > .lms-gen-slot { grid-template-rows: 1fr; }

/* 칸 발치 = [골라서 생성]이 서는 자리(2026-08-21 사용자 지시로 칸 머리에서 내려왔다).
   트리가 길든 짧든 늘 같은 곳에 서고, 켜면 바로 위 생성 패널이 그 위로 펼쳐져
   [고르기 → 만들기]가 아래에서 한 줄로 이어진다. 패널이 펼쳐진 동안은 윗선을 지운다 —
   패널의 윗선 하나면 충분하고, 두 줄이면 발치가 남남처럼 떨어져 보인다. */
.lms-pane-foot { flex-shrink: 0; padding: 10px; border-top: 1px solid var(--line); }
.lms-studio-pane.picking > .lms-pane-foot { padding-top: 0; border-top: 0; }
/* 꺼져 있을 땐 검정(.btn.primary) — 이 화면에서 제일 먼저 누를 버튼이다. 켠 동안엔
   검정을 위 [HTML 생성]에 넘기고 자기는 조용한 테두리 한 겹으로 물러난다. */
.lms-pane-toggle { width: 100%; justify-content: center; }
/* 껐는데 고른 차시가 남아 있으면 그 수를 버튼에 달아 둔다 — 안 보이는 선택이 조용히
   남아 있다가 다음에 [생성]을 눌렀을 때 놀라는 일을 막는다. 검정 위라 흰 알약이다. */
.lms-pane-toggle > .n {
  min-width: 16px; padding: 0 5px; border-radius: 999px;
  background: color-mix(in oklch, var(--surface) 22%, transparent); color: var(--accent-ink);
  font-size: 10.5px; font-weight: 700; font-variant-numeric: tabular-nums; text-align: center;
}

/* ── 일괄 생성 모달 — 왼쪽 [생성할 차시] · 오른쪽 [페이지 구성 묶음] ──
   두 칸을 한 화면에 놓는 게 이 모달의 전부다: 오른쪽에서 정한 구성 **한 벌**이
   왼쪽에서 그 묶음에 담은 차시에 걸린다. 30차시 중 열 차시는 7페이지, 다른 열
   차시는 8페이지 — 실제 과정은 이렇게 갈리므로 구성은 하나가 아니라 여럿이다.
   세로 선 하나로 "이 구성 ↔ 저 차시들"의 관계를 말하고, 색으로 묶음을 잇는다. */
.modal.lms-batch { max-width: 1080px; }
/* 두 칸의 키 — 내용만큼만 크고, 창을 넘지는 않는다. 차시가 40개면 두 칸에 다 들어와
   스크롤이 없고, 120개면 창 높이에서 멈추고 목록만 스크롤한다(모달은 그대로).
   232px = 배경 여백 48 + 머리 ~118 + 발치 ~66. 짧은 창에서는 min-height가 받친다.
   1fr 행을 minmax(0,·)로 두어야 max-height에 걸렸을 때 칸이 넘치지 않고 줄어든다.
   묶음 탭 줄(한 줄 33px ~ 세 줄 91px)이 오른쪽 칸 안에 한 겹 더 서지만 바깥 키는
   그대로다 — 탭은 세 줄에서 스스로 멈추고, 넘치는 몫은 그 칸(.lms-batch-col.cfg)이
   세로로 흘려 받는다. 그래서 묶음이 둘이든 스물이든 모달 크기는 안 변한다. */
.lms-batch-cols {
  display: grid; grid-template-columns: minmax(0, 1fr) 330px; grid-template-rows: minmax(0, 1fr);
  min-height: 400px; max-height: calc(100vh - 232px);
  margin-top: 14px; border-top: 1px solid var(--line);
}
.lms-batch-col { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
.lms-batch-col + .lms-batch-col { border-left: 1px solid var(--line); }
/* 구성 칸만 세로로 흐른다 — 탭 줄이 한 겹 더 서서 짧은 창에서는 발치(문항·모델)가
   잘린다. 목록 칸의 스크롤과 서로 간섭하지 않게 이 칸에서만 허용한다. */
.lms-batch-col.cfg { overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
.lms-batch-col.cfg > * { flex-shrink: 0; }
/* 흘러도 머리·탭은 남는다 — 지금 어느 묶음을 고치는 중인지가 스크롤에 밀려나면
   아래 체크가 누구 것인지 알 길이 없다. 흐르는 건 구성·문항뿐이다. */
.lms-cfg-top { position: sticky; top: 0; z-index: 1; background: var(--surface); }
/* 칸 이름표 — 검수 화면 칸 머리(.lms-studio-pane-head)와 같은 말투. */
.lms-batch-col-head {
  display: flex; align-items: center; gap: 6px; flex-shrink: 0;
  padding: 11px 13px 7px;
  font-size: 11px; font-weight: 650; color: var(--ink-4); letter-spacing: .06em;
}
.lms-batch-col-head .t { min-width: 0; flex: 1; }
.lms-batch-col-head .cnt { font-size: 10px; font-weight: 500; letter-spacing: 0; color: var(--ink-5); }
.lms-batch-list { padding: 0 6px 8px; }
/* 규격 자리 11줄은 늘 한 덩이로 본다(자기 스크롤 없음) — 넘치면 구성 칸이 통째로
   흐른다. 자리마다 스크롤을 주면 "이 묶음의 구성 한 벌"이 토막나 보인다. */
.lms-batch-list.scroll { flex: 1; min-height: 0; overflow-y: auto; }
/* 차시 목록은 두 칸으로 흘린다 — 넓어진 모달에서 40차시가 거의 한눈에 들어온다.
   세로로 다 채운 뒤 다음 칸으로 넘어가야 번호가 순서대로 읽힌다(grid-auto-flow: column).
   칸당 줄 수는 차시 수에 따라 달라지므로 화면이 grid-template-rows를 얹는다. */
/* 칸은 남는 폭을 반씩 나눠 갖는다(minmax(0,1fr)) — auto로 두면 긴 차시명이 칸을
   밀어내 목록이 옆으로 흐른다. 0을 바닥으로 열어 둬야 줄 안에서 말줄임이 먹는다. */
.lms-batch-list.lessons {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  column-gap: 10px; align-content: start;
}
/* 차시 줄은 트리처럼 겹쳐 들여쓸 게 없다 — 체크를 칸 왼쪽 끝에 붙인다. */
.lms-batch-list .lms-gen-check { margin-left: 5px; }
/* 모달 줄은 눌러 고르는 게 아니라 체크로만 고른다 — 줄에 헛손짓(포인터·하이라이트)을 주지 않는다. */
.lms-batch-list .lms-tree-row { cursor: default; }
.lms-batch-list .lms-tree-row:not(.on):hover { background: transparent; }
/* 꼬리표(생성됨 알약)는 줄이 좁아져도 줄지 않는다 — 줄어드는 건 차시명 쪽이다. */
.lms-batch-list .lms-tree-row > .pill { flex-shrink: 0; }
/* 체크를 푼 자리 — 지우지 않고 흐리게 남긴다(무엇을 뺐는지 그대로 보인다). */
.lms-tree-row.off, .lms-tree-row.off .num { color: var(--ink-5); }
/* 조건부 자리(1차시만 · 2차시부터)와 "영상 편수만큼"을 다는 작은 꼬리표. */
.lms-batch-when {
  flex-shrink: 0; padding: 1px 6px; border-radius: 999px;
  background: var(--surface-2); color: var(--ink-4);
  font-size: 10px; font-weight: 600;
}
/* ── 자리마다 재생시간 (2026-08-22) ────────────────────────────────────────
   출처 캡션(AI·URL만·스크립트·고정)을 걷어낸 자리다 — 그 말은 한 번 읽으면 그만인데
   330px 칸의 오른쪽 끝을 늘 먹고 있었다. 대신 이 칸이 서서 "이 페이지에 몇 분 머무나"를
   묶음마다 정한다(종전에는 생성 뒤 검수 화면에서 페이지를 하나씩 고쳐야 했다).
   폭 54px = 'MM:SS' 다섯 글자 + 좌우 여백. 조건부 배지가 붙는 줄에서도 안 밀린다. */
.lms-pt {
  flex-shrink: 0; width: 54px; padding: 2px 4px;
  border: 1px solid var(--line-strong); border-radius: 6px;
  background: var(--surface); color: var(--ink-2);
  font-family: var(--font-mono); font-size: 10.5px; font-variant-numeric: tabular-nums;
  text-align: center; outline: 0;
  transition: border-color var(--t), box-shadow var(--t), background var(--t), color var(--t);
}
.lms-pt:hover:not(:disabled) { background: var(--surface-2); }
.lms-pt:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); background: var(--surface); }
/* 규격과 다르게 정한 칸 — 훑기만 해도 "내가 바꾼 자리"가 보여야 한다. */
.lms-pt.over { border-color: var(--accent); color: var(--accent); font-weight: 700; }
/* 본영상 — 실측값이라 못 고친다. 점선으로 "칸은 있으나 손댈 수 없다"를 말한다.
   한글이라 글꼴은 본문 것을 쓴다(모노 글꼴에 한글을 태우면 '실 측'처럼 벌어진다). */
.lms-pt.fixed {
  border-style: dashed; border-color: var(--line); background: transparent; color: var(--ink-5);
  font-family: var(--font); font-size: 10px; font-weight: 600; letter-spacing: -.01em; cursor: default;
}
.lms-pt:disabled { cursor: default; }
/* 체크를 푼 자리 — 칸은 없애되 자리는 남긴다. 안 남기면 조건부 배지(1차시만 · 본영상 앞)가
   오른쪽 끝으로 튀어 줄마다 세로줄이 어긋난다. */
.lms-pt-gap { flex-shrink: 0; width: 54px; height: 20px; }

/* 문항 수·모델은 규격 자리 바로 아래에 붙인다 — 발치로 밀어 두면(margin-top:auto)
   창이 커질수록 줄 목록과 사이가 벌어져 남남처럼 보인다. */
.lms-batch-sec {
  flex-shrink: 0; border-top: 1px solid var(--line); padding: 10px 13px;
  display: flex; flex-direction: column; gap: 8px;
}
.lms-batch-note { font-size: 10.5px; color: var(--ink-5); line-height: 1.6; padding: 2px 13px 11px; }
.lms-batch-note b { color: var(--ink-3); font-weight: 650; }
/* 푸터 요약 — 버튼 왼쪽에 밀어 둔다(모달 푸터는 오른쪽 정렬이 규칙). */
.lms-batch .modal-foot { align-items: center; }
.lms-batch .modal-foot .sum { margin-right: auto; min-width: 0; font-size: 11.5px; color: var(--ink-3); }
.lms-batch .modal-foot .sum b { font-weight: 650; color: var(--ink); font-variant-numeric: tabular-nums; }
/* 곁말(건너뛰는 차시 안내) — 요약 숫자보다 한 톤 낮춘다. */
.lms-batch .modal-foot .sum .dim { color: var(--ink-5); }

/* ── 묶음 탭 — 오른쪽 칸이 지금 어느 구성을 보여 주는가 ─────────────────────
   구성이 갈린 차시 무리를 한 모달에서 다루려면 "지금 편집 중인 묶음"이 늘 보여야
   한다. 점(dot)의 색이 곧 그 묶음의 색이고, 왼쪽 목록의 체크·줄 배경·글자 배지가
   같은 색을 쓴다 — 색 하나로 "이 구성이 저 차시들에 걸린다"를 이어 말한다.

   묶음은 최대 스무 개다. 스무 개가 알약으로 늘어설 자리는 없으니 탭 줄이 접힌다:
   여섯 개까지는 이름을 다 적고(● 묶음 A · 12차시), 일곱 개부터는 점+글자+수만
   남긴 압축형(●A 12)으로 갈아입는다. 경계값 6은 실측이다 — 330px 칸에서 완전형은 한
   줄에 두 개가 한계라 일곱 개면 ＋까지 넉 줄이 되어 아래 세 줄 상한을 넘긴다. */
.lms-gtabs {
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px; padding: 0 13px 9px;
  /* 세 줄에서 멈추고 제 안에서 흐른다(24px 칩 셋 + 줄 사이 5px 둘 + 발치 9px = 91px).
     탭이 자라는 대로 두면 sticky 머리가 규격 목록을 덮어 정작 고칠 구성이 안 보인다. */
  max-height: 91px; overflow-y: auto;
  scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent;
}
.lms-gtab {
  display: inline-flex; align-items: center; gap: 6px;
  height: 24px; padding: 0 9px; border: 1px solid var(--line); border-radius: 999px;
  background: var(--surface); color: var(--ink-3);
  font-size: 11px; font-weight: 600; letter-spacing: -.005em; cursor: pointer;
  transition: background var(--t), border-color var(--t), color var(--t);
}
.lms-gtab:hover { background: var(--surface-2); border-color: var(--line-strong); color: var(--ink); }
/* 압축형 — 이름을 줄인 만큼 폭도 줄여 한 줄에 다섯 개가 선다(＋는 제 원을 지킨다). */
.lms-gtabs.tight { gap: 4px; }
.lms-gtabs.tight .lms-gtab { gap: 5px; padding: 0 8px; }
.lms-gtabs.tight .lms-gtab.add { padding: 0; }
.lms-gtab > .dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; background: var(--g, var(--accent)); }
.lms-gtab > .n { font-size: 10px; font-weight: 600; color: var(--ink-5); font-variant-numeric: tabular-nums; }
/* 활성 탭 — 그 묶음 색의 soft 한 겹. 테두리를 지워야 아래 규격 자리와 한 몸으로 보인다. */
.lms-gtab.on { background: color-mix(in oklch, var(--g) 12%, transparent); border-color: transparent; color: var(--g); }
.lms-gtab.on:hover { background: color-mix(in oklch, var(--g) 18%, transparent); color: var(--g); }
.lms-gtab.on > .n { color: inherit; opacity: .7; }
/* 지우개는 활성 탭에만 단다 — 안 보고 있는 묶음이 한 번의 오조준으로 사라지지 않는다.
   탭이 <button>이라 안에 버튼을 넣을 수 없어 <span role="button">으로 세운다. */
.lms-gtab > .x {
  display: grid; place-items: center; width: 15px; height: 15px; margin-right: -4px;
  border-radius: 50%; color: inherit; opacity: .5; cursor: pointer;
  transition: opacity var(--t), background var(--t);
}
.lms-gtab > .x:hover { opacity: 1; background: color-mix(in oklch, var(--g) 22%, transparent); }
/* ＋ — 아직 없는 것을 만드는 자리라 점선 원이다(있는 묶음은 실선 알약). */
.lms-gtab.add { width: 24px; padding: 0; justify-content: center; border-style: dashed; border-radius: 50%; color: var(--ink-4); font-size: 13px; }
.lms-gtab.add:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.lms-gtab.add:disabled { opacity: .45; cursor: default; }
.lms-gtab.add:disabled:hover { background: var(--surface); border-color: var(--line); color: var(--ink-4); }
.lms-gtab:disabled { cursor: default; }

/* ── 묶음 색이 왼쪽 목록까지 간다 ───────────────────────────────────────────
   줄마다 인라인 --g가 얹힌다: 담긴 줄은 그 묶음 색, 아직 안 담긴 줄은 **지금 열린**
   묶음 색이다(손을 얹으면 어디에 담길지가 먼저 보인다). 모달 안으로만 스코프한다 —
   검수 화면 트리의 체크는 묶음과 무관하니 늘 인디고여야 한다.

   20색 팔레트 근거(값은 GROUP_COLORS) — soft(12%) 배경 위 글자 대비 2.8:1 이상(기존
   amber-600이 하한)·OKLab L .44~.67의 중간~진한 톤만 골라 흰 체크가 얹히는 왼쪽 체크
   에서도 버티게 했고, 알파벳 이웃끼리는 색상환에서 최소 39°(평균 100°) 벌려 A와 B가
   닮은 색으로 나란히 서지 않게 인터리브했다(닮은 색끼리는 최소 일곱 글자 거리). */
.lms-batch-cols .lms-gen-check:hover { border-color: var(--g, var(--accent)); }
.lms-batch-cols .lms-gen-check.on { background: var(--g, var(--accent)); border-color: var(--g, var(--accent)); }
.lms-batch-cols .lms-tree-row.on { background: color-mix(in oklch, var(--g, var(--accent)) 9%, transparent); }
/* 이름 뒤 묶음 글자 — 색만으로는 A와 B를 가르지 못하는 눈이 있고(색각), 스크롤 중엔
   옆 탭을 못 보므로 줄 자체가 소속을 말해야 한다. */
.lms-gbadge {
  flex-shrink: 0; height: 15px; min-width: 15px; padding: 0 4px; border-radius: 999px;
  background: color-mix(in oklch, var(--g, var(--accent)) 15%, transparent); color: var(--g, var(--accent));
  font-size: 9.5px; font-weight: 700; letter-spacing: 0; line-height: 15px; text-align: center;
}

/* ── 생성 진행 — 차시별 한 줄 ────────────────────────────────────────────
   한 줄이 곧 한 차시다: [번호] [이름 + 4px 막대] [상태]. 막대만 보고도 어디까지
   갔는지 알고, 오른쪽 알약만 훑어도 완료·실패가 잡힌다. 실패는 그 줄에서 바로
   다시 시도한다 — 전체를 처음부터 돌리지 않는다. */
.lms-run-top { padding: 14px 24px 12px; display: flex; flex-direction: column; gap: 8px; }
.lms-run-top-line { display: flex; align-items: baseline; gap: 7px; font-size: 12.5px; color: var(--ink-4); }
.lms-run-top-line b { font-size: 13.5px; font-weight: 650; color: var(--ink); font-variant-numeric: tabular-nums; }
.lms-run-top-line .r { margin-left: auto; font-size: 11.5px; color: var(--ink-5); font-variant-numeric: tabular-nums; display: inline-flex; align-items: center; gap: 5px; }
/* 고르는 얼굴(.lms-batch-cols)과 키를 맞춘다 — 안 맞추면 [생성]을 누르는 순간
   모달이 껑충 줄었다 늘어난다. 260px = cols의 232 + 진행 요약 54 − 진행 얼굴에서
   빠지는 설명문 26. 564px는 차시 40개짜리 목록 두 칸의 키(592)에 맞춘 상한이다. */
.lms-run-list { height: min(564px, calc(100vh - 260px)); min-height: 280px; overflow-y: auto; padding: 8px 18px 14px; border-top: 1px solid var(--line); }
.lms-run-row { display: flex; align-items: center; gap: 9px; padding: 7px 6px; border-radius: 8px; transition: background var(--t); }
.lms-run-row:hover { background: var(--surface-2); }
.lms-run-row > .num { flex-shrink: 0; font-size: 10.5px; font-weight: 700; color: var(--ink-4); font-variant-numeric: tabular-nums; }
.lms-run-row.wait > .num { color: var(--ink-5); }
.lms-run-cell { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 5px; }
.lms-run-name { font-size: 12.5px; color: var(--ink-2); }
.lms-run-row.wait .lms-run-name { color: var(--ink-5); }
.lms-run-detail { font-size: 10.5px; color: var(--ink-5); }
.lms-run-detail.err { color: var(--danger); }
.lms-run-side { flex-shrink: 0; display: flex; align-items: center; gap: 6px; }
/* 멈춘 자리까지만 붉게 채운다 — 0%로 되돌리면 "어디서 끊겼나"가 사라진다. */
.lms-bar.err > i { background: var(--danger); }

/* ── 꾹 눌러 끌기 — 모달 두 목록의 순서 바꾸기 ──────────────────────────────
   두 목록이 같은 손짓을 쓴다: 줄을 **꾹 눌러**(280ms) 들어 올리고 끌어 놓는다.
   손잡이(⋮⋮)를 따로 달지 않은 이유는 줄마다 체크가 이미 왼쪽 끝을 먹고 있어서다 —
   손잡이를 하나 더 달면 좁은 줄에 잡을 것이 셋(체크·손잡이·글자)이 된다. 대신
   "누르는 시간"으로 가른다: 짧게 누르면 체크 토글, 길게 누르면 순서 바꾸기.
   검수 화면 트리의 끌기(.lms-tree-line.dragging)와 달리 여기선 고스트가 뜬다 —
   두 칸으로 흘린 목록은 제자리만 흐려서는 어느 칸으로 옮기는지가 안 보인다. */
.lms-batch-cols .lms-tree-line {
  cursor: grab;
  /* 세로 스크롤은 살려 두고(pan-y) 가로 스와이프·확대만 막는다 — 목록 자체가 흐른다. */
  touch-action: pan-y; -webkit-user-select: none; user-select: none;
}
/* 들어 올린 자리 — 지우지 않고 흐리게 남긴다(원래 어디 있었는지가 보인다). */
.lms-batch-cols .lms-tree-line.lms-drag-src { opacity: .32; }
/* 커서를 따라가는 고스트 — 줄을 그대로 복제해 살짝 띄운다(scale 1.03 + 그림자).
   들리는 순간의 스케일 트랜지션이 "집었다"는 신호다. */
.lms-drag-ghost {
  position: fixed; z-index: 300; margin: 0; pointer-events: none;
  max-height: 120px; overflow: hidden; opacity: .96;
  border-radius: 9px; background: var(--surface); box-shadow: var(--shadow-lg);
  transform: scale(1.03);
}
/* 놓으면 여기 들어간다 — 액센트 2px. 줄 폭에 맞춰 그어야 두 칸 목록에서 "어느 칸의
   어느 틈"인지가 갈린다. 고스트(300)보다 위에 둔다 — 커서를 따라온 고스트가 바로 그
   틈을 덮고 서므로, 아래에 깔면 선이 통째로 가려진다. 검수 트리의 .lms-drop-line은
   줄 사이에 끼우는 블록이라 이름을 갈라 쓴다(여긴 화면 좌표에 뜨는 조각이다). */
.lms-batch-drop-line {
  position: fixed; z-index: 310; height: 2px; border-radius: 2px;
  background: var(--accent); pointer-events: none;
  box-shadow: 0 0 0 1px color-mix(in oklch, var(--accent) 30%, transparent);
}

/* ══ 콘텐츠 리스트 — 과정 카탈로그 표 (2026-08-21) ══════════════════════════
   LMS 콘텐츠의 두 번째 알약 탭(LmsContentCatalog). 뼈대는 교육 운영대장의 표를
   그대로 빌려 쓴다(.edu-panel > .eg-controls + .edu-table-wrap > .edu-table-scroll) —
   여기 있는 건 "열 15개가 한 화면에 들어가야 한다"와 "표 안에서 바로 고친다"에서
   갈리는 것뿐이다: 줄 높이·칸 여백을 촘촘하게 덮고, 셀 입력과 줄 끝 손잡이를 더한다. */
.lms-catalog { display: flex; flex-direction: column; }
/* 검색·개수는 왼쪽, 손대는 버튼 넷(추가·양식·다운로드·업로드)은 오른쪽 끝에 모은다. */
.lms-catalog-tools { margin-left: auto; display: flex; align-items: center; gap: 7px; }

/* 표 — 운영대장(12.5px·64px 줄)보다 한 단계 촘촘하다. 열이 많아 가로로 구르므로
   과정명만 줄바꿈을 허용하고 나머지는 한 줄로 붙여 폭이 예측되게 둔다. */
table.edu-table.lms-catalog-table { font-size: 11.5px; }
table.edu-table.lms-catalog-table th { padding: 10px 9px; }
table.edu-table.lms-catalog-table td { height: 40px; padding: 5px 9px; }
table.edu-table.lms-catalog-table th.c, table.edu-table.lms-catalog-table td.c { text-align: center; }
table.edu-table.lms-catalog-table th.act, table.edu-table.lms-catalog-table td.act { width: 62px; padding-left: 6px; }
table.edu-table.lms-catalog-table td.name {
  color: var(--ink); font-weight: 550;
  white-space: normal; word-break: keep-all; line-height: 1.45;
}
table.edu-table.lms-catalog-table td.num { font-variant-numeric: tabular-nums; }
/* 아직 아무것도 없거나 검색이 빈손일 때 — 표 폭을 가로지르는 한 줄. */
table.edu-table.lms-catalog-table td.lms-catalog-empty {
  height: 200px; text-align: center; color: var(--ink-4); font-size: 12.5px;
}
/* 곁말(끌어다 놓기 안내) — 본문 아래 한 톤 낮춰 붙인다. 표가 nowrap이라 줄바꿈은
   block으로 낸다(<br>은 white-space에 걸려 붙어 버린다). */
table.edu-table.lms-catalog-table td.lms-catalog-empty .d {
  display: block; margin-top: 7px; color: var(--ink-5); font-size: 11.5px;
}

/* 고치는 줄(강조색) · 새로 넣는 줄(초록) — 지금 어느 줄에 손대고 있는지 색 하나로.
   입력이 들어차므로 칸 여백은 더 줄인다. */
table.edu-table.lms-catalog-table tr.editing td { background: color-mix(in oklch, var(--accent) 6%, var(--surface)); }
table.edu-table.lms-catalog-table tr.adding td { background: color-mix(in oklch, var(--ok) 7%, var(--surface)); }
table.edu-table.lms-catalog-table tr.editing td,
table.edu-table.lms-catalog-table tr.adding td { height: 40px; padding: 4px 5px; }
/* 손대는 줄은 짚어도 색이 바뀌지 않는다 — 편집 색이 곧 그 줄의 상태다. */
table.edu-table.lms-catalog-table tbody tr.editing:hover td { background: color-mix(in oklch, var(--accent) 6%, var(--surface)); }
table.edu-table.lms-catalog-table tbody tr.adding:hover td { background: color-mix(in oklch, var(--ok) 7%, var(--surface)); }

/* 셀 입력 — .input을 그대로 쓰면 여백(9px 12px)이 커서 15열이 한 화면에 안 들어온다. */
.lms-catalog-cell {
  width: 100%; min-width: 44px; padding: 5px 7px;
  border: 1px solid var(--line); border-radius: 6px;
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 11.5px; outline: none;
  transition: border-color var(--t), box-shadow var(--t);
}
.lms-catalog-cell:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.lms-catalog-cell::placeholder { color: var(--ink-5); }
select.lms-catalog-cell { cursor: pointer; }
.lms-catalog-cell[type="number"], .lms-catalog-cell[type="date"] { font-variant-numeric: tabular-nums; }

/* 줄 끝 손잡이(수정·삭제·저장·취소) — 표가 조용해야 읽히므로 평소엔 먹색 한 톤이고
   짚었을 때만 제 뜻(빨강=삭제, 초록=저장)을 드러낸다. */
.lms-catalog-act { display: flex; align-items: center; gap: 2px; }
.lms-catalog-act > button {
  width: 24px; height: 24px; flex-shrink: 0;
  display: grid; place-items: center; padding: 0;
  border: 0; border-radius: 6px; background: transparent; color: var(--ink-5);
  cursor: pointer; transition: background var(--t), color var(--t);
}
.lms-catalog-act > button:hover { background: var(--surface-2); color: var(--ink-2); }
.lms-catalog-act > button.ok:hover { background: color-mix(in oklch, var(--ok) 13%, transparent); color: var(--ok); }
.lms-catalog-act > button.del:hover { background: color-mix(in oklch, var(--danger) 10%, transparent); color: var(--danger); }
.lms-catalog-act > button:disabled { opacity: .4; pointer-events: none; }

/* ───────── 엑셀 끌어다 놓기 ───────── */
/* 표 카드 한 장이 통째로 과녁이다(빈 상태 포함). 자리는 그대로 두고 테두리 색과 글로우만
   갈아 끼운다 — 끌고 오는 동안 표가 밀리면 놓을 자리를 눈으로 좇을 수 없다. 카드는
   테두리를 세 겹(패널 · 검색 줄 · 표) 겹쳐 쓰므로 셋을 함께 물들여야 한 줄로 보인다. */
.lms-catalog-panel { position: relative; transition: border-color var(--t), box-shadow var(--t); }
.lms-catalog-panel.drop { border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.lms-catalog-panel.drop > .eg-controls,
.lms-catalog-panel.drop > .edu-table-wrap { border-color: var(--accent); }

/* 카드 위 덮개 — 마우스를 받지 않는 것이 핵심이다(pointer-events: none). 덮개가 커서를
   가로채면 카드 입장에선 커서가 밖으로 나간 셈이라 dragleave가 떠서 제 손으로 저를
   깜빡인다. 표 머리글이 sticky z:3이라 그보다 위에 서고, 뼈대는 늘 붙어 있고 켜짐만
   토글한다(도우미 판의 .lms-att-dropzone과 같은 규칙). */
.lms-catalog-drop {
  position: absolute; z-index: 4; inset: 0; pointer-events: none;
  display: grid; place-items: center;
  background: color-mix(in oklch, var(--accent) 7%, transparent);
  opacity: 0; visibility: hidden;
  transition: opacity .15s ease, visibility .15s;
}
.lms-catalog-drop.on { opacity: 1; visibility: visible; transition: opacity .15s ease, visibility 0s; }
/* 가운데 카드 — 표가 비쳐 보이므로 한 겹 띄워야 글자가 읽힌다. 표식만 강조색을 쓰고
   글자는 앱 먹색 그대로다(소리치는 자리가 아니다). */
.lms-catalog-drop .card {
  display: flex; align-items: center; gap: 11px;
  padding: 13px 18px 13px 13px; border-radius: 15px;
  background: color-mix(in oklch, var(--surface) 92%, transparent);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
  backdrop-filter: blur(18px) saturate(1.6);
  border: 1px solid color-mix(in oklch, var(--accent) 30%, var(--line));
  box-shadow: 0 2px 6px rgba(15, 15, 15, .05), 0 20px 44px -22px rgba(15, 15, 15, .36);
}
.lms-catalog-drop .card .ic {
  flex-shrink: 0; width: 34px; height: 34px; display: grid; place-items: center;
  border-radius: 11px; background: var(--accent-soft); color: var(--accent);
}
.lms-catalog-drop .card b { display: block; font-size: 12.5px; font-weight: 650; color: var(--ink); }
.lms-catalog-drop .card .d { display: block; margin-top: 2px; font-size: 10.5px; color: var(--ink-5); }
.lms-catalog-drop .card .d .mono { font-size: 9.5px; color: var(--ink-4); }

/* ───────── 마우스 제스처(우클릭 드래그) ───────── */
/* 전체 화면 궤적 + 인식된 동작 버블(화면 중앙). body 포털·pointer-events:none이라
   어떤 화면 위에서도 입력을 가로채지 않는다. z는 앱 최상위 레이어(1000)보다 위. */
.mg-layer { --mg-ink: var(--accent); position: fixed; inset: 0; z-index: 1100; pointer-events: none; transition: opacity .22s ease; }
.mg-layer.out { opacity: 0; }
.mg-trail { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.mg-trail polyline {
  fill: none; stroke: var(--mg-ink); stroke-opacity: .9;
  stroke-width: 3; stroke-linecap: round; stroke-linejoin: round;
  filter: drop-shadow(0 0 7px color-mix(in srgb, var(--mg-ink) 45%, transparent));
}
.mg-label {
  position: fixed; transform: translate(-50%, -50%);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  min-width: 104px; padding: 16px 22px 13px; border-radius: 18px;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-lg);
  color: var(--mg-ink);
  animation: mg-pop .17s cubic-bezier(.2,.8,.2,1) both;
}
@keyframes mg-pop { from { transform: translate(-50%, -50%) scale(.9); opacity: 0; } }
.mg-name { font-size: 12px; font-weight: 600; letter-spacing: .01em; color: var(--ink-3); white-space: nowrap; }

/* ───────── Blazor Static SSR 셸 보정 ───────── */
/* FocusOnNavigate가 페이지 제목(h1)에 포커스를 준다 — 링은 그리지 않는다. */
h1:focus { outline: none; }
/* 접힌 사이드바에서는 내 프로필 버튼의 꺾쇠를 숨긴다(원본은 React 조건부 렌더). */
.shell.compact .sb-user-chevron { display: none; }

/* ───────── 아직 옮기지 않은 모듈의 빈 화면 ───────── */
.empty-module {
  display: grid; justify-items: center;
  margin-top: 8px; padding: 58px 28px;
  border: 1px dashed var(--line-strong); border-radius: var(--radius);
  background: var(--surface-2); text-align: center;
}
.empty-module-icon {
  width: 48px; height: 48px; display: grid; place-items: center; margin-bottom: 14px;
  border: 1px solid var(--line); border-radius: 50%; background: var(--surface); color: var(--ink-4);
}
.empty-module h3 { margin: 0; font-size: 15px; font-weight: 650; }
.empty-module p { max-width: 440px; margin: 8px 0 0; color: var(--ink-3); font-size: 12px; line-height: 1.65; }

/* ───────── 프로필 서랍 (pd-) — 원본 ProfileDrawer.tsx의 인라인 스타일을 클래스로 ───────── */
.pd-bg {
  position: fixed; inset: 0; z-index: 120;
  background: rgba(10,10,10,.32); backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none; transition: opacity .2s;
}
.shell.profile-open .pd-bg { opacity: 1; pointer-events: auto; }
.pd {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 130;
  width: 440px; max-width: 92vw;
  background: var(--bg); border-left: 1px solid var(--line); box-shadow: var(--shadow-lg);
  transform: translateX(100%); transition: transform .35s cubic-bezier(.2,.7,.2,1);
  display: flex; flex-direction: column; overflow: hidden;
}
.shell.profile-open .pd { transform: translateX(0); }
.pd-head { padding: 18px 20px; display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--line); flex-shrink: 0; }
.pd-kicker { font-size: 11px; font-weight: 600; color: var(--ink-4); letter-spacing: .12em; }
.pd-body { flex: 1; overflow-y: auto; padding: 24px 24px 40px; }
.pd-identity { display: flex; gap: 16px; align-items: flex-start; }
.pd-avatar {
  width: 72px; height: 72px; border-radius: 50%; color: #fff;
  display: grid; place-items: center; font-weight: 700; font-size: 26px; letter-spacing: -.04em;
  position: relative; flex-shrink: 0;
}
.pd-avatar.online::after {
  content: ""; position: absolute; bottom: 2px; right: 2px; width: 14px; height: 14px;
  background: #10B981; border-radius: 50%; border: 3px solid var(--bg);
}
.pd-name { font-size: 22px; font-weight: 650; letter-spacing: -.02em; margin: 0; }
.pd-role { font-size: 13px; color: var(--ink-3); margin-top: 4px; }
.pd-email { font-size: 12.5px; color: var(--ink-4); margin-top: 3px; }
.pd-pills { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
.pd-meta {
  display: grid; grid-template-columns: repeat(3, 1fr); margin-top: 22px; padding: 14px 16px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
}
.pd-meta-k { font-size: 10.5px; color: var(--ink-4); letter-spacing: .08em; text-transform: uppercase; font-weight: 600; }
.pd-meta-v { font-size: 13px; font-weight: 550; margin-top: 4px; letter-spacing: -.005em; }
.pd-section { font-size: 10.5px; color: var(--ink-4); letter-spacing: .1em; text-transform: uppercase; font-weight: 600; margin: 28px 0 10px; }
.pd-settings { display: flex; flex-direction: column; gap: 1px; background: var(--surface); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; }
.pd-row {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px; width: 100%;
  border: 0; border-top: 1px solid var(--line); background: transparent;
  color: var(--ink-2); font-size: 13.5px; font-family: inherit; text-align: left; text-decoration: none;
  cursor: pointer; transition: background .15s;
}
.pd-row:first-child { border-top: 0; }
.pd-row[hidden] { display: none; }
/* 데스크톱 앱(WPF + WebView2) 전용·브라우저 전용 조각 — html.desktop-app은 App.razor 머리의 한 줄과 desktop.js가 붙인다. */
html:not(.desktop-app) [data-desktop-only] { display: none !important; }
html.desktop-app [data-web-only] { display: none !important; }
.pd-row:hover { background: var(--surface-3); }
.pd-row:disabled { opacity: .5; cursor: default; }
.pd-row:disabled:hover { background: transparent; }
.pd-row.static { cursor: default; }
.pd-row.static:hover { background: transparent; }
.pd-row-text { flex: 1; text-align: left; }
.pd-row-sub { font-size: 11px; color: var(--ink-4); margin-top: 2px; }
.pd-switch {
  width: 40px; height: 23px; flex-shrink: 0; border-radius: 999px; border: none; padding: 0; position: relative;
  background: var(--line-strong); cursor: pointer; transition: background .18s;
}
.pd-switch.on { background: var(--accent); }
.pd-switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 19px; height: 19px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: left .18s;
}
.pd-switch.on::after { left: 19px; }
.pd-admin {
  display: flex; align-items: center; gap: 12px; margin-top: 20px; padding: 13px 16px;
  background: var(--ink); color: var(--bg); border-radius: 12px; text-decoration: none; transition: background .15s;
}
.pd-admin:hover { background: var(--ink-2); }
.pd-admin-icon { width: 30px; height: 30px; border-radius: 8px; flex-shrink: 0; background: rgba(255,255,255,.12); display: grid; place-items: center; }
.pd-admin-title { font-size: 13.5px; font-weight: 600; letter-spacing: -.01em; }
.pd-admin-sub { font-size: 11.5px; opacity: .65; margin-top: 1px; }
.pd-logout {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%; margin-top: 10px; padding: 12px 16px;
  border: 1px solid var(--line); background: transparent; border-radius: 10px;
  color: var(--ink-3); font-size: 13px; font-weight: 500; font-family: inherit; cursor: pointer; transition: all .15s;
}
.pd-logout:hover { background: var(--surface-2); color: var(--ink); }
.pd-logout:disabled { opacity: .5; cursor: default; }
.pd-logout:disabled:hover { background: transparent; color: var(--ink-3); }

/* 모바일 서랍의 배경막 — 원본은 React가 .sb-overlay에 on 클래스를 따로 붙였지만,
   여기서는 셸 상태 하나(.shell.nav-open)로 서랍과 배경막을 함께 켠다. */
.shell.nav-open .sb-overlay { opacity: 1; pointer-events: auto; }
