<script>
  // 문서 상세 /documents/[id] — 확정 시안(d3-deepened) 스타일을 그대로 포팅, 데이터만 바인딩.
  // 데스크탑: 상단 헤더 띠 + [좌 절 트리(색바+연결선)][중 절 집중 뷰][우 슬림 레일]. 절 없으면 fallback.
  // 모바일: 헤더 + 나란한 토글 pill(절구조|인사이트) + 본문 절 카드 연속(+탭 이동). 편집/필기/네비 보존.
  import { onMount } from 'svelte';
  import { page } from '$app/stores';
  import { goto } from '$app/navigation';
  import { api, getAccessToken } from '$lib/api';
  import { isMdSuccess } from '$lib/utils/mdStatus';
  import { addToast } from '$lib/stores/toast';
  import { marked } from 'marked';
  import DOMPurify from 'dompurify';
  import { ChevronRight, FileText } from 'lucide-svelte';
  import Button from '$lib/components/ui/Button.svelte';
  import EmptyState from '$lib/components/ui/EmptyState.svelte';
  import Skeleton from '$lib/components/ui/Skeleton.svelte';
  import HandwriteCanvas from '$lib/components/HandwriteCanvas.svelte';
  import MarkdownDoc from '$lib/components/MarkdownDoc.svelte';
  import { renderDocMarkdown } from '$lib/utils/docMarkdown';
  import MarkdownStatusBadge from '$lib/components/MarkdownStatusBadge.svelte';
  import NoteEditor from '$lib/components/editors/NoteEditor.svelte';
  import EditUrlEditor from '$lib/components/editors/EditUrlEditor.svelte';
  import TagsEditor from '$lib/components/editors/TagsEditor.svelte';
  import AIClassificationEditor from '$lib/components/editors/AIClassificationEditor.svelte';
  import LibraryPathEditor from '$lib/components/editors/LibraryPathEditor.svelte';
  import DocumentDangerZone from '$lib/components/editors/DocumentDangerZone.svelte';
  import { untrack } from 'svelte';
  import { cleanHeading, pathSegments, sectionTypeLabel, collapseWindows, partitionOutlineItems, partGroupViews, groupKeyByChunkId } from '$lib/utils/headingPath';
  import { domainLabel } from '$lib/utils/domainSlug';

  marked.use({ mangle: false, headerIds: false });
  function renderMd(text) {
    return DOMPurify.sanitize(marked(text || ''), {
      USE_PROFILES: { html: true }, FORBID_TAGS: ['style', 'script'], FORBID_ATTR: ['onerror', 'onclick'], ALLOW_UNKNOWN_PROTOCOLS: false,
    });
  }

  let doc = $state(null);
  let loading = $state(true);
  let error = $state(null);
  let rawMarkdown = $state('');
  let docId = $derived($page.params.id);

  // 필기
  let noteOpen = $state(false);
  let noteStrokes = $state(null);
  let noteLoaded = $state(false);
  async function ensureNoteLoaded() {
    if (noteLoaded) return;
    try { const r = await api(`/documents/${docId}/note`); noteStrokes = r.strokes_json && r.strokes_json.strokes ? r.strokes_json : { version: 1, strokes: [] }; }
    catch { noteStrokes = { version: 1, strokes: [] }; }
    noteLoaded = true;
  }
  async function saveNote(s) { try { await api(`/documents/${docId}/note`, { method: 'PUT', body: JSON.stringify({ strokes_json: s }) }); } catch (e) { console.warn(e); } }
  async function toggleNote() { if (!noteOpen) await ensureNoteLoaded(); noteOpen = !noteOpen; }

  // 인접 자료
  let neighbors = $state({ prev: null, next: null });
  async function loadNeighbors() { try { neighbors = await api(`/documents/${docId}/library-neighbors`); } catch { neighbors = { prev: null, next: null }; } }
  async function readAndGoNext() {
    try { await api(`/documents/${docId}/read`, { method: 'POST' }); addToast('success', '1회독 완료'); }
    catch (err) { addToast('error', err?.detail || '회독 기록 실패'); return; }
    if (neighbors.next) goto(`/documents/${neighbors.next.id}`);
  }

  // 절 목차
  let sections = $state([]);
  let hasSections = $derived(sections.length > 0);
  // 과대 절은 builder 가 window 조각(같은 제목·is_leaf)으로 분해하고 부모를 heading 만 남긴 split-parent 로
  // 강등한다(예: 5180 = 27개 논리 절 → 562 window). raw sections 를 그대로 그리면 동일 제목 수백 행으로
  // 파편화되므로, collapseWindows 로 논리 절 1개(대표=split-parent, bodyText=window 본문 합본)로 합친다.
  let outline = $derived(collapseWindows(sections));
  // Part 접이 트리(ASME 등 hasParts): 같은 outline 인스턴스를 front-matter/PART 로 재배치(재-collapse 없음
  // → selectedSectionId/focusView 정합). flat 1030 → front-matter 단일그룹 + ~14 PART 접이. (D8)
  let treePart = $derived(partitionOutlineItems(outline));
  let treeGroups = $derived(treePart.hasParts ? partGroupViews(treePart) : null);
  let treeGroupIndex = $derived(treeGroups ? groupKeyByChunkId(treeGroups) : null);
  let treeExpanded = $state({}); // key 없으면 접힘(기본 전부 접힘). Svelte5 deep-proxy 반응형.
  function toggleTreeGroup(key) { treeExpanded[key] = !treeExpanded[key]; }
  // sections 로딩 완료 플래그 — 미완 동안 fallback 풀-문서 뷰어를 띄우면, 곧 절뷰로 교체되며
  // 풀-문서 이미지가 '살짝 보였다 사라지는' 플래시가 난다(절 보유 문서). 로딩 중엔 skeleton.
  let sectionsLoaded = $state(false);
  async function loadSections() {
    const reqId = docId;
    try { const r = await api(`/documents/${reqId}/sections`); if (reqId === docId) sections = r?.sections ?? []; }
    catch { if (reqId === docId) sections = []; }
    finally { if (reqId === docId) sectionsLoaded = true; }
  }

  onMount(async () => {
    try {
      doc = await api(`/documents/${docId}`);
      const vt = doc.source_channel === 'news' ? 'article' : getViewerType(doc.file_format);
      if ((vt === 'markdown' || vt === 'hwp-markdown') && !doc.extracted_text) {
        try { const resp = await fetch(`/api/documents/${docId}/file?token=${getAccessToken()}`); if (resp.ok) rawMarkdown = await resp.text(); } catch { rawMarkdown = ''; }
      }
    } catch (err) { error = err?.status === 404 ? 'not_found' : 'network'; }
    finally { loading = false; }
    if (doc && doc.category === 'library') loadNeighbors();
    if (doc) loadSections();
  });

  let viewerType = $derived(doc ? (doc.source_channel === 'news' ? 'article' : getViewerType(doc.file_format)) : 'none');
  let canShowMarkdown = $derived(!!(isMdSuccess(doc?.md_status) && doc?.md_content?.trim()));
  // 절 본문은 청크 text(절별 원문)에서 오므로 md_content 성공/존재와 무관.
  // hasSections 만으로 절뷰 사용 → partial / 대형 split(md_content 5만 자 절단) 문서도 절뷰 표시.
  let useSectionView = $derived(hasSections);

  let pdfViewMode = $state('markdown');
  let lastDocId = $state(null);
  $effect(() => {
    if (!doc) return;
    if (doc.id !== lastDocId) { lastDocId = doc.id; pdfViewMode = canShowMarkdown ? 'markdown' : 'pdf'; }
    if (!canShowMarkdown && pdfViewMode === 'markdown') pdfViewMode = 'pdf';
  });

  function getViewerType(format) {
    if (['md', 'txt', 'csv', 'html'].includes(format)) return 'markdown';
    if (format === 'pdf') return 'pdf';
    if (['hwp', 'hwpx'].includes(format)) return 'hwp-markdown';
    if (['odoc', 'osheet'].includes(format)) return 'synology';
    if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(format)) return 'image';
    return 'unsupported';
  }

  // 절 집중/모바일 상태
  let selectedSectionId = $state(null);
  let mTree = $state(false);
  let mIns = $state(false);
  let manageOpen = $state(false);
  // 기본 선택 = 첫 본문 Part 의 첫 절(front-matter TOC 가 아니라 실제 내용으로 진입, front-matter 접힘 유지).
  let defaultSelId = $derived.by(() => {
    // 딥링크 진입: ?section=<chunk_id> 가 outline 에 있으면 그 절로 (/clause 절 바로가기 → 해당 절 표시).
    const deep = Number($page.url.searchParams.get('section'));
    if (deep && outline.some((it) => it.section.chunk_id === deep)) return deep;
    if (treeGroups) {
      const body = treeGroups.find((g) => !g.isFrontMatter);
      if (body && body.items.length) return body.items[0].section.chunk_id;
    }
    return outline[0]?.section.chunk_id ?? null;
  });
  $effect(() => { if (outline.length && !outline.some((it) => it.section.chunk_id === selectedSectionId)) selectedSectionId = defaultSelId; });
  // 문서가 바뀌면(sections 교체) Part 접이·모바일 본문 펼침 상태 리셋 — 문서 간 PART 라벨/chunk_id 가
  // 겹쳐 이전 상태가 이월되는 것 차단(기본 전부 접힘 보존). ※ 같은 컴포넌트 인스턴스로 client 네비 시
  // sections 가 재로딩될 때만 발화 — 현재 [id] 페이지는 onMount 1회 로딩이라 SPA prev/next 미reload 는
  // 선존 별도 이슈(D8 범위 밖, 사용자 보고 대상).
  $effect(() => {
    void sections;
    untrack(() => { treeExpanded = {}; mBodyOpen = {}; });
  });
  // 선택 절의 조상 Part 를 펼침(prev/next·딥링크 진입 시 트리에서 자동 노출). untrack=쓰기 자기재발화 차단.
  $effect(() => {
    const sel = selectedSectionId;
    const idx = treeGroupIndex;
    if (sel == null || !idx) return;
    const gk = idx.get(sel);
    if (gk) untrack(() => { treeExpanded[gk] = true; });
  });
  // selectedSectionId 미설정(초기) 시 defaultSelId(첫 본문 Part)로 바로 해석 — outline[0](표지/front-matter)
  // 를 잠깐 렌더했다 effect 가 defaultSelId 로 바꾸는 절뷰 내부 플래시 차단.
  let selectedItem = $derived(outline.find((it) => it.section.chunk_id === (selectedSectionId ?? defaultSelId)) ?? outline[0] ?? null);
  let selectedSection = $derived(selectedItem?.section ?? null);
  let selIdx = $derived(outline.findIndex((it) => it.section.chunk_id === selectedItem?.section?.chunk_id));
  // 절 본문 = 청크 원문(it.bodyText, window 조각 합본) 직접 렌더. 과거 char_start 로 md_content 를
  // 슬라이스했으나, 대형 split 문서는 md_content 가 앞 5만 자만 보존되고 char_start 도 NULL 이라 본문이
  // 비었다. 청크 text 는 절 전체를 담으므로(절 보유 문서 344개, 본문 합 평균 68KB·max 1.6MB) 그대로 렌더.
  function bodyHtml(it) { return it?.bodyText ? renderMd(it.bodyText) : ''; }
  let selectedBodyHtml = $derived(bodyHtml(selectedItem));
  // 모바일 연속 카드: 본문은 '본문 보기' 펼칠 때만 파싱(논리 절 수백 개 × marked 즉시 파싱 회피).
  let mBodyOpen = $state({});

  // 절 유형 색 (시안: 정의 청 / 절차 올리브 / 요건 황)
  const TYPE_META = {
    definition: { label: '정의', en: 'definition', color: '#2f7d8f' },
    procedure: { label: '절차', en: 'procedure', color: '#7a8b3f' },
    requirement: { label: '요건', en: 'requirement', color: '#b5840a' },
  };
  function typeMeta(t) { return TYPE_META[t] ?? { label: sectionTypeLabel(t) || '', en: t || '', color: '#9aa090' }; }
  function isLowConf(c) { return c != null && c < 0.5; }
  function isMidLow(c) { return c != null && c < 0.6; }
  function confColor(c) { return c == null ? '#9aa090' : c < 0.6 ? '#b5840a' : '#1f9d6b'; }
  function secTitle(s) { return cleanHeading(s.section_title) || pathSegments(s.heading_path).at(-1) || '(제목 없음)'; }
  function secDepth(s) { return Math.max(0, (s.level ?? 1) - 1); }
  function confPct(c) { return c == null ? 0 : Math.round(c * 100); }

  // 도메인 색 (시안 도메인 팔레트)
  const DOMAIN_COLOR = { Industrial_Safety: '#b5840a', Engineering: '#2f7d8f', Programming: '#3d7256', General: '#7a8b3f', Reference: '#8a6a3f', Philosophy: '#7a6a9b' };
  function domainColor(d) { return DOMAIN_COLOR[(d || '').split('/')[0]] ?? '#697061'; }
  function fmtColor(f) { return f === 'pdf' ? '#c0564a' : f === 'md' ? '#5a8f7a' : ['m4a', 'mp3', 'wav'].includes(f) ? '#8a6aa5' : f === 'html' ? '#c2911f' : '#697061'; }

  let quality = $derived(doc?.md_extraction_quality?.metrics ?? doc?.md_extraction_quality ?? null);

  function copyLink() {
    navigator.clipboard.writeText(`${window.location.origin}/documents/${docId}`).then(() => addToast('success', '링크 복사됨')).catch(() => addToast('error', '복사 실패'));
  }
  function downloadOriginal() { window.open(`/api/documents/${docId}/file?token=${getAccessToken()}&download=true`); }
  function handleDocDelete() { addToast('success', '문서가 삭제되어 목록으로 이동합니다.'); goto('/documents'); }
</script>

<!-- ════ 좌 트리 (시안: 색바 + 연결선 + 활성 + 저신뢰 경고) ════ -->
{#snippet treeNav(jumpMode)}
  <div class="d3tree" style="font-size:14px;">
    <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:9px;">
      <div style="font-size:12px;font-weight:700;color:#697061;letter-spacing:.4px;">절 구조</div>
      <span style="font-size:10.5px;color:#9aa090;font-variant-numeric:tabular-nums;">{outline.length}절</span>
    </div>
    <div style="display:flex;flex-wrap:wrap;gap:6px 8px;margin-bottom:11px;padding-bottom:10px;border-bottom:1px solid #dde3d6;">
      <span style="display:inline-flex;align-items:center;gap:4px;font-size:10px;color:#697061;"><span style="width:8px;height:8px;border-radius:2px;background:#2f7d8f;"></span>정의</span>
      <span style="display:inline-flex;align-items:center;gap:4px;font-size:10px;color:#697061;"><span style="width:8px;height:8px;border-radius:2px;background:#7a8b3f;"></span>절차</span>
      <span style="display:inline-flex;align-items:center;gap:4px;font-size:10px;color:#697061;"><span style="width:8px;height:8px;border-radius:2px;background:#b5840a;"></span>요건</span>
    </div>
    {#snippet treeNode(it)}
      {@const s = it.section}
      {@const tm = typeMeta(it.sectionType)}
      {@const active = !jumpMode && s.chunk_id === selectedSection?.chunk_id}
      {@const child = secDepth(s) > 0}
      {@const low = isMidLow(it.confidence)}
      <svelte:element this={jumpMode ? 'a' : 'div'} href={jumpMode ? `#m-sec-${s.chunk_id}` : undefined}
        role={jumpMode ? undefined : 'button'} tabindex={jumpMode ? undefined : 0}
        onclick={() => !jumpMode && (selectedSectionId = s.chunk_id)}
        onkeydown={(e) => { if (!jumpMode && (e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); selectedSectionId = s.chunk_id; } }}
        class="d3node {child ? 'd3child' : ''} {active ? 'd3active' : ''}"
        style="display:block;border:1px solid {active ? '#4f8a6b' : low ? '#e7d49a' : 'transparent'};border-radius:9px;padding:{child ? '6px 8px' : '7px 8px'};margin-bottom:2px;{low ? 'background:#fbf6e6;' : ''}text-decoration:none;cursor:pointer;">
        <div style="display:flex;align-items:center;gap:7px;">
          <span style="width:3px;height:{child ? '13px' : '16px'};border-radius:2px;background:{tm.color};flex-shrink:0;"></span>
          <span class="d3title" style="font-size:{child ? '11.5px' : '12.5px'};flex:1;min-width:0;{child ? 'color:#697061;' : ''}{active ? 'color:#3d7256;font-weight:600;' : ''}overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{secTitle(s)}</span>
          {#if low}
            <span class="d3warn" title="저신뢰 절" style="display:inline-flex;width:14px;height:14px;border-radius:50%;background:#b5840a;color:#fff;align-items:center;justify-content:center;font-size:9px;font-weight:700;flex-shrink:0;">!</span>
          {:else if !child}
            <span title="신뢰도 {it.confidence != null ? it.confidence.toFixed(2) : '—'}" style="width:7px;height:7px;border-radius:50%;background:{confColor(it.confidence)};flex-shrink:0;"></span>
          {/if}
        </div>
      </svelte:element>
    {/snippet}

    {#if treeGroups}
      <!-- Part 접이(ASME 등): front-matter 단일그룹 + PART 접이, 기본 접힘. 선택/딥링크 시 조상 Part auto-expand. -->
      {#each treeGroups as g (g.key)}
        {@const isOpen = !!treeExpanded[g.key]}
        <button type="button" class="d3grp" aria-expanded={isOpen} onclick={() => toggleTreeGroup(g.key)}
          style="display:flex;align-items:center;gap:7px;width:100%;text-align:left;background:none;border:none;cursor:pointer;border-radius:8px;padding:6px 8px;margin:4px 0 1px;">
          <span style="transition:transform .16s;transform:rotate({isOpen ? 90 : 0}deg);color:#9aa090;font-weight:700;font-size:12px;flex-shrink:0;">›</span>
          <span style="flex:1;min-width:0;font-size:11px;font-weight:700;color:{g.isFrontMatter ? '#9aa090' : '#697061'};letter-spacing:.3px;text-transform:uppercase;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{g.label}</span>
          <span style="font-size:10px;color:#9aa090;font-variant-numeric:tabular-nums;flex-shrink:0;">{g.items.length}</span>
        </button>
        {#if isOpen}
          {#each g.items as it (it.section.chunk_id)}{@render treeNode(it)}{/each}
        {/if}
      {/each}
    {:else}
      {#each outline as it (it.section.chunk_id)}{@render treeNode(it)}{/each}
    {/if}
    {#if quality}
      <div style="margin-top:12px;padding-top:10px;border-top:1px solid #dde3d6;">
        <div style="font-size:10.5px;font-weight:700;color:#697061;margin-bottom:7px;letter-spacing:.3px;">추출 품질</div>
        <div style="display:grid;grid-template-columns:1fr 1fr;gap:5px;font-size:10.5px;color:#697061;font-variant-numeric:tabular-nums;">
          {#if quality.headings != null}<span>headings <b style="color:#23291f;">{quality.headings}</b></span>{/if}
          {#if quality.tables != null}<span>tables <b style="color:#23291f;">{quality.tables}</b></span>{/if}
          {#if quality.images != null}<span>images <b style="color:#23291f;">{quality.images}</b></span>{/if}
        </div>
      </div>
    {/if}
  </div>
{/snippet}

<!-- ════ 절 집중 뷰 (데스크탑 중앙) ════ -->
{#snippet focusView()}
  {#if selectedSection}
    {@const tm = typeMeta(selectedItem?.sectionType)}
    {@const conf = selectedItem?.confidence ?? null}
    {@const summaries = selectedItem?.summaries ?? []}
    <div style="display:flex;align-items:center;gap:6px;font-size:12px;color:#9aa090;margin-bottom:12px;flex-wrap:wrap;">
      <span class="truncate" style="max-width:200px;">{doc.title}</span>
      {#each pathSegments(selectedSection.heading_path) as seg}<span style="color:#c8d6c0;">/</span><span style="color:#697061;font-weight:600;">{seg}</span>{/each}
    </div>
    <div style="display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin-bottom:13px;">
      <h2 style="margin:0;font-size:22px;font-weight:700;color:#23291f;line-height:1.3;flex:1;min-width:180px;">{secTitle(selectedSection)}</h2>
      {#if tm.label}<span style="display:inline-flex;align-items:center;gap:5px;padding:4px 11px;border-radius:999px;background:{tm.color}1a;border:1px solid {tm.color}55;font-size:12px;color:{tm.color};font-weight:600;"><span style="width:8px;height:8px;border-radius:2px;background:{tm.color};"></span>{tm.label} {tm.en}</span>{/if}
    </div>
    {#if conf != null}
      <div style="display:flex;align-items:center;gap:9px;margin-bottom:18px;">
        <span style="font-size:11px;color:#697061;font-weight:600;flex-shrink:0;">신뢰도</span>
        <div style="flex:1;max-width:300px;height:7px;border-radius:999px;background:#e3ebdf;overflow:hidden;"><div style="width:{confPct(conf)}%;height:100%;background:{confColor(conf)};border-radius:999px;"></div></div>
        <span style="font-size:13px;font-weight:700;color:{confColor(conf)};font-variant-numeric:tabular-nums;flex-shrink:0;">{conf.toFixed(2)}</span>
      </div>
    {/if}
    {#if isLowConf(conf)}
      <div style="display:flex;align-items:flex-start;gap:8px;background:#faf3e2;border:1px solid #ecdca3;border-radius:10px;padding:10px 12px;margin-bottom:16px;font-size:12.5px;color:#8a6306;"><span style="flex-shrink:0;width:16px;height:16px;border-radius:50%;border:1.5px solid #b5840a;color:#b5840a;font-size:10px;font-weight:800;display:inline-flex;align-items:center;justify-content:center;margin-top:1px;">!</span><span>저신뢰 절 — 표·수식 추출이 불완전할 수 있습니다. 정확한 내용은 원본을 확인하세요.</span></div>
    {/if}
    {#if summaries.length}
      <div style="background:#ecf0e8;border-left:3px solid #4f8a6b;border-radius:0 10px 10px 0;padding:14px 16px;margin-bottom:20px;">
        <div style="font-size:10.5px;font-weight:700;color:#3d7256;letter-spacing:.6px;margin-bottom:6px;">절 요약{#if summaries.length > 1} · {summaries.length}개 부분{/if}</div>
        {#if summaries.length === 1}
          <div style="font-size:15.5px;line-height:1.6;color:#23291f;white-space:pre-line;">{summaries[0]}</div>
        {:else}
          <ul style="margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:8px;">
            {#each summaries as sm, i}<li style="font-size:13.5px;line-height:1.55;color:#23291f;display:flex;gap:8px;"><span style="flex-shrink:0;color:#7a8b3f;font-weight:700;font-variant-numeric:tabular-nums;">{i + 1}</span><span style="white-space:pre-line;">{sm}</span></li>{/each}
          </ul>
        {/if}
      </div>
    {/if}
    {#if selectedItem?.bodyText}
      <MarkdownDoc documentId={doc.id} mdContent={selectedItem.bodyText} mdStatus={null} class="prose prose-base max-w-none text-text" />
    {:else}
      <p style="color:#9aa090;font-size:14px;font-style:italic;">이 절의 본문은 추출되지 않았습니다. 헤더의 '원본'에서 확인하세요.</p>
    {/if}
    <div style="display:flex;justify-content:space-between;gap:10px;margin-top:20px;padding-top:14px;border-top:1px solid #dde3d6;">
      {#if selIdx > 0}
        {@const pv = outline[selIdx - 1].section}
        <button type="button" onclick={() => (selectedSectionId = pv.chunk_id)} style="font-size:12px;color:#697061;border:1px solid #dde3d6;border-radius:9px;padding:8px 12px;background:#fff;cursor:pointer;">← {secTitle(pv)}</button>
      {:else}<span></span>{/if}
      {#if selIdx >= 0 && selIdx < outline.length - 1}
        {@const nxIt = outline[selIdx + 1]}
        {@const nx = nxIt.section}
        <button type="button" onclick={() => (selectedSectionId = nx.chunk_id)} style="font-size:12px;color:{isMidLow(nxIt.confidence) ? '#8a6306' : '#697061'};border:1px solid {isMidLow(nxIt.confidence) ? '#e7d49a' : '#dde3d6'};border-radius:9px;padding:8px 12px;background:#fff;cursor:pointer;display:inline-flex;align-items:center;gap:6px;">{#if isMidLow(nxIt.confidence)}<span style="display:inline-flex;width:13px;height:13px;border-radius:50%;background:#b5840a;color:#fff;align-items:center;justify-content:center;font-size:8px;font-weight:700;">!</span>{/if}{secTitle(nx)} →</button>
      {:else}<span></span>{/if}
    </div>
  {/if}
{/snippet}

<!-- ════ 우 슬림 레일 (시안 카드 스타일) ════ -->
{#snippet rail()}
  <div style="display:flex;flex-direction:column;gap:11px;font-size:14px;">
    {#if doc.ai_tldr || doc.ai_summary}
      <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:13px;">
        <div style="font-size:10.5px;font-weight:700;color:#697061;letter-spacing:.4px;margin-bottom:7px;">TL;DR</div>
        <div class="summary-md" style="font-size:12px;line-height:1.5;color:#23291f;">{@html renderDocMarkdown(doc.ai_tldr || doc.ai_summary)}</div>
      </div>
    {/if}
    {#if doc.ai_bullets && doc.ai_bullets.length}
      <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:13px;">
        <div style="font-size:10.5px;font-weight:700;color:#697061;letter-spacing:.4px;margin-bottom:8px;">핵심점</div>
        <ul style="margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:7px;">
          {#each doc.ai_bullets as b}<li style="font-size:12px;line-height:1.4;display:flex;gap:6px;"><span style="color:#b5840a;font-weight:700;flex-shrink:0;">·</span><span style="flex:1;min-width:0;color:#23291f;">{b}</span></li>{/each}
        </ul>
      </div>
    {/if}
    {#if doc.ai_detail_summary}
      <div style="background:#f4f7f1;border:1px solid #c8d6c0;border-radius:14px;padding:13px;">
        <div style="display:flex;align-items:center;gap:6px;margin-bottom:7px;">
          <span style="font-size:10.5px;font-weight:700;color:#3d7256;letter-spacing:.4px;">심층</span>
          {#if doc.ai_analysis_tier === 'deep'}<span style="font-size:9px;color:#fff;background:#4f8a6b;border-radius:999px;padding:1px 7px;font-weight:600;">DEEP</span>{/if}
        </div>
        <div style="font-size:11.5px;line-height:1.5;color:#23291f;white-space:pre-line;">{doc.ai_detail_summary}</div>
      </div>
    {/if}
    {#if doc.ai_inconsistencies && doc.ai_inconsistencies.length}
      <div style="background:#fbf6e6;border:1px solid #e7d49a;border-radius:14px;padding:13px;">
        <div style="font-size:10.5px;font-weight:700;color:#8a6306;letter-spacing:.4px;margin-bottom:7px;">불일치 {doc.ai_inconsistencies.length}</div>
        <ul style="margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:5px;">{#each doc.ai_inconsistencies as inc}<li style="font-size:11.5px;line-height:1.45;color:#23291f;">· {typeof inc === 'string' ? inc : inc.desc || inc.kind}</li>{/each}</ul>
      </div>
    {/if}
    {#if doc.ai_domain}
      <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:13px;">
        <div style="font-size:10.5px;font-weight:700;color:#697061;letter-spacing:.4px;margin-bottom:8px;">분류</div>
        <div style="display:flex;flex-direction:column;gap:6px;font-size:11.5px;">
          <div style="display:flex;justify-content:space-between;gap:8px;"><span style="color:#697061;">도메인</span><span style="display:inline-flex;align-items:center;gap:5px;color:#23291f;font-weight:600;text-align:right;"><span style="width:7px;height:7px;border-radius:50%;background:{domainColor(doc.ai_domain)};"></span>{domainLabel(doc.ai_domain)}</span></div>
          {#if doc.ai_sub_group}<div style="display:flex;justify-content:space-between;gap:8px;"><span style="color:#697061;">하위</span><span style="color:#23291f;font-weight:600;">{doc.ai_sub_group}</span></div>{/if}
          {#if doc.ai_analysis_tier}<div style="display:flex;justify-content:space-between;gap:8px;"><span style="color:#697061;">tier</span><span style="color:#3d7256;font-weight:600;">{doc.ai_analysis_tier}</span></div>{/if}
          {#if doc.ai_confidence != null}<div style="display:flex;justify-content:space-between;gap:8px;"><span style="color:#697061;">신뢰도</span><span style="color:#1f9d6b;font-weight:700;font-variant-numeric:tabular-nums;">{doc.ai_confidence.toFixed(2)}</span></div>{/if}
        </div>
      </div>
    {/if}
    {#if doc.ai_tags && doc.ai_tags.length}
      <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:13px;">
        <div style="font-size:10.5px;font-weight:700;color:#697061;letter-spacing:.4px;margin-bottom:8px;">태그</div>
        <div style="display:flex;flex-wrap:wrap;gap:5px;">{#each doc.ai_tags as t}<span style="font-size:11px;padding:3px 8px;border-radius:999px;background:#fff;border:1px solid #dde3d6;color:#697061;">{t}</span>{/each}</div>
      </div>
    {/if}
    <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:13px;">
      <div style="font-size:10.5px;font-weight:700;color:#697061;letter-spacing:.4px;margin-bottom:6px;">관련 문서</div>
      <div style="font-size:11px;color:#9aa090;line-height:1.5;">벡터 유사도 기반 — 준비 중</div>
    </div>
  </div>
{/snippet}

<!-- ════ 절 카드 (모바일 연속 본문) ════ -->
{#snippet sectionCard(it)}
  {@const s = it.section}
  {@const tm = typeMeta(it.sectionType)}
  <div id="m-sec-{s.chunk_id}" style="scroll-margin-top:12px;background:#f4f7f1;border:1px solid {isLowConf(it.confidence) ? '#e7d49a' : '#dde3d6'};border-radius:14px;padding:14px 15px;">
    <div style="display:flex;align-items:center;gap:7px;margin-bottom:7px;">
      <h2 style="margin:0;font-size:16px;font-weight:700;color:#23291f;flex:1;min-width:0;line-height:1.3;">{secTitle(s)}</h2>
      {#if tm.label}<span style="flex-shrink:0;font-size:10.5px;font-weight:650;padding:2px 8px;border-radius:999px;background:{tm.color}1a;color:{tm.color};white-space:nowrap;">{tm.label}</span>{/if}
    </div>
    {#if isLowConf(it.confidence)}
      <div style="display:flex;align-items:flex-start;gap:7px;background:#faf3e2;border:1px solid #ecdca3;border-radius:9px;padding:8px 10px;margin-bottom:10px;font-size:12px;color:#8a6306;"><span style="flex-shrink:0;width:15px;height:15px;border-radius:50%;border:1.5px solid #b5840a;color:#b5840a;font-size:10px;font-weight:800;display:inline-flex;align-items:center;justify-content:center;margin-top:1px;">!</span><span>저신뢰 — 표·수식 추출 불완전, 원본 확인 권장</span></div>
    {/if}
    {#if it.summaries.length}
      <div style="border-left:3px solid #4f8a6b;background:#ecf0e8;border-radius:0 8px 8px 0;padding:9px 12px;margin-bottom:12px;">
        <div style="font-size:9.5px;font-weight:700;color:#3d7256;letter-spacing:.5px;margin-bottom:3px;">절 요약{#if it.summaries.length > 1} · {it.summaries.length}개 부분{/if}</div>
        {#if it.summaries.length === 1}
          <div style="font-size:13.5px;line-height:1.55;color:#23291f;white-space:pre-line;">{it.summaries[0]}</div>
        {:else}
          <ul style="margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:6px;">{#each it.summaries as sm, i}<li style="font-size:12.5px;line-height:1.5;color:#23291f;display:flex;gap:6px;"><span style="flex-shrink:0;color:#7a8b3f;font-weight:700;font-variant-numeric:tabular-nums;">{i + 1}</span><span style="white-space:pre-line;">{sm}</span></li>{/each}</ul>
        {/if}
      </div>
    {/if}
    {#if it.bodyText}
      <details class="m-secbody" ontoggle={(e) => { if (e.currentTarget.open) mBodyOpen[s.chunk_id] = true; }}>
        <summary style="cursor:pointer;list-style:none;font-size:12px;color:#697061;padding:5px 0;user-select:none;display:flex;align-items:center;gap:5px;">본문 보기 <span class="m-chev" style="transition:transform .16s;color:#9aa090;">›</span></summary>
        {#if mBodyOpen[s.chunk_id]}<div style="margin-top:6px;"><MarkdownDoc documentId={doc.id} mdContent={it.bodyText} mdStatus={null} class="prose prose-sm max-w-none text-text" /></div>{/if}
      </details>
    {/if}
  </div>
{/snippet}

<div style="background:#e7ebe4;min-height:100%;" class="p-4 lg:p-6">
 <div style="max-width:1360px;margin:0 auto;">
  <!-- breadcrumb -->
  <div class="flex items-center gap-2 text-sm mb-3 text-dim">
    <a href="/documents" class="hover:text-text">문서</a><span class="text-faint">/</span>
    <span class="truncate max-w-md text-text">{doc?.title || '로딩...'}</span>
  </div>

  {#if loading}
    <Skeleton h="h-96" rounded="card" />
  {:else if error === 'not_found'}
    <EmptyState icon={FileText} title="문서를 찾을 수 없습니다" description="삭제되었거나 접근 권한이 없을 수 있습니다."><Button variant="ghost" size="sm" href="/documents">목록으로</Button></EmptyState>
  {:else if error === 'network'}
    <EmptyState icon={FileText} title="문서를 불러올 수 없습니다" description="네트워크 오류"><Button variant="secondary" size="sm" onclick={() => location.reload()}>다시 시도</Button></EmptyState>
  {:else if doc}
    <!-- ════ 상단 띠: 문서 헤더 (시안) ════ -->
    <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:16px 18px;margin-bottom:14px;">
      <div style="display:flex;align-items:flex-start;gap:13px;flex-wrap:wrap;">
        <div style="width:40px;height:40px;border-radius:10px;background:{fmtColor(doc.file_format)};color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:10.5px;letter-spacing:.5px;flex-shrink:0;text-transform:uppercase;">{doc.file_format}</div>
        <div style="flex:1;min-width:0;">
          <div style="font-size:17px;font-weight:700;line-height:1.35;color:#23291f;">{doc.title}</div>
          <div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:8px;align-items:center;">
            {#if doc.ai_domain}<span style="display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:999px;background:#fff;border:1px solid #dde3d6;font-size:11.5px;color:#23291f;"><span style="width:7px;height:7px;border-radius:50%;background:{domainColor(doc.ai_domain)};"></span>{domainLabel(doc.ai_domain)}</span>{/if}
            {#if doc.ai_sub_group}<span style="padding:3px 9px;border-radius:999px;background:#fff;border:1px solid #dde3d6;font-size:11.5px;color:#697061;">{doc.ai_sub_group}</span>{/if}
            {#if doc.ai_analysis_tier === 'deep'}<span style="padding:3px 9px;border-radius:999px;background:#4f8a6b;color:#fff;font-size:11.5px;font-weight:600;letter-spacing:.3px;">tier DEEP</span>{/if}
            {#if doc.ai_confidence != null}<span style="padding:3px 9px;border-radius:999px;background:#e3ebdf;border:1px solid #c8d6c0;font-size:11.5px;color:#3d7256;font-variant-numeric:tabular-nums;">신뢰도 {doc.ai_confidence.toFixed(2)}</span>{/if}
            {#if canShowMarkdown}<span style="padding:3px 9px;border-radius:999px;background:#eafaf2;border:1px solid #b8e3cc;font-size:11.5px;color:#1f9d6b;">PDF→MD success</span>{/if}
          </div>
        </div>
        <div style="display:flex;gap:6px;flex-shrink:0;flex-wrap:wrap;">
          {#if doc.edit_url}<button type="button" onclick={() => window.open(doc.edit_url, '_blank')} style="font-size:11.5px;color:#697061;border:1px solid #dde3d6;border-radius:8px;padding:5px 9px;background:#fff;cursor:pointer;">Synology</button>{/if}
          <button type="button" onclick={downloadOriginal} style="font-size:11.5px;color:#697061;border:1px solid #dde3d6;border-radius:8px;padding:5px 9px;background:#fff;cursor:pointer;">원본</button>
          <button type="button" onclick={copyLink} style="font-size:11.5px;color:#697061;border:1px solid #dde3d6;border-radius:8px;padding:5px 9px;background:#fff;cursor:pointer;">링크</button>
          {#if doc.category === 'library'}<button type="button" onclick={toggleNote} style="font-size:11.5px;color:{noteOpen ? '#fff' : '#697061'};border:1px solid {noteOpen ? '#4f8a6b' : '#dde3d6'};border-radius:8px;padding:5px 9px;background:{noteOpen ? '#4f8a6b' : '#fff'};cursor:pointer;">{noteOpen ? '필기 닫기' : '필기'}</button>{/if}
          <button type="button" onclick={() => (manageOpen = !manageOpen)} style="font-size:11.5px;color:#697061;border:1px solid #dde3d6;border-radius:8px;padding:5px 9px;background:#fff;cursor:pointer;">관리</button>
        </div>
      </div>
    </div>

    {#if !sectionsLoaded}
      <!-- sections 로딩 중: fallback 풀-문서(이미지)→절뷰 교체 플래시 방지용 skeleton -->
      <Skeleton h="h-96" rounded="card" />
    {:else if useSectionView}
      <!-- 데스크탑(xl+): 3영역 -->
      <div class="hidden xl:grid" style="grid-template-columns:252px minmax(0,1fr) 336px;gap:13px;align-items:start;">
        <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:13px 11px;position:sticky;top:14px;max-height:calc(100vh - 2rem);overflow-y:auto;">{@render treeNav(false)}</div>
        <div style="min-width:0;"><div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:20px 22px;">{@render focusView()}</div></div>
        <div style="position:sticky;top:14px;">{@render rail()}</div>
      </div>

      <!-- 모바일(<xl): 나란한 토글 pill + 패널 + 본문 연속 -->
      <div class="xl:hidden">
        <div style="display:flex;gap:8px;margin-bottom:10px;position:sticky;top:0;z-index:5;background:#e7ebe4;padding:6px 0;">
          <button type="button" onclick={() => (mTree = !mTree)} style="flex:1;display:flex;align-items:center;justify-content:space-between;gap:6px;border-radius:10px;padding:9px 12px;font-size:12.5px;font-weight:600;cursor:pointer;background:{mTree ? '#e3ebdf' : '#f4f7f1'};border:1px solid {mTree ? '#4f8a6b' : '#dde3d6'};color:{mTree ? '#23291f' : '#697061'};">절 구조 <span style="font-size:10px;color:#9aa090;font-weight:500;">{outline.length}절</span><span style="transition:transform .16s;transform:rotate({mTree ? 90 : 0}deg);color:#9aa090;font-weight:700;">›</span></button>
          <button type="button" onclick={() => (mIns = !mIns)} style="flex:1;display:flex;align-items:center;justify-content:space-between;gap:6px;border-radius:10px;padding:9px 12px;font-size:12.5px;font-weight:600;cursor:pointer;background:{mIns ? '#e3ebdf' : '#f4f7f1'};border:1px solid {mIns ? '#4f8a6b' : '#dde3d6'};color:{mIns ? '#23291f' : '#697061'};">인사이트<span style="transition:transform .16s;transform:rotate({mIns ? 90 : 0}deg);color:#9aa090;font-weight:700;">›</span></button>
        </div>
        {#if mTree}<div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:12px;padding:6px;margin-bottom:10px;">{@render treeNav(true)}</div>{/if}
        {#if mIns}<div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:12px;padding:13px 14px;margin-bottom:10px;">{@render rail()}</div>{/if}
        <!-- D8 스코프 한계(의도적): 모바일 본문은 전체 outline(~1030)을 연속 카드로 eager 마운트한다.
             Part 접이는 위 treeNav(앵커 점프 네비)에만 적용 — 본문 롱스크롤은 줄이지 않는다. 데스크탑은
             focusView 가 단일 절만 렌더하므로 무관. 모바일 본문 분할/가상화는 별 follow-up. -->
        <div style="display:flex;flex-direction:column;gap:10px;">{#each outline as it (it.section.chunk_id)}{@render sectionCard(it)}{/each}</div>
      </div>
    {:else}
      <!-- 절 없음 fallback: 절이 없어도 인사이트는 항상 보이게 (모바일=인사이트 상단 / 데스크탑=우측 레일) -->
      {#snippet fbViewer()}
        <div style="min-width:0;background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:18px 20px;min-height:360px;">
          {#if !hasSections && canShowMarkdown}<p style="font-size:11px;color:#9aa090;margin-bottom:12px;">이 문서는 절 분석이 없어 전체 본문으로 표시합니다. 위/옆 인사이트는 그대로 제공됩니다.</p>{/if}
          {#if viewerType === 'markdown' || viewerType === 'hwp-markdown'}
            <MarkdownDoc documentId={doc.id} mdContent={doc.md_content} mdFrontmatter={doc.md_frontmatter} mdStatus={doc.md_status} mdExtractionError={doc.md_extraction_error} mdExtractionQuality={doc.md_extraction_quality} extractedText={doc.extracted_text || rawMarkdown} class="prose prose-base max-w-none" />
          {:else if viewerType === 'pdf'}
            <div class="mb-2 flex items-center gap-2">
              <MarkdownStatusBadge mdStatus={doc.md_status} mdExtractionError={doc.md_extraction_error} mdExtractionQuality={doc.md_extraction_quality} />
              {#if canShowMarkdown}<Button size="sm" variant={pdfViewMode === 'markdown' ? 'primary' : 'secondary'} onclick={() => (pdfViewMode = 'markdown')}>Markdown</Button><Button size="sm" variant={pdfViewMode === 'pdf' ? 'primary' : 'secondary'} onclick={() => (pdfViewMode = 'pdf')}>PDF 원본</Button>{/if}
            </div>
            {#if pdfViewMode === 'markdown' && canShowMarkdown}
              <MarkdownDoc documentId={doc.id} mdContent={doc.md_content} mdFrontmatter={doc.md_frontmatter} mdStatus={doc.md_status} mdExtractionError={doc.md_extraction_error} mdExtractionQuality={doc.md_extraction_quality} extractedText={doc.extracted_text} class="prose prose-base max-w-none" />
            {:else}<iframe src="/api/documents/{doc.id}/file?token={getAccessToken()}" class="w-full h-[80vh] rounded" title={doc.title}></iframe>{/if}
          {:else if viewerType === 'image'}
            <img src="/api/documents/{doc.id}/file?token={getAccessToken()}" alt={doc.title} class="max-w-full rounded" />
          {:else if viewerType === 'synology'}
            <EmptyState icon={FileText} title="Synology Office 문서" description="외부 편집기에서 열어야 합니다."><Button variant="primary" size="sm" href={doc.edit_url || 'https://link.hyungi.net'} target="_blank">새 창에서 열기</Button></EmptyState>
          {:else if viewerType === 'article'}
            {#if doc.md_content || doc.extracted_text}<MarkdownDoc documentId={doc.id} mdContent={doc.md_content} mdFrontmatter={doc.md_frontmatter} mdStatus={null} mdExtractionError={doc.md_extraction_error} mdExtractionQuality={doc.md_extraction_quality} extractedText={doc.extracted_text} class="prose prose-base max-w-none" />{/if}
            {#if doc.edit_url}<div class="mt-4"><Button variant="primary" size="sm" href={doc.edit_url} target="_blank">원문 보기</Button></div>{/if}
          {:else}<EmptyState icon={FileText} title="인앱 미리보기 미지원" description="포맷: {doc.file_format}" />{/if}
        </div>
      {/snippet}

      <!-- 데스크탑: 본문 | 인사이트 레일 -->
      <div class="hidden xl:grid xl:grid-cols-[minmax(0,1fr)_336px] gap-3.5 items-start">
        {@render fbViewer()}
        <div style="position:sticky;top:14px;">{@render rail()}</div>
      </div>
      <!-- 모바일: 인사이트(상단 상시) + 본문 -->
      <div class="xl:hidden">
        <div style="margin-bottom:12px;">{@render rail()}</div>
        {@render fbViewer()}
      </div>
    {/if}

    <!-- 관리 (편집/삭제) — 헤더 '관리'로 토글 -->
    {#if manageOpen}
      <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;padding:16px 18px;margin-top:14px;">
        <div style="font-size:12px;font-weight:700;color:#697061;margin-bottom:12px;letter-spacing:.3px;">관리 · 분류 편집</div>
        <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
          <AIClassificationEditor {doc} />
          <LibraryPathEditor {doc} />
          <NoteEditor {doc} />
          <EditUrlEditor {doc} />
          <TagsEditor {doc} />
        </div>
        <div class="pt-3 mt-3 border-t border-default"><DocumentDangerZone {doc} ondelete={handleDocDelete} /></div>
      </div>
    {/if}

    {#if noteOpen && doc.category === 'library' && noteLoaded}
      <div style="background:#f4f7f1;border:1px solid #dde3d6;border-radius:14px;overflow:hidden;margin-top:14px;"><div class="h-[60vh] min-h-[400px] flex flex-col"><HandwriteCanvas sessionId={doc.id} initialStrokes={noteStrokes} onChange={(s) => saveNote(s)} /></div></div>
    {/if}

    {#if doc.category === 'library'}
      <div class="lg:hidden fixed bottom-0 inset-x-0 z-30 bg-surface border-t border-default px-3 py-2 flex items-center gap-2 shadow-lg">
        <button type="button" onclick={() => neighbors.prev && goto(`/documents/${neighbors.prev.id}`)} disabled={!neighbors.prev} class="px-3 py-2 rounded text-dim disabled:opacity-30" aria-label="이전">‹</button>
        <button type="button" onclick={readAndGoNext} disabled={!neighbors.next} class="flex-1 px-3 py-2.5 rounded-lg bg-accent text-white text-sm font-medium disabled:opacity-50">{#if neighbors.next}1회독 완료 + 다음{:else}1회독 완료 (마지막){/if}</button>
        <button type="button" onclick={() => neighbors.next && goto(`/documents/${neighbors.next.id}`)} disabled={!neighbors.next} class="px-3 py-2 rounded text-dim disabled:opacity-30" aria-label="다음">›</button>
      </div>
      <div class="lg:hidden h-20"></div>
    {/if}
  {/if}
 </div>
</div>

<style>
  .d3node:hover { background: #ecf0e8; }
  .d3active:hover { background: #e3ebdf; }
  .d3grp:hover { background: #ecf0e8; }
  .d3child { position: relative; }
  .d3child::before { content: ""; position: absolute; left: 2px; top: -3px; bottom: 50%; width: 1px; background: #cdd6c4; }
  .d3child::after { content: ""; position: absolute; left: 2px; top: 50%; width: 7px; height: 1px; background: #cdd6c4; }
  .m-secbody[open] .m-chev { transform: rotate(90deg); }
  .d3warn { animation: d3pulse 2.4s ease-in-out infinite; }
  @keyframes d3pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(181, 132, 10, .35); } 50% { box-shadow: 0 0 0 3px rgba(181, 132, 10, 0); } }
</style>
